tpl/ack-mail: Left align votetaker.
[usenet/usevote.git] / uvcfv.pl
CommitLineData
ac7e2c54
TH
1#!/usr/bin/perl -w
2
3###############################################################################
ef295458
TH
4# UseVoteGer 4.09 Personalisierte Wahlscheine
5# (c) 2001-2005 Marc Langer <uv@marclanger.de>
ac7e2c54
TH
6#
7# This script package is free software; you can redistribute it and/or
8# modify it under the terms of the GNU Public License as published by the
9# Free Software Foundation.
10#
11# Use this script to read mails and send back a CfV with unique ballot id
12#
13# Many thanks to:
14# - Ron Dippold (Usevote 3.0, 1993/94)
15# - Frederik Ramm (German translation, 1994)
16# - Wolfgang Behrens (UseVoteGer 3.1, based on Frederik's translation, 1998/99)
17# - Cornell Binder for some good advice and code fragments
18#
19# This is a complete rewrite of UseVoteGer 3.1 in Perl (former versions were
20# written in C). Not all functions of Usevote/UseVoteGer 3.x are implemented!
21###############################################################################
22
23use strict;
24use Getopt::Long;
25use Digest::MD5 qw(md5_hex);
26use Text::Wrap qw(wrap $columns);
27use FindBin qw($Bin);
28use lib $Bin;
29use UVconfig;
30use UVmenu;
31use UVmessage;
32use UVreadmail;
33use UVsendmail;
34use UVtemplate;
35
36my %opt_ctl = ();
37
ef295458 38print "\n$usevote_version Personalisierte Wahlscheine - (c) 2001-2005 Marc Langer\n\n";
ac7e2c54
TH
39
40# unknown parameters remain in @ARGV (for "help")
41Getopt::Long::Configure(qw(pass_through bundling));
42
43# Put known parameters in %opt_ctl
44GetOptions(\%opt_ctl, qw(test t config-file=s c=s));
45
46# test mode? (default: no)
47my $test_only = $opt_ctl{test} || $opt_ctl{t} || 0;
48
49# # Additional parameters or invalid options? Show help and exit.
50help() if (@ARGV);
51
52# Get name auf config file (default: usevote.cfg) and read it
53my $cfgfile = $opt_ctl{'config-file'} || $opt_ctl{c} || "usevote.cfg";
54UVconfig::read_config($cfgfile);
55
56# Set columns for Text::Wrap
57$columns = $config{rightmargin};
58
59# read list of suspicious mail addresses from file
60my @bad_addr = UVconfig::read_badaddr();
61
62# exit if option "personal=1" in config file not set
63unless ($config{personal}) {
64 die wrap ('', '', UVmessage::get("ERR_NOTPERSONAL", (CFGFILE => $cfgfile))) . "\n\n";
65}
66
67# option -t used?
68if ($test_only) {
69 print_ballot();
70 exit 0;
71}
72
73# check for lock file
74if (-e $config{lockfile}) {
75 my $lockfile = $config{lockfile};
76
77 # don't delete lockfile in END block ;-)
78 $config{lockfile} = '';
79
80 # exit
81 die UVmessage::get("ERR_LOCK", (FILE=>$lockfile)) . "\n\n";
82}
83
84# safe exit (delete lockfile)
85$SIG{QUIT} = 'sighandler';
86$SIG{INT} = 'sighandler';
87$SIG{KILL} = 'sighandler';
88$SIG{TERM} = 'sighandler';
89$SIG{HUP} = 'sighandler';
90
91# create lock file
92open (LOCKFILE, ">$config{lockfile}");
93close (LOCKFILE);
94
95# check for tmp directory and domail file
96unless (-d $config{tmpdir}) {
97 mkdir ($config{tmpdir}, 0700)
98 or die UVmessage::get("ERR_MKDIR", (DIR => $config{tmpdir})) . "\n$!\n\n";
99}
100
101# generate filename for mail archive
102# normally unixtime is sufficient, if it is not unique append a number
103my $file = my $base = "anforderung-" . time();
104my $count = 0;
105while ($count<1000 && (-e "$config{archivedir}/$file" || -e "$config{tmpdir}/$file")) {
106 $file = "$base-" . ++$count;
107}
108die UVmessage::get("ERR_FILE_CREATION") . "\n\n" if ($count == 1000);
109
110unless ($config{pop3}) {
111 rename ($config{requestfile}, "$config{tmpdir}/$file")
112 or die UVmessage::get("ERR_RENAME_MAILFILE") . "$!\n\n";
113}
114
115# wait, so that current mail deliveries can finalize
116sleep 2;
117
118# initiliaze random number generator
119srand;
120
121# read votes and process them
122# for each mail pass a reference to the sub to be called
123# The third parameter "1" shows that it is called from uvcfv.pl
124$count = UVreadmail::process("$config{tmpdir}/$file", \&process_request, 1);
125print "\n", UVmessage::get("CFV_NUMBER", (COUNT => $count)), "\n\n";
126UVsendmail::send();
127
128print UVmessage::get("INFO_TIDY_UP") . "\n\n";
129rename("$config{tmpdir}/$file", "$config{archivedir}/$file");
130chmod (0400, "$config{archivedir}/$file");
131
132exit 0;
133
134
135##############################################################################
136# Evaluate a ballot request #
137# Called from UVreadmail::process() for every mail #
138# Parameters: Voter address and name, date header of vote mail (strings), #
139# complete header and body (references to Strings) #
140##############################################################################
141
142sub process_request {
143 my ($voter_addr, $voter_name, $h_date, $entity, $body) = @_;
144
145 my @header = split(/\n/, $entity->stringify_header);
146 my $head = $entity->head;
147 my $msgid = $head->get('Message-ID');
148 chomp($msgid) if ($msgid);
149
150 # found address?
151 if ($voter_addr) {
152 # check for suspicious addresses
153 foreach my $element (@bad_addr) {
154 if ($voter_addr =~ /^$element/) {
155 my (@votes, @set, $ballot_id); # irrelevant, but necessary for UVmenu::menu()
156 my @errors = ('SuspiciousAccountBallot');
157 my $res = UVmenu::menu(\@votes, \@header, $body, \$voter_addr, \$voter_name, \$ballot_id, \@set, \@errors);
158
159 # "Ignore": don't deliver a ballot
160 return 0 if ($res eq 'i');
161 if (@errors) {
162 # send error mail if address hasn't been accepted
163 my $template = UVtemplate->new();
164 $template->setKey('head' => $entity->stringify_header);
165 $template->setKey('body' => $$body);
166 my $msg = $template->processTemplate($config{tpl_invalid_account});
167 UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid);
168 return 0;
169 }
170 last;
171 }
172 }
173 } else {
174
175 # no address found in mail (non-RFC compliant?)
176 my (@votes, @set, $ballot_id); # irrelevant, but necessary for UVmenu::menu()
177 my @errors = ('InvalidAddressBallot');
178 my $res = UVmenu::menu(\@votes, \@header, $body, \$voter_addr, \$voter_name, \$ballot_id, \@set, \@errors);
179
180 # "ignore" or address not ok: no ballot can be sent
181 return 0 if (@errors || $res eq 'i');
182 }
183
184 my $subject = UVmessage::get("CFV_SUBJECT");
185 my $template = UVtemplate->new();
186 my $ballot_id = "";
187
188 #if ($ballot_id ne $ids{$voter_addr}) {
189 if ($ids{$voter_addr}) {
190 $ballot_id = $ids{$voter_addr};
191 $template->setKey('alreadysent' => 1) if ($ballot_id = $ids{$voter_addr});
192 } else {
193 # generate new ballot id from the MD5 sum of header, body and a random value
194 $ballot_id = md5_hex($entity->stringify_header . $body . rand 65535);
195 $ids{$voter_addr} = $ballot_id;
196
197 # write ballot id to file
198 open(IDFILE, ">>$config{idfile}")
199 or die UVmessage::get("CFV_ERRWRITE", (FILE => $config{idfile})) . "\n\n";
200 print IDFILE "$voter_addr $ballot_id\n";
201 close(IDFILE) or die UVmessage::get("CFV_ERRCLOSE") . "\n\n";
202 }
203
204 $template->setKey('ballotid' => $ballot_id);
205 $template->setKey('address' => $voter_addr);
206 $template->setKey('bdsginfo' => $config{bdsginfo});
207
208 for (my $n=0; $n<@groups; $n++) {
209 $template->addListItem('groups', pos=>$n+1, group=>$groups[$n]);
210 }
211
212 my $msg = $template->processTemplate($config{'tpl_ballot_personal'});
213
214 # $config{voteaccount} is the Reply-To address:
215 UVsendmail::mail($voter_addr, $subject, $msg, $msgid, $config{voteaccount});
216
217}
218
219
220##############################################################################
221# Print dummy personalized ballot in STDOUT for checking purposes #
222# Called if command line argument -t is present #
223##############################################################################
224
225sub print_ballot {
226 my $template = UVtemplate->new();
227
228 # generate new ballot id
229 my $ballot_id = md5_hex(rand 65535);
230
231 $template->setKey('ballotid' => $ballot_id);
232 $template->setKey('address' => 'dummy@foo.invalid');
233 $template->setKey('bdsginfo' => $config{bdsginfo});
234
235 for (my $n=0; $n<@groups; $n++) {
236 $template->addListItem('groups', pos=>$n+1, group=>$groups[$n]);
237 }
238
239 my $msg = $template->processTemplate($config{'tpl_ballot_personal'});
240
241 print $msg, "\n";
242}
243
244
245##############################################################################
246# Handle Signals and delete lock files when exiting #
247##############################################################################
248
249END {
250 # delete lockfile
251 unlink $config{lockfile} if ($config{lockfile});
252}
253
254
255sub sighandler {
256 my ($sig) = @_;
257 die "\n\nSIG$sig: deleting lockfile and exiting\n\n";
258}
259
260
261##############################################################################
262# Print help text (options and syntax) on -h or --help #
263##############################################################################
264
265sub help {
266 print <<EOF;
267Usage: uvcfv.pl [-c config_file] [-t]
268 uvcfv.pl -h
269
270Liest Mailboxen ein und beantwortet alle Mails mit personalisierten CfVs.
271
272 -c config_file liest die Konfiguration aus config_file
273 (usevote.cfg falls nicht angegeben)
274
275 -t, --test gibt einen Dummy-Wahlschein fuer Pruefzwecke aus
276
277 -h, --help zeigt diesen Hilfetext an
278
279EOF
280
281 exit 0;
282}
This page took 0.024461 seconds and 4 git commands to generate.