home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / mush6.4 / part09 / hdrs.c < prev   
C/C++ Source or Header  |  1989-03-12  |  19KB  |  632 lines

  1. /* hdrs.c     (c) copyright 1986 (Dan Heller) */
  2.  
  3. /*
  4.  * Routines that deal with message headers inside messages
  5.  * msg_get(n, from, count) -- get the From_ line in msg n into "from".
  6.  * header_field(n, str) -- get the header named "str" from msg n.
  7.  * do_hdrs(argc, argv, list) -- diplay message headers.
  8.  * specl_hdrs(argv, list) -- display msgs that share common attributes.
  9.  * compose_hdr(cnt) -- compose a message header from msg n.
  10.  * reply_to(n, all, buf) -- construct a header based on the To: header of n.
  11.  * subject_to(n, buf) -- get the subject for replying to msg n.
  12.  * cc_to(n, buf) -- construct a Cc header based on the Cc of message n.
  13.  */
  14. #include "mush.h"
  15.  
  16. /*
  17.  * Get a message from the current folder by its offset.
  18.  * Copy the From_ line to the second argument if the third arg > 0,
  19.  * and return the second argument, or NULL on an error.
  20.  */
  21. char *
  22. msg_get(n, from, count)
  23. int n, count;
  24. char *from;
  25. {
  26.     if (fseek(tmpf, msg[n].m_offset, L_SET) == -1) {
  27.     error("fseek in %s (msg %d, folder=%s)", tempfile, n+1, mailfile);
  28.     turnon(glob_flags, READ_ONLY);
  29.     return NULL;
  30.     }
  31.     if (count)
  32. #ifndef MSG_SEPARATOR
  33.     return fgets(from, count, tmpf);
  34. #else
  35.     *from = '\0';
  36. #endif
  37.     return from;
  38. }
  39.  
  40. /*
  41.  * get which message via the offset and search for the headers which
  42.  * match the string "str". there may be more than one of a field (like Cc:)
  43.  * so get them all and "cat" them together into the static buffer
  44.  * "buf" and return its address.
  45.  */
  46. char *
  47. header_field(n, str)
  48. char *str;
  49. {
  50.     static char    buf[HDRSIZ];
  51.     char        tmp[HDRSIZ];
  52.     register char  *p, *p2, *b = buf;
  53.     int contd_hdr;  /* true if next line is a continuation of the hdr we want */
  54.  
  55.     if (!msg_get(n, tmp, sizeof tmp))
  56.     return NULL;
  57.     *b = 0;
  58.     while((p = fgets(tmp, sizeof(tmp), tmpf)) && *p != '\n') {
  59.     if (*p != ' ' && *p != '\t') {
  60.         contd_hdr = 0;
  61.         /* strcmp ignoring case */
  62.         for(p2 = str; *p && *p2 && *p2 == lower(*p); ++p, ++p2);
  63.         /* MATCH is true if p2 is at the end of str and *p is ':' */
  64.         if (*p2 || *p++ != ':')
  65.         continue;
  66.         else
  67.         contd_hdr = 1;
  68.     } else if (!contd_hdr)
  69.         continue;
  70.     skipspaces(0);
  71.     p2 = no_newln(p);
  72.     *++p2 = ',', *++p2 = ' ', *++p2 = 0;
  73.     if (strlen(p) + (b-buf) < sizeof (buf))
  74.         b += Strcpy(b, p);
  75.     }
  76.     if (b > buf) /* now get rid of the trailing ", " */
  77.     *--b = 0, *--b = 0;
  78.     return (*buf)? buf: NULL;
  79. }
  80.  
  81. do_hdrs(argc, argv, list)
  82. register char **argv, list[];
  83. {
  84.     register int   pageful = 0;
  85.     SIGRET        (*oldint)(), (*oldquit)();
  86.     int           show_deleted;
  87.     static int     cnt;
  88.     register char  *p;
  89.     char        first_char = (argc) ? **argv: 'h';
  90.  
  91.     if (argc > 1 && !strcmp(argv[1], "-?"))
  92.     return help(0, "headers", cmd_help);
  93.  
  94.     if (!msg_cnt) {
  95.     if (ison(glob_flags, DO_PIPE))
  96.         return 0;
  97. #ifdef CURSES
  98.     if (iscurses)
  99.         clear();
  100. #endif /* CURSES */
  101. #ifdef SUNTOOL
  102.     if (istool)
  103.         mail_status(0);
  104. #endif /* SUNTOOL */
  105.     return 0;
  106.     }
  107.     if (first_char == ':' || (argc > 1 && argv[1][0] == ':')) {
  108.     if (first_char != ':')
  109.         argv++;
  110.     return specl_hdrs(argv, list);
  111.     }
  112.  
  113.     on_intr();
  114.  
  115.     if (argc && (argv[0][1] == '+' || argc > 1 && !strcmp(argv[1], "+")) ||
  116.         first_char == 'z' && !argv[1])
  117.     if (msg_cnt > screen)
  118.         cnt = min(msg_cnt - screen, n_array[0] + screen);
  119.     else
  120.         cnt = 0;
  121.     else if (argc && (argv[0][1] == '-' || argc > 1 && !strcmp(argv[1], "-")))
  122.     cnt = max((cnt - 2*screen), 0);
  123.     else if (argc && *++argv &&
  124.     (isdigit(**argv) || **argv == '^' || **argv == '$' || **argv == '.')
  125.      || ison(glob_flags, IS_PIPE)) {
  126.     /* if we're coming from a pipe, start display at the first msg bit
  127.      * set in the msg_list
  128.      */
  129.     int fnd;
  130.     if (ison(glob_flags, IS_PIPE)) {
  131.         if (isoff(glob_flags, DO_PIPE))
  132.         for (fnd = 0; fnd < msg_cnt; fnd++)
  133.             if (msg_bit(list, fnd))
  134.             wprint("%s\n", compose_hdr(fnd));
  135.         off_intr();
  136.         return 0;
  137.     }
  138.     /* if a number was given, use it */
  139.     if (!(fnd = chk_msg(*argv))) {
  140.         off_intr();
  141.         return -1;
  142.     }
  143.     for (cnt = fnd - 1; cnt > 0 && cnt + screen > msg_cnt; cnt--)
  144.         ;
  145.     } else if (current_msg < n_array[0] || current_msg > n_array[screen-1])
  146.     cnt = current_msg; /* adjust if reads have passed screen bounds */
  147.     else if (cnt >= msg_cnt || !argc || !*argv)
  148.     cnt = max((cnt - screen), 0); /* adjust window to maintain position */
  149.  
  150.     show_deleted = !!do_set(set_options, "show_deleted");
  151.  
  152.     /* Make sure we have at least $screen headers to print */
  153.     if (cnt > 0 && !iscurses && !show_deleted && first_char != 'h') {
  154.     int tmp = cnt;
  155.     /* first count how many messages we can print without adjusting */
  156.     for (pageful = 0; pageful < screen && cnt < msg_cnt; cnt++)
  157.         if (isoff(msg[cnt].m_flags, DELETE))
  158.         pageful++;
  159.     /* if we can't print a pagefull of hdrs, back up till we can */
  160.     for (cnt = tmp; pageful < screen && cnt; --cnt)
  161.         if (isoff(msg[cnt].m_flags, DELETE))
  162.         pageful++;
  163.     pageful = 0;    /* Used later as an index, so reset */
  164.     }
  165.  
  166.     for (;pageful<screen && cnt<msg_cnt && isoff(glob_flags, WAS_INTR); cnt++) {
  167.     if (!iscurses && !show_deleted && first_char == 'h'
  168.         && ison(msg[cnt].m_flags, DELETE))
  169.         continue;
  170.     n_array[pageful++] = cnt;
  171.     /* this message was displayed -- set the bit */
  172.     if (list)
  173.         set_msg_bit(list, cnt);
  174.     /* if do_pipe, don't output anything */
  175.     if (ison(glob_flags, DO_PIPE))
  176.         continue;
  177.     p = compose_hdr(cnt);
  178.     if (!istool && (!iscurses || ison(glob_flags, IS_GETTING)))
  179.         puts(p);
  180. #ifdef SUNTOOL
  181.     else if (istool) {
  182.         if (cnt == current_msg) /* embolden or reverse-video */
  183.         highlight(hdr_win, 0,pageful*l_height(DEFAULT), DEFAULT,p);
  184.         else
  185.         pw_text(hdr_win, 0, pageful * l_height(DEFAULT), PIX_SRC,
  186.                             fonts[DEFAULT], p);
  187.         Clrtoeol(hdr_win, strlen(p)*l_width(DEFAULT),
  188.              pageful*l_height(DEFAULT), DEFAULT);
  189.     }
  190. #endif /* SUNTOOL */
  191. #ifdef CURSES
  192.         else if (iscurses) {
  193.         move(pageful, 0);
  194.         printw("%-.*s", COLS-2, p), clrtoeol();
  195.         }
  196. #endif /* CURSES */
  197.     }
  198.     /* just in case a signal stopped us */
  199.     off_intr();
  200.     pageful++;
  201. #ifdef CURSES
  202.     if (iscurses && pageful < screen)
  203.     move(pageful, 0), clrtobot();
  204. #endif /* CURSES */
  205.     if (cnt == msg_cnt) {
  206.     while (pageful <= screen) {
  207.         n_array[pageful-1] = msg_cnt+1; /* assign out-of-range values */
  208. #ifdef SUNTOOL
  209.         if (istool)
  210.         Clrtoeol(hdr_win, 0, pageful * l_height(DEFAULT), DEFAULT);
  211. #endif /* SUNTOOL */
  212.         ++pageful;
  213.     }
  214.     }
  215. #ifdef SUNTOOL
  216.     if (istool) {
  217.     if (msg_cnt > screen) {
  218.         panel_set(next_scr, PANEL_SHOW_ITEM, TRUE, 0);
  219.         panel_set(prev_scr, PANEL_SHOW_ITEM, TRUE, 0);
  220.     }
  221.     mail_status(0);
  222.     }
  223. #endif /* SUNTOOL */
  224.     return 0;
  225. }
  226.  
  227. #define NEW 1
  228. #define ALL 2
  229.  
  230. specl_hdrs(argv, list)
  231. char **argv, list[];
  232. {
  233.     u_long    special = 0;
  234.     int     n = 0;
  235.  
  236.     while (argv[0][++n])
  237.     switch(argv[0][n]) {
  238.         case 'a': special = ALL;
  239.         when 'n': special = NEW;
  240.         when 'u': special = UNREAD;
  241.         when 'o': special = OLD;
  242.         when 'd': special = DELETE;
  243.         when 'r': special = REPLIED;
  244.         when 's': special = SAVED;
  245.         when 'p': special = PRESERVE;
  246.         otherwise: print("choose from n,u,o,d,r,s,p or a"); return -1;
  247.     }
  248.     if (debug)
  249.     (void) check_flags(special);
  250.  
  251.     for (n = 0; n < msg_cnt; n++) {
  252.     /*
  253.      * First, see if we're looking for NEW messages.
  254.      * If so, then check to see if the msg is unread and not old.
  255.      * If special > ALL, then special has a mask of bits describing
  256.      * the state of the message.
  257.      */
  258.     if (ison(glob_flags, IS_PIPE)&& !msg_bit(list, n))
  259.         continue;
  260.     if (special == ALL || special == NEW &&
  261.            (ison(msg[n].m_flags, UNREAD) && isoff(msg[n].m_flags, OLD))) {
  262.         if (isoff(glob_flags, DO_PIPE))
  263.         print("%s\n", compose_hdr(n));
  264.         if (list)
  265.         set_msg_bit(list, n);
  266. #ifndef M_XENIX
  267.     /*
  268.      * XENIX compiler can't handle "special" in ison() macro.
  269.      * It only works if the second argument is a constant!
  270.      */
  271.     } else if (special > ALL && ison(msg[n].m_flags, special)) {
  272.         if (isoff(glob_flags, DO_PIPE))
  273.         print("%s\n", compose_hdr(n));
  274.         if (list)
  275.         set_msg_bit(list, n);
  276. #endif /* M_XENIX */
  277.     } else {
  278.         if (list)
  279.         unset_msg_bit(list, n);
  280.         if (debug) {
  281.         printf("msg[%d].m_flags: %d", n, msg[n].m_flags);
  282.         (void) check_flags(msg[n].m_flags);
  283.         }
  284.     }
  285.     }
  286.     return 0;
  287. }
  288.  
  289. #define Strncpy(buf,p) (void)(strncpy(buf,p,sizeof(buf)),buf[sizeof(buf)-1]=0)
  290.  
  291. /*
  292.  * compose a header from the information about a message (from, to, date,
  293.  * subject, etc..).  The header for message number "cnt" is built and is
  294.  * returned in the static buffer "buf".  There will be *at least* 9 chars
  295.  * in the buffer which will be something like: " 123 >N " The breakdown
  296.  * is as follows: 4 chars for the message number, 1 space, 1 char for '>'
  297.  * (if current message) and two spaces for message status (new, unread, etc)
  298.  * followed by 1 terminating space.
  299.  * Read other comments in the routine for more info.
  300.  */
  301. char *
  302. compose_hdr(cnt)
  303. {
  304.     static char        buf[256];
  305.     register char    *p, *p2, *b;
  306.     int            len, do_pad = FALSE, val, pad, got_dot, isauthor = 0, n;
  307.     char from[HDRSIZ], subject[256], date[64], lines[16];
  308.     char to[256], addr[256], name[256], status[4];
  309.     char Day[3], Mon[4], Tm[8], Yr[5], Wkday[4], *date_p;
  310.  
  311.     /* status of the message */
  312.     if (ison(msg[cnt].m_flags, DELETE))
  313.     status[0] = '*';
  314.     else if (ison(msg[cnt].m_flags, PRESERVE))
  315.     status[0] = 'P';
  316.     else if (ison(msg[cnt].m_flags, SAVED))
  317.     status[0] = 'S';
  318.     else if (ison(msg[cnt].m_flags, OLD) && ison(msg[cnt].m_flags, UNREAD))
  319.     status[0] = 'U';
  320.     else if (isoff(msg[cnt].m_flags, UNREAD))
  321.     status[0] = ' ';
  322.     else
  323.     status[0] = 'N';
  324.  
  325.     if (ison(msg[cnt].m_flags, REPLIED))
  326.     status[1] = 'r';
  327.     else
  328.     status[1] = ' ';
  329.  
  330.     to[0] = from[0] = subject[0] = date[0] = lines[0] = addr[0] =
  331.     name[0] = Day[0] = Mon[0] = Tm[0] = Yr[0] = Wkday[0] = 0;
  332.  
  333.     /* who's the message to */
  334.     if ((p = header_field(cnt, "resent-to")) ||
  335.     (p = header_field(cnt, "to")) ||
  336.     (p = header_field(cnt, "apparently-to")))
  337.     Strncpy(to, p);
  338.  
  339.     /* who's the message from */
  340.     if ((p = header_field(cnt, "from")) && strcpy(from, p)
  341.         || (p = reply_to(cnt, 0, from))) {
  342.     /* NOTE:  this fails if the sender has '<' or '!' in
  343.      * the RFC822 comment fields -- leading "comment"
  344.      * or trailing (comment) -- but that isn't critical
  345.      */
  346.     if ((p2 = rindex(p, '!')) || (p2 = index(p, '<')))
  347.         p = p2 + 1;
  348.     } else
  349.     p = strcpy(from, "unknown"); /* just in case */
  350.     /* If the From field contains the user's login name, then the message is
  351.      * from the user -- attempt to give more useful information by telling
  352.      * to whom the message was sent.  This is not possible if the "to" header
  353.      * failed to get info (which is probably impossible).
  354.      */
  355.     if (!strncmp(p, login, strlen(login))) {
  356.     isauthor = TRUE;
  357.     (void) get_name_n_addr(to, name+4, addr+4);
  358.     if (addr[4])
  359.         (void) strncpy(addr, "TO: ", 4);
  360.     if (name[4]) {  /* check to see if a name got added */
  361.         (void) strncpy(name, "TO: ", 4);
  362.         Strncpy(from, name);
  363.     } else
  364.         Strncpy(from, addr);
  365.     } else
  366.     (void) get_name_n_addr(from, name, addr);
  367.  
  368.     if (ison(glob_flags, DATE_RECV))
  369.     date_p = msg[cnt].m_date_recv;
  370.     else
  371.     date_p = msg[cnt].m_date_sent;
  372.     date_to_string(date_p, Yr, Mon, Day, Wkday, Tm, date);
  373.  
  374.     /* and the subject */
  375.     if (p = header_field(cnt, "subject"))
  376.     Strncpy(subject, p);
  377.  
  378.     /* now, construct a header out of a format string */
  379.     if (!hdr_format)
  380.     hdr_format = DEF_HDR_FMT;
  381.  
  382.     (void) sprintf(buf, "%4.d ", cnt+1);
  383.     b = buf+5;
  384.     *b++ = ((cnt == current_msg && !iscurses)? '>': ' ');
  385.     *b++ = status[0], *b++ = status[1];
  386.     *b++ = ' ';
  387.     /* Count chars since beginning of buf. Initialize to 9 (strlen(buf) so far)
  388.      * This magic number is used in other places in msgs.c and mail.c
  389.      */
  390.     n = 9;
  391.     for (p = hdr_format; *p; p++)
  392.     if (*p == '\\')
  393.         switch (*++p) {
  394.         case 't':
  395.             while (n % 8)
  396.             n++, *b++ = ' ';
  397.         when 'n':
  398.             n = 1, *b++ = '\n';
  399.         otherwise: n++, *b++ = *p;
  400.         }
  401.     else if (*p == '%') {
  402.         char fmt[64];
  403.  
  404.         p2 = fmt;
  405.         /* first check for string padding: %5n, %.4a, %10.5f, %-.3l etc. */
  406.         do_pad = pad = val = got_dot = 0;
  407.         *p2++ = '%';
  408.         if (p[1] != '-')
  409.         *p2++ = '-';
  410.         else
  411.         ++p;
  412.         while (isdigit(*++p) || !got_dot && *p == '.') {
  413.         if (*p == '.')
  414.             got_dot = TRUE, val = pad, pad = 0;
  415.         else
  416.             pad = pad * 10 + *p - '0';
  417.         *p2++ = *p;
  418.         }
  419.         if (!got_dot && isdigit(p[-1])) {
  420.         *p2 = 0; /* assure null termination */
  421.         val = atoi(fmt+1);
  422.         if (val < 0)
  423.             val = -val;
  424.         p2 += strlen(sprintf(p2, ".%d", val));
  425.         }
  426.         pad = min(pad, val);
  427.         *p2++ = 's', *p2 = 0;
  428.         switch (*p) {
  429.         case 'f': p2 = from, do_pad = TRUE;
  430.         when 'a':
  431.             if (!*(p2 = addr))
  432.             p2 = from;
  433.             do_pad = TRUE;
  434.         when 'n':
  435.             if (!*(p2 = name))
  436.             p2 = from, do_pad = TRUE;
  437.         when '%': p2 = "%";
  438.         when 't': p2 = to;
  439.         when 's': p2 = subject;
  440.         when 'l': p2 = sprintf(lines, "%d", msg[cnt].m_lines);
  441.         when 'c': p2 = sprintf(lines, "%ld", msg[cnt].m_size);
  442.         when 'i': p2 = header_field(cnt, "message-id");
  443.         /* date formatting chars */
  444.         when 'd': p2 = date; /* the full date */
  445.         when 'T': p2 = Tm;
  446.         when 'M': p2 = Mon;
  447.         when 'Y': p2 = Yr;
  448.         when 'y': p2 = Yr+2;
  449.         when 'N': p2 = Day;
  450.         when 'D': case 'W': p2 = Wkday;
  451.         otherwise: continue; /* unknown formatting char */
  452.         }
  453.         if (do_pad && pad && strlen(p2) > pad) {
  454.         char *old_p2 = p2, *p3;
  455.         /* if addr is too long, move pointer forward till the
  456.          * "important" part is readable only for ! paths/addresses.
  457.          */
  458.         while (p3 = index(p2, '!')) {
  459.             int tmp = strlen(p3+1); /* xenix has compiler problems */
  460.             p2 = p3+1;
  461.             if (tmp + isauthor*4 < pad) {
  462.             if (isauthor && (p2 -= 4) < old_p2)
  463.                 p2 = old_p2;
  464.             break;
  465.             }
  466.         }
  467.         if (isauthor && p2 > old_p2+4 && !p3 && strlen(p2) + 4 > pad)
  468.             p2 -= 4;
  469.         if (old_p2 != p2 && isauthor)
  470.             (void) strncpy(p2, "TO: ", 4); /* doesn't null terminate */
  471.         }
  472.         len = strlen(sprintf(b, fmt, p2));
  473.         n += len, b += len;
  474.         /* Get around a bug in 5.5 IBM RT which pads with NULs not ' ' */
  475.         while (n && !*(b-1))
  476.         b--, n--;
  477.     } else
  478.         n++, *b++ = *p;
  479.     for (*b-- = 0; isspace(*b) && *b != '\n'; --b)
  480.     *b = 0;
  481.     return buf;
  482. }
  483.  
  484. /*
  485.  * Using message "n", build a list of recipients that you would mail to if
  486.  * you were to reply to this message.  If "all" is true, then it will take
  487.  * everyone from the To line in addition to the original sender.
  488.  * route_addresses() is called from mail.c, not from here.  There are too many
  489.  * other uses for reply_to to always require reconstruction of return paths.
  490.  * Note that we do NOT deal with Cc paths here either.
  491.  * Check to make sure that we in fact return a legit address (i.e. not blanks
  492.  * or null). If such a case occurs, return login name.  Always pad end w/blank.
  493.  */
  494. char *
  495. reply_to(n, all, buf)
  496. char buf[];
  497. {
  498.     register char *p = NULL, *p2, *b = buf, *field;
  499.     char line[256], name[256], addr[256];
  500.  
  501.     if (field = do_set(set_options, "reply_to_hdr")) {
  502. #ifndef MSG_SEPARATOR
  503.     if (!*field)
  504.         goto DoFrom; /* special case -- get the colon-less From line */
  505. #endif /* MSG_SEPARATOR */
  506.     field = lcase_strcpy(line, field);
  507.     while (*field) {
  508.         if (p2 = any(field, " \t,:"))
  509.         *p2 = 0;
  510. #ifndef MSG_SEPARATOR
  511.         if (!lcase_strncmp(field, "from_", -1))
  512.         goto DoFrom;
  513. #endif /* MSG_SEPARATOR */
  514.         if ((p = header_field(n, field)) || !p2)
  515.         break;
  516.         else {
  517.         field = p2+1;
  518.         while (isspace(*field) || *field == ':' || *field == ',')
  519.             field++;
  520.         }
  521.     }
  522.     if (!p)
  523.         print("Warning: message contains no `reply_to_hdr' headers.\n");
  524.     }
  525.     if (p || (!p && ((p = header_field(n, field = "reply-to")) ||
  526.         (p = header_field(n, field = "return-path")) ||
  527.         (p = header_field(n, field = "from")))))
  528.     skipspaces(0);
  529.     else if (!p) {
  530. #ifndef MSG_SEPARATOR
  531. DoFrom:
  532.     field = "from_";
  533.     /* if all else fails, then get the first token in "From" line */
  534.     if (p2 = msg_get(n, line, sizeof line))
  535.         p = index(p2, ' ');
  536.     else
  537.         return "";
  538.     skipspaces(1);
  539.     if (p2 = index(p, ' '))
  540.         *p2 = 0;
  541.     (void) unscramble_addr(p, line); /* p is safely recopied to line */
  542.     p = line;
  543. #else /* MSG_SEPARATOR */
  544.     wprint("Warning: unable to find who msg %d is from!\n", n+1);
  545. #endif /* MSG_SEPARATOR */
  546.     }
  547.     get_name_n_addr(p, name, addr);
  548.     if (!name[0] && (!lcase_strncmp(field, "return-path", -1) ||
  549.              !lcase_strncmp(field, "from_", -1))) {
  550.     /*
  551.      * Get the name of the author of the message we're replying to from the
  552.      * From: header since that header contains the author's name.  Only do
  553.      * this if the address was gotten from the return-path or from_ lines
  554.      * because this is the only way to guarantee that the return address
  555.      * matches the author's name.  Reply-To: may not be the same person!
  556.      * Check Resent-From: first since that's presumably more recent.
  557.      */
  558.     if ((p = header_field(n, "resent-from")) ||
  559.         (p = header_field(n, "from")))
  560.         get_name_n_addr(p, name, NULL);
  561.     if (!name[0] && (p = header_field(n, "name")))
  562.         (void) strcpy(name, p);
  563.     if (name[0]) {
  564.         if ((p = any(name, "(<,\"")) && (*p == ',' || *p == '<'))
  565.         *b++ = '"';
  566.         b += Strcpy(b, name);
  567.         if (p && (*p == ',' || *p == '<'))
  568.         *b++ = '"';
  569.         *b++ = ' ', *b++ = '<';
  570.     }
  571.     b += Strcpy(b, addr);
  572.     if (name[0])
  573.         *b++ = '>', *b = 0;
  574.     } else
  575.     b += Strcpy(buf, p);
  576.  
  577.     /*
  578.      * if `all' is true, append everyone on the "To:" line.
  579.      * cc_to(), called separately, will catch the cc's
  580.      */
  581.     if (all &&
  582.     ((p = header_field(n, "resent-to")) || (p = header_field(n, "to")) ||
  583.      (p = header_field(n, "apparently-to"))) && *p) {
  584.     *b++ = ',', *b++ = ' ';
  585.     /* The assumption that HDRSIZ is correct is unwise, but I know it
  586.      * to be true for Mush.  Be forewarned if you call this routine.
  587.      */
  588.     p[HDRSIZ - (b - buf) - 2] = '\0'; /* prevent overflow */
  589.     b += Strcpy(b, p);
  590.     }
  591.     /* Also append the Resent-From address if there is one. */
  592.     if (all && (p = header_field(n, "resent-from")) && *p) {
  593.     *b++ = ',', *b++ = ' ';
  594.     /* Another trick to prevent overflow.   See warning above. */
  595.     (void) strncpy(b, p, HDRSIZ - (b - buf) - 2);
  596.     buf[HDRSIZ - 3] = 0;
  597.     }
  598.     fix_up_addr(buf);
  599.     take_me_off(buf);
  600.     for (p = buf; *p == ',' || isspace(*p); p++)
  601.     ;
  602.     if (!*p)
  603.     (void) strcpy(buf, login);
  604.     return buf;
  605. }
  606.  
  607. char *
  608. subject_to(n, buf)
  609. register char *buf;
  610. {
  611.     register char *p;
  612.     buf[0] = 0; /* make sure it's already null terminated */
  613.     if (!(p = header_field(n, "subject")))
  614.     return NULL;
  615.     if (lcase_strncmp(p, "Re:", 3))
  616.     (void) strcpy(buf, "Re: ");
  617.     return strcat(buf, p);
  618. }
  619.  
  620. char *
  621. cc_to(n, buf)
  622. register char *buf;
  623. {
  624.     register char *p;
  625.     buf[0] = 0; /* make sure it's already null terminated */
  626.     if (!(p = header_field(n, "cc")))
  627.     return NULL;
  628.     fix_up_addr(p);
  629.     take_me_off(p);
  630.     return strcpy(buf, p);
  631. }
  632.