Blame samples/mailto-form.pl

Packit f574b8
#! /usr/bin/perl -w
Packit f574b8
# Some scripts for handling mailto URLs within lynx via an interactive form
Packit f574b8
# 
Packit f574b8
# Warning: this is a quick demo, to show what kinds of things are possible
Packit f574b8
# by hooking some external commands into lynx.  Use at your own risk.
Packit f574b8
# 
Packit f574b8
# Requirements:
Packit f574b8
# 
Packit f574b8
# - Perl and CGI.pm.
Packit f574b8
# - A "sendmail" command for actually sending mail (if you need some
Packit f574b8
#   other interface, change the code below in sub sendit appropriately).
Packit f574b8
# - Lynx compiled with support for lynxcgi, that means EXEC_CGI must have
Packit f574b8
#   been defined at compilation, usually done with
Packit f574b8
#     ./configure --enable-cgi-links
Packit f574b8
# - Lynx must have support for CERN-style rules as of 2.8.3, which must
Packit f574b8
#   not have been disabled at compilation (it is enabled by default).
Packit f574b8
# 
Packit f574b8
# Instructions:
Packit f574b8
# (This is for people without lynxcgi experience; if you are already
Packit f574b8
# use lynxcgi, you don't have to follow everything literally, use
Packit f574b8
# common sense for picking appropriate file locations in your situation.)
Packit f574b8
# 
Packit f574b8
# - Make a subdirectory 'lynxcgi' under you home directory, i.e.
Packit f574b8
#      mkdir ~/lynxcgi
Packit f574b8
# - Put this three script file mailto-form.pl there and make it
Packit f574b8
#   executable.  For example,
Packit f574b8
#      cp mailto-form.pl ~/lynxcgi
Packit f574b8
#      chmod a+x ~/lynxcgi/mailto-form.pl
Packit f574b8
# - Edit mailto-form.pl (THIS FILE), there are some strings that
Packit f574b8
#   that need to be changed, see ### Configurable variables ###
Packit f574b8
#   below.
Packit f574b8
# - Allow lynx to execute lynxcgi files in that directory, for example,
Packit f574b8
#   put in your lynx.cfg file:
Packit f574b8
#      TRUSTED_LYNXCGI:<tab>/home/myhomedir/lynxcgi/mailto-form.pl
Packit f574b8
#   where <tab> is a real TAB character and you have to put the real
Packit f574b8
#   location of your directory in place of "myhomedir", of course.
Packit f574b8
#   The '~' abbreviation cannot be used.
Packit f574b8
#   You could also just enable execution of all lynxcgi scripts, by
Packit f574b8
#   not having any TRUSTED_LYNXCGI options in lynx.cfg at all, but
Packit f574b8
#   that can't be recommended.
Packit f574b8
# - Tell lynx to actually use the lynxcgi scripts for mailto URLs.
Packit f574b8
#   There are two variants:
Packit f574b8
#   a) Redirect "mailto"
Packit f574b8
#   Requires patched lynx, currently not yet in the developent code.
Packit f574b8
#   Use the following two lines in the file that is configured as
Packit f574b8
#   RULESFILE in lynxcfg:
Packit f574b8
#      PermitRedirection mailto:*
Packit f574b8
#      Redirect mailto:* lynxcgi:/home/myhomedir/lynxcgi/mailto-form.pl?from=myname@myhost&to=*
Packit f574b8
#   You can also put them directly in lynx.cfg, prefixing each with
Packit f574b8
#   "RULE:".  Replace ""myhomedir", "myname", and "myhost" with your
Packit f574b8
#   correct values, of course.
Packit f574b8
#   b) Redirect "xmailto"
Packit f574b8
#   Requires defining a fake proxy before starting lynx, like
Packit f574b8
#      export xmailto_proxy=dummy  # or for csh: setenv xmailto_proxy dummy
Packit f574b8
#   Requires that you change "mailto" to "xmailto" each time you want
Packit f574b8
#   to activate a mailto link.  This can be done conveniently with
Packit f574b8
#   a few keys: 'E', ^A, 'x', Enter.
Packit f574b8
#   Use the following two lines in the file that is configured as
Packit f574b8
#   RULESFILE in lynxcfg:
Packit f574b8
#      PermitRedirection xmailto:*
Packit f574b8
#      Redirect xmailto:* lynxcgi:/home/myhomedir/lynxcgi/mailto-form.pl?from=myname@myhost&to=*
Packit f574b8
#   You can also put them directly in lynx.cfg, prefixing each with
Packit f574b8
#   "RULE:".  Replace ""myhomedir", "myname", and "myhost" with your
Packit f574b8
#   correct values, of course.
Packit f574b8
# 
Packit f574b8
# Limitations:
Packit f574b8
# 
Packit f574b8
# - Only applies to mailto URLs that appear as links or are entered at
Packit f574b8
#   a 'g'oto prompt.  Does not apply to other ways of sending mail, like
Packit f574b8
#   the 'c' (COMMENT) key, mailto as a FORM action, or mailing a file
Packit f574b8
#   from the 'P'rinting Options screen.
Packit f574b8
# - Nothing is done for charset labelling, content-transfer-encoding
Packit f574b8
#   of non-ASCII characters, and other MIME niceties.
Packit f574b8
#
Packit f574b8
# Klaus Weide 20000712
Packit f574b8
Packit f574b8
########################################################################
Packit f574b8
########## Configurable variables ######################################
Packit f574b8
Packit f574b8
$SENDMAIL = '/usr/sbin/sendmail';
Packit f574b8
#                                   The location of your sendmail binary
Packit f574b8
$SELFURL = 'lynxcgi:/home/lynxdev/lynxcgi/mailto-form.pl';
Packit f574b8
#                                   Where this script lives in URL space
Packit f574b8
$SEND_TOKEN = '/vJhOp6eQ';
Packit f574b8
#                           When found in the PATH_INFO part of the URL,
Packit f574b8
#                           this causes the script to actually send mail
Packit f574b8
#                           by calling $SENDMAIL instead of just throwing
Packit f574b8
#                           up a form.  CHANGE IT!  And don't tell anyone!
Packit f574b8
#                           Treat it like a password.
Packit f574b8
#                           Must start with '/', probably should have only
Packit f574b8
#                           alphanumeric ASCII characters.
Packit f574b8
Packit f574b8
## Also, make sure the first line of this script points
Packit f574b8
## to your PERL binary
Packit f574b8
Packit f574b8
########## Nothing else to change - I hope #############################
Packit f574b8
########################################################################
Packit f574b8
Packit f574b8
use CGI;
Packit f574b8
Packit f574b8
$|=1;
Packit f574b8
Packit f574b8
### Upcase first character
Packit f574b8
##sub ucfirst {
Packit f574b8
##    s/^./\U$1/;
Packit f574b8
##}
Packit f574b8
Packit f574b8
# If there are multiple occurrences of the same thing, how to join them
Packit f574b8
# into one string
Packit f574b8
%joiner = (from => ', ',
Packit f574b8
	   to => ', ',
Packit f574b8
	   cc => ', ',
Packit f574b8
	   subject => '; ',
Packit f574b8
	   body => "\n\n"
Packit f574b8
	   );
Packit f574b8
sub joiner {
Packit f574b8
    my ($key) = @_;
Packit f574b8
    if ($joiner{$key}) {
Packit f574b8
	$joiner{$key};
Packit f574b8
    } else {
Packit f574b8
	" ";
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
# Here we check whether this script is called for actual sending, rather
Packit f574b8
# than form generation.  If so, all the rest is handled by sub sendit, below.
Packit f574b8
$pathinfo = $ENV{'PATH_INFO'}; 
Packit f574b8
if (defined($pathinfo) && $pathinfo eq $SEND_TOKEN) {
Packit f574b8
    $q = new CGI;
Packit f574b8
    print $q->header('text/plain');
Packit f574b8
    sendit();
Packit f574b8
    exit;
Packit f574b8
}
Packit f574b8
Packit f574b8
$method = $ENV{'REQUEST_METHOD'};
Packit f574b8
$querystring = $ENV{'QUERY_STRING'};
Packit f574b8
if ($querystring) {
Packit f574b8
    if ($method && $method eq "POST" && $ENV{'CONTENT_LENGTH'}) {
Packit f574b8
	$querystring =~ s/((^|\&)to=[^?&]*)\?/$1&/;
Packit f574b8
	$q0 = new CGI;
Packit f574b8
	$q = new CGI($querystring);
Packit f574b8
	@fields = $q0->param();
Packit f574b8
	foreach $key (@fields) {
Packit f574b8
	    @vals = $q0->param($key);
Packit f574b8
#	    print "Content-type: text/html\n\n";
Packit f574b8
#	    print "Appending $key to \$q...\n";
Packit f574b8
	    $q->append($key, @vals);
Packit f574b8
#	    print "

Current Values in \$q0

\n";
Packit f574b8
#	    print $q0->dump;
Packit f574b8
#	    print "

Current Values in \$q

\n";
Packit f574b8
#	    print $q->dump;
Packit f574b8
Packit f574b8
	}
Packit f574b8
Packit f574b8
    } else {
Packit f574b8
	$querystring =~ s/((^|\&)to=[^?&]*)\?/$1&/;
Packit f574b8
	$q = new CGI($querystring);
Packit f574b8
    }
Packit f574b8
} else {
Packit f574b8
    $q = new CGI;
Packit f574b8
}
Packit f574b8
Packit f574b8
print $q->header;
Packit f574b8
Packit f574b8
$long_title = $ENV{'QUERY_STRING'};
Packit f574b8
$long_title =~ s/^from=([^&]*)\&to=//;
Packit f574b8
$long_title = "someone" unless $long_title;
Packit f574b8
$long_title = "Compose mail for $long_title";
Packit f574b8
if (length($long_title) > 72) {
Packit f574b8
    $title = substr($long_title,0,72) . "...";
Packit f574b8
} else {
Packit f574b8
    $title = $long_title;
Packit f574b8
}
Packit f574b8
$long_title =~ s/&/&/g;
Packit f574b8
$long_title =~ s/</</g;
Packit f574b8
print
Packit f574b8
    $q->start_html($title), "\n",
Packit f574b8
    $q->h1($long_title), "\n",
Packit f574b8
    $q->start_form(-method=>'POST', -action => $SELFURL . $SEND_TOKEN), "\n";
Packit f574b8
Packit f574b8
print "\n";
Packit f574b8
@fields = $q->param();
Packit f574b8
foreach $key (@fields) {
Packit f574b8
    @vals = $q->param($key);
Packit f574b8
    if (scalar(@vals) != 1) {
Packit f574b8
	print "multiple values " . scalar(@vals) ." for $key!\n";
Packit f574b8
	$q->param($key, join (joiner($key), @vals));
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
foreach $key (@fields) {
Packit f574b8
    $_ = lc($key);
Packit f574b8
    if ($_ ne $key) {
Packit f574b8
	print "noncanonical case for $key!\n";
Packit f574b8
	$val=$q->param($key);
Packit f574b8
	$q->delete($key);
Packit f574b8
	if (!$q->param($_)) {
Packit f574b8
	    $q->param($_, $val);
Packit f574b8
	} else {
Packit f574b8
	    $q->param($_, $q->param($_) . joiner($_) . "$val");
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
foreach $key ('from', 'to', 'cc', 'subject') {
Packit f574b8
    print $q->Tr,
Packit f574b8
    $q->td(ucfirst($key) . ":"),
Packit f574b8
    $q->td($q->textfield(-name=>$key,
Packit f574b8
			 -size=>60,
Packit f574b8
			 -default=>$q->param($key))), "\n";
Packit f574b8
    $q->delete($key);
Packit f574b8
}
Packit f574b8
Packit f574b8
# Also pass on any unrecognized header fields that were specified.
Packit f574b8
# This may not be a good idea for general use!
Packit f574b8
# At least some dangerous header fields may have to be suppressed.
Packit f574b8
@keys = $q->param();
Packit f574b8
if (scalar(@keys) > (($q->param('body')) ? 1 : 0)) {
Packit f574b8
    print "Additional headers:\n";
Packit f574b8
    foreach $key ($q->param()) {
Packit f574b8
	if ($key ne 'body') {
Packit f574b8
	    print $q->Tr,
Packit f574b8
	    $q->td(ucfirst($key) . ":"),
Packit f574b8
	    $q->td($q->textfield(-name=>$key,
Packit f574b8
				 -size=>60,
Packit f574b8
				 -default=>$q->param($key))), "\n";
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
print "\n";
Packit f574b8
print $q->textarea(-name=>'body',
Packit f574b8
		   -default=>$q->param('body')), "\n";
Packit f574b8
print "
\n\n
", "\n",
Packit f574b8
    $q->submit(-value=>"Send the message"), "\n",
Packit f574b8
    $q->endform, "\n";
Packit f574b8
Packit f574b8
print "\n";
Packit f574b8
exit;
Packit f574b8
Packit f574b8
# This is for header field values.
Packit f574b8
sub sanitize_field_value {
Packit f574b8
    my($val) = @_;
Packit f574b8
    $val =~ s/\0/./g;
Packit f574b8
    $val =~ s/\r\n/\n/g;
Packit f574b8
    $val =~ s/\r/\n/g;
Packit f574b8
    $val =~ s/\n*$//g;
Packit f574b8
    $val =~ s/\n+/\n/g;
Packit f574b8
    $val =~ s/\n(\S)/\n\t$1/g;
Packit f574b8
    $val;
Packit f574b8
}
Packit f574b8
Packit f574b8
sub sendit {
Packit f574b8
    open (MAIL, "| $SENDMAIL -t -oi -v") || die ("$0: Can't run sendmail: $!\n");
Packit f574b8
    @fields = $q->param();
Packit f574b8
    foreach $key (@fields) {
Packit f574b8
	@vals = $q->param($key);
Packit f574b8
	if (scalar(@vals) != 1) {
Packit f574b8
	    print "multiple values " . scalar(@vals) ." for $key!\n";
Packit f574b8
	    $q->param($key, join (joiner($key), @vals));
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
    foreach $key (@fields) {
Packit f574b8
	if ($key ne 'body') {
Packit f574b8
	    if ($key =~ /[^A-Za-z0-9_-]/) {
Packit f574b8
		print "$0: Ignoring malformed header field named '$key'!\n";
Packit f574b8
		next;
Packit f574b8
	    }
Packit f574b8
	    print MAIL ucfirst($key) . ": " .
Packit f574b8
		sanitize_field_value($q->param($key)) . "\n"
Packit f574b8
		or die ("$0: Feeding header to sendmail failed: $!\n");
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
    print MAIL "\n"
Packit f574b8
	or die ("$0: Ending header for sendmail failed: $!\n");
Packit f574b8
    print MAIL $q->param('body'), "\n"
Packit f574b8
	or die ("$0: Feeding body to sendmail failed: $!\n");
Packit f574b8
    close(MAIL)
Packit f574b8
	or warn $! ? "Error closing pipe to sendmail: $!"
Packit f574b8
	    : ($? & 127) ? ("Sendmail killed by signal " . ($? & 127) .
Packit f574b8
			    ($? & 127) ? ", core dumped" : "")
Packit f574b8
		: "Return value " . ($? >> 8) . " from sendmail";
Packit f574b8
}