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