home *** CD-ROM | disk | FTP | other *** search
/ ftp.freefriends.org / ftp.freefriends.org.tar / ftp.freefriends.org / arnold / Source / mush.rstevens.tar.gz / mush.tar / hdrs.c < prev    next >
C/C++ Source or Header  |  1994-07-09  |  23KB  |  805 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. #ifdef SUNTOOL
  17. #define highlight(win,x,y,s) \
  18.     (void) (pw_text(win,x,y, PIX_SRC, mush_font, s), \
  19.     pw_text(win,x+1,y, \
  20.     (ison(glob_flags, REV_VIDEO))? PIX_NOT(PIX_SRC): PIX_SRC|PIX_DST, \
  21.     mush_font, s))
  22. #endif /* SUNTOOL */
  23.  
  24. /*
  25.  * Get a message from the current folder by its offset.
  26.  * Copy the From_ line to the second argument if the third arg > 0,
  27.  * and return the second argument, or NULL on an error.
  28.  */
  29. char *
  30. msg_get(n, from, count)
  31. int n, count;
  32. char *from;
  33. {
  34.     if (fseek(tmpf, msg[n].m_offset, L_SET) == -1) {
  35.     error("fseek in %s (msg %d, folder=%s)", tempfile, n+1, mailfile);
  36.     turnon(glob_flags, READ_ONLY);
  37.     return NULL;
  38.     }
  39.     if (count)
  40. #ifndef MSG_SEPARATOR
  41.     return fgets(from, count, tmpf);
  42. #else
  43.     *from = '\0';
  44. #endif
  45.     return from;
  46. }
  47.  
  48. /*
  49.  * get which message via the offset and search for the headers which
  50.  * match the string "str". there may be more than one of a field (like Cc:)
  51.  * so get them all and "cat" them together into the static buffer
  52.  * "buf" and return its address.
  53.  */
  54. char *
  55. header_field(n, str)
  56. char *str;
  57. {
  58.     static char    buf[HDRSIZ];
  59.     char        tmp[HDRSIZ];
  60.     register char  *p, *p2, *b = buf;
  61.     int contd_hdr;  /* true if next line is a continuation of the hdr we want */
  62.  
  63.     /* use msg_get as a test for fseek() -- don't let it fgets() (pass 0) */
  64.     if (!msg_get(n, tmp, 0))
  65.     return NULL;
  66.     *b = 0;
  67.     while((p = fgets(tmp, sizeof(tmp), tmpf)) && *p != '\n') {
  68.     if (*p != ' ' && *p != '\t') {
  69.         contd_hdr = 0;
  70.         /* strcmp ignoring case */
  71.         for(p2 = str; *p && *p2 && lower(*p2) == lower(*p); ++p, ++p2);
  72.         /* MATCH is true if p2 is at the end of str and *p is ':' */
  73.         if (*p2 || *p++ != ':')
  74.         continue;
  75.         else
  76.         contd_hdr = 1;
  77.         if (b > buf && (b - buf) < sizeof buf - 2)
  78.         *b++ = ',';
  79.     } else if (!contd_hdr)
  80.         continue;
  81.     skipspaces(0);
  82.     (void) no_newln(p);
  83.     if (strlen(p) + (b - buf) < sizeof buf - 1) {
  84.         if (b > buf)
  85.         *b++ = ' ';
  86.         b += Strcpy(b, p);
  87.     }
  88.     }
  89.     if (b > buf && *--b == ',')
  90.     *b = 0;
  91.     return (*buf)? buf: NULL;
  92. }
  93.  
  94. do_hdrs(argc, argv, list)
  95. register char **argv, list[];
  96. {
  97.     register int   pageful = 0;
  98.     SIGRET        (*oldint)(), (*oldquit)();
  99.     int           show_deleted, srch = 1; /* search forward by default */
  100.     static int     cnt, oldscrn = 1;
  101.     register char  *p;
  102.     char        first_char = (argc) ? **argv: 'h';
  103.  
  104.     if (argc > 1 && !strcmp(argv[1], "-?"))
  105.     return help(0, "headers", cmd_help);
  106.  
  107.     if (!msg_cnt) {
  108.     if (ison(glob_flags, DO_PIPE) && !istool)
  109.         return 0;
  110. #ifdef CURSES
  111.     if (iscurses)
  112.         clear();
  113. #endif /* CURSES */
  114. #ifdef SUNTOOL
  115.     if (istool)
  116.         mail_status(0);
  117. #endif /* SUNTOOL */
  118.     return 0;
  119.     }
  120.     if (first_char == ':' || (argc > 1 && argv[1][0] == ':')) {
  121.     if (first_char != ':')
  122.         argv++;
  123.     return specl_hdrs(argv, list);
  124.     } else if (argc > 1 && !strncmp(argv[1], "-H:", 3)) {
  125.     argv[1][0] = ':';
  126.     argv[1][1] = argv[1][3];
  127.     argv[1][2] = 0;
  128.     return specl_hdrs(&argv[1], list);
  129.     }
  130.  
  131.     on_intr();
  132.  
  133.     if (argc && (argv[0][1] == '-' || argc > 1 && !strcmp(argv[1], "-"))) {
  134.     cnt = max(n_array[0], 0);
  135.     srch = -1;    /* search backwards */
  136.     } else if (argc && (argv[0][1] == '+' ||
  137.         argc > 1 && !strcmp(argv[1], "+")) ||
  138.         first_char == 'z' && !argv[1]) {
  139.     if (msg_cnt > screen)
  140.         cnt = min(msg_cnt - screen, n_array[0] + screen);
  141.     else
  142.         cnt = 0;
  143.     } else if (argc && *++argv &&
  144.         (isdigit(**argv) || **argv == '^' ||
  145.         **argv == '$' || **argv == '.') ||
  146.         ison(glob_flags, IS_PIPE) && list) {
  147.     /* if we're coming from a pipe, start display at the first msg bit
  148.      * set in the msg_list
  149.      */
  150.     int fnd;
  151.     if (ison(glob_flags, IS_PIPE)) {
  152.         if (isoff(glob_flags, DO_PIPE))
  153.         for (fnd = 0; fnd < msg_cnt; fnd++)
  154.             if (msg_bit(list, fnd))
  155.             wprint("%s\n", compose_hdr(fnd));
  156.         off_intr();
  157.         return 0;
  158.     }
  159.     /* if a number was given, use it */
  160.     if (!(fnd = chk_msg(*argv))) {
  161.         off_intr();
  162.         return -1;
  163.     }
  164.     for (cnt = fnd - 1; cnt > 0 && cnt + screen > msg_cnt; cnt--)
  165.         ;
  166.     } else if (current_msg < n_array[0] || current_msg > n_array[oldscrn-1] ||
  167.         (iscurses || oldscrn != screen) &&
  168.         (cnt > current_msg + screen || cnt < current_msg - screen))
  169.     cnt = current_msg; /* adjust if reads have passed screen bounds */
  170.     else if (cnt >= msg_cnt || !argc || !*argv)
  171.     /* adjust window to maintain position */
  172.     cnt = (n_array[0] > msg_cnt) ? current_msg : n_array[0];
  173.  
  174.     oldscrn = screen;
  175.     show_deleted = !!do_set(set_options, "show_deleted");
  176.  
  177.     /* Make sure we have at least $screen headers to print */
  178.     if (cnt > 0 && !iscurses && first_char == 'h') {
  179.     int top, bot = cnt;
  180.     /* first count how many messages we can print without adjusting */
  181.     for (pageful = 0; pageful<screen && bot<msg_cnt && bot; bot += srch)
  182.         if (show_deleted || isoff(msg[bot].m_flags, DELETE))
  183.         pageful++;
  184.     /* if we can't print a pagefull of hdrs, back up till we can */
  185.     for (top = cnt-srch; pageful<screen && top && top<msg_cnt; top -= srch)
  186.         if (show_deleted || isoff(msg[top].m_flags, DELETE))
  187.         pageful++;
  188.     if (srch < 0)
  189.         cnt = bot;    /* the search was upside down */
  190.     else
  191.         cnt = top + (pageful == screen);
  192.     pageful = 0;    /* Used later as an index, so reset */
  193.     } else if (cnt > 0 && srch < 0)
  194.     cnt = max(cnt - screen, 0);
  195.     else
  196.     cnt = max(cnt, 0);
  197.  
  198.     for (;pageful<screen && cnt<msg_cnt && isoff(glob_flags, WAS_INTR); cnt++) {
  199.     if (!iscurses && !show_deleted && first_char == 'h'
  200.         && ison(msg[cnt].m_flags, DELETE))
  201.         continue;
  202.     n_array[pageful++] = cnt;
  203.     /* this message was displayed -- set the bit */
  204.     if (list)
  205.         set_msg_bit(list, cnt);
  206.     /* if do_pipe, don't output anything */
  207.     if (ison(glob_flags, DO_PIPE) && !istool)
  208.         continue;
  209.     p = compose_hdr(cnt);
  210.     if (!istool && (!iscurses || ison(glob_flags, IS_GETTING)))
  211.         puts(p);
  212. #ifdef SUNTOOL
  213.     else if (istool) {
  214.         if (cnt == current_msg) /* embolden or reverse-video */
  215.         highlight(hdr_win, 0,pageful*l_height(), p);
  216.         else
  217.         (void) pw_text(hdr_win, 0, pageful * l_height(), PIX_SRC,
  218.                             mush_font, p);
  219.         Clrtoeol(hdr_win, strlen(p)*l_width(), pageful*l_height());
  220.     }
  221. #endif /* SUNTOOL */
  222.  
  223. #ifdef CURSES
  224.     else if (iscurses) {
  225.         move(pageful, 0);
  226.         printw("%-.*s", COLS-2, p), clrtoeol();
  227.     }
  228. #endif /* CURSES */
  229.     }
  230.     /* just in case a signal stopped us */
  231.     off_intr();
  232.     pageful++;
  233. #ifdef CURSES
  234.     if (iscurses && pageful < screen)
  235.     move(pageful, 0), clrtobot();
  236. #endif /* CURSES */
  237.     if (cnt == msg_cnt) {
  238.     while (pageful <= screen) {
  239.         n_array[pageful-1] = msg_cnt+1; /* assign out-of-range values */
  240. #ifdef SUNTOOL
  241.         if (istool)
  242.         Clrtoeol(hdr_win, 0, pageful * l_height());
  243. #endif /* SUNTOOL */
  244.         ++pageful;
  245.     }
  246.     }
  247. #ifdef SUNTOOL
  248.     if (istool) {
  249.     Scrollbar sb = (Scrollbar) window_get(hdr_sw, WIN_VERTICAL_SCROLLBAR);
  250.  
  251.     if (show_deleted) {
  252.         scrollbar_set(sb,
  253.         SCROLL_OBJECT_LENGTH,    msg_cnt,
  254.         SCROLL_VIEW_START,    n_array[0],
  255.         0);
  256.     } else {
  257.         int i, not_deleted, start;
  258.  
  259.         for (i = start = 0; i < n_array[0]; i++)
  260.         if (!ison(msg[i].m_flags, DELETE))
  261.             start++;
  262.         for (not_deleted = start; i < msg_cnt; i++)
  263.         if (!ison(msg[i].m_flags, DELETE))
  264.             not_deleted++;
  265.         scrollbar_set(sb,
  266.         SCROLL_OBJECT_LENGTH,    not_deleted,
  267.         SCROLL_VIEW_START,    start,
  268.         0);
  269.         }
  270.  
  271.     scrollbar_paint(sb);
  272.     mail_status(0);
  273.     }
  274. #endif /* SUNTOOL */
  275.  
  276.     return 0;
  277. }
  278.  
  279. #define NEW 1
  280. #define ALL 2
  281.  
  282. specl_hdrs(argv, list)
  283. char **argv, list[];
  284. {
  285.     u_long    special = 0;
  286.     int     n = 0;
  287.  
  288.     while (argv[0][++n])
  289.     switch(argv[0][n]) {
  290.         case 'a': special = ALL;
  291.         when 'd': special = DELETE;
  292.         when 'm': special = M_PRIORITY(0);
  293.         when 'n': special = NEW;
  294.         when 'o': special = OLD;
  295.         when 'p': special = PRESERVE;
  296.         when 'r': special = REPLIED;
  297.         when 's': special = SAVED;
  298.         when 'u': special = UNREAD;
  299.         otherwise: print("choose from d,m,n,o,p,r,s,u or a"); return -1;
  300.     }
  301.     if (debug)
  302.     (void) check_flags(special);
  303.  
  304.     for (n = 0; n < msg_cnt; n++) {
  305.     /*
  306.      * First, see if we're looking for NEW messages.
  307.      * If so, then check to see if the msg is unread and not old.
  308.      * If special > ALL, then special has a mask of bits describing
  309.      * the state of the message.
  310.      */
  311.     if (ison(glob_flags, IS_PIPE)&& !msg_bit(list, n))
  312.         continue;
  313.     if (special == ALL || special == NEW &&
  314.            (ison(msg[n].m_flags, UNREAD) && isoff(msg[n].m_flags, OLD))) {
  315.         if (isoff(glob_flags, DO_PIPE))
  316.         print("%s\n", compose_hdr(n));
  317.         if (list)
  318.         set_msg_bit(list, n);
  319.     } else if (special > ALL && ison(msg[n].m_flags, special)) {
  320.         if (isoff(glob_flags, DO_PIPE))
  321.         print("%s\n", compose_hdr(n));
  322.         if (list)
  323.         set_msg_bit(list, n);
  324.     } else {
  325.         if (list)
  326.         unset_msg_bit(list, n);
  327.         if (debug) {
  328.         (void) printf("msg[%d].m_flags: %d", n, msg[n].m_flags);
  329.         (void) check_flags(msg[n].m_flags);
  330.         }
  331.     }
  332.     }
  333.     return 0;
  334. }
  335.  
  336. #define Strncpy(buf,p) (void)(strncpy(buf,p,sizeof(buf)),buf[sizeof(buf)-1]=0)
  337.  
  338. /*
  339.  * format a header from the information about a message (from, to, date,
  340.  * subject, etc..).  The header for message number "cnt" is built and is
  341.  * returned in the static buffer "buf".  There will be *at least* 9 chars
  342.  * in the buffer which will be something like: " 123 >N " The breakdown
  343.  * is as follows: 4 chars for the message number, 1 space, 1 char for '>'
  344.  * (if current message) and two spaces for message status (new, unread, etc)
  345.  * followed by 1 terminating space.
  346.  * Read other comments in the routine for more info.
  347.  */
  348. char *
  349. format_hdr(cnt, hdr_fmt, show_to)
  350. int cnt, show_to;
  351. char *hdr_fmt;
  352. {
  353.     static char        buf[HDRSIZ];
  354.     register char    *p, *p2, *b;
  355.     int            len, do_pad = FALSE, val, pad, got_dot, isauthor = 0, n;
  356.     char from[HDRSIZ], subject[256], date[64], lines[16];
  357.     char to[256], addr[256], name[256], user[256], status[4];
  358.     char Day[3], Mon[4], Tm[8], Yr[5], Wkday[4], Zone[8], *date_p;
  359.  
  360.     buf[0] = 0;
  361.     if (msg_cnt < 1)
  362.     return buf;
  363.  
  364.     /* status of the message */
  365.     if (ison(msg[cnt].m_flags, DELETE))
  366.     status[0] = '*';
  367.     else if (ison(msg[cnt].m_flags, PRESERVE))
  368.     status[0] = 'P';
  369.     else if (ison(msg[cnt].m_flags, SAVED))
  370.     status[0] = 'S';
  371.     else if (ison(msg[cnt].m_flags, OLD) && ison(msg[cnt].m_flags, UNREAD))
  372.     status[0] = 'U';
  373.     else if (ison(msg[cnt].m_flags, PRINTED))
  374.     status[0] = 'p';
  375.     else if (ison(msg[cnt].m_flags, FORWARD))
  376.     status[0] = 'f';
  377.     else if (isoff(msg[cnt].m_flags, UNREAD))
  378.     status[0] = ' ';
  379.     else
  380.     status[0] = 'N';
  381.  
  382.     if (ison(msg[cnt].m_flags, REPLIED))
  383.     status[1] = 'r';
  384.     else
  385.     status[1] = ' ';
  386.     status[2] = 0;
  387.  
  388.     to[0] = from[0] = subject[0] = date[0] = lines[0] = addr[0] =
  389.     user[0] = name[0] = Day[0] = Mon[0] = Tm[0] = Yr[0] = Wkday[0] = 0;
  390.  
  391.     /* who's the message to */
  392.     if ((p = header_field(cnt, "resent-to")) ||
  393.     (p = header_field(cnt, "to")) ||
  394.     (p = header_field(cnt, "apparently-to")))
  395.     Strncpy(to, p);
  396.  
  397.     /* who's the message from */
  398.     if ((p = header_field(cnt, "from")) && strcpy(from, p)
  399.         || (p = reply_to(cnt, 0, from))) {
  400.     /* NOTE:  this fails if the sender has '<' or '!' in
  401.      * the RFC822 comment fields -- leading "comment"
  402.      * or trailing (comment) -- but that isn't critical
  403.      */
  404.     if ((p2 = rindex(p, '!')) || (p2 = index(p, '<')))
  405.         p = p2 + 1;
  406.     } else
  407.     p = strcpy(from, "unknown"); /* just in case */
  408.     /* If the From field contains the user's login name, then the message
  409.      * could be from the user -- attempt to give more useful information
  410.      * by telling to whom the message was sent.  This is not possible if
  411.      * the "to" header failed to get info (which is probably impossible).
  412.      * Use take_me_off() to be sure the message really is from the current
  413.      * user and not just someone with the same login at another site.
  414.      */
  415.     if (show_to && !strncmp(p, login, strlen(login)))
  416.     (void) take_me_off(from);
  417.     if (show_to && (isauthor = !*from)) {  /* assign and test */
  418.     (void) get_name_n_addr(to, name+4, addr+4);
  419.     if (addr[4])
  420.         (void) strncpy(addr, "TO: ", 4);
  421.     if (name[4]) {  /* check to see if a name got added */
  422.         (void) strncpy(name, "TO: ", 4);
  423.         Strncpy(from, name);
  424.     } else
  425.         Strncpy(from, addr);
  426.     } else
  427.     (void) get_name_n_addr(from, name, addr);
  428.  
  429.     if (ison(glob_flags, DATE_RECV))
  430.     date_p = msg[cnt].m_date_recv;
  431.     else
  432.     date_p = msg[cnt].m_date_sent;
  433.     (void) date_to_string(date_p, Yr, Mon, Day, Wkday, Tm, Zone, date);
  434.  
  435.     /* and the subject */
  436.     if (p = header_field(cnt, "subject"))
  437.     Strncpy(subject, p);
  438.  
  439.     /* now, construct a header out of a format string */
  440.     if (!hdr_fmt)
  441.     hdr_fmt = hdr_format;
  442.     {
  443.     int i;
  444.     for (i = MAX_PRIORITY; i > 0; i--)
  445.         if (ison(msg[cnt].m_flags, M_PRIORITY(i))) {
  446.         p2 = sprintf(lines, "%d", i);
  447.         break;
  448.         }
  449.     (void) sprintf(buf, "%c%3.d%s%c%s ",
  450.         ((cnt == current_msg && !iscurses)? '>': ' '),
  451.         cnt+1, cnt < 999 ? " " : "",
  452.         (ison(msg[cnt].m_flags, M_PRIORITY(0)) ? '+' :
  453.                     i > 0 ? 'A' + i - 1 : ' '),
  454.         status);
  455.     }
  456.     /* Count chars since beginning of buf. Initialize to 9 (strlen(buf) so far)
  457.      * This magic number is used in other places in msgs.c and mail.c
  458.      */
  459.     n = 9;
  460.     b = buf+9;
  461.     for (p = hdr_fmt; *p; p++)
  462.     if (*p == '\\')
  463.         switch (*++p) {
  464.         case 't':
  465.             while (n % 8)
  466.             n++, *b++ = ' ';
  467.         when 'n':
  468.             n = 1, *b++ = '\n';
  469.         otherwise: n++, *b++ = *p;
  470.         }
  471.     else if (*p == '%') {
  472.         char fmt[64];
  473.  
  474.         p2 = fmt;
  475.         /* first check for string padding: %5n, %.4a, %10.5f, %-.3l etc. */
  476.         do_pad = pad = val = got_dot = 0;
  477.         *p2++ = '%';
  478.         if (p[1] != '-')
  479.         *p2++ = '-';
  480.         else
  481.         ++p;
  482.         while (isdigit(*++p) || !got_dot && *p == '.') {
  483.         if (*p == '.')
  484.             got_dot = TRUE, val = pad, pad = 0;
  485.         else
  486.             pad = pad * 10 + *p - '0';
  487.         *p2++ = *p;
  488.         }
  489.         if (!got_dot && isdigit(p[-1])) {
  490.         *p2 = 0; /* assure null termination */
  491.         val = atoi(fmt+1);
  492.         if (val < 0)
  493.             val = -val;
  494.         p2 += strlen(sprintf(p2, ".%d", val));
  495.         }
  496.         pad = min(pad, val);
  497.         *p2++ = 's', *p2 = 0;
  498.         if (!*p)
  499.         break;
  500.         switch (*p) {
  501.         case 'f': p2 = from, do_pad = TRUE;
  502.         when 'a':
  503.             if (!*(p2 = addr))
  504.             p2 = from;
  505.             do_pad = TRUE;
  506.         when 'u' :
  507.             if (!user[0])
  508.             (void) bang_form(user, addr);
  509.             if (p2 = rindex(user, '!'))
  510.             p2++;
  511.             else
  512.             p2 = user;
  513.         when 'n':
  514.             if (!*(p2 = name))
  515.             p2 = from, do_pad = TRUE;
  516.         when '%': p2 = "%";
  517.         when 't': p2 = to;
  518.         when 's': p2 = subject;
  519.         when 'l': p2 = sprintf(lines, "%d", msg[cnt].m_lines);
  520.         when 'c': p2 = sprintf(lines, "%ld", msg[cnt].m_size);
  521.         when 'i': (p2 = header_field(cnt, "message-id")) || (p2 = "");
  522.         /* date formatting chars */
  523.         when 'd': p2 = date; /* the full date */
  524.         when 'T': p2 = Tm;
  525.         when 'M': p2 = Mon;
  526.         when 'Y': p2 = Yr;
  527.         when 'y': p2 = Yr+2;
  528.         when 'N': p2 = Day;
  529.         when 'D': case 'W': p2 = Wkday;
  530.         when 'Z': p2 = Zone;
  531.         /* Any selected header */
  532.         when '?': {
  533.             p2 = p + 1;
  534.             p = index(p2, '?');
  535.             if (p) {
  536.             *p = 0;
  537.             if (!(p2 = header_field(cnt, p2)))
  538.                 p2 = "";
  539.             *p = '?';
  540.             } else {
  541.             p = p2 + (strlen(p2) - 1);
  542.             if (!(p2 = header_field(cnt, p2)))
  543.                 p2 = "";
  544.             }
  545.         }
  546.         otherwise: continue; /* unknown formatting char */
  547.         }
  548.         if (do_pad && pad && strlen(p2) > pad) {
  549.         char *old_p2 = p2, *p3;
  550.         int is_bangform = 0;
  551.         /* if addr is too long, move pointer forward till the
  552.          * "important" part is readable only for ! paths/addresses.
  553.          */
  554.         while (p3 = index(p2, '!')) {
  555.             is_bangform = 1;
  556.             len = strlen(p3+1); /* xenix has compiler problems */
  557.             p2 = p3+1;
  558.             if (len + isauthor*4 < pad) {
  559.             if (isauthor && (p2 -= 4) < old_p2)
  560.                 p2 = old_p2;
  561.             break;
  562.             }
  563.         }
  564.         if (isauthor && p2 > old_p2+4 && !p3 && strlen(p2) + 4 > pad)
  565.             p2 -= 4;
  566.         if (is_bangform && (p3 = rindex(p2, '@'))) {
  567.             len = strlen(p3);
  568.             while (len-- && --p2 > old_p2) {
  569.             if (*(p2 + isauthor*4 - 1) == '!')
  570.                 break;
  571.             }
  572.         }
  573.         if (old_p2 != p2 && isauthor)
  574.             (void) strncpy(p2, "TO: ", 4); /* doesn't null terminate */
  575.         }
  576.         len = strlen(sprintf(b, fmt, p2));
  577.         n += len, b += len;
  578.         /* Get around a bug in 5.5 IBM RT which pads with NULs not ' ' */
  579.         while (n && !*(b-1))
  580.         b--, n--;
  581.     } else
  582.         n++, *b++ = *p;
  583.     /* Since show_to is true only when called from compose_hdr() below,
  584.      * use it to decide whether trailing whitespace should be trimmed.
  585.      */
  586.     if (show_to)
  587.     for (*b-- = 0; isspace(*b) && *b != '\n'; --b)
  588.         *b = 0;
  589.     else
  590.     *b = 0;
  591.     return buf;
  592. }
  593.  
  594. char *
  595. compose_hdr(cnt)
  596. int cnt;
  597. {
  598.     if (!hdr_format)
  599.     hdr_format = DEF_HDR_FMT;
  600.     return format_hdr(cnt, hdr_format, TRUE);
  601. }
  602.  
  603. /*
  604.  * Using message "n", build a list of recipients that you would mail to if
  605.  * you were to reply to this message.  If "all" is true, then it will take
  606.  * everyone from the To line in addition to the original sender.
  607.  * route_addresses() is called from mail.c, not from here.  There are too many
  608.  * other uses for reply_to to always require reconstruction of return paths.
  609.  * Note that we do NOT deal with Cc paths here either.
  610.  * Check to make sure that we in fact return a legit address (i.e. not blanks
  611.  * or null). If such a case occurs, return login name.  Always pad end w/blank.
  612.  */
  613. char *
  614. reply_to(n, all, buf)
  615. char buf[];
  616. {
  617.     register char *p = NULL, *p2 = NULL, *b = buf, *field;
  618.     char line[256], name[256], addr[256], *unscramble_addr();
  619.  
  620.     name[0] = addr[0] = '\0';
  621.  
  622.     if (field = do_set(set_options, "reply_to_hdr")) {
  623. #ifndef MSG_SEPARATOR
  624.     if (!*field)
  625.         goto DoFrom; /* special case -- get the colon-less From line */
  626. #endif /* MSG_SEPARATOR */
  627.     field = lcase_strcpy(line, field);
  628.     while (*field) {
  629.         if (p2 = any(field, " \t,:"))
  630.         *p2 = 0;
  631. #ifndef MSG_SEPARATOR
  632.         if (!lcase_strncmp(field, "from_", -1))
  633.         goto DoFrom;
  634. #endif /* MSG_SEPARATOR */
  635.         if ((p = header_field(n, field)) || !p2)
  636.         break;
  637.         else {
  638.         field = p2+1;
  639.         while (isspace(*field) || *field == ':' || *field == ',')
  640.             field++;
  641.         }
  642.     }
  643.     if (!p)
  644.         print("Warning: message contains no `reply_to_hdr' headers.\n");
  645.     }
  646.     if (p || (!p && ((p = header_field(n, field = "reply-to")) ||
  647.             (p = header_field(n, field = "from")) ||
  648.             (p = header_field(n, field = "return-path"))))) {
  649.     skipspaces(0);
  650.     } else if (!p) {
  651. DoFrom:
  652.     field = "from_";
  653. #ifndef MSG_SEPARATOR
  654.     /* if all else fails, then get the first token in "From" line */
  655.     if (p2 = msg_get(n, line, sizeof line))
  656.         p = index(p2, ' ');
  657.     if (!p2 || !p)
  658.         return "";
  659.     skipspaces(1);
  660.     /* Extra work to handle quoted tokens */
  661.     while (p2 = any(p, "\" ")) {
  662.         if (*p2 == '"') {
  663.         if (p2 = index(p2 + 1, '"'))
  664.             p2++;
  665.         else
  666.             return "";
  667.         } else
  668.         break;
  669.     }
  670.     if (p2)
  671.         *p2 = 0;
  672.     if (!unscramble_addr(p, line)) { /* p is safely recopied to line */
  673.         p2 = addr;
  674.         goto BrokenFrom;
  675.     } else {
  676.         p = line;
  677.         p2 = NULL;
  678.     }
  679. #else /* MSG_SEPARATOR */
  680.     wprint("Warning: unable to find who msg %d is from!\n", n+1);
  681.     p2 = addr;
  682.     goto BrokenFrom;
  683. #endif /* MSG_SEPARATOR */
  684.     }
  685.     (void) get_name_n_addr(p, name, addr);
  686.     if (!name[0] && (!lcase_strncmp(field, "return-path", -1) ||
  687.              !lcase_strncmp(field, "from_", -1))) {
  688.     /*
  689.      * Get the name of the author of the message we're replying to from the
  690.      * From: header since that header contains the author's name.  Only do
  691.      * this if the address was gotten from the return-path or from_ lines
  692.      * because this is the only way to guarantee that the return address
  693.      * matches the author's name.  Reply-To: may not be the same person!
  694.      * Check Resent-From: if the address came from the from_ line, else
  695.      * check From:, and finally Sender: or Name:.
  696.      */
  697. BrokenFrom:
  698.     if (!lcase_strncmp(field, "from_", -1) &&
  699.         (p = header_field(n, "resent-from")) ||
  700.             (p = header_field(n, "from")) ||
  701.             (p = header_field(n, "sender"))) {
  702.         /* p2 is either NULL or addr (BrokenFrom) */
  703.         (void) get_name_n_addr(p, name, p2);
  704.     }
  705.     if (!name[0] && (p = header_field(n, "name")))
  706.         (void) strcpy(name, p);
  707.     if (name[0]) {
  708.         if ((p = any(name, "(<,\"")) && (*p == ',' || *p == '<'))
  709.         *b++ = '"';
  710.         b += Strcpy(b, name);
  711.         if (p && (*p == ',' || *p == '<'))
  712.         *b++ = '"';
  713.         *b++ = ' ', *b++ = '<';
  714.     }
  715.     b += Strcpy(b, addr);
  716.     if (name[0])
  717.         *b++ = '>', *b = 0;
  718.     } else
  719.     b += Strcpy(buf, p);
  720.  
  721.     /*
  722.      * if `all' is true, append everyone on the "To:" line(s).
  723.      * cc_to(), called separately, will catch the cc's
  724.      */
  725.     if (all) {
  726.     int lim = HDRSIZ - (b - buf) - 2;
  727.     /* Check for overflow on each copy.
  728.      * The assumption that HDRSIZ is correct is unwise, but I know it
  729.      * to be true for Mush.  Be forewarned if you call this routine.
  730.      */
  731.     if (lim > 0 && (p = header_field(n, "resent-to")) && *p) {
  732.         *b++ = ',', *b++ = ' ';
  733.         p[lim] = '\0'; /* prevent overflow */
  734.         b += Strcpy(b, p);
  735.         lim = HDRSIZ - (b - buf) - 2;
  736.     }
  737.     if (lim > 0 && (p = header_field(n, "to")) && *p) {
  738.         *b++ = ',', *b++ = ' ';
  739.         p[lim] = '\0'; /* prevent overflow */
  740.         b += Strcpy(b, p);
  741.         lim = HDRSIZ - (b - buf) - 2;
  742.     }
  743.     if (lim > 0 && (p = header_field(n, "apparently-to")) && *p) {
  744.         *b++ = ',', *b++ = ' ';
  745.         p[lim] = '\0'; /* prevent overflow */
  746.         b += Strcpy(b, p);
  747.         lim = HDRSIZ - (b - buf) - 2;
  748.     }
  749.     /* Also append the Resent-From address if there is one. */
  750.     if (lim > 0 && (p = header_field(n, "resent-from")) && *p) {
  751.         *b++ = ',', *b++ = ' ';
  752.         p[lim] = '\0'; /* prevent overflow */
  753.         (void) strcpy(b, p);
  754.     }
  755.     }
  756.     fix_up_addr(buf);
  757.     /* p2 used to save boolean value of $metoo */
  758.     if (!(p2 = do_set(set_options, "metoo"))) {
  759.     /* Save the original name/addr in case it is the only one */
  760.     (void) get_name_n_addr(buf, name, addr);
  761.     take_me_off(buf);
  762.     }
  763.     for (p = buf; *p == ',' || isspace(*p); p++)
  764.     ;
  765.     if (!*p)
  766.     if (p2) /* take_me_off() was not done */
  767.         (void) strcpy(buf, login);
  768.     else {
  769.         if (!*name)
  770.         (void) sprintf(buf, "<%s>", addr);
  771.         else if (index(name, '"'))
  772.         (void) sprintf(buf, "<%s> (%s)", addr, name);
  773.         else
  774.         (void) sprintf(buf, "\"%s\" <%s>", name, addr);
  775.     }
  776.     return buf;
  777. }
  778.  
  779. char *
  780. subject_to(n, buf)
  781. register char *buf;
  782. {
  783.     register char *p;
  784.     buf[0] = 0; /* make sure it's already null terminated */
  785.     if (!(p = header_field(n, "subject")))
  786.     return NULL;
  787.     if (lcase_strncmp(p, "Re:", 3))
  788.     (void) strcpy(buf, "Re: ");
  789.     return strcat(buf, p);
  790. }
  791.  
  792. char *
  793. cc_to(n, buf)
  794. register char *buf;
  795. {
  796.     register char *p;
  797.     buf[0] = 0; /* make sure it's already null terminated */
  798.     if (!(p = header_field(n, "cc")))
  799.     return NULL;
  800.     fix_up_addr(p);
  801.     if (!do_set(set_options, "metoo"))
  802.     take_me_off(p);
  803.     return strcpy(buf, p);
  804. }
  805.