home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume15 / xmail / part05 / callbacks.c next >
C/C++ Source or Header  |  1991-10-29  |  47KB  |  1,359 lines

  1. /*
  2.  * xmail - X window system interface to the mail program
  3.  *
  4.  * Copyright 1990,1991 by National Semiconductor Corporation
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of National Semiconductor Corporation not
  11.  * be used in advertising or publicity pertaining to distribution of the
  12.  * software without specific, written prior permission.
  13.  *
  14.  * NATIONAL SEMICONDUCTOR CORPORATION MAKES NO REPRESENTATIONS ABOUT THE
  15.  * SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS"
  16.  * WITHOUT EXPRESS OR IMPLIED WARRANTY.  NATIONAL SEMICONDUCTOR CORPORATION
  17.  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
  18.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO
  19.  * EVENT SHALL NATIONAL SEMICONDUCTOR CORPORATION BE LIABLE FOR ANY SPECIAL,
  20.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  21.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  22.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  23.  * PERFORMANCE OF THIS SOFTWARE.
  24.  *
  25.  * Author:  Michael C. Wagnitz - National Semiconductor Corporation
  26.  *
  27.  */
  28.  
  29.  
  30. #include "global.h"
  31. #include "xmailregexp.h"
  32. #include <sys/wait.h>
  33. #include <sys/stat.h>
  34. #include <sys/types.h>
  35. #include <signal.h>
  36. #include <errno.h>
  37. #include <pwd.h>
  38.  
  39. #ifdef vms
  40. extern int    noshare errno;
  41. extern int    noshare sys_nerr;
  42. extern char    noshare *sys_errlist[];
  43. #else
  44. extern int    errno;
  45. extern int    sys_nerr;
  46. extern char    *sys_errlist[];
  47. #endif
  48.  
  49. extern    char    otherBuf[BUFSIZ];
  50.  
  51. /*
  52. ** @(#)Autograph() - Add user's Sign or sign autograph to outgoing mail
  53. **                   Then make button insensitive, to prevent multiple calls.
  54. **                   If requested autograph signature does not exist, tell user.
  55. */
  56. /* ARGSUSED */
  57. XtCallbackProc
  58. Autograph(w, C, call_data)
  59. Widget    w;
  60. caddr_t    C;
  61. caddr_t    call_data;        /* unused */
  62. {
  63.  FILE        *fp;
  64.  struct stat    st_buf;
  65.  char        tmp[BUFSIZ];
  66.  char        *autograph, *getenv();
  67.  int        n;
  68.  
  69.  
  70.  (void) strcpy(tmp, "Sign");    /* Default action is to use Sign autograph */
  71.  if (*C == 'a') tmp[0] = 's';
  72.  autograph = GetMailEnv(tmp);    /* First, see if an autograph exists */
  73.  
  74.  if (! autograph) {
  75.     /*
  76.     ** If no Sign or sign, see if the user has created a .signature file
  77.     */
  78.     st_buf.st_size = 0;
  79.     (void) sprintf(tmp, "%s/.Signature", getenv("HOME"));
  80.     if (*C == 'a')
  81.        (void) sprintf(tmp, "%s/.signature", getenv("HOME"));
  82.     if (stat(tmp, &st_buf) != -1 &&
  83.         st_buf.st_size < BUFSIZ &&
  84.        (fp = fopen(tmp, "r")) != NULL) {
  85.        autograph = XtMalloc((unsigned) st_buf.st_size + 1);
  86.        n = fread(autograph, sizeof(char), (int) st_buf.st_size, fp);
  87.        autograph[n] = '\0';
  88.        (void) fclose(fp);
  89.       } else {
  90.        (void) strcpy(tmp, "Cannot find a 'Sign'ature to append\n");
  91.        if (*C == 'a') tmp[15] = 's';
  92.        if (st_buf.st_size) {
  93.           (void) sprintf(tmp,"Cannot append your .Signature (exceeds %d characters)\n",
  94.                  BUFSIZ - 1);
  95.           if (*C == 'a') tmp[20] = 's';
  96.          }
  97.        Bell(tmp);
  98.        return;
  99.       }
  100.    }
  101.  
  102.  XtSetSensitive(w, False);    /* Don't let us be pressed more than once */
  103.  if (*C == 'A')            /* also make other sign button inoperative */
  104.     XtSetSensitive(XtNameToWidget(XtParent(w), "autograph"), False);
  105.  else                /* if this was a request for lowercase sign */
  106.     XtSetSensitive(XtNameToWidget(XtParent(w), "Autograph"), False);
  107.  
  108.  for (n = 0; n < BUFSIZ - 1 && *autograph; autograph++)
  109.      if (*autograph == '\\' && *(autograph + 1) == 'n') {
  110.         tmp[n++] = '\n';    /* Replace newline strings with a character */
  111.         autograph++;
  112.        } else tmp[n++] = *autograph;
  113.  
  114.  if (tmp[n - 1] != '\n')    /* make sure msg ends with a newline */
  115.     tmp[n++] = '\n';
  116.  tmp[n] = '\0';
  117.  
  118.  if ((fp = fopen(tmpName, "a")) != NULL) {
  119.     (void) fwrite(tmp, sizeof(* tmp), strlen(tmp), fp);
  120.     (void) fclose(fp);
  121.    }
  122.  XtFree(autograph);
  123. } /* Autograph */
  124.  
  125.  
  126. /*
  127. ** @(#)endDelivery() - catch the signal when the delivery child finishes
  128. */
  129. int
  130. endDelivery(signum)
  131. int    signum;
  132. {
  133.  int    status;
  134.  
  135.  
  136.  if (signum != SIGCHLD)
  137.     return 1;
  138.  
  139.  if (mailpid == wait(&status))
  140.     return 1;                /* in case mail child was what died */
  141.  
  142.  (void) signal(SIGCHLD, SIG_DFL);    /* turn off the endDelivery hook */
  143.  
  144.  return 1;
  145. } /* endDelivery */
  146.  
  147.  
  148. /*
  149. ** @(#)Done() - Send composed message - if closure data says "Deliver"
  150. */
  151. /* ARGSUSED */
  152. XtCallbackProc
  153. Done(w, closure, call_data)
  154. Widget w;
  155. caddr_t closure;
  156. caddr_t call_data;
  157. {
  158.  Arg        args[1];
  159.  FILE        *fp, *xf, *popen();
  160.  String        m, p, q, record, folder;
  161.  Widget        shell;
  162.  char        *getenv(), *strchr();
  163.  char        From[BUFSIZ], Copy[BUFSIZ], tmp[BUFSIZ], addressees[BUFSIZ];
  164.  char        To[BUFSIZ], Subject[BUFSIZ], Cc[BUFSIZ], Bcc[BUFSIZ];
  165.  long        clock;
  166.  int        n, len;
  167. #ifdef X_FACE
  168.  int        faces_sendmail = 0;    /* Are we using faces.sendmail script */
  169. #endif
  170.  struct stat    st_buf;
  171.  
  172.  
  173.  Bell(Default_Status_Info);
  174.  
  175.  shell = XtNameToWidget(toplevel, "topBox.commandPanel.Send.popup");
  176.  if (! shell) return;            /* SOMEthing would be VERY wrong here */
  177.  
  178.  XtPopdown(shell);            /* remove from use but don't destroy */
  179. /*
  180. ** Restore the sensitivity of the Autograph, Send, and reply buttons
  181. */
  182.  XtSetSensitive(XtNameToWidget(XtParent(w), "Autograph"), True);
  183.  XtSetSensitive(XtNameToWidget(XtParent(w), "autograph"), True);
  184.  XtSetSensitive(XtNameToWidget(toplevel, "topBox.commandPanel.Send"), True);
  185.  XtSetSensitive(XtNameToWidget(toplevel, "topBox.commandPanel.reply"), True);
  186.  
  187.  st_buf.st_size = 0;            /* (in case msg file does not exist) */
  188.  (void) stat(tmpName, &st_buf);
  189.  
  190.  if (strcmp(closure, "Deliver") != 0) {
  191.     n = st_buf.st_size;        /* the number of bytes in the message text */
  192.     if (n == 0 && *closure == 'c')
  193.        Bell("No text to save in your dead letter file\n");
  194.     else {
  195.        if (n && (*closure == 'c' || ! Confirm("REALLY discard this text"))) {
  196.           if ((record = GetMailEnv("DEAD")) == NULL)
  197.              (void) sprintf(Copy, "%s/dead.letter", getenv("HOME"));
  198.           else {
  199.              if (*record != '~')
  200.                 (void) strcpy(Copy, record);    /* take whatever is given */
  201.              else {
  202.                 if (*(record+1) == '/')
  203.                    (void) sprintf(Copy, "%s/%s", getenv("HOME"), &record[1]);
  204.                 else {
  205.                    struct passwd *pw;
  206.  
  207.                    for (len = 0, n = 1; record[n] && record[n] != '/';)
  208.                        tmp[len++] = record[n++];
  209.                    tmp[len] = '\0';
  210.  
  211.                    if (pw = getpwnam(tmp))
  212.                       (void) sprintf(Copy, "%s%s", pw->pw_dir, &record[n]);
  213.                    else (void) strcpy(Copy, record);
  214.                   }
  215.                }
  216.              XtFree(record);
  217.             }
  218.           st_buf.st_size = -1;        /* see if our target exists */
  219.           (void) stat(Copy, &st_buf);
  220.           if (fp = fopen(Copy, "a")) {
  221.              xf = fopen(tmpName, "r");
  222.              while (fgets(tmp, BUFSIZ, xf) != NULL) {
  223.                    if (strncmp(tmp, "From ", 5) == 0) (void) fprintf(fp, ">");
  224.                    (void) fprintf(fp, "%s", tmp);
  225.                   }
  226.              (void) fclose(xf);
  227.              if (*tmp != '\n')
  228.                 (void) fprintf(fp, "\n");
  229.              (void) fclose(fp);
  230.  
  231.              (void) sprintf(tmp, "\"%s\" [%s] (%d bytes)\n", Copy,
  232.                  (st_buf.st_size >= 0) ? "Appended" : "New file", n);
  233.              Bell(tmp);
  234.             } else {
  235.              (void) sprintf(tmp, "Could not write file %s - %s\n", Copy,
  236.                     (errno < sys_nerr)? sys_errlist[errno] : "Unknown error");
  237.              Bell(tmp); 
  238.             }
  239.          }
  240.       }                    /* end - if some message text exists */
  241.     (void) unlink(tmpName);        /* remove the message text file */
  242.    } else {                /* Deliver this message text */
  243.     /*
  244.     ** Call the alias() routine recursively, to de-alias the user's To:, Cc:,
  245.     ** and Bcc: fields.
  246.     */
  247.     To[0] = Subject[0] = Cc[0] = Bcc[0] = otherBuf[0] = '\0';
  248.     /*
  249.     ** Retrieve current values from the header buffers
  250.     */
  251.     XtSetArg(args[0], XtNstring, &m);
  252.     XtGetValues(XtNameToWidget(shell, "*SubjCc*To"), args, 1);
  253.     if (*m) {
  254.        (void) strcpy(addressees, m);
  255.        /*
  256.        ** alias() adds filenames to a list and returns just user addresses
  257.        ** (it also automatically wraps long header lines)
  258.        */
  259.        for (p = alias(addressees); strcmp(p, addressees); p = alias(addressees))
  260.            (void) strcpy(addressees, p);
  261.        (void) strcpy(To, addressees);
  262.       }
  263.     
  264.     XtSetArg(args[0], XtNstring, &m);
  265.     XtGetValues(XtNameToWidget(shell, "*SubjCc*Subject"), args, 1);
  266.  
  267.     if (! *addressees || (! *m && st_buf.st_size == 0)) {
  268.        if (! *addressees)
  269.           Bell("No recipient specified\n"); 
  270.        else
  271.           Bell("No subject and no message body\n"); 
  272.       } else {            /* if there is a message to be delivered... */
  273.        (void) strcpy(Subject, m);
  274.     
  275.        XtSetArg(args[0], XtNstring, &m);
  276.        XtGetValues(XtNameToWidget(shell, "*SubjCc*Cc"), args, 1);
  277.        if (*m) {
  278.           (void) strcpy(tmp, m);
  279.           for (p = alias(tmp); strcmp(p, tmp); p = alias(tmp))
  280.               (void) strcpy(tmp, p);
  281.  
  282.           if (*p) {
  283.              (void) strcat(addressees, ", ");
  284.              (void) strcat(addressees, p);
  285.              (void) strcpy(Cc, p);
  286.             }
  287.          }
  288.  
  289.        XtSetArg(args[0], XtNstring, &m);
  290.        XtGetValues(XtNameToWidget(shell, "*SubjCc*Bcc"), args, 1);
  291.     
  292.        if (*m) {
  293.           (void) strcpy(tmp, m);
  294.           for (p = alias(tmp); strcmp(p, tmp); p = alias(tmp))
  295.               (void) strcpy(tmp, p);
  296.  
  297.           if (*p) {
  298.              (void) strcat(addressees, ", ");
  299.              (void) strcat(addressees, p);
  300.              (void) strcpy(Bcc, p);
  301.             }
  302.          }
  303.        /*
  304.        ** To avoid a bug in Sun's sendmail (for occasionally not being able to
  305.        ** find the name of the real author of the message), strip commas from
  306.        ** the address list and pass the recipient names to sendmail on the
  307.        ** command line, ala Mail.  Also, strip all but the actual address from
  308.        ** any compound addresses present in the list.
  309.        */
  310.        for (q = addressees; *q; q++) {
  311.            if (*q == ',') {        /* remove any commas */
  312.               if (q[1] == ' ')        /* if comma is followed by a space */
  313.                  bcopy(&q[1], q, strlen(q));        /* then shift left */
  314.               else *q = ' ';        /* else substitute space for comma */
  315.               q++;
  316.              }
  317.            if (*q == '\n') {        /* remove the newline tab from this */
  318.               bcopy(&q[2], q, strlen(q) - 1);
  319.              }
  320.            if (p = strchr(q, ',')) {    /* find the end of next alias in list */
  321.               n = (int) (p - q);
  322.               bzero(tmp, n + 1);
  323.               bcopy(q, tmp, n);        /* shorten our search to just this */
  324.               if ((m = strchr(tmp, '<')) || (m = strchr(tmp, '('))) {
  325.                  if (*m == '<') {    /* if its a chevroned address type */
  326.                     if (! sscanf(tmp, "%*[^<]<%[^>]>", Copy))
  327.                          (void) sscanf(tmp, "<%[^>]>", Copy);
  328.                     bcopy(Copy, q, strlen(Copy));    /* stuff address only */
  329.                     m = q + strlen(Copy);
  330.                     bcopy(p, m, strlen(p) + 1);    /* shift rest of addressees */
  331.                     if (q = strchr(q, ',')) q--;
  332.                    } else {        /* must be a parenthetical style */
  333.                     for (n = 0; tmp[n] && strchr(" \n\t", tmp[n]); n++);
  334.                     if (1 == sscanf(&tmp[n], "%*[^)]) %s", Copy)) {
  335.                        bcopy(Copy, q, strlen(Copy));
  336.                        m = q + strlen(Copy);
  337.                        bcopy(p, m, strlen(p) + 1);
  338.                        if (q = strchr(q, ',')) q--;
  339.                       } else {
  340.                        (void) sscanf(&tmp[n], "%s", Copy);    /* address preceeds */
  341.                        m = q + strlen(Copy);
  342.                        bcopy(p, m, strlen(p) + 1);
  343.                        if (q = strchr(q, ',')) q--;
  344.                       }
  345.                    }
  346.                 } else q = p - 1;    /* skip to alias end if not compound */
  347.              } else {            /* last (or only) alias in the list */
  348.               if ((m = strchr(q, '<')) || (m = strchr(q, '('))) {
  349.                  if (*m == '<') {
  350.                     if (! sscanf(q, "%*[^<]<%[^>]>", Copy))
  351.                          (void) sscanf(q, "<%[^>]>", Copy);
  352.                     bcopy(Copy, q, strlen(Copy) + 1);
  353.                    } else {
  354.                     for (p = q; strchr(" \n\t", *p); p++);
  355.                     if (1 == sscanf(p, "%*[^)]) %s", Copy)) {
  356.                        bcopy(Copy, q, strlen(Copy) + 1);
  357.                       } else {
  358.                        (void) sscanf(p, "%s", Copy);
  359.                        p[strlen(Copy) + 1] = '\0';
  360.                       }
  361.                    }
  362.                 }
  363.               break;            /* no more commas to be replaced */
  364.              }
  365.           }
  366.  
  367.        if ((p = GetMailEnv("sendmail")) == NULL)
  368.             p = XtNewString("/usr/lib/sendmail");
  369. #ifdef X_FACE
  370.        else {
  371.           faces_sendmail = (strcmp(&p[strlen(p) - 14], "faces.sendmail") == 0);
  372.          }
  373. #endif
  374.        /*
  375.        ** The following arguments are passed to the sendmail command:
  376.        **
  377.        ** -oi    don't accept a dot on a line by itself as message termination
  378.        **
  379.        ** -om    send to "me" too, if I am a member of an alias expansion
  380.        */
  381.        (void) sprintf(tmp, "%s -oi -om %s\n", p, addressees);
  382.        XtFree(p);
  383.  
  384.        p      = GetMailEnv("outfolder");
  385.        folder = GetMailEnv("folder");
  386.        record = GetMailEnv("record");
  387.        m      = getenv("HOME");
  388.        /*
  389.        ** Fork a child process to effect the message delivery functions.
  390.        */
  391.        if ((n = fork()) != 0) {            /* if we are not the child */
  392.           if (n == -1) {            /* delivery fork failed ... */
  393.              if (errno == ENOMEM)
  394.                 Bell("Not enough core for message delivery child\n");
  395.              else
  396.                 Bell("No more processes - no message delivery!?!\n");
  397.             } else                /* parent sets delivery hook */
  398.              (void) signal(SIGCHLD, endDelivery);
  399.  
  400.           XtFree(p);
  401.           XtFree(record);
  402.           XtFree(folder);
  403.           return;
  404.          }
  405.        /*
  406.        ** Use this child process to effect the message delivery functions.
  407.        **
  408.        ** First, mail the header information and message text (in temporary
  409.        ** file) using sendmail.
  410.        */
  411.        if (fp = popen(tmp, "w")) {
  412.           /*
  413.           ** First, write the header information.
  414.           */
  415.           if (*To)      (void) fprintf(fp, "To: %s\n", To);
  416.           if (*Subject) (void) fprintf(fp, "Subject: %s\n", Subject);
  417.           if (*InReply) (void) fprintf(fp, "%s\n", InReply);
  418.           if (*Cc)      (void) fprintf(fp, "Cc: %s\n", Cc);
  419.           if (*Bcc)     (void) fprintf(fp, "Bcc: %s\n", Bcc);
  420. #ifdef X_FACE
  421.           /*
  422.           ** Look for, and add contents of, user's ~/.face file unless
  423.           ** user is already invoking the faces.sendmail script, which
  424.           ** does the job itself.  In that case, don't add info here.
  425.           ** To accomodate both cases, look for and add header if none. 
  426.           */
  427.           if (! faces_sendmail) {
  428.              (void) sprintf(tmp, "%s/.face", m);
  429.              if (xf = fopen(tmp, "r")) {
  430.                 n = 1;
  431.                 while (fgets(tmp, BUFSIZ, xf) != NULL) {
  432.                       if (n) {
  433.                          n = 0;
  434.                          if (strncmp(tmp, "X-Face:", 7) != 0)
  435.                               (void) fprintf(fp, "X-Face:");
  436.                         }
  437.                       (void) fprintf(fp, "%s", tmp);
  438.                      }
  439.                 (void) fclose(xf);
  440.                }
  441.             }
  442. #endif X_FACE
  443.           (void) fprintf(fp, "\n");    /* separate the header from any text */
  444.           /*
  445.           ** Now write message text (if any) to the sendmail process.  ANY
  446.           ** line which begins with the keyword ``From '' gets prepended
  447.           ** with a greater than (>) symbol.
  448.           */
  449.  
  450.           if (st_buf.st_size) {
  451.              xf = fopen(tmpName, "r");
  452.              while (fgets(tmp, BUFSIZ, xf) != NULL) {
  453.                    if (strncmp(tmp, "From ", 5) == 0) (void) fprintf(fp, ">");
  454.                    (void) fprintf(fp, "%s", tmp);
  455.                   }
  456.              (void) fclose(xf);
  457.              if (*tmp != '\n')
  458.                 (void) fprintf(fp, "\n");    /* ensure last line is blank */
  459.             }
  460.           (void) pclose(fp);
  461.          } else {
  462.           /*
  463.           ** We can't use the Bell routine, because we are a child process
  464.           */
  465.           XtWarning("Could not establish connections with sendmail daemon"); 
  466.          }
  467.  
  468.        (void) time(&clock);
  469.        (void) sprintf(From, "From %s %24.24s\n", getenv("USER"), ctime(&clock));
  470.        /*
  471.        ** If user has set ``record'' in their .mailrc, add a message copy to
  472.        ** that file.  Try to faithfully follow the description of the
  473.        ** ``outfolder'' variable, even if Berkeley Mail doesn't appear to do so.
  474.        ** To whit, if ``outfolder'' is set, "locate files used to record
  475.        ** outgoing messages (the record variable, for one) in the directory
  476.        ** specified by the folder variable, unless the pathname is absolute."
  477.        ** (Quoted from Mail man page description of the outfolder variable.) 
  478.        ** Consider both absolute and relative addressing (i.e. /* and ./*)
  479.        ** Also accomodate tilde address values ~/ and ~username/.
  480.        */
  481.        if (record) {
  482.           if (*record != '+' &&
  483.              (*record == '/' || (*record == '.' && *(record+1) == '/') ||
  484.              p == NULL || folder == NULL)) {
  485.              (void) strcpy(Copy, record);
  486.             } else {
  487.              if (*record == '~') {
  488.                 if (*(record+1) == '/')
  489.                    (void) sprintf(Copy, "%s/%s", m, &record[1]);
  490.                 else {
  491.                    struct passwd *pw;
  492.  
  493.                    for (len = 0, n = 1; record[n] && record[n] != '/';)
  494.                        tmp[len++] = record[n++];
  495.                    tmp[len] = '\0';
  496.  
  497.                    if (pw = getpwnam(tmp))
  498.                       (void) sprintf(Copy, "%s%s", pw->pw_dir, &record[n]);
  499.                    else (void) strcpy(Copy, record);
  500.                   }
  501.                } else {
  502.                 if (*folder == '/')
  503.                    (void) sprintf(Copy, "%s/%s", folder,
  504.                         (*record == '+') ? &record[1] : record);
  505.                 else
  506.                    (void) sprintf(Copy, "%s/%s/%s", m, folder,
  507.                         (*record == '+') ? &record[1] : record);
  508.                }
  509.             }
  510.           XtFree(record);
  511.  
  512.           if (fp = fopen(Copy, "a")) {
  513.              (void) fprintf(fp, From);
  514.              if (*To)      (void) fprintf(fp, "To: %s\n", To);
  515.              if (*Subject) (void) fprintf(fp, "Subject: %s\n", Subject);
  516.              if (*InReply) (void) fprintf(fp, "%s\n", InReply);
  517.              if (*Cc)      (void) fprintf(fp, "Cc: %s\n", Cc);
  518.              if (*Bcc)     (void) fprintf(fp, "Bcc: %s\n", Bcc);
  519. #ifdef X_FACE
  520.              if (! faces_sendmail) {
  521.                 (void) sprintf(tmp, "%s/.face", m);
  522.                 if (xf = fopen(tmp, "r")) {
  523.                    n = 1;
  524.                    while (fgets(tmp, BUFSIZ, xf) != NULL) {
  525.                          if (n) {
  526.                             n = 0;
  527.                             if (strncmp(tmp, "X-Face:", 7) != 0)
  528.                                  (void) fprintf(fp, "X-Face:");
  529.                            }
  530.                          (void) fprintf(fp, "%s", tmp);
  531.                         }
  532.                    (void) fclose(xf);
  533.                   }
  534.                }
  535. #endif X_FACE
  536.              (void) fprintf(fp, "\n");
  537.              if (st_buf.st_size) {
  538.                 xf = fopen(tmpName, "r");
  539.                 while (fgets(tmp, BUFSIZ, xf) != NULL) {
  540.                       if (strncmp(tmp, "From ", 5) == 0) (void) fprintf(fp, ">");
  541.                       (void) fprintf(fp, "%s", tmp);
  542.                      }
  543.                 (void) fclose(xf);
  544.                 if (*tmp != '\n')
  545.                    (void) fprintf(fp, "\n");
  546.                }
  547.              (void) fclose(fp);
  548.             } else {
  549.              (void) sprintf(tmp, "Could not write file %s - %s\n", Copy,
  550.                     (errno < sys_nerr)? sys_errlist[errno] : "Unknown error");
  551.              /*
  552.              ** Can't use the Bell routine internally, because we are a child
  553.              */
  554.              XtWarning(tmp); 
  555.             }
  556.          }            /* end - if record variable is set */
  557.        /*
  558.        ** If other addresses exist, add copies to those files and or folders
  559.        */
  560.        if (*otherBuf) {
  561.           for (record = otherBuf; *record;) {
  562.               for (q = record; *q && *q != ','; q++);
  563.               n = 0;
  564.               if (*q == ',') {
  565.                  *q = '\0';
  566.                  n = 1;
  567.                 }
  568.               if (*record != '+' && 
  569.                  (*record == '/' || (*record == '.' && *(record+1) == '/') ||
  570.                  p == NULL || folder == NULL)) {
  571.                  (void) strcpy(Copy, record);
  572.                 } else {
  573.                  if (*record == '~') {
  574.                     if (*(record+1) == '/')
  575.                        (void) sprintf(Copy, "%s/%s", m, &record[1]);
  576.                     else {
  577.                        struct passwd *pw;
  578.  
  579.                        for (len = 0, n = 1; record[n] && record[n] != '/';)
  580.                            tmp[len++] = record[n++];
  581.                        tmp[len] = '\0';
  582.  
  583.                        if (pw = getpwnam(tmp))
  584.                           (void) sprintf(Copy, "%s%s", pw->pw_dir, &record[n]);
  585.                        else (void) strcpy(Copy, record);
  586.                       }
  587.                    } else {
  588.                     if (*folder == '/')
  589.                        (void) sprintf(Copy, "%s/%s", folder,
  590.                                      (*record == '+') ? &record[1] : record);
  591.                     else
  592.                        (void) sprintf(Copy, "%s/%s/%s", m, folder,
  593.                                      (*record == '+') ? &record[1] : record);
  594.                    }
  595.                 }
  596.               if (fp = fopen(Copy, "a")) {
  597.                  (void) fprintf(fp, From);
  598.                  if (*To)      (void) fprintf(fp, "To: %s\n", To);
  599.                  if (*Subject) (void) fprintf(fp, "Subject: %s\n", Subject);
  600.                  if (*InReply) (void) fprintf(fp, "%s\n", InReply);
  601.                  if (*Cc)      (void) fprintf(fp, "Cc: %s\n", Cc);
  602.                  if (*Bcc)     (void) fprintf(fp, "Bcc: %s\n", Bcc);
  603. #ifdef X_FACE
  604.                  if (! faces_sendmail) {
  605.                     (void) sprintf(tmp, "%s/.face", m);
  606.                     if (xf = fopen(tmp, "r")) {
  607.                        n = 1;
  608.                        while (fgets(tmp, BUFSIZ, xf) != NULL) {
  609.                              if (n) {
  610.                                 n = 0;
  611.                                 if (strncmp(tmp, "X-Face:", 7) != 0)
  612.                                      (void) fprintf(fp, "X-Face:");
  613.                                }
  614.                              (void) fprintf(fp, "%s", tmp);
  615.                             }
  616.                        (void) fclose(xf);
  617.                       }
  618.                    }
  619. #endif X_FACE
  620.                  (void) fprintf(fp, "\n");
  621.                  if (st_buf.st_size) {
  622.                     xf = fopen(tmpName, "r");
  623.                     while (fgets(tmp, BUFSIZ, xf) != NULL) {
  624.                           if (strncmp(tmp, "From ", 5) == 0) (void) fprintf(fp, ">");
  625.                           (void) fprintf(fp, "%s", tmp);
  626.                          }
  627.                     (void) fclose(xf);
  628.                     if (*tmp != '\n')
  629.                        (void) fprintf(fp, "\n");
  630.                    }
  631.                  (void) fclose(fp);
  632.                 } else {
  633.                  (void) sprintf(tmp, "Could not write file %s - %s\n", Copy,
  634.                     (errno < sys_nerr)? sys_errlist[errno] : "Unknown error");
  635.                  XtWarning(tmp); 
  636.                 }        /* end - if fopen of otherBuf file succeeds */
  637.               if (n) *q++ = ',';
  638.               record = q;
  639.              }            /* end - for each record in otherBuf */
  640.           XtFree(p);
  641.           XtFree(folder);
  642.          }            /* end - if there were records in otherBuf */
  643.       }                /* end - if we wanted to deliver something */
  644.     (void) unlink(tmpName);    /* remove any message text */
  645.     exit(1);            /* this is the end of delivery child process */
  646.     /* NOTREACHED */
  647.    }
  648. } /* Done */
  649.  
  650.  
  651. /*
  652. ** @(#)DoIt() - send command - passed via client_data argument - to mail
  653. */
  654. /* ARGSUSED */
  655. XtCallbackProc
  656. DoIt(w, closure, call_data)
  657. Widget        w;
  658. caddr_t        closure;
  659. caddr_t        call_data;
  660. {
  661.  int        n;
  662.  Arg        args[1];
  663.  String        buf;
  664.  
  665.  
  666.  SetCursor(NORMAL);
  667.  (void) sprintf(Command, "%s\n", closure);
  668.  if (mailpid) {                /* If connections are okay,... */
  669.     SetCursor(WATCH);            /* will be reset by parser routine */
  670.     if ((n = match(command_pattern, Command)) != C_FILE && n != C_NEWMAIL) {
  671.        writeMail(Command);
  672.       } else {                /* check for commit of any changes */
  673.        XtSetArg(args[0], XtNlabel, &buf);
  674.        XtGetValues(XtNameToWidget(toplevel, "topBox.titleBar.title"), args, 1);
  675.  
  676.        if (strcmp(&buf[strlen(buf) - 7], "deleted") ||
  677.            strcmp(closure, "inc") == 0 ||
  678.            Confirm("COMMIT all changes to this folder")) {
  679.           writeMail(Command);
  680.          }
  681.       }
  682.    } else if (C_NEWMAIL != match(command_pattern, Command))
  683.          Bell("No current mail connection\n");        /* if not 'Newmail' */
  684.      else {
  685.          SetCursor(WATCH);        /* will be reset by parser routine */
  686.          if (mailargc > 2 && strcmp(mailargv[mailargc - 2], "-f") == 0) {
  687.             mailargc -= 2;        /* throw away any folder argument */
  688.             mailargv[mailargc] = NULL;    /* and NULL end of argument list */
  689.            }
  690.          callMail(mailargv);        /* restart the mail connections */
  691.          (void) strcpy(Command, "Start"); /* Let em know we've re-started */
  692.          UnsetNewmail(w, (caddr_t) NULL, (caddr_t) NULL);
  693.          In_Bogus_Mail_File = False;    /* reset this so titleBar will chg */
  694.         }
  695. } /* DoIt */
  696.  
  697.  
  698. /*
  699. ** @(#)DoPrint() - Call the PrintMsg action routine from a callback
  700. */
  701. /* ARGSUSED */
  702. XtCallbackProc
  703. DoPrint(w, closure, call_data)
  704. Widget    w;
  705. caddr_t closure;
  706. caddr_t    call_data;
  707. {
  708.  PrintMsg(w, NULL, NULL, NULL);
  709. } /* DoPrint */
  710.  
  711.  
  712. /*
  713. ** @(#)DoQuit() - Terminate xmail after first closing mail connection
  714. */
  715. /* ARGSUSED */
  716. XtCallbackProc
  717. DoQuit(w, closure, call_data)
  718. Widget w;
  719. caddr_t closure;
  720. caddr_t call_data;
  721. {
  722.  Arg        args[1];
  723.  String        buf;
  724.  
  725.  
  726.  if (mailpid) {                /* check for commit of any changes */
  727.     XtSetArg(args[0], XtNlabel, &buf);
  728.     XtGetValues(XtNameToWidget(toplevel, "topBox.titleBar.title"), args, 1);
  729.  
  730.     if (*closure != 'q' || strcmp(&buf[strlen(buf) - 7], "deleted") ||
  731.         Confirm("Changes in folder.  REALLY quit")) {
  732.        (void) sprintf(Command, "%s\n", closure);
  733.        writeMail(Command);
  734.       } else return;
  735.    }
  736.  
  737.  XtFree(XMail.iconGeometry);
  738.  XtFree(XMail.MFileName);
  739.  XtFree(XMail.editorCommand);
  740.  
  741.  XtDestroyWidget(toplevel);
  742.  
  743.  XCloseDisplay(XtDisplay(toplevel));
  744.  
  745.  _exit(0);
  746. } /* DoQuit */
  747.  
  748.  
  749. /*
  750. ** @(#)DoSet() - send specified set request to mail and destroy current menu.
  751. **         To accommodate those systems where mail cannot handle the
  752. **         'set no' commands, convert 'set no's to unsets.
  753. */
  754. /* ARGSUSED */
  755. XtCallbackProc
  756. DoSet(w, closure, call_data)
  757. Widget    w;
  758. caddr_t    closure;
  759. caddr_t    call_data;
  760. {
  761.  char    *c, buf[32];
  762.  
  763.  
  764.  if (! mailpid)
  765.     Bell("No current mail connection\n");
  766.  else {
  767.     SetCursor(WATCH);
  768.     c = w->core.name;
  769.     if (strlen(c) > 5 && strcmp(&c[strlen(c) - 6], "expert") == 0)
  770.        if (*c == 'n')
  771.             XMail.expert = (Boolean) 0;
  772.        else XMail.expert = (Boolean) 1;
  773.     else {
  774.        if (*c == 'n')
  775.           (void) sprintf(buf, "unset %s", &c[2]);
  776.        else
  777.           (void) sprintf(buf, "set %s", c);
  778.  
  779.        c = QueryMail(buf);
  780.        XtFree(c);
  781.       }
  782.  
  783.     XtDestroyWidget(XtParent(XtParent(w)));
  784.     SetCursor(NORMAL);
  785.    }
  786. } /* DoSet */
  787.  
  788.  
  789. /* ARGSUSED */
  790. /*
  791. ** @(#)DoWith() - send client_data command to mail with selected msg number
  792. */
  793. XtCallbackProc
  794. DoWith(w, client_data, call_data)
  795. Widget    w;
  796. caddr_t    client_data;
  797. caddr_t    call_data;
  798. {
  799.  int    num = 0;
  800.  
  801.  
  802.  if (! mailpid) Bell("No current mail connection\n");
  803.  else {
  804.     SetCursor(WATCH);
  805.     num = SelectionNumber(*client_data == 'u');
  806.  
  807.     if (num) (void) sprintf(Command, "%s %d\n", client_data, num);
  808.     else (void) sprintf(Command, "%s \n", client_data);
  809.  
  810.     writeMail(Command);
  811.    }
  812. } /* DoWith */
  813.  
  814.  
  815. /* ARGSUSED */
  816. /*
  817. ** @(#)DropIt() - callback to destroy the current folder popup list(s)
  818. */
  819. XtCallbackProc
  820. DropIt(w, client_data, call_data)
  821. Widget w;
  822. caddr_t client_data;
  823. caddr_t call_data;
  824. {
  825.  Widget    popup = XtNameToWidget(toplevel,"topBox.commandPanel.Folder.popupList");
  826.  if (popup)
  827.     XtDestroyWidget(popup);
  828.  SetCursor(NORMAL);
  829. } /* DropIt */
  830.  
  831.  
  832. /*
  833. ** @(#)GetAliasName() - retrieve alias name from button label
  834. */
  835. /* ARGSUSED */
  836. XtCallbackProc
  837. GetAliasName(w, client_data, call_data)
  838. Widget    w;
  839. caddr_t    client_data;            /* unused */
  840. caddr_t    call_data;            /* unused */
  841. {
  842.  Arg        args[1];
  843.  String        alias_name;
  844.  Widget        shell;
  845.  
  846.  
  847.  XtSetArg(args[0], XtNlabel, &alias_name);
  848.  XtGetValues(w, (ArgList) args, 1);    /* get this entry's label value */
  849.  
  850.  shell = XtParent(XtParent(w));        /* aliasList<-table<-entry */
  851.  XtPopdown(shell);
  852.  
  853.  shell = XtParent(shell);        /* (To|Cc|Bcc)<-aliasList */
  854.  
  855.  if (TextGetLastPos(shell))        /* if some alias is already in there */
  856.     writeTo(shell, ", ", APPEND);    /* add comma separator between names */
  857.  
  858.  writeTo(shell, alias_name, APPEND);
  859. } /* GetAliasName */
  860.  
  861.  
  862. /*
  863. ** @(#)GetFolderName() - retrieve full folder name from button labels
  864. */
  865. /* ARGSUSED */
  866. XtCallbackProc
  867. GetFolderName(w, client_data, call_data)
  868. Widget    w;
  869. caddr_t    client_data, call_data;
  870. {
  871.  Arg        args[1];
  872.  Cardinal    k, n, x;
  873.  String        folder_name;
  874.  Widget        shell;
  875.  char        tmp[BUFSIZ], buf[BUFSIZ];
  876.  
  877.  
  878.  XtSetArg(args[0], XtNlabel, &folder_name);
  879.  XtGetValues(w, (ArgList) args, 1);
  880.  
  881.  if (! call_data)                /* just a simple label name */
  882.     (void) sprintf(buf, "File: %s", folder_name);
  883.  else {                        /* multiple stack of names */
  884.     tmp[0] = '\0';
  885.     shell = w;
  886.     (void) sscanf(call_data, "%d", &n);        /* using the nesting depth */
  887.  
  888.     for (x = 1, k = (n * 2) + n - 1; k; k--) {
  889.         shell = shell->core.parent;        /* travel up the widget tree */
  890.         if (++x == 3) {                /* when we get to a label... */
  891.            x = 0;
  892.            (void) strcpy(buf, shell->core.name); /* stuff label name in */
  893.            (void) strcat(buf, tmp);        /* front of previous labels */
  894.            (void) strcpy(tmp, buf);        /* to build a complete path */
  895.           }
  896.        }
  897.     (void) sprintf(buf, "File: +%s%s", tmp, folder_name);
  898.    }
  899.  writeTo(XtNameToWidget(toplevel, "topBox.commandPanel.fileWindow"),
  900.          buf, REPLACE);
  901. } /* GetFolderName */
  902.  
  903.  
  904. /*
  905. ** @(#)ReEdit() - Call the editMail routine to re-edit a message
  906. */
  907. /* ARGSUSED */
  908. XtCallbackProc
  909. ReEdit(w, closure, call_data)
  910. Widget    w;
  911. caddr_t closure;
  912. caddr_t    call_data;
  913. {
  914.  Widget    Popup;
  915.  
  916.  
  917.  Popup = XtNameToWidget(toplevel, "topBox.commandPanel.Send.popup");
  918.  
  919.  if (! Popup) {
  920.     XBell(XtDisplay(toplevel), 33);
  921.     return;                /* SOMEthing must be VERY wrong here */
  922.    }
  923.  
  924.  XtPopdown(Popup);            /* pop down the send popup */
  925.  
  926.  editMail();                /* re-edit the message file */
  927.  
  928.  return;
  929. } /* ReEdit */
  930.  
  931.  
  932. /*
  933. ** @(#)Reply() - send a reply to the author of the selected message
  934. **               include its text and/or copy the other recipients, if asked.
  935. */
  936. /* ARGSUSED */
  937. XtCallbackProc
  938. Reply(w, client_data, call_data)
  939. Widget w;
  940. caddr_t client_data;
  941. caddr_t call_data;
  942. {
  943.  Widget        sb = XtNameToWidget(toplevel, "topBox.commandPanel.Send");
  944.  struct    sigvec    ovec;
  945.  String        p, q, r, old_From;
  946.  String        txt, ccList, author, subject, others, date, reference, empty;
  947.  String        Recipient, SubjBuf, CcBuf, BccBuf;
  948.  char        *us, *getlogin();
  949.  int        fd;
  950.  int        erasable = 0;
  951.  int        alwaysIgnore;
  952.  
  953.  
  954.  (void) sigvec(SIGCHLD, NULL, &ovec);
  955.  if (ovec.sv_handler != SIG_DFL) {
  956.     Bell("Still delivering your previous message.  Please try again later.\n");
  957.     return;
  958.    }
  959.  
  960.  XtSetSensitive(sb, False);    /* Don't start more than one composition */
  961.  XtSetSensitive(XtNameToWidget(toplevel, "topBox.commandPanel.reply"), False);
  962.  
  963.  txt = ccList = author = subject = others = date = reference = empty = old_From = "";
  964.  if (*client_data != 's') {
  965.     if ((fd = open(tmpName, O_WRONLY | O_CREAT, 0600)) == -1) {
  966.        Bell("xmail: Cannot open the temp file\n");
  967.        return;
  968.       }
  969.  
  970.     if (p = GetMailEnv("alwaysignore")) {
  971.        XtFree(p);
  972.        alwaysIgnore = (strchr("SRA", *client_data)) ? 1 : 0;
  973.       } else alwaysIgnore = 0;
  974.  
  975.     if (alwaysIgnore)        /* do we need to include a limited copy? */
  976.        (void) sprintf(Command, "p %d", SelectionNumber(False));
  977.     else
  978.        (void) sprintf(Command, "P %d", SelectionNumber(False));
  979.  
  980.     txt = QueryMail(Command);
  981.  
  982.     switch (*client_data) {
  983.        case 'S':
  984.             (void) write(fd, "---------- Begin Forwarded Message ----------\n", 46);
  985.             /*
  986.             ** Any lines that begin with keyword 'From ' get a leading symbol
  987.             */
  988.             for (q = r = txt; *r;) {
  989.                 for (; *r && *r != '\n'; r++);
  990.                     if (*r == '\n') {        /* For each line of text */
  991.                        *r = '\0';        /* temporarily mark off eos, */
  992.                        if (strncmp(q, "From ", 5) == 0)
  993.                           (void) write(fd, ">", 1);
  994.                        (void) write(fd, q, strlen(q));    /* this line of text, */
  995.                        (void) write(fd, "\n", 1);    /* the ending newline */
  996.                        *r = '\n';        /* and replace for later use */
  997.                        q = ++r;
  998.                       }
  999.                }
  1000.             if (*q) {                /* should never happen, but. */
  1001.                if (strncmp(q, "From ", 5) == 0)
  1002.                   (void) write(fd, ">", 1);
  1003.                (void) write(fd, q, strlen(q));    /* write last line of text */
  1004.                (void) write(fd, "\n", 1);    /* and an ending newline. */
  1005.               }
  1006.             (void) write(fd, "----------- End Forwarded Message -----------\n", 46);
  1007.             break;
  1008.        case 'R':
  1009.        case 'A':
  1010.             if ((p = GetMailEnv("indentprefix")) != NULL)
  1011.                erasable = 1;
  1012.             else
  1013.                p = "\t";
  1014.             for (q = r = txt; *r;) {
  1015.                 for (; *r && *r != '\n'; r++);
  1016.                     if (*r == '\n') {    /* For each line of insert */
  1017.                        *r = '\0';        /* temporarily mark off eos, */
  1018.                        (void) write(fd, p, strlen(p));    /* write indent prefix, */
  1019.                        (void) write(fd, q, strlen(q));    /* this line of text, */
  1020.                        (void) write(fd, "\n", 1);    /* and missing newline, */
  1021.                        *r = '\n';        /* and replace for later use */
  1022.                        q = ++r;
  1023.                       }
  1024.                }
  1025.             if (*q) {                /* should never happen, but. */
  1026.                (void) write(fd, p, strlen(p));    /* write the indent prefix, */
  1027.                (void) write(fd, q, strlen(q));    /* this last line of text, */
  1028.                (void) write(fd, "\n", 1);    /* and an ending newline. */
  1029.               }
  1030.             if (erasable)
  1031.                XtFree(p);
  1032.             break;
  1033.       } /* end - switch on client_data */
  1034.  
  1035.     (void) close(fd);
  1036. /*
  1037. ** strip author, subject, and Carbon copy information from the selected message
  1038. */
  1039.     if (alwaysIgnore) {        /* get full headers for data (top 100 lines) */
  1040.        XtFree(txt);
  1041.        txt = QueryMail("unset alwaysignore");
  1042.        XtFree(txt);
  1043.        (void) sprintf(Command, "top %d", SelectionNumber(False));
  1044.        txt = QueryMail(Command);
  1045.        p = QueryMail("set alwaysignore");
  1046.        XtFree(p);
  1047.       }
  1048.     for (p = txt; *p; p++) {
  1049.         if (strcmp(p, empty) == 0 || strncmp(p, "Status:", 7) == 0) break;
  1050.  
  1051.         if (strncmp(p, "From ", 5) == 0 ) {
  1052.            old_From = p + 5;
  1053.            for (p = old_From; *p && *p != ' ' && *p != '\n'; p++);
  1054.            if (*p) *p++ = '\0';            /* drop the date portion now */
  1055.            for (; *p && *p != '\n'; p++);    /* skip to end of this line */
  1056.           }
  1057.  
  1058.         else if (strncmp(p, "Return-Path:", 12) == 0) {
  1059.            reference = p + 13;            /* step past the header */
  1060.            for (p = reference; *p && *p != '\n'; p++);
  1061.            if (*p) *p = '\0';            /* drop the trailing newline */
  1062.           }
  1063.  
  1064.         else if (strncmp(p, "Date:", 5) == 0) {
  1065.            date = p + 6;
  1066.            for (p = date; *p && *p != '\n'; p++);
  1067.            if (*p) *p = '\0';
  1068.           }
  1069.  
  1070.         else if (strncmp(p, "From:", 5) == 0) {
  1071.            author = p + 6;
  1072.            for (p = author; *p && *p != '\n'; p++);
  1073.            while (*(p+1) && strchr(" \t", *(p+1))) {
  1074.                  *p = ' ';        /* change this newline to a space */
  1075.                  *(p+1) = ' ';        /* change possible tab to a space */
  1076.                  for (p++; *p && *p != '\n'; p++);
  1077.                 }
  1078.            if (*p) *p = '\0';
  1079.           }
  1080.  
  1081.         else if (strncmp(p, "To:", 3) == 0) {
  1082.            others = p + 4;
  1083.            for (p = others; *p && *p != '\n'; p++);
  1084.            while (*(p+1) && strchr(" \t", *(p+1))) {
  1085.                  *p = ' ';        /* change this newline to a space */
  1086.                  *(p+1) = ' ';        /* change possible tab to a space */
  1087.                  for (p++; *p && *p != '\n'; p++);
  1088.                 }
  1089.            if (*p) *p = '\0';
  1090.           }
  1091.  
  1092.         else if (strncmp(p, "Subject:", 8) == 0) {
  1093.            subject = p + 9;
  1094.            for (p = subject; *p && *p != '\n'; p++);
  1095.            while (*(p+1) && strchr(" \t", *(p+1))) {
  1096.                  *p = ' ';        /* change this newline to a space */
  1097.                  *(p+1) = ' ';        /* change possible tab to a space */
  1098.                  for (p++; *p && *p != '\n'; p++);
  1099.                 }
  1100.            if (*p) *p = '\0';
  1101.           }
  1102.  
  1103.         else if (strncmp(p, "Cc:", 3) == 0) {
  1104.            ccList = p + 4;
  1105.            for (p = ccList; *p && *p != '\n'; p++);
  1106.            while (*(p+1) && strchr(" \t", *(p+1))) {
  1107.                  *p = ' ';        /* change this newline to a space */
  1108.                  *(p+1) = ' ';        /* change possible tab to a space */
  1109.                  for (p++; *p && *p != '\n'; p++);
  1110.                 }
  1111.            if (*p) *p = '\0';
  1112.           }
  1113.         else for (; *p && *p != '\n'; p++);
  1114.        } /* end - for all of message body */
  1115.  
  1116.     if (*client_data != 'a' && *client_data != 'A') {
  1117.        ccList = empty;    /* If not [rR]eplyall, make sender enter any Cc: */
  1118.        others = empty;
  1119.       } else {        /* otherwise, remove ourself from the others list */
  1120.        us = getlogin();
  1121.        if (! us) {
  1122.           struct passwd *pw = getpwuid(getuid());
  1123.  
  1124.           if (pw)
  1125.              us = pw->pw_name;
  1126.          }
  1127.        for (p = others; *us && *p; p++) {
  1128.            if (strncmp(p, us, strlen(us)) == 0) {
  1129.               for (us = p + strlen(us); *us && *us != ',' && *us != ' ';) us++;
  1130.               for (; *us && (*us == ',' || *us == ' ');) us++;
  1131.               for (; *us;) *p++ = *us++;
  1132.               *p = '\0';
  1133.               break;
  1134.              }
  1135.            while (*p && *p != ',' && *p != ' ') p++;
  1136.            while (*p && (*p == ',' || *p == ' ')) p++;
  1137.            p--;
  1138.           }
  1139.       }
  1140.    } /* end - if client_data does not equal 's' */
  1141.  
  1142.  Recipient = SubjBuf = CcBuf = BccBuf = NULL;
  1143.  InReply[0] = '\0';
  1144. /*
  1145. ** If message did not have a 'From:', use 'Return-Path:' for reply recipient.
  1146. ** If message also did not have a 'Return-Path', use the older style 'From '.
  1147. */
  1148.  if (*client_data != 'S' && *client_data != 's') {
  1149.     if (! *author && *reference) 
  1150.        author = reference;
  1151.     if (! *author && *old_From)
  1152.        author = old_From;
  1153.     Recipient = XtNewString(author);
  1154. /*
  1155. ** If author's name consists of a compound address (i.e. name <address>,
  1156. ** (Name) address, or equivalents...) strip off the real address portion
  1157. ** (i.e. that portion not in parens, but possibly between chevrons).
  1158. */
  1159.     if ((p = strchr(Recipient, '(')) || (p = strchr(Recipient, '<')))
  1160.        switch (*p) {
  1161.           case '(': q = strchr(p, ')');        /* skipping past the parens */
  1162.                     if (p == Recipient) {    /* '(Name) address' format */
  1163.                        for (q++; *q && (*q == ' ' || *q == '\t'); q++);
  1164.                        bcopy(p, Recipient, strlen(p) + 1);
  1165.                       } else {            /* 'address (Name)' format */
  1166.                        for (; (p-1) > Recipient &&
  1167.                             (*(p-1) == ' ' || *(p-1) == '\t'); p--);
  1168.                        *p = '\0';
  1169.                       }
  1170.                     break;
  1171.  
  1172.           case '<': q = strchr(p++, '>');
  1173.                     *q = '\0';    /* '<address> Name' or 'Name <address>' */
  1174.                     bcopy(p, Recipient, strlen(p) + 1);
  1175.                     break;
  1176.          }
  1177. /*
  1178. ** If the user wishes to include all recipients of the original
  1179. ** message in this message, include those others in the address.
  1180. */
  1181.     if (*others && (*client_data == 'a' || *client_data == 'A')) {
  1182.        p = XtRealloc(Recipient, strlen(Recipient) + strlen(others) + 3);
  1183.        Recipient = p;
  1184.        if (LASTCH(Recipient) && LASTCH(Recipient) != ',')
  1185.           (void) strcat(Recipient, ", ");
  1186.        (void) strcat(Recipient, others);
  1187.        for (p = Recipient + strlen(Recipient) - 1; *p == ' ' || *p == ','; p--);
  1188.        *++p = '\0';            /* drop any trailing ", " garbage */
  1189.       }
  1190.    }
  1191.  
  1192.  if (*client_data != 's' && *author && *date) {
  1193.     r = (*client_data == 'S') ? "Forwarding" : "In-Reply-To";
  1194.     (void) sprintf(InReply, "%s: Mail from '%s'\n      dated: %s", r, author, date);
  1195.    }
  1196.  
  1197.  if (*subject) {
  1198.     SubjBuf = XtMalloc((unsigned) strlen(subject) + 5);
  1199.     if (strncmp(subject, "Re:", 3) != 0 &&
  1200.         strncmp(subject, "Re;", 3) != 0 &&
  1201.         strncmp(subject, "RE:", 3) != 0 &&
  1202.         strncmp(subject, "RE;", 3) != 0 &&
  1203.         strncmp(subject, "re:", 3) != 0 &&
  1204.         strncmp(subject, "re;", 3) != 0)
  1205.        (void) strcpy(SubjBuf, "Re: ");
  1206.     (void) strcat(SubjBuf, subject);
  1207.    }
  1208.  
  1209.  CcBuf = XtNewString(ccList);
  1210.  
  1211.  XtFree(txt);
  1212.  
  1213.  sendMail(sb);
  1214.  
  1215.  if (! Recipient)
  1216.     writeTo(XtNameToWidget(sb, "*To"), "", REPLACE);
  1217.  else {
  1218.     writeTo(XtNameToWidget(sb, "*To"), Recipient, REPLACE);
  1219.     XtFree(Recipient);
  1220.    }
  1221.  
  1222.  if (! SubjBuf)
  1223.     writeTo(XtNameToWidget(sb, "*Subject"), "", REPLACE);
  1224.  else {
  1225.     writeTo(XtNameToWidget(sb, "*Subject"), SubjBuf, REPLACE);
  1226.     XtFree(SubjBuf);
  1227.    }
  1228.  
  1229.  if (! CcBuf)
  1230.     writeTo(XtNameToWidget(sb, "*Cc"), "", REPLACE);
  1231.  else {
  1232.     writeTo(XtNameToWidget(sb, "*Cc"), CcBuf, REPLACE);
  1233.     XtFree(CcBuf);
  1234.    }
  1235.  
  1236.  if (! BccBuf)
  1237.     writeTo(XtNameToWidget(sb, "*Bcc"), "", REPLACE);
  1238.  else {
  1239.     writeTo(XtNameToWidget(sb, "*Bcc"), BccBuf, REPLACE);
  1240.     XtFree(BccBuf);
  1241.    }
  1242.  
  1243.  editMail();
  1244. } /* Reply */
  1245.  
  1246.  
  1247. /*
  1248. ** @(#)Save() - (or copy) a message to specified folder or mbox
  1249. */
  1250. /* ARGSUSED */
  1251. XtCallbackProc
  1252. Save(w, cmd, call_data)
  1253. Widget w;
  1254. caddr_t cmd;
  1255. caddr_t call_data;
  1256. {
  1257.  char        *getenv();
  1258.  Arg            args[1];
  1259.  Cardinal        num;
  1260.  String            p, q, r, FBuf;
  1261.  XawTextPosition    pos;
  1262.  Widget            fileWindow;
  1263.  
  1264.  
  1265.  if (! mailpid) Bell("No current mail connection\n");
  1266.  else {
  1267.     SetCursor(WATCH);            /* reset by parser routines */
  1268.     num = SelectionNumber(False);    /* no current message returns zero */
  1269.     if (*cmd == 'C' || *cmd == 'S' || num == 0) {
  1270.        if (num) {
  1271.           (void) sprintf(Command, "%s %d\n", cmd, num);
  1272.          } else {
  1273.           (void) sprintf(Command, "%s \n", cmd);
  1274.          }
  1275.       } else {
  1276.        fileWindow = XtNameToWidget(toplevel, "topBox.commandPanel.fileWindow");
  1277.        pos = TextGetLastPos(fileWindow);
  1278.        if (pos - StartPos > 0) {
  1279.           XtSetArg(args[0], XtNstring, &FBuf);
  1280.           XtGetValues(fileWindow, args, 1);
  1281.  
  1282.           if (FBuf[pos] != '\0') FBuf[pos] = '\0';
  1283.           p = XtNewString(&FBuf[StartPos]);
  1284.           (void) sprintf(Command, "%s %d %s\n", cmd, num, p);
  1285.           XtFree(p);
  1286.          } else {
  1287.           /*
  1288.           ** If no specified filename, use the mbox pointer.  We MUST include
  1289.           ** it here, because specifying the message number for the action
  1290.           ** would be interpreted as a filename, if we didn't append one.
  1291.           */
  1292.           if ((p = GetMailEnv("MBOX"))) {
  1293.                q = GetMailEnv("outfolder");
  1294.                r = GetMailEnv("folder");
  1295.              if (*p != '+' && (*p == '/' || (*p == '.' && *(p+1) == '/') ||
  1296.                   q == NULL || r == NULL)) {
  1297.                 (void) sprintf(Command, "%s %d %s\n", cmd, num, p);
  1298.                } else {
  1299.                 if (*r == '/')
  1300.                    (void) sprintf(Command, "%s %d %s/%s\n", cmd, num, r, (*p == '+') ? &p[1] : p);
  1301.                 else
  1302.                    (void) sprintf(Command, "%s %d %s/%s/%s\n", cmd, num,
  1303.                            getenv("HOME"), r, (*p == '+') ? &p[1] : p);
  1304.                }
  1305.              XtFree(r);
  1306.              XtFree(q);
  1307.              XtFree(p);
  1308.             }
  1309.          }
  1310.       }
  1311.     writeMail(Command);
  1312.    }
  1313. } /* Save */
  1314.  
  1315.  
  1316. /*
  1317. ** @(#)SetNewmail - Highlight Newmail button to attract user attention
  1318. */
  1319. /* ARGSUSED */
  1320. XtCallbackProc
  1321. SetNewmail(w, client_data, call_data)
  1322. Widget    w;            /* unused */
  1323. caddr_t    client_data;        /* unused */
  1324. caddr_t    call_data;        /* unused */
  1325. {
  1326.  Widget    cw;
  1327.  
  1328.  if (! Highlighted) {
  1329.     cw = XtNameToWidget(toplevel, "topBox.commandPanel.Newmail");
  1330.     XSetWindowBackgroundPixmap(XtDisplay(toplevel), XtWindow(cw), hatch);
  1331.     XtUnmapWidget(cw);
  1332.     XtMapWidget(cw);
  1333.     Highlighted = 1;
  1334.     reset_mailbox(XtNameToWidget(toplevel, "icon.mailbox"), 0);
  1335.    }
  1336. } /* SetNewmail */
  1337.  
  1338.  
  1339. /*
  1340. ** @(#)UnsetNewmail - Remove Newmail button highlighting
  1341. */
  1342. /* ARGSUSED */
  1343. XtCallbackProc
  1344. UnsetNewmail(w, client_data, call_data)
  1345. Widget    w;            /* unused */
  1346. caddr_t    client_data;        /* unused */
  1347. caddr_t    call_data;        /* unused */
  1348. {
  1349.  Widget    cw = XtNameToWidget(toplevel, "topBox.commandPanel.Newmail");
  1350.  
  1351.  if (Highlighted) {
  1352.     XSetWindowBackground(XtDisplay(toplevel), XtWindow(cw), cw->core.background_pixel);
  1353.     XtUnmapWidget(cw);
  1354.     XtMapWidget(cw);
  1355.     Highlighted = 0;
  1356.     reset_mailbox(XtNameToWidget(toplevel, "icon.mailbox"), 1);
  1357.    }
  1358. } /* UnsetNewmail */
  1359.