tpl/ack-mail: Left align votetaker.
[usenet/usevote.git] / UVmenu.pm
1 # UVmenu: menu for interaction with the votetaker
2 # Used by uvvote.pl, uvcfv.pl, uvcount.pl
3  
4 package UVmenu;
5  
6 use strict;
7 use UVconfig;
8 use UVmessage;
9 use UVrules;
10 use vars qw($VERSION);
11
12 use Text::Wrap qw(wrap $columns);
13  
14 # Module version
15 $VERSION = "0.4";
16
17 ##############################################################################
18 # Menu for interaction with the votetaker                                    #
19 # Parameters: votes list and header (references to arrays)                   #
20 #             Body, Mailadress, Name, Ballot ID (references to strings)      #
21 #             List of newly set fields (reference to array)                  #
22 #             List of errors to correct (Array-Ref)                          #
23 # Return Values: 'w': proceed                                                #
24 #                'i': ignore (don't save vote)                               #
25 ##############################################################################
26
27 sub menu {
28   my ($votes, $header, $body, $addr, $name, $ballot_id, $set, $errors) = @_;
29   my $input = "";
30   my $voter_addr = $$addr || '';
31   my $voter_name = $$name || '';
32   my @newvotes = @$votes;
33   my $mailonly = 0;
34   my %errors;
35   $$ballot_id ||= '';
36
37   foreach my $error (@$errors) {
38
39     # unrecognized vote: extract group number und display warning
40     if ($error =~ /^UnrecognizedVote #(\d+)#(.+)$/) {
41       $errors{UnrecognizedVote} ||= UVmessage::get("MENU_UNRECOGNIZEDVOTE");
42       $errors{UnrecognizedVote} .= "\n  " . UVmessage::get("MENU_UNRECOGNIZED_LIST")
43                                           . " #$1: $2";
44
45     # violated rule: extract rule number and display warning
46     } elsif ($error =~ /^ViolatedRule #(\d+)$/) {
47       $errors{ViolatedRule} ||= UVmessage::get("MENU_VIOLATEDRULE", (RULE => "#$1"));
48
49     } else {
50       # special handling if called from uvballot.pl
51       $mailonly = 1 if ($error =~ s/Ballot$//);
52
53       # get error message for this error from messages.cfg
54       $errors{$error} = UVmessage::get("MENU_" . uc($error));
55     }
56   }
57
58   # This loop is only left by 'return'
59   while (1) {
60
61     system($config{clearcmd});
62     print UVmessage::get("MENU_PROBLEMS") . "\n";
63
64     foreach my $error (keys %errors) {
65       print "* $errors{$error}\n";
66     }
67
68     my $menucaption = UVmessage::get("MENU_CAPTION");
69     print "\n\n$menucaption\n";
70     print "=" x length($menucaption), "\n\n";
71     print "(1) ", UVmessage::get("MENU_SHOW_MAIL"), "\n\n",
72           UVmessage::get("MENU_CHANGE_PROPERTIES"), "\n",
73           "(2) ", UVmessage::get("MENU_ADDRESS"), " [$voter_addr]\n";
74
75     # don't print these options if called from uvcfv.pl
76     unless ($mailonly) {
77       print "(3) ", UVmessage::get("MENU_NAME"), " [$voter_name]\n";
78       print "(4) ", UVmessage::get("MENU_VOTES"), " [", @$votes, "]\n";
79       print "(5) ", UVmessage::get("MENU_BALLOT_ID"), " [$$ballot_id]\n"
80         if ($config{personal});
81       print "(6) ", UVmessage::get("MENU_BDSG"), "\n" if ($config{bdsg});
82     }
83
84     print "\n",
85           "(i) ", UVmessage::get("MENU_IGNORE"), "\n",
86           "(w) ", UVmessage::get("MENU_PROCEED"), "\n\n",
87           UVmessage::get("MENU_PROMPT");
88
89     do { $input = <STDIN>; } until ($input);
90     chomp $input;
91     print "\n";
92
93     # only accept 1, 2, i and w if called from uvcfv.pl
94     next if ($mailonly && $input !~ /^[12iw]$/i);
95
96     if ($input eq '1') {
97       system($config{clearcmd});
98       # ignore SIGPIPE (Bug in more and less)
99       $SIG{PIPE} = 'IGNORE';
100       open (MORE, "|$config{pager}");
101       print MORE join("\n", @$header), "\n\n", $$body, "\n";
102       close (MORE);
103       
104       print "\n", UVmessage::get("MENU_GETKEY");
105       $input = <STDIN>;
106
107     } elsif ($input eq '2') {
108       my $sel;
109       do {
110         print "[a] ", UVmessage::get("MENU_ADDRESS_OK"), "\n",
111               "[b] ", UVmessage::get("MENU_ADDRESS_CHANGE"), "\n",
112               "[c] ", UVmessage::get("MENU_ADDRESS_INVALID"), "\n\n",
113               UVmessage::get("MENU_PROMPT");
114         $sel = <STDIN>;
115       } until ($sel =~ /^[abc]$/i);
116       if ($sel =~ /^a$/i) {
117         delete $errors{SuspiciousAccount};
118         delete $errors{InvalidAddress};
119         next;
120       } elsif ($sel =~ /^c$/i) {
121         delete $errors{SuspiciousAccount};
122         $errors{InvalidAddress} = UVmessage::get("MENU_INVALIDADDRESS") . " " .
123                                   UVmessage::get("MENU_INVALIDADDRESS2");
124         next;
125       }
126         
127       do {
128         print "\n", UVmessage::get("MENU_ADDRESS_PROMPT"), " ";
129         $voter_addr = <STDIN>;
130         chomp ($voter_addr);
131       } until ($voter_addr);
132       $$addr = $voter_addr;
133       push (@$set, 'Adresse');
134       delete $errors{SuspiciousAccount};
135       delete $errors{InvalidAddress};
136       check_ballotid(\%errors, \$voter_addr, $ballot_id, \%ids);
137
138     } elsif ($input eq '3') {
139       my $sel;
140       do {
141         print "[a] ", UVmessage::get("MENU_NAME_OK"), "\n",
142               "[b] ", UVmessage::get("MENU_NAME_CHANGE"), "\n",
143               "[c] ", UVmessage::get("MENU_NAME_INVALID"), "\n\n",
144               UVmessage::get("MENU_PROMPT");
145         $sel = <STDIN>;
146       } until ($sel =~ /^[abc]$/i);
147       if ($sel =~ /^a$/i) {
148         delete $errors{InvalidName};
149         next;
150       } elsif ($sel =~ /^c$/i) {
151         $errors{InvalidName} = UVmessage::get("MENU_INVALIDNAME");
152         next;
153       }
154       print UVmessage::get("MENU_NAME"), ": ";
155       $voter_name = <STDIN>;
156       chomp ($voter_name);
157       $$name = $voter_name;
158       push (@$set, 'Name');
159       delete $errors{NoName};
160       delete $errors{InvalidName};
161
162       $errors{InvalidName} = UVmessage::get("MENU_INVALIDNAME")
163         unless ($voter_name =~ /$config{name_re}/);
164  
165     } elsif ($input eq '4') {
166       # set votes
167
168       my $sel;
169       do {
170         print "[a] ", UVmessage::get("MENU_VOTES_OK"), "\n",
171               "[b] ", UVmessage::get("MENU_VOTES_RESET"), "\n",
172               "[c] ", UVmessage::get("MENU_VOTES_INVALID"), "\n",
173               "[d] ", UVmessage::get("MENU_VOTES_CANCELLED"), "\n\n",
174               UVmessage::get("MENU_PROMPT");
175         $sel = <STDIN>;
176       } until ($sel =~ /^[abcd]$/i);
177       if ($sel =~ /^[ad]$/i) {
178         delete $errors{NoVote};
179         delete $errors{UnrecognizedVote};
180         delete $errors{ViolatedRule};
181         delete $errors{DuplicateVote};
182         if ($sel =~ /^d$/i) {
183           # cancelled vote: replace all votes with an A
184           @$votes = split(//, 'A' x scalar @groups);
185           push @$set, 'Stimmen';
186           # some errors are irrelevant when cancelling a vote:
187           delete $errors{InvalidName};
188           delete $errors{NoName};
189           delete $errors{InvalidBDSG};
190           delete $errors{InvalidAddress};
191           delete $errors{SuspiciousAccount};
192         }
193         next;
194       } elsif ($sel =~ /^c$/i) {
195         $errors{NoVote} = UVmessage::get("MENU_INVALIDVOTE");
196         next;
197       }
198
199       # Set columns for Text::Wrap
200       $columns = $config{rightmargin};
201       print "\n", wrap('', '', UVmessage::get("MENU_VOTES_REENTER_ASK")), "\n\n";
202       print UVmessage::get("MENU_VOTES_REENTER_LEGEND"), "\n";
203
204       for (my $n=0; $n<@groups; $n++) {
205         my $voteinput = "";
206         $votes->[$n] ||= 'E';
207
208         # repeat while invalid character entered
209         while (!($voteinput =~ /^[JNE]$/)) {
210           my $invalid = $#groups ? 0 : 1;
211           print UVmessage::get("MENU_VOTES_REENTER", (GROUP => $groups[$n]));
212           $voteinput = <STDIN>;
213           chomp $voteinput;
214           $voteinput ||= $votes->[$n];
215           $voteinput =~ tr/jne/JNE/;
216         }
217         
218         # valid input, save new votes
219         $newvotes[$n] = $voteinput;
220       } 
221
222       print "\n\n";
223       my $oldvotes = UVmessage::get("MENU_VOTES_REENTER_OLD");
224       my $newvotes = UVmessage::get("MENU_VOTES_REENTER_NEW");
225       my $oldlen = length($oldvotes);
226       my $newlen = length($newvotes);
227       my $maxlen = 1 + (($newlen>$oldlen) ? $newlen : $oldlen);
228       print $oldvotes, ' ' x ($maxlen - length($oldvotes)), @$votes, "\n",
229             $newvotes, ' ' x ($maxlen - length($newvotes)), @newvotes, "\n\n";
230
231       do {
232         print "[a] ", UVmessage::get("MENU_VOTES_REENTER_ACK"), "    ",
233               "[b] ", UVmessage::get("MENU_VOTES_REENTER_NACK"), "\n\n", 
234                UVmessage::get("MENU_PROMPT");
235         $sel = <STDIN>;
236       } until ($sel =~ /^[ab]$/i);
237
238       next if ($sel =~ /^b$/i);
239       @$votes = @newvotes;
240       push @$set, 'Stimmen';
241       delete $errors{UnrecognizedVote};
242       delete $errors{DuplicateVote};
243       delete $errors{NoVote};
244       delete $errors{ViolatedRule};
245
246       if (my $rule = UVrules::rule_check($votes)) {
247         $errors{ViolatedRule} = UVmessage::get("MENU_VIOLATEDRULE", (RULE => "#$rule"));
248       }
249
250     } elsif ($input eq '5' && $config{personal}) {
251       print "\n", UVmessage::get("MENU_BALLOT_ID"), ": ";
252       $$ballot_id = <STDIN>;
253       chomp ($$ballot_id);
254       push (@$set, 'Kennung');
255       check_ballotid(\%errors, \$voter_addr, $ballot_id, \%ids);
256
257     } elsif ($input eq '6' && $config{bdsg}) {
258       my $sel;
259       do {
260         print "[a] ", UVmessage::get("MENU_BDSG_ACCEPTED"), "\n",
261               "[b] ", UVmessage::get("MENU_BDSG_DECLINED"), "\n\n",
262               UVmessage::get("MENU_PROMPT");
263         $sel = <STDIN>;
264       } until ($sel =~ /^[ab]$/i);
265
266       if ($sel =~ /^a$/i) {
267         delete $errors{InvalidBDSG};
268       } else {
269         $errors{InvalidBDSG} = UVmessage::get("MENU_INVALIDBDSG");
270       }
271
272     } elsif ($input =~ /^i$/i) {
273       my $ignore = UVmessage::get("MENU_IGNORE_STRING");
274       # Set columns for Text::Wrap
275       $columns = $config{rightmargin};
276       print wrap('', '', UVmessage::get("MENU_IGNORE_WARNING",
277                                         (MENU_IGNORE_STRING => $ignore)
278                                        ));
279       if (<STDIN> eq "$ignore\n") {
280         print "\n";
281         return "i";
282       }
283
284     } elsif ($input =~ /^w$/i) {
285
286       if (keys %errors) {
287         if ((keys %errors)==1 && $errors{UnrecognizedVote}) {
288           # unrecognized vote lines aren't errors if votetaker
289           # did not change them
290           @$errors = ();
291         } else {
292           # Set columns for Text::Wrap
293           $columns = $config{rightmargin};
294           @$errors = keys %errors;
295           my $warning = ' ' . UVmessage::get("MENU_ERROR_WARNING") . ' ';
296           my $length = length($warning);
297           print "\n", '*' x (($config{rightmargin}-$length)/2), $warning,
298                 '*' x (($config{rightmargin}-$length)/2), "\n\n",
299                 wrap('', '', UVmessage::get("MENU_ERROR_TEXT")), "\n\n",
300                 '*' x $config{rightmargin}, "\n\n",
301                 UVmessage::get("MENU_ERROR_GETKEY");
302           my $input = <STDIN>;
303           next if ($input !~ /^y$/i);
304           print "\n";
305         }
306       } else {
307         @$errors = ();
308       }
309  
310       system($config{clearcmd});
311       print "\n", UVmessage::get("MENU_PROCESSING"), "\n";
312       return "w";
313     }
314   }
315
316   sub check_ballotid {
317     my ($errors, $voter_addr, $ballot_id, $ids) = @_;
318
319     return 0 unless ($config{personal});
320
321     delete $errors->{NoBallotID};
322     delete $errors->{WrongBallotID};
323     delete $errors->{AddressNotRegistered};
324
325     if ($$ballot_id) {
326       if ($ids->{$$voter_addr}) {
327         if ($ids->{$$voter_addr} ne $$ballot_id) {
328           # ballot id incorrect
329           $errors->{WrongBallotID} = UVmessage::get("MENU_WRONGBALLOTID");
330         }
331       } else {
332         $errors->{AddressNotRegistered} = UVmessage::get("MENU_ADDRESSNOTREGISTERED");
333       } 
334     } else {
335       $errors->{NoBallotID} = UVmessage::get("MENU_NOBALLOTID");
336     }
337   }
338
339 }
340
341
342 ##############################################################################
343 # Menu for sorting out duplicate votings manually                            #
344 # Parameters: References to hashes with the paragraphs from the result file  #
345 #             and the default value                                          #
346 # Return value: selected menu item (1, 2 or 0)                               #
347 ##############################################################################
348
349 sub dup_choice {
350   my ($vote1, $vote2, $default) = @_;
351
352   print STDERR "\n", UVmessage::get("MENU_DUP_VOTE"), "\n\n";
353   print STDERR UVmessage::get("MENU_DUP_FIRST"), "\n";
354   print STDERR "A: $vote1->{A}\n";
355   print STDERR "N: $vote1->{N}\n";
356   print STDERR "D: $vote1->{D}\n";
357   print STDERR "K: $vote1->{K}\n";
358   print STDERR "S: $vote1->{S}\n\n";
359   print STDERR UVmessage::get("MENU_DUP_SECOND"), "\n";
360   print STDERR "A: $vote2->{A}\n";
361   print STDERR "N: $vote2->{N}\n";
362   print STDERR "D: $vote2->{D}\n";
363   print STDERR "K: $vote2->{K}\n";
364   print STDERR "S: $vote2->{S}\n\n";
365   print STDERR "1: ", UVmessage::get("MENU_DUP_DELFIRST"), "\n",
366                "2: ", UVmessage::get("MENU_DUP_DELSECOND"), "\n",
367                "0: ", UVmessage::get("MENU_DUP_DELNONE"), "\n\n";
368
369   my $input;
370
371   do {
372     print STDERR UVmessage::get("MENU_PROMPT"), "[$default] ";
373     $input = <STDIN>;
374     chomp $input;
375   } until ($input eq '' || ($input >= 0 && $input<3));
376
377   return $input || $default;
378 }
379
380 1;
This page took 0.019679 seconds and 3 git commands to generate.