Fix multi-leg promotions
[xboard.git] / cmail.in
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, 2016 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
31 sub 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
45 sub 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
128 sub 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
317 sub 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
354 sub 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
378 sub 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
396 sub 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
424 sub 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
444 sub 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
469 sub 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
554 sub 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
745 sub 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
790 sub 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
809 sub 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
908 sub 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
918 sub 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
937 sub 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
949 sub 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
1172 sub 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 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
1182 sub 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
1221 sub 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
1288 sub 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
1474 sub 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
1493 sub 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
1526 sub 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
1560 sub 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
1583 sub 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__
1609 cmail (From XBoard version @PACKAGE_VERSION@), Copyright (C) 1993 Free Software Foundation, Inc.
1610 cmail comes with ABSOLUTELY NO WARRANTY; for details type `cmail -w'.
1611 cmail is free software, and you are welcome to redistribute it
1612 under 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
1619 a notice placed by the copyright holder saying it may be distributed
1620 under the terms of this General Public License.  The "Program", below,
1621 refers to any such program or work, and a "work based on the Program"
1622 means either the Program or any derivative work under copyright law:
1623 that is to say, a work containing the Program or a portion of it,
1624 either verbatim or with modifications and/or translated into another
1625 language.  (Hereinafter, translation is included without limitation in
1626 the term "modification".)  Each licensee is addressed as "you".
1627
1628 Activities other than copying, distribution and modification are not
1629 covered by this License; they are outside its scope.  The act of
1630 running the Program is not restricted, and the output from the Program
1631 is covered only if its contents constitute a work based on the
1632 Program (independent of having been made by running the Program).
1633 Whether that is true depends on what the Program does.
1634
1635   1. You may copy and distribute verbatim copies of the Program's
1636 source code as you receive it, in any medium, provided that you
1637 conspicuously and appropriately publish on each copy an appropriate
1638 copyright notice and disclaimer of warranty; keep intact all the
1639 notices that refer to this License and to the absence of any warranty;
1640 and give any other recipients of the Program a copy of this License
1641 along with the Program.
1642
1643 You may charge a fee for the physical act of transferring a copy, and
1644 you 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
1647 of it, thus forming a work based on the Program, and copy and
1648 distribute such modifications or work under the terms of Section 1
1649 above, 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 \f
1670 These requirements apply to the modified work as a whole.  If
1671 identifiable sections of that work are not derived from the Program,
1672 and can be reasonably considered independent and separate works in
1673 themselves, then this License, and its terms, do not apply to those
1674 sections when you distribute them as separate works.  But when you
1675 distribute the same sections as part of a whole which is a work based
1676 on the Program, the distribution of the whole must be on the terms of
1677 this License, whose permissions for other licensees extend to the
1678 entire whole, and thus to each and every part regardless of who wrote it.
1679
1680 Thus, it is not the intent of this section to claim rights or contest
1681 your rights to work written entirely by you; rather, the intent is to
1682 exercise the right to control the distribution of derivative or
1683 collective works based on the Program.
1684
1685 In addition, mere aggregation of another work not based on the Program
1686 with the Program (or with a work based on the Program) on a volume of
1687 a storage or distribution medium does not bring the other work under
1688 the scope of this License.
1689
1690   3. You may copy and distribute the Program (or a work based on it,
1691 under Section 2) in object code or executable form under the terms of
1692 Sections 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
1711 The source code for a work means the preferred form of the work for
1712 making modifications to it.  For an executable work, complete source
1713 code means all the source code for all modules it contains, plus any
1714 associated interface definition files, plus the scripts used to
1715 control compilation and installation of the executable.  However, as a
1716 special exception, the source code distributed need not include
1717 anything that is normally distributed (in either source or binary
1718 form) with the major components (compiler, kernel, and so on) of the
1719 operating system on which the executable runs, unless that component
1720 itself accompanies the executable.
1721
1722 If distribution of executable or object code is made by offering
1723 access to copy from a designated place, then offering equivalent
1724 access to copy the source code from the same place counts as
1725 distribution of the source code, even though third parties are not
1726 compelled to copy the source along with the object code.
1727 \f
1728   4. You may not copy, modify, sublicense, or distribute the Program
1729 except as expressly provided under this License.  Any attempt
1730 otherwise to copy, modify, sublicense or distribute the Program is
1731 void, and will automatically terminate your rights under this License.
1732 However, parties who have received copies, or rights, from you under
1733 this License will not have their licenses terminated so long as such
1734 parties remain in full compliance.
1735
1736   5. You are not required to accept this License, since you have not
1737 signed it.  However, nothing else grants you permission to modify or
1738 distribute the Program or its derivative works.  These actions are
1739 prohibited by law if you do not accept this License.  Therefore, by
1740 modifying or distributing the Program (or any work based on the
1741 Program), you indicate your acceptance of this License to do so, and
1742 all its terms and conditions for copying, distributing or modifying
1743 the Program or works based on it.
1744
1745   6. Each time you redistribute the Program (or any work based on the
1746 Program), the recipient automatically receives a license from the
1747 original licensor to copy, distribute or modify the Program subject to
1748 these terms and conditions.  You may not impose any further
1749 restrictions on the recipients' exercise of the rights granted herein.
1750 You are not responsible for enforcing compliance by third parties to
1751 this License.
1752
1753   7. If, as a consequence of a court judgment or allegation of patent
1754 infringement or for any other reason (not limited to patent issues),
1755 conditions are imposed on you (whether by court order, agreement or
1756 otherwise) that contradict the conditions of this License, they do not
1757 excuse you from the conditions of this License.  If you cannot
1758 distribute so as to satisfy simultaneously your obligations under this
1759 License and any other pertinent obligations, then as a consequence you
1760 may not distribute the Program at all.  For example, if a patent
1761 license would not permit royalty-free redistribution of the Program by
1762 all those who receive copies directly or indirectly through you, then
1763 the only way you could satisfy both it and this License would be to
1764 refrain entirely from distribution of the Program.
1765
1766 If any portion of this section is held invalid or unenforceable under
1767 any particular circumstance, the balance of the section is intended to
1768 apply and the section as a whole is intended to apply in other
1769 circumstances.
1770
1771 It is not the purpose of this section to induce you to infringe any
1772 patents or other property right claims or to contest validity of any
1773 such claims; this section has the sole purpose of protecting the
1774 integrity of the free software distribution system, which is
1775 implemented by public license practices.  Many people have made
1776 generous contributions to the wide range of software distributed
1777 through that system in reliance on consistent application of that
1778 system; it is up to the author/donor to decide if he or she is willing
1779 to distribute software through any other system and a licensee cannot
1780 impose that choice.
1781
1782 This section is intended to make thoroughly clear what is believed to
1783 be a consequence of the rest of this License.
1784 \f
1785   8. If the distribution and/or use of the Program is restricted in
1786 certain countries either by patents or by copyrighted interfaces, the
1787 original copyright holder who places the Program under this License
1788 may add an explicit geographical distribution limitation excluding
1789 those countries, so that distribution is permitted only in or among
1790 countries not thus excluded.  In such case, this License incorporates
1791 the limitation as if written in the body of this License.
1792
1793   9. The Free Software Foundation may publish revised and/or new versions
1794 of the General Public License from time to time.  Such new versions will
1795 be similar in spirit to the present version, but may differ in detail to
1796 address new problems or concerns.
1797
1798 Each version is given a distinguishing version number.  If the Program
1799 specifies a version number of this License which applies to it and "any
1800 later version", you have the option of following the terms and conditions
1801 either of that version or of any later version published by the Free
1802 Software Foundation.  If the Program does not specify a version number of
1803 this License, you may choose any version ever published by the Free Software
1804 Foundation.
1805
1806   10. If you wish to incorporate parts of the Program into other free
1807 programs whose distribution conditions are different, write to the author
1808 to ask for permission.  For software which is copyrighted by the Free
1809 Software Foundation, write to the Free Software Foundation; we sometimes
1810 make exceptions for this.  Our decision will be guided by the two goals
1811 of preserving the free status of all derivatives of our free software and
1812 of 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
1818 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
1819 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
1820 PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
1821 OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1822 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
1823 TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
1824 PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
1825 REPAIR OR CORRECTION.
1826
1827   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
1828 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
1829 REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
1830 INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
1831 OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
1832 TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
1833 YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
1834 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
1835 POSSIBILITY OF SUCH DAMAGES.
1836