1 # UVsendmail: functions for sending mails
2 # Used by uvvote.pl, uvcfv.pl
10 use Text::Wrap qw(wrap $columns);
12 # Set columns for Text::Wrap
13 $columns = $config{rightmargin};
15 use vars qw($VERSION);
22 ##############################################################################
23 # generation of acknowledge and error mails (don't sends them out yet) #
24 # each mail is saved in a different file and a control file containing #
25 # filename and envelope-to address is generated. #
26 # Parameters: mail address, fixed part of subject and body of mail (strings) #
27 ##############################################################################
30 my ($addr, $subject, $text, $reference, $replyto) = @_;
34 # generate mail to sender
36 my $template = UVtemplate->new();
37 $template->setKey('from' => mimeencode($config{mailfrom}));
38 $template->setKey('subject' => mimeencode("$config{votename} - $subject"));
39 $template->setKey('address' => $addr);
40 $template->setKey('reference' => $reference) if ($reference);
41 $template->setKey('reply-to' => $replyto) if ($replyto);
42 $template->setKey('usevote-version' => $usevote_version);
44 my $message = $template->processTemplate($config{'tpl_mailheader'});
45 $message .= "\n" . $text;
47 # get envelope-to addresses
49 $envaddr .= " $config{mailcc}" if ($config{mailcc});
53 # search for file names
56 $mailfile = "$config{tmpdir}/ack.$num";
57 } while (-e $mailfile);
59 # write mail in a file and append a line at the control file
61 open (CONTROL, ">>$config{controlfile}") or print STDERR "\n\n",
62 UVmessage::get("SENDMAIL_ERROPENCONTROL", (FILE => $config{controlfile})), "\n";
63 print CONTROL "$mailfile\t$envaddr\n";
64 close (CONTROL) or print STDERR "\n\n",
65 UVmessage::get("SENDMAIL_ERRCLOSECONTROL", (FILE => $config{controlfile})), "\n";
67 open (MAIL, ">$mailfile") or print STDERR "\n\n",
68 UVmessage::get("SENDMAIL_ERROPENMAIL", (FILE => $config{controlfile})), "\n";
70 close (MAIL) or print STDERR "\n\n",
71 UVmessage::get("SENDMAIL_ERRCLOSEMAIL", (FILE => $config{controlfile})), "\n";
77 ##############################################################################
78 # Send previously generated acknowledge or error mails. #
79 # Depending on configuration mails are piped to your MTA or send via SMTP. #
80 ##############################################################################
83 unless (-e $config{controlfile}) {
84 print "\n", UVmessage::get("SENDMAIL_NOMAILS", (FILE => $config{controlfile})),
89 open (CONTROL, "<$config{controlfile}") or die "\n\n",
90 UVmessage::get("SENDMAIL_ERROPENCONTROL", (FILE => $config{controlfile})), "\n";
91 my @mailinfo = <CONTROL>;
94 print UVmessage::get("SENDMAIL_SENDING"), "\n";
99 my $smtp = Net::SMTP->new("$config{smtpserver}:$config{smtpport}",
100 Hello => $config{smtphelo});
101 die UVmessage::get("SENDMAIL_SMTP_CONNREFUSED") . "\n\n" unless ($smtp);
102 if ($config{smtpauth}) {
103 $smtp->auth($config{smtpuser}, $config{smtppass})
104 or die UVmessage::get("SENDMAIL_SMTP_CONNREFUSED") . "\n" .
105 $smtp->code() . ' ' . $smtp->message() . "\n";
109 my $missingfiles = 0;
111 open (CONTROL, ">$config{controlfile}") or die "\n\n",
112 UVmessage::get("SENDMAIL_ERROPENCONTROL", (FILE => $config{controlfile})), "\n";
114 foreach my $mail (@mailinfo) {
119 my ($file, $envelope) = split(/\t/, $mail);
121 open (MAIL, "<$file") or $notfound = 1;
123 print STDERR UVmessage::get("SENDMAIL_ERRNOTFOUND") . "\n";
127 my $message = join('', <MAIL>);
130 next unless $message;
133 $smtp->mail($config{envelopefrom});
134 unless ($smtp->ok()) {
135 print STDERR UVmessage::get("SENDMAIL_SMTP_INVRCPT", (RCPT => $envelope)),
136 "\n", $smtp->code(), ' ', $smtp->message(), "\n";
143 foreach my $addr (split(/ +/, $envelope)) {
148 print CONTROL ($onefail ? " " : "$file\t");
150 print STDERR UVmessage::get("SENDMAIL_SMTP_INVRCPT", (RCPT => $envelope)),
151 "\n", $smtp->code(), ' ', $smtp->message(), "\n";
158 print CONTROL "\n" if ($onefail);
159 next unless $onesent;
163 $smtp->datasend($message);
166 unless ($smtp->ok()) {
167 print STDERR UVmessage::get("SENDMAIL_SMTP_INVRCPT", (RCPT => $envelope)),
168 "\n", $smtp->code(), ' ', $smtp->message(), "\n";
172 unlink ($file) unless ($onefail);
176 close (CONTROL) or die "\n\n",
177 UVmessage::get("SENDMAIL_ERRCLOSECONTROL", (FILE => $config{controlfile})), "\n";
180 print STDERR "\n".wrap('', '', "$errors ".UVmessage::get("SENDMAIL_ERROCCURED"))."\n\n";
184 print STDERR wrap('', '', "$missingfiles " .
185 UVmessage::get("SENDMAIL_MISSINGFILES")), "\n\n";
190 foreach my $mail (@mailinfo) {
193 my ($file, @rcpt) = split(/\s+/, $mail);
194 open (DOMAIL, ">>$config{domailfile}");
195 print DOMAIL "$config{mailcmd} ";
196 foreach my $rcpt (@rcpt) {
197 print DOMAIL "'$rcpt' ";
199 print DOMAIL "<$file && rm $file ; $config{sleepcmd}\n";
201 or print STDERR "\n\n", UVmessage::get("SENDMAIL_ERRCLOSEDOMAIL"), "\n";
203 chmod(0700, $config{domailfile});
204 system($config{domailfile});
208 opendir (DIR, $config{tmpdir});
209 my @files = grep (/^ack\.\d+/, readdir (DIR));
211 return 0 if (@files);
213 unlink $config{controlfile} or print STDERR "\n\n",
214 UVmessage::get("SENDMAIL_ERRDELCONTROL", (FILE => $config{controlfile})), "\n";
216 unless ($config{smtp}) {
217 unlink $config{domailfile} or print STDERR "\n\n",
218 UVmessage::get("SENDMAIL_ERRDELCONTROL", (FILE => $config{domailfile})), "\n";
224 ##############################################################################
225 # Encodes a string for use in mail headers #
227 # Parameters: $text = string to encode. #
228 # Returns: $newtext = encoded string. #
229 ##############################################################################
233 my @words = split(/ /, $text);
237 foreach my $word (@words) {
241 if ($word =~ /[\x7F-\xFF]/) {
242 $encword = MIME::Words::encode_mimeword($word, 'Q', 'ISO-8859-1');
243 } elsif (length($word) > 75) {
244 $encword = MIME::Words::encode_mimeword($word, 'Q', 'us-ascii');
249 # no more than 75 chars per line allowed
250 if (length($encword) > 75) {
252 if ($encword =~ /(^=\?[-\w]+\?\w\?)(.{55}.*?)((=.{2}|[^=]{3}).*\?=)$/) {
253 addword($1 . $2 . '?=', \$line, \@lines, $sameword);
256 addword($encword, \$line, \@lines, $sameword);
262 addword($encword, \$line, \@lines, $sameword);
266 my $delim = (@lines) ? ' ' : '';
267 push(@lines, $delim . $line) if ($line);
268 return join('', @lines);
272 ##############################################################################
273 # Adds a word to a MIME encoded string, inserts linefeed if necessary #
276 # $word = word to add #
277 # $line = current line #
278 # $lines = complete text (without current line) #
279 # $sameword = boolean switch, indicates that this is another part of #
280 # the last word (for encoded words > 75 chars) #
281 ##############################################################################
284 my ($word, $line, $lines, $sameword) = @_;
286 # If the passed fragment is a new word (and not another part of the
287 # previous): Check if it is MIME encoded
288 if (!$sameword && $word =~ /^(=\?[^\?]+?\?[QqBb]\?)(.+\?=[^\?]*)$/) {
290 # Word is encoded, save without the MIME header
291 # (e.g. "t=E4st?=" instead of "?iso-8859-1?q?t=E4st?=")
295 if ($$line =~ /^(=\?[^\?]+\?[QqBb]\?)(.+)\?=$/) {
296 # Previous word was encoded, too:
297 # Delete the trailing "?=" and insert an underline character (=space)
298 # (space between to encoded words is ignored)
299 if ($1 eq $charset) {
300 if (length($1.$2)+length($newword)>75) {
301 my $delim = (@$lines) ? ' ' : '';
302 push(@$lines, "$delim$1$2_?=\n");
305 $$line = $1 . $2 . '_' . $newword;
308 if (length("$$line $word")>75) {
309 my $delim = (@$lines) ? ' ' : '';
310 push(@$lines, "$delim$1$2_?=\n");
313 $$line = "$1$2_?= $word";
320 # New word is not encoded: simply append it, but check for line length
321 # and add a newline if necessary
322 if (length($$line) > 0) {
323 if (length($$line) + length($word) >= 75) {
324 my $delim = (@$lines) ? ' ' : '';
325 push(@$lines, "$delim$$line\n");