#!/usr/bin/perl
use Socket;
sub OutputError;
sub OutputLoginPage;
sub OutputHeader;
sub OutputFooter;
sub LoginToPOPServer;
sub QueryServer;
sub GetMessageInfo;
sub HTMLize;
sub OutputMessageInfo;
sub OutputMessage;
sub DeleteMessage;
sub OutputMessageForm;
sub SendMessage;
sub ReadConfig;
sub InterpolateVariables;
sub HideString;
sub UnhideString;
sub OSSettings;
sub ReadParse;
############################################################################
# This script is used to generate many different individual web pages, and
# invoked separately at several different points in the process. These
# possible points are:
#
# 1) Initially: query string is null. This script generates a login page.
# 2) Login: the login page calls this script to do the mail check.
# 3) Reply: this script is invoked to reply to a message (or a forward).
# 4) Send: this script is invoked to send a new message.
#
# This section of the program is used to determine what behavior this
# individual invocation of the script is to be responsible for, based
# upon the query string.
############################################################################
# Do anything that is OS-specific.
OSSettings();
# Set this to TRUE if your Perl interpreter supports "alarm". As of this
# Writing, NT Perl does not. If this is not set, Mail 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.
# $UseAlarm = TRUE;
# Retrieve some important variables to make them easier to use.
ReadParse();
$login = UnhideString($in{"LOGIN"});
$hidden_login = HideString($login);
$password = UnhideString($in{"PASSWORD"});
$hidden_password = HideString($password);
$server = UnhideString($in{"SERVER"});
$hidden_server = HideString($server);
$card_number = 1;
# Read the configuration file.
ReadConfig();
# Find a URL to this script so that Mail can call itself.
$Me = $ENV{SCRIPT_NAME};
unless($Me =~ /^\//){ $Me = "/$Me"; } # Make sure it's rooted.
# First check for orders from a form, from a previous instance of mailman.
if($in{"MAILMAN_LOGIN"})
{
QueryServer();
exit(0);
}
# If this is the result of a message display subform.
elsif($in{"MAILMAN_DISPLAY"})
{
OutputMessage($in{"ID"});
exit(0);
}
# If this is the result of a message delete subform.
elsif($in{"MAILMAN_DELETE"})
{
DeleteMessage($in{"ID"});
exit(0);
}
# If this is the result of a new message subform.
elsif($in{"MAILMAN_NEW"})
{
OutputMessageForm("NEW",0,0);
exit(0);
}
# If this is the result of a reply subform.
elsif($in{"MAILMAN_REPLY"})
{
OutputMessageForm($in{"ID"},0,0);
exit(0);
}
# If this is the result of a reply all subform.
elsif($in{"MAILMAN_REPLYALL"})
{
OutputMessageForm($in{"ID"},TRUE,0);
exit(0);
}
# If this is the result of a forward subform.
elsif($in{"MAILMAN_FORWARD"})
{
OutputMessageForm($in{"ID"},0,TRUE);
exit(0);
}
# If this is the result of a forward subform.
elsif($in{"MAILMAN_SEND"})
{
SendMessage();
exit(0);
}
# This is a new login.
else
{
# If not all info is present, the login page must be presented
# instead of simply querying the server.
if($login && $password && $server)
{
QueryServer();
exit(0);
}
# If there is not a query string, and no configuration file,
# or if there is no password in the configuration file,
# then display the login page.
OutputLoginPage();
exit(0);
}
# A general-purpose routine used to produce error message pages.
sub OutputError
{
my($error_message) = @_;
# If there is no parameter, then this routine was called
# by the system as a timeout, so use the preset timeout message
if($error_message eq "ALRM")
{
if($UseAlarm eq TRUE){ alarm(0); }
$error_message = "$timeout_message";
# Finish the session gracefully.
print SOCKET "QUIT\n";
close SOCKET;
}
# Produce the standard header.
OutputHeader("MailMan Error: $error_message");
# Print the actual error.
print "$error_message ";
# Produce the standard footer.
OutputFooter();
# Quit the program.
exit(1);
}
# Routine used to produce a user login page.
sub OutputLoginPage
{
# Produce the standard header.
OutputHeader("MailMan Login");
# Interpolate variables into the template.
$HTMLLoginInterpolated = InterpolateVariables($HTMLLogin,
''=>$login,
''=>$password,
''=>$server);
# Print the template.
print $HTMLLoginInterpolated;
# Product the standard footer.
OutputFooter();
}
# This produces the HTML declaration for the server, plus a standard
# header from a file, or a default header if there is no file found.
sub OutputHeader
{
my($title,$extra) = @_;
# Only do this once.
if($OutputHeaderUsed++) { return; }
# No buffering on the output.
$|=1;
# Instruct everybody downstream not to cache this document.
# print "Pragma: no-cache\n";
# print "Expires: Fri, 01 Jan 1983 00:00:00 GMT\n";
# Declare that this is HTML code.
print "Content-Type: text/vnd.wap.wml\n\n";
# Spit out any extra headers that might be wanted.
print "\n$extra\n";
# Print the template.
print InterpolateVariables($HTMLHeader,
'',$title);
}
# Just like OutputHeader, but at the bottom of the page.
sub OutputFooter
{
# Only do this once.
if($OutputFooterUsed++) { return; }
print $HTMLFooter;
}
# This routine deals with the details of loggin in to a POP server.
sub LoginToPOPServer
{
# Make sure that there is enough information to proceed.
unless($login)
{
OutputError("No login provided, cannot proceed.");
}
unless($password)
{
OutputError("No password provided, cannot proceed.");
}
unless($server)
{
OutputError("No server provided, cannot proceed.");
}
# Set up a timeout for this operation.
if($UseAlarm eq TRUE)
{
$timeout_message = "Connection to server timed out.";
$SIG{'ALRM'} = \&OutputError;
alarm(180);
}
# Attempt to open a socket to the POP3 server.
$protocol = getprotobyname('tcp');
socket(SOCKET,PF_INET,SOCK_STREAM,$protocol);
$remote_ip = gethostbyname($server);
$remote_sock = pack('Sna4x8', AF_INET, 110, $remote_ip);
unless(connect(SOCKET, $remote_sock))
{
OutputError("Could not connect to server \"$server\"");
}
# No buffering on the socket.
select(SOCKET); $|=1; select(STDOUT);
# Set up the next timeout.
$timeout_message = "The server connected, but will not respond.";
if($UseAlarm eq TRUE){ alarm(180); }
# Check to make sure that it looks like a POP3 server,
# according to RFC 1725.
unless( =~ /\+OK/)
{
OutputError("The server does not respond appropriately.");
}
# Reset the timeout clock.
$timeout_message = "The server timed out during login.";
if($UseAlarm eq TRUE){ alarm(180); }
# Send the user name.
print SOCKET "USER $login\n";
$return = ;
unless($return =~ /\+OK/)
{
OutputError("Server Error: \"$return\"");
}
print SOCKET "PASS $password\n";
$return = ;
unless($return =~ /\+OK/)
{
OutputError("Server Error: \"$return\"");
}
# Get a list from the server.
print SOCKET "LIST\n";
$return = ;
unless($return =~ /\+OK/)
{
OutputError("Server Error: \"$return\"");
}
$MessageNumber = 0;
while( =~ /(\d+) (\d+)/)
{
$MessageSize[$1] = $2;
$MessageNumber ++;
}
}
# This routine does the real work of connecting to the specified server.
sub QueryServer
{
# Do the server login with the details provided.
LoginToPOPServer();
# Produce the standard header.
OutputHeader("Mailman: $login\@$server", "");
# Produce some output for starters.
print InterpolateVariables($HTMLMessagesHeader,
''=>$MessageNumber,
''=>$login,
''=>$server,
''=>$hidden_login,
''=>$hidden_password,
''=>$hidden_server);
# Reset the timeout clock.
$timeout_message = "The server timed out during message listing.";
if($UseAlarm eq TRUE){ alarm(180); }
# Get a list from the server.
print SOCKET "LIST\n";
$return = ;
unless($return =~ /\+OK/)
{
OutputError("Server Error: \"$return\"");
}
$MessageNumber = 0;
while( =~ /(\d+) (\d+)/)
{
$MessageSize[$1] = $2;
$MessageNumber ++;
}
# Cycle through the message list again, producing output.
for($index=0;$index<$MessageNumber;$index++)
{
GetMessageInfo($index+1);
$card_number++;
print qq! Next