home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume15 / xmail / part07 / parser.c < prev    next >
C/C++ Source or Header  |  1991-10-29  |  19KB  |  523 lines

  1. /*
  2.  * xmail - X window system interface to the mail program
  3.  *
  4.  * Copyright 1989 The University of Texas at Austin
  5.  *
  6.  * Author:    Po Cheung
  7.  * Date:    March 10, 1989
  8.  *
  9.  * Permission to use, copy, modify, and distribute this software and
  10.  * its documentation for any purpose and without fee is hereby granted,
  11.  * provided that the above copyright notice appear in all copies and that
  12.  * both that copyright notice and this permission notice appear in
  13.  * supporting documentation.  The University of Texas at Austin makes no 
  14.  * representations about the suitability of this software for any purpose.  
  15.  * It is provided "as is" without express or implied warranty.
  16.  *
  17.  * Copyright 1990,1991 by National Semiconductor Corporation
  18.  *
  19.  * Permission to use, copy, modify, and distribute this software and its
  20.  * documentation for any purpose is hereby granted without fee, provided that
  21.  * the above copyright notice appear in all copies and that both that
  22.  * copyright notice and this permission notice appear in supporting
  23.  * documentation, and that the name of National Semiconductor Corporation not
  24.  * be used in advertising or publicity pertaining to distribution of the
  25.  * software without specific, written prior permission.
  26.  *
  27.  * NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE
  28.  * SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS"
  29.  * WITHOUT EXPRESS OR IMPLIED WARRANTY.  NATIONAL SEMICONDUCTOR CORPORATION
  30.  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
  31.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO
  32.  * EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL,
  33.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  34.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  35.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  36.  * PERFORMANCE OF THIS SOFTWARE.
  37.  *
  38.  * Author:  Michael C. Wagnitz - National Semiconductor Corporation
  39.  *
  40.  */
  41.  
  42. #define    PARSER
  43.  
  44. #include    <ctype.h>
  45. #include    "global.h"
  46. #include    "xmailregexp.h"
  47.  
  48. #define    INIT        register char *sp=instring; int sed=1;
  49. #define    GETC()        (*sp++)
  50. #define    PEEKC()        (*sp)
  51. #define    UNGETC(c)    (--sp)
  52. #define    RETURN(c)    return
  53. #define    ERROR(c)    regerr(c)
  54.  
  55. #include <regexp.h>
  56.  
  57. int    regexp_indx;
  58.  
  59. static    char    MailPrompt[80];        /* overkill on size, but to be safe */
  60.  
  61. extern    void    reset_mailbox();
  62. extern    Boolean    Waiting;
  63.  
  64. static char *regexp_error[] = {
  65.           "","","","","","","","","","","",
  66.  /* 11 */ "Range endpoint too large", "","","","",
  67.  /* 16 */ "Bad number", "","","","","","","","",
  68.  /* 25 */ "``\\digit'' out of range", "","","","","","","","","","",
  69.  /* 36 */ "Illegal or missing delimiter", "","","","",
  70.  /* 41 */ "No remembered search string",
  71.  /* 42 */ "\\(\\) imbalance",
  72.  /* 43 */ "Too many \\(",
  73.  /* 44 */ "More than 2 numbers given in \\{\\}",
  74.  /* 45 */ "} expected after \\",
  75.  /* 46 */ "First number exceeds second in \\{\\}", "", "",
  76.  /* 49 */ "[] imbalance",
  77.  /* 50 */ "Regular expression too long",
  78.  NULL
  79. };
  80.  
  81.  
  82. regerr(c)
  83. int    c;
  84. {
  85.  (void) fprintf(stderr, "xmail: %s (item %d).\n", regexp_error[c], regexp_indx);
  86.  exit(0);
  87. }
  88.  
  89.  
  90. /*
  91. **  @(#)compile_pattern() - compile regular expression patterns in a table.
  92. **  A pattern table is an array of pattern records.
  93. **  Each pattern record consists of a regular expression,
  94. **  and a buffer for the compiled regular expression,
  95. */
  96. void
  97. compile_pattern(patternTable)
  98. PatternRecPtr    patternTable;
  99. {
  100.  PatternRecPtr    cp;
  101.  char        *bp;
  102.  int        i;
  103.  
  104.  for (regexp_indx=0, cp=patternTable; cp->pat||cp->buf; regexp_indx++, cp++) {
  105.      if (! cp->pat) continue;        /* skip over grouping separations */
  106.      i = 2 * strlen(cp->pat) + 1;
  107.      for (bp = cp->pat; *bp && (bp = (char *)strchr(bp, '[')); bp++) i += 17;
  108.      bp = (char *) XtMalloc((unsigned) i);
  109.      (void) compile(cp->pat, bp, &bp[i], '\0');
  110.      cp->buf = bp;
  111.     }
  112. }
  113.  
  114. /*
  115. ** @(#)match() - string against regular expressions in pattern table.
  116. */
  117. int
  118. match(patternTable, string)
  119. PatternRecPtr     patternTable;
  120. char        *string;
  121. {
  122.  PatternRecPtr    cp;
  123.  int        id;
  124.  
  125.  if (strcmp(string, "") == NULL) return -1;
  126.  for (id = 0, cp = patternTable; cp->pat || cp->buf; cp++) {
  127.      if (! cp->pat) { id++; continue; }
  128.      if (advance(string, cp->buf))
  129.         return (id);
  130.     }
  131.  return (-1);
  132. }
  133.  
  134.  
  135. /*
  136. ** @(#)parser_init()- compile command and output pattern tables.
  137. */
  138. void
  139. parser_init()
  140. {
  141.  (void) compile_pattern(command_pattern);
  142.  (void) compile_pattern(output_pattern);
  143. }
  144.  
  145.  
  146. /*
  147. ** @(#)parse() - command and output and call appropriate handler
  148. */
  149. void
  150. parse(msg)
  151. String    msg;
  152. {
  153.  Cardinal    j, k, msgnum;
  154.  Widget        button, icon, iw;
  155.  char        tmp[128], *c, *s;
  156.  static    Boolean    first_time = True;
  157.  
  158.  
  159.  j = match(command_pattern, Command);
  160.  switch (j) {
  161. /*
  162. ** If error on startup, mail has terminated connection.  Remove our input
  163. ** handler, close the file from our end, and indicate that no connection
  164. ** exists.  Otherwise, establish conversation requirements and display the
  165. ** current message.  If *Show_Last: resource is NOT False, show latest, if
  166. ** none are newer.  We delay setting the icon event handler until now, to
  167. ** ensure mail startup completed before being interrupted by a map event,
  168. ** for the case where we have been started iconic.
  169. */
  170.     case C_START :  if (O_BELL == match(output_pattern, msg)) {
  171.                        if (mailpid) {
  172.                           XtRemoveInput(mailInputId);
  173.                           (void) close(mail_fd);
  174.                           mailpid = 0;
  175.                           if (MailPrompt)
  176.                              MailPrompt[0] = NULL;
  177.                          }
  178.                if (strncmp(msg, "No mail for ", 12) == 0)
  179.               Bell("No mail in your system mailbox\n");
  180.                else Bell(msg);
  181.                (void) UpdateTitleBar("No current folder");
  182.                        XtFree(msg);
  183.                *msg = '\0';
  184.                       } else {
  185. /*
  186. ** To prevent a race condition (?) when starting the application iconic,
  187. ** (which would cause this loop to repeat multiple times), test the value
  188. ** of the ``screen'' mail environment variable.  If 10,000 then we're done.
  189. */
  190.                        j = True;
  191.                        if (c = GetMailEnv("screen")) {
  192.                           j = (strcmp("10000", c) != 0) ? True : False;
  193.                           XtFree(c);
  194.                          }
  195.                        if (j) {            /* if not yet set to 10000... */
  196.                           (void) strcpy(tmp, "set screen=10000 toplines=100 ");
  197.  
  198.                           /* default action for xmail is hold (ala mailtool) */
  199.  
  200.                           if (c = GetMailrc("nohold")) XtFree(c);
  201.                           else (void) strcat(tmp, "hold");
  202.  
  203.                           c = QueryMail(tmp);
  204.                           XtFree(c);
  205.  
  206.                           (void) strcpy(tmp, "unset crt replyall cmd");
  207.  
  208.                           c = QueryMail(tmp);
  209.                           XtFree(c);
  210.  
  211.                           if (msgnum = file_handler()) {
  212.                              (void) sprintf(tmp, "%d", msgnum);
  213.                              XtFree(msg);
  214.                              msg = QueryMail(tmp);
  215.                             }
  216.                           Bell("");        /* reset any worthy-ness flag */
  217.                           Bell(Default_Status_Info);
  218.                          }
  219.                       }
  220.                     if (first_time) {        /* only need to do this once */
  221.                        Waiting = FALSE;
  222.                        first_time = False;
  223.                        icon = XtNameToWidget(toplevel, "icon");
  224.                        XtAddEventHandler(icon, StructureNotifyMask, False,
  225.                                          icon_handler, NULL);
  226.                        if (In_Bogus_Mail_File) {
  227.                           (void) unlink(sprintf(tmp, "%s+", tmpName));
  228.                           XtFree(msg);
  229.                   *msg = '\0';        /* ignore 'skipping' message */
  230.                          }
  231.                       }
  232.                 break;
  233. /*
  234. ** In response to normal or change folder commands, test output.  If an
  235. ** error, display message in status window, and ring bell unless command
  236. ** was save, Save to author, or undelete.  If our current mail message
  237. ** folder is the bogus folder, erase any text and index and note state.
  238. ** If we have text of next mail message, tell index_handler to mark its
  239. ** number, else retrieve the appropriate message text (which also marks
  240. ** its number).  If *Show_Last: resource is NOT False, file cmd shows
  241. ** latest, if none new.
  242. */
  243.     case C_EXEC  :
  244.     case C_FILE  :  j = match(output_pattern, msg);
  245.             switch (j) {
  246.                case O_BELL:
  247.                             if (strchr("SsCcw", Command[0]) != NULL) {
  248.                                if (isdigit(msg[strlen(msg) - 2]))
  249.                                   LASTCH(msg) = '\0';
  250.                                else Command[0] = '\0';
  251.                               }
  252.                     if (strncmp(msg, tmpName, strlen(tmpName)) == 0)
  253.                        Bell("No mail in your system mailbox");
  254.                     else Bell(msg);
  255.                                     XtFree(msg);
  256. /*
  257. ** Save our current message number, because asking about our 'file' status
  258. ** will reset mail's idea of the 'current message' count to one, regardless.
  259. */
  260.                                     msgnum = SelectionNumber(False);
  261. /*
  262. ** Now ask for 'file' status to determine if we are still caught in our 'bogus'
  263. ** mailfile, in order to generate a more meaningful title-bar status message.
  264. */
  265.                                     msg = QueryMail("file");
  266.                                     if (strncmp(&msg[1], tmpName, strlen(tmpName)) == 0) {
  267.                                (void) UpdateTitleBar("No current folder");
  268.                                        iw = XtNameToWidget(toplevel, "topBox");
  269.                                        writeTo(XtNameToWidget(iw, "indexWindow"), " ", REPLACE);
  270.                                        writeText(" ");
  271.                                       } else {
  272.                                        (void) UpdateTitleBar(msg);
  273.                                        XtFree(msg);
  274. /*
  275. ** If not in our bogus mail folder, reset the current message
  276. ** number in Mail by again pointing at that numbered message.
  277. */
  278.                                        (void) sprintf(tmp, "f %d", msgnum);
  279.                                        msg = QueryMail(tmp);
  280.                                        if (Command[0] != NULL)
  281.                                           if (strchr("Ssw", Command[0]))
  282.                                              markIndex(">S");
  283.                                       }
  284.                                     XtFree(msg);
  285.                                     *msg='\0';
  286.                                     break;
  287.                case O_EXEC: msgnum = index_handler(0, 0);
  288.                                     break;
  289.                case O_FILE: msgnum = file_handler();
  290.                             c = strchr(msg, '\n');
  291.                             if ((int)(c - msg) < strlen(msg) - 1) {
  292.                                        *c = '\0';    /* don't bell this */
  293.                        Bell("");    /* clear worthy flag */
  294.                        Bell(msg);
  295.                               }
  296.                                     XtFree(msg);
  297.                                     *msg = '\0';
  298.                                     if (msgnum) {
  299.                                        (void) sprintf(tmp, "%d", msgnum);
  300.                                        msg = QueryMail(tmp);
  301.                                       }
  302.                             break;
  303.                   }
  304.                     break;
  305. /*
  306. ** When deleting a message, simply mark that index line with a capital 'D'.
  307. ** If un-deleting, mark that index line with a blank ' '.  If no current
  308. ** index, restore it.  If autoprinting, mail will include text of next msg.
  309. */
  310.     case C_DELETE : if (O_BELL == match(output_pattern, msg)) {
  311.                        Bell(msg);
  312.                        XtFree(msg);
  313.                        *msg = '\0';
  314.                       } else {
  315.                        msgnum = SelectionNumber(False);
  316.                        if (Command[0] == 'd') {
  317.                           if (msgnum) {
  318.                              markIndex("D");
  319.                      msgnum = index_handler(msgnum+1, 0);
  320.                             }
  321.                          } else {        /* if we are 'undeleting' */
  322.                   c = QueryMail("=");
  323.                   (void) sscanf(c, "%d", &msgnum);
  324.                   XtFree(c);
  325.                           iw = XtNameToWidget(toplevel, "topBox.indexWindow");
  326.                           if (TextGetLastPos(iw) < (XawTextPosition) 4) {
  327.                              c = QueryMail("h");
  328.                              writeTo(iw, c, REPLACE);
  329.                      XtFree(c);
  330.                             }
  331.                   msgnum = index_handler(msgnum, 1);
  332.                          }
  333.                        c = QueryMail("file");    /* resets current msg to 1 */
  334.                        (void) UpdateTitleBar(c);
  335.                XtFree(c);
  336.  
  337.                        if (msgnum == 0)    {    /* if was last msg in file */
  338.                           XtFree(msg);
  339.                           msg = XtNewString("\n");    /* erase its text */
  340.                          } else {        /* reset mail's idea of the */
  341.                           (void) sprintf(tmp, "f %d", msgnum); /* current message */
  342.                           c = QueryMail(tmp);
  343.                           XtFree(c);
  344.                          }
  345.                        if (! *msg)        /* Don't allow memory leaks */
  346.                           XtFree(msg);        /* to accumulate if no text */
  347.                       }
  348.             break;
  349. /*
  350. ** In response to a request to view new mail, first reset the mailbox flag.
  351. ** If mail came back with an error, complain to the user.  Otherwise, clear
  352. ** the Newmail command button highlighting. Then display any new mail text.
  353. */
  354.     case C_NEWMAIL:
  355.             button = XtNameToWidget(toplevel, "topBox.commandPanel.Folder");
  356.             UnsetNewmail(button, NULL, NULL);
  357.                     if (O_BELL == match(output_pattern, msg)) {
  358.                        if (strncmp(msg, "No mail for ", 12) == 0) {
  359.                           Bell("No mail in your system mailbox\n");
  360.                          } else { Bell(msg); }
  361.                        XtFree(msg);
  362.                        *msg = '\0';
  363.                       } else {
  364.                        Bell("");        /* reset any worthy-ness flag */
  365.                        Bell(Default_Status_Info);
  366.                        msgnum = file_handler();
  367.                if (*msg) {
  368.                   s = msg;
  369.                   c = strchr(msg, '\n');
  370.                   if ((c - s) + 1 < strlen(msg)) {
  371.                              *c = '\0';    /* don't bell this */
  372.                  Bell(msg);
  373.                             }
  374.                          }
  375.                        XtFree(msg);
  376.                        *msg = '\0';
  377.                        if (msgnum) {
  378.                           (void) sprintf(tmp, "%d", msgnum);
  379.                           msg = QueryMail(tmp);
  380.                          }
  381.                       }
  382.             break;
  383.  
  384.            default: j = match(output_pattern, msg);
  385.             switch (j) {
  386.                        case O_BELL:
  387.                             Bell(msg);
  388.                             XtFree(msg);
  389.                             *msg = '\0';
  390.                     break;
  391. /*
  392. ** If output is from the print command, display a status message
  393. */
  394.                case O_PRINT:
  395.                             (void) sscanf(&Command[2], "%d", &j);
  396.                             c = strrchr(msg, '/');
  397.                             (void) sscanf(c, "/%d", &k);
  398.                             (void) sprintf(tmp,
  399.                              "Message %d sent to printer -- %d bytes\n", j, k);
  400.                             Bell(tmp);
  401.                             XtFree(msg);
  402.                             *msg = '\0';
  403.                     break;
  404. /*
  405. ** If we didn't specifically ask for it, and its not an error, just toss it.
  406. ** Preserve post processing moved here, in case we weren't allowed to do it.
  407. */
  408.                        default:
  409.                             if (strncmp(Command, "preserve", 8) == 0)
  410.                                markIndex("P");
  411.  
  412.                             XtFree(msg);
  413.                             *msg = '\0';
  414.                     break;
  415.                       }
  416.             break;
  417.    }
  418. /*
  419. ** If any text remains, display it in the bottom (text) window.
  420. */
  421.  if (*msg) {
  422.     for (j = strlen(msg)-1; j > 1 && msg[j] == '\n' && msg[j-1] == '\n'; j--);
  423.     msg[++j] = '\0';            /* drop all but the last newline */
  424.     writeText(msg);
  425.     XtFree(msg);
  426.     *msg = '\0';
  427.    }
  428.  SetCursor(NORMAL);
  429. } /* parse */
  430.  
  431. #define    FILEBUF    4096
  432.  
  433.  
  434. /*
  435. ** @(#)QueryMail() - Sends a command and returns corresponding output.
  436. ** If called by the Xt input procedure readMail, no command is included.
  437. */
  438. char *
  439. QueryMail(cmd)
  440. char    *cmd;
  441. {
  442.  int        j, outputsize, size, dlen, length = 0;
  443.  char        *temp, s[FILEBUF];
  444.  static char    *output;
  445.  
  446.  
  447.  if (*MailPrompt) length = strlen(MailPrompt);
  448. /*
  449. ** allocate one block to 'output' to begin with
  450. */
  451.  outputsize = FILEBUF;
  452.  output = XtMalloc((unsigned) outputsize);
  453.  output[0] = '\0';
  454.  
  455.  if (! mailpid)
  456.     Bell("No current mail program connection\n");
  457.  else {
  458.     if (*cmd) {                /* allow us to be called by readMail */
  459.        if (LASTCH(cmd) != '\n')
  460.           (void) sprintf(s, "%s\n", cmd);
  461.        else
  462.           (void) strcpy(s, cmd);
  463.        writeMail(s);
  464.       }
  465.  
  466.     for (;;) {
  467.         if ((size = read(mail_fd, s, FILEBUF)) < 1) {    /* EOF or an error? */
  468.            if (! *output) {
  469.               (void) strcpy(output, "No current mail service connection\n");
  470.               if (mailpid) {
  471.                  XtRemoveInput(mailInputId);
  472.                  (void) close(mail_fd);
  473.                  mailpid = 0;
  474.                  if (MailPrompt)
  475.                     MailPrompt[0] = NULL;
  476.                 }
  477.              }
  478.            break;
  479.           }
  480.  
  481.         if (size < FILEBUF)
  482.            s[size] = '\0';
  483.  
  484.         if (strlen(output) + size > outputsize) {
  485.            outputsize += FILEBUF;
  486.            temp = XtRealloc(output, outputsize);
  487.            output = temp;
  488.           }
  489.         (void) strcat(output, s);
  490.  
  491.         /*
  492.         ** If we have no prompt and are just starting, get the prompt string.
  493.         ** This makes the GROSS assumption that we will have gotten it here.
  494.         */
  495.         if (*output && ! *MailPrompt && strcmp(Command, "Start") == 0) {
  496.            if ((temp = strrchr(output, '\n')) != NULL)
  497.               (void) strcpy(MailPrompt, temp + 1);
  498.            else
  499.               (void) strcpy(MailPrompt, output);
  500.            length = strlen(MailPrompt);
  501.           }
  502.  
  503.         j = strlen(output) - length;
  504.         if (j < 0) j = 0;        /* no references before zero */
  505.         if (*MailPrompt && strcmp(&output[j], MailPrompt) == 0) {
  506.            output[j] = '\0';        /* Drop prompt from end of text */
  507.            break;            /* and return from read routine */
  508.           }
  509.  
  510.         if (O_BELL == match(output_pattern,output) && !strcmp(Command,"Start"))
  511.            break;
  512.        }
  513.  
  514.     if (*cmd) 
  515.        LASTCH(output) = '\0';        /* drop newline for normal queries */
  516.    }
  517.  
  518.  temp = XtRealloc(output, strlen(output) + 1);
  519.  output = temp;
  520.  
  521.  return(output);
  522. } /* QueryMail */
  523.