2 ## (configure will change the top line to the location of perl on your system)
3 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
4 ## cmail $Revision: 2.1 $: a tool to aid playing chess by email
5 ## Copyright (C) 1993,2009 Free Software Foundation, Inc.
7 ## cmail is free software: you can redistribute it and/or modify
8 ## it under the terms of the GNU General Public License as published by
9 ## the Free Software Foundation, either version 3 of the License, or (at
10 ## your option) any later version.
12 ## cmail is distributed in the hope that it will be useful, but
13 ## WITHOUT ANY WARRANTY; without even the implied warranty of
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ## General Public License for more details.
17 ## You should have received a copy of the GNU General Public License
18 ## along with this program. If not, see http://www.gnu.org/licenses/. *
20 ## Modified: $Date: 2003/10/27 19:21:00 $
21 ## Revision: $Revision: 2.1 $
22 ## Email: evan@quadstone.co.uk
23 ## Snailmail: Evan Welsh
28 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
31 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
32 ## Print verbose diagnostics for debugging
35 local ($old) = select ; ## Remember selected output
37 $| = 1 ; ## Keep it flushed
38 print @_ ; ## Print arguments
42 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
45 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
46 ## Create a directory for storing games in if it doesn't already exist
50 ## ################################################################# ##
51 ## Check for existence of the named chess directory
52 ## ################################################################# ##
54 if (! (-d "$CMAILDIR")) {
56 ## ############################################################# ##
57 ## Ask user for confirmation if attached to tty
58 ## ############################################################# ##
61 $old = select ; ## Remember selected output
62 select (stdout) ; ## Write to standard output
63 $| = 1 ; ## Keep it flushed
64 print ( "CMail directory \"$CMAILDIR\" does not exist."
65 . " Create it? [y/q]: ") ;
67 $_ = <tty> ; ## Read response from tty
68 die "Bye!\n" if (/^[qQ].*/) ; ## Quit if q selected
70 select ($old) ; ## Re-select the old output
73 ## ############################################################# ##
74 ## Create a cmail directory or die
75 ## ############################################################# ##
77 die "cmail: Can't create CMail directory: \"$CMAILDIR\"\n"
78 unless mkdir ("$CMAILDIR", 511) ;
79 print ( "Created cmail directory \"$CMAILDIR\".\n"
80 . "You can move it but remember to set the CMAIL_DIR"
81 . " environment variable.\n") ;
84 ## ################################################################# ##
85 ## Change to the $CMAILDIR directory whether newly created or not
86 ## ################################################################# ##
88 die "Couldn't changed directory to \"$CMAILDIR\"\n"
89 unless (chdir "$CMAILDIR") ;
91 ## ################################################################# ##
92 ## Check for existence of the named chess directory
93 ## ################################################################# ##
95 if (! (-d "$ARCDIR")) {
97 ## ############################################################# ##
98 ## Ask user for confirmation if attached to tty
99 ## ############################################################# ##
102 $old = select ; ## Remember selected output
103 select (stdout) ; ## Write to standard output
104 $| = 1 ; ## Keep it flushed
105 print ( "Archive directory \"$ARCDIR\" does not exist."
106 . " Create it? [y/q]: ") ;
108 $_ = <tty> ; ## Read response from tty
109 die "Bye!\n" if (/^[qQ].*/) ; ## Quit if q selected
111 select ($old) ; ## Re-select the old output
114 ## ############################################################# ##
115 ## Create a chess directory or die
116 ## ############################################################# ##
118 die "cmail: Can't create archive directory: \"$ARCDIR\"\n"
119 unless mkdir ("$ARCDIR", 511) ;
120 print ( "Created archive directory \"$ARCDIR\".\n"
121 . "You can move it but remember to set the CMAIL_ARCDIR"
122 . " environment variable.\n") ;
125 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
128 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
129 ## Parse command-line arguments
131 ## ################################################################# ##
132 ## Set up defaults from the environment or from hard-wired constants
133 ## ################################################################# ##
137 $OUTPUT_POS = $ENV{'CMAIL_OUTPUT_POS'} ;
138 $LOGFILE = $ENV{'CMAIL_LOGFILE'} ;
139 $MAILPROG = $ENV{'CMAIL_MAILPROG'} ;
140 $MAILPROG = "/usr/sbin/sendmail" if ( (-x "/usr/sbin/sendmail")
142 $MAILPROG = "/usr/lib/sendmail" if ( (-x "/usr/lib/sendmail")
144 $MAILPROG = "/etc/sendmail" if ( (-x "/usr/lib/sendmail")
146 $MAILPROG = "/usr/ucb/Mail" if ( (-x "/usr/ucb/Mail")
148 $MAILPROG = "/usr/ucb/mail" if ( (-x "/usr/ucb/mail")
150 $MAILPROG = "Mail" unless ($MAILPROG) ;
151 $HOMEDIR = $ENV{'HOME'} ;
152 $CMAILDIR = $ENV{'CMAIL_DIR'} ;
153 $CMAILDIR = $ENV{'CHESSDIR'} unless ($CMAILDIR) ;
154 $CMAILDIR = "$HOMEDIR/Chess" unless ($CMAILDIR) ;
155 $CMAILDIR = "~/Chess" unless ($HOMEDIR) ;
159 $TIME_DELAY = $ENV{'CMAIL_TIME_DELAY'} ;
160 $TIME_DELAY = 0 unless ($TIME_DELAY) ;
161 $PW_NAME = &get_pw_name () ;
162 $MY_NNAME = $PW_NAME ;
163 $MY_NNAME = $ENV{'LOGNAME'} unless ($MY_NNAME) ;
164 $MY_NNAME = $ENV{'USER'} unless ($MY_NNAME) ;
165 $MY_NNAME = "?" unless ($MY_NNAME) ;
166 $PGN_EVENT = "Email correspondence game" ;
172 $LOAD_XBOARD = 1 unless $ENV{'CMAIL_NO_XBOARD'} ;
174 @TD_FLAGS = ("-td", $TIME_DELAY) ;
175 @NCP_FLAGS = ("-ncp") ;
177 ## ################################################################# ##
178 ## Define the usage string
179 ## ################################################################# ##
182 [-h] [-c] [-w] [-[x]v] [-[x]mail] [-[x]xboard] [-[x]reuse] [-remail]
183 [-game <name>] [-(w|b|)games <number>] [-(me|opp) <short name>]
184 [-(w|b|my|opp)name <full name>] [-(w|b|my|opp)na <email>]
185 [-dir <directory>] [-arcdir <directory>] [-mailprog <mail program>]
186 [-logFile <file>] [-event <event>] [-site <site>] [-round <round>]
189 ## ################################################################# ##
190 ## Overwrite defaults if specified on the command-line
191 ## ################################################################# ##
194 while ($ARGV = shift) {
195 $UNREC = 0 if ($ARGV =~ /^-/) ;
196 if ("$ARGV" eq "-h") {die ("Usage: $USAGE\n") ;}
197 elsif ("$ARGV" eq "-c") {$SHOWC = 1 ;}
198 elsif ("$ARGV" eq "-w") {$SHOWW = 1 ;}
199 elsif ("$ARGV" eq "-v") {$DEBUG = 1 ;
200 @DEBUG_FLAGS = ("-debug") ;}
201 elsif ("$ARGV" eq "-xv") {$DEBUG = 0 ;
203 elsif ("$ARGV" eq "-mail") {$SEND_MAIL = 1 ;}
204 elsif ("$ARGV" eq "-xmail") {$SEND_MAIL = 0 ;}
205 elsif ("$ARGV" eq "-xboard") {$LOAD_XBOARD = 1 ;}
206 elsif ("$ARGV" eq "-xxboard") {$LOAD_XBOARD = 0 ;}
207 elsif ("$ARGV" eq "-reuse") {$REUSE = 1 ;}
208 elsif ("$ARGV" eq "-xreuse") {$REUSE = 0 ;}
209 elsif ("$ARGV" eq "-remail") {$LOAD_XBOARD = 0 ;
212 elsif ("$ARGV" eq "-game") {$PGN_GAME = shift ;}
213 elsif ("$ARGV" eq "-games") {$NUM_GAMES = shift ;}
214 elsif ("$ARGV" eq "-wgames") {$NUM_WGAMES = shift ;}
215 elsif ("$ARGV" eq "-bgames") {$NUM_BGAMES = shift ;}
216 elsif ("$ARGV" eq "-me") {$MY_NNAME = shift ;}
217 elsif ("$ARGV" eq "-opp") {$OPP_NNAME = shift ;}
218 elsif ("$ARGV" eq "-myname") {$MY_FNAME = shift ;}
219 elsif ("$ARGV" eq "-oppname") {$OPP_FNAME = shift ;}
220 elsif ("$ARGV" eq "-wname") {$WHITE_FNAME = shift ;}
221 elsif ("$ARGV" eq "-bname") {$BLACK_FNAME = shift ;}
222 elsif ("$ARGV" eq "-myna") {$MY_ADDRESS = shift ;}
223 elsif ("$ARGV" eq "-oppna") {$OPP_ADDRESS = shift ;}
224 elsif ("$ARGV" eq "-wna") {$WHITENA = shift ;}
225 elsif ("$ARGV" eq "-bna") {$BLACKNA = shift ;}
226 elsif ("$ARGV" eq "-dir") {$CMAILDIR = shift ;}
227 elsif ("$ARGV" eq "-arcdir") {$ARCDIR = shift ;}
228 elsif ("$ARGV" eq "-mailprog") {$MAILPROG = shift ;}
229 elsif ("$ARGV" eq "-logFile") {$LOGFILE = shift ;}
230 elsif ("$ARGV" =~ /^-(td|timeDelay)$/)
233 elsif ("$ARGV" =~ /^-noChessComputer$/)
234 {@NCP_FLAGS = ($ARGV,
236 elsif ("$ARGV" =~ /^-[x]?ncp$/) {@NCP_FLAGS = ($ARGV) ;}
237 elsif ("$ARGV" eq "-event") {$PGN_EVENT = shift ;}
238 elsif ("$ARGV" eq "-site") {$PGN_SITE = shift ;}
239 elsif ("$ARGV" eq "-round") {$PGN_ROUND = shift ;}
240 elsif ("$ARGV" eq "-mode") {$PGN_MODE = shift ;}
241 elsif ("$ARGV" =~ /^-/ || $UNREC) {
242 push(@UNREC_ARGS, $ARGV) ;
245 die("cmail: Unrecognised flag \"$ARGV\"\nUsage: $USAGE\n") ;
249 ## ################################################################# ##
250 ## Assign a value to $ARCDIR if not specified on the command line
251 ## ################################################################# ##
253 $ARCDIR = $ENV{'CMAIL_ARCDIR'} unless ($ARCDIR) ;
254 $ARCDIR = $CMAILDIR unless ($ARCDIR) ;
255 $ENV{'CMAIL_ARCDIR'} = $ARCDIR ; ## Make sure this is set for xboard
257 ## ################################################################# ##
258 ## Propagate some CMAIL variables through xboard to the cmail
259 ## grandchild so that it uses the same important variables as this one
260 ## ################################################################# ##
262 $ENV{'CMAIL_MAILPROG'} = $MAILPROG ;
263 $ENV{'CMAIL_DIR'} = $CMAILDIR ;
264 $ENV{'CHESSDIR'} = $CMAILDIR ; ## Make xboard use $CMAILDIR
265 $ENV{'CMAIL_ARCDIR'} = $ARCDIR ;
267 $ENV{'CMAIL_LOGFILE'} = $LOGFILE ;
269 $LOGFILE = "&STDERR" ;
272 ## ################################################################# ##
273 ## Work out how many games of each colour will be played
274 ## ################################################################# ##
276 die "cmail: Illegal number of games: $NUM_GAMES\n"
277 if ($NUM_GAMES < 0) ;
278 die "cmail: Illegal number of white games: $NUM_WGAMES\n"
279 if ($NUM_WGAMES < 0) ;
280 die "cmail: Illegal number of black games: $NUM_BGAMES\n"
281 if ($NUM_BGAMES < 0) ;
282 if ("$NUM_GAMES" ne "?") {
283 if ("$NUM_WGAMES" eq "?") {
284 if ("$NUM_BGAMES" eq "?") {
285 $NUM_BGAMES = int($NUM_GAMES / 2) ;
287 $NUM_WGAMES = $NUM_GAMES - $NUM_BGAMES ;
288 } elsif ("$NUM_BGAMES" eq "?") {
289 $NUM_BGAMES = $NUM_GAMES - $NUM_WGAMES ;
291 } elsif ("$NUM_WGAMES" eq "?") {
292 if ("$NUM_BGAMES" eq "?") {
297 $NUM_GAMES = $NUM_BGAMES ;
301 if ("$NUM_BGAMES" eq "?") {
302 $NUM_GAMES = $NUM_WGAMES ;
305 $NUM_GAMES = $NUM_WGAMES + $NUM_BGAMES ;
308 die "cmail: Illegal number of games: $NUM_GAMES\n"
309 if ("$NUM_GAMES" eq "0") ;
310 die ( "cmail: Inconsistent numbers of games specified:"
311 . " $NUM_WGAMES + $NUM_BGAMES != $NUM_GAMES\n")
312 unless ($NUM_GAMES == $NUM_WGAMES + $NUM_BGAMES) ;
314 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
317 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
318 ## Initialisation of variables and environment
320 ## ################################################################# ##
321 ## Show copyright notice
322 ## ################################################################# ##
325 last if (/^{END OF GPL COPYRIGHT}$/) ;
326 s/\$Revision[:] (.*) \$/$1/ ;
330 ## ################################################################# ##
331 ## Show conditions if requested
332 ## ################################################################# ##
335 last if (/^{END OF GPL CONDITIONS}$/) ;
339 ## ################################################################# ##
340 ## Show warranty if requested
341 ## ################################################################# ##
344 print "\n" if ($SHOWW) ;
345 print while (<DATA>) ;
349 exit 0 if ($SHOWC || $SHOWW) ; ## Abort if showed conditions or warranty
351 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
354 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
355 ## Initialisation of variables and environment
357 local ($p) = "[.PRNBQKprnbqk]" ;
358 local ($l) = "$p $p $p $p $p $p $p $p\n" ;
359 local ($board) = "$l$l$l$l$l$l$l$l" ;
360 local ($tp) = ".* to play\n" ;
361 $posdiag = "\{--------------\n$board$tp--------------\}\n+" ;
363 &parse_flags (@ARGV) ; ## Parse command-line arguments
365 &showGPL unless $QUIET ;
367 open (tty, "< /dev/tty") ; ## Open tty for reading
369 &need_chess_dir () ; ## Check for the existence of CMAILDIR
371 open (logfile, ">$LOGFILE") if ($DEBUG) ; ## Default is STDERR
373 &debug ("Called <initialise>\n") ;
375 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
378 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
379 ## Prompt for a game name, if <cr> use a default
380 sub prompt_for_game_name {
381 &debug ("Called <prompt_for_game_name>\n") ;
382 local ($old) = select ; ## Remember the selected output
383 select (stdout); ## Prompt goes to stdout
384 $| = 1 ; ## Keep it flushed
386 print "Game name [<cr> to use default]: " ;
387 die "cmail: tty not open\n" unless (-t) ;
388 <tty> =~ /(.*)/ ; ## Read line from tty
389 $PGN_GAME = "$1" ; ## Assign to game name
391 select ($old) ; ## Re-select the old output
393 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
396 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
397 ## Prompt for opponent's address
398 sub prompt_for_opp_address {
399 &debug ("Called <prompt_for_opp_address>\n") ;
400 local ($old) = select ; ## Remember the selected output
401 select (stdout); ## Prompt goes to stdout
402 $| = 1 ; ## Keep it flushed
404 ## ################################################################# ##
405 ## Prompt for opponent's email address
406 ## ################################################################# ##
408 print "Opponent's email address: " ;
409 die "cmail: tty not open\n" unless (-t) ;
413 ## ################################################################# ##
414 ## Use name as default if still blank
415 ## ################################################################# ##
417 $OPP_ADDRESS = $OPP_NNAME if ("" eq $OPP_ADDRESS) ;
419 select ($old) ; ## Re-select the old output
421 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
424 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
425 ## Prompt for opponent's name
426 sub prompt_for_opp_name {
427 &debug ("Called <prompt_for_opp_name>\n") ;
428 local ($old) = select ; ## Remember the selected output
429 select (stdout) ; ## Prompt goes to stdout
430 $| = 1 ; ## Keep it flushed
431 print "Opponent's name: " ;
433 die "cmail: tty not open\n" unless (-t) ; ## Check tty is open
434 <tty> =~ /(.*)/ ; ## Read line from tty
435 $OPP_NNAME = $1 ; ## Match!
436 die "cmail: Can't proceed without the opponent's name.\n"
437 unless ($OPP_NNAME) ;
439 select ($old) ; ## Re-select the old output
441 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
444 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
446 sub prompt_for_move {
447 local ($prompt) = shift ;
448 local ($pattern) = shift ;
449 &debug ("Called <prompt_for_move>\n") ;
452 local ($old) = select ; ## Remember the selected output
453 select (stdout) ; ## Write to stdout
454 $| = 1 ; ## Keep it flushed
455 die "cmail: tty not open\n" unless (-t) ; ## Check tty is open
459 <STDIN> =~ /(.*)/ ; ## Read line from tty
460 $move = $1 ; ## Match!
461 } until ($move =~ /^$pattern$/) ;
463 select ($old) ; ## Re-select the old output
466 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
469 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
472 &debug ("Called <play_game>\n") ;
474 $| = 1 ; ## Start flushing output buffer
476 ## ################################################################# ##
477 ## Load xboard unless inhibited by command-line arguments
478 ## ################################################################# ##
480 if (($STARTING_NEW_GAME) && ($NUM_WGAMES == 0)) {
481 print ( "Bypassing xboard and mailing $NUM_BGAMES empty"
482 . " black games.\n") ;
483 } elsif ($LOAD_XBOARD) {
484 ## ############################################################# ##
485 ## Remove output file from previous run, but preserve
486 ## $PGN_GAME.game.out.* because they will be empty black games
487 ## ############################################################# ##
489 unlink "$PGN_GAME.out" ;
491 ## ############################################################# ##
492 ## Invoke xboard with loads of flags
493 ## ############################################################# ##
497 local ($date) = &get_date_from_games (@ARCHIVE) ;
498 $XBOARD_ARGS = join (' ', (("-lgf",
499 "'$ARCDIR/$PGN_GAME.$date.archive'"),
506 $XBOARD_ARGS = join (' ', (("-cmail", "'$PGN_GAME'"),
514 $PGN_GAME = "unknown.cmail" ;
515 $XBOARD_ARGS = join (' ', (("-lgf", "'$PGN_GAME'"),
524 $LOG_FILE = "$PGN_GAME.log" ;
525 &debug ("Invoking xboard with args: $XBOARD_ARGS\n") ;
526 $PID_FILE = "$PGN_GAME.pid" ;
528 || (! ( (-f $PID_FILE)
529 && ($XBOARD_PID = `cat '$PID_FILE'`)
530 && ("$XBOARD_PID" =~ /^\d+$/)
531 && (kill "SIGUSR1", $XBOARD_PID)))) {
532 print "Loading xboard for game \"$PGN_GAME\"..." ;
533 # system ("gdb xboard") ;
534 system ( "{ ({ xboard $XBOARD_ARGS & } ;"
535 . " echo \$! > '$PID_FILE' ;"
537 . " rm '$PID_FILE') & } >'$LOG_FILE' 2>&1") ;
539 . "If nothing happens look for an error message in\n"
540 . "$CMAILDIR/$LOG_FILE\n") ;
542 print ("Revived existing xboard for game \"$PGN_GAME\".\n"
543 . "If nothing happens"
544 . " remove $CMAILDIR/$PID_FILE and try again.\n") ;
551 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
554 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
555 ## Enter moves on tty instead of xboard
557 &debug ("Called <play_on_tty>\n") ;
559 local (@results) = @_ ;
561 local (@games, $game, $to_play) ;
563 ## ################################################################# ##
564 ## Check we have access to tty
565 ## ################################################################# ##
567 if (open(STDIN, '/dev/tty')) {
568 ## ############################################################# ##
570 ## ############################################################# ##
572 local ($infile) = "$PGN_GAME.game.in" ;
574 @games = &get_games_from_file($infile) ;
575 &debug ("Read in games from \"$infile\"\n") ;
578 foreach $game (@games) {
579 $result = shift (@results) ;
580 if ($result && ($game =~ /\[Result\s+"[^*]+"\]/)) {
586 ## ################################################################# ##
587 ## Accept move on tty for each game in turn
588 ## ################################################################# ##
590 local ($comment_orig, $comment, $comment_line,
591 $pos, $move, $normal_move, $action, $result) ;
593 foreach $game (@games) {
596 $game =~ s/[\s\n]*[*]?[\s\n]*$// ;
598 $pos = $1 if ($game =~ s/($posdiag)//) ;
599 print $game, "\n\n", $pos ;
601 ($number, $to_play) = &get_to_play ($game) ;
604 $game_nocomment = $game ;
605 if ($game_nocomment =~ s/\n?{\n?([^{]*)}$//) {
607 $comment_orig =~ s/([^\n])$/$1\n/ ;
608 # &debug ("Comment is:\n{\n$comment_orig}\n") ;
610 if ($game =~ /\[Result\s+"[^*]+"\]/) {
611 &prompt_for_move ("Game finished, press \"Return\" to continue: ", "") ;
615 $tmpgame = $game_nocomment ;
616 $comment = $comment_orig ;
620 if ($game =~ /{\n?.* offers a draw\n?}$/) {
621 $move = &prompt_for_move ("Enter move [MOVE/(r)esign/(a)ccept/(c)omment/re(t)ry]: ",
622 "([-a-h0-9PRNBQK][-a-h0-9PRNBQK]+|[ract])") ;
624 $move = &prompt_for_move ("Enter move [MOVE/(r)esign/(c)omment/re(t)ry]: ",
625 "([-a-h0-9PRNBQK][-a-h0-9PRNBQK]+|[rct])") ;
629 if ($move =~ /^\s*r\s*$/i) {
630 if ($to_play eq "White") {
635 $move = "\n{$to_play resigns} $result" ;
636 } elsif ($move =~ /^\s*a\s*$/i) {
637 $move = "\n{Draw agreed} $result" ;
638 } elsif ($move =~ /^\s*c\s*$/i) {
639 while ($comment_line = &prompt_for_move ("Enter comment: ", ".*")) {
640 $comment .= $comment_line . "\n" ;
643 } elsif ($move =~ /^\s*t\s*$/i) {
644 print $game, "\n\n", $pos ;
645 $tmpgame = $game_nocomment ;
646 $comment = $comment_orig ;
647 print "Try again.\n" ;
653 $tmpgame .= "\n{\n" . $comment . "}" if ($comment) ;
654 if (! $normal_move) {
655 $tmpgame .= "$move" ;
656 } elsif ($to_play eq "White") {
657 $tmpgame .= "\n$number. $move" ;
658 } elsif ($tmpgame =~ /}$/) {
659 $tmpgame .= "\n$number. ... $move" ;
661 $tmpgame .= " $move" ;
664 $tmpgame =~ s/\[Result\s+"(.*)"\]/[Result "$result"]/ if ($result) ;
669 $action = &prompt_for_move ("Enter action [(d)raw/(c)omment/(s)end/re(t)ry]: ",
672 $action = &prompt_for_move ("Enter action [(s)end/re(t)ry]: ",
675 $action = &prompt_for_move ("Enter action [(c)omment/(s)end/re(t)ry]: ",
678 if ($action =~ /^\s*d\s*$/i) {
680 $comment .= "$to_play offers a draw\n" ;
683 $action = &prompt_for_move ("Enter action [(c)omment/(s)end/re(t)ry]: ",
685 if ($action =~ /^\s*c\s*$/i) {
686 while ($comment_line = &prompt_for_move ("Enter comment: ", ".*")) {
687 $comment .= $comment_line . "\n" ;
690 } elsif ($action =~ /^\s*t\s*$/i) {
691 print $game, "\n\n", $pos ;
692 $tmpgame = $game_nocomment ;
693 $comment = $comment_orig ;
694 print "Try again.\n" ;
696 } elsif ($action =~ /^\s*s\s*$/i) {
697 $tmpgame .= "\n{\n" . $comment . "}" ;
702 print "You can't offer a draw at this point.\n" ;
705 } elsif ($action =~ /^\s*c\s*$/i) {
707 print "You can't enter a comment after the game is finished.\n" ;
709 while ($comment_line = &prompt_for_move ("Enter comment: ", ".*")) {
710 $comment .= $comment_line . "\n" ;
714 } elsif ($action =~ /^\s*t\s*$/i) {
716 $tmpgame = $game_nocomment ;
717 $comment = $comment_orig ;
718 print "Try again.\n" ;
720 } elsif ($action =~ /^\s*s\s*$/i) {
721 $tmpgame .= "\n{\n" . $comment . "}\n" if ($comment) ;
729 $tmpgame .= "\n*" if ($normal_move) ;
734 die "cmail: No games to be read\n" ;
737 die "cmail: Can't open tty" ;
742 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
745 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
746 ## Find the game the user wants by any means possible
748 &debug ("Called <find_game>\n") ;
750 ## ################################################################# ##
751 ## Ask user for a game name if not already known
752 ## ################################################################# ##
754 &prompt_for_game_name () if ("" eq "$PGN_GAME") ;
756 ## ################################################################# ##
757 ## Find out opponent's details
758 ## ################################################################# ##
760 if ("" eq "$PGN_GAME") {
761 ## ############################################################# ##
762 ## Failed to find the game name so construct a default from players
763 ## ############################################################# ##
765 &prompt_for_opp_name () if ("" eq "$OPP_NNAME") ; ## Ask user
766 die "cmail: Can't proceed without your opponent's short name (-opp)\n"
767 if ("" eq "$OPP_NNAME") ;
768 die "cmail: Can't proceed without your own short name (-me)\n"
769 if ("" eq "$MY_NNAME") ;
770 if ($NUM_WGAMES > 0) {
771 $PGN_GAME = "$MY_NNAME-vs-$OPP_NNAME" ; ## Construct default
773 $PGN_GAME = "$OPP_NNAME-vs-$MY_NNAME" ; ## Construct default
775 } elsif (("" eq "$OPP_ADDRESS") && ("" ne "$RETURN_ADDRESS")) {
776 $OPP_ADDRESS = $RETURN_ADDRESS ; ## Use return address instead
777 &debug ( "Using return address \"$OPP_ADDRESS\""
778 . " for opponent address\n") ;
781 ## ################################################################# ##
782 ## If no $PGN_GAME.game.in file, assume we're starting a new game
783 ## ################################################################# ##
785 &start_new_game () unless (-f "$PGN_GAME.game.in") ;
787 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
790 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
793 local ($the_time) = time ;
794 local ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
795 localtime ($the_time) ;
806 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
809 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
812 print ( "Starting new game"
813 . " -- $NUM_WGAMES as white, $NUM_BGAMES as black.\n") ;
814 local ($to_play) = "white" ;
816 $STARTING_NEW_GAME = 1 ;
820 ## ################################################################# ##
821 ## Ask user for opponent's email address if unknown
822 ## ################################################################# ##
824 &prompt_for_opp_address () if ("" eq "$OPP_ADDRESS") ;
826 ## ################################################################# ##
827 ## Give up if we haven't got anywhere to send a move to
828 ## ################################################################# ##
830 die "cmail: Can't proceed without your opponent's email address.\n"
831 if ("" eq "$OPP_ADDRESS") ;
833 ## ################################################################# ##
834 ## Create an empty game file
835 ## ################################################################# ##
837 open (GAMEFILE, "> $PGN_GAME.game.in") ;
838 for ($j = 1; $j <= $NUM_GAMES; $j ++) {
839 $PW_GCOS = &get_pw_gcos () ;
841 $PGN_MYCOL = $MY_FNAME ;
842 $PGN_MYCOL = $PW_GCOS unless $PGN_MYCOL ;
843 $PGN_MYCOL = $MY_NNAME unless $PGN_MYCOL ;
844 $PGN_MYCOLNA = $MY_ADDRESS ;
845 $PGN_MYCOLNA = "?" unless ($PGN_MYCOLNA) ;
847 $PGN_OPPCOL = $OPP_FNAME ;
848 $PGN_OPPCOL = "?" unless ($PGN_OPPCOL) ;
849 $PGN_OPPCOLNA = $OPP_ADDRESS ;
850 $PGN_OPPCOLNA = "?" unless ($PGN_OPPCOLNA) ;
852 if ($j > $NUM_WGAMES) {
853 $PGN_WHITE = $PGN_OPPCOL ;
854 $PGN_BLACK = $PGN_MYCOL ;
855 $PGN_WHITENA = $PGN_OPPCOLNA ;
856 $PGN_BLACKNA = $PGN_MYCOLNA ;
858 $PGN_WHITE = $PGN_MYCOL ;
859 $PGN_BLACK = $PGN_OPPCOL ;
860 $PGN_WHITENA = $PGN_MYCOLNA ;
861 $PGN_BLACKNA = $PGN_OPPCOLNA ;
864 ## ######################################################### ##
865 ## If we only have one colour of game then allow command-line
866 ## colour specs to override
867 ## ######################################################### ##
869 if (! ($NUM_WGAMES && $NUM_BGAMES)) {
870 $PGN_WHITE = $WHITE_FNAME if ($WHITE_FNAME) ;
871 $PGN_BLACK = $BLACK_FNAME if ($BLACK_FNAME) ;
872 $PGN_WHITENA = $WHITENA if ($WHITENA) ;
873 $PGN_BLACKNA = $BLACKNA if ($BLACKNA) ;
876 $PGN_DATE = &get_date () ;
877 $PGN_DATE = "?" unless ($PGN_DATE) ;
879 if ($NUM_GAMES > 1) {
884 @game = ("[Event \"$PGN_EVENT\"]\n",
885 "[Site \"$PGN_SITE\"]\n",
886 "[Date \"$PGN_DATE\"]\n",
887 "[Round \"$PGN_ROUND\"]\n",
888 "[White \"$PGN_WHITE\"]\n",
889 "[Black \"$PGN_BLACK\"]\n",
891 "[WhiteNA \"$PGN_WHITENA\"]\n",
892 "[BlackNA \"$PGN_BLACKNA\"]\n",
893 "[Mode \"$PGN_MODE\"]\n",
894 "[CmailGameName \"$PGN_GAME$SUFFIX\"]\n\n*\n") ;
895 if ($j > $NUM_WGAMES) {
896 open (GAMEOUTFILE, "> $PGN_GAME.game.out.$j") ;
897 print GAMEOUTFILE @game ;
898 close (GAMEOUTFILE) ;
900 print GAMEFILE @game ;
905 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
908 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
909 ## Get the password file gcos (full name) entry
911 local ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) =
915 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
918 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
919 ## Get password file gcos (full name) entry
923 ($dummy, $PW_GCOS) = &get_pw_entry () ;
924 $PW_GCOS =~ s/^\s*([^,()]+[^ ,()])[ ]*[,()].*$/$1/;
925 if ($PW_GCOS =~ /^([^,()]+)\s+([^\s,()]+)$/) { ## Multi-word name
926 $PW_GCOS = $2 . ", " . $1 ;
927 } elsif ($PW_GCOS !~ /^([^\s,()]+)/) { ## No sensible gcos entry
929 } ## Else leave it as one word
930 &debug ("PW full name is \"$PW_GCOS\"\n");
934 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
937 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
938 ## Get password file user name entry
941 ($PW_NAME, $dummy) = &get_pw_entry () ;
942 &debug ("PW name is $PW_NAME\n");
946 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
949 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
950 ## Analyse the email message
951 sub analyse_email_message {
952 local ($new_result, $delete_result, $unfinished, $finished)
954 local ($gamefile, @games) ;
956 ## ################################################################# ##
957 ## Slurp the mail message
958 ## ################################################################# ##
960 die "cmail: No games on standard input"
961 unless (@games = &get_games_from_file ("STDIN")) ;
963 ## ################################################################# ##
964 ## Is the message a real cmail message or just a chess game? $PGN_GAME
965 ## will have been set by calling get_games_from_file if it's real
966 ## ################################################################# ##
968 print "Processing game message..." ;
971 ## ############################################################# ##
972 ## Restore the results file from the archive if
973 ## necessary. This is helpful if the user pipes in an old
974 ## message for take-back purposes or whatever.
975 ## ############################################################# ##
977 if (! -f "$PGN_GAME.res") {
978 ## Find what date would have been used to create the archive
980 if (/\[Date\s"(.*)"\]/) {
982 last ; ## Assume all dates are the same
985 ## Restore results file from archive directory if it exists
986 if ($date && (-f "$ARCDIR/$PGN_GAME.$date.archive")) {
988 "$ARCDIR/$PGN_GAME.$date.archive",
990 print stderr ( "\nWarning: couldn't restore results file"
991 . " from archive\n") ;
993 print "restored results file from archive..." ;
998 ## ############################################################# ##
999 ## Find existing results, if any.
1000 ## ############################################################# ##
1002 local (@results) = &get_games_from_file ("$PGN_GAME.res") ;
1004 ## ############################################################# ##
1006 ## ############################################################# ##
1008 foreach $game (@games) {
1009 next unless ($game) ;
1011 ($game_name, $game_num) = &get_game_name_and_number ($game) ;
1014 @game = split("\n", $game) ;
1016 if (/^\[(Black|White)\s*"[?]"\]$/) {
1018 $PW_GCOS = &get_pw_gcos () unless ($PW_GCOS) ;
1019 $PW_GCOS = "$MY_NNAME" unless ($PW_GCOS) ;
1020 s/".*"/"$PW_GCOS"/ ;
1021 &debug ("Changed $colour tag to be $_") ;
1022 } elsif (/^\[((Black|White)NA)\s*"(.*)"\]$/) {
1025 if ($RETURN_ADDRESS) {
1026 $NA = $RETURN_ADDRESS ;
1030 $_ = "[$1 \"$NA\"]" ;
1031 &debug ("Changed $1 tag.\n") ;
1033 if ($2 eq "White") {
1034 $PGN_WHITENA = $NA ;
1035 &debug ("WhiteNA tag is \"$PGN_WHITENA\"\n") ;
1037 $PGN_BLACKNA = $NA ;
1038 &debug ("BlackNA tag is \"$PGN_BLACKNA\"\n") ;
1040 } elsif (/\[Result\s*"(.*)"\]$/) {
1047 } elsif (/^(.*[^\d]+)?\d+[.]\s*([^\s*]*\s+)?[^\s.*]+(\s*\d+[.]\s*)?[\s*]*$/) {
1049 $to_play = "white" ;
1051 $to_play = "black" ;
1053 &debug ("$to_play to play\n") ;
1057 ## ######################################################### ##
1058 ## Reconstruct possibly edited game
1059 ## ######################################################### ##
1061 $game = join ("\n", @game) . "\n\n" ;
1063 ## ######################################################### ##
1064 ## Build up results array
1065 ## ######################################################### ##
1068 $results[$game_num] = $games[$game_num] ;
1070 } elsif ($results[$game_num]) {
1071 ## Deleting a result does actually make sense if the user
1072 ## pipes in an old message for take-back purposes or whatever
1073 $results[$game_num] = "" ;
1074 $delete_result = 1 ;
1077 ## ######################################################### ##
1078 ## Remove old .out files
1079 ## ######################################################### ##
1081 unlink <$PGN_GAME.game.out.*> ;
1083 ## ######################################################### ##
1084 ## Write ongoing games to game file and append new results
1085 ## ######################################################### ##
1087 die "cmail: Can't open file for writing:"
1088 . " \"$CMAILDIR/$PGN_GAME.game.in\"\n"
1089 unless open (gamefile, ">$PGN_GAME.game.in") ;
1091 print gamefile @games ;
1095 ## ############################################################# ##
1096 ## Print how many finished/unfinished games were found
1097 ## ############################################################# ##
1099 printf ("%d unfinished %s and %d finished %s...",
1100 $unfinished, ($unfinished == 1) ? "game" : "games",
1101 $finished, ($finished == 1) ? "game" : "games") ;
1103 ## ############################################################# ##
1104 ## Write results back to results file if there were any results
1106 ## ############################################################# ##
1108 if ($new_result || $delete_result) {
1109 die ( "cmail: Can't open results file for writing:"
1110 . "\"$CMAILDIR/$PGN_GAME.res\"\n")
1111 unless open (resfile, ">$PGN_GAME.res") ;
1112 print resfile @results ;
1116 ## ############################################################# ##
1117 ## Archive results if there are no unfinished games
1118 ## ############################################################# ##
1120 @ARCHIVE = @results unless ($unfinished) ;
1122 ## ############################################################# ##
1123 ## Figure out return address if not known
1124 ## ############################################################# ##
1126 if (! $RETURN_ADDRESS) {
1127 if ($to_play eq "black") {
1128 $RETURN_ADDRESS = $PGN_WHITENA unless ("$PGN_WHITENA" eq "?") ;
1130 $RETURN_ADDRESS = $PGN_BLACKNA unless ("$PGN_BLACKNA" eq "?") ;
1134 ## ############################################################# ##
1135 ## Decide to include position diagrams in output if not already
1136 ## decided and a position diagram was found in the input
1137 ## ############################################################# ##
1139 if ("$OUTPUT_POS" eq "") {
1140 if (grep (/$posdiag/, @games)) {
1141 $OUTPUT_POS = "y" ; # Output position only if it was input
1146 $ENV{'CMAIL_OUTPUT_POS'} = $OUTPUT_POS ;
1148 ## ############################################################# ##
1149 ## Check that we have enough info about the players to continue
1150 ## ############################################################# ##
1154 ## ############################################################# ##
1155 ## Set up xboard for viewing non-cmail PGN file
1156 ## ############################################################# ##
1158 local ($file) = "unknown.cmail" ;
1159 print "done.\nDumping non-cmail file into $CMAILDIR/$file..." ;
1161 die "cmail: Can't open file for writing: \"$CMAILDIR/$file\"\n"
1162 unless open (gamefile, ">$file") ;
1163 print gamefile @games ;
1169 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1172 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1173 ## Sort two filenames by the numeric suffix
1174 sub sort_by_numeric_suffix {
1175 $a =~ /[.](\d+)$/ ; local ($na) = $1 ;
1176 $b =~ /[.](\d+)$/ ; local ($nb) = $1 ;
1178 return ($na <=> $nb) ;
1180 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1183 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1184 sub get_game_name_and_number {
1185 local ($game) = join ("\n", @_) ;
1187 local ($game_name, $game_num) ;
1189 die "CMailGameName tag missing\n"
1190 unless ($game =~ /\[C[Mm]ailGameName\s+"(.*)"\]/) ;
1192 ## ################################################################# ##
1193 ## Set game name and number
1194 ## ################################################################# ##
1197 if ($game_name =~ s/^(.*)[.](\d+)$/$1/) {
1203 ## ################################################################# ##
1204 ## Set $PGN_GAME as a side-effect or check validity
1205 ## ################################################################# ##
1208 die ( "cmail: Mismatched game names in input message:\n"
1209 . "\"$PGN_GAME\", \"$game_name\"\n")
1210 if ("$PGN_GAME" ne "$game_name") ;
1212 $PGN_GAME = $game_name ;
1213 &debug ("PGN_GAME set to \"$PGN_GAME\"\n") ;
1216 return ($game_name, $game_num) ;
1218 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1221 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1222 ## Read in a file of games and split into separate games
1223 sub get_games_from_file {
1224 local ($file) = shift ;
1226 local (@file, $first_line) ; ## Slurp stdin
1227 if ($file eq "STDIN") {
1228 if ($first_line = <STDIN>) { ## Necessary to handle no input case
1229 @file = <STDIN> ; ## Slurp stdin
1230 @file = ($first_line, @file) ;
1233 ## Strip off leading quotation characters
1237 ## Find return address and set it as a side-effect
1238 if ( /^From:?.*<([^>]+)>.*\n$/
1239 || /^From:? *([^ ]*).*\n$/) {
1240 $RETURN_ADDRESS = $1 ; ## Default for opp's email
1241 &debug ("Found opponent's email address",
1242 " \"$RETURN_ADDRESS\"\n") ;
1243 } elsif (/\[C[Mm]ailGameName\s+"(.*)"\]/) {
1245 $PGN_GAME =~ s/[.]\d+$// ;
1249 return (@file) unless ($PGN_GAME) ;
1250 if (grep (/\{--------------|\[Event/, @file)) {
1251 shift (@file) while ($file[0] !~ /\{--------------|\[Event/) ;
1257 return () unless (open (file, "<$file")) ;
1259 @file = <file> ; ## Slurp file
1263 local (@games, $game_name, $game_num, $game, $tag) ;
1265 ## ################################################################# ##
1266 ## Remove headers and leading blanks
1267 ## ################################################################# ##
1269 local (@tgames) = split (/($posdiag\[Event|\[Event)/, join ('', @file)) ;
1270 shift (@tgames) while (!$tgames[0]) ;
1272 ## ################################################################# ##
1273 ## Set up @games array with proper game numbers
1274 ## ################################################################# ##
1277 $game = shift (@tgames) . shift (@tgames) ;
1279 ($game_name, $game_num) = &get_game_name_and_number ($game) ;
1280 $games[$game_num] = $game ;
1285 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1288 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1289 ## Analyse output files and send the move
1291 &debug ("Called <send_move>\n") ;
1293 ## ################################################################# ##
1294 ## Cat the pos (if it exists), game and result (if it exists) files
1295 ## into the .out file.
1296 ## ################################################################# ##
1298 local ($unfinished, $finished) = (0, 0) ;
1299 local (@results, $move, $move_msg, $to_play, $number) ;
1301 ## ################################################################# ##
1302 ## Find any .game.out.* files
1303 ## ################################################################# ##
1305 local (@outfiles) = (<$PGN_GAME.game.out.*>) ;
1306 @outfiles = grep (/[.]\d+$/, @outfiles) ; ## Ignore autosave files
1307 @outfiles = sort sort_by_numeric_suffix @outfiles ; ## Sort
1309 ## ################################################################# ##
1310 ## Find .res file if it exists
1311 ## ################################################################# ##
1313 local ($resfile) = "$PGN_GAME.res" ;
1315 @results = &get_games_from_file($resfile) ;
1316 &debug ("Read in results\n") ;
1319 &debug ("No results to read\n") ;
1322 ## ################################################################# ##
1323 ## Find .out file if it exists
1324 ## ################################################################# ##
1326 local ($outfile) = "$PGN_GAME.out" ;
1327 if (! ($REMAIL || $LOAD_XBOARD)) {
1328 @games = &play_on_tty (@results) ;
1329 } elsif (@outfiles) {
1330 foreach (@outfiles) {
1331 die "Can't open game file \"$_\" for reading"
1332 unless (open (game, "<$_")) ;
1333 die "Empty game file \"$_\""
1334 unless ($game = join ('', <game>)) ;
1336 &debug ("Read in game file \"$_\"\n") ;
1337 ## Remove position diagram if it wasn't in the input msg
1338 $game =~ s/($posdiag)// if ("$OUTPUT_POS" ne "y") ;
1339 ($game_name, $game_num) = &get_game_name_and_number ($game) ;
1340 $games[$game_num] = $game ;
1342 &debug ("Read in games from output files\n") ;
1345 &debug ("No games to read from STDIN\n") ;
1347 @games = &get_games_from_file($outfile) ;
1349 die "Can't find any game files\n" unless (@results) ;
1353 ## ################################################################# ##
1355 ## ################################################################# ##
1358 ## ############################################################# ##
1359 ## Find opponent's email address in games
1360 ## ############################################################# ##
1362 $OPP_ADDRESS = &get_opp_address_from_games (@games)
1363 unless ($OPP_ADDRESS) ;
1365 ## ############################################################# ##
1366 ## Collect the .game.out.* files into the .out file, remembering
1367 ## the move number of the last line and whether result or not
1368 ## ############################################################# ##
1374 ## Write games to output file
1375 die "Can't open output file \"$PGN_GAME.out\" for writing\n"
1376 unless open (outfile, ">$PGN_GAME.out") ;
1377 print outfile @games ;
1382 foreach $game (@games) {
1384 next unless ($game) ;
1387 ## Determine last move and whether result or not
1389 foreach (split(/\n/, $game)) {
1390 if (/^(.*[^\d]+|)(\d+)[.]+\s*[^\s.]*\s+(\S+)\s*$/) {
1393 } elsif (/^\[Result\s*"(.*)"\]$/) {
1403 $results[$game_num] = $game if ($result) ;
1406 ## Write result files back to $PGN_GAME.res
1408 die "Can't open results file $PGN_GAME.res for writing\n"
1409 unless open (resfile, ">$PGN_GAME.res") ;
1410 print resfile @results ;
1414 unlink <$PGN_GAME.game.out.*> ;
1416 ## ############################################################# ##
1417 ## Just say how many games are in the message
1418 ## ############################################################# ##
1420 if ($num_games > 1) {
1421 $move_msg = "$num_games games" ;
1423 $move_msg = "1 game" ;
1426 ## ############################################################# ##
1427 ## Print how many finished/unfinished games were found
1428 ## ############################################################# ##
1430 printf ("Sending %d unfinished %s and %d finished %s.\n",
1431 $unfinished, ($unfinished == 1) ? "game" : "games",
1432 $finished, ($finished == 1) ? "game" : "games") ;
1434 ## ############################################################# ##
1435 ## Send the mail message to opponent's address unless bypassed
1436 ## ############################################################# ##
1439 local ($subject) = "cmail $move_msg <$PGN_GAME>" ;
1440 if ($MAILPROG =~ /sendmail/) {
1441 $opened = open (mail, "|$MAILPROG $OPP_ADDRESS") ;
1442 print mail "To: $OPP_ADDRESS\n";
1443 print mail "Subject: $subject\n";
1444 print mail "Mime-Version: 1.0\n";
1445 print mail "Content-Type: application/x-chess;name=$PGN_GAME.pgn\n\n";
1447 $opened = open (mail, "|$MAILPROG -s \"$subject\" $OPP_ADDRESS") ;
1452 print ( "Mailed cmail message to \"$OPP_ADDRESS\":\n"
1453 . "$move_msg <$PGN_GAME>\n") ;
1454 @ARCHIVE = @results unless ($unfinished) ;
1456 die "Failed to mail cmail message.\n" ;
1459 print ( "Email not sent (as requested).\n"
1460 . "Would have mailed cmail message to \"$OPP_ADDRESS\":\n"
1461 . "$NUM_GAMES games <$PGN_GAME>\n") ;
1465 print "Email not sent (the game is over).\n" ;
1467 die "No games found\n" ;
1471 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1474 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1475 ## Get date from array of games
1476 sub get_date_from_games {
1477 local (@games) = @_ ;
1479 local ($date) = "nodate" ;
1482 if (/\[Date\s"(.*)"\]/) {
1484 last ; ## Assume all dates are the same
1490 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1493 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1494 ## Determine which colour is to play and the move number
1496 &debug ("Called <get_to_play>\n") ;
1497 local ($game) = shift ;
1499 local ($number, $to_play) = (1, "White") ;
1501 $game =~ s/{[^}]*}//g ;
1502 $game =~ s/[\s\n]*[*][\s\n]*$// ;
1504 if ($game =~ /(\d+)[.][\n ]*([.]*)[\n ]*([^\n.]*)[\n\s]*[10-]*[\n\s]*$/) {
1507 if ($game =~ /\[Result "0-1"\]/) {
1508 $to_play = "Black" ;
1509 } elsif ($game =~ /\[Result "1-0"\]/) {
1510 $to_play = "White" ;
1511 } elsif (($2 ne "") || (($3 =~ / /) || ($3 eq ""))) {
1512 $to_play = "White" ;
1515 $to_play = "Black" ;
1519 &debug ("$to_play to play on move $number\n") ;
1521 return ($number, $to_play) ;
1523 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1526 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1527 ## Get opp address from array of games
1528 sub get_opp_address_from_games {
1529 &debug ("Called <get_opp_address_from_games>\n") ;
1530 local (@games) = @_ ;
1532 local ($opp_address) = "" ;
1533 local ($number, $to_play, $tag) ;
1538 ($number, $to_play) = &get_to_play ($_) ;
1539 $tag = ( ($to_play eq "White")
1543 if (/\[$tag\s"(.*)"\]/) {
1545 die "cmail: Empty \"$tag\" tag\n" unless ($opp_address) ;
1546 &debug ("Found opponent's address \"$opp_address\" from games.\n") ;
1547 last ; ## Assume all opp addresses are the same
1549 die "cmail: Can't find \"$tag\" tag\n" ;
1553 die "cmail: Can't find opponent's email address\n" unless ($opp_address) ;
1555 return ($opp_address) ;
1557 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1560 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1561 ## Archive @ARCHIVE in the $ARCDIR directory
1563 return () unless (@ARCHIVE) ;
1565 local ($date) = &get_date_from_games (@ARCHIVE) ;
1567 local ($file) = "$ARCDIR/$PGN_GAME.$date.archive" ;
1568 if (open (archive, ">$file")) {
1569 print archive @ARCHIVE ;
1571 print "Archived game in $file\n" ;
1572 local (@remove) = <$PGN_GAME*> ;
1573 @remove = grep ($_ ne "$PGN_GAME.$date.archive",
1574 @remove) ; ## Don't delete archive
1577 print "Couldn't open \"$file\" to archive game\n" ;
1580 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1583 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1586 local (@games) = () ;
1588 &initialise () ; ## Initialise variables etc.
1590 if (-t || $REMAIL) { ## No input directed (invoked from a shell rather than a mailer)
1591 &debug ("Interactive!\n") ;
1592 &find_game () ; ## Get the necessary info about the game
1594 &debug ("Piping!\n") ;
1595 &analyse_email_message () ; ## Analyse the mail message
1598 if (! &play_game ()) { ## Load the game
1599 &send_move () ; ## Analyse output and send moves
1602 &archive () ; ## Archive games if all finished
1604 close (tty) ; ## Tidy up
1605 close (logfile) if ($DEBUG) ; ## Tidy up
1607 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1609 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1611 cmail $Revision: 2.1 $, Copyright (C) 1993 Free Software Foundation, Inc.
1612 cmail comes with ABSOLUTELY NO WARRANTY; for details type `cmail -w'.
1613 cmail is free software, and you are welcome to redistribute it
1614 under certain conditions; type `cmail -c' for details.
1616 {END OF GPL COPYRIGHT}
1617 GNU GENERAL PUBLIC LICENSE
1618 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
1620 0. This License applies to any program or other work which contains
1621 a notice placed by the copyright holder saying it may be distributed
1622 under the terms of this General Public License. The "Program", below,
1623 refers to any such program or work, and a "work based on the Program"
1624 means either the Program or any derivative work under copyright law:
1625 that is to say, a work containing the Program or a portion of it,
1626 either verbatim or with modifications and/or translated into another
1627 language. (Hereinafter, translation is included without limitation in
1628 the term "modification".) Each licensee is addressed as "you".
1630 Activities other than copying, distribution and modification are not
1631 covered by this License; they are outside its scope. The act of
1632 running the Program is not restricted, and the output from the Program
1633 is covered only if its contents constitute a work based on the
1634 Program (independent of having been made by running the Program).
1635 Whether that is true depends on what the Program does.
1637 1. You may copy and distribute verbatim copies of the Program's
1638 source code as you receive it, in any medium, provided that you
1639 conspicuously and appropriately publish on each copy an appropriate
1640 copyright notice and disclaimer of warranty; keep intact all the
1641 notices that refer to this License and to the absence of any warranty;
1642 and give any other recipients of the Program a copy of this License
1643 along with the Program.
1645 You may charge a fee for the physical act of transferring a copy, and
1646 you may at your option offer warranty protection in exchange for a fee.
1648 2. You may modify your copy or copies of the Program or any portion
1649 of it, thus forming a work based on the Program, and copy and
1650 distribute such modifications or work under the terms of Section 1
1651 above, provided that you also meet all of these conditions:
1653 a) You must cause the modified files to carry prominent notices
1654 stating that you changed the files and the date of any change.
1656 b) You must cause any work that you distribute or publish, that in
1657 whole or in part contains or is derived from the Program or any
1658 part thereof, to be licensed as a whole at no charge to all third
1659 parties under the terms of this License.
1661 c) If the modified program normally reads commands interactively
1662 when run, you must cause it, when started running for such
1663 interactive use in the most ordinary way, to print or display an
1664 announcement including an appropriate copyright notice and a
1665 notice that there is no warranty (or else, saying that you provide
1666 a warranty) and that users may redistribute the program under
1667 these conditions, and telling the user how to view a copy of this
1668 License. (Exception: if the Program itself is interactive but
1669 does not normally print such an announcement, your work based on
1670 the Program is not required to print an announcement.)
1672 These requirements apply to the modified work as a whole. If
1673 identifiable sections of that work are not derived from the Program,
1674 and can be reasonably considered independent and separate works in
1675 themselves, then this License, and its terms, do not apply to those
1676 sections when you distribute them as separate works. But when you
1677 distribute the same sections as part of a whole which is a work based
1678 on the Program, the distribution of the whole must be on the terms of
1679 this License, whose permissions for other licensees extend to the
1680 entire whole, and thus to each and every part regardless of who wrote it.
1682 Thus, it is not the intent of this section to claim rights or contest
1683 your rights to work written entirely by you; rather, the intent is to
1684 exercise the right to control the distribution of derivative or
1685 collective works based on the Program.
1687 In addition, mere aggregation of another work not based on the Program
1688 with the Program (or with a work based on the Program) on a volume of
1689 a storage or distribution medium does not bring the other work under
1690 the scope of this License.
1692 3. You may copy and distribute the Program (or a work based on it,
1693 under Section 2) in object code or executable form under the terms of
1694 Sections 1 and 2 above provided that you also do one of the following:
1696 a) Accompany it with the complete corresponding machine-readable
1697 source code, which must be distributed under the terms of Sections
1698 1 and 2 above on a medium customarily used for software interchange; or,
1700 b) Accompany it with a written offer, valid for at least three
1701 years, to give any third party, for a charge no more than your
1702 cost of physically performing source distribution, a complete
1703 machine-readable copy of the corresponding source code, to be
1704 distributed under the terms of Sections 1 and 2 above on a medium
1705 customarily used for software interchange; or,
1707 c) Accompany it with the information you received as to the offer
1708 to distribute corresponding source code. (This alternative is
1709 allowed only for noncommercial distribution and only if you
1710 received the program in object code or executable form with such
1711 an offer, in accord with Subsection b above.)
1713 The source code for a work means the preferred form of the work for
1714 making modifications to it. For an executable work, complete source
1715 code means all the source code for all modules it contains, plus any
1716 associated interface definition files, plus the scripts used to
1717 control compilation and installation of the executable. However, as a
1718 special exception, the source code distributed need not include
1719 anything that is normally distributed (in either source or binary
1720 form) with the major components (compiler, kernel, and so on) of the
1721 operating system on which the executable runs, unless that component
1722 itself accompanies the executable.
1724 If distribution of executable or object code is made by offering
1725 access to copy from a designated place, then offering equivalent
1726 access to copy the source code from the same place counts as
1727 distribution of the source code, even though third parties are not
1728 compelled to copy the source along with the object code.
1730 4. You may not copy, modify, sublicense, or distribute the Program
1731 except as expressly provided under this License. Any attempt
1732 otherwise to copy, modify, sublicense or distribute the Program is
1733 void, and will automatically terminate your rights under this License.
1734 However, parties who have received copies, or rights, from you under
1735 this License will not have their licenses terminated so long as such
1736 parties remain in full compliance.
1738 5. You are not required to accept this License, since you have not
1739 signed it. However, nothing else grants you permission to modify or
1740 distribute the Program or its derivative works. These actions are
1741 prohibited by law if you do not accept this License. Therefore, by
1742 modifying or distributing the Program (or any work based on the
1743 Program), you indicate your acceptance of this License to do so, and
1744 all its terms and conditions for copying, distributing or modifying
1745 the Program or works based on it.
1747 6. Each time you redistribute the Program (or any work based on the
1748 Program), the recipient automatically receives a license from the
1749 original licensor to copy, distribute or modify the Program subject to
1750 these terms and conditions. You may not impose any further
1751 restrictions on the recipients' exercise of the rights granted herein.
1752 You are not responsible for enforcing compliance by third parties to
1755 7. If, as a consequence of a court judgment or allegation of patent
1756 infringement or for any other reason (not limited to patent issues),
1757 conditions are imposed on you (whether by court order, agreement or
1758 otherwise) that contradict the conditions of this License, they do not
1759 excuse you from the conditions of this License. If you cannot
1760 distribute so as to satisfy simultaneously your obligations under this
1761 License and any other pertinent obligations, then as a consequence you
1762 may not distribute the Program at all. For example, if a patent
1763 license would not permit royalty-free redistribution of the Program by
1764 all those who receive copies directly or indirectly through you, then
1765 the only way you could satisfy both it and this License would be to
1766 refrain entirely from distribution of the Program.
1768 If any portion of this section is held invalid or unenforceable under
1769 any particular circumstance, the balance of the section is intended to
1770 apply and the section as a whole is intended to apply in other
1773 It is not the purpose of this section to induce you to infringe any
1774 patents or other property right claims or to contest validity of any
1775 such claims; this section has the sole purpose of protecting the
1776 integrity of the free software distribution system, which is
1777 implemented by public license practices. Many people have made
1778 generous contributions to the wide range of software distributed
1779 through that system in reliance on consistent application of that
1780 system; it is up to the author/donor to decide if he or she is willing
1781 to distribute software through any other system and a licensee cannot
1784 This section is intended to make thoroughly clear what is believed to
1785 be a consequence of the rest of this License.
1787 8. If the distribution and/or use of the Program is restricted in
1788 certain countries either by patents or by copyrighted interfaces, the
1789 original copyright holder who places the Program under this License
1790 may add an explicit geographical distribution limitation excluding
1791 those countries, so that distribution is permitted only in or among
1792 countries not thus excluded. In such case, this License incorporates
1793 the limitation as if written in the body of this License.
1795 9. The Free Software Foundation may publish revised and/or new versions
1796 of the General Public License from time to time. Such new versions will
1797 be similar in spirit to the present version, but may differ in detail to
1798 address new problems or concerns.
1800 Each version is given a distinguishing version number. If the Program
1801 specifies a version number of this License which applies to it and "any
1802 later version", you have the option of following the terms and conditions
1803 either of that version or of any later version published by the Free
1804 Software Foundation. If the Program does not specify a version number of
1805 this License, you may choose any version ever published by the Free Software
1808 10. If you wish to incorporate parts of the Program into other free
1809 programs whose distribution conditions are different, write to the author
1810 to ask for permission. For software which is copyrighted by the Free
1811 Software Foundation, write to the Free Software Foundation; we sometimes
1812 make exceptions for this. Our decision will be guided by the two goals
1813 of preserving the free status of all derivatives of our free software and
1814 of promoting the sharing and reuse of software generally.
1815 {END OF GPL CONDITIONS}
1816 GNU GENERAL PUBLIC LICENSE
1819 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
1820 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
1821 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
1822 PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
1823 OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1824 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
1825 TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
1826 PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
1827 REPAIR OR CORRECTION.
1829 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
1830 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
1831 REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
1832 INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
1833 OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
1834 TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
1835 YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
1836 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
1837 POSSIBILITY OF SUCH DAMAGES.