Merge branch 'thh-pickfromupstream' into next
[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";
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});
b9f52014 84 print "(7) ", UVmessage::get("MENU_VOTING"), " [", $$voting, "]\n";
ac7e2c54
TH
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
b9f52014
TH
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
ac7e2c54
TH
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
368sub 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
3991;
This page took 0.026776 seconds and 4 git commands to generate.