#!/usr/bin/perl #!c:/perl/bin/perl.exe # The above line may need to be changed to reflect the location of # the perl interpreter on your system. Use "which perl" on a Unix system # to make a noble attempt to locate your perl interpreter. If you are # installing this on an NT IIS server then you probably do not need to # modify this line because it will most likely be ignored. Apache under # NT generally DOES require the top line to be configured. We have provided # two common paths above as examples, only the top line will be used, the # second line is just there to provide an example. ############################################################################ # MailMan, Professional Edition, version 3.1 # # Copyright (c) 1996 - 2002, Endymion Corporation. All rights reserved. # Endymion Corporation: http://www.endymion.com/ # by Ryan Alyn Porter, 1996 - 2002 # contributions by Stephen M Noa, 2001 # # This product is not free and is not in the public domain. # For detailed information on the licensing structure of MailMan, see # http://www.endymion.com/products/mailman/ # # Initiated: 9/07/1997 Version 1.1 # Re-awakened: 4/24/1998 Version 2.0 beta # Released: 7/20/1998 Version 2.0 # Last Modified: 2/05/2002 Version 3.1 ############################################################################ # If you are having problems with MailMan not working at all, please # take a look at the MailMan FAQ, stored online at # http://www.endymion.com/products/mailman/faq.htm. A version of the FAQ # should also have been in the distribution that contained this file. package mailman; # Enable these while you are working on modifications. Make absolutely # certain that 'use strict' is NOT enabled in production installations. # CGI.pm and 'use strict' are not compatible, if you have 'use strict' # enabled then your users will not be able to upload files because CGI.pm # provides uploaded files using a bizarre on-the-fly file handle that will # cause an error if you have 'use strict' enabled. We think that this is # ugly too, but there is no way around it at the moment. #use strict; #$^W = 1; # Warnings. # If you are getting mysterious "Internal Server Error" messages when # you try to run MailMan, then you might want to un-comment this line # to get a decent log of the error in a location that you can find. #BEGIN #{ # open(STDERR, 'c:/tmp/mailman_log.txt'); #} # Version information that might find its way into output. $mailman::strMailManVersion = 'v3.1'; $mailman::strMailManEdition = 'Professional Edition'; # Variable initialization. Clean and neat and all, but very necessary # for mod_perl. InitializeVars(); ############################################################################ # This section contains a few variables that you might need to set in order # to get MailMan functioning properly. If your installation is working, # then you don't need to worry about any of these. ############################################################################ # Local Location Users # IMPORTANT: Set this variable to point to a directory that you have # set up as the user storage area. Make sure that your web user has # read and write access to this directory. This needs to be a path # that makes sense at runtime for the web user, probably an absolute # path like '/something/somewhere/mailman/users/' or # "C\:\\mailman\\users\\". Note the terminal slash at the end. That's # important. It won't work without that slash. You probably shouldn't # be storing your user messages in publicly readable areas of your # web server for obvious security reasons, but some people don't have the # option. Just use your head, and ask us if you have any questions. # Also PLEASE remember that the data that MailMan writes to this # directory should be considered irreplacable user data and should be # handled and backed up appropriately. $mailman::strLocalLocationUsers = '/users/'; # User Disk Quota # This is fairly self-explanatory, it's the number of bytes that users # are allowed to use on your HTTP server for storing messages. If this # value is set to zero then no quota will be maintained and users will # never see quota status indicators. You can turn this on and off and # mess with the size at will, but note that if you decrease the quota # size after users have downloaded stuff then you could put some users # over quota. We have taken care to gracefully handle this situation # but your users might not think that things look very graceful when that # happens. Remember to set this in bytes. 1024*1024 bytes in a megabyte, # some common values are as follows: # 1 MB = 1048576 B # 2 MB = 2097152 B # 5 MB = 5242880 B # 10 MB = 10485760 B # Note that there are a couple of ways that a user can go slightly # over quota. MailMan allows this in cases like the storage of an # outgoing message and the like where recovery from a quota error # would be very difficult and un-graceful. Quotas are primarily # enforced when a user downloads new messages. If you notice that a # particular user has gone slightly over 100% of his/her quota, please # don't consider that a bug in MailMan. We have intentionally set things # up this way. This is a hint to administrators to allow for a little # more room on storage systems than the sum of all users' quotas. $mailman::iUserDiskQuota = 20971520; # Download Individual Accounts # Use this variable to tell MailMan that it should only download messages # from external accounts when the user explicitly issues a LOADACCOUNT # command. If this value is not set, MailMan will automatically download # messages from all of a user's accounts when they log in. #$mailman::bDownloadIndividualAccounts = 1; # Case Insensitive Accounts # This variable is used to indicate to MailMan that the POP3 account # names are case insensitive, so "BOB", "Bob" and "bob" are all considered # the same POP3 user. This is important in locating the user's persistent # information such as the message archive and the user's properties files. $mailman::bCaseInsensitiveAccounts = 1; # Outgoing Banner Text # This is the banner that is appended to the end of any message that # this MailMan installation sends. One reason why this is one of the # first configuration options is because we want to make it very # obvious that you can remove or modify this banner. Endymion places # no restrictions at all on this banner, so don't worry about leaving # credit to us in here or anything like that. Please feel free to # change this to whatever you like, or completely remove it. If this # value is not defined then it will simply append no banner. #$mailman::strOutgoingBannerText = # "\n" . # "---------------------------------------------\n" . # "This message was sent using RCC Mail.\n" . # # Incoming Mail Server: # The way that we originally intended to allow people to 'rig' the server # names for an installation was through simple template modifications, as # mentioned in the FAQ. A lot of people have asked about ways to rig the # server names in the script itself though, so we added this. We aim to # please... If you want to rig your incoming server name so that it makes # no difference at all what an incoming form specifies, just un-comment # this line and specify it. #$mailman::strIncomingServer = 'pop3.norton.antivirus'; $mailman::strIncomingServer = 'rcctvm.org'; # Outgoing Mail Server: # Same deal, different server. $mailman::strOutgoingServer = 'rcctvm.org'; # Sendmail Path: # If you would like your MailMan installation to use a local Sendmail # invocation when sending outbound mail instead of connecting to an # SMTP server, then you can un-comment this line and configure this to # point to the path of your Sendmail command. Use this if you do not # have an SMTP server running at all. # This might also work with some minor modification with other # command-line agents that support something like Sendmail's "-bs" # option, which instructs Sendmail to use the SMTP protocol via standard # input and standard output. If you have access to an SMTP server then # you are really probably better off using the wire connection instead # of this. #$mailman::strLocalLocationSendmail = '/usr/sbin/sendmail'; # Email Address Settings # The following few settings pertain to MailMan's need to infer a # user's email address. When a user logs in to MailMan, they provide # a POP3 username, server name, and password. That's not quite # enough information though. If the user ever wants to send mail, # then MailMan will need to know the user's email address for using # on the "FROM" line of the outgoing message. In many cases the # user's email address can be inferred by concatenating the user's # POP3 username with the POP3 server name. For example, the POP3 # user "sales" at the mail server "endymion.com" would result in the # email address "sales@endymion.com". This is the default behavior, # and if it is possible for you to configure your server name simply # like in this example so that it will result in functional and # attractive email addresses, then you don't need to do anything to # any of these options. # From Domain Trim: # If you have to specify a machine name for your POP3 server, then # such as "mail.endymion.com" rather than "endymion.com", then # MailMan will guess something dumb like "sales@mail.endymion.com" # when it needs to guess an email address. You can use this option # to have MailMan automatically trim one or more names from the # left side of a POP3 server's name. The number that you set here # represents the total number of names to shear off of the left-hand # side of the machine name. For instance, if the user's POP3 server # name is "mail.rex.endymion.com", and you set this value to 0, the # default, then when the user composes a message MailMan will guess # "sales@mail.rex.endymion.com" as the 'from' address. If you set # this value to 1 then it will guess "sales@rex.endymion.com", if # you set it to 2 then it will guess "sales@endymion.com", etc. This # can be helpful if you have a number of different virtual domains # and you want the email address to be inferred dynamically, rather # than by hard-coding it with the "From Domain Name" configuration value. #$mailman::iFromDomainTrim = 1; # From Domain Name: # In some cases, the POP3 server that your users check their mail from # doesn't have anything to do with the domain name portion of the # user's email address. You can use this option to manually set the # entire domain name portion of a user's email address. # For instance, consider the hyptothetical email address # "sales@endymion.com", which is served by a mailbox on the server # "mail5.it.endy-backoffice.com". When the user "sales" logs into # the POP3 server "mail5.it.endy-backoffice.com", MailMan will assume # that the email address is "sales@mail5.it.endy-backoffice.com". # If you set this variable to "endymion.com", then it will assume that # this user's email address is "sales@endymion.com" instead. $mailman::strFromDomainName = "rcctvm.org"; # Username is the Email Address # The above options hopefully helped you to configure the domain name # portion of your users' email addresses. In some cases you don't # want MailMan trying to guess a domain name at all because your users # log in to the POP3 server with their complete email address. For # instance, consider the hypothetical email address "sales@endymion.com" # that is served by a mailbox called "sales@endymion.com" on the # mail server "pop3.endymion.com". MailMan's default behavior would # be to infer the email address "sales@endymion.com@pop3.endymion.com", # which is obviously wrong. Un-comment the following line to instruct # MailMan to simply ignore the entire mail server name when inferring # the user's email address, using only the POP3 username. #$mailman::bUsernameIsEmailAddress = '1'; # Email Address Mapping File # This is a last option if all else fails. In an increasing number of # cases, the user's POP3 username has nothing to do with their email # address at all. For instance, you might have a user named "endy-sales" # on your mail server, but that mailbox actually corresponds to the # email address "sales@endymion.com". In these cases you either need # to make a custom code modification to MailMan that will allow your # user to log in with the name "sales" and have MailMan automatically # infer or look up the POP3 user name "endy-sales", which is hard and # may take some time. The simpler solution is to have your users log # in using their POP3 username as normal, and then provide a mapping # file that allows MailMan to look up each user's email address based # on their POP3 username, like a phone book. For instance, if you # provide a flat text file that contains a few lines like this: # endy-sales sales@endymion.com # endy-support support@endymion.com # (without the '#' marks at the beginning of the lines) # ...then MailMan will open the file and search for the POP3 user # name in the left column each time it needs to infer an email # address. If an entry is found, then it will use the email address # listed, if an entry is not found then MailMan will fall back on # the methods listed above. To enable this option, simply construct # a text file and provide the name of the text file here. The text # file can be automatically constructed if you like. #$mailman::strUsernameMappingFileName = "mapfile.txt"; # Outgoing Domain Name: # When a user specifies a recipient name without full domain qualification # ("rap" instead of "rap@endymion.com", for example) then the SMTP server # should provide configuration rules for determining how to deal with this # mail. It should not be the responsibility of the mail client to fill in # a complete address. We have had many requests for a feature to allow # an administrator to specify a default domain name, however, and we aim # to please. This configuration variable is the result. If you want # MailMan to assume a default domain name when it is given an incomplete # address, uncomment this line and set it to your domain name. We strongly # recommend against this, however, you should be looking into your SMTP # server's configuration options and not using this feature. #$mailman::strOutgoingDomainName = 'endymion.com'; # Messages Per Page: # This value controls the number of messages returned per page in a # message list. Adjust it if you like. # The user has the option of overriding this value in the user preferences # page. If you don't want them to be able to do this you can hide that # field in your templates. $mailman::iMessagesPerPage = 10; # Redirect Location # MailMan can redirect users to an alternate web page instead of the login # page when logging out. To redirect to an alternate location besides the # default login page you need to uncomment the line below and set it to the # URL location of the page you want to use. #$mailman::strURLRedirectLocation = 'http://www.rcctvm.org/'; # Local Template Location: # If you have a web server that sets the current directory to something # strange, you can set this to an absolute path to make it easier to # allow MailMan to find the templates. Just set this variable to an # absolute path like "C\:\\inetpub\\wwwroot\\mailman\\templates\\" # or '/usr/home/rap/mailman/' or whatever. Note the final slash, that's # important. If you leave it out then things won't work. If you need # to set this value, then un-comment the following line: #$mailman::strLocalTemplateLocation = "D:/inetpub/wwwroot/Endymion2/products/mailman/demo/"; # Local Script Location: # If your server is one of the ones that causes problems that require the # above value to be set, then you might also need to set this value. In # most cases your script location and your template location will be # identical, but if you move your templates to a different directory than # your script for whatever reason, then you will need to set this. If you # have no idea what I'm talking about, you should probably just leave this. $mailman::strLocalScriptLocation = $mailman::strLocalTemplateLocation; # URL Image Location: # Use this to rig the URLs that will be used to access the images that # the templates point to. This value will be prepended to any value in # the templates of the form ""i_*.gif"" (including the inner quotes). # If you have customized your templates and your own custom images are # not showing up in MailMan's output, it is probably because the custom # images that you are using are not named "i_*.gif". # To use this variable, set it to the exact value that you want prepended # to image names in order to make them into URLs that will point to your # image directory. For instance, if you bury your images in an "images" # directory under the directory where MailMan is installed, set this to # 'images/' (with the slash). If you put your images in a completely # different directory, something that is rooted, like '/mailman/images/' # might be what you are looking for. In the most extreme cases you can # do away with relative URLs entirely and provide a complete absolute URL # like the one below #$mailman::strURLImageLocation = 'http://www.endymion.com/images/'; # Use Perl 'alarm()' function: # Set this to true if your Perl interpreter supports "alarm". As of this # Writing, NT Perl does not. If this is not set, MailMan will not be able # to timeout when a server hangs. The OSSettings() routine will attempt # to set this variable, but you can override it here if you want. # The point of the "alarm" feature as used in MailMan is to allow MailMan # to detect when a mail server has not responded within a reasonable # amount of time. If your server's Perl interpreter does not support # "alarm", then MailMan will still work, but if a mail server ever does # not respond then the user will get no feedback to that effect. #$mailman::bUseAlarm = 1; # Timeout Duration: # The aforementioned timeout delay. Set this to something else to modify # how long MailMan will sit around waiting for a mail server to respond. # Only works if $mailman::bUseAlarm is set to something. $mailman::iTimeoutDurationInSeconds = 180; # Use Perl 'crypt()' function: # Some Perl impelentations apparently do not support the crypt() function. # We have never seen one, and there are plenty of implementations out there # that you should be able to find a good one, but we try to accomodate # anyway. Comment out this line if your Perl implementation is breaking # on the crypt() function. Be warned that if you do this your users' # usernames and passwords will be less obfuscated than they were before, # which admittedly wasn't much. This is a good place to repeat the # suggestion that MailMan is an excellent candidate for SSL and other # fancy HTTP security mechanisms. #$mailman::bUseCrypt = 1; # Use Hijack Test: # MailMan performs a test to determine if the current session has been # hijacked by a different user from a different address. On a few # systems this will not work because of the configuration. If your # MailMan installation sits behind a cluster of caching proxy servers # for load balancing, for instance. If you want to disable the hijack # checking functionality, just comment out this line. #$mailman::bUseHijackTest = 1; # Kiosk Mode: # If you are using MailMan in a kiosk environment, it will generally # be possible for a user to use a combination of "BACK" and "RELOAD" in # the kiosk web browser to intrude backwards into the mail sessions of # previous users. If you set this value then MailMan will operate in # kiosk mode, which means that when a user logs in, MailMan will create # a new browser window with that user's session. If the user logs out # then that window will close, and the user's history information will # go with the window so that intrusions with "BACK" and "RELOAD" aren't # possible. We recommend against using this feature for installations # that are not kiosk-based because it relies on Javascript and cookies, # which does not leave users with older browsers with a way in. If you # are in a kiosk environment then you have control over the browser an # that's not a problem. We strongly recommend against using the # Microsoft Internet Explorer for kiosk environments because it does not # properly respect the "Expires:" and "Cache-control:" HTTP headers, so # IE will cache user mail to the hard drive whether you want it to or # not. Microsoft appears to have no interest in fixing this problem. # IE 4 SP1 pretty consistently crashed during our tests of the # full-screen popup window kiosk mode, too, which is likely not exactly # the behavior that you are looking for in your kiosk browser. # The kiosk mode feature primarily activates and deactivates sections # of outbound templates, so if you have customized your templates before # you decided to use kiosk mode then it is entirely possible that you # broke this mode by removing vital Javascript. Consult the # out-of-the-box template set for examples of the Javascript snippets # necessary for this mode. #$mailman::bKioskMode = 1; # Date Format # By default, MailMan does not process dates as date objects, it handles # them as simple strings. If you want more control over the formatting # of your dates, then you can set this date format string and this format # will be used for the dates on message lists. The format for this string # is specified by the documentation for the Date::Manip Perl module, which # is included in most Unix Perl distributions now. If you get an error # when you try to use this, just make sure that you have Date::Manip # installed from CPAN, http://www.cpan.org Note also that date processing # is dependent on your time zone, so make sure that your 'TZ' environment # variable is set. If you get an error about this, then you can always # explicitly set the time zone by un-commenting the following: $ENV{'TZ'} = 'EST'; # Un-comment the following line to instruct MailMan to reformat dates. $mailman::strDateFormat = '%dd/%mm/%yy'; # Location Attachments # When a user selects an attachment from a message for downloading, # MailMan generates that attachment on-the-fly and sends it through the # HTTP server to the user's browser. MailMan includes the necessary # HTTP header information for the user's browser to determine the # file name, but many broswers, most notably Microsoft's Internet # Explorer, either ignore these headers or just don't handle them # very well. The result is that when a user downloads an attachment, # your browser may present the user with a "Save As" box with the # file name filled in as the name of this script, a string or random # characters, or any number of other un-graceful things. We think that # the best solution to this problem would be for browser makers to # pay attention to HTTP headers, but until then we provide a mechanism # for working around the problem. If you set up a directory that is # writable by MailMan and readable by your web server, then MailMan # will write out the attachment file to that directory temporarily, # and redirect the user's browser to that file. When the user logs # in or out MailMan will ensure that the user's files in this # temporary directory are removed. A user that exits MailMan without # logging out and never logs back in could potentially leave stale # attachment files on the server, so occasional monitoring of the # temporary directory for stale files would be appropriate. Also note # that this mechanism could be considered a privacy problem since a # user's attachments are deposited temporarily into a world-readable # directory rather than generated on-the-fly the way MailMan normally # would do. We have left the decision up to each individual # administrator as to whether or not to use this feature. Most people # seem to prefer allowing MailMan to generate attachments on-the-fly # for simplicity, ease of administration, and security/privacy, but # some people think that the attachment file name thing is a critical # issue. The decision is yours. # IMPORTANT SECURITY ADVISORY: # Make absolutely certain that the directory that you use for # attachments does *NOT* allow executable code. Do NOT use this # method of attachment handling if you are not absolutely certain # that executable code is not allowed in that directory. If your # temporary directory allows executable code then any attachments # that end in ".cgi", ".php", ".pl", etc, may be executed by your # server when they are accessed, rather than simply served. You do # *NOT* want this. # To use this feature, create a directory that is readable by your # web server and writable by the user that MailMan runs as. Set # $mailman::strLocalLocationAttachments to the local path name of # this directory, for instance # $mailman::strLocalLocationAttachments = '/public_html/attachtmp/'; # Then set $mailman::strURLLocationAttachments to the URL location # of this directory, for instance # $mailman::strURLLocationAttachments = '/attachtmp/'; # Note the terminal slashes at the end, those are necessary. Just # set and uncomment the following lines to use this feature: #$mailman::strLocalLocationAttachments = 'c:/www/public_html/mailman/tmp/'; #$mailman::strURLLocationAttachments = '/mailman/tmp/'; # Local File Permissions # Use this if you want to modify the permissions that files and # directories created by MailMan use. This will only make much sense # to Unix and Unix-like operating systems. If this value is not set, # nothing will happen. This should be an octal integer as in the # example below, not a string. $mailman::iLocalFilePermissions = 0666; # Local Directory Permissions # Same as above, used for directories created by MailMan. $mailman::iLocalDirectoryPermissions = 0777; # Subject Truncation Length # This is the maximum length allowed for a subject line in the message # list pages. If you set this then subject lines will be truncated at # this length, for predictable layout. If you don't set this, then # subjects will be left untouched. Subjects will always be left alone # on the message display page. $mailman::iSubjectTruncationLength = 20; ############################################################################ # You should not have to configure any values after this line. ############################################################################ # The following section of code is CGI manipulation routines # originally provided as a module called "cgi-lib.pl". This # code includes some very minor modifications to that code. # This is the original copyright notice from that code: # # Copyright (c) 1993-1999 Steven E. Brenner # Unpublished work. # # We have removed the original license notice to avoid confusion # over MailMan's license. If you are interested in this excellent # CGI handling code, then please see: # http://cgi-lib.stanford.edu/cgi-lib/ $cgi_lib'version = sprintf("%d.%02d", q$Revision: 2.18 $ =~ /(\d+)\.(\d+)/); # ReadParse # Reads in GET or POST data, converts it to unescaped text, and puts # key/value pairs in %in, using "\0" to separate multiple selections # Returns >0 if there was input, 0 if there was no input # undef indicates some failure. # Now that cgi scripts can be put in the normal file space, it is useful # to combine both the form and the script in one place. If no parameters # are given (i.e., ReadParse returns FALSE), then a form could be output. # If a reference to a hash is given, then the data will be stored in that # hash, but the data from $in and @in will become inaccessable. # If a variable-glob (e.g., *cgi_input) is the first parameter to ReadParse, # information is stored there, rather than in $in, @in, and %in. # Second, third, and fourth parameters fill associative arrays analagous to # %in with data relevant to file uploads. # If no method is given, the script will process both command-line arguments # of the form: name=value and any text that is in $ENV{'QUERY_STRING'} # This is intended to aid debugging and may be changed in future releases sub ReadParse { # Disable warnings as this code deliberately uses local and environment # variables which are preset to undef (i.e., not explicitly initialized) my ($perlwarn); $perlwarn = $^W; $^W = 0; # Parameters affecting cgi-lib behavior # User-configurable parameters affecting file upload. # $cgi_lib'maxdata = 131072; # maximum bytes to accept via POST - 2^17 $cgi_lib'maxdata = 5242880; # five megabytes $cgi_lib'writefiles = 0; # directory to which to write files, or # 0 if files should not be written $cgi_lib'filepre = "cgi-lib"; # Prefix of file names, in directory above # Do not change the following parameters unless you have special reasons $cgi_lib'bufsize = 8192; # default buffer size when reading multipart $cgi_lib'maxbound = 100; # maximum boundary length to be encounterd $cgi_lib'headerout = 0; # indicates whether the header has been printed (*mailman::in) = shift if @_; # CGI input (*mailman::incfn, # Client's filename (may not be provided) *mailman::inct, # Client's content-type (may not be provided) *mailman::insfn) = @_; # Server's filename (for spooled files) my ($len, $type, $meth, $errflag, $cmdflag, $got, $name); binmode(STDIN); # we need these for DOS-based systems binmode(STDOUT); # and they shouldn't hurt anything else binmode(STDERR); # Get several useful env variables $type = $ENV{'CONTENT_TYPE'}; $len = $ENV{'CONTENT_LENGTH'}; $meth = $ENV{'REQUEST_METHOD'}; if ($len > $cgi_lib'maxdata) { #' &CgiDie("cgi-lib.pl: Request to receive too much data: $len bytes\n"); } if (!defined $meth || $meth eq '' || $meth eq 'GET' || $meth eq 'HEAD' || $type eq 'application/x-www-form-urlencoded') { my ($key, $val, $i); # Read in text if (!defined $meth || $meth eq '') { $mailman::in = $ENV{'QUERY_STRING'}; $cmdflag = 1; # also use command-line options } elsif($meth eq 'GET' || $meth eq 'HEAD') { $mailman::in = $ENV{'QUERY_STRING'}; } elsif ($meth eq 'POST') { if (($got = read(STDIN, $mailman::in, $len) != $len)) {$errflag="Short Read: wanted $len, got $got\n";}; } else { &CgiDie("cgi-lib.pl: Unknown request method: $meth\n"); } @mailman::in = split(/[&;]/,$mailman::in); push(@mailman::in, @ARGV) if $cmdflag; # add command-line parameters foreach $i (0 .. $#mailman::in) { # Convert plus to space $mailman::in[$i] =~ s/\+/ /g; # Split into key and value. ($key, $val) = split(/=/,$mailman::in[$i],2); # splits on the first =. # Convert %XX from hex numbers to alphanumeric $key =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge; $val =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge; # Associate key and value $mailman::in{$key} .= "\0" if (defined($mailman::in{$key})); # \0 is the multiple separator $mailman::in{$key} .= $val; } } elsif ($ENV{'CONTENT_TYPE'} =~ m/^multipart\/form-data/) { # for efficiency, compile multipart code only if needed $errflag = !(eval <<'END_MULTIPART'); my ($buf, $boundary, $head, @heads, $cd, $ct, $fname, $ctype, $blen); my ($bpos, $lpos, $left, $amt, $fn, $ser); my ($bufsize, $maxbound, $writefiles) = ($cgi_lib'bufsize, $cgi_lib'maxbound, $cgi_lib'writefiles); # The following lines exist solely to eliminate spurious warning messages $buf = ''; ($boundary) = $type =~ /boundary="([^"]+)"/; #"; # find boundary ($boundary) = $type =~ /boundary=(\S+)/ unless $boundary; &CgiDie ("Boundary not provided: probably a bug in your server") unless $boundary; $boundary = "--" . $boundary; $blen = length ($boundary); if ($ENV{'REQUEST_METHOD'} ne 'POST') { &CgiDie("Invalid request method for multipart/form-data: $meth\n"); } if ($writefiles) { my($me); stat ($writefiles); $writefiles = "/tmp" unless -d _ && -w _; # ($me) = $0 =~ m#([^/]*)$#; $writefiles .= "/$cgi_lib'filepre"; } # read in the data and split into parts: # put headers in @in and data in %in # General algorithm: # There are two dividers: the border and the '\r\n\r\n' between # header and body. Iterate between searching for these # Retain a buffer of size(bufsize+maxbound); the latter part is # to ensure that dividers don't get lost by wrapping between two bufs # Look for a divider in the current batch. If not found, then # save all of bufsize, move the maxbound extra buffer to the front of # the buffer, and read in a new bufsize bytes. If a divider is found, # save everything up to the divider. Then empty the buffer of everything # up to the end of the divider. Refill buffer to bufsize+maxbound # Note slightly odd organization. Code before BODY: really goes with # code following HEAD:, but is put first to 'pre-fill' buffers. BODY: # is placed before HEAD: because we first need to discard any 'preface,' # which would be analagous to a body without a preceeding head. $left = $len; PART: # find each part of the multi-part while reading data while (1) { die $@ if $errflag; $amt = ($left > $bufsize+$maxbound-length($buf) ? $bufsize+$maxbound-length($buf): $left); $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != $amt); die "Short Read: wanted $amt, got $got\n" if $errflag; $left -= $amt; $mailman::in{$name} .= "\0" if defined $mailman::in{$name}; $mailman::in{$name} .= $fn if $fn; $name=~/([-\w]+)/; # This allows $insfn{$name} to be untainted if (defined $1) { $mailman::insfn{$1} .= "\0" if defined $mailman::insfn{$1}; $mailman::insfn{$1} .= $fn if $fn; } BODY: while (($bpos = index($buf, $boundary)) == -1) { if ($left == 0 && $buf eq '') { my $value; foreach $value (values %mailman::insfn) { unlink(split("\0",$value)); } &CgiDie("cgi-lib.pl: reached end of input while seeking boundary " . "of multipart. Format of CGI input is wrong.\n"); } die $@ if $errflag; if ($name) { # if no $name, then it's the prologue -- discard if ($fn) { print FILE substr($buf, 0, $bufsize); } else { $mailman::in{$name} .= substr($buf, 0, $bufsize); } } $buf = substr($buf, $bufsize); $amt = ($left > $bufsize ? $bufsize : $left); #$maxbound==length($buf); $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != $amt); die "Short Read: wanted $amt, got $got\n" if $errflag; $left -= $amt; } if (defined $name) { # if no $name, then it's the prologue -- discard if ($fn) { print FILE substr($buf, 0, $bpos-2); } else { $mailman::in {$name} .= substr($buf, 0, $bpos-2); } # kill last \r\n } close (FILE); last PART if substr($buf, $bpos + $blen, 2) eq "--"; substr($buf, 0, $bpos+$blen+2) = ''; $amt = ($left > $bufsize+$maxbound-length($buf) ? $bufsize+$maxbound-length($buf) : $left); $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != $amt); die "Short Read: wanted $amt, got $got\n" if $errflag; $left -= $amt; undef $head; undef $fn; HEAD: while (($lpos = index($buf, "\r\n\r\n")) == -1) { if ($left == 0 && $buf eq '') { my $value; foreach $value (values %mailman::insfn) { unlink(split("\0",$value)); } &CgiDie("cgi-lib: reached end of input while seeking end of " . "headers. Format of CGI input is wrong.\n$buf"); } die $@ if $errflag; $head .= substr($buf, 0, $bufsize); $buf = substr($buf, $bufsize); $amt = ($left > $bufsize ? $bufsize : $left); #$maxbound==length($buf); $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != $amt); die "Short Read: wanted $amt, got $got\n" if $errflag; $left -= $amt; } $head .= substr($buf, 0, $lpos+2); push (@mailman::in, $head); @heads = split("\r\n", $head); ($cd) = grep (/^\s*Content-Disposition:/i, @heads); ($ct) = grep (/^\s*Content-Type:/i, @heads); ($name) = $cd =~ /\bname="([^"]+)"/i; #"; ($name) = $cd =~ /\bname=([^\s:;]+)/i unless defined $name; ($fname) = $cd =~ /\bfilename="([^"]*)"/i; #"; # filename can be null-str ($fname) = $cd =~ /\bfilename=([^\s:;]+)/i unless defined $fname; $mailman::incfn{$name} .= (defined $mailman::in{$name} ? "\0" : "") . (defined $fname ? $fname : ""); ($ctype) = $ct =~ /^\s*Content-type:\s*"([^"]+)"/i; #"; ($ctype) = $ct =~ /^\s*Content-Type:\s*([^\s:;]+)/i unless defined $ctype; $mailman::inct{$name} .= (defined $mailman::in{$name} ? "\0" : "") . $ctype; if ($writefiles && defined $fname) { $ser++; $fn = $writefiles . ".$$.$ser"; open (FILE, ">$fn") || &CgiDie("Couldn't open $fn\n"); binmode (FILE); # write files accurately } substr($buf, 0, $lpos+4) = ''; undef $fname; undef $ctype; } 1; END_MULTIPART if ($errflag) { my ($errmsg, $value); $errmsg = $@ || $errflag; foreach $value (values %mailman::insfn) { unlink(split("\0",$value)); } &CgiDie($errmsg); } else { # everything's ok. } } else { &CgiDie("cgi-lib.pl: Unknown Content-type: $ENV{'CONTENT_TYPE'}\n"); } # no-ops to avoid warnings $mailman::insfn = $mailman::insfn; $mailman::incfn = $mailman::incfn; $mailman::inct = $mailman::inct; $^W = $perlwarn; return ($errflag ? undef : scalar(@mailman::in)); } # PrintHeader # Returns the magic line which tells WWW that we're an HTML document sub PrintHeader { return "Content-type: text/html\n\n"; } # HtmlTop # Returns the
of a document and the beginning of the body # with the title and a body