home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / x / volume13 / xmail / part05 / parser.c < prev   
C/C++ Source or Header  |  1991-06-15  |  17KB  |  466 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 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 TORTUOUS 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    "global.h"
  45. #include    "regex.h"
  46. #include    "xmailregex.h"
  47.  
  48. #define        BYTEWIDTH    8
  49. #define        RE_BUFFER    100
  50.  
  51. extern void    reset_mailbox();
  52.  
  53. /*
  54. **  @(#)compile() - regular expression patterns into a pattern table.
  55. **  A pattern table is an array of pattern records.
  56. **  Each pattern record consists of a regular expression,
  57. **  and a buffer for the to-be-compiled regular expression,
  58. */
  59. static void
  60. compile(patternTable)
  61. PatternRec *patternTable;
  62. {
  63.  PatternRec    *p;
  64.  char     fastmap[(1 << BYTEWIDTH)];
  65.  int        i;
  66.  
  67.     for (i=0; patternTable[i].pat; i++) {
  68.     p = &patternTable[i];
  69.     p->buf = (struct re_pattern_buffer *) 
  70.       XtMalloc (sizeof (struct re_pattern_buffer));
  71.     p->buf->allocated = RE_BUFFER;
  72.     p->buf->buffer = (char *) XtMalloc (p->buf->allocated);
  73.     p->buf->fastmap = fastmap;
  74.     p->buf->translate = NULL;
  75.     re_compile_pattern(p->pat, strlen(p->pat), p->buf);
  76.     re_compile_fastmap(p->buf);
  77.     }
  78.  
  79. /*
  80. ** @(#)match() - string against regular expressions in pattern table.
  81. ** The best match is found, and function returns index to the pattern table.
  82. */
  83. int
  84. match(patternTable, string)
  85. PatternRec     *patternTable;
  86. char     *string;
  87. {
  88.     int            m, bestmatch = -1, index = -1, i;
  89.  
  90.     if (strcmp(string, "") == NULL) return -1;
  91.     for (i=0; patternTable[i].pat; i++) {
  92.     m = re_match(patternTable[i].buf, string, strlen(string), 0, NULL);
  93.     if (m > bestmatch) {
  94.         bestmatch = m;
  95.         index = i;
  96.     }
  97.     }
  98.     return index;
  99. }
  100.  
  101. /*
  102. ** @(#)parser_init()- compile output and command pattern tables.
  103. */
  104. void
  105. parser_init()
  106. {
  107.  compile(output_pattern);
  108.  compile(command_pattern);
  109. }
  110.  
  111.  
  112. /*
  113. ** @(#)parse() - command and output and call appropriate handler
  114. */
  115. void
  116. parse(msg)
  117. String    msg;
  118. {
  119.  Cardinal    j, k, msgnum;
  120.  Widget        button, icon, iw;
  121.  char        tmp[128], *c, *s;
  122.  static    Boolean    first_time = True;
  123.  
  124.  
  125.  j = match(command_pattern, Command);
  126.  switch (j) {
  127. /*
  128. ** If error on startup, mail has terminated connection.  Remove our input
  129. ** handler, close the file from our end, and indicate that no connection
  130. ** exists.  Otherwise, establish conversation requirements and display the
  131. ** current message.  If *Show_Last: resource is NOT False, show latest, if
  132. ** none are newer.  We delay setting the icon event handler until now, to
  133. ** ensure mail startup completed before being interrupted by a map event,
  134. ** for the case where we have been started iconic.
  135. */
  136.     case C_START :  if (O_BELL == match(output_pattern, msg)) {
  137.                        if (mailpid) {
  138.                           XtRemoveInput(mailInputId);
  139.                           close(mail_fd);
  140.                           mailpid = 0;
  141.                          }
  142.                LASTCH(msg) = '\0';    /* Don't ring Bell() for this */
  143.                Bell(msg);
  144.                (void) UpdateTitleBar("No current folder");
  145.                        XtFree(msg);
  146.                *msg = '\0';
  147.                       } else {
  148. /*
  149. ** To prevent a race condition (?) when starting the application iconic,
  150. ** (which would cause this loop to repeat multiple times), test the value
  151. ** of the ``screen'' mail environment variable.  If 10,000 then we're done.
  152. */
  153.                        j = True;
  154.                        if (c = GetMailEnv("screen")) {
  155.                           j = (strcmp("10000", c) != 0) ? True : False;
  156.                           XtFree(c);
  157.                          }
  158.                        if (j) {            /* if not yet set to 10000... */
  159.                           strcpy(tmp, "set screen=10000 toplines=100 ");
  160.  
  161.                           /* default action for xmail is hold (ala mailtool) */
  162.  
  163.                           if (c = GetMailrc("nohold")) XtFree(c);
  164.                           else strcat(tmp, "hold");
  165.  
  166.                           c = QueryMail(tmp);
  167.                           XtFree(c);
  168.  
  169.                           strcpy(tmp, "unset crt replyall");
  170.  
  171.                           c = QueryMail(tmp);
  172.                           XtFree(c);
  173.  
  174.                           if (msgnum = file_handler()) {
  175.                              sprintf(tmp, "%d", msgnum);
  176.                              XtFree(msg);
  177.                              msg = QueryMail(tmp);
  178.                             }
  179.                           Bell("");        /* reset any worthy-ness flag */
  180.                           Bell(Default_Status_Info);
  181.                          }
  182.                       }
  183.                     if (first_time) {        /* only need to do this once */
  184.                        first_time = False;
  185.                        icon = XtNameToWidget(toplevel, "icon");
  186.                        XtAddEventHandler(icon, StructureNotifyMask, False,
  187.                                          icon_handler, NULL);
  188.                        if (In_Bogus_Mail_File) {
  189.                           unlink(sprintf(tmp, "%s+", tmpName));
  190.                           XtFree(msg);
  191.                   *msg = '\0';        /* ignore 'skipping' message */
  192.                          }
  193.                       }
  194.                 break;
  195. /*
  196. ** In response to normal or change folder commands, test output.  If an
  197. ** error, display message in status window, and ring bell unless command
  198. ** was save, Save to author, or undelete.  If our current mail message
  199. ** folder is the bogus folder, erase any text and index and note state.
  200. ** If we have text of next mail message, tell index_handler to mark its
  201. ** number, else retrieve the appropriate message text (which also marks
  202. ** its number).  If *Show_Last: resource is NOT False, file cmd shows
  203. ** latest, if none new.
  204. */
  205.     case C_EXEC  :
  206.     case C_FILE  :  j = match(output_pattern, msg);
  207.             switch (j) {
  208.                case O_BELL  :
  209.                               if (strchr("Ssu", *Command))
  210.                                  LASTCH(msg) = '\0';
  211.                               Bell(msg);
  212.                                       XtFree(msg);
  213. /*
  214. ** Save our current message number, because asking about our 'file' status
  215. ** will reset mail's idea of the 'current message' count to one, regardless.
  216. */
  217.                                       msgnum = SelectionNumber(False);
  218. /*
  219. ** Now ask for 'file' status to determine if we are still caught in our 'bogus'
  220. ** mailfile, in order to generate a more meaningful title-bar status message.
  221. */
  222.                                       msg = QueryMail("file");
  223.                                       if (strncmp(&msg[1], tmpName, strlen(tmpName)) == 0) {
  224.                                  (void) UpdateTitleBar("No current folder");
  225.                                          iw = XtNameToWidget(toplevel, "topBox");
  226.                                          writeTo(XtNameToWidget(iw, "indexWindow"), " ");
  227.                                          writeTo(XtNameToWidget(iw, "textWindow.text"), " ");
  228.                                         } else {
  229.                                          (void) UpdateTitleBar(msg);
  230.                                          XtFree(msg);
  231. /*
  232. ** If not in our bogus mail folder, reset the current message
  233. ** number in Mail by again pointing at that numbered message.
  234. */
  235.                                          sprintf(tmp, "f %d", msgnum);
  236.                                          msg = QueryMail(tmp);
  237.                                          if (strchr("Ss", *Command))
  238.                                             markIndex(">S");
  239.                                         }
  240.                                       XtFree(msg);
  241.                                       *msg='\0';
  242.                                       break;
  243.                case O_EXEC  : msgnum = index_handler(0, 0);
  244.                                       break;
  245.                case O_FILE  : msgnum = file_handler();
  246.                               c = strchr(msg, '\n');
  247.                               if ((int)(c - msg) < strlen(msg) - 1) {
  248.                                          *c = '\0';    /* don't bell this */
  249.                      Bell("");    /* clear worthy flag */
  250.                      Bell(msg);
  251.                                 }
  252.                                       XtFree(msg);
  253.                                       *msg = '\0';
  254.                                       if (msgnum) {
  255.                                          sprintf(tmp, "%d", msgnum);
  256.                                          msg = QueryMail(tmp);
  257.                                         }
  258.                               break;
  259.                   }
  260.                     break;
  261. /*
  262. ** When deleting a message, simply mark that index line with a capital 'D'.
  263. ** If un-deleting, mark that index line with a blank ' '.  If no current
  264. ** index, restore it.  If autoprinting, mail will include text of next msg.
  265. */
  266.     case C_DELETE : if (O_BELL == match(output_pattern, msg)) {
  267.                        Bell(msg);
  268.                        XtFree(msg);
  269.                        *msg = '\0';
  270.                       } else {
  271.                        msgnum = SelectionNumber(False);
  272.                        if (*Command == 'd') {
  273.                           if (msgnum) {
  274.                              markIndex("D");
  275.                      msgnum = index_handler(msgnum+1, 0);
  276.                             }
  277.                          } else {        /* if we are 'undeleting' */
  278.                   c = QueryMail("=");
  279.                   sscanf(c, "%d", &msgnum);
  280.                   XtFree(c);
  281.                           iw = XtNameToWidget(toplevel, "topBox.indexWindow");
  282.                           if (TextGetLastPos(iw) < (XawTextPosition) 4) {
  283.                              c = QueryMail("h");
  284.                              writeTo(iw, c);
  285.                      XtFree(c);
  286.                             }
  287.                   msgnum = index_handler(msgnum, 1);
  288.                          }
  289.                        c = QueryMail("file");    /* resets current msg to 1 */
  290.                        (void) UpdateTitleBar(c);
  291.                XtFree(c);
  292.  
  293.                        if (msgnum == 0)    {    /* if was last msg in file */
  294.                           XtFree(msg);
  295.                           msg = XtNewString("\n");    /* erase its text */
  296.                          } else {        /* reset mail's idea of the */
  297.                           sprintf(tmp, "f %d", msgnum); /* current message */
  298.                           c = QueryMail(tmp);
  299.                           XtFree(c);
  300.                          }
  301.                        if (! *msg)        /* Don't allow memory leaks */
  302.                           XtFree(msg);        /* to accumulate if no text */
  303.                       }
  304.             break;
  305. /*
  306. ** In response to a request to view new mail, first reset the mailbox flag.
  307. ** If mail came back with an error, complain to the user.  Otherwise, clear
  308. ** the Newmail command button highlighting. Then display any new mail text.
  309. */
  310.     case C_NEWMAIL:
  311.             button = XtNameToWidget(toplevel, "topBox.commandPanel.Folder");
  312.             UnsetNewmail(button, NULL, NULL);
  313.                     if (O_BELL == match(output_pattern, msg)) {
  314.                        if (strncmp(msg, "No mail for ", 12) == 0) {
  315.                           Bell("No mail in your system mailbox\n");
  316.                          } else { Bell(msg); }
  317.                        XtFree(msg);
  318.                        *msg = '\0';
  319.                       } else {
  320.                        Bell("");        /* reset any worthy-ness flag */
  321.                        Bell(Default_Status_Info);
  322.                        msgnum = file_handler();
  323.                if (*msg) {
  324.                   s = msg;
  325.                   c = strchr(msg, '\n');
  326.                   if ((c - s) + 1 < strlen(msg)) {
  327.                              *c = '\0';    /* don't bell this */
  328.                  Bell(msg);
  329.                             }
  330.                          }
  331.                        XtFree(msg);
  332.                        *msg = '\0';
  333.                        if (msgnum) {
  334.                           sprintf(tmp, "%d", msgnum);
  335.                           msg = QueryMail(tmp);
  336.                          }
  337.                       }
  338.             break;
  339.  
  340.            default: j = match(output_pattern, msg);
  341.             switch (j) {
  342.                        case O_BELL:
  343.                             Bell(msg);
  344.                             XtFree(msg);
  345.                             *msg = '\0';
  346.                     break;
  347. /*
  348. ** If output is from the print command, display a status message
  349. */
  350.                case O_PRINT:
  351.                             sscanf(&Command[2], "%d", &j);
  352.                             c = strrchr(msg, '/');
  353.                             sscanf(c, "/%d", &k);
  354.                             sprintf(tmp,
  355.                              "Message %d sent to printer -- %d bytes\n", j, k);
  356.                             Bell(tmp);
  357.                             XtFree(msg);
  358.                             *msg = '\0';
  359.                     break;
  360.                       }
  361.             break;
  362.    }
  363. /*
  364. ** If any text remains, display it in the bottom (text) window.
  365. */
  366.  if (*msg) {
  367.     for (j = strlen(msg)-1; j > 1 && msg[j] == '\n' && msg[j-1] == '\n'; j--);
  368.     msg[++j] = '\0';            /* drop all but the last newline */
  369.     writeTo(XtNameToWidget(toplevel, "topBox.textWindow.text"), msg);
  370.     XtFree(msg);
  371.     *msg = '\0';
  372.    }
  373. } /* parse */
  374.  
  375. #define    FILEBUF    4096
  376.  
  377. /*
  378. ** @(#)QueryMail() - Sends a command and returns corresponding output.
  379. ** If called by the Xt input procedure readMail, no command is included.
  380. */
  381. char *
  382. QueryMail(cmd)
  383. char    *cmd;
  384. {
  385.  int        j, outputsize, size, length = strlen(MailPrompt);
  386.  char        *temp, s[FILEBUF];
  387.  static char    *output;
  388.  
  389.  
  390.  SetCursor(1);
  391. /*
  392. ** allocate one block to 'output' to begin with
  393. */
  394.  outputsize = FILEBUF;
  395.  output = XtMalloc(outputsize);
  396.  output[0] = '\0';
  397.  
  398.  if (! mailpid)
  399.     Bell("No current mail program connection\n");
  400.  else {
  401.     if (*cmd) {                /* allow us to be called by readMail */
  402.        if (LASTCH(cmd) != '\n')
  403.           sprintf(s, "%s\n", cmd);
  404.        else
  405.           strcpy(s, cmd);
  406.        writeMail(s);
  407.       }
  408.  
  409.     for (;;) {
  410.         if ((size = read(mail_fd, s, FILEBUF)) < 1) {    /* EOF or an error? */
  411.            if (! *output) {
  412.               strcpy(output, "No current mail service connection\n");
  413.               if (mailpid) {
  414.                  XtRemoveInput(mailInputId);
  415.                  close(mail_fd);
  416.                  mailpid = 0;
  417.                 }
  418.              }
  419.            break;
  420.           }
  421.  
  422.         if (size < FILEBUF)
  423.            s[size] = '\0';
  424.  
  425.         if (strlen(output) + size > outputsize) {
  426.            outputsize += FILEBUF;
  427.            temp = XtRealloc(output, outputsize);
  428.            output = temp;
  429.           }
  430.         strcat(output, s);
  431.  
  432.         j = strlen(output) - length;    /* no accidents allowed here */
  433.         if (j < 0) j = 0;        /* no references before zero */
  434.         if (strcmp(&output[j], MailPrompt) == 0) {
  435.            output[j] = '\0';        /* Drop prompt from end of text */
  436.            break;            /* and return from read routine */
  437.           }
  438.  
  439.         if (!strcmp(Command,"Start")) {    /* see if somehow missed the prompt */
  440.            j = strlen(output) - 3;    /* no accidents allowed here either */
  441.            if (j < 0) j = 0;        /* no string references before zero */
  442.            if (strcmp(&output[j], "\n& ") == 0) { /* if default mail prompt */
  443.               output[++j] = '\0';    /* drop prompt from end of string */
  444.               XtFree(MailPrompt);    /* intended prompt is now bogus */
  445.               MailPrompt = XtNewString("& ");    /* reset the mail prompt */
  446.               break;            /* and return from read routine */
  447.              }
  448.           }
  449.  
  450.         if (O_BELL == match(output_pattern,output) && !strcmp(Command,"Start"))
  451.            break;
  452.        }
  453.  
  454.     if (*cmd) 
  455.        LASTCH(output) = '\0';        /* drop newline for normal queries */
  456.    }
  457.  
  458.  temp = XtRealloc(output, strlen(output) + 1);
  459.  output = temp;
  460.  
  461.  SetCursor(0);
  462.  
  463.  return(output);
  464. } /* QueryMail */
  465.