1 # UVmenu: menu for interaction with the votetaker
2 # Used by uvvote.pl, uvcfv.pl, uvcount.pl
10 use vars qw($VERSION);
12 use Text::Wrap qw(wrap $columns);
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 ##############################################################################
29 my ($votes, $header, $body, $addr, $name, $ballot_id, $voting, $set, $errors) = @_;
31 my $voter_addr = $$addr || '';
32 my $voter_name = $$name || '';
33 my @newvotes = @$votes;
38 foreach my $error (@$errors) {
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")
46 # violated rule: extract rule number and display warning
47 } elsif ($error =~ /^ViolatedRule #(\d+)$/) {
48 $errors{ViolatedRule} ||= UVmessage::get("MENU_VIOLATEDRULE", (RULE => "#$1"));
51 # special handling if called from uvballot.pl
52 $mailonly = 1 if ($error =~ s/Ballot$//);
54 # get error message for this error from messages.cfg
55 $errors{$error} = UVmessage::get("MENU_" . uc($error));
59 # This loop is only left by 'return'
62 system($config{clearcmd});
63 print UVmessage::get("MENU_PROBLEMS") . "\n";
65 foreach my $error (keys %errors) {
66 print "* $errors{$error}\n";
69 my $menucaption = UVmessage::get("MENU_CAPTION");
70 print "\n\n$menucaption\n";
71 print "=" x length($menucaption), "\n\n";
72 print "(1) ", UVmessage::get("MENU_SHOW_MAIL"), "\n\n",
73 UVmessage::get("MENU_CHANGE_PROPERTIES"), "\n",
74 "(2) ", UVmessage::get("MENU_ADDRESS"), " [$voter_addr]\n";
76 # don't print these options if called from uvcfv.pl
78 print "(3) ", UVmessage::get("MENU_NAME"), " [$voter_name]\n";
79 print "(4) ", UVmessage::get("MENU_VOTES"), " [", @$votes, "]\n";
80 print "(5) ", UVmessage::get("MENU_BALLOT_ID"), " [$$ballot_id]\n"
81 if ($config{personal});
82 print "(6) ", UVmessage::get("MENU_BDSG"), "\n" if ($config{bdsg});
83 print "(7) ", UVmessage::get("MENU_VOTING"), " [", $$voting, "]\n";
87 "(i) ", UVmessage::get("MENU_IGNORE"), "\n",
88 "(w) ", UVmessage::get("MENU_PROCEED"), "\n\n",
89 UVmessage::get("MENU_PROMPT");
91 do { $input = <STDIN>; } until ($input);
95 # only accept 1, 2, i and w if called from uvcfv.pl
96 next if ($mailonly && $input !~ /^[12iw]$/i);
99 system($config{clearcmd});
100 # ignore SIGPIPE (Bug in more and less)
101 $SIG{PIPE} = 'IGNORE';
102 open (MORE, "|$config{pager}");
103 print MORE join("\n", @$header), "\n\n", $$body, "\n";
106 print "\n", UVmessage::get("MENU_GETKEY");
109 } elsif ($input eq '2') {
112 print "[a] ", UVmessage::get("MENU_ADDRESS_OK"), "\n",
113 "[b] ", UVmessage::get("MENU_ADDRESS_CHANGE"), "\n",
114 "[c] ", UVmessage::get("MENU_ADDRESS_INVALID"), "\n\n",
115 UVmessage::get("MENU_PROMPT");
117 } until ($sel =~ /^[abc]$/i);
118 if ($sel =~ /^a$/i) {
119 delete $errors{SuspiciousAccount};
120 delete $errors{InvalidAddress};
122 } elsif ($sel =~ /^c$/i) {
123 delete $errors{SuspiciousAccount};
124 $errors{InvalidAddress} = UVmessage::get("MENU_INVALIDADDRESS") . " " .
125 UVmessage::get("MENU_INVALIDADDRESS2");
130 print "\n", UVmessage::get("MENU_ADDRESS_PROMPT"), " ";
131 $voter_addr = <STDIN>;
133 } until ($voter_addr);
134 $$addr = $voter_addr;
135 push (@$set, 'Adresse');
136 delete $errors{SuspiciousAccount};
137 delete $errors{InvalidAddress};
138 check_ballotid(\%errors, \$voter_addr, $ballot_id, \%ids);
140 } elsif ($input eq '3') {
143 print "[a] ", UVmessage::get("MENU_NAME_OK"), "\n",
144 "[b] ", UVmessage::get("MENU_NAME_CHANGE"), "\n",
145 "[c] ", UVmessage::get("MENU_NAME_INVALID"), "\n\n",
146 UVmessage::get("MENU_PROMPT");
148 } until ($sel =~ /^[abc]$/i);
149 if ($sel =~ /^a$/i) {
150 delete $errors{InvalidName};
152 } elsif ($sel =~ /^c$/i) {
153 $errors{InvalidName} = UVmessage::get("MENU_INVALIDNAME");
156 print UVmessage::get("MENU_NAME"), ": ";
157 $voter_name = <STDIN>;
159 $$name = $voter_name;
160 push (@$set, 'Name');
161 delete $errors{NoName};
162 delete $errors{InvalidName};
164 $errors{InvalidName} = UVmessage::get("MENU_INVALIDNAME")
165 unless ($voter_name =~ /$config{name_re}/);
167 } elsif ($input eq '4') {
172 print "[a] ", UVmessage::get("MENU_VOTES_OK"), "\n",
173 "[b] ", UVmessage::get("MENU_VOTES_RESET"), "\n",
174 "[c] ", UVmessage::get("MENU_VOTES_INVALID"), "\n",
175 "[d] ", UVmessage::get("MENU_VOTES_CANCELLED"), "\n\n",
176 UVmessage::get("MENU_PROMPT");
178 } until ($sel =~ /^[abcd]$/i);
179 if ($sel =~ /^[ad]$/i) {
180 delete $errors{NoVote};
181 delete $errors{UnrecognizedVote};
182 delete $errors{ViolatedRule};
183 delete $errors{DuplicateVote};
184 if ($sel =~ /^d$/i) {
185 # cancelled vote: replace all votes with an A
186 @$votes = split(//, 'A' x scalar @groups);
187 push @$set, 'Stimmen';
188 # some errors are irrelevant when cancelling a vote:
189 delete $errors{InvalidName};
190 delete $errors{NoName};
191 delete $errors{InvalidBDSG};
192 delete $errors{InvalidAddress};
193 delete $errors{SuspiciousAccount};
196 } elsif ($sel =~ /^c$/i) {
197 $errors{NoVote} = UVmessage::get("MENU_INVALIDVOTE");
201 # Set columns for Text::Wrap
202 $columns = $config{rightmargin};
203 print "\n", wrap('', '', UVmessage::get("MENU_VOTES_REENTER_ASK")), "\n\n";
204 print UVmessage::get("MENU_VOTES_REENTER_LEGEND"), "\n";
206 for (my $n=0; $n<@groups; $n++) {
208 $votes->[$n] ||= 'E';
210 # repeat while invalid character entered
211 while (!($voteinput =~ /^[JNE]$/)) {
212 my $invalid = $#groups ? 0 : 1;
213 print UVmessage::get("MENU_VOTES_REENTER", (GROUP => $groups[$n]));
214 $voteinput = <STDIN>;
216 $voteinput ||= $votes->[$n];
217 $voteinput =~ tr/jne/JNE/;
220 # valid input, save new votes
221 $newvotes[$n] = $voteinput;
225 my $oldvotes = UVmessage::get("MENU_VOTES_REENTER_OLD");
226 my $newvotes = UVmessage::get("MENU_VOTES_REENTER_NEW");
227 my $oldlen = length($oldvotes);
228 my $newlen = length($newvotes);
229 my $maxlen = 1 + (($newlen>$oldlen) ? $newlen : $oldlen);
230 print $oldvotes, ' ' x ($maxlen - length($oldvotes)), @$votes, "\n",
231 $newvotes, ' ' x ($maxlen - length($newvotes)), @newvotes, "\n\n";
234 print "[a] ", UVmessage::get("MENU_VOTES_REENTER_ACK"), " ",
235 "[b] ", UVmessage::get("MENU_VOTES_REENTER_NACK"), "\n\n",
236 UVmessage::get("MENU_PROMPT");
238 } until ($sel =~ /^[ab]$/i);
240 next if ($sel =~ /^b$/i);
242 push @$set, 'Stimmen';
243 delete $errors{UnrecognizedVote};
244 delete $errors{DuplicateVote};
245 delete $errors{NoVote};
246 delete $errors{ViolatedRule};
248 if (my $rule = UVrules::rule_check($votes)) {
249 $errors{ViolatedRule} = UVmessage::get("MENU_VIOLATEDRULE", (RULE => "#$rule"));
252 } elsif ($input eq '5' && $config{personal}) {
253 print "\n", UVmessage::get("MENU_BALLOT_ID"), ": ";
254 $$ballot_id = <STDIN>;
256 push (@$set, 'Kennung');
257 check_ballotid(\%errors, \$voter_addr, $ballot_id, \%ids);
259 } elsif ($input eq '6' && $config{bdsg}) {
262 print "[a] ", UVmessage::get("MENU_BDSG_ACCEPTED"), "\n",
263 "[b] ", UVmessage::get("MENU_BDSG_DECLINED"), "\n\n",
264 UVmessage::get("MENU_PROMPT");
266 } until ($sel =~ /^[ab]$/i);
268 if ($sel =~ /^a$/i) {
269 delete $errors{InvalidBDSG};
271 $errors{InvalidBDSG} = UVmessage::get("MENU_INVALIDBDSG");
274 } elsif ($input eq '7') {
277 print "[a] ", UVmessage::get("MENU_VOTING_CORRECT"), "\n",
278 "[b] ", UVmessage::get("MENU_VOTING_WRONG"), "\n\n",
279 UVmessage::get("MENU_PROMPT");
281 } until ($sel =~ /^[ab]$/i);
283 if ($sel =~ /^a$/i) {
284 delete $errors{NoVoting};
285 delete $errors{WrongVoting};
287 $errors{WrongVoting} = UVmessage::get("MENU_WRONGVOTING");
290 } elsif ($input eq '7') {
293 print "[a] ", UVmessage::get("MENU_VOTING_CORRECT"), "\n",
294 "[b] ", UVmessage::get("MENU_VOTING_WRONG"), "\n\n",
295 UVmessage::get("MENU_PROMPT");
297 } until ($sel =~ /^[ab]$/i);
299 if ($sel =~ /^a$/i) {
300 delete $errors{NoVoting};
301 delete $errors{WrongVoting};
303 $errors{WrongVoting} = UVmessage::get("MENU_WRONGVOTING");
306 } elsif ($input =~ /^i$/i) {
307 my $ignore = UVmessage::get("MENU_IGNORE_STRING");
308 # Set columns for Text::Wrap
309 $columns = $config{rightmargin};
310 print wrap('', '', UVmessage::get("MENU_IGNORE_WARNING",
311 (MENU_IGNORE_STRING => $ignore)
313 if (<STDIN> eq "$ignore\n") {
318 } elsif ($input =~ /^w$/i) {
321 if ((keys %errors)==1 && $errors{UnrecognizedVote}) {
322 # unrecognized vote lines aren't errors if votetaker
323 # did not change them
326 # Set columns for Text::Wrap
327 $columns = $config{rightmargin};
328 @$errors = keys %errors;
329 my $warning = ' ' . UVmessage::get("MENU_ERROR_WARNING") . ' ';
330 my $length = length($warning);
331 print "\n", '*' x (($config{rightmargin}-$length)/2), $warning,
332 '*' x (($config{rightmargin}-$length)/2), "\n\n",
333 wrap('', '', UVmessage::get("MENU_ERROR_TEXT")), "\n\n",
334 '*' x $config{rightmargin}, "\n\n",
335 UVmessage::get("MENU_ERROR_GETKEY");
337 next if ($input !~ /^y$/i);
344 system($config{clearcmd});
345 print "\n", UVmessage::get("MENU_PROCESSING"), "\n";
351 my ($errors, $voter_addr, $ballot_id, $ids) = @_;
353 return 0 unless ($config{personal});
355 delete $errors->{NoBallotID};
356 delete $errors->{WrongBallotID};
357 delete $errors->{AddressNotRegistered};
360 if ($ids->{$$voter_addr}) {
361 if ($ids->{$$voter_addr} ne $$ballot_id) {
362 # ballot id incorrect
363 $errors->{WrongBallotID} = UVmessage::get("MENU_WRONGBALLOTID");
366 $errors->{AddressNotRegistered} = UVmessage::get("MENU_ADDRESSNOTREGISTERED");
369 $errors->{NoBallotID} = UVmessage::get("MENU_NOBALLOTID");
376 ##############################################################################
377 # Menu for sorting out duplicate votings manually #
378 # Parameters: References to hashes with the paragraphs from the result file #
379 # and the default value #
380 # Return value: selected menu item (1, 2 or 0) #
381 ##############################################################################
384 my ($vote1, $vote2, $default) = @_;
386 print STDERR "\n", UVmessage::get("MENU_DUP_VOTE"), "\n\n";
387 print STDERR UVmessage::get("MENU_DUP_FIRST"), "\n";
388 print STDERR "A: $vote1->{A}\n";
389 print STDERR "N: $vote1->{N}\n";
390 print STDERR "D: $vote1->{D}\n";
391 print STDERR "K: $vote1->{K}\n";
392 print STDERR "S: $vote1->{S}\n\n";
393 print STDERR UVmessage::get("MENU_DUP_SECOND"), "\n";
394 print STDERR "A: $vote2->{A}\n";
395 print STDERR "N: $vote2->{N}\n";
396 print STDERR "D: $vote2->{D}\n";
397 print STDERR "K: $vote2->{K}\n";
398 print STDERR "S: $vote2->{S}\n\n";
399 print STDERR "1: ", UVmessage::get("MENU_DUP_DELFIRST"), "\n",
400 "2: ", UVmessage::get("MENU_DUP_DELSECOND"), "\n",
401 "0: ", UVmessage::get("MENU_DUP_DELNONE"), "\n\n";
406 print STDERR UVmessage::get("MENU_PROMPT"), "[$default] ";
409 } until ($input eq '' || ($input >= 0 && $input<3));
411 return $input || $default;