home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / send / s_get.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-11  |  18.3 KB  |  870 lines

  1. /*
  2. **        S _ G E T
  3. **
  4. **
  5. **    R E V I S I O N  H I S T O R Y
  6. **
  7. **    03/31/83  GWH    Split the SEND program into component parts
  8. **            This module contains getuinfo, gethead, prefix,
  9. **            getaddr, and addrcat.
  10. **
  11. **    04/15/83  DPK    Changed address format from "user at host" to
  12. **            "user@host". Also added call to getmailid() in get
  13. **            getuinfo();
  14. **
  15. **    05/20/83  GWH    Modified getuinfo() to allow a number of user-
  16. **            selectable options. These include the use of a
  17. **            ".sendrc" file on the user's home directory. With
  18. **            the use of the "rc" file the user can set such things
  19. **            default editor, local-alias-file, signature block,
  20. **            and a directory for draft files. Also included is a
  21. **            provision for keeping file copies of messages that
  22. **            are successfully copied (incomplete at this time).
  23. **
  24. **    06/22/83  GWH    Added the required code to addrcat to enable local
  25. **            alias file feature.
  26. **
  27. **    10/21/83  GWH    Fixed a bug in the alias file code (in addrcat).
  28. **            Prevents segmentation faults when loops are found
  29. **            in the alias file definitions.
  30. **
  31. **    11/16/83  DPK    Merged in DPK signature checking and Geo loop catcher
  32. **
  33. **    11/21/83  GWH    Added 'directedit' option.
  34. **
  35. **    03/18/85  DPK    Fixed usage of parsadr function so that after parsing
  36. **          VAK    we now use the components instead of original string.
  37. **
  38. */
  39.  
  40.  
  41. #include <stdio.h>
  42. #include "./s.h"
  43. #include "./s_externs.h"
  44.  
  45. extern char *getmailid();
  46. extern char *malloc();
  47. extern char *strdup();
  48. extern struct passwd *getpwuid();
  49. extern char *mktemp();
  50. extern char *index();
  51. extern char *getenv();
  52.  
  53. extern char *dfleditor;
  54. extern char *dflveditor;
  55. extern char *dflchecker;
  56.  
  57. #define END    (char *)0
  58.  
  59. struct RCOPTION rcoptions[] = {
  60.     "copyfile", COPYFILE,
  61.     "draftdir", DRAFTDIR,
  62.     "signature", SIGNATURE,
  63.     "nosignature", NOSIGNATURE,
  64.     "replyto", REPLYTO,
  65.     "aliases", ALIASES,
  66.     "subargs", SUBARGS,
  67.     "editor", EDITOR,
  68.     "veditor", VEDITOR,
  69.     "file", CFILE,
  70.     "fileonquery", QFILE,
  71.     "nofile", NOFILE,
  72.     "directedit", DIREDIT,
  73.     "checker", CHECKER,
  74.     "header", ADDHEADER,
  75.     "paging", PAGING,
  76.     END
  77. };
  78.  
  79. int picko();
  80.  
  81. struct passwd *pw;
  82. char *midp;
  83. char *d_subargs = "vm";
  84. char *drft_tmplt = "drft.XXXXXX";
  85. char linebuf[128];
  86. char tmpline[128];
  87.  
  88. struct ALIAS *als, alias_ptr;
  89. struct ALIAS *old_als;
  90. FILE *afd;
  91.  
  92. getuinfo() {
  93.     FILE *fp;
  94.     int realid, effecid;
  95.     char *av[NARGS];
  96.     char rcfilename[128];
  97.     register char *p;
  98.  
  99.     int i;
  100.  
  101.     /* build a draft file name */
  102.  
  103.     mktemp(drft_tmplt);
  104.     /* Who are we this time */
  105.  
  106.     getwho(&realid, &effecid);
  107.  
  108.     /* If nothing found return false. */
  109.  
  110.     if ((pw = getpwuid(effecid)) == NULL ||
  111.         (midp = getmailid(pw->pw_name)) == NULL)
  112.             return(FALSE);
  113.  
  114.     /* Build a name for this user */
  115. #ifdef PWNAME
  116.     if (pw->pw_gecos != NULL && *pw->pw_gecos != '\0') {
  117.         if (p = index(pw->pw_gecos, ','))
  118.             *p = '\0';
  119.         if (p = index(pw->pw_gecos, '<'))
  120.             *p = '\0';
  121.         if (p = index(pw->pw_gecos, '&')) {
  122.             /* Deal with Berkeley folly */
  123.             *p = 0;
  124.             sprintf(from, "%s%c%s%s <%s@%s>", pw->pw_gecos,
  125.                  lowtoup(pw->pw_name[0]),
  126.                  pw->pw_name+1, p+1, midp, locname);
  127.         } else
  128.             sprintf(from, "%s <%s@%s>", pw->pw_gecos, midp, locname);
  129.     } else
  130. #endif
  131.     sprintf(from, "%c%s@%s",    /* default from text */
  132.         lowtoup(midp[0]), &(midp[1]), locname);
  133.     /* Set default values for those options that need defaults */
  134.  
  135.     strcpy(editor, ((p = getenv("EDITOR")) && *p) ? p : dfleditor);
  136.     strcpy(veditor, ((p = getenv("VISUAL")) && *p) ? p : dflveditor);
  137.     strcpy(checker, dflchecker);
  138.     sprintf(linebuf, "%s/.sent", pw->pw_dir);
  139.     strcpy(copyfile, linebuf);
  140.     sprintf(drffile, "%s/%s", pw->pw_dir, drft_tmplt);
  141.     strcpy(subargs, d_subargs);
  142.     wflag = 0;
  143.     cflag = 0;
  144.     aflag = 0;
  145.     rflag = 0;
  146.     qflag = 0;
  147.     dflag = 0;
  148.     pflag = 0;
  149.  
  150.     strcpy(signature, from);
  151.  
  152.     /* Get info from the ".sendrc" file */
  153.  
  154.     sprintf(rcfilename, "%s/%s", pw->pw_dir, SENDRC);
  155.     if ((fp = fopen(rcfilename, "r")) != NULL) {
  156.         char *cp;
  157.  
  158.         /* Process info a line at a time */
  159.         while (fgets(linebuf, sizeof(linebuf), fp) != NULL) {
  160.             if (cp = index(linebuf, '\n'))
  161.                 *cp = 0;
  162.             if (sstr2arg(linebuf, NARGS, av, " \t") < 0)
  163.                 continue;
  164.             if ((i=picko(av[0])) < 0)
  165.                 continue; /* bad option */
  166.             select_o(i, av);
  167.         }    /* end of while on lines */
  168.     }    /* end of if statement on file open */
  169.  
  170.     return(TRUE);
  171. }    /* end of getuinfo routine */
  172.  
  173. /* select an option */
  174.  
  175. picko(pp)
  176. char *pp;
  177. {
  178.     struct RCOPTION *rcopt;
  179.  
  180.     rcopt = rcoptions;
  181.     while (rcopt->name != END) {
  182.         if (lexequ(rcopt->name, pp))
  183.             return(rcopt->idnum);
  184.         rcopt++;
  185.     }
  186.  
  187.     return(-1); /* no match */
  188. }
  189.  
  190. get_key(s, key, list)
  191. char *s, **key, **list;
  192. {
  193.     char tmps[512];
  194.     char *ptmps;
  195.     int len_list;
  196. /*
  197. **  This routine takes the input string s and divides it into two parts,
  198. **  the first of which consists of the first word in the original string.
  199. **  It is returned in key. The second part is a list of the remaining names.
  200. **  They are returned in the list. Malloc is used to allocate the necessary
  201. **  storage for the sublists.
  202. */
  203.  
  204.     /* throw away initial white space */
  205.  
  206.     while (*s == ' ' || *s == '\t')
  207.         *s++;
  208.  
  209.     /* get the first word. It may be terminated by spaces, tabs, commas, */
  210.     /* newlines or end-of-file                         */
  211.  
  212.     ptmps = tmps;
  213.     while (*s != ' ' && *s != '\t' && *s != ',' && *s != '\n' && 
  214.             *s != (char)EOF) {
  215.         *ptmps++ = *s++;
  216.     }
  217.     *ptmps = 0;
  218.     len_list = strlen(tmps);
  219.     if ((*key = malloc((unsigned)(len_list) + 1)) <= 0) {
  220.         perror(" SEND - GET_KEY -- MALLOC ERROR");
  221.         return(-1);
  222.     }
  223.  
  224.     strcpy(*key, tmps);
  225.  
  226.     /* and now the rest of the list */
  227.  
  228.     ptmps = s;
  229.     while (*s != '\n' && *s != (char)EOF && *s != '\0')
  230.         *s++;
  231.     *s = 0;
  232.     len_list = strlen(ptmps);
  233.     if (len_list <= 0)
  234.         return(-1);    /* no list - ERROR - ERROR */
  235.     if ((*list = malloc((unsigned)(len_list) +1)) <= 0) {
  236.         perror(" SEND GET_KEY - MALLOC ERROR");
  237.         return(-1);
  238.     }
  239.  
  240.     strcpy(*list, ptmps);
  241.     return(0);
  242. }
  243.  
  244. select_o(key, pp)
  245. int key;
  246. char **pp;
  247. {
  248.     register char *p;
  249.     char *akey, *list;
  250.     char tmpbuf[512];
  251.  
  252.     switch (key) {
  253.     case COPYFILE:
  254.         /* Pick a file to store file copies of sent messages */
  255.         strcpy(copyfile, *(++pp));
  256.         if (copyfile[0] != '/') {
  257.             strcpy(tmpline, copyfile);
  258.             sprintf(copyfile, "%s/%s", pw->pw_dir, tmpline);
  259.         }
  260.         break;
  261.  
  262.     case DRAFTDIR:
  263.         /* pickup the draft directory */
  264.         if (*(++pp) != 0)
  265.             sprintf(drffile, "%s/%s", *pp, drft_tmplt);
  266.         else
  267.             sprintf(drffile, "%s/%s", pw->pw_dir, drft_tmplt);
  268.         break;
  269.  
  270.     case SIGNATURE:
  271.         /* If he wants a signature block use it */
  272.         if (*(++pp) == 0) {
  273. #ifdef PWNAME
  274.             /* use his login name alone */
  275.             sprintf(signature, "%c%s@%s",
  276.                 lowtoup(midp[0]), &(midp[1]), locname);
  277. #else
  278.             strcpy(signature, from);    /* NO-OP ? */
  279. #endif
  280.         } else {
  281.             linebuf[0] = '\0';
  282.             while (*pp != 0) {
  283.                 strcat(linebuf, *pp);
  284.                 strcat(linebuf, " ");
  285.                 *pp++;
  286.             }
  287.             if (checksignature(linebuf) == 0) {
  288.                 strcpy(tmpline, locname);
  289.                 for(p=tmpline ; *p ; p++)
  290.                     *p = uptolow(*p);
  291.                 sprintf(signature, "%s <%s@%s>",
  292.                     linebuf, midp, tmpline);
  293.             } else {
  294.                 printf("Illegal signature, using default\n");
  295.             }
  296.         }
  297.         break;
  298.  
  299.     case NOSIGNATURE:
  300. #ifdef PWNAME
  301.         /* use his login name alone */
  302.         sprintf(signature, "%c%s@%s",
  303.             lowtoup(midp[0]), &(midp[1]), locname);
  304. #else
  305.         strcpy(signature, from);
  306. #endif
  307.         break;
  308.  
  309.     case REPLYTO:
  310.         rflag = 1;
  311.         break;
  312.  
  313.     case ALIASES:
  314.         aflag = 1;
  315.         strcpy(aliasfilename, *(++pp));
  316.         if (aliasfilename[0] != '/') {
  317.             strcpy(tmpline, aliasfilename);
  318.             sprintf(aliasfilename, "%s/%s",pw->pw_dir,tmpline);
  319.         }
  320.  
  321.         /*
  322.         **  Open the alias file and store the keys and lists
  323.         **  in core
  324.         */
  325.  
  326.         afd = fopen(aliasfilename, "r");
  327.         if (afd <= NULL) {
  328.             aflag = 0;
  329.             perror(" Can't open alias file ");
  330.             break;
  331.         }
  332.         als = &alias_ptr;
  333.         old_als = NULL;
  334.         while (1) {
  335.             if (fgets(tmpbuf, sizeof(tmpbuf), afd) != NULL) {
  336.                 get_key(tmpbuf, &akey, &list);
  337.                 if (old_als > 0) {
  338.                     if ((als = (struct ALIAS *) malloc(sizeof(alias_ptr))) <= 0) {
  339.                         perror("SEND GETUINFO - MALLOC ERROR");
  340.                         break;
  341.                     }
  342.                     old_als->next_int = als;
  343.                 }
  344.                 als->key = akey;
  345.                 als->cntr = 0;
  346.                 als->names = list;
  347.                 old_als = als;
  348.             }
  349.             else {
  350.                 old_als = NULL;
  351.                 break;
  352.             }
  353.         }
  354.         break;
  355.  
  356.     case SUBARGS:
  357.         strcpy(subargs, d_subargs);    /* Reset to default (required) */
  358.         while (*(++pp) != NULL)
  359.             strcat(subargs, *pp);
  360.         wflag = 1;
  361.         break;
  362.  
  363.     case EDITOR:
  364.         /* Default editor for use with the "e" command */
  365.         strcpy(editor, *(++pp));
  366.         break;
  367.  
  368.     case VEDITOR:
  369.         /* Default editor for use with the "v" command */
  370.         strcpy(veditor, *(++pp));
  371.         break;
  372.  
  373.     case CHECKER:
  374.         /* Default spelling checker for use with the "c" command */
  375.         strcpy(checker, *(++pp));
  376.         break;
  377.  
  378.     case DIREDIT:
  379.         dflag = 1;
  380.         if ((*(++pp) != (char *) 0) && (**pp == 'e'))
  381.             dflag = 2;
  382.         break;
  383.  
  384.     case PAGING : 
  385.         /* Turn on paging during message review */
  386.         pflag = 1;
  387.         break;
  388.  
  389.     case CFILE:
  390.         cflag = 1;
  391.         break;
  392.  
  393.     case QFILE:
  394.         qflag = 1;
  395.         /* DROP */
  396.     case NOFILE:
  397.         cflag = 0;
  398.         break;
  399.  
  400.     case ADDHEADER:
  401.         /* Add a header line to the message */
  402.         ++pp;
  403.         if (isstr(*pp))
  404.             addheader(pp[0], pp[1]);
  405.         break;
  406.  
  407.     default:
  408.         printf("GETUINFO - NO SUCH OPTION key = %d\n", key);
  409.  
  410.     } /* end of switch */
  411. }
  412.  
  413. /* Prompts for a header with print as prompt and gathers it up */
  414. gethead(print, buf, flag)
  415. char    print[];
  416. register char    *buf;
  417. int    flag;            /* print contents, if any?        */
  418. {
  419.     register int    c, n;
  420.     register int    max = S_BSIZE;
  421.     int    retval;        /* type of FLD modification        */
  422.  
  423.     if (flag && *buf)        /* print what already is there    */
  424.         printf(shrtfmt, print, buf);
  425.  
  426.     flag = TRUE;        /* always & only look at first char    */
  427.     do {
  428.         printf("%s", print);    /* prompt            */
  429.         if (*buf == '\\') {
  430.             *buf++ = ',';
  431.             *buf++ = '\n';
  432.         }
  433.         fflush(stdout);
  434.  
  435.         if (flag) {
  436.             flag = FALSE;    /* ignore first char of next lines */
  437.             switch (c = getchar()) {
  438.             case '-':    /* delete single name        */
  439.                 retval = ITMRMV;
  440.                 break;
  441.             case '#':    /* delete all contents    */
  442.                 *buf = 0;
  443.                 while (getchar() != '\n');
  444.                 return(FLDREMV);
  445.  
  446.             case '\n':    /* leave it as it is        */
  447.                 return(FLDSAME);
  448.  
  449.             case '+':    /* append to end of field    */
  450.                 retval = FLDADD;
  451.                 if (*buf != '\0') { /* if not already empty */
  452.                     /* point to end of buf */
  453.                     buf = &buf[strlen(buf)];
  454.                     /* assume it's an address field */
  455.                     *buf++ = ',';
  456.                     *buf++ = ' ';
  457.                     max -= 2;
  458.                 }
  459.                 break;
  460.  
  461.             default:    /* copy over it            */
  462.                 retval = FLDOVER;
  463.                 *buf++ = c;
  464.                 max--;
  465.                 break;
  466.             }
  467.         }
  468.         n = gather(buf, max);    /* get rest of header line    */
  469.         max -= n;
  470.         buf = &buf[n - 1];
  471.     } while (*buf == '\\');    /* user wants to add more?    */
  472.  
  473.     return(retval);
  474. }
  475.  
  476. prefix(buf, pre)
  477. char *buf, *pre;
  478. {
  479.     while (*pre)
  480.         if (*buf++ != *pre++)
  481.             return(FALSE);
  482.     return(TRUE);
  483. }
  484.  
  485.  
  486. getaddr(print, buf, flag, defhost)
  487. char print[];
  488. char *buf;
  489. int flag;
  490. char defhost[];
  491. {
  492.     char    addrin[S_BSIZE];    /* temporary store for user input */
  493.     char    *dn, *gstrindex();
  494.  
  495.     if (flag && *buf)        /* print what already is there    */
  496.         printf(shrtfmt, print, buf);
  497.  
  498.     addrin[0] = '\0';        /* mark temp buffer as empty    */
  499.     switch (gethead(print, addrin, NO)) {
  500.     case FLDREMV:        /* erase any existing contents    */
  501.         buf[0] = '\0';
  502.         break;
  503.  
  504.     case ITMRMV:        /* delete single name        */
  505.         dn = gstrindex(addrin, buf);
  506.         if (dn == 0) {
  507.             printf(" no such name in the list; name = '%s'\n",
  508.                 addrin);
  509.             break;
  510.         }
  511.         dlt_name(buf, dn);
  512.         break;
  513.     case FLDSAME:        /* leave as is            */
  514.         break;
  515.  
  516.     case FLDOVER:        /* overwrite existing contents    */
  517.         buf[0] = '\0';    /* erase existing, then add    */
  518.         addrcat(buf, addrin, defhost);
  519.         break;
  520.  
  521.     case FLDADD:        /* append to existing        */
  522.         addrcat(buf, addrin, defhost);
  523.         break;
  524.     }
  525. }
  526.  
  527. /* these varibles are made global for recursive reasons */
  528.  
  529. int linelen,
  530. destlen,
  531. addrlen;
  532.  
  533. addrcat(dest, src, thehost)
  534. char *dest, *src, thehost[];
  535. {
  536.     char    addr[S_BSIZE], name[ADDRSIZE], address[ADDRSIZE],
  537.         temphost[FILNSIZE], defhost[FILNSIZE], hostname[FILNSIZE];
  538.     char    *sadrptr, *ptr;
  539.     int    sub_flag;
  540.  
  541.     if (thehost != 0)        /* save official version of default */
  542.         strcpy(defhost, thehost);
  543.  
  544.     for (ptr = dest, linelen = 0; *ptr != '\0'; ptr++, linelen++)
  545.         if (*ptr == '\n')    /* get length of last line of header */
  546.             linelen = -1;    /* make it zero for next character */
  547.     destlen = ptr - dest;
  548.  
  549.     for (adrptr = src;;) {        /* adrptr is state variable, used in */
  550.                     /*   next_address        */
  551.         switch (next_address(addr)) {
  552.         case -1:        /* all done            */
  553.  
  554.             /* clean markers in aliases structure */
  555.             als = &alias_ptr;
  556.             while (als != NULL) {
  557.                 als->cntr = 0;
  558.                 als = als->next_int;
  559.             }
  560.             return;
  561.  
  562.         case 0:        /* empty address            */
  563.             continue;
  564.         }
  565.  
  566.         name[0] = address[0] = temphost[0] = '\0';
  567.         parsadr(addr, name, address, temphost);
  568.         if (address[0] == '\0') {    /* change the default host */
  569.             if (temphost[0] != '\0')
  570.                 strcpy(defhost, temphost);
  571.             continue;
  572.         }
  573.         if (aflag && temphost[0]==0) {
  574.             als = &alias_ptr;
  575.             sub_flag = 0;
  576.             while (als != NULL) {
  577.                 if (lexequ(address, als->key) && als->cntr == 0) {
  578.                     als->cntr++;
  579.                     sadrptr = adrptr;
  580.                     addrcat(dest, als->names, thehost);
  581.                     adrptr = sadrptr;
  582.                     sub_flag = 1;
  583.                     break;
  584.                 }
  585.                 else
  586.                     if (lexequ(address, als->key) && als->cntr != 0) {
  587.                         sub_flag = 1;
  588.                         break;
  589.                     }
  590.                 als = als->next_int;
  591.             }
  592.             if (sub_flag == 1)
  593.                 continue;
  594.         }
  595.         if (temphost[0] == '\0')
  596.             strcpy(hostname, defhost);
  597.         else
  598.             strcpy(hostname, temphost);
  599.  
  600.         if (name[0] != '\0') {    /* put into canonical form    */
  601.                     /* name <mailbox@host>        */
  602.  
  603.             /* force hostname to lower        */
  604.             for (ptr = hostname; !isnull(*ptr); ptr++)
  605.                 *ptr = uptolow(*ptr);
  606.  
  607.             /* is quoting needed for specials?    */
  608.             for (ptr = name; ; ptr++) {
  609.                 switch (*ptr) {
  610.                 default:
  611.                     continue;
  612.  
  613.                 case '\0':    /* nope            */
  614.                     sprintf(addr, "%s <%s@%s>",
  615.                         name, address, hostname);
  616.                     goto doaddr;
  617.  
  618.                 case '<':    /* quoting needed    */
  619.                 case '>':
  620.                 case '@':
  621.                 case ',':
  622.                 case ';':
  623.                 case ':':
  624.                     sprintf(addr, "\"%s\" <%s@%s>",
  625.                         name, address, hostname);
  626.                     goto doaddr;
  627.                 }
  628.             }
  629.         }
  630.         else {
  631.             sprintf(addr, "%s@%s", address, hostname);
  632.         }
  633.  
  634. doaddr:
  635.         addrlen = strlen(addr);
  636.  
  637.         /* it will fit into dest buffer    */
  638.         if ((destlen + addrlen) < (S_BSIZE - 15)) {
  639.             if (destlen == 0)
  640.                 strcpy(dest, addr);
  641.             else {    /* monitor line length        */
  642.                 if ((linelen + addrlen) < 67)
  643.                     sprintf(&dest[destlen], ", %s", addr);
  644.                 else {
  645.                     sprintf(&dest[destlen], ",\n%s", addr);
  646.                     linelen = 0;
  647.                 }
  648.                 destlen += 2;
  649.                 linelen += 2;
  650.             }
  651.             destlen += addrlen;
  652.             linelen += addrlen;
  653.         }
  654.  
  655.     }
  656. }
  657. /*
  658. **    S P E C I A L  S T R I N D E X    F U N C T I O N
  659. **
  660. ** Specially modified by George Hartwig to return a pointer to the beginning
  661. ** of the requested string instead of the offset.
  662. */
  663.  
  664. char *gstrindex(str, target)        /* return column str starts in target */
  665. register char    *str,
  666. *target;
  667. {
  668.     char *otarget;
  669.     register short slen;
  670.  
  671.     for (otarget = target, slen = strlen(str); ; target++) {
  672.         if (*target == '\0')
  673.             return((char *) 0);
  674.  
  675.         if (equal(str, target, slen))
  676.             return(target);
  677.     }
  678. }
  679.  
  680. /* buf is a pointer to a character array and pos is a pointer to a position  */
  681. /* within that array. The purpose of this routine is delete the name field   */
  682. /* pointed to by pos. In order to do this we will search backward to either  */
  683. /* comma ',' or a colon ':' (if a comma, we will then delete that comma also */
  684. /* and then delete forward until another comma or                 */
  685. /* a end-of-string '\0' is found.                         */
  686. dlt_name(buf, pos)
  687. char *buf, *pos;
  688. {
  689.     char tmpbuffer[S_BSIZE];
  690.     char *sd, *ed, *cp;
  691.     int quote_flag;
  692.  
  693.  
  694.     cp = pos;
  695.     quote_flag = 0;
  696.  
  697.     while (cp >= buf) {
  698.         if (*cp == '"')
  699.             if (quote_flag == 0)
  700.                 quote_flag = 1;
  701.             else
  702.                 quote_flag = 0;
  703.         if (*cp == ',' && quote_flag == 0)
  704.             break;
  705.         else
  706.             cp--;
  707.     }
  708.     sd = cp;
  709.  
  710.     cp = pos;
  711.  
  712.     while (*cp != '\0') {
  713.         if (*cp == '"')
  714.             if (quote_flag == 0)
  715.                 quote_flag = 1;
  716.             else
  717.                 quote_flag = 0;
  718.         if (*cp == ',' && quote_flag == 0)
  719.             break;
  720.         else
  721.             cp++;
  722.     }
  723.  
  724.     ed = cp;
  725.  
  726.     /* at this point *sd should point at the comma preceding the name
  727.     ** to be deleted or the beginning of the line and ed should be
  728.     ** pointing to the trailing comma or the end of the line. So it is
  729.     ** necessary at this point to determine just which of these cases
  730.     ** have occurred so that the string may be properly reassembled.
  731.     */
  732.  
  733.     if (*sd == ',' && *ed == ',') {
  734.         sd++;
  735.         *sd = '\0';
  736.         ed++;
  737.         sprintf(tmpbuffer, "%s%s", buf, ed);
  738.     }
  739.  
  740.     else
  741.         if (sd <= buf) {
  742.             ed++;
  743.             strcpy(tmpbuffer, ed);
  744.         }
  745.         else
  746.             if (*ed == '\0') {
  747.                 *sd = '\0';
  748.                 strcpy(tmpbuffer, buf);
  749.             }
  750.     strcpy(buf, tmpbuffer);
  751. }
  752.  
  753. /*
  754.  *    checksignature()
  755.  *
  756.  *  Verifies that the signature string does not contain any special
  757.  *  characters or is quoted.  Also checks for blank "name" portion.
  758.  */
  759. checksignature(sp)
  760. register char *sp;
  761. {
  762.     char tptr[128], *savptr, *ptr;
  763.     static char quote[] = "\"";
  764.  
  765.     savptr = sp;
  766.     while (*sp && isspace(*sp))    /* eat leading whitespace */
  767.         sp++;
  768.     if (*sp == '\0') {
  769.         printf("Signature is blank\n");
  770.         return(-1);        /* must have some signature */
  771.     }
  772.     while (*sp) {
  773.         switch (*sp) {
  774.         case '<':
  775.         case '>':
  776.         case '@':
  777.         case ',':
  778.         case ';':
  779.         case ':':
  780.         case '.':    /*  Arggggg...    */
  781.         case '[':
  782.         case ']':
  783.             /* surround bad signature with quotes */
  784.             tptr[0] = '\0';
  785.             strcat(tptr,quote);
  786.             sp = savptr;
  787.             strcat(tptr,sp);
  788.             if (ptr = rindex(tptr, ' '))
  789.                 *ptr = '\0';
  790.             strcat(tptr,quote);
  791.             strcpy(sp,tptr);
  792.             return(0);
  793.  
  794.         case '\\':
  795.             sp++;
  796.             if (*sp == '\0')
  797.                 return(-1);
  798.             break;
  799.  
  800.         case '"':
  801.             for (sp++; *sp != '"'; sp++) {
  802.                 if (*sp == '\\') {
  803.                     sp++;
  804.                     if (*sp == '\0')
  805.                         return(-1);
  806.                 } else if (*sp == '\0') {
  807.                     printf("Unmatched '\"' in signature\n");
  808.                     return(-1);
  809.                 }
  810.             }
  811.             break;
  812.  
  813.         default:
  814.             break;
  815.         }
  816.         sp++;
  817.     }
  818.  
  819.     return(0);
  820. }
  821.  
  822. addheader(name, data)
  823. char    *name;
  824. char    *data;
  825. {
  826.     register struct header *nhp;
  827.     register struct header *ohp;
  828.     register char *cp;
  829.     char    buf[LINESIZE];
  830.  
  831.     if (!isstr(name))
  832.         return;
  833.     for (cp = name; *cp; cp++)
  834.         if (!isprint(*cp) && *cp != '\t') {
  835.             printf("Illegal character in header name.\n");
  836.             return;
  837.         }
  838.     data = (isstr(data) ? data : "");
  839.     for (cp = data; *cp; cp++)
  840.         if (!isprint(*cp) && *cp != '\t') {
  841.             printf("Illegal character in header data.\n");
  842.             return;
  843.         }
  844.     if (headers) {
  845.         for (ohp = headers; !lexequ(name, ohp->hname); ohp = ohp->hnext)
  846.             if (ohp->hnext == (struct header *)0)
  847.                 break;
  848.         if (lexequ(name, ohp->hname)) {
  849.             strncpy(ohp->hdata, data, sizeof(ohp->hdata)-1);
  850.             return;
  851.         }
  852.     }
  853.     nhp = (struct header *)malloc(sizeof(*nhp));
  854.     sprintf(buf, "%s:  ", name);
  855.     if (nhp == NULL || (nhp->hname = strdup(buf)) == NULL) {
  856.         printf("No memory for header '%s'\n", buf);
  857.         if (nhp)
  858.             free(nhp);
  859.         return;
  860.     }
  861.     strncpy(nhp->hdata, data, sizeof(nhp->hdata)-1);
  862.     nhp->hnext = (struct header *)0;
  863.     nhp->hdata[sizeof(nhp->hdata)-1] = '\0';
  864.     if (headers == (struct header *)0) {
  865.         headers = nhp;
  866.         return;
  867.     }
  868.     ohp->hnext = nhp;
  869. }
  870.