2 ## (configure will change the top line to the location of perl on your system)
3 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
4 ## cmail $Revision$: a tool to aid playing chess by email
5 ## Copyright (C) 1993 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 2 of the License, or
10 ## (at your option) any later version.
12 ## cmail is distributed in the hope that it will be useful,
13 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ## GNU General Public License for more details.
17 ## You should have received a copy of the GNU General Public License
18 ## along with cmail; if not, write to the Free Software
19 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
22 ## Revision: $Revision$
23 ## Email: evan@quadstone.co.uk
24 ## Snailmail: Evan Welsh
29 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
32 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
33 ## Print verbose diagnostics for debugging
36 local ($old) = select ; ## Remember selected output
38 $| = 1 ; ## Keep it flushed
39 print @_ ; ## Print arguments
43 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
46 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
47 ## Create a directory for storing games in if it doesn't already exist
51 ## ################################################################# ##
52 ## Check for existence of the named chess directory
53 ## ################################################################# ##
55 if (! (-d "$CMAILDIR")) {
57 ## ############################################################# ##
58 ## Ask user for confirmation if attached to tty
59 ## ############################################################# ##
62 $old = select ; ## Remember selected output
63 select (stdout) ; ## Write to standard output
64 $| = 1 ; ## Keep it flushed
65 print ( "CMail directory \"$CMAILDIR\" does not exist."
66 . " Create it? [y/q]: ") ;
68 $_ = <tty> ; ## Read response from tty
69 die "Bye!\n" if (/^[qQ].*/) ; ## Quit if q selected
71 select ($old) ; ## Re-select the old output
74 ## ############################################################# ##
75 ## Create a cmail directory or die
76 ## ############################################################# ##
78 die "cmail: Can't create CMail directory: \"$CMAILDIR\"\n"
79 unless mkdir ("$CMAILDIR", 511) ;
80 print ( "Created cmail directory \"$CMAILDIR\".\n"
81 . "You can move it but remember to set the CMAIL_DIR"
82 . " environment variable.\n") ;
85 ## ################################################################# ##
86 ## Change to the $CMAILDIR directory whether newly created or not
87 ## ################################################################# ##
89 die "Couldn't changed directory to \"$CMAILDIR\"\n"
90 unless (chdir "$CMAILDIR") ;
92 ## ################################################################# ##
93 ## Check for existence of the named chess directory
94 ## ################################################################# ##
96 if (! (-d "$ARCDIR")) {
98 ## ############################################################# ##
99 ## Ask user for confirmation if attached to tty
100 ## ############################################################# ##
103 $old = select ; ## Remember selected output
104 select (stdout) ; ## Write to standard output
105 $| = 1 ; ## Keep it flushed
106 print ( "Archive directory \"$ARCDIR\" does not exist."
107 . " Create it? [y/q]: ") ;
109 $_ = <tty> ; ## Read response from tty
110 die "Bye!\n" if (/^[qQ].*/) ; ## Quit if q selected
112 select ($old) ; ## Re-select the old output
115 ## ############################################################# ##
116 ## Create a chess directory or die
117 ## ############################################################# ##
119 die "cmail: Can't create archive directory: \"$ARCDIR\"\n"
120 unless mkdir ("$ARCDIR", 511) ;
121 print ( "Created archive directory \"$ARCDIR\".\n"
122 . "You can move it but remember to set the CMAIL_ARCDIR"
123 . " environment variable.\n") ;
126 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
129 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
130 ## Parse command-line arguments
132 ## ################################################################# ##
133 ## Set up defaults from the environment or from hard-wired constants
134 ## ################################################################# ##
138 $OUTPUT_POS = $ENV{'CMAIL_OUTPUT_POS'} ;
139 $LOGFILE = $ENV{'CMAIL_LOGFILE'} ;
140 $MAILPROG = $ENV{'CMAIL_MAILPROG'} ;
141 $MAILPROG = "/usr/sbin/sendmail" if ( (-x "/usr/sbin/sendmail")
143 $MAILPROG = "/usr/lib/sendmail" if ( (-x "/usr/lib/sendmail")
145 $MAILPROG = "/etc/sendmail" if ( (-x "/usr/lib/sendmail")
147 $MAILPROG = "/usr/ucb/Mail" if ( (-x "/usr/ucb/Mail")
149 $MAILPROG = "/usr/ucb/mail" if ( (-x "/usr/ucb/mail")
151 $MAILPROG = "Mail" unless ($MAILPROG) ;
152 $HOMEDIR = $ENV{'HOME'} ;
153 $CMAILDIR = $ENV{'CMAIL_DIR'} ;
154 $CMAILDIR = $ENV{'CHESSDIR'} unless ($CMAILDIR) ;
155 $CMAILDIR = "$HOMEDIR/Chess" unless ($CMAILDIR) ;
156 $CMAILDIR = "~/Chess" unless ($HOMEDIR) ;
160 $TIME_DELAY = $ENV{'CMAIL_TIME_DELAY'} ;
161 $TIME_DELAY = 0 unless ($TIME_DELAY) ;
162 $PW_NAME = &get_pw_name () ;
163 $MY_NNAME = $PW_NAME ;
164 $MY_NNAME = $ENV{'LOGNAME'} unless ($MY_NNAME) ;
165 $MY_NNAME = $ENV{'USER'} unless ($MY_NNAME) ;
166 $MY_NNAME = "?" unless ($MY_NNAME) ;
167 $PGN_EVENT = "Email correspondence game" ;
173 $LOAD_XBOARD = 1 unless $ENV{'CMAIL_NO_XBOARD'} ;
175 @TD_FLAGS = ("-td", $TIME_DELAY) ;
176 @NCP_FLAGS = ("-ncp") ;
178 ## ################################################################# ##
179 ## Define the usage string
180 ## ################################################################# ##
183 [-h] [-c] [-w] [-[x]v] [-[x]mail] [-[x]xboard] [-[x]reuse] [-remail]
184 [-game <name>] [-(w|b|)games <number>] [-(me|opp) <short name>]
185 [-(w|b|my|opp)name <full name>] [-(w|b|my|opp)na <email>]
186 [-dir <directory>] [-arcdir <directory>] [-mailprog <mail program>]
187 [-logFile <file>] [-event <event>] [-site <site>] [-round <round>]
190 ## ################################################################# ##
191 ## Overwrite defaults if specified on the command-line
192 ## ################################################################# ##
195 while ($ARGV = shift) {
196 $UNREC = 0 if ($ARGV =~ /^-/) ;
197 if ("$ARGV" eq "-h") {die ("Usage: $USAGE\n") ;}
198 elsif ("$ARGV" eq "-c") {$SHOWC = 1 ;}
199 elsif ("$ARGV" eq "-w") {$SHOWW = 1 ;}
200 elsif ("$ARGV" eq "-v") {$DEBUG = 1 ;
201 @DEBUG_FLAGS = ("-debug") ;}
202 elsif ("$ARGV" eq "-xv") {$DEBUG = 0 ;
204 elsif ("$ARGV" eq "-mail") {$SEND_MAIL = 1 ;}
205 elsif ("$ARGV" eq "-xmail") {$SEND_MAIL = 0 ;}
206 elsif ("$ARGV" eq "-xboard") {$LOAD_XBOARD = 1 ;}
207 elsif ("$ARGV" eq "-xxboard") {$LOAD_XBOARD = 0 ;}
208 elsif ("$ARGV" eq "-reuse") {$REUSE = 1 ;}
209 elsif ("$ARGV" eq "-xreuse") {$REUSE = 0 ;}
210 elsif ("$ARGV" eq "-remail") {$LOAD_XBOARD = 0 ;
213 elsif ("$ARGV" eq "-game") {$PGN_GAME = shift ;}
214 elsif ("$ARGV" eq "-games") {$NUM_GAMES = shift ;}
215 elsif ("$ARGV" eq "-wgames") {$NUM_WGAMES = shift ;}
216 elsif ("$ARGV" eq "-bgames") {$NUM_BGAMES = shift ;}
217 elsif ("$ARGV" eq "-me") {$MY_NNAME = shift ;}
218 elsif ("$ARGV" eq "-opp") {$OPP_NNAME = shift ;}
219 elsif ("$ARGV" eq "-myname") {$MY_FNAME = shift ;}
220 elsif ("$ARGV" eq "-oppname") {$OPP_FNAME = shift ;}
221 elsif ("$ARGV" eq "-wname") {$WHITE_FNAME = shift ;}
222 elsif ("$ARGV" eq "-bname") {$BLACK_FNAME = shift ;}
223 elsif ("$ARGV" eq "-myna") {$MY_ADDRESS = shift ;}
224 elsif ("$ARGV" eq "-oppna") {$OPP_ADDRESS = shift ;}
225 elsif ("$ARGV" eq "-wna") {$WHITENA = shift ;}
226 elsif ("$ARGV" eq "-bna") {$BLACKNA = shift ;}
227 elsif ("$ARGV" eq "-dir") {$CMAILDIR = shift ;}
228 elsif ("$ARGV" eq "-arcdir") {$ARCDIR = shift ;}
229 elsif ("$ARGV" eq "-mailprog") {$MAILPROG = shift ;}
230 elsif ("$ARGV" eq "-logFile") {$LOGFILE = shift ;}
231 elsif ("$ARGV" =~ /^-(td|timeDelay)$/)
234 elsif ("$ARGV" =~ /^-noChessComputer$/)
235 {@NCP_FLAGS = ($ARGV,
237 elsif ("$ARGV" =~ /^-[x]?ncp$/) {@NCP_FLAGS = ($ARGV) ;}
238 elsif ("$ARGV" eq "-event") {$PGN_EVENT = shift ;}
239 elsif ("$ARGV" eq "-site") {$PGN_SITE = shift ;}
240 elsif ("$ARGV" eq "-round") {$PGN_ROUND = shift ;}
241 elsif ("$ARGV" eq "-mode") {$PGN_MODE = shift ;}
242 elsif ("$ARGV" =~ /^-/ || $UNREC) {
243 push(@UNREC_ARGS, $ARGV) ;
246 die("cmail: Unrecognised flag \"$ARGV\"\nUsage: $USAGE\n") ;
250 ## ################################################################# ##
251 ## Assign a value to $ARCDIR if not specified on the command line
252 ## ################################################################# ##
254 $ARCDIR = $ENV{'CMAIL_ARCDIR'} unless ($ARCDIR) ;
255 $ARCDIR = $CMAILDIR unless ($ARCDIR) ;
256 $ENV{'CMAIL_ARCDIR'} = $ARCDIR ; ## Make sure this is set for xboard
258 ## ################################################################# ##
259 ## Propagate some CMAIL variables through xboard to the cmail
260 ## grandchild so that it uses the same important variables as this one
261 ## ################################################################# ##
263 $ENV{'CMAIL_MAILPROG'} = $MAILPROG ;
264 $ENV{'CMAIL_DIR'} = $CMAILDIR ;
265 $ENV{'CHESSDIR'} = $CMAILDIR ; ## Make xboard use $CMAILDIR
266 $ENV{'CMAIL_ARCDIR'} = $ARCDIR ;
268 $ENV{'CMAIL_LOGFILE'} = $LOGFILE ;
270 $LOGFILE = "&STDERR" ;
273 ## ################################################################# ##
274 ## Work out how many games of each colour will be played
275 ## ################################################################# ##
277 die "cmail: Illegal number of games: $NUM_GAMES\n"
278 if ($NUM_GAMES < 0) ;
279 die "cmail: Illegal number of white games: $NUM_WGAMES\n"
280 if ($NUM_WGAMES < 0) ;
281 die "cmail: Illegal number of black games: $NUM_BGAMES\n"
282 if ($NUM_BGAMES < 0) ;
283 if ("$NUM_GAMES" ne "?") {
284 if ("$NUM_WGAMES" eq "?") {
285 if ("$NUM_BGAMES" eq "?") {
286 $NUM_BGAMES = int($NUM_GAMES / 2) ;
288 $NUM_WGAMES = $NUM_GAMES - $NUM_BGAMES ;
289 } elsif ("$NUM_BGAMES" eq "?") {
290 $NUM_BGAMES = $NUM_GAMES - $NUM_WGAMES ;
292 } elsif ("$NUM_WGAMES" eq "?") {
293 if ("$NUM_BGAMES" eq "?") {
298 $NUM_GAMES = $NUM_BGAMES ;
302 if ("$NUM_BGAMES" eq "?") {
303 $NUM_GAMES = $NUM_WGAMES ;
306 $NUM_GAMES = $NUM_WGAMES + $NUM_BGAMES ;
309 die "cmail: Illegal number of games: $NUM_GAMES\n"
310 if ("$NUM_GAMES" eq "0") ;
311 die ( "cmail: Inconsistent numbers of games specified:"
312 . " $NUM_WGAMES + $NUM_BGAMES != $NUM_GAMES\n")
313 unless ($NUM_GAMES == $NUM_WGAMES + $NUM_BGAMES) ;
315 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
318 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
319 ## Initialisation of variables and environment
321 ## ################################################################# ##
322 ## Show copyright notice
323 ## ################################################################# ##
326 last if (/^{END OF GPL COPYRIGHT}$/) ;
327 s/\$Revision[:] (.*) \$/$1/ ;
331 ## ################################################################# ##
332 ## Show conditions if requested
333 ## ################################################################# ##
336 last if (/^{END OF GPL CONDITIONS}$/) ;
340 ## ################################################################# ##
341 ## Show warranty if requested
342 ## ################################################################# ##
345 print "\n" if ($SHOWW) ;
346 print while (<DATA>) ;
350 exit 0 if ($SHOWC || $SHOWW) ; ## Abort if showed conditions or warranty
352 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
355 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
356 ## Initialisation of variables and environment
358 local ($p) = "[.PRNBQKprnbqk]" ;
359 local ($l) = "$p $p $p $p $p $p $p $p\n" ;
360 local ($board) = "$l$l$l$l$l$l$l$l" ;
361 local ($tp) = ".* to play\n" ;
362 $posdiag = "\{--------------\n$board$tp--------------\}\n+" ;
364 &parse_flags (@ARGV) ; ## Parse command-line arguments
366 &showGPL unless $QUIET ;
368 open (tty, "< /dev/tty") ; ## Open tty for reading
370 &need_chess_dir () ; ## Check for the existence of CMAILDIR
372 open (logfile, ">$LOGFILE") if ($DEBUG) ; ## Default is STDERR
374 &debug ("Called <initialise>\n") ;
376 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
379 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
380 ## Prompt for a game name, if <cr> use a default
381 sub prompt_for_game_name {
382 &debug ("Called <prompt_for_game_name>\n") ;
383 local ($old) = select ; ## Remember the selected output
384 select (stdout); ## Prompt goes to stdout
385 $| = 1 ; ## Keep it flushed
387 print "Game name [<cr> to use default]: " ;
388 die "cmail: tty not open\n" unless (-t) ;
389 <tty> =~ /(.*)/ ; ## Read line from tty
390 $PGN_GAME = "$1" ; ## Assign to game name
392 select ($old) ; ## Re-select the old output
394 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
397 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
398 ## Prompt for opponent's address
399 sub prompt_for_opp_address {
400 &debug ("Called <prompt_for_opp_address>\n") ;
401 local ($old) = select ; ## Remember the selected output
402 select (stdout); ## Prompt goes to stdout
403 $| = 1 ; ## Keep it flushed
405 ## ################################################################# ##
406 ## Prompt for opponent's email address
407 ## ################################################################# ##
409 print "Opponent's email address: " ;
410 die "cmail: tty not open\n" unless (-t) ;
414 ## ################################################################# ##
415 ## Use name as default if still blank
416 ## ################################################################# ##
418 $OPP_ADDRESS = $OPP_NNAME if ("" eq $OPP_ADDRESS) ;
420 select ($old) ; ## Re-select the old output
422 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
425 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
426 ## Prompt for opponent's name
427 sub prompt_for_opp_name {
428 &debug ("Called <prompt_for_opp_name>\n") ;
429 local ($old) = select ; ## Remember the selected output
430 select (stdout) ; ## Prompt goes to stdout
431 $| = 1 ; ## Keep it flushed
432 print "Opponent's name: " ;
434 die "cmail: tty not open\n" unless (-t) ; ## Check tty is open
435 <tty> =~ /(.*)/ ; ## Read line from tty
436 $OPP_NNAME = $1 ; ## Match!
437 die "cmail: Can't proceed without the opponent's name.\n"
438 unless ($OPP_NNAME) ;
440 select ($old) ; ## Re-select the old output
442 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
445 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
447 sub prompt_for_move {
448 local ($prompt) = shift ;
449 local ($pattern) = shift ;
450 &debug ("Called <prompt_for_move>\n") ;
453 local ($old) = select ; ## Remember the selected output
454 select (stdout) ; ## Write to stdout
455 $| = 1 ; ## Keep it flushed
456 die "cmail: tty not open\n" unless (-t) ; ## Check tty is open
460 <STDIN> =~ /(.*)/ ; ## Read line from tty
461 $move = $1 ; ## Match!
462 } until ($move =~ /^$pattern$/) ;
464 select ($old) ; ## Re-select the old output
467 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
470 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
473 &debug ("Called <play_game>\n") ;
475 $| = 1 ; ## Start flushing output buffer
477 ## ################################################################# ##
478 ## Load xboard unless inhibited by command-line arguments
479 ## ################################################################# ##
481 if (($STARTING_NEW_GAME) && ($NUM_WGAMES == 0)) {
482 print ( "Bypassing xboard and mailing $NUM_BGAMES empty"
483 . " black games.\n") ;
484 } elsif ($LOAD_XBOARD) {
485 ## ############################################################# ##
486 ## Remove output file from previous run, but preserve
487 ## $PGN_GAME.game.out.* because they will be empty black games
488 ## ############################################################# ##
490 unlink "$PGN_GAME.out" ;
492 ## ############################################################# ##
493 ## Invoke xboard with loads of flags
494 ## ############################################################# ##
498 local ($date) = &get_date_from_games (@ARCHIVE) ;
499 $XBOARD_ARGS = join (' ', (("-lgf",
500 "$ARCDIR/$PGN_GAME.$date.archive"),
507 $XBOARD_ARGS = join (' ', (("-cmail", $PGN_GAME),
515 $PGN_GAME = "unknown.cmail" ;
516 $XBOARD_ARGS = join (' ', (("-lgf", $PGN_GAME),
525 $LOG_FILE = "$PGN_GAME.log" ;
526 &debug ("Invoking xboard with args: $XBOARD_ARGS\n") ;
527 $PID_FILE = "$PGN_GAME.pid" ;
529 || (! ( (-f $PID_FILE)
530 && ($XBOARD_PID = `cat $PID_FILE`)
531 && ("$XBOARD_PID" =~ /^\d+$/)
532 && (kill "SIGUSR1", $XBOARD_PID)))) {
533 print "Loading xboard for game \"$PGN_GAME\"..." ;
534 # system ("gdb xboard") ;
535 system ( "{ ({ xboard $XBOARD_ARGS & } ;"
536 . " echo \$! > $PID_FILE ;"
538 . " rm $PID_FILE) & } >$LOG_FILE 2>&1") ;
540 . "If nothing happens look for an error message in\n"
541 . "$CMAILDIR/$LOG_FILE\n") ;
543 print ("Revived existing xboard for game \"$PGN_GAME\".\n"
544 . "If nothing happens"
545 . " remove $CMAILDIR/$PID_FILE and try again.\n") ;
552 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
555 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
556 ## Enter moves on tty instead of xboard
558 &debug ("Called <play_on_tty>\n") ;
560 local (@results) = @_ ;
562 local (@games, $game, $to_play) ;
564 ## ################################################################# ##
565 ## Check we have access to tty
566 ## ################################################################# ##
568 if (open(STDIN, '/dev/tty')) {
569 ## ############################################################# ##
571 ## ############################################################# ##
573 local ($infile) = "$PGN_GAME.game.in" ;
575 @games = &get_games_from_file($infile) ;
576 &debug ("Read in games from \"$infile\"\n") ;
579 foreach $game (@games) {
580 $result = shift (@results) ;
581 if ($result && ($game =~ /\[Result\s+"[^*]+"\]/)) {
587 ## ################################################################# ##
588 ## Accept move on tty for each game in turn
589 ## ################################################################# ##
591 local ($comment_orig, $comment, $comment_line,
592 $pos, $move, $normal_move, $action, $result) ;
594 foreach $game (@games) {
597 $game =~ s/[\s\n]*[*]?[\s\n]*$// ;
599 $pos = $1 if ($game =~ s/($posdiag)//) ;
600 print $game, "\n\n", $pos ;
602 ($number, $to_play) = &get_to_play ($game) ;
605 $game_nocomment = $game ;
606 if ($game_nocomment =~ s/\n?{\n?([^{]*)}$//) {
608 $comment_orig =~ s/([^\n])$/$1\n/ ;
609 # &debug ("Comment is:\n{\n$comment_orig}\n") ;
611 if ($game =~ /\[Result\s+"[^*]+"\]/) {
612 &prompt_for_move ("Game finished, press \"Return\" to continue: ", "") ;
616 $tmpgame = $game_nocomment ;
617 $comment = $comment_orig ;
621 if ($game =~ /{\n?.* offers a draw\n?}$/) {
622 $move = &prompt_for_move ("Enter move [MOVE/(r)esign/(a)ccept/(c)omment/re(t)ry]: ",
623 "([-a-h0-9PRNBQK][-a-h0-9PRNBQK]+|[ract])") ;
625 $move = &prompt_for_move ("Enter move [MOVE/(r)esign/(c)omment/re(t)ry]: ",
626 "([-a-h0-9PRNBQK][-a-h0-9PRNBQK]+|[rct])") ;
630 if ($move =~ /^\s*r\s*$/i) {
631 if ($to_play eq "White") {
636 $move = "\n{$to_play resigns} $result" ;
637 } elsif ($move =~ /^\s*a\s*$/i) {
638 $move = "\n{Draw agreed} $result" ;
639 } elsif ($move =~ /^\s*c\s*$/i) {
640 while ($comment_line = &prompt_for_move ("Enter comment: ", ".*")) {
641 $comment .= $comment_line . "\n" ;
644 } elsif ($move =~ /^\s*t\s*$/i) {
645 print $game, "\n\n", $pos ;
646 $tmpgame = $game_nocomment ;
647 $comment = $comment_orig ;
648 print "Try again.\n" ;
654 $tmpgame .= "\n{\n" . $comment . "}" if ($comment) ;
655 if (! $normal_move) {
656 $tmpgame .= "$move" ;
657 } elsif ($to_play eq "White") {
658 $tmpgame .= "\n$number. $move" ;
659 } elsif ($tmpgame =~ /}$/) {
660 $tmpgame .= "\n$number. ... $move" ;
662 $tmpgame .= " $move" ;
665 $tmpgame =~ s/\[Result\s+"(.*)"\]/[Result "$result"]/ if ($result) ;
670 $action = &prompt_for_move ("Enter action [(d)raw/(c)omment/(s)end/re(t)ry]: ",
673 $action = &prompt_for_move ("Enter action [(s)end/re(t)ry]: ",
676 $action = &prompt_for_move ("Enter action [(c)omment/(s)end/re(t)ry]: ",
679 if ($action =~ /^\s*d\s*$/i) {
681 $comment .= "$to_play offers a draw\n" ;
684 $action = &prompt_for_move ("Enter action [(c)omment/(s)end/re(t)ry]: ",
686 if ($action =~ /^\s*c\s*$/i) {
687 while ($comment_line = &prompt_for_move ("Enter comment: ", ".*")) {
688 $comment .= $comment_line . "\n" ;
691 } elsif ($action =~ /^\s*t\s*$/i) {
692 print $game, "\n\n", $pos ;
693 $tmpgame = $game_nocomment ;
694 $comment = $comment_orig ;
695 print "Try again.\n" ;
697 } elsif ($action =~ /^\s*s\s*$/i) {
698 $tmpgame .= "\n{\n" . $comment . "}" ;
703 print "You can't offer a draw at this point.\n" ;
706 } elsif ($action =~ /^\s*c\s*$/i) {
708 print "You can't enter a comment after the game is finished.\n" ;
710 while ($comment_line = &prompt_for_move ("Enter comment: ", ".*")) {
711 $comment .= $comment_line . "\n" ;
715 } elsif ($action =~ /^\s*t\s*$/i) {
717 $tmpgame = $game_nocomment ;
718 $comment = $comment_orig ;
719 print "Try again.\n" ;
721 } elsif ($action =~ /^\s*s\s*$/i) {
722 $tmpgame .= "\n{\n" . $comment . "}\n" if ($comment) ;
730 $tmpgame .= "\n*" if ($normal_move) ;
735 die "cmail: No games to be read\n" ;
738 die "cmail: Can't open tty" ;
743 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
746 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
747 ## Find the game the user wants by any means possible
749 &debug ("Called <find_game>\n") ;
751 ## ################################################################# ##
752 ## Ask user for a game name if not already known
753 ## ################################################################# ##
755 &prompt_for_game_name () if ("" eq "$PGN_GAME") ;
757 ## ################################################################# ##
758 ## Find out opponent's details
759 ## ################################################################# ##
761 if ("" eq "$PGN_GAME") {
762 ## ############################################################# ##
763 ## Failed to find the game name so construct a default from players
764 ## ############################################################# ##
766 &prompt_for_opp_name () if ("" eq "$OPP_NNAME") ; ## Ask user
767 die "cmail: Can't proceed without your opponent's short name (-opp)\n"
768 if ("" eq "$OPP_NNAME") ;
769 die "cmail: Can't proceed without your own short name (-me)\n"
770 if ("" eq "$MY_NNAME") ;
771 if ($NUM_WGAMES > 0) {
772 $PGN_GAME = "$MY_NNAME-vs-$OPP_NNAME" ; ## Construct default
774 $PGN_GAME = "$OPP_NNAME-vs-$MY_NNAME" ; ## Construct default
776 } elsif (("" eq "$OPP_ADDRESS") && ("" ne "$RETURN_ADDRESS")) {
777 $OPP_ADDRESS = $RETURN_ADDRESS ; ## Use return address instead
778 &debug ( "Using return address \"$OPP_ADDRESS\""
779 . " for opponent address\n") ;
782 ## ################################################################# ##
783 ## If no $PGN_GAME.game.in file, assume we're starting a new game
784 ## ################################################################# ##
786 &start_new_game () unless (-f "$PGN_GAME.game.in") ;
788 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
791 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
794 local ($the_time) = time ;
795 local ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
796 localtime ($the_time) ;
807 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
810 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
813 print ( "Starting new game"
814 . " -- $NUM_WGAMES as white, $NUM_BGAMES as black.\n") ;
815 local ($to_play) = "white" ;
817 $STARTING_NEW_GAME = 1 ;
821 ## ################################################################# ##
822 ## Ask user for opponent's email address if unknown
823 ## ################################################################# ##
825 &prompt_for_opp_address () if ("" eq "$OPP_ADDRESS") ;
827 ## ################################################################# ##
828 ## Give up if we haven't got anywhere to send a move to
829 ## ################################################################# ##
831 die "cmail: Can't proceed without your opponent's email address.\n"
832 if ("" eq "$OPP_ADDRESS") ;
834 ## ################################################################# ##
835 ## Create an empty game file
836 ## ################################################################# ##
838 open (GAMEFILE, "> $PGN_GAME.game.in") ;
839 for ($j = 1; $j <= $NUM_GAMES; $j ++) {
840 $PW_GCOS = &get_pw_gcos () ;
842 $PGN_MYCOL = $MY_FNAME ;
843 $PGN_MYCOL = $PW_GCOS unless $PGN_MYCOL ;
844 $PGN_MYCOL = $MY_NNAME unless $PGN_MYCOL ;
845 $PGN_MYCOLNA = $MY_ADDRESS ;
846 $PGN_MYCOLNA = "?" unless ($PGN_MYCOLNA) ;
848 $PGN_OPPCOL = $OPP_FNAME ;
849 $PGN_OPPCOL = "?" unless ($PGN_OPPCOL) ;
850 $PGN_OPPCOLNA = $OPP_ADDRESS ;
851 $PGN_OPPCOLNA = "?" unless ($PGN_OPPCOLNA) ;
853 if ($j > $NUM_WGAMES) {
854 $PGN_WHITE = $PGN_OPPCOL ;
855 $PGN_BLACK = $PGN_MYCOL ;
856 $PGN_WHITENA = $PGN_OPPCOLNA ;
857 $PGN_BLACKNA = $PGN_MYCOLNA ;
859 $PGN_WHITE = $PGN_MYCOL ;
860 $PGN_BLACK = $PGN_OPPCOL ;
861 $PGN_WHITENA = $PGN_MYCOLNA ;
862 $PGN_BLACKNA = $PGN_OPPCOLNA ;
865 ## ######################################################### ##
866 ## If we only have one colour of game then allow command-line
867 ## colour specs to override
868 ## ######################################################### ##
870 if (! ($NUM_WGAMES && $NUM_BGAMES)) {
871 $PGN_WHITE = $WHITE_FNAME if ($WHITE_FNAME) ;
872 $PGN_BLACK = $BLACK_FNAME if ($BLACK_FNAME) ;
873 $PGN_WHITENA = $WHITENA if ($WHITENA) ;
874 $PGN_BLACKNA = $BLACKNA if ($BLACKNA) ;
877 $PGN_DATE = &get_date () ;
878 $PGN_DATE = "?" unless ($PGN_DATE) ;
880 if ($NUM_GAMES > 1) {
885 @game = ("[Event \"$PGN_EVENT\"]\n",
886 "[Site \"$PGN_SITE\"]\n",
887 "[Date \"$PGN_DATE\"]\n",
888 "[Round \"$PGN_ROUND\"]\n",
889 "[White \"$PGN_WHITE\"]\n",
890 "[Black \"$PGN_BLACK\"]\n",
892 "[WhiteNA \"$PGN_WHITENA\"]\n",
893 "[BlackNA \"$PGN_BLACKNA\"]\n",
894 "[Mode \"$PGN_MODE\"]\n",
895 "[CmailGameName \"$PGN_GAME$SUFFIX\"]\n\n*\n") ;
896 if ($j > $NUM_WGAMES) {
897 open (GAMEOUTFILE, "> $PGN_GAME.game.out.$j") ;
898 print GAMEOUTFILE @game ;
899 close (GAMEOUTFILE) ;
901 print GAMEFILE @game ;
906 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
909 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
910 ## Get the password file gcos (full name) entry
912 local ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) =
916 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
919 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
920 ## Get password file gcos (full name) entry
924 ($dummy, $PW_GCOS) = &get_pw_entry () ;
925 $PW_GCOS =~ s/^\s*([^,()]+[^ ,()])[ ]*[,()].*$/$1/;
926 if ($PW_GCOS =~ /^([^,()]+)\s+([^\s,()]+)$/) { ## Multi-word name
927 $PW_GCOS = $2 . ", " . $1 ;
928 } elsif ($PW_GCOS !~ /^([^\s,()]+)/) { ## No sensible gcos entry
930 } ## Else leave it as one word
931 &debug ("PW full name is \"$PW_GCOS\"\n");
935 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
938 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
939 ## Get password file user name entry
942 ($PW_NAME, $dummy) = &get_pw_entry () ;
943 &debug ("PW name is $PW_NAME\n");
947 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
950 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
951 ## Analyse the email message
952 sub analyse_email_message {
953 local ($new_result, $delete_result, $unfinished, $finished)
955 local ($gamefile, @games) ;
957 ## ################################################################# ##
958 ## Slurp the mail message
959 ## ################################################################# ##
961 die "cmail: No games on standard input"
962 unless (@games = &get_games_from_file ("STDIN")) ;
964 ## ################################################################# ##
965 ## Is the message a real cmail message or just a chess game? $PGN_GAME
966 ## will have been set by calling get_games_from_file if it's real
967 ## ################################################################# ##
969 print "Processing game message..." ;
972 ## ############################################################# ##
973 ## Restore the results file from the archive if
974 ## necessary. This is helpful if the user pipes in an old
975 ## message for take-back purposes or whatever.
976 ## ############################################################# ##
978 if (! -f "$PGN_GAME.res") {
979 ## Find what date would have been used to create the archive
981 if (/\[Date\s"(.*)"\]/) {
983 last ; ## Assume all dates are the same
986 ## Restore results file from archive directory if it exists
987 if ($date && (-f "$ARCDIR/$PGN_GAME.$date.archive")) {
989 "$ARCDIR/$PGN_GAME.$date.archive",
991 print stderr ( "\nWarning: couldn't restore results file"
992 . " from archive\n") ;
994 print "restored results file from archive..." ;
999 ## ############################################################# ##
1000 ## Find existing results, if any.
1001 ## ############################################################# ##
1003 local (@results) = &get_games_from_file ("$PGN_GAME.res") ;
1005 ## ############################################################# ##
1007 ## ############################################################# ##
1009 foreach $game (@games) {
1010 next unless ($game) ;
1012 ($game_name, $game_num) = &get_game_name_and_number ($game) ;
1015 @game = split("\n", $game) ;
1017 if (/^\[(Black|White)\s*"[?]"\]$/) {
1019 $PW_GCOS = &get_pw_gcos () unless ($PW_GCOS) ;
1020 $PW_GCOS = "$MY_NNAME" unless ($PW_GCOS) ;
1021 s/".*"/"$PW_GCOS"/ ;
1022 &debug ("Changed $colour tag to be $_") ;
1023 } elsif (/^\[((Black|White)NA)\s*"(.*)"\]$/) {
1026 if ($RETURN_ADDRESS) {
1027 $NA = $RETURN_ADDRESS ;
1031 $_ = "[$1 \"$NA\"]" ;
1032 &debug ("Changed $1 tag.\n") ;
1034 if ($2 eq "White") {
1035 $PGN_WHITENA = $NA ;
1036 &debug ("WhiteNA tag is \"$PGN_WHITENA\"\n") ;
1038 $PGN_BLACKNA = $NA ;
1039 &debug ("BlackNA tag is \"$PGN_BLACKNA\"\n") ;
1041 } elsif (/\[Result\s*"(.*)"\]$/) {
1048 } elsif (/^(.*[^\d]+)?\d+[.]\s*([^\s*]*\s+)?[^\s.*]+(\s*\d+[.]\s*)?[\s*]*$/) {
1050 $to_play = "white" ;
1052 $to_play = "black" ;
1054 &debug ("$to_play to play\n") ;
1058 ## ######################################################### ##
1059 ## Reconstruct possibly edited game
1060 ## ######################################################### ##
1062 $game = join ("\n", @game) . "\n\n" ;
1064 ## ######################################################### ##
1065 ## Build up results array
1066 ## ######################################################### ##
1069 $results[$game_num] = $games[$game_num] ;
1071 } elsif ($results[$game_num]) {
1072 ## Deleting a result does actually make sense if the user
1073 ## pipes in an old message for take-back purposes or whatever
1074 $results[$game_num] = "" ;
1075 $delete_result = 1 ;
1078 ## ######################################################### ##
1079 ## Remove old .out files
1080 ## ######################################################### ##
1082 unlink <$PGN_GAME.game.out.*> ;
1084 ## ######################################################### ##
1085 ## Write ongoing games to game file and append new results
1086 ## ######################################################### ##
1088 die "cmail: Can't open file for writing:"
1089 . " \"$CMAILDIR/$PGN_GAME.game.in\"\n"
1090 unless open (gamefile, ">$PGN_GAME.game.in") ;
1092 print gamefile @games ;
1096 ## ############################################################# ##
1097 ## Print how many finished/unfinished games were found
1098 ## ############################################################# ##
1100 printf ("%d unfinished %s and %d finished %s...",
1101 $unfinished, ($unfinished == 1) ? "game" : "games",
1102 $finished, ($finished == 1) ? "game" : "games") ;
1104 ## ############################################################# ##
1105 ## Write results back to results file if there were any results
1107 ## ############################################################# ##
1109 if ($new_result || $delete_result) {
1110 die ( "cmail: Can't open results file for writing:"
1111 . "\"$CMAILDIR/$PGN_GAME.res\"\n")
1112 unless open (resfile, ">$PGN_GAME.res") ;
1113 print resfile @results ;
1117 ## ############################################################# ##
1118 ## Archive results if there are no unfinished games
1119 ## ############################################################# ##
1121 @ARCHIVE = @results unless ($unfinished) ;
1123 ## ############################################################# ##
1124 ## Figure out return address if not known
1125 ## ############################################################# ##
1127 if (! $RETURN_ADDRESS) {
1128 if ($to_play eq "black") {
1129 $RETURN_ADDRESS = $PGN_WHITENA unless ("$PGN_WHITENA" eq "?") ;
1131 $RETURN_ADDRESS = $PGN_BLACKNA unless ("$PGN_BLACKNA" eq "?") ;
1135 ## ############################################################# ##
1136 ## Decide to include position diagrams in output if not already
1137 ## decided and a position diagram was found in the input
1138 ## ############################################################# ##
1140 if ("$OUTPUT_POS" eq "") {
1141 if (grep (/$posdiag/, @games)) {
1142 $OUTPUT_POS = "y" ; # Output position only if it was input
1147 $ENV{'CMAIL_OUTPUT_POS'} = $OUTPUT_POS ;
1149 ## ############################################################# ##
1150 ## Check that we have enough info about the players to continue
1151 ## ############################################################# ##
1155 ## ############################################################# ##
1156 ## Set up xboard for viewing non-cmail PGN file
1157 ## ############################################################# ##
1159 local ($file) = "unknown.cmail" ;
1160 print "done.\nDumping non-cmail file into $CMAILDIR/$file..." ;
1162 die "cmail: Can't open file for writing: \"$CMAILDIR/$file\"\n"
1163 unless open (gamefile, ">$file") ;
1164 print gamefile @games ;
1170 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1173 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1174 ## Sort two filenames by the numeric suffix
1175 sub sort_by_numeric_suffix {
1176 $a =~ /[.](\d+)$/ ; local ($na) = $1 ;
1177 $b =~ /[.](\d+)$/ ; local ($nb) = $1 ;
1179 return ($na <=> $nb) ;
1181 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1184 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1185 sub get_game_name_and_number {
1186 local ($game) = join ("\n", @_) ;
1188 local ($game_name, $game_num) ;
1190 die "CMailGameName tag missing\n"
1191 unless ($game =~ /\[C[Mm]ailGameName\s+"(.*)"\]/) ;
1193 ## ################################################################# ##
1194 ## Set game name and number
1195 ## ################################################################# ##
1198 if ($game_name =~ s/^(.*)[.](\d+)$/$1/) {
1204 ## ################################################################# ##
1205 ## Set $PGN_GAME as a side-effect or check validity
1206 ## ################################################################# ##
1209 die ( "cmail: Mismatched game names in input message:\n"
1210 . "\"$PGN_GAME\", \"$game_name\"\n")
1211 if ("$PGN_GAME" ne "$game_name") ;
1213 $PGN_GAME = $game_name ;
1214 &debug ("PGN_GAME set to \"$PGN_GAME\"\n") ;
1217 return ($game_name, $game_num) ;
1219 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1222 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1223 ## Read in a file of games and split into separate games
1224 sub get_games_from_file {
1225 local ($file) = shift ;
1227 local (@file, $first_line) ; ## Slurp stdin
1228 if ($file eq "STDIN") {
1229 if ($first_line = <STDIN>) { ## Necessary to handle no input case
1230 @file = <STDIN> ; ## Slurp stdin
1231 @file = ($first_line, @file) ;
1234 ## Strip off leading quotation characters
1238 ## Find return address and set it as a side-effect
1239 if ( /^From:?.*<([^>]+)>.*\n$/
1240 || /^From:? *([^ ]*).*\n$/) {
1241 $RETURN_ADDRESS = $1 ; ## Default for opp's email
1242 &debug ("Found opponent's email address",
1243 " \"$RETURN_ADDRESS\"\n") ;
1244 } elsif (/\[C[Mm]ailGameName\s+"(.*)"\]/) {
1246 $PGN_GAME =~ s/[.]\d+$// ;
1250 return (@file) unless ($PGN_GAME) ;
1251 if (grep (/\{--------------|\[Event/, @file)) {
1252 shift (@file) while ($file[0] !~ /\{--------------|\[Event/) ;
1258 return () unless (open (file, "<$file")) ;
1260 @file = <file> ; ## Slurp file
1264 local (@games, $game_name, $game_num, $game, $tag) ;
1266 ## ################################################################# ##
1267 ## Remove headers and leading blanks
1268 ## ################################################################# ##
1270 local (@tgames) = split (/($posdiag\[Event|\[Event)/, join ('', @file)) ;
1271 shift (@tgames) while (!$tgames[0]) ;
1273 ## ################################################################# ##
1274 ## Set up @games array with proper game numbers
1275 ## ################################################################# ##
1278 $game = shift (@tgames) . shift (@tgames) ;
1280 ($game_name, $game_num) = &get_game_name_and_number ($game) ;
1281 $games[$game_num] = $game ;
1286 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1289 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1290 ## Analyse output files and send the move
1292 &debug ("Called <send_move>\n") ;
1294 ## ################################################################# ##
1295 ## Cat the pos (if it exists), game and result (if it exists) files
1296 ## into the .out file.
1297 ## ################################################################# ##
1299 local ($unfinished, $finished) = (0, 0) ;
1300 local (@results, $move, $move_msg, $to_play, $number) ;
1302 ## ################################################################# ##
1303 ## Find any .game.out.* files
1304 ## ################################################################# ##
1306 local (@outfiles) = (<$PGN_GAME.game.out.*>) ;
1307 @outfiles = grep (/[.]\d+$/, @outfiles) ; ## Ignore autosave files
1308 @outfiles = sort sort_by_numeric_suffix @outfiles ; ## Sort
1310 ## ################################################################# ##
1311 ## Find .res file if it exists
1312 ## ################################################################# ##
1314 local ($resfile) = "$PGN_GAME.res" ;
1316 @results = &get_games_from_file($resfile) ;
1317 &debug ("Read in results\n") ;
1320 &debug ("No results to read\n") ;
1323 ## ################################################################# ##
1324 ## Find .out file if it exists
1325 ## ################################################################# ##
1327 local ($outfile) = "$PGN_GAME.out" ;
1328 if (! ($REMAIL || $LOAD_XBOARD)) {
1329 @games = &play_on_tty (@results) ;
1330 } elsif (@outfiles) {
1331 foreach (@outfiles) {
1332 die "Can't open game file \"$_\" for reading"
1333 unless (open (game, "<$_")) ;
1334 die "Empty game file \"$_\""
1335 unless ($game = join ('', <game>)) ;
1337 &debug ("Read in game file \"$_\"\n") ;
1338 ## Remove position diagram if it wasn't in the input msg
1339 $game =~ s/($posdiag)// if ("$OUTPUT_POS" ne "y") ;
1340 ($game_name, $game_num) = &get_game_name_and_number ($game) ;
1341 $games[$game_num] = $game ;
1343 &debug ("Read in games from output files\n") ;
1346 &debug ("No games to read from STDIN\n") ;
1348 @games = &get_games_from_file($outfile) ;
1350 die "Can't find any game files\n" unless (@results) ;
1354 ## ################################################################# ##
1356 ## ################################################################# ##
1359 ## ############################################################# ##
1360 ## Find opponent's email address in games
1361 ## ############################################################# ##
1363 $OPP_ADDRESS = &get_opp_address_from_games (@games)
1364 unless ($OPP_ADDRESS) ;
1366 ## ############################################################# ##
1367 ## Collect the .game.out.* files into the .out file, remembering
1368 ## the move number of the last line and whether result or not
1369 ## ############################################################# ##
1375 ## Write games to output file
1376 die "Can't open output file \"$PGN_GAME.out\" for writing\n"
1377 unless open (outfile, ">$PGN_GAME.out") ;
1378 print outfile @games ;
1383 foreach $game (@games) {
1385 next unless ($game) ;
1388 ## Determine last move and whether result or not
1390 foreach (split(/\n/, $game)) {
1391 if (/^(.*[^\d]+|)(\d+)[.]+\s*[^\s.]*\s+(\S+)\s*$/) {
1394 } elsif (/^\[Result\s*"(.*)"\]$/) {
1404 $results[$game_num] = $game if ($result) ;
1407 ## Write result files back to $PGN_GAME.res
1409 die "Can't open results file $PGN_GAME.res for writing\n"
1410 unless open (resfile, ">$PGN_GAME.res") ;
1411 print resfile @results ;
1415 unlink <$PGN_GAME.game.out.*> ;
1417 ## ############################################################# ##
1418 ## Just say how many games are in the message
1419 ## ############################################################# ##
1421 if ($num_games > 1) {
1422 $move_msg = "$num_games games" ;
1424 $move_msg = "1 game" ;
1427 ## ############################################################# ##
1428 ## Print how many finished/unfinished games were found
1429 ## ############################################################# ##
1431 printf ("Sending %d unfinished %s and %d finished %s.\n",
1432 $unfinished, ($unfinished == 1) ? "game" : "games",
1433 $finished, ($finished == 1) ? "game" : "games") ;
1435 ## ############################################################# ##
1436 ## Send the mail message to opponent's address unless bypassed
1437 ## ############################################################# ##
1440 local ($subject) = "cmail $move_msg <$PGN_GAME>" ;
1441 if ($MAILPROG =~ /sendmail/) {
1442 $opened = open (mail, "|$MAILPROG $OPP_ADDRESS") ;
1443 print mail "To: $OPP_ADDRESS\n";
1444 print mail "Subject: $subject\n";
1445 print mail "Mime-Version: 1.0\n";
1446 print mail "Content-Type: application/x-chess;name=$PGN_GAME.pgn\n\n";
1448 $opened = open (mail, "|$MAILPROG -s \"$subject\" $OPP_ADDRESS") ;
1453 print ( "Mailed cmail message to \"$OPP_ADDRESS\":\n"
1454 . "$move_msg <$PGN_GAME>\n") ;
1455 @ARCHIVE = @results unless ($unfinished) ;
1457 die "Failed to mail cmail message.\n" ;
1460 print ( "Email not sent (as requested).\n"
1461 . "Would have mailed cmail message to \"$OPP_ADDRESS\":\n"
1462 . "$NUM_GAMES games <$PGN_GAME>\n") ;
1466 print "Email not sent (the game is over).\n" ;
1468 die "No games found\n" ;
1472 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1475 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1476 ## Get date from array of games
1477 sub get_date_from_games {
1478 local (@games) = @_ ;
1480 local ($date) = "nodate" ;
1483 if (/\[Date\s"(.*)"\]/) {
1485 last ; ## Assume all dates are the same
1491 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1494 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1495 ## Determine which colour is to play and the move number
1497 &debug ("Called <get_to_play>\n") ;
1498 local ($game) = shift ;
1500 local ($number, $to_play) = (1, "White") ;
1502 $game =~ s/{[^}]*}//g ;
1503 $game =~ s/[\s\n]*[*][\s\n]*$// ;
1505 if ($game =~ /(\d+)[.][\n ]*([.]*)[\n ]*([^\n.]*)[\n\s]*[10-]*[\n\s]*$/) {
1508 if ($game =~ /\[Result "0-1"\]/) {
1509 $to_play = "Black" ;
1510 } elsif ($game =~ /\[Result "1-0"\]/) {
1511 $to_play = "White" ;
1512 } elsif (($2 ne "") || (($3 =~ / /) || ($3 eq ""))) {
1513 $to_play = "White" ;
1516 $to_play = "Black" ;
1520 &debug ("$to_play to play on move $number\n") ;
1522 return ($number, $to_play) ;
1524 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1527 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1528 ## Get opp address from array of games
1529 sub get_opp_address_from_games {
1530 &debug ("Called <get_opp_address_from_games>\n") ;
1531 local (@games) = @_ ;
1533 local ($opp_address) = "" ;
1534 local ($number, $to_play, $tag) ;
1539 ($number, $to_play) = &get_to_play ($_) ;
1540 $tag = ( ($to_play eq "White")
1544 if (/\[$tag\s"(.*)"\]/) {
1546 die "cmail: Empty \"$tag\" tag\n" unless ($opp_address) ;
1547 &debug ("Found opponent's address \"$opp_address\" from games.\n") ;
1548 last ; ## Assume all opp addresses are the same
1550 die "cmail: Can't find \"$tag\" tag\n" ;
1554 die "cmail: Can't find opponent's email address\n" unless ($opp_address) ;
1556 return ($opp_address) ;
1558 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1561 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1562 ## Archive @ARCHIVE in the $ARCDIR directory
1564 return () unless (@ARCHIVE) ;
1566 local ($date) = &get_date_from_games (@ARCHIVE) ;
1568 local ($file) = "$ARCDIR/$PGN_GAME.$date.archive" ;
1569 if (open (archive, ">$file")) {
1570 print archive @ARCHIVE ;
1572 print "Archived game in $file\n" ;
1573 local (@remove) = <$PGN_GAME*> ;
1574 @remove = grep ($_ ne "$PGN_GAME.$date.archive",
1575 @remove) ; ## Don't delete archive
1578 print "Couldn't open \"$file\" to archive game\n" ;
1581 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1584 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1587 local (@games) = () ;
1589 &initialise () ; ## Initialise variables etc.
1591 if (-t || $REMAIL) { ## No input directed (invoked from a shell rather than a mailer)
1592 &debug ("Interactive!\n") ;
1593 &find_game () ; ## Get the necessary info about the game
1595 &debug ("Piping!\n") ;
1596 &analyse_email_message () ; ## Analyse the mail message
1599 if (! &play_game ()) { ## Load the game
1600 &send_move () ; ## Analyse output and send moves
1603 &archive () ; ## Archive games if all finished
1605 close (tty) ; ## Tidy up
1606 close (logfile) if ($DEBUG) ; ## Tidy up
1608 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1610 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1612 cmail $Revision$, Copyright (C) 1993 Free Software Foundation, Inc.
1613 cmail comes with ABSOLUTELY NO WARRANTY; for details type `cmail -w'.
1614 cmail is free software, and you are welcome to redistribute it
1615 under certain conditions; type `cmail -c' for details.
1617 {END OF GPL COPYRIGHT}
1618 GNU GENERAL PUBLIC LICENSE
1619 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
1621 0. This License applies to any program or other work which contains
1622 a notice placed by the copyright holder saying it may be distributed
1623 under the terms of this General Public License. The "Program", below,
1624 refers to any such program or work, and a "work based on the Program"
1625 means either the Program or any derivative work under copyright law:
1626 that is to say, a work containing the Program or a portion of it,
1627 either verbatim or with modifications and/or translated into another
1628 language. (Hereinafter, translation is included without limitation in
1629 the term "modification".) Each licensee is addressed as "you".
1631 Activities other than copying, distribution and modification are not
1632 covered by this License; they are outside its scope. The act of
1633 running the Program is not restricted, and the output from the Program
1634 is covered only if its contents constitute a work based on the
1635 Program (independent of having been made by running the Program).
1636 Whether that is true depends on what the Program does.
1638 1. You may copy and distribute verbatim copies of the Program's
1639 source code as you receive it, in any medium, provided that you
1640 conspicuously and appropriately publish on each copy an appropriate
1641 copyright notice and disclaimer of warranty; keep intact all the
1642 notices that refer to this License and to the absence of any warranty;
1643 and give any other recipients of the Program a copy of this License
1644 along with the Program.
1646 You may charge a fee for the physical act of transferring a copy, and
1647 you may at your option offer warranty protection in exchange for a fee.
1649 2. You may modify your copy or copies of the Program or any portion
1650 of it, thus forming a work based on the Program, and copy and
1651 distribute such modifications or work under the terms of Section 1
1652 above, provided that you also meet all of these conditions:
1654 a) You must cause the modified files to carry prominent notices
1655 stating that you changed the files and the date of any change.
1657 b) You must cause any work that you distribute or publish, that in
1658 whole or in part contains or is derived from the Program or any
1659 part thereof, to be licensed as a whole at no charge to all third
1660 parties under the terms of this License.
1662 c) If the modified program normally reads commands interactively
1663 when run, you must cause it, when started running for such
1664 interactive use in the most ordinary way, to print or display an
1665 announcement including an appropriate copyright notice and a
1666 notice that there is no warranty (or else, saying that you provide
1667 a warranty) and that users may redistribute the program under
1668 these conditions, and telling the user how to view a copy of this
1669 License. (Exception: if the Program itself is interactive but
1670 does not normally print such an announcement, your work based on
1671 the Program is not required to print an announcement.)
1673 These requirements apply to the modified work as a whole. If
1674 identifiable sections of that work are not derived from the Program,
1675 and can be reasonably considered independent and separate works in
1676 themselves, then this License, and its terms, do not apply to those
1677 sections when you distribute them as separate works. But when you
1678 distribute the same sections as part of a whole which is a work based
1679 on the Program, the distribution of the whole must be on the terms of
1680 this License, whose permissions for other licensees extend to the
1681 entire whole, and thus to each and every part regardless of who wrote it.
1683 Thus, it is not the intent of this section to claim rights or contest
1684 your rights to work written entirely by you; rather, the intent is to
1685 exercise the right to control the distribution of derivative or
1686 collective works based on the Program.
1688 In addition, mere aggregation of another work not based on the Program
1689 with the Program (or with a work based on the Program) on a volume of
1690 a storage or distribution medium does not bring the other work under
1691 the scope of this License.
1693 3. You may copy and distribute the Program (or a work based on it,
1694 under Section 2) in object code or executable form under the terms of
1695 Sections 1 and 2 above provided that you also do one of the following:
1697 a) Accompany it with the complete corresponding machine-readable
1698 source code, which must be distributed under the terms of Sections
1699 1 and 2 above on a medium customarily used for software interchange; or,
1701 b) Accompany it with a written offer, valid for at least three
1702 years, to give any third party, for a charge no more than your
1703 cost of physically performing source distribution, a complete
1704 machine-readable copy of the corresponding source code, to be
1705 distributed under the terms of Sections 1 and 2 above on a medium
1706 customarily used for software interchange; or,
1708 c) Accompany it with the information you received as to the offer
1709 to distribute corresponding source code. (This alternative is
1710 allowed only for noncommercial distribution and only if you
1711 received the program in object code or executable form with such
1712 an offer, in accord with Subsection b above.)
1714 The source code for a work means the preferred form of the work for
1715 making modifications to it. For an executable work, complete source
1716 code means all the source code for all modules it contains, plus any
1717 associated interface definition files, plus the scripts used to
1718 control compilation and installation of the executable. However, as a
1719 special exception, the source code distributed need not include
1720 anything that is normally distributed (in either source or binary
1721 form) with the major components (compiler, kernel, and so on) of the
1722 operating system on which the executable runs, unless that component
1723 itself accompanies the executable.
1725 If distribution of executable or object code is made by offering
1726 access to copy from a designated place, then offering equivalent
1727 access to copy the source code from the same place counts as
1728 distribution of the source code, even though third parties are not
1729 compelled to copy the source along with the object code.
1731 4. You may not copy, modify, sublicense, or distribute the Program
1732 except as expressly provided under this License. Any attempt
1733 otherwise to copy, modify, sublicense or distribute the Program is
1734 void, and will automatically terminate your rights under this License.
1735 However, parties who have received copies, or rights, from you under
1736 this License will not have their licenses terminated so long as such
1737 parties remain in full compliance.
1739 5. You are not required to accept this License, since you have not
1740 signed it. However, nothing else grants you permission to modify or
1741 distribute the Program or its derivative works. These actions are
1742 prohibited by law if you do not accept this License. Therefore, by
1743 modifying or distributing the Program (or any work based on the
1744 Program), you indicate your acceptance of this License to do so, and
1745 all its terms and conditions for copying, distributing or modifying
1746 the Program or works based on it.
1748 6. Each time you redistribute the Program (or any work based on the
1749 Program), the recipient automatically receives a license from the
1750 original licensor to copy, distribute or modify the Program subject to
1751 these terms and conditions. You may not impose any further
1752 restrictions on the recipients' exercise of the rights granted herein.
1753 You are not responsible for enforcing compliance by third parties to
1756 7. If, as a consequence of a court judgment or allegation of patent
1757 infringement or for any other reason (not limited to patent issues),
1758 conditions are imposed on you (whether by court order, agreement or
1759 otherwise) that contradict the conditions of this License, they do not
1760 excuse you from the conditions of this License. If you cannot
1761 distribute so as to satisfy simultaneously your obligations under this
1762 License and any other pertinent obligations, then as a consequence you
1763 may not distribute the Program at all. For example, if a patent
1764 license would not permit royalty-free redistribution of the Program by
1765 all those who receive copies directly or indirectly through you, then
1766 the only way you could satisfy both it and this License would be to
1767 refrain entirely from distribution of the Program.
1769 If any portion of this section is held invalid or unenforceable under
1770 any particular circumstance, the balance of the section is intended to
1771 apply and the section as a whole is intended to apply in other
1774 It is not the purpose of this section to induce you to infringe any
1775 patents or other property right claims or to contest validity of any
1776 such claims; this section has the sole purpose of protecting the
1777 integrity of the free software distribution system, which is
1778 implemented by public license practices. Many people have made
1779 generous contributions to the wide range of software distributed
1780 through that system in reliance on consistent application of that
1781 system; it is up to the author/donor to decide if he or she is willing
1782 to distribute software through any other system and a licensee cannot
1785 This section is intended to make thoroughly clear what is believed to
1786 be a consequence of the rest of this License.
1788 8. If the distribution and/or use of the Program is restricted in
1789 certain countries either by patents or by copyrighted interfaces, the
1790 original copyright holder who places the Program under this License
1791 may add an explicit geographical distribution limitation excluding
1792 those countries, so that distribution is permitted only in or among
1793 countries not thus excluded. In such case, this License incorporates
1794 the limitation as if written in the body of this License.
1796 9. The Free Software Foundation may publish revised and/or new versions
1797 of the General Public License from time to time. Such new versions will
1798 be similar in spirit to the present version, but may differ in detail to
1799 address new problems or concerns.
1801 Each version is given a distinguishing version number. If the Program
1802 specifies a version number of this License which applies to it and "any
1803 later version", you have the option of following the terms and conditions
1804 either of that version or of any later version published by the Free
1805 Software Foundation. If the Program does not specify a version number of
1806 this License, you may choose any version ever published by the Free Software
1809 10. If you wish to incorporate parts of the Program into other free
1810 programs whose distribution conditions are different, write to the author
1811 to ask for permission. For software which is copyrighted by the Free
1812 Software Foundation, write to the Free Software Foundation; we sometimes
1813 make exceptions for this. Our decision will be guided by the two goals
1814 of preserving the free status of all derivatives of our free software and
1815 of promoting the sharing and reuse of software generally.
1816 {END OF GPL CONDITIONS}
1817 GNU GENERAL PUBLIC LICENSE
1820 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
1821 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
1822 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
1823 PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
1824 OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1825 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
1826 TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
1827 PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
1828 REPAIR OR CORRECTION.
1830 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
1831 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
1832 REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
1833 INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
1834 OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
1835 TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
1836 YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
1837 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
1838 POSSIBILITY OF SUCH DAMAGES.