1#! @PERLPATH@
2## (configure will change the top line to the location of perl on your system)
3#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
4## cmail: a tool to aid playing chess by email
5## Copyright (C) 1993,2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
6##
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.
11##
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.
16##
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/.  *
19##
20## Email:     evan@quadstone.co.uk
21## Snailmail: Evan Welsh
22##            Quadstone Ltd
23##            16 Chester Street
24##            Edinburgh EH3 7RA
25##            Scotland
26#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
27
28
29#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
30## Print verbose diagnostics for debugging
31sub debug {
32    if ($DEBUG) {
33	local ($old) = select ;	## Remember selected output
34	select (logfile) ;
35	$| = 1 ;		## Keep it flushed
36	print @_ ;		## Print arguments
37	select ($old) ;
38    }
39}
40#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
41
42
43#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
44## Create a directory for storing games in if it doesn't already exist
45sub need_chess_dir {
46    local ($old) ;
47
48    ## ################################################################# ##
49    ## Check for existence of the named chess directory
50    ## ################################################################# ##
51
52    if (! (-d "$CMAILDIR")) {
53
54	## ############################################################# ##
55	## Ask user for confirmation if attached to tty
56	## ############################################################# ##
57
58	if (-t) {
59	    $old = select ;	## Remember selected output
60	    select (stdout) ;	## Write to standard output
61	    $| = 1 ;		## Keep it flushed
62	    print (  "CMail directory \"$CMAILDIR\" does not exist."
63		   . " Create it? [y/q]: ") ;
64
65	    $_ = <tty> ;	## Read response from tty
66	    die "Bye!\n" if (/^[qQ].*/) ; ## Quit if q selected
67
68	    select ($old) ;	## Re-select the old output
69	}
70
71	## ############################################################# ##
72	## Create a cmail directory or die
73	## ############################################################# ##
74
75	die "cmail: Can't create CMail directory: \"$CMAILDIR\"\n"
76	    unless mkdir ("$CMAILDIR", 511) ;
77	print (  "Created cmail directory \"$CMAILDIR\".\n"
78	       . "You can move it but remember to set the CMAIL_DIR"
79	       . " environment variable.\n") ;
80    }
81
82    ## ################################################################# ##
83    ## Change to the $CMAILDIR directory whether newly created or not
84    ## ################################################################# ##
85
86    die "Couldn't changed directory to \"$CMAILDIR\"\n"
87	unless (chdir "$CMAILDIR") ;
88
89    ## ################################################################# ##
90    ## Check for existence of the named chess directory
91    ## ################################################################# ##
92
93    if (! (-d "$ARCDIR")) {
94
95	## ############################################################# ##
96	## Ask user for confirmation if attached to tty
97	## ############################################################# ##
98
99	if (-t) {
100	    $old = select ;	## Remember selected output
101	    select (stdout) ;	## Write to standard output
102	    $| = 1 ;		## Keep it flushed
103	    print (  "Archive directory \"$ARCDIR\" does not exist."
104		   . " Create it? [y/q]: ") ;
105
106	    $_ = <tty> ;	## Read response from tty
107	    die "Bye!\n" if (/^[qQ].*/) ; ## Quit if q selected
108
109	    select ($old) ;	## Re-select the old output
110	}
111
112	## ############################################################# ##
113	## Create a chess directory or die
114	## ############################################################# ##
115
116	die "cmail: Can't create archive directory: \"$ARCDIR\"\n"
117	    unless mkdir ("$ARCDIR", 511) ;
118	print (  "Created archive directory \"$ARCDIR\".\n"
119	       . "You can move it but remember to set the CMAIL_ARCDIR"
120	       . " environment variable.\n") ;
121    }
122}
123#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
124
125
126#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
127## Parse command-line arguments
128sub parse_flags {
129    ## ################################################################# ##
130    ## Set up defaults from the environment or from hard-wired constants
131    ## ################################################################# ##
132
133    $SHOWC       = 0 ;
134    $SHOWW       = 0 ;
135    $OUTPUT_POS  = $ENV{'CMAIL_OUTPUT_POS'} ;
136    $LOGFILE     = $ENV{'CMAIL_LOGFILE'} ;
137    $MAILPROG    = $ENV{'CMAIL_MAILPROG'} ;
138    $MAILPROG    = "/usr/sbin/sendmail" if (   (-x "/usr/sbin/sendmail")
139					    && (! $MAILPROG)) ;
140    $MAILPROG    = "/usr/lib/sendmail" if (   (-x "/usr/lib/sendmail")
141					   && (! $MAILPROG)) ;
142    $MAILPROG    = "/etc/sendmail" if (   (-x "/usr/lib/sendmail")
143					   && (! $MAILPROG)) ;
144    $MAILPROG    = "/usr/ucb/Mail" if (   (-x "/usr/ucb/Mail")
145				       && (! $MAILPROG)) ;
146    $MAILPROG    = "/usr/ucb/mail" if (   (-x "/usr/ucb/mail")
147				       && (! $MAILPROG)) ;
148    $MAILPROG    = "Mail" unless ($MAILPROG) ;
149    $HOMEDIR     = $ENV{'HOME'} ;
150    $CMAILDIR	 = $ENV{'CMAIL_DIR'} ;
151    $CMAILDIR	 = $ENV{'CHESSDIR'} unless ($CMAILDIR) ;
152    $CMAILDIR	 = "$HOMEDIR/Chess" unless ($CMAILDIR) ;
153    $CMAILDIR	 = "~/Chess"        unless ($HOMEDIR) ;
154    $NUM_GAMES	 = "?" ;
155    $NUM_WGAMES	 = "?" ;
156    $NUM_BGAMES	 = "?" ;
157    $TIME_DELAY	 = $ENV{'CMAIL_TIME_DELAY'} ;
158    $TIME_DELAY	 = 0 unless ($TIME_DELAY) ;
159    $PW_NAME     = &get_pw_name () ;
160    $MY_NNAME	 = $PW_NAME ;
161    $MY_NNAME	 = $ENV{'LOGNAME'} unless ($MY_NNAME) ;
162    $MY_NNAME	 = $ENV{'USER'} unless ($MY_NNAME) ;
163    $MY_NNAME	 = "?" unless ($MY_NNAME) ;
164    $PGN_EVENT   = "Email correspondence game" ;
165    $PGN_SITE	 = "NET";
166    $PGN_ROUND	 = "-";
167    $PGN_MODE    = "EM";
168    $SEND_MAIL   = 1 ;
169    $REMAIL      = 0 ;
170    $LOAD_XBOARD = 1 unless $ENV{'CMAIL_NO_XBOARD'} ;
171    $REUSE       = 1 ;
172    @TD_FLAGS    = ("-td", $TIME_DELAY) ;
173    @NCP_FLAGS   = ("-ncp") ;
174
175    ## ################################################################# ##
176    ## Define the usage string
177    ## ################################################################# ##
178
179    $USAGE = ("cmail
180        [-h] [-c] [-w] [-[x]v] [-[x]mail] [-[x]xboard] [-[x]reuse] [-remail]
181        [-game <name>] [-(w|b|)games <number>] [-(me|opp) <short name>]
182        [-(w|b|my|opp)name <full name>] [-(w|b|my|opp)na <email>]
183        [-dir <directory>] [-arcdir <directory>] [-mailprog <mail program>]
184        [-logFile <file>] [-event <event>] [-site <site>] [-round <round>]
185	[-mode <mode>]") ;
186
187    ## ################################################################# ##
188    ## Overwrite defaults if specified on the command-line
189    ## ################################################################# ##
190
191    @UNREC_ARGS = () ;
192    while ($ARGV = shift) {
193	$UNREC = 0 if ($ARGV =~ /^-/) ;
194	if    ("$ARGV" eq "-h")		  {die ("Usage: $USAGE\n")     ;}
195	elsif ("$ARGV" eq "-c")		  {$SHOWC       = 1            ;}
196	elsif ("$ARGV" eq "-w")		  {$SHOWW       = 1            ;}
197	elsif ("$ARGV" eq "-v")		  {$DEBUG       = 1            ;
198				           @DEBUG_FLAGS = ("-debug")   ;}
199	elsif ("$ARGV" eq "-xv")	  {$DEBUG       = 0            ;
200				           $QUIET       = 1            ;}
201	elsif ("$ARGV" eq "-mail")	  {$SEND_MAIL   = 1            ;}
202	elsif ("$ARGV" eq "-xmail")	  {$SEND_MAIL   = 0            ;}
203	elsif ("$ARGV" eq "-xboard")	  {$LOAD_XBOARD = 1            ;}
204	elsif ("$ARGV" eq "-xxboard")	  {$LOAD_XBOARD = 0            ;}
205	elsif ("$ARGV" eq "-reuse")	  {$REUSE       = 1            ;}
206	elsif ("$ARGV" eq "-xreuse")	  {$REUSE       = 0            ;}
207	elsif ("$ARGV" eq "-remail")      {$LOAD_XBOARD = 0            ;
208					   $SEND_MAIL   = 1            ;
209					   $REMAIL      = 1            ;}
210	elsif ("$ARGV" eq "-game")	  {$PGN_GAME    = shift        ;}
211	elsif ("$ARGV" eq "-games")       {$NUM_GAMES   = shift        ;}
212	elsif ("$ARGV" eq "-wgames")      {$NUM_WGAMES  = shift        ;}
213	elsif ("$ARGV" eq "-bgames")      {$NUM_BGAMES  = shift        ;}
214	elsif ("$ARGV" eq "-me")	  {$MY_NNAME    = shift        ;}
215	elsif ("$ARGV" eq "-opp")	  {$OPP_NNAME   = shift        ;}
216	elsif ("$ARGV" eq "-myname")	  {$MY_FNAME    = shift        ;}
217	elsif ("$ARGV" eq "-oppname")	  {$OPP_FNAME   = shift        ;}
218	elsif ("$ARGV" eq "-wname")	  {$WHITE_FNAME	= shift	       ;}
219	elsif ("$ARGV" eq "-bname")	  {$BLACK_FNAME	= shift	       ;}
220	elsif ("$ARGV" eq "-myna")	  {$MY_ADDRESS  = shift        ;}
221	elsif ("$ARGV" eq "-oppna")	  {$OPP_ADDRESS = shift        ;}
222	elsif ("$ARGV" eq "-wna")	  {$WHITENA	= shift	       ;}
223	elsif ("$ARGV" eq "-bna")	  {$BLACKNA	= shift	       ;}
224	elsif ("$ARGV" eq "-dir")	  {$CMAILDIR    = shift        ;}
225	elsif ("$ARGV" eq "-arcdir")	  {$ARCDIR      = shift        ;}
226	elsif ("$ARGV" eq "-mailprog")	  {$MAILPROG    = shift        ;}
227	elsif ("$ARGV" eq "-logFile")     {$LOGFILE     = shift        ;}
228	elsif ("$ARGV" =~ /^-(td|timeDelay)$/)
229	                                  {@TD_FLAGS    = ($ARGV,
230							   shift)      ;}
231	elsif ("$ARGV" =~ /^-noChessComputer$/)
232	                                  {@NCP_FLAGS   = ($ARGV,
233							   shift)      ;}
234	elsif ("$ARGV" =~ /^-[x]?ncp$/)	  {@NCP_FLAGS	= ($ARGV)      ;}
235	elsif ("$ARGV" eq "-event")	  {$PGN_EVENT	= shift        ;}
236	elsif ("$ARGV" eq "-site")	  {$PGN_SITE	= shift        ;}
237	elsif ("$ARGV" eq "-round")	  {$PGN_ROUND	= shift        ;}
238	elsif ("$ARGV" eq "-mode")	  {$PGN_MODE	= shift        ;}
239	elsif ("$ARGV" =~ /^-/ || $UNREC) {
240	    push(@UNREC_ARGS, $ARGV) ;
241	    $UNREC = 1 ;
242	} else {
243	    die("cmail: Unrecognised flag \"$ARGV\"\nUsage: $USAGE\n") ;
244	}
245    }
246
247    ## ################################################################# ##
248    ## Assign a value to $ARCDIR if not specified on the command line
249    ## ################################################################# ##
250
251    $ARCDIR = $ENV{'CMAIL_ARCDIR'} unless ($ARCDIR) ;
252    $ARCDIR = $CMAILDIR unless ($ARCDIR) ;
253    $ENV{'CMAIL_ARCDIR'} = $ARCDIR ; ## Make sure this is set for xboard
254
255    ## ################################################################# ##
256    ## Propagate some CMAIL variables through xboard to the cmail
257    ## grandchild so that it uses the same important variables as this one
258    ## ################################################################# ##
259
260    $ENV{'CMAIL_MAILPROG'} = $MAILPROG ;
261    $ENV{'CMAIL_DIR'}      = $CMAILDIR ;
262    $ENV{'CHESSDIR'}       = $CMAILDIR ; ## Make xboard use $CMAILDIR
263    $ENV{'CMAIL_ARCDIR'}   = $ARCDIR ;
264    if ($LOGFILE) {
265	$ENV{'CMAIL_LOGFILE'}  = $LOGFILE ;
266    } else {
267	$LOGFILE = "&STDERR" ;
268    }
269
270    ## ################################################################# ##
271    ## Work out how many games of each colour will be played
272    ## ################################################################# ##
273
274    die "cmail: Illegal number of games: $NUM_GAMES\n"
275	if ($NUM_GAMES < 0) ;
276    die "cmail: Illegal number of white games: $NUM_WGAMES\n"
277	if ($NUM_WGAMES < 0) ;
278    die "cmail: Illegal number of black games: $NUM_BGAMES\n"
279	if ($NUM_BGAMES < 0) ;
280    if ("$NUM_GAMES" ne "?") {
281	if ("$NUM_WGAMES" eq "?") {
282	    if ("$NUM_BGAMES" eq "?") {
283		$NUM_BGAMES = int($NUM_GAMES / 2) ;
284	    }
285	    $NUM_WGAMES = $NUM_GAMES - $NUM_BGAMES ;
286	} elsif ("$NUM_BGAMES" eq "?") {
287	    $NUM_BGAMES = $NUM_GAMES - $NUM_WGAMES ;
288	}
289    } elsif ("$NUM_WGAMES" eq "?") {
290	if ("$NUM_BGAMES" eq "?") {
291	    $NUM_GAMES  = 1 ;
292	    $NUM_WGAMES = 1 ;
293	    $NUM_BGAMES = 0 ;
294	} else {
295	    $NUM_GAMES  = $NUM_BGAMES ;
296	    $NUM_WGAMES = 0 ;
297	}
298    } else {
299	if ("$NUM_BGAMES" eq "?") {
300	    $NUM_GAMES  = $NUM_WGAMES ;
301	    $NUM_BGAMES = 0 ;
302	} else {
303	    $NUM_GAMES  = $NUM_WGAMES + $NUM_BGAMES ;
304	}
305    }
306    die "cmail: Illegal number of games: $NUM_GAMES\n"
307	if ("$NUM_GAMES" eq "0") ;
308    die (  "cmail: Inconsistent numbers of games specified:"
309	 . " $NUM_WGAMES + $NUM_BGAMES != $NUM_GAMES\n")
310	unless ($NUM_GAMES == $NUM_WGAMES + $NUM_BGAMES) ;
311}
312#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
313
314
315#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
316## Initialisation of variables and environment
317sub showGPL {
318    ## ################################################################# ##
319    ## Show copyright notice
320    ## ################################################################# ##
321
322    while (<DATA>) {
323	last if (/^{END OF GPL COPYRIGHT}$/) ;
324	s/\$Revision[:] (.*) \$/$1/ ;
325	print ;
326    }
327
328    ## ################################################################# ##
329    ## Show conditions if requested
330    ## ################################################################# ##
331
332    while (<DATA>) {
333	last if (/^{END OF GPL CONDITIONS}$/) ;
334	print if ($SHOWW) ;
335    }
336
337    ## ################################################################# ##
338    ## Show warranty if requested
339    ## ################################################################# ##
340
341    if ($SHOWC) {
342	print "\n" if ($SHOWW) ;
343	print while (<DATA>) ;
344    }
345
346
347    exit 0 if ($SHOWC || $SHOWW) ; ## Abort if showed conditions or warranty
348}
349#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
350
351
352#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
353## Initialisation of variables and environment
354sub initialise {
355    local ($p) = "[.PRNBQKprnbqk]" ;
356    local ($l) = "$p $p $p $p $p $p $p $p\n" ;
357    local ($board) = "$l$l$l$l$l$l$l$l" ;
358    local ($tp) = ".* to play\n" ;
359    $posdiag = "\{--------------\n$board$tp--------------\}\n+" ;
360
361    &parse_flags (@ARGV) ;	## Parse command-line arguments
362
363    &showGPL unless $QUIET ;
364
365    open (tty, "< /dev/tty") ;	## Open tty for reading
366
367    &need_chess_dir () ;	## Check for the existence of CMAILDIR
368
369    open (logfile, ">$LOGFILE") if ($DEBUG) ; ## Default is STDERR
370
371    &debug ("Called <initialise>\n") ;
372}
373#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
374
375
376#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
377## Prompt for a game name, if <cr> use a default
378sub prompt_for_game_name {
379    &debug ("Called <prompt_for_game_name>\n") ;
380    local ($old) = select ;	## Remember the selected output
381    select (stdout);		## Prompt goes to stdout
382    $| = 1 ;			## Keep it flushed
383
384    print "Game name [<cr> to use default]: " ;
385    die "cmail: tty not open\n" unless (-t) ;
386    <tty> =~ /(.*)/ ;		## Read line from tty
387    $PGN_GAME = "$1" ;		## Assign to game name
388
389    select ($old) ;		## Re-select the old output
390}
391#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
392
393
394#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
395## Prompt for opponent's address
396sub prompt_for_opp_address {
397    &debug ("Called <prompt_for_opp_address>\n") ;
398    local ($old) = select ;	## Remember the selected output
399    select (stdout);		## Prompt goes to stdout
400    $| = 1 ;			## Keep it flushed
401
402    ## ################################################################# ##
403    ## Prompt for opponent's email address
404    ## ################################################################# ##
405
406    print "Opponent's email address: " ;
407    die "cmail: tty not open\n" unless (-t) ;
408    <tty> =~ /(.*)/ ;
409    $OPP_ADDRESS = $1 ;
410
411    ## ################################################################# ##
412    ## Use name as default if still blank
413    ## ################################################################# ##
414
415    $OPP_ADDRESS = $OPP_NNAME if ("" eq $OPP_ADDRESS) ;
416
417    select ($old) ;		## Re-select the old output
418}
419#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
420
421
422#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
423## Prompt for opponent's name
424sub prompt_for_opp_name {
425    &debug ("Called <prompt_for_opp_name>\n") ;
426    local ($old) = select ;	## Remember the selected output
427    select (stdout) ;		## Prompt goes to stdout
428    $| = 1 ;			## Keep it flushed
429    print "Opponent's name: " ;
430
431    die "cmail: tty not open\n" unless (-t) ; ## Check tty is open
432    <tty> =~ /(.*)/ ;		## Read line from tty
433    $OPP_NNAME = $1 ;		## Match!
434    die "cmail: Can't proceed without the opponent's name.\n"
435	unless ($OPP_NNAME) ;
436
437    select ($old) ;		## Re-select the old output
438}
439#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
440
441
442#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
443## Prompt for move
444sub prompt_for_move {
445    local ($prompt) = shift ;
446    local ($pattern) = shift ;
447    &debug ("Called <prompt_for_move>\n") ;
448
449    local ($move) = "" ;
450    local ($old) = select ;	## Remember the selected output
451    select (stdout) ;		## Write to stdout
452    $| = 1 ;			## Keep it flushed
453    die "cmail: tty not open\n" unless (-t) ; ## Check tty is open
454
455    do {
456	print $prompt ;
457	<STDIN> =~ /(.*)/ ;	## Read line from tty
458	$move = $1 ;		## Match!
459    } until ($move =~ /^$pattern$/) ;
460
461    select ($old) ;		## Re-select the old output
462    return ($move) ;
463}
464#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
465
466
467#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
468## Load the game
469sub play_game {
470    &debug ("Called <play_game>\n") ;
471
472    $| = 1 ;			## Start flushing output buffer
473
474    ## ################################################################# ##
475    ## Load xboard unless inhibited by command-line arguments
476    ## ################################################################# ##
477
478    if (($STARTING_NEW_GAME) && ($NUM_WGAMES == 0)) {
479	print (  "Bypassing xboard and mailing $NUM_BGAMES empty"
480	       . " black games.\n") ;
481    } elsif ($LOAD_XBOARD) {
482	## ############################################################# ##
483	## Remove output file from previous run, but preserve
484	## $PGN_GAME.game.out.* because they will be empty black games
485	## ############################################################# ##
486
487	unlink "$PGN_GAME.out" ;
488
489	## ############################################################# ##
490	## Invoke xboard with loads of flags
491	## ############################################################# ##
492
493	if ($PGN_GAME) {
494	    if (@ARCHIVE) {
495		local ($date) = &get_date_from_games (@ARCHIVE) ;
496		$XBOARD_ARGS = join (' ', (("-lgf",
497					    "'$ARCDIR/$PGN_GAME.$date.archive'"),
498					   @NCP_FLAGS,
499					   "-xics",
500					   @TD_FLAGS,
501					   @DEBUG_FLAGS,
502					   @UNREC_ARGS)) ;
503	    } else {
504		$XBOARD_ARGS = join (' ', (("-cmail", "'$PGN_GAME'"),
505					   @TD_FLAGS,
506					   @NCP_FLAGS,
507					   "-xics",
508					   @DEBUG_FLAGS,
509					   @UNREC_ARGS)) ;
510	    }
511	} else {
512	    $PGN_GAME = "unknown.cmail" ;
513	    $XBOARD_ARGS = join (' ', (("-lgf", "'$PGN_GAME'"),
514				       @NCP_FLAGS,
515				       "-xics",
516				       @TD_FLAGS,
517				       @DEBUG_FLAGS,
518				       @UNREC_ARGS)) ;
519	    $REUSE = 0 ;
520	}
521
522	$LOG_FILE = "$PGN_GAME.log" ;
523	&debug ("Invoking xboard with args: $XBOARD_ARGS\n") ;
524	$PID_FILE = "$PGN_GAME.pid" ;
525	if (   (! $REUSE)
526	    || (! (   (-f $PID_FILE)
527		   && ($XBOARD_PID = `cat '$PID_FILE'`)
528		   && ("$XBOARD_PID" =~ /^\d+$/)
529		   && (kill "SIGUSR1", $XBOARD_PID)))) {
530	    print "Loading xboard for game \"$PGN_GAME\"..." ;
531#  	    system ("gdb xboard") ;
532	    system (  "{ ({ xboard $XBOARD_ARGS & } ;"
533		    . "   echo \$! > '$PID_FILE' ;"
534		    . "   wait ;"
535		    . "   rm '$PID_FILE') & } >'$LOG_FILE' 2>&1") ;
536	    print (  "done.\n"
537		   . "If nothing happens look for an error message in\n"
538		   . "$CMAILDIR/$LOG_FILE\n") ;
539	} else {
540	    print ("Revived existing xboard for game \"$PGN_GAME\".\n"
541		   . "If nothing happens"
542		   . " remove $CMAILDIR/$PID_FILE and try again.\n") ;
543	}
544
545	return 1 ;
546    }
547    return 0 ;
548}
549#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
550
551
552#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
553## Enter moves on tty instead of xboard
554sub play_on_tty {
555    &debug ("Called <play_on_tty>\n") ;
556
557    local (@results) = @_ ;
558
559    local (@games, $game, $to_play) ;
560
561    ## ################################################################# ##
562    ## Check we have access to tty
563    ## ################################################################# ##
564
565    if (open(STDIN, '/dev/tty')) {
566	## ############################################################# ##
567	## Read in games
568	## ############################################################# ##
569
570	local ($infile) = "$PGN_GAME.game.in" ;
571	if (-f $infile) {
572	    @games = &get_games_from_file($infile) ;
573	    &debug ("Read in games from \"$infile\"\n") ;
574
575	    if (@results) {
576		foreach $game (@games) {
577		    $result = shift (@results) ;
578		    if ($result && ($game =~ /\[Result\s+"[^*]+"\]/)) {
579			$game = "" ;
580		    }
581		}
582	    }
583
584	    ## ################################################################# ##
585	    ## Accept move on tty for each game in turn
586	    ## ################################################################# ##
587
588	    local ($comment_orig, $comment, $comment_line,
589		   $pos, $move, $normal_move, $action, $result) ;
590
591	    foreach $game (@games) {
592		next unless $game ;
593
594		$game =~ s/[\s\n]*[*]?[\s\n]*$// ;
595		$pos = "" ;
596		$pos = $1 if ($game =~ s/($posdiag)//) ;
597		print $game, "\n\n", $pos ;
598
599		($number, $to_play) = &get_to_play ($game) ;
600
601		$comment_orig = "" ;
602		$game_nocomment = $game ;
603		if ($game_nocomment =~ s/\n?{\n?([^{]*)}$//) {
604		    $comment_orig = $1 ;
605		    $comment_orig =~ s/([^\n])$/$1\n/ ;
606#  		    &debug ("Comment is:\n{\n$comment_orig}\n") ;
607		}
608		if ($game =~ /\[Result\s+"[^*]+"\]/) {
609		    &prompt_for_move ("Game finished, press \"Return\" to continue: ", "") ;
610                    next ;
611		}
612
613		$tmpgame = $game_nocomment ;
614		$comment = $comment_orig ;
615
616	      outer:
617		while (1) {
618		    if ($game =~ /{\n?.* offers a draw\n?}$/) {
619			$move = &prompt_for_move ("Enter move [MOVE/(r)esign/(a)ccept/(c)omment/re(t)ry]: ",
620						  "([-a-h0-9PRNBQK][-a-h0-9PRNBQK]+|[ract])") ;
621		    } else {
622			$move = &prompt_for_move ("Enter move [MOVE/(r)esign/(c)omment/re(t)ry]: ",
623						  "([-a-h0-9PRNBQK][-a-h0-9PRNBQK]+|[rct])") ;
624		    }
625		    $normal_move = 0 ;
626		    $result = "" ;
627		    if ($move =~ /^\s*r\s*$/i) {
628			if ($to_play eq "White") {
629			    $result = "0-1" ;
630			} else {
631			    $result = "1-0" ;
632			}
633			$move = "\n{$to_play resigns} $result" ;
634		    } elsif ($move =~ /^\s*a\s*$/i) {
635			$move = "\n{Draw agreed} $result" ;
636		    } elsif ($move =~ /^\s*c\s*$/i) {
637                        while ($comment_line = &prompt_for_move ("Enter comment: ", ".*")) {
638			    $comment .= $comment_line . "\n" ;
639                        }
640			next ;
641		    } elsif ($move =~ /^\s*t\s*$/i) {
642			print $game, "\n\n", $pos ;
643			$tmpgame = $game_nocomment ;
644			$comment = $comment_orig ;
645			print "Try again.\n" ;
646			next ;
647		    } else {
648			$normal_move = 1 ;
649		    }
650
651		    $tmpgame .= "\n{\n" . $comment . "}" if ($comment) ;
652		    if (! $normal_move) {
653			$tmpgame .= "$move"  ;
654		    } elsif ($to_play eq "White") {
655			$tmpgame .= "\n$number. $move"  ;
656		    } elsif ($tmpgame =~ /}$/) {
657			$tmpgame .= "\n$number. ... $move"  ;
658		    } else {
659			$tmpgame .= " $move"  ;
660		    }
661
662		    $tmpgame =~ s/\[Result\s+"(.*)"\]/[Result "$result"]/ if ($result) ;
663		    $comment = "" ;
664		  middle:
665		    while (1) {
666			if ($normal_move) {
667			    $action = &prompt_for_move ("Enter action [(d)raw/(c)omment/(s)end/re(t)ry]: ",
668							"[dcst]") ;
669			} elsif ($result) {
670			    $action = &prompt_for_move ("Enter action [(s)end/re(t)ry]: ",
671							"[st]") ;
672			} else {
673			    $action = &prompt_for_move ("Enter action [(c)omment/(s)end/re(t)ry]: ",
674							"[cst]") ;
675			}
676			if ($action =~ /^\s*d\s*$/i) {
677			    if ($normal_move) {
678				$comment .= "$to_play offers a draw\n" ;
679
680				while (1) {
681				    $action = &prompt_for_move ("Enter action [(c)omment/(s)end/re(t)ry]: ",
682								"[cst]") ;
683				    if ($action =~ /^\s*c\s*$/i) {
684					while ($comment_line = &prompt_for_move ("Enter comment: ", ".*")) {
685					    $comment .= $comment_line . "\n" ;
686                        		}
687				        next ;
688				    } elsif ($action =~ /^\s*t\s*$/i) {
689					print $game, "\n\n", $pos ;
690					$tmpgame = $game_nocomment ;
691					$comment = $comment_orig ;
692					print "Try again.\n" ;
693					next outer;
694				    } elsif ($action =~ /^\s*s\s*$/i) {
695					$tmpgame .= "\n{\n" . $comment . "}" ;
696					last middle ;
697				    }
698				}
699			    } else {
700				print "You can't offer a draw at this point.\n" ;
701				next ;
702			    }
703			} elsif ($action =~ /^\s*c\s*$/i) {
704			    if ($result) {
705				print "You can't enter a comment after the game is finished.\n" ;
706			    } else {
707				while ($comment_line = &prompt_for_move ("Enter comment: ", ".*")) {
708				    $comment .= $comment_line . "\n" ;
709                        	}
710			    }
711			    next ;
712			} elsif ($action =~ /^\s*t\s*$/i) {
713			    print $game, $pos ;
714			    $tmpgame = $game_nocomment ;
715			    $comment = $comment_orig ;
716			    print "Try again.\n" ;
717			    next outer;
718			} elsif ($action =~ /^\s*s\s*$/i) {
719			    $tmpgame .= "\n{\n" . $comment . "}\n" if ($comment) ;
720			    last ;
721			}
722		    }
723
724		    last ;
725		}
726
727		$tmpgame .= "\n*" if ($normal_move) ;
728		$tmpgame .= "\n\n" ;
729		$game = $tmpgame ;
730	    }
731	} else {
732	    die "cmail: No games to be read\n" ;
733	}
734    } else {
735	die "cmail: Can't open tty" ;
736    }
737
738    return (@games) ;
739}
740#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
741
742
743#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
744## Find the game the user wants by any means possible
745sub find_game {
746    &debug ("Called <find_game>\n") ;
747
748    ## ################################################################# ##
749    ## Ask user for a game name if not already known
750    ## ################################################################# ##
751
752    &prompt_for_game_name () if ("" eq "$PGN_GAME") ;
753
754    ## ################################################################# ##
755    ## Find out opponent's details
756    ## ################################################################# ##
757
758    if ("" eq "$PGN_GAME") {
759	## ############################################################# ##
760	## Failed to find the game name so construct a default from players
761	## ############################################################# ##
762
763	&prompt_for_opp_name () if ("" eq "$OPP_NNAME") ; ## Ask user
764	die "cmail: Can't proceed without your opponent's short name (-opp)\n"
765	    if ("" eq "$OPP_NNAME") ;
766	die "cmail: Can't proceed without your own short name (-me)\n"
767	    if ("" eq "$MY_NNAME") ;
768	if ($NUM_WGAMES > 0) {
769	    $PGN_GAME = "$MY_NNAME-vs-$OPP_NNAME" ; ## Construct default
770	} else {
771	    $PGN_GAME = "$OPP_NNAME-vs-$MY_NNAME" ; ## Construct default
772	}
773    } elsif (("" eq "$OPP_ADDRESS") && ("" ne "$RETURN_ADDRESS")) {
774	$OPP_ADDRESS = $RETURN_ADDRESS ; ## Use return address instead
775	&debug (  "Using return address \"$OPP_ADDRESS\""
776		. " for opponent address\n") ;
777    }
778
779    ## ################################################################# ##
780    ## If no $PGN_GAME.game.in file, assume we're starting a new game
781    ## ################################################################# ##
782
783    &start_new_game () unless (-f "$PGN_GAME.game.in") ;
784}
785#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
786
787
788#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
789## Get the date
790sub get_date {
791    local ($the_time) = time ;
792    local ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
793	localtime ($the_time) ;
794    $mon ++ ;
795    $year += 1900 ;
796    if ($mon < 10) {
797	$mon = "0$mon" ;
798    }
799    if ($mday < 10) {
800        $mday = "0$mday" ;
801    }
802    "$year.$mon.$mday" ;
803}
804#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
805
806
807#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
808## Start a new game
809sub start_new_game {
810    print (  "Starting new game"
811	   . " -- $NUM_WGAMES as white, $NUM_BGAMES as black.\n") ;
812    local ($to_play) = "white" ;
813    $move_num = 0 ;
814    $STARTING_NEW_GAME = 1 ;
815
816    local (@game) ;
817
818    ## ################################################################# ##
819    ## Ask user for opponent's email address if unknown
820    ## ################################################################# ##
821
822    &prompt_for_opp_address () if ("" eq "$OPP_ADDRESS") ;
823
824    ## ################################################################# ##
825    ## Give up if we haven't got anywhere to send a move to
826    ## ################################################################# ##
827
828    die "cmail: Can't proceed without your opponent's email address.\n"
829	if ("" eq "$OPP_ADDRESS") ;
830
831    ## ################################################################# ##
832    ## Create an empty game file
833    ## ################################################################# ##
834
835    open (GAMEFILE, "> $PGN_GAME.game.in") ;
836    for ($j = 1; $j <= $NUM_GAMES; $j ++) {
837	$PW_GCOS      =  &get_pw_gcos () ;
838
839	$PGN_MYCOL    =  $MY_FNAME ;
840	$PGN_MYCOL    =  $PW_GCOS unless $PGN_MYCOL ;
841	$PGN_MYCOL    =  $MY_NNAME unless $PGN_MYCOL ;
842	$PGN_MYCOLNA  =  $MY_ADDRESS ;
843	$PGN_MYCOLNA  =  "?" unless ($PGN_MYCOLNA) ;
844
845	$PGN_OPPCOL   =  $OPP_FNAME ;
846	$PGN_OPPCOL   =  "?" unless ($PGN_OPPCOL) ;
847	$PGN_OPPCOLNA =  $OPP_ADDRESS ;
848	$PGN_OPPCOLNA =  "?" unless ($PGN_OPPCOLNA) ;
849
850	if ($j > $NUM_WGAMES) {
851	    $PGN_WHITE   = $PGN_OPPCOL ;
852	    $PGN_BLACK   = $PGN_MYCOL ;
853	    $PGN_WHITENA = $PGN_OPPCOLNA ;
854	    $PGN_BLACKNA = $PGN_MYCOLNA ;
855	} else {
856	    $PGN_WHITE   = $PGN_MYCOL ;
857	    $PGN_BLACK   = $PGN_OPPCOL ;
858	    $PGN_WHITENA = $PGN_MYCOLNA ;
859	    $PGN_BLACKNA = $PGN_OPPCOLNA ;
860	}
861
862    	## ######################################################### ##
863	## If we only have one colour of game then allow command-line
864	## colour specs to override
865	## ######################################################### ##
866
867	if (! ($NUM_WGAMES && $NUM_BGAMES)) {
868	    $PGN_WHITE   = $WHITE_FNAME if ($WHITE_FNAME) ;
869	    $PGN_BLACK   = $BLACK_FNAME if ($BLACK_FNAME) ;
870	    $PGN_WHITENA = $WHITENA     if ($WHITENA)     ;
871	    $PGN_BLACKNA = $BLACKNA     if ($BLACKNA)     ;
872	}
873
874	$PGN_DATE = &get_date () ;
875	$PGN_DATE = "?" unless ($PGN_DATE) ;
876
877	if ($NUM_GAMES > 1) {
878	    $SUFFIX = ".$j" ;
879	} else {
880	    $SUFFIX = "" ;
881	}
882	@game = ("[Event \"$PGN_EVENT\"]\n",
883		 "[Site \"$PGN_SITE\"]\n",
884		 "[Date \"$PGN_DATE\"]\n",
885		 "[Round \"$PGN_ROUND\"]\n",
886		 "[White \"$PGN_WHITE\"]\n",
887		 "[Black \"$PGN_BLACK\"]\n",
888		 "[Result \"*\"]\n",
889		 "[WhiteNA \"$PGN_WHITENA\"]\n",
890		 "[BlackNA \"$PGN_BLACKNA\"]\n",
891		 "[Mode \"$PGN_MODE\"]\n",
892		 "[CmailGameName \"$PGN_GAME$SUFFIX\"]\n\n*\n") ;
893	if ($j > $NUM_WGAMES) {
894	    open (GAMEOUTFILE, "> $PGN_GAME.game.out.$j") ;
895	    print GAMEOUTFILE @game ;
896	    close (GAMEOUTFILE) ;
897	} else {
898	    print GAMEFILE @game ;
899	}
900    }
901    close (GAMEFILE) ;
902}
903#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
904
905
906#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
907## Get the password file gcos (full name) entry
908sub get_pw_entry {
909    local ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) =
910	getpwuid ($<);
911    ($name, $gcos) ;
912}
913#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
914
915
916#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
917## Get password file gcos (full name) entry
918sub get_pw_gcos {
919    local ($PW_GCOS) ;
920    if (! $PW_GCOS) {
921	($dummy, $PW_GCOS) = &get_pw_entry () ;
922	$PW_GCOS =~ s/^\s*([^,()]+[^ ,()])[ ]*[,()].*$/$1/;
923	if ($PW_GCOS =~ /^([^,()]+)\s+([^\s,()]+)$/) { ## Multi-word name
924	    $PW_GCOS = $2 . ", " . $1 ;
925	} elsif ($PW_GCOS !~ /^([^\s,()]+)/) { ## No sensible gcos entry
926	    $PW_GCOS = "" ;
927	}			## Else leave it as one word
928	&debug ("PW full name is \"$PW_GCOS\"\n");
929    }
930    return $PW_GCOS ;
931}
932#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
933
934
935#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
936## Get password file user name entry
937sub get_pw_name {
938    local ($PW_NAME) ;
939    ($PW_NAME, $dummy) = &get_pw_entry () ;
940    &debug ("PW name is $PW_NAME\n");
941
942    return $PW_NAME ;
943}
944#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
945
946
947#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
948## Analyse the email message
949sub analyse_email_message {
950    local ($new_result, $delete_result, $unfinished, $finished)
951	= (0, 0, 0, 0) ;
952    local ($gamefile, @games) ;
953
954    ## ################################################################# ##
955    ## Slurp the mail message
956    ## ################################################################# ##
957
958    die "cmail: No games on standard input"
959	unless (@games = &get_games_from_file ("STDIN")) ;
960
961    ## ################################################################# ##
962    ## Is the message a real cmail message or just a chess game? $PGN_GAME
963    ## will have been set by calling get_games_from_file if it's real
964    ## ################################################################# ##
965
966    print "Processing game message..." ;
967
968    if ($PGN_GAME) {
969	## ############################################################# ##
970	## Restore the results file from the archive if
971	## necessary. This is helpful if the user pipes in an old
972	## message for take-back purposes or whatever.
973	## ############################################################# ##
974
975	if (! -f "$PGN_GAME.res") {
976	    ## Find what date would have been used to create the archive
977	    foreach (@games) {
978		if (/\[Date\s"(.*)"\]/) {
979		    $date = $1 ;
980		    last ;	## Assume all dates are the same
981		}
982	    }
983	    ## Restore results file from archive directory if it exists
984	    if ($date && (-f "$ARCDIR/$PGN_GAME.$date.archive")) {
985		if (system ("cp",
986			    "$ARCDIR/$PGN_GAME.$date.archive",
987			    "$PGN_GAME.res")) {
988		    print stderr (  "\nWarning: couldn't restore results file"
989				  . " from archive\n") ;
990		} else {
991		    print "restored results file from archive..." ;
992		}
993	    }
994	}
995
996	## ############################################################# ##
997	## Find existing results, if any.
998	## ############################################################# ##
999
1000	local (@results) = &get_games_from_file ("$PGN_GAME.res") ;
1001
1002	## ############################################################# ##
1003	## Parse each game
1004	## ############################################################# ##
1005
1006	foreach $game (@games) {
1007	    next unless ($game) ;
1008
1009	    ($game_name, $game_num) = &get_game_name_and_number ($game) ;
1010
1011	    $result = 0 ;
1012	    @game = split("\n", $game) ;
1013	    foreach (@game) {
1014		if (/^\[(Black|White)\s*"[?]"\]$/) {
1015		    $colour = $1;
1016		    $PW_GCOS = &get_pw_gcos () unless ($PW_GCOS) ;
1017		    $PW_GCOS = "$MY_NNAME" unless ($PW_GCOS) ;
1018		    s/".*"/"$PW_GCOS"/ ;
1019		    &debug ("Changed $colour tag to be $_") ;
1020		} elsif (/^\[((Black|White)NA)\s*"(.*)"\]$/) {
1021		    $NA = $3 ;
1022		    if ($NA eq "?") {
1023			if ($RETURN_ADDRESS) {
1024			    $NA = $RETURN_ADDRESS ;
1025			} else {
1026			    $NA = "??" ;
1027			}
1028			$_ = "[$1 \"$NA\"]" ;
1029			&debug ("Changed $1 tag.\n") ;
1030		    }
1031		    if ($2 eq "White") {
1032			$PGN_WHITENA = $NA ;
1033			&debug ("WhiteNA tag is \"$PGN_WHITENA\"\n") ;
1034		    } else {
1035			$PGN_BLACKNA = $NA ;
1036			&debug ("BlackNA tag is \"$PGN_BLACKNA\"\n") ;
1037		    }
1038		} elsif (/\[Result\s*"(.*)"\]$/) {
1039		    if ($1 ne "*") {
1040			$result = 1 ;
1041			$finished ++ ;
1042		    } else {
1043			$unfinished ++ ;
1044		    }
1045		} elsif (/^(.*[^\d]+)?\d+[.]\s*([^\s*]*\s+)?[^\s.*]+(\s*\d+[.]\s*)?[\s*]*$/) {
1046		    if ($2) {
1047			$to_play = "white" ;
1048		    } else {
1049			$to_play = "black" ;
1050		    }
1051		    &debug ("$to_play to play\n") ;
1052		}
1053	    }
1054
1055	    ## ######################################################### ##
1056	    ## Reconstruct possibly edited game
1057	    ## ######################################################### ##
1058
1059	    $game = join ("\n", @game) . "\n\n" ;
1060
1061	    ## ######################################################### ##
1062	    ## Build up results array
1063	    ## ######################################################### ##
1064
1065	    if ($result) {
1066		$results[$game_num] = $games[$game_num] ;
1067		$new_result = 1 ;
1068	    } elsif ($results[$game_num]) {
1069		## Deleting a result does actually make sense if the user
1070		## pipes in an old message for take-back purposes or whatever
1071		$results[$game_num] = "" ;
1072		$delete_result = 1 ;
1073	    }
1074
1075	    ## ######################################################### ##
1076	    ## Remove old .out files
1077	    ## ######################################################### ##
1078
1079	    unlink <$PGN_GAME.game.out.*> ;
1080
1081	    ## ######################################################### ##
1082	    ## Write ongoing games to game file and append new results
1083	    ## ######################################################### ##
1084
1085	    die   "cmail: Can't open file for writing:"
1086		. " \"$CMAILDIR/$PGN_GAME.game.in\"\n"
1087		unless open (gamefile, ">$PGN_GAME.game.in") ;
1088	    &debug (@games) ;
1089	    print gamefile @games ;
1090	    close (gamefile) ;
1091	}
1092
1093	## ############################################################# ##
1094	## Print how many finished/unfinished games were found
1095	## ############################################################# ##
1096
1097	printf ("%d unfinished %s and %d finished %s...",
1098		$unfinished, ($unfinished == 1) ? "game" : "games",
1099		$finished, ($finished == 1) ? "game" : "games") ;
1100
1101	## ############################################################# ##
1102	## Write results back to results file if there were any results
1103	## in the input
1104	## ############################################################# ##
1105
1106	if ($new_result || $delete_result) {
1107	    die (  "cmail: Can't open results file for writing:"
1108		 . "\"$CMAILDIR/$PGN_GAME.res\"\n")
1109		unless open (resfile, ">$PGN_GAME.res") ;
1110	    print resfile @results ;
1111	    close (resfile) ;
1112	}
1113
1114	## ############################################################# ##
1115	## Archive results if there are no unfinished games
1116	## ############################################################# ##
1117
1118	@ARCHIVE = @results unless ($unfinished) ;
1119
1120	## ############################################################# ##
1121	## Figure out return address if not known
1122	## ############################################################# ##
1123
1124	if (! $RETURN_ADDRESS) {
1125	    if ($to_play eq "black") {
1126		$RETURN_ADDRESS = $PGN_WHITENA unless ("$PGN_WHITENA" eq "?") ;
1127	    } else {
1128		$RETURN_ADDRESS = $PGN_BLACKNA unless ("$PGN_BLACKNA" eq "?") ;
1129	    }
1130	}
1131
1132	## ############################################################# ##
1133	## Decide to include position diagrams in output if not already
1134	## decided and a position diagram was found in the input
1135	## ############################################################# ##
1136
1137	if ("$OUTPUT_POS" eq "") {
1138	    if (grep (/$posdiag/, @games)) {
1139		$OUTPUT_POS = "y" ; # Output position only if it was input
1140	    } else {
1141		$OUTPUT_POS = "n" ;
1142	    }
1143	}
1144	$ENV{'CMAIL_OUTPUT_POS'} = $OUTPUT_POS ;
1145
1146	## ############################################################# ##
1147	## Check that we have enough info about the players to continue
1148	## ############################################################# ##
1149
1150	&find_game () ;
1151    } else {
1152	## ############################################################# ##
1153	## Set up xboard for viewing non-cmail PGN file
1154	## ############################################################# ##
1155
1156	local ($file) = "unknown.cmail" ;
1157	print "done.\nDumping non-cmail file into $CMAILDIR/$file..." ;
1158
1159	die "cmail: Can't open file for writing: \"$CMAILDIR/$file\"\n"
1160	    unless open (gamefile, ">$file") ;
1161	print gamefile @games ;
1162	close (gamefile) ;
1163    }
1164
1165    print "done.\n" ;
1166}
1167#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1168
1169
1170#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1171## Sort two filenames by the numeric suffix
1172sub sort_by_numeric_suffix {
1173    $a =~ /[.](\d+)$/ ; local ($na) = $1 ;
1174    $b =~ /[.](\d+)$/ ; local ($nb) = $1 ;
1175
1176    return ($na <=> $nb) ;
1177}
1178#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1179
1180
1181#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1182sub get_game_name_and_number {
1183    local ($game) = join ("\n", @_) ;
1184
1185    local ($game_name, $game_num) ;
1186
1187    die "CMailGameName tag missing\n"
1188	unless ($game =~ /\[C[Mm]ailGameName\s+"(.*)"\]/) ;
1189
1190    ## ################################################################# ##
1191    ## Set game name and number
1192    ## ################################################################# ##
1193
1194    $game_name = $1 ;
1195    if ($game_name =~ s/^(.*)[.](\d+)$/$1/) {
1196	$game_num = $2 ;
1197    } else {
1198	$game_num = 1 ;
1199    }
1200
1201    ## ################################################################# ##
1202    ## Set $PGN_GAME as a side-effect or check validity
1203    ## ################################################################# ##
1204
1205    if ($PGN_GAME) {
1206	die (  "cmail: Mismatched game names in input message:\n"
1207	     . "\"$PGN_GAME\", \"$game_name\"\n")
1208	    if ("$PGN_GAME" ne "$game_name") ;
1209    } else {
1210	$PGN_GAME = $game_name ;
1211	&debug ("PGN_GAME set to \"$PGN_GAME\"\n") ;
1212    }
1213
1214    return ($game_name, $game_num) ;
1215}
1216#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1217
1218
1219#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1220## Read in a file of games and split into separate games
1221sub get_games_from_file {
1222    local ($file) = shift ;
1223
1224    local (@file, $first_line) ; ## Slurp stdin
1225    if ($file eq "STDIN") {
1226	if ($first_line = <STDIN>) { ## Necessary to handle no input case
1227	    @file = <STDIN> ; ## Slurp stdin
1228	    @file = ($first_line, @file) ;
1229
1230	    foreach (@file) {
1231		## Strip off leading quotation characters
1232		s/^[^\s]*>// ;
1233		s/^[ \t]+// ;
1234
1235		## Find return address and set it as a side-effect
1236		if (   /^From:?.*<([^>]+)>.*\n$/
1237		    || /^From:? *([^ ]*).*\n$/) {
1238		    $RETURN_ADDRESS = $1 ; ## Default for opp's email
1239		    &debug ("Found opponent's email address",
1240			    " \"$RETURN_ADDRESS\"\n") ;
1241		} elsif (/\[C[Mm]ailGameName\s+"(.*)"\]/) {
1242		    $PGN_GAME =  $1 ;
1243		    $PGN_GAME =~ s/[.]\d+$// ;
1244		}
1245	    }
1246
1247	    return (@file) unless ($PGN_GAME) ;
1248	    if (grep (/\{--------------|\[Event/, @file)) {
1249		shift (@file) while ($file[0] !~ /\{--------------|\[Event/) ;
1250	    }
1251	} else {
1252	    return () ;
1253	}
1254    } else {
1255	return () unless (open (file, "<$file")) ;
1256
1257	@file = <file> ; ## Slurp file
1258	close (file) ;
1259    }
1260
1261    local (@games, $game_name, $game_num, $game, $tag) ;
1262
1263    ## ################################################################# ##
1264    ## Remove headers and leading blanks
1265    ## ################################################################# ##
1266
1267    local (@tgames) = split (/($posdiag\[Event|\[Event)/, join ('', @file)) ;
1268    shift (@tgames) while (!$tgames[0]) ;
1269
1270    ## ################################################################# ##
1271    ## Set up @games array with proper game numbers
1272    ## ################################################################# ##
1273
1274    while (@tgames) {
1275	$game = shift (@tgames) . shift (@tgames) ;
1276
1277	($game_name, $game_num) = &get_game_name_and_number ($game) ;
1278	$games[$game_num] = $game ;
1279    }
1280
1281    return (@games) ;
1282}
1283#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1284
1285
1286#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1287## Analyse output files and send the move
1288sub send_move {
1289    &debug ("Called <send_move>\n") ;
1290
1291    ## ################################################################# ##
1292    ## Cat the pos (if it exists), game and result (if it exists) files
1293    ## into the .out file.
1294    ## ################################################################# ##
1295
1296    local ($unfinished, $finished) = (0, 0) ;
1297    local (@results, $move, $move_msg, $to_play, $number) ;
1298
1299    ## ################################################################# ##
1300    ## Find any .game.out.* files
1301    ## ################################################################# ##
1302
1303    local (@outfiles) = (<$PGN_GAME.game.out.*>) ;
1304    @outfiles = grep (/[.]\d+$/, @outfiles) ; ## Ignore autosave files
1305    @outfiles = sort sort_by_numeric_suffix @outfiles ; ## Sort
1306
1307    ## ################################################################# ##
1308    ## Find .res file if it exists
1309    ## ################################################################# ##
1310
1311    local ($resfile) = "$PGN_GAME.res" ;
1312    if (-f $resfile) {
1313	@results = &get_games_from_file($resfile) ;
1314	&debug ("Read in results\n") ;
1315    } else {
1316	@results = () ;
1317	&debug ("No results to read\n") ;
1318    }
1319
1320    ## ################################################################# ##
1321    ## Find .out file if it exists
1322    ## ################################################################# ##
1323
1324    local ($outfile) = "$PGN_GAME.out" ;
1325    if (! ($REMAIL || $LOAD_XBOARD)) {
1326	@games = &play_on_tty (@results) ;
1327    } elsif (@outfiles) {
1328	foreach (@outfiles) {
1329	    die "Can't open game file \"$_\" for reading"
1330		unless (open (game, "<$_")) ;
1331	    die "Empty game file \"$_\""
1332		unless ($game = join ('', <game>)) ;
1333	    close (game) ;
1334	    &debug ("Read in game file \"$_\"\n") ;
1335	    ## Remove position diagram if it wasn't in the input msg
1336	    $game =~ s/($posdiag)// if ("$OUTPUT_POS" ne "y") ;
1337	    ($game_name, $game_num) = &get_game_name_and_number ($game) ;
1338	    $games[$game_num] = $game ;
1339	}
1340	&debug ("Read in games from output files\n") ;
1341	$games[0] = "" ;
1342    } else {
1343	&debug ("No games to read from STDIN\n") ;
1344	if (-f $outfile) {
1345	    @games = &get_games_from_file($outfile) ;
1346	} else {
1347	    die "Can't find any game files\n" unless (@results) ;
1348	}
1349    }
1350
1351    ## ################################################################# ##
1352    ## Process games
1353    ## ################################################################# ##
1354
1355    if (@games) {
1356	## ############################################################# ##
1357	## Find opponent's email address in games
1358	## ############################################################# ##
1359
1360	$OPP_ADDRESS = &get_opp_address_from_games (@games)
1361	    unless ($OPP_ADDRESS) ;
1362
1363	## ############################################################# ##
1364	## Collect the .game.out.* files into the .out file, remembering
1365	## the move number of the last line and whether result or not
1366	## ############################################################# ##
1367
1368	$unfinished = 0 ;
1369	$move_num = 0 ;
1370	$move = blank ;
1371
1372	## Write games to output file
1373	die "Can't open output file \"$PGN_GAME.out\" for writing\n"
1374	    unless open (outfile, ">$PGN_GAME.out") ;
1375	print outfile @games ;
1376	close (outfile) ;
1377
1378	$game_num = -1 ;
1379	$num_games = 0 ;
1380	foreach $game (@games) {
1381	    $game_num ++ ;
1382	    next unless ($game) ;
1383
1384	    $num_games ++ ;
1385	    ## Determine last move and whether result or not
1386	    $result = 0 ;
1387	    foreach (split(/\n/, $game)) {
1388		if (/^(.*[^\d]+|)(\d+)[.]+\s*[^\s.]*\s+(\S+)\s*$/) {
1389		    $move_num = $2 ;
1390		    $move    = $3 ;
1391		} elsif (/^\[Result\s*"(.*)"\]$/) {
1392		    if ($1 ne "*") {
1393			$result = 1 ;
1394			$finished ++ ;
1395		    } else {
1396			$unfinished ++ ;
1397		    }
1398		}
1399	    }
1400
1401	    $results[$game_num] = $game if ($result) ;
1402	}
1403
1404	## Write result files back to $PGN_GAME.res
1405	if (@results) {
1406	    die "Can't open results file $PGN_GAME.res for writing\n"
1407		unless open (resfile, ">$PGN_GAME.res") ;
1408	    print resfile @results ;
1409	    close (results) ;
1410	}
1411
1412	unlink <$PGN_GAME.game.out.*> ;
1413
1414	## ############################################################# ##
1415	## Just say how many games are in the message
1416	## ############################################################# ##
1417
1418	if ($num_games > 1) {
1419	    $move_msg = "$num_games games" ;
1420	} else {
1421	    $move_msg = "1 game" ;
1422	}
1423
1424	## ############################################################# ##
1425	## Print how many finished/unfinished games were found
1426	## ############################################################# ##
1427
1428	printf ("Sending %d unfinished %s and %d finished %s.\n",
1429		$unfinished, ($unfinished == 1) ? "game" : "games",
1430		$finished, ($finished == 1) ? "game" : "games") ;
1431
1432	## ############################################################# ##
1433	## Send the mail message to opponent's address unless bypassed
1434	## ############################################################# ##
1435
1436	if ($SEND_MAIL) {
1437	    local ($subject) = "cmail $move_msg <$PGN_GAME>" ;
1438	    if ($MAILPROG =~ /sendmail/) {
1439		$opened = open (mail, "|$MAILPROG $OPP_ADDRESS") ;
1440 		print mail "To: $OPP_ADDRESS\n";
1441 		print mail "Subject: $subject\n";
1442 		print mail "Mime-Version: 1.0\n";
1443 		print mail "Content-Type: application/x-chess;name=$PGN_GAME.pgn\n\n";
1444	    } else {
1445		$opened = open (mail, "|$MAILPROG -s \"$subject\" $OPP_ADDRESS") ;
1446	    }
1447  	    if ($opened) {
1448		print mail @games ;
1449		close (mail) ;
1450		print (  "Mailed cmail message to \"$OPP_ADDRESS\":\n"
1451		       . "$move_msg <$PGN_GAME>\n") ;
1452		@ARCHIVE = @results unless ($unfinished) ;
1453	    } else {
1454		die "Failed to mail cmail message.\n" ;
1455	    }
1456	} else {
1457	    print (  "Email not sent (as requested).\n"
1458		   . "Would have mailed cmail message to \"$OPP_ADDRESS\":\n"
1459		   . "$NUM_GAMES games <$PGN_GAME>\n") ;
1460	}
1461    } else {
1462	if (@results) {
1463	    print "Email not sent (the game is over).\n" ;
1464	} else {
1465	    die "No games found\n" ;
1466	}
1467    }
1468}
1469#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1470
1471
1472#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1473## Get date from array of games
1474sub get_date_from_games {
1475    local (@games) = @_ ;
1476
1477    local ($date) = "nodate" ;
1478
1479    foreach (@games) {
1480	if (/\[Date\s"(.*)"\]/) {
1481	    $date = $1 ;
1482	    last ;		## Assume all dates are the same
1483	}
1484    }
1485
1486    return ($date) ;
1487}
1488#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1489
1490
1491#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1492## Determine which colour is to play and the move number
1493sub get_to_play {
1494    &debug ("Called <get_to_play>\n") ;
1495    local ($game) = shift ;
1496
1497    local ($number, $to_play) = (1, "White") ;
1498
1499    $game =~ s/{[^}]*}//g ;
1500    $game =~ s/[\s\n]*[*][\s\n]*$// ;
1501
1502    if ($game =~ /(\d+)[.][\n ]*([.]*)[\n ]*([^\n.]*)[\n\s]*[10-]*[\n\s]*$/) {
1503	$number = $1 ;
1504
1505	if ($game =~ /\[Result "0-1"\]/) {
1506	    $to_play = "Black" ;
1507	} elsif ($game =~ /\[Result "1-0"\]/) {
1508	    $to_play = "White" ;
1509	} elsif (($2 ne "") || (($3 =~ / /) || ($3 eq ""))) {
1510	    $to_play = "White" ;
1511	    $number ++ ;
1512	} else {
1513	    $to_play = "Black" ;
1514	}
1515    }
1516
1517    &debug ("$to_play to play on move $number\n") ;
1518
1519    return ($number, $to_play) ;
1520}
1521#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1522
1523
1524#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1525## Get opp address from array of games
1526sub get_opp_address_from_games {
1527    &debug ("Called <get_opp_address_from_games>\n") ;
1528    local (@games) = @_ ;
1529
1530    local ($opp_address) = "" ;
1531    local ($number, $to_play, $tag) ;
1532
1533    foreach (@games) {
1534	next unless $_ ;
1535
1536	($number, $to_play) = &get_to_play ($_) ;
1537	$tag = (  ($to_play eq "White")
1538		? "WhiteNA"
1539		: "BlackNA") ;
1540
1541	if (/\[$tag\s"(.*)"\]/) {
1542	    $opp_address = $1 ;
1543	    die "cmail: Empty \"$tag\" tag\n" unless ($opp_address) ;
1544	    &debug ("Found opponent's address \"$opp_address\" from games.\n") ;
1545	    last ;		## Assume all opp addresses are the same
1546	} else {
1547	    die "cmail: Can't find \"$tag\" tag\n" ;
1548	}
1549    }
1550
1551    die "cmail: Can't find opponent's email address\n" unless ($opp_address) ;
1552
1553    return ($opp_address) ;
1554}
1555#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1556
1557
1558#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1559## Archive @ARCHIVE in the $ARCDIR directory
1560sub archive {
1561    return () unless (@ARCHIVE) ;
1562
1563    local ($date) = &get_date_from_games (@ARCHIVE) ;
1564
1565    local ($file) = "$ARCDIR/$PGN_GAME.$date.archive" ;
1566    if (open (archive, ">$file")) {
1567	print archive @ARCHIVE ;
1568	close (archive) ;
1569	print "Archived game in $file\n" ;
1570	local (@remove) = <$PGN_GAME*> ;
1571	@remove = grep ($_ ne "$PGN_GAME.$date.archive",
1572			@remove) ; ## Don't delete archive
1573	unlink (@remove) ;
1574    } else {
1575	print "Couldn't open \"$file\" to archive game\n" ;
1576    }
1577}
1578#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1579
1580
1581#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1582## Main body
1583sub main {
1584    local (@games) = () ;
1585
1586    &initialise () ;		## Initialise variables etc.
1587
1588    if (-t || $REMAIL) { ## No input directed (invoked from a shell rather than a mailer)
1589	&debug ("Interactive!\n") ;
1590	&find_game () ;		## Get the necessary info about the game
1591    } else {
1592	&debug ("Piping!\n") ;
1593	&analyse_email_message () ; ## Analyse the mail message
1594    }
1595
1596    if (! &play_game ()) {	## Load the game
1597	&send_move () ;		## Analyse output and send moves
1598    }
1599
1600    &archive () ;		## Archive games if all finished
1601
1602    close (tty) ;		## Tidy up
1603    close (logfile) if ($DEBUG) ; ## Tidy up
1604}
1605#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1606&main () ;
1607#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1608__END__
1609cmail (From XBoard version @PACKAGE_VERSION@), Copyright (C) 1993 Free Software Foundation, Inc.
1610cmail comes with ABSOLUTELY NO WARRANTY; for details type `cmail -w'.
1611cmail is free software, and you are welcome to redistribute it
1612under certain conditions; type `cmail -c' for details.
1613
1614{END OF GPL COPYRIGHT}
1615		    GNU GENERAL PUBLIC LICENSE
1616   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
1617
1618  0. This License applies to any program or other work which contains
1619a notice placed by the copyright holder saying it may be distributed
1620under the terms of this General Public License.  The "Program", below,
1621refers to any such program or work, and a "work based on the Program"
1622means either the Program or any derivative work under copyright law:
1623that is to say, a work containing the Program or a portion of it,
1624either verbatim or with modifications and/or translated into another
1625language.  (Hereinafter, translation is included without limitation in
1626the term "modification".)  Each licensee is addressed as "you".
1627
1628Activities other than copying, distribution and modification are not
1629covered by this License; they are outside its scope.  The act of
1630running the Program is not restricted, and the output from the Program
1631is covered only if its contents constitute a work based on the
1632Program (independent of having been made by running the Program).
1633Whether that is true depends on what the Program does.
1634
1635  1. You may copy and distribute verbatim copies of the Program's
1636source code as you receive it, in any medium, provided that you
1637conspicuously and appropriately publish on each copy an appropriate
1638copyright notice and disclaimer of warranty; keep intact all the
1639notices that refer to this License and to the absence of any warranty;
1640and give any other recipients of the Program a copy of this License
1641along with the Program.
1642
1643You may charge a fee for the physical act of transferring a copy, and
1644you may at your option offer warranty protection in exchange for a fee.
1645
1646  2. You may modify your copy or copies of the Program or any portion
1647of it, thus forming a work based on the Program, and copy and
1648distribute such modifications or work under the terms of Section 1
1649above, provided that you also meet all of these conditions:
1650
1651    a) You must cause the modified files to carry prominent notices
1652    stating that you changed the files and the date of any change.
1653
1654    b) You must cause any work that you distribute or publish, that in
1655    whole or in part contains or is derived from the Program or any
1656    part thereof, to be licensed as a whole at no charge to all third
1657    parties under the terms of this License.
1658
1659    c) If the modified program normally reads commands interactively
1660    when run, you must cause it, when started running for such
1661    interactive use in the most ordinary way, to print or display an
1662    announcement including an appropriate copyright notice and a
1663    notice that there is no warranty (or else, saying that you provide
1664    a warranty) and that users may redistribute the program under
1665    these conditions, and telling the user how to view a copy of this
1666    License.  (Exception: if the Program itself is interactive but
1667    does not normally print such an announcement, your work based on
1668    the Program is not required to print an announcement.)
1669
1670These requirements apply to the modified work as a whole.  If
1671identifiable sections of that work are not derived from the Program,
1672and can be reasonably considered independent and separate works in
1673themselves, then this License, and its terms, do not apply to those
1674sections when you distribute them as separate works.  But when you
1675distribute the same sections as part of a whole which is a work based
1676on the Program, the distribution of the whole must be on the terms of
1677this License, whose permissions for other licensees extend to the
1678entire whole, and thus to each and every part regardless of who wrote it.
1679
1680Thus, it is not the intent of this section to claim rights or contest
1681your rights to work written entirely by you; rather, the intent is to
1682exercise the right to control the distribution of derivative or
1683collective works based on the Program.
1684
1685In addition, mere aggregation of another work not based on the Program
1686with the Program (or with a work based on the Program) on a volume of
1687a storage or distribution medium does not bring the other work under
1688the scope of this License.
1689
1690  3. You may copy and distribute the Program (or a work based on it,
1691under Section 2) in object code or executable form under the terms of
1692Sections 1 and 2 above provided that you also do one of the following:
1693
1694    a) Accompany it with the complete corresponding machine-readable
1695    source code, which must be distributed under the terms of Sections
1696    1 and 2 above on a medium customarily used for software interchange; or,
1697
1698    b) Accompany it with a written offer, valid for at least three
1699    years, to give any third party, for a charge no more than your
1700    cost of physically performing source distribution, a complete
1701    machine-readable copy of the corresponding source code, to be
1702    distributed under the terms of Sections 1 and 2 above on a medium
1703    customarily used for software interchange; or,
1704
1705    c) Accompany it with the information you received as to the offer
1706    to distribute corresponding source code.  (This alternative is
1707    allowed only for noncommercial distribution and only if you
1708    received the program in object code or executable form with such
1709    an offer, in accord with Subsection b above.)
1710
1711The source code for a work means the preferred form of the work for
1712making modifications to it.  For an executable work, complete source
1713code means all the source code for all modules it contains, plus any
1714associated interface definition files, plus the scripts used to
1715control compilation and installation of the executable.  However, as a
1716special exception, the source code distributed need not include
1717anything that is normally distributed (in either source or binary
1718form) with the major components (compiler, kernel, and so on) of the
1719operating system on which the executable runs, unless that component
1720itself accompanies the executable.
1721
1722If distribution of executable or object code is made by offering
1723access to copy from a designated place, then offering equivalent
1724access to copy the source code from the same place counts as
1725distribution of the source code, even though third parties are not
1726compelled to copy the source along with the object code.
1727
1728  4. You may not copy, modify, sublicense, or distribute the Program
1729except as expressly provided under this License.  Any attempt
1730otherwise to copy, modify, sublicense or distribute the Program is
1731void, and will automatically terminate your rights under this License.
1732However, parties who have received copies, or rights, from you under
1733this License will not have their licenses terminated so long as such
1734parties remain in full compliance.
1735
1736  5. You are not required to accept this License, since you have not
1737signed it.  However, nothing else grants you permission to modify or
1738distribute the Program or its derivative works.  These actions are
1739prohibited by law if you do not accept this License.  Therefore, by
1740modifying or distributing the Program (or any work based on the
1741Program), you indicate your acceptance of this License to do so, and
1742all its terms and conditions for copying, distributing or modifying
1743the Program or works based on it.
1744
1745  6. Each time you redistribute the Program (or any work based on the
1746Program), the recipient automatically receives a license from the
1747original licensor to copy, distribute or modify the Program subject to
1748these terms and conditions.  You may not impose any further
1749restrictions on the recipients' exercise of the rights granted herein.
1750You are not responsible for enforcing compliance by third parties to
1751this License.
1752
1753  7. If, as a consequence of a court judgment or allegation of patent
1754infringement or for any other reason (not limited to patent issues),
1755conditions are imposed on you (whether by court order, agreement or
1756otherwise) that contradict the conditions of this License, they do not
1757excuse you from the conditions of this License.  If you cannot
1758distribute so as to satisfy simultaneously your obligations under this
1759License and any other pertinent obligations, then as a consequence you
1760may not distribute the Program at all.  For example, if a patent
1761license would not permit royalty-free redistribution of the Program by
1762all those who receive copies directly or indirectly through you, then
1763the only way you could satisfy both it and this License would be to
1764refrain entirely from distribution of the Program.
1765
1766If any portion of this section is held invalid or unenforceable under
1767any particular circumstance, the balance of the section is intended to
1768apply and the section as a whole is intended to apply in other
1769circumstances.
1770
1771It is not the purpose of this section to induce you to infringe any
1772patents or other property right claims or to contest validity of any
1773such claims; this section has the sole purpose of protecting the
1774integrity of the free software distribution system, which is
1775implemented by public license practices.  Many people have made
1776generous contributions to the wide range of software distributed
1777through that system in reliance on consistent application of that
1778system; it is up to the author/donor to decide if he or she is willing
1779to distribute software through any other system and a licensee cannot
1780impose that choice.
1781
1782This section is intended to make thoroughly clear what is believed to
1783be a consequence of the rest of this License.
1784
1785  8. If the distribution and/or use of the Program is restricted in
1786certain countries either by patents or by copyrighted interfaces, the
1787original copyright holder who places the Program under this License
1788may add an explicit geographical distribution limitation excluding
1789those countries, so that distribution is permitted only in or among
1790countries not thus excluded.  In such case, this License incorporates
1791the limitation as if written in the body of this License.
1792
1793  9. The Free Software Foundation may publish revised and/or new versions
1794of the General Public License from time to time.  Such new versions will
1795be similar in spirit to the present version, but may differ in detail to
1796address new problems or concerns.
1797
1798Each version is given a distinguishing version number.  If the Program
1799specifies a version number of this License which applies to it and "any
1800later version", you have the option of following the terms and conditions
1801either of that version or of any later version published by the Free
1802Software Foundation.  If the Program does not specify a version number of
1803this License, you may choose any version ever published by the Free Software
1804Foundation.
1805
1806  10. If you wish to incorporate parts of the Program into other free
1807programs whose distribution conditions are different, write to the author
1808to ask for permission.  For software which is copyrighted by the Free
1809Software Foundation, write to the Free Software Foundation; we sometimes
1810make exceptions for this.  Our decision will be guided by the two goals
1811of preserving the free status of all derivatives of our free software and
1812of promoting the sharing and reuse of software generally.
1813{END OF GPL CONDITIONS}
1814		    GNU GENERAL PUBLIC LICENSE
1815			    NO WARRANTY
1816
1817  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
1818FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
1819OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
1820PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
1821OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1822MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
1823TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
1824PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
1825REPAIR OR CORRECTION.
1826
1827  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
1828WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
1829REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
1830INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
1831OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
1832TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
1833YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
1834PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
1835POSSIBILITY OF SUCH DAMAGES.
1836
1837