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