home *** CD-ROM | disk | FTP | other *** search
- /* readmail.c 8/7/91
- *
- * Copyright 1991 Perry R. Ross
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation without fee is hereby granted, subject to the restrictions
- * detailed in the README file, which is included here by reference.
- * Any other use requires written permission from the author. This software
- * is distributed "as is" without any warranty, including any implied
- * warranties of merchantability or fitness for a particular purpose.
- * The author shall not be liable for any damages resulting from the
- * use of this software. By using this software, the user agrees
- * to these terms.
- */
-
- #include "ldb.h"
-
- /*----------------------------------------------------------------------
- * readmail -- read the incoming mail and process it
- *
- * This function extracts each packet from the mail file and applies it
- * to the appropriate game structure. Most packets are processed by
- * calling the handler found in the func array, which is a 2-dimensional
- * array indexed by the current game state and the received opcode.
- * The handlers are responsible for transforming the game state as
- * necessary. The START and RSTART opcodes receive special processing,
- * since they apply to games that do not exist and thus have no state.
- * START packets result in the creation of a game, whose state is set
- * such that the correct handler will be called. The RSTART opcode
- * is processed in the same way as the -start command line argument;
- * the packet is then discarded.
- *
- * Note that the file argument can be actually be a pattern, causing
- * all matching files to be scanned. On UNIX systems, patterns are
- * interpreted in the same manner as the shell. On VMS, they
- * are interpreted in the same manner as DCL.
- *----------------------------------------------------------------------
- */
-
- readmail(file)
- char *file;
- {
- struct flist *fl, *t;
-
- fl = filelist(file); /* generate a list of all matching files */
- while (fl != NULL) { /* for each matching file found */
- readfile(fl->name); /* scan it */
- free(fl->name); /* free the string */
- t = fl; /* keep a pointer to the struct */
- fl = fl->next; /* advance fl pointer */
- free(t); /* free the previous struct */
- }
- }
-
-
- /*----------------------------------------------------------------------
- * readfile -- scan a file looking for incoming messages
- *
- * This function is called by readmail to scan a file that matches
- * the pattern.
- *----------------------------------------------------------------------
- */
-
- readfile(name)
- char *name;
- {
- FILE *fp;
- int d, c1, c2;
- int flags = 0, match = 0;
- struct people *p;
- struct game *g;
-
- if ( (fp = fopen(name,"r")) == NULL)
- return;
- if (rc.debug & DB_READFILE)
- message("DB-readfile: scanning %s\n",name);
- while (getpkt(fp) > 0) { /* as long as we found a valid packet */
- if (P.gameptr == NULL) {
- if (rc.debug & DB_READFILE)
- message("DB-readfile: found packet for <unknown>\n");
- if (P.opcode == START) {
- if ( ((p = findppl(P.addr,P_ADDR)) != NULL) &&
- (p->fence >= P.timestamp) )
- continue; /* ignore old start packets */
- P.gameptr = addgame(); /* init later in start() */
- P.gameptr->ppl = p;
- P.gameptr->gameid = P.gameid;
- P.gameptr->state = ST_OPSTART;
- }
- else if (P.opcode == RSTART) { /* remote start packet */
- if (rc.debug & DB_RSTART)
- message("DB-readfile: remstart to %s\n",P.addr);
- if ( (p = findppl(P.addr,P_ADDR)) != NULL)
- P.addr = p->addr; /* use real addr */
- for (g = ghead; g != NULL; g = g->next)
- if ( (P.timestamp == g->starttime) &&
- (strcmp(P.addr,g->opaddr) == 0) )
- break; /* already seen this packet */
- if (g != NULL)
- continue;
- if ( (p != NULL) && (p->fence >= P.timestamp) )
- continue; /* this game already played */
- if (rc.debug & DB_RSTART)
- message("DB-readfile: address is %s\n",P.addr);
- if (P.dir == NULL) /* if no direction was given */
- d = cr_mydir; /* use my default */
- else /* dir was given, grab it */
- d = (*P.dir == 'u') ? 1 : -1;
- if (P.colors == NULL) { /* if no colors were given */
- c1 = cr_mycolor; /* use my defaults */
- c2 = cr_opcolor;
- }
- else { /* colors were given */
- c1 = *P.colors; /* use them */
- c2 = P.colors[1];
- }
- if (P.jacoby != NULL)
- flags |= F_JACOBY;
- if (P.crawford != NULL)
- flags |= F_CRAWFORD;
- if (P.european != NULL)
- flags |= F_EUROPE;
- if (P.perm != NULL)
- flags |= F_PERM;
- if (P.match != NULL)
- match = atoi(P.match);
- notify = P.notify; /* store notify address */
- startgame(P.addr,d,c1,c2,flags,match,P.timestamp);
- continue; /* game started, discard this packet */
- }
- else {
- message("ERROR: no such gameid: %s (ignored)\n",
- P.gameid);
- continue;
- }
- }
- if (rc.debug & DB_READFILE)
- message("DB-readfile: found packet for %s\n",
- P.gameptr->gameid);
- if (P.gameptr->state >= OPSTATES) { /* hey, it's still my turn */
- message("ERROR: move out of turn: %s (ignored)\n",P.gameid);
- continue;
- }
- if (P.name != NULL) { /* snarf opponent's name */
- P.gameptr->opname = P.name;
- if (P.gameptr->ppl != NULL) {
- if (P.gameptr->ppl->name != NULL)
- free(P.gameptr->ppl->name);
- P.gameptr->ppl->name = save(P.name);
- }
- }
- if (P.notify != NULL)
- P.gameptr->notify = P.notify;
- (*func[P.gameptr->state][P.opcode])(P.gameptr); /* call handler */
- }
- fclose(fp);
- if ( ((*rc.delmail == 'y') || (*rc.delmail == 'Y'))
- #ifndef VMS
- && (*name != '/') /* absolute paths not deleted */
- #endif
- ) {
- if (rc.debug & DB_READFILE)
- message("DB-readfile: deleting mail file %s\n",name);
- unlink(name);
- }
- }
-
-
- /*---------------------------------------------------------------------------
- * getpkt -- read one packet from a file
- *
- * This function reads the next packet from the specified file.
- * Getpkt() is passed a open file pointer to the file it is to scan.
- * Lines are read and discarded until a line is found that contains only:
- * <<<===LDB===>>>
- * Subsequent lines should contain name/value pairs as specified
- * in nv_packet. The packet ends with end of file or a line beginning
- * with "end=". Getpkt reads from the input file until one
- * packet has been found and processed, then returns. Subsequent calls
- * to getpkt with the same file pointer will process additional packets.
- * Getpkt returns 1 if a valid packet was read, 0 if EOF was encountered.
- * Getpkt ignores incoming packets with the incorrect sequence number.
- *
- * As a compatibility hook with old versions, getpkt checks that the
- * version field on the incoming packet is high enough to support
- * the following features if they are enabled in the game:
- * feature need at least version
- * -------------------------------------
- * match play 1.1
- * jacoby rule 1.1
- * crawford rule 1.1
- * european rule 1.1
- * permanent games 1.1
- * If the incoming packet indicates a feature is not supported by the
- * remote ldb, it is disabled and the game continues as if it had
- * never been set. The Crawford rule contained a bug in pre-1.3 games,
- * so 1.3 will print a warning if an older version tries to start
- * a game with the crawford rule enabled.
- *
- * Getpkt handles RESEND packets itself, performing a resend and
- * discarding the packet.
- *---------------------------------------------------------------------------
- */
-
- getpkt(fp)
- FILE *fp;
- {
- static char buf[128];
- char *oldaddr;
- struct game *g;
- struct people *p;
- int i;
-
- while (fgets(buf,sizeof(buf),fp) != NULL) {
- if (strcmp(buf,"<<<===LDB===>>>\n"))/* skip all other lines */
- continue;
- P.gameid = NULL; /* init P structure */
- P.version = 100; /* default to oldest version */
- P.timestamp = 0L;
- P.opcode = -1;
- P.name = NULL;
- P.addr = NULL;
- P.comment = NULL;
- P.comment2 = NULL;
- P.seq = -1;
- P.autodbl = NULL;
- P.jacoby = NULL; /* jacoby is off by default */
- P.crawford = NULL; /* so is crawford */
- P.perm = NULL; /* so is permanent option */
- P.european = NULL; /* so is european rule */
- P.match = NULL; /* so is match play */
- clearmvs(P.mvs);
- P.gameptr = NULL;
- P.notify = NULL;
- nvscan(fp,nv_packet,&P); /* scan the packet into P */
- if (P.gameid == NULL) { /* didn't get a gameid */
- message("ERROR: missing gameid in packet -- ignored\n");
- continue;
- }
- if (P.version > 100) { /* versions after 1.0 rot13 comments */
- if (P.comment != NULL)
- rotate(P.comment);
- if (P.comment2 != NULL)
- rotate(P.comment2);
- }
- if ( (P.gameptr = findgame(P.gameid)) == NULL) {/* doesn't exist */
- if ( (P.opcode != START) && (P.opcode != RSTART) )
- continue; /* ignore pkts for dead games */
- i = 1; /* initial seq == 1 */
- }
- else {
- if (P.opcode == RESEND) { /* resend request */
- if ((P.seq + 1) != P.gameptr->seq)
- continue; /* old resend request, ignore */
- if (P.timestamp < P.gameptr->lastacc)
- continue; /* old resend request, ignore */
- message(
- "Resend requested for game %s -- sending...\n",
- P.gameid);
- resendpkt(P.gameptr); /* resend */
- P.gameptr->lastacc = time( (long *) 0); /*set lastacc*/
- if (P.timestamp > P.gameptr->lastacc)
- P.gameptr->lastacc = P.timestamp;
- continue; /* and ignore packet */
- }
- i = P.gameptr->seq+1; /* get current seq */
- }
- if (P.seq != i) { /* sequence number is wrong */
- if (P.seq > i) /* rec'd seq # is too big */
- message( /* shouldn't happen */
- "WARNING: game %s, seq no. is %d, s/b %d -- ignored.\n"
- ,P.gameid,P.seq,i);
- continue; /* ignore pkts with bad sequence #s */
- }
- if ( (P.opcode < 0) || (P.opcode >= NOP) ) { /* bad opcode */
- message("ERROR: bad opcode for game %s: %d -- ignored.\n",
- P.gameid,P.opcode);
- continue;
- }
-
- if (P.gameptr == NULL) /* everything after here needs ptr */
- return(1); /* to game structure */
-
- P.gameptr->seq += 2; /* bump sequence number */
- P.gameptr->lastacc = time( (long *) 0); /*set lastacc*/
- if (P.timestamp > P.gameptr->lastacc)
- P.gameptr->lastacc = P.timestamp;
- if (P.gameptr->opcmt != NULL)
- free(P.gameptr->opcmt); /* discard old comment */
- P.gameptr->opcmt = P.comment; /* copy new comment */
- if (P.gameptr->opcmt2 != NULL)
- free(P.gameptr->opcmt2);/* discard old comment */
- P.gameptr->opcmt2 = P.comment2; /* copy new comment */
- P.gameptr->opver = P.version; /*in case he changed versions*/
- P.gameptr->ppl->opver = P.version;
-
- if (P.addr != NULL) { /* opponent's address changed */
- oldaddr = P.gameptr->ppl->addr;
- for (g = ghead; g != NULL; g = g->next) /* all games with */
- if (strcmp(g->ppl->addr,oldaddr) == 0) {/* this opp */
- free(g->opaddr); /* free old addr */
- g->opaddr = save(P.addr); /* copy new */
- }
- for (p = phead; p != NULL; p = p->next) /* look for dangling */
- if (p->equiv != NULL) /* equiv records */
- if (strcmp(oldaddr,p->equiv) == 0) {
- free(p->equiv);
- p->equiv = save(P.addr);
- }
- free(P.gameptr->ppl->addr);
- P.gameptr->ppl->addr = save(P.addr);
- message("Address change for %s: %s\n",
- P.gameptr->opname,P.gameptr->opaddr);
- }
-
- if (P.gameptr->ppl->newaddr == NA_SENT) {/* newaddr pending this op */
- P.gameptr->ppl->newaddr = NA_NONE; /* cancel it */
- message("newaddr: %s notified.\n",P.gameptr->ppl->addr);
- }
-
- /* any 1.1 features used with 1.0? */
- if ( (P.version < 110) && ( (P.gameptr->mtotal > 0) ||
- (P.gameptr->flags & (F_JACOBY|F_CRAWFORD|F_PERM|F_EUROPE))) ) {
- message("Warning: in game %s:\n",P.gameid);
- message(
- "The following features are not supported by your opponent's version of ldb:\n"
- );
- if (P.gameptr->flags & F_JACOBY)
- message("\tJacoby rule.\n");
- if (P.gameptr->flags & F_CRAWFORD)
- message("\tCrawford rule.\n");
- if (P.gameptr->flags & F_EUROPE)
- message("\tEuropean rule.\n");
- if (P.gameptr->flags & F_PERM)
- message("\tPermanent games.\n");
- if (P.gameptr->mtotal > 0)
- message("\tMatch play.\n");
- P.gameptr->flags &=
- ~(F_CRAWFORD|F_JACOBY|F_PERM|F_EUROPE);
- P.gameptr->mtotal = 0;
- message(
- "This game will continue as if those features had not been used.\n");
- }
- if ( (P.version < 130) && (P.gameptr->flags & F_CRAWFORD) )
- message(
- "Warning: opponent using pre-1.3 ldb -- using Crawford rule not recommended!\n"
- );
- return(1); /* return success */
- }
- return(0); /* return this to mean end of file */
- }
-