Commit | Line | Data |
---|---|---|
ac7e2c54 TH |
1 | #!/usr/bin/perl -w |
2 | ||
3 | ############################################################################### | |
4 | # UseVoteGer 4.09 Wahldurchfuehrung | |
5 | # (c) 2001-2005 Marc Langer <uv@marclanger.de> | |
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 | # The script reads usenet vote ballots from mailbox files. The format | |
12 | # can be set by changing the option "mailstart". | |
13 | # | |
14 | # Many thanks to: | |
15 | # - Ron Dippold (Usevote 3.0, 1993/94) | |
16 | # - Frederik Ramm (German translation, 1994) | |
17 | # - Wolfgang Behrens (UseVoteGer 3.1, based on Frederik's translation, 1998/99) | |
18 | # - Cornell Binder for some good advice and code fragments | |
19 | # | |
20 | # This is a complete rewrite of UseVoteGer 3.1 in Perl (former versions were | |
21 | # written in C). Not all functions of Usevote/UseVoteGer 3.x are implemented! | |
22 | ############################################################################### | |
23 | ||
24 | use strict; | |
25 | use Getopt::Long; | |
26 | use Text::Wrap qw(wrap $columns); | |
27 | use FindBin qw($Bin); | |
28 | use lib $Bin; | |
29 | use UVconfig; | |
30 | use UVmenu; | |
31 | use UVmessage; | |
32 | use UVreadmail; | |
33 | use UVsendmail; | |
34 | use UVrules; | |
35 | use UVtemplate; | |
36 | ||
37 | my $clean = 0; | |
38 | my %opt_ctl = (); | |
39 | ||
40 | print "\n$usevote_version Wahldurchfuehrung - (c) 2001-2005 Marc Langer\n\n"; | |
41 | ||
42 | # unknown parameters remain in @ARGV (for "help") | |
43 | Getopt::Long::Configure(qw(pass_through bundling)); | |
44 | ||
45 | # Put known parameters in %opt_ctl | |
46 | GetOptions(\%opt_ctl, qw(test t config-file=s c=s)); | |
47 | ||
48 | # Get name auf config file (default: usevote.cfg) and read it | |
49 | my $cfgfile = $opt_ctl{'config-file'} || $opt_ctl{c} || "usevote.cfg"; | |
50 | ||
51 | # test mode? (default: no) | |
52 | my $test_only = $opt_ctl{test} || $opt_ctl{t} || 0; | |
53 | ||
54 | if (@ARGV){ | |
55 | # additional parameters passed | |
56 | ||
57 | if ($ARGV[0] eq "clean") { | |
58 | $clean = 1; | |
59 | } else { | |
60 | # print help and exit program | |
61 | help(); | |
62 | } | |
63 | } | |
64 | ||
65 | UVconfig::read_config($cfgfile, 1); # read config file, redirect errors to log | |
66 | UVrules::read_rulefile(); # read rules from file | |
67 | ||
68 | # read list of suspicious mail addresses from file | |
69 | my @bad_addr = UVconfig::read_badaddr(); | |
70 | ||
71 | # option -t used? | |
72 | if ($test_only) { | |
73 | UVconfig::test_config(); | |
74 | exit 0; | |
75 | } | |
76 | ||
77 | # check for lock file | |
78 | if (-e $config{lockfile}) { | |
79 | my $lockfile = $config{lockfile}; | |
80 | ||
81 | # don't delete lockfile in END block ;-) | |
82 | $config{lockfile} = ''; | |
83 | ||
84 | # exit | |
85 | die UVmessage::get("ERR_LOCK", (FILE=>$lockfile)) . "\n\n"; | |
86 | } | |
87 | ||
88 | # safe exit (delete lockfile) | |
89 | $SIG{QUIT} = 'sighandler'; | |
90 | $SIG{INT} = 'sighandler'; | |
91 | $SIG{KILL} = 'sighandler'; | |
92 | $SIG{TERM} = 'sighandler'; | |
93 | $SIG{HUP} = 'sighandler'; | |
94 | ||
95 | # create lock file | |
96 | open (LOCKFILE, ">$config{lockfile}"); | |
97 | close (LOCKFILE); | |
98 | ||
99 | # Set columns for Text::Wrap | |
100 | $columns = $config{rightmargin}; | |
101 | ||
102 | # check for tmp and archive directory | |
103 | unless (-d $config{archivedir}) { | |
104 | mkdir ($config{archivedir}, 0700) | |
105 | or die UVmessage::get("ERR_MKDIR", (DIR=>$config{archivedir})) . "$!\n\n"; | |
106 | } | |
107 | ||
108 | unless (-d $config{tmpdir}) { | |
109 | mkdir ($config{tmpdir}, 0700) | |
110 | or die UVmessage::get("ERR_MKDIR", (DIR=>$config{tmpdir})) . "$!\n\n"; | |
111 | } | |
112 | ||
113 | if ($clean) { | |
114 | # Program has been startet with "clean" option: | |
115 | # save votes and send out acknowledge mails | |
116 | make_clean(); | |
117 | ||
118 | } else { | |
119 | # normal processing | |
120 | ||
121 | # generate file names for result file | |
122 | # normally unixtime is sufficient, if it is not unique append our PID | |
123 | my $ext = time; | |
124 | ||
125 | opendir (TMP, $config{tmpdir}); | |
126 | my @tmpfiles = readdir (DIR); | |
127 | closedir (TMP); | |
128 | opendir (FERTIG, $config{archivedir}); | |
129 | my @fertigfiles = readdir (FERTIG); | |
130 | closedir (FERTIG); | |
131 | ||
132 | # append PID if necessary | |
133 | $ext .= "-$$" if (grep (/$ext/, @tmpfiles) || grep (/$ext/, @fertigfiles)); | |
134 | ||
135 | my $thisresult = "ergebnis-" . $ext; | |
136 | my $thisvotes = "stimmen-" . $ext; | |
137 | ||
138 | # POP3 not activated: rename votes file | |
139 | unless ($config{pop3}) { | |
140 | print UVmessage::get("VOTE_RENAMING_MAILBOX"), "\n"; | |
141 | rename ($config{votefile}, "$config{tmpdir}/$thisvotes") | |
142 | or die UVmessage::get("ERR_RENAME_MAILFILE") . "$!\n\n"; | |
143 | ||
144 | # wait, so that current mail deliveries can finalize | |
145 | sleep 2; | |
146 | } | |
147 | ||
148 | # open results file | |
149 | open (RESULT, ">>$config{tmpdir}/$thisresult") | |
150 | or die UVmessage::get("VOTE_WRITE_RESULTS", (FILE=>$thisresult)) . "\n\n"; | |
151 | ||
152 | # read votes and process them | |
153 | # for each mail pass a reference to the sub to be called | |
154 | my $count = UVreadmail::process("$config{tmpdir}/$thisvotes", \&process_vote, 0); | |
155 | ||
156 | close (RESULT) | |
157 | or print STDERR UVmessage::get("VOTE_CLOSE_RESULTS", (FILE=>$thisresult)) . "\n"; | |
158 | ||
159 | # no mails: exit here | |
160 | unless ($count) { | |
161 | print UVmessage::get("VOTE_NO_VOTES") . "\n\n"; | |
162 | exit 0; | |
163 | } | |
164 | ||
165 | if ($config{onestep}) { | |
166 | # everything should be done in one step | |
167 | print "\n" . UVmessage::get("VOTE_NUM_VOTES", (COUNT=>$count)) . "\n"; | |
168 | make_clean(); | |
169 | ||
170 | } else { | |
171 | ||
172 | print "\n", UVmessage::get("VOTE_NOT_SAVED", (COUNT=>$count)), "\n", | |
173 | wrap('', '', UVmessage::get("VOTE_FIRSTRUN")), "\n\n"; | |
174 | } | |
175 | } | |
176 | ||
177 | exit 0; | |
178 | ||
179 | END { | |
180 | close (STDERR); | |
181 | ||
182 | # delete lockfile | |
183 | unlink $config{lockfile} if ($config{lockfile}); | |
184 | ||
185 | if (-s $config{errorfile}) { | |
186 | # errors ocurred | |
187 | print '*' x $config{rightmargin}, "\n", | |
188 | UVmessage::get("VOTE_ERRORS",(FILE => $config{errorfile})), "\n", | |
189 | '*' x $config{rightmargin}, "\n\n"; | |
190 | open (ERRFILE, "<$config{errorfile}"); | |
191 | print <ERRFILE>; | |
192 | close (ERRFILE); | |
193 | print "\n"; | |
194 | } else { | |
195 | unlink ($config{errorfile}); | |
196 | } | |
197 | } | |
198 | ||
199 | ||
200 | sub sighandler { | |
201 | my ($sig) = @_; | |
202 | die "\n\nSIG$sig: deleting lockfile and exiting\n\n"; | |
203 | } | |
204 | ||
205 | ||
206 | ############################################################################## | |
207 | # Evaluation of a vote mail # | |
208 | # Called from UVreadmail::process() for each mail. # | |
209 | # Parameters: voter address and name, date header of the vote mail (strings) # | |
210 | # complete header (reference to array), body (ref. to strings) # | |
211 | ############################################################################## | |
212 | ||
213 | sub process_vote { | |
214 | my ($voter_addr, $voter_name, $h_date, $entity, $body) = @_; | |
215 | ||
216 | my @header = split(/\n/, $entity->stringify_header); | |
217 | my $head = $entity->head; | |
218 | my $msgid = $head->get('Message-ID'); | |
219 | chomp($msgid) if ($msgid); | |
220 | ||
221 | my @votes = (); # the votes | |
222 | my @set; # interactively changed fields | |
223 | my @errors = (); # recognized errors (show menu for manual action) | |
224 | my $onevote = 0; # 0=no votes, 1=everything OK, 2=vote cancelled | |
225 | my $voteerror = ""; # error message in case of invalid vote | |
226 | my $ballot_id = ""; # ballot id (German: Wahlscheinkennung) | |
227 | ||
228 | # found address? | |
229 | if ($voter_addr) { | |
230 | # search for suspicious addresses | |
231 | foreach my $element (@bad_addr) { | |
232 | if ($voter_addr =~ /^$element/) { | |
233 | push (@errors, 'SuspiciousAccount'); | |
234 | last; | |
235 | } | |
236 | } | |
237 | } else { | |
238 | # found no address in mail (perhaps violates RFC?) | |
239 | push (@errors, 'InvalidAddress'); | |
240 | } | |
241 | ||
242 | # personalized ballots? | |
243 | if ($config{personal}) { | |
244 | if ($$body =~ /$config{ballotidtext}\s+([a-z0-9]+)/) { | |
245 | $ballot_id = $1; | |
246 | # Address registered? ($ids is set in UVconfig.pm) | |
247 | if ($ids{$voter_addr}) { | |
248 | push (@errors, 'WrongBallotID') if ($ids{$voter_addr} ne $ballot_id); | |
249 | } else { | |
250 | push (@errors, 'AddressNotRegistered'); | |
251 | } | |
252 | } else { | |
253 | push (@errors, 'NoBallotID'); | |
254 | } | |
255 | } | |
256 | ||
257 | # evaluate vote strings | |
258 | for (my $n=0; $n<@groups; $n++) { | |
259 | ||
260 | # counter starts at 1 in ballot | |
261 | my $votenum = $n+1; | |
262 | my $vote = ""; | |
263 | ||
264 | # a line looks like this: #1 [ VOTE ] Group | |
265 | # matching only on number and vote, because of line breaks likely | |
266 | # inserted by mail programs | |
267 | ||
268 | # duplicate vote? | |
269 | if ($$body =~ /#$votenum\W*?\[\s*?(\w+)\s*?\].+?#$votenum\W*?\[\s*?(\w+)\s*?\]/s) { | |
270 | push (@errors, "DuplicateVote") if ($1 ne $2); | |
271 | } | |
272 | ||
273 | # this matches on a single appearance: | |
274 | if ($$body =~ /#$votenum\W*?\[(.+)\]/) { | |
275 | # one or more vote strings were found | |
276 | $onevote = 1; | |
277 | my $votestring = $1; | |
278 | if ($votestring =~ /^\W*$config{ja_stimme}\W*$/i) { | |
279 | $vote = "J"; | |
280 | } elsif ($votestring =~ /^\W*$config{nein_stimme}\W*$/i) { | |
281 | $vote = "N"; | |
282 | } elsif ($votestring =~ /^\W*$config{enth_stimme}\W*$/i) { | |
283 | $vote = "E"; | |
284 | } elsif ($votestring =~ /^\s*$/) { | |
285 | # nothing has been entered between the [ ] | |
286 | $vote = "E"; | |
287 | } elsif ($votestring =~ /^\W*$config{ann_stimme}\W*$/i) { | |
288 | $vote = "A"; | |
289 | $onevote = 2; # Cancelled vote: set $onevote to 2 | |
290 | } elsif (!$votes[$n]) { | |
291 | # vote not recognized | |
292 | $vote = "E"; | |
293 | push (@errors, 'UnrecognizedVote #' . $votenum . "#$votestring"); | |
294 | } | |
295 | push (@votes, $vote); | |
296 | } else { | |
297 | # vote not found | |
298 | push (@votes, 'E'); | |
299 | push (@errors, 'UnrecognizedVote #' . $votenum . '#(keine Stimmabgabe fuer "' | |
300 | . $groups[$n] . '" gefunden)'); | |
301 | } | |
302 | } | |
303 | ||
304 | if ($onevote == 0) { | |
305 | push (@errors, "NoVote") unless ($onevote); | |
306 | } elsif ($onevote == 1) { | |
307 | # check rules | |
308 | my $rule = UVrules::rule_check(\@votes); | |
309 | push (@errors, "ViolatedRule #$rule") if ($rule); | |
310 | } else { | |
311 | # cancelled vote: replace all votes with an A | |
312 | @votes = split(//, 'A' x scalar @votes); | |
313 | } | |
314 | ||
315 | # Evaluate Data Protection Law clause (not on cancelled votes) | |
316 | if ($config{bdsg} && $onevote<2) { | |
317 | ||
318 | # Text in ballot complete and clause accepted? | |
319 | # Should read like this: #a [ STIMME ] Text | |
320 | # (Text is configurable in usevote.cfg) | |
321 | unless ($$body =~ /$bdsg_regexp/s && | |
322 | $$body =~ /#a\W*?\[\W*?$config{ja_stimme}\W*?\]\W*?$bdsg2_regexp/is) { | |
323 | ||
324 | push (@errors, 'InvalidBDSG'); | |
325 | } | |
326 | } | |
327 | ||
328 | # Name in body? | |
329 | if ($$body =~ /($config{nametext}|$config{nametext2})( |\t)*(\S.+?)$/m) { | |
330 | $voter_name = $3; | |
331 | $voter_name =~ s/^\s+//; # strip leading spaces | |
332 | $voter_name =~ s/\s+$//; # strip trailing spaces | |
333 | } | |
334 | ||
335 | if ($voter_name) { | |
336 | # Name invalid? | |
337 | push (@errors, 'InvalidName') unless ($voter_name =~ /$config{name_re}/); | |
338 | } else { | |
339 | # no name found: | |
340 | push (@errors, 'NoName') unless ($voter_name); | |
341 | } | |
342 | ||
343 | # Errors encountered? | |
344 | if (@errors) { | |
345 | my $res = UVmenu::menu(\@votes, \@header, $body, \$voter_addr, \$voter_name, | |
346 | \$ballot_id, \@set, \@errors); | |
347 | return 0 if ($res eq 'i'); # "Ignore": Ignore vote, don't save | |
348 | ||
349 | my $tpl; | |
350 | ||
351 | # Check Ballot ID stuff | |
352 | if ($config{personal}) { | |
353 | if ($ballot_id) { | |
354 | if ($ids{$voter_addr}) { | |
355 | if ($ids{$voter_addr} ne $ballot_id) { | |
356 | $voteerror = UVmessage::get("VOTE_INVALID_BALLOTID"); | |
357 | $tpl = $config{tpl_wrong_ballotid}; | |
358 | } | |
359 | } else { | |
360 | $voteerror = UVmessage::get("VOTE_UNREGISTERED_ADDRESS"); | |
361 | $tpl = $config{tpl_addr_reg}; | |
362 | } | |
363 | } else { | |
364 | $voteerror = UVmessage::get("VOTE_MISSING_BALLOTID"); | |
365 | $tpl = $config{tpl_no_ballotid}; | |
366 | } | |
367 | ||
368 | # generate error mail (if error occurred) | |
369 | if ($tpl) { | |
370 | my $template = UVtemplate->new(); | |
371 | $template->setKey('head' => $entity->stringify_header); | |
372 | $template->setKey('body' => $$body); | |
373 | my $msg = $template->processTemplate($tpl); | |
374 | UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack}); | |
375 | } | |
376 | } | |
377 | } | |
378 | ||
379 | # Check rules and send error mail unless rule violation was ignored in the use menu | |
380 | # or another error was detected | |
381 | if (grep(/ViolatedRule/, @errors) && !$voteerror && (my $rule = UVrules::rule_check(\@votes))) { | |
382 | $voteerror = UVmessage::get("VOTE_VIOLATED_RULE", (RULE=>$rule)); | |
383 | my $template = UVtemplate->new(); | |
384 | $template->setKey('body' => $$body); | |
385 | $template->setKey('rules' => UVrules::rule_print($rule-1)); | |
386 | my $msg = $template->processTemplate($config{tpl_rule_violated}); | |
387 | UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack}); | |
388 | } | |
389 | ||
390 | if (!$voteerror && @errors) { | |
391 | ||
392 | # turn errors array into hash | |
393 | ||
394 | my %error; | |
395 | foreach my $error (@errors) { | |
396 | $error{$error} = 1; | |
397 | } | |
398 | ||
399 | # Check uncorrected errors | |
400 | if ($error{InvalidBDSG}) { | |
401 | my $template = UVtemplate->new(); | |
402 | my $msg = $template->processTemplate($config{tpl_bdsg_error}); | |
403 | UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack}); | |
404 | return 0; | |
405 | } elsif ($error{NoVote}) { | |
406 | $voteerror = UVmessage::get("VOTE_NO_VOTES"); | |
407 | my $template = UVtemplate->new(); | |
408 | $template->setKey('body' => $$body); | |
409 | my $msg = $template->processTemplate($config{tpl_no_votes}); | |
410 | UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack}); | |
411 | } elsif ($error{SuspiciousAccount}) { | |
412 | $voteerror = UVmessage::get("VOTE_INVALID_ACCOUNT"); | |
413 | my $template = UVtemplate->new(); | |
414 | $template->setKey('head' => $entity->stringify_header); | |
415 | $template->setKey('body' => $$body); | |
416 | my $msg = $template->processTemplate($config{tpl_invalid_account}); | |
417 | UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack}); | |
418 | } elsif ($error{InvalidAddress}) { | |
419 | $voteerror = UVmessage::get("VOTE_INVALID_ADDRESS"); | |
420 | } elsif ($error{InvalidName}) { | |
421 | $voteerror = UVmessage::get("VOTE_INVALID_REALNAME"); | |
422 | my $template = UVtemplate->new(); | |
423 | $template->setKey('head' => $entity->stringify_header); | |
424 | $template->setKey('body' => $$body); | |
425 | my $msg = $template->processTemplate($config{tpl_invalid_name}); | |
426 | UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack}); | |
427 | } elsif ($error{DuplicateVote}) { | |
428 | $voteerror = UVmessage::get("VOTE_DUPLICATES"); | |
429 | my $template = UVtemplate->new(); | |
430 | $template->setKey('head' => $entity->stringify_header); | |
431 | $template->setKey('body' => $$body); | |
432 | my $msg = $template->processTemplate($config{tpl_multiple_votes}); | |
433 | UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack}); | |
434 | } | |
435 | } | |
436 | ||
437 | # check voter name | |
438 | unless ($voter_name || $voteerror) { | |
439 | $voteerror = UVmessage::get("VOTE_MISSING_NAME"); | |
440 | my $template = UVtemplate->new(); | |
441 | $template->setKey('head' => $entity->stringify_header); | |
442 | $template->setKey('body' => $$body); | |
443 | my $msg = $template->processTemplate($config{tpl_invalid_name}); | |
444 | UVsendmail::mail($voter_addr, "Fehler", $msg, $msgid) if ($config{voteack}); | |
445 | } | |
446 | ||
447 | # set mark for cancelled vote | |
448 | $onevote = 2 if ($votes[0] eq 'A'); | |
449 | ||
450 | # create comment line for result file | |
451 | my $comment; | |
452 | if ($config{personal}) { | |
453 | # Personalized Ballots: insert ballot id | |
454 | $comment = "($ballot_id)"; | |
455 | } else { | |
456 | $comment = "()"; | |
457 | } | |
458 | ||
459 | if (@set) { | |
460 | $comment .= ' '.UVmessage::get("VOTE_FILE_COMMENT", (FIELDS => join(', ', @set))); | |
461 | } | |
462 | ||
463 | # write result file | |
464 | print RESULT "A: $voter_addr\n"; | |
465 | print RESULT "N: $voter_name\n"; | |
466 | print RESULT "D: $h_date\n"; | |
467 | print RESULT "K: $comment\n"; | |
468 | ||
469 | # invalid vote? | |
470 | if ($voteerror) { | |
471 | print RESULT "S: ! $voteerror\n"; | |
472 | ||
473 | # cancelled vote? | |
474 | } elsif ($onevote == 2) { | |
475 | print RESULT "S: * Annulliert\n"; | |
476 | ||
477 | if ($config{voteack}) { | |
478 | # send cancellation acknowledge | |
479 | my $template = UVtemplate->new(); | |
480 | my $msg = $template->processTemplate($config{tpl_cancelled}); | |
481 | UVsendmail::mail($voter_addr, "Bestaetigung", $msg, $msgid); | |
482 | } | |
483 | ||
484 | } else { | |
485 | print RESULT "S: ", join ("", @votes), "\n"; | |
486 | ||
487 | # send acknowledge mail? | |
488 | if ($config{voteack}) { | |
489 | ||
490 | my $template = UVtemplate->new(); | |
491 | $template->setKey(ballotid => $ballot_id); | |
492 | $template->setKey(address => $voter_addr); | |
493 | $template->setKey(name => $voter_name); | |
494 | ||
495 | for (my $n=0; $n<@groups; $n++) { | |
496 | my $vote = $votes[$n]; | |
497 | $vote =~ s/^J$/JA/; | |
498 | $vote =~ s/^N$/NEIN/; | |
499 | $vote =~ s/^E$/ENTHALTUNG/; | |
500 | $template->addListItem('groups', pos=>$n+1, vote=>$vote, group=>$groups[$n]); | |
501 | } | |
502 | ||
503 | my $msg = $template->processTemplate($config{'tpl_ack_mail'}); | |
504 | UVsendmail::mail($voter_addr, "Bestaetigung", $msg, $msgid); | |
505 | } | |
506 | } | |
507 | } | |
508 | ||
509 | ||
510 | ############################################################################## | |
511 | # Send out acknowledge mails and tidy up (we're called as "uvvote.pl clean") # | |
512 | ############################################################################## | |
513 | ||
514 | sub make_clean { | |
515 | ||
516 | # send mails | |
517 | UVsendmail::send(); | |
518 | ||
519 | print UVmessage::get("INFO_TIDY_UP"), "\n"; | |
520 | ||
521 | # search unprocessed files | |
522 | opendir (DIR, $config{tmpdir}); | |
523 | my @files = readdir DIR; | |
524 | closedir (DIR); | |
525 | ||
526 | my @resultfiles = grep (/^ergebnis-/, @files); | |
527 | my @votefiles = grep (/^stimmen-/, @files); | |
528 | ||
529 | unless (@resultfiles) { | |
530 | print wrap('', '', UVmessage::get("VOTE_NO_NEW_RESULTS")), "\n\n"; | |
531 | return 0; | |
532 | } | |
533 | ||
534 | foreach my $thisresult (@resultfiles) { | |
535 | chmod (0400, "$config{tmpdir}/$thisresult"); | |
536 | rename "$config{tmpdir}/$thisresult", "$config{archivedir}/$thisresult" | |
537 | or die UVmessage::get("VOTE_MOVE_RESULTFILE", (FILE=>$thisresult)) . "$!\n\n"; | |
538 | } | |
539 | ||
540 | foreach my $thisvotes (@votefiles) { | |
541 | chmod (0400, "$config{tmpdir}/$thisvotes"); | |
542 | rename "$config{tmpdir}/$thisvotes", "$config{archivedir}/$thisvotes" | |
543 | or die UVmessage::get("VOTE_MOVE_VOTEFILE", (FILE=>$thisvotes)) . "$!\n\n"; | |
544 | } | |
545 | ||
546 | print UVmessage::get("VOTE_CREATING_RESULTS", (FILENAME=>$config{resultfile})), "\n"; | |
547 | ||
548 | # search all result files | |
549 | opendir (DIR, "$config{archivedir}/"); | |
550 | @files = grep (/^ergebnis-/, readdir (DIR)); | |
551 | closedir (DIR); | |
552 | ||
553 | # Create complete result from all single result files. | |
554 | # The resulting file (ergebnis.alle) is overwritten as there could have been | |
555 | # made changes in the single result files | |
556 | open(RESULT, ">$config{resultfile}"); | |
557 | foreach my $file (sort @files) { | |
558 | open(THISRESULT, "<$config{archivedir}/$file"); | |
559 | print RESULT join('', <THISRESULT>); | |
560 | close(THISRESULT); | |
561 | } | |
562 | close(RESULT); | |
563 | ||
564 | print "\n"; | |
565 | ||
566 | } | |
567 | ||
568 | ||
569 | ############################################################################## | |
570 | # Print help text (options and syntax) on -h or --help # | |
571 | ############################################################################## | |
572 | ||
573 | sub help { | |
574 | print <<EOF; | |
575 | Usage: uvvote.pl [-c config_file] [-t] | |
576 | uvvote.pl [-c config_file] clean | |
577 | uvvote.pl -h | |
578 | ||
579 | Liest Mailboxen aus einer Datei oder per POP3 ein wertet die Mails | |
580 | als Stimmzettel aus. Erst beim Aufruf mit der Option "clean" werden | |
581 | die Ergebnisse endgueltig gespeichert und die Bestaetigungsmails | |
582 | verschickt. | |
583 | ||
584 | -c config_file liest die Konfiguration aus config_file | |
585 | (usevote.cfg falls nicht angegeben) | |
586 | ||
587 | -t, --test fuehrt einen Test der Konfiguration durch und | |
588 | gibt das ermittelte Ergebnis aus. | |
589 | ||
590 | -h, --help zeigt diesen Hilfetext an | |
591 | ||
592 | EOF | |
593 | ||
594 | exit 0; | |
595 | } |