home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume36 / ldb / part03 / readmail.c < prev   
Encoding:
C/C++ Source or Header  |  1993-04-11  |  11.9 KB  |  352 lines

  1. /*    readmail.c        8/7/91
  2.  *
  3.  * Copyright 1991  Perry R. Ross
  4.  *
  5.  * Permission to use, copy, modify, and distribute this software and its
  6.  * documentation without fee is hereby granted, subject to the restrictions
  7.  * detailed in the README file, which is included here by reference.
  8.  * Any other use requires written permission from the author.  This software
  9.  * is distributed "as is" without any warranty, including any implied
  10.  * warranties of merchantability or fitness for a particular purpose.
  11.  * The author shall not be liable for any damages resulting from the
  12.  * use of this software.  By using this software, the user agrees
  13.  * to these terms.
  14.  */
  15.  
  16. #include "ldb.h"
  17.  
  18. /*----------------------------------------------------------------------
  19.  *    readmail -- read the incoming mail and process it
  20.  *
  21.  * This function extracts each packet from the mail file and applies it
  22.  * to the appropriate game structure.  Most packets are processed by
  23.  * calling the handler found in the func array, which is a 2-dimensional
  24.  * array indexed by the current game state and the received opcode.
  25.  * The handlers are responsible for transforming the game state as
  26.  * necessary.  The START and RSTART opcodes receive special processing,
  27.  * since they apply to games that do not exist and thus have no state.
  28.  * START packets result in the creation of a game, whose state is set
  29.  * such that the correct handler will be called.  The RSTART opcode
  30.  * is processed in the same way as the -start command line argument;
  31.  * the packet is then discarded.
  32.  *
  33.  * Note that the file argument can be actually be a pattern, causing
  34.  * all matching files to be scanned.  On UNIX systems, patterns are
  35.  * interpreted in the same manner as the shell.  On VMS, they
  36.  * are interpreted in the same manner as DCL.
  37.  *----------------------------------------------------------------------
  38.  */
  39.  
  40. readmail(file)
  41. char *file;
  42. {
  43. struct flist *fl, *t;
  44.  
  45. fl = filelist(file);        /* generate a list of all matching files */
  46. while (fl != NULL) {        /* for each matching file found */
  47.     readfile(fl->name);    /* scan it */
  48.     free(fl->name);        /* free the string */
  49.     t = fl;            /* keep a pointer to the struct */
  50.     fl = fl->next;        /* advance fl pointer */
  51.     free(t);        /* free the previous struct */
  52.     }
  53. }
  54.  
  55.  
  56. /*----------------------------------------------------------------------
  57.  *    readfile -- scan a file looking for incoming messages
  58.  *
  59.  * This function is called by readmail to scan a file that matches
  60.  * the pattern.
  61.  *----------------------------------------------------------------------
  62.  */
  63.  
  64. readfile(name)
  65. char *name;
  66. {
  67. FILE *fp;
  68. int d, c1, c2;
  69. int flags = 0, match = 0;
  70. struct people *p;
  71. struct game *g;
  72.  
  73. if ( (fp = fopen(name,"r")) == NULL)
  74.     return;
  75. if (rc.debug & DB_READFILE)
  76.     message("DB-readfile: scanning %s\n",name);
  77. while (getpkt(fp) > 0) {    /* as long as we found a valid packet */
  78.     if (P.gameptr == NULL) {
  79.         if (rc.debug & DB_READFILE)
  80.             message("DB-readfile: found packet for <unknown>\n");
  81.         if (P.opcode == START) {
  82.             if ( ((p = findppl(P.addr,P_ADDR)) != NULL) &&
  83.                  (p->fence >= P.timestamp) )
  84.                 continue;    /* ignore old start packets */
  85.             P.gameptr = addgame(); /* init later in start() */
  86.             P.gameptr->ppl = p;
  87.             P.gameptr->gameid = P.gameid;
  88.             P.gameptr->state = ST_OPSTART;
  89.             }
  90.         else if (P.opcode == RSTART) {    /* remote start packet */
  91.             if (rc.debug & DB_RSTART)
  92.                 message("DB-readfile: remstart to %s\n",P.addr);
  93.             if ( (p = findppl(P.addr,P_ADDR)) != NULL)
  94.                 P.addr = p->addr;    /* use real addr */
  95.             for (g = ghead; g != NULL; g = g->next)
  96.                 if ( (P.timestamp == g->starttime) &&
  97.                      (strcmp(P.addr,g->opaddr) == 0) )
  98.                     break;    /* already seen this packet */
  99.             if (g != NULL)
  100.                 continue;
  101.             if ( (p != NULL) && (p->fence >= P.timestamp) )
  102.                 continue;    /* this game already played */
  103.             if (rc.debug & DB_RSTART)
  104.                 message("DB-readfile: address is %s\n",P.addr);
  105.             if (P.dir == NULL)    /* if no direction was given */
  106.                 d = cr_mydir;    /* use my default */
  107.             else            /* dir was given, grab it */
  108.                 d = (*P.dir == 'u') ? 1 : -1;
  109.             if (P.colors == NULL) {    /* if no colors were given */
  110.                 c1 = cr_mycolor;    /* use my defaults */
  111.                 c2 = cr_opcolor;
  112.                 }
  113.             else {                /* colors were given */
  114.                 c1 = *P.colors;        /* use them */
  115.                 c2 = P.colors[1];
  116.                 }
  117.             if (P.jacoby != NULL)
  118.                 flags |= F_JACOBY;
  119.             if (P.crawford != NULL)
  120.                 flags |= F_CRAWFORD;
  121.             if (P.european != NULL)
  122.                 flags |= F_EUROPE;
  123.             if (P.perm != NULL)
  124.                 flags |= F_PERM;
  125.             if (P.match != NULL)
  126.                 match = atoi(P.match);
  127.             notify = P.notify;    /* store notify address */
  128.             startgame(P.addr,d,c1,c2,flags,match,P.timestamp);
  129.             continue;    /* game started, discard this packet */
  130.             }
  131.         else {
  132.             message("ERROR: no such gameid: %s (ignored)\n",
  133.                 P.gameid);
  134.             continue;
  135.             }
  136.         }
  137.     if (rc.debug & DB_READFILE)
  138.         message("DB-readfile: found packet for %s\n",
  139.             P.gameptr->gameid);
  140.     if (P.gameptr->state >= OPSTATES) {    /* hey, it's still my turn */
  141.         message("ERROR: move out of turn: %s (ignored)\n",P.gameid);
  142.         continue;
  143.         }
  144.     if (P.name != NULL) {        /* snarf opponent's name */
  145.         P.gameptr->opname = P.name;
  146.         if (P.gameptr->ppl != NULL) {
  147.             if (P.gameptr->ppl->name != NULL)
  148.                 free(P.gameptr->ppl->name);
  149.             P.gameptr->ppl->name = save(P.name);
  150.             }
  151.         }
  152.     if (P.notify != NULL)
  153.         P.gameptr->notify = P.notify;
  154.     (*func[P.gameptr->state][P.opcode])(P.gameptr);    /* call handler */
  155.     }
  156. fclose(fp);
  157. if ( ((*rc.delmail == 'y') || (*rc.delmail == 'Y'))
  158. #ifndef VMS
  159.         && (*name != '/')    /* absolute paths not deleted */
  160. #endif
  161.     ) {
  162.     if (rc.debug & DB_READFILE)
  163.         message("DB-readfile: deleting mail file %s\n",name);
  164.     unlink(name);
  165.     }
  166. }
  167.  
  168.  
  169. /*---------------------------------------------------------------------------
  170.  *    getpkt -- read one packet from a file
  171.  *
  172.  * This function reads the next packet from the specified file.
  173.  * Getpkt() is passed a open file pointer to the file it is to scan.
  174.  * Lines are read and discarded until a line is found that contains only:
  175.  *        <<<===LDB===>>>
  176.  * Subsequent lines should contain name/value pairs as specified
  177.  * in nv_packet.  The packet ends with end of file or a line beginning
  178.  * with "end=".  Getpkt reads from the input file until one
  179.  * packet has been found and processed, then returns.  Subsequent calls
  180.  * to getpkt with the same file pointer will process additional packets.
  181.  * Getpkt returns 1 if a valid packet was read, 0 if EOF was encountered.
  182.  * Getpkt ignores incoming packets with the incorrect sequence number.
  183.  *
  184.  * As a compatibility hook with old versions, getpkt checks that the
  185.  * version field on the incoming packet is high enough to support
  186.  * the following features if they are enabled in the game:
  187.  *    feature        need at least version
  188.  *    -------------------------------------
  189.  *    match play        1.1
  190.  *    jacoby rule        1.1
  191.  *    crawford rule        1.1
  192.  *    european rule        1.1
  193.  *    permanent games        1.1
  194.  * If the incoming packet indicates a feature is not supported by the
  195.  * remote ldb, it is disabled and the game continues as if it had
  196.  * never been set.  The Crawford rule contained a bug in pre-1.3 games,
  197.  * so 1.3 will print a warning if an older version tries to start
  198.  * a game with the crawford rule enabled.
  199.  *
  200.  * Getpkt handles RESEND packets itself, performing a resend and
  201.  * discarding the packet.
  202.  *---------------------------------------------------------------------------
  203.  */
  204.  
  205. getpkt(fp)
  206. FILE *fp;
  207. {
  208. static char buf[128];
  209. char *oldaddr;
  210. struct game *g;
  211. struct people *p;
  212. int i;
  213.  
  214. while (fgets(buf,sizeof(buf),fp) != NULL) {
  215.     if (strcmp(buf,"<<<===LDB===>>>\n"))/* skip all other lines */
  216.         continue;
  217.     P.gameid = NULL;    /* init P structure */
  218.     P.version = 100;    /* default to oldest version */
  219.     P.timestamp = 0L;
  220.     P.opcode = -1;
  221.     P.name = NULL;
  222.     P.addr = NULL;
  223.     P.comment = NULL;
  224.     P.comment2 = NULL;
  225.     P.seq = -1;
  226.     P.autodbl = NULL;
  227.     P.jacoby = NULL;    /* jacoby is off by default */
  228.     P.crawford = NULL;    /* so is crawford */
  229.     P.perm = NULL;        /* so is permanent option */
  230.     P.european = NULL;    /* so is european rule */
  231.     P.match = NULL;        /* so is match play */
  232.     clearmvs(P.mvs);
  233.     P.gameptr = NULL;
  234.     P.notify = NULL;
  235.     nvscan(fp,nv_packet,&P);    /* scan the packet into P */
  236.     if (P.gameid == NULL) {        /* didn't get a gameid */
  237.         message("ERROR: missing gameid in packet -- ignored\n");
  238.         continue;
  239.         }
  240.     if (P.version > 100) {        /* versions after 1.0 rot13 comments */
  241.         if (P.comment != NULL)
  242.             rotate(P.comment);
  243.         if (P.comment2 != NULL)
  244.             rotate(P.comment2);
  245.         }
  246.     if ( (P.gameptr = findgame(P.gameid)) == NULL) {/* doesn't exist */
  247.         if ( (P.opcode != START) && (P.opcode != RSTART) )
  248.             continue;    /* ignore pkts for dead games */
  249.         i = 1;            /* initial seq == 1 */
  250.         }
  251.     else {
  252.         if (P.opcode == RESEND) {    /* resend request */
  253.             if ((P.seq + 1) != P.gameptr->seq)
  254.                 continue;    /* old resend request, ignore */
  255.             if (P.timestamp < P.gameptr->lastacc)
  256.                 continue;    /* old resend request, ignore */
  257.             message(
  258.                 "Resend requested for game %s -- sending...\n",
  259.                 P.gameid);
  260.             resendpkt(P.gameptr);    /* resend */
  261.             P.gameptr->lastacc = time( (long *) 0);    /*set lastacc*/
  262.             if (P.timestamp > P.gameptr->lastacc)
  263.                 P.gameptr->lastacc = P.timestamp;
  264.             continue;        /* and ignore packet */
  265.             }
  266.         i = P.gameptr->seq+1;    /* get current seq */
  267.         }
  268.     if (P.seq != i) {        /* sequence number is wrong */
  269.         if (P.seq > i)        /* rec'd seq # is too big */
  270.             message(        /* shouldn't happen */
  271.             "WARNING: game %s, seq no. is %d, s/b %d -- ignored.\n"
  272.             ,P.gameid,P.seq,i);
  273.         continue;        /* ignore pkts with bad sequence #s */
  274.         }
  275.     if ( (P.opcode < 0) || (P.opcode >= NOP) ) {    /* bad opcode */
  276.         message("ERROR: bad opcode for game %s: %d -- ignored.\n",
  277.             P.gameid,P.opcode);
  278.         continue;
  279.         }
  280.  
  281.     if (P.gameptr == NULL)        /* everything after here needs ptr */
  282.         return(1);        /* to game structure */
  283.  
  284.     P.gameptr->seq += 2;    /* bump sequence number */
  285.     P.gameptr->lastacc = time( (long *) 0);    /*set lastacc*/
  286.     if (P.timestamp > P.gameptr->lastacc)
  287.         P.gameptr->lastacc = P.timestamp;
  288.     if (P.gameptr->opcmt != NULL)
  289.         free(P.gameptr->opcmt);    /* discard old comment */
  290.     P.gameptr->opcmt = P.comment;    /* copy new comment */
  291.     if (P.gameptr->opcmt2 != NULL)
  292.         free(P.gameptr->opcmt2);/* discard old comment */
  293.     P.gameptr->opcmt2 = P.comment2;    /* copy new comment */
  294.     P.gameptr->opver = P.version;    /*in case he changed versions*/
  295.     P.gameptr->ppl->opver = P.version;
  296.  
  297.     if (P.addr != NULL) {    /* opponent's address changed */
  298.         oldaddr = P.gameptr->ppl->addr;
  299.         for (g = ghead; g != NULL; g = g->next)    /* all games with */
  300.             if (strcmp(g->ppl->addr,oldaddr) == 0) {/* this opp */
  301.                 free(g->opaddr);    /* free old addr */
  302.                 g->opaddr = save(P.addr);    /* copy new */
  303.                 }
  304.         for (p = phead; p != NULL; p = p->next)    /* look for dangling */
  305.             if (p->equiv != NULL)        /* equiv records */
  306.                 if (strcmp(oldaddr,p->equiv) == 0) {
  307.                     free(p->equiv);
  308.                     p->equiv = save(P.addr);
  309.                     }
  310.         free(P.gameptr->ppl->addr);
  311.         P.gameptr->ppl->addr = save(P.addr);
  312.         message("Address change for %s: %s\n",
  313.             P.gameptr->opname,P.gameptr->opaddr);
  314.         }
  315.     
  316.     if (P.gameptr->ppl->newaddr == NA_SENT) {/* newaddr pending this op */
  317.         P.gameptr->ppl->newaddr = NA_NONE;    /* cancel it */
  318.         message("newaddr: %s notified.\n",P.gameptr->ppl->addr);
  319.         }
  320.  
  321.             /* any 1.1 features used with 1.0? */
  322.     if ( (P.version < 110) && ( (P.gameptr->mtotal > 0) ||
  323.          (P.gameptr->flags & (F_JACOBY|F_CRAWFORD|F_PERM|F_EUROPE))) ) {
  324.         message("Warning: in game %s:\n",P.gameid);
  325.         message(
  326. "The following features are not supported by your opponent's version of ldb:\n"
  327.         );
  328.         if (P.gameptr->flags & F_JACOBY)
  329.             message("\tJacoby rule.\n");
  330.         if (P.gameptr->flags & F_CRAWFORD)
  331.             message("\tCrawford rule.\n");
  332.         if (P.gameptr->flags & F_EUROPE)
  333.             message("\tEuropean rule.\n");
  334.         if (P.gameptr->flags & F_PERM)
  335.             message("\tPermanent games.\n");
  336.         if (P.gameptr->mtotal > 0)
  337.             message("\tMatch play.\n");
  338.         P.gameptr->flags &=
  339.             ~(F_CRAWFORD|F_JACOBY|F_PERM|F_EUROPE);
  340.         P.gameptr->mtotal = 0;
  341.         message(
  342. "This game will continue as if those features had not been used.\n");
  343.         }
  344.     if ( (P.version < 130) && (P.gameptr->flags & F_CRAWFORD) )
  345.         message(
  346. "Warning: opponent using pre-1.3 ldb -- using Crawford rule not recommended!\n"
  347.         );
  348.     return(1);            /* return success */
  349.     }
  350. return(0);        /* return this to mean end of file */
  351. }
  352.