home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / mush6.4 / part11 / msgs.c < prev   
Encoding:
C/C++ Source or Header  |  1989-03-12  |  23.5 KB  |  850 lines

  1. /* @(#)msgs.c    (c) copyright 10/18/86 (Dan Heller) */
  2.  
  3. #include "mush.h"
  4.  
  5. void
  6. display_msg(n, flg)
  7. register int n;
  8. long flg;
  9. {
  10.     if (ison(msg[n].m_flags, DELETE) && !do_set(set_options, "show_deleted")) {
  11.     print("Message %d deleted; ", n+1);
  12. #ifdef SUNTOOL
  13.     if (istool)
  14.         print_more("Select UNDELETE to read."), do_clear();
  15.     else
  16. #endif /* SUNTOOL */
  17.     if (iscurses)
  18.         print_more("Type 'u' to undelete.");
  19.     else
  20.         print("Type 'undelete %d' to undelete\n", n+1);
  21.     return;
  22.     }
  23.     set_isread(n);
  24.     if (ison(flg, M_TOP)) {
  25.     turnon(flg, NO_HEADER);
  26.     print("Top of "), turnon(glob_flags, CONT_PRNT);
  27.     }
  28.  
  29. #ifdef MMDF
  30.     turnon(flg, NO_SEPARATOR);
  31. #endif /* MMDF */
  32.     if (!istool && isoff(flg, NO_PAGE) &&
  33.         crt < msg[n].m_lines && isoff(flg, M_TOP)) {
  34.     char buf[32], *pager = do_set(set_options, "pager");
  35.     if (!pager)
  36.         pager = DEF_PAGER;
  37.     if (!*pager || !strcmp(pager, "internal"))
  38.         pager = NULL; /* default to internal pager if pager set to "" */
  39.     (void) do_pager(pager, TRUE); /* start pager */
  40.     (void) do_pager(sprintf(buf, "Message #%d (%d lines)\n",
  41.              n+1, msg[n].m_lines), FALSE);
  42.     (void) copy_msg(n, NULL_FILE, flg);
  43.     (void) do_pager(NULL, FALSE); /* end pager */
  44.     } else {
  45.     print("Message #%d (%d lines)\n", n+1, msg[n].m_lines);
  46.     (void) copy_msg(n, stdout, flg);
  47.     }
  48. }
  49.  
  50. /*
  51.  * copy message 'n' to file "fp" according to various flag arguments
  52.  * return number of lines copied or -1 if system error on fputs.
  53.  * If "fp" is null, send to internal pager.  This can only happen from
  54.  * display_msg above.
  55.  */
  56. copy_msg(n, fp, flags)
  57. register int n;
  58. register FILE *fp;
  59. u_long flags;
  60. {
  61.     register int  ignoring = 0, lines = 0;
  62.     register char *indent_str;
  63.     int  on_hdr = 1, top, squeeze = 0;
  64.     char       line[BUFSIZ], *show_hdrs = NULL;
  65.  
  66.     still_more = 0;
  67.     if (ison(flags, M_TOP)) {
  68.     register char *p = do_set(set_options, "toplines");
  69.     top = (p)? atoi(p) : crt;
  70.     }
  71.     /* When updating to a folder, always write all headers! */
  72.     if (ison(flags, UPDATE_STATUS))
  73.     turnon(flags, NO_IGNORE);
  74.     else if (do_set(set_options, "alwaysignore"))
  75.     turnoff(flags, NO_IGNORE);
  76.     if (isoff(flags, NO_IGNORE)) {
  77.     if (do_set(set_options, "squeeze"))
  78.         squeeze = 1;
  79.     show_hdrs = do_set(set_options, "show_hdrs");
  80.     }
  81.  
  82. #ifdef SUNTOOL
  83.     if (istool && (!fp || fp == stdout)) {
  84.     register int x = (msg[n].m_lines + 2) * l_height(curfont);
  85.  
  86.     if (x > 32765) { /* to overcome a bug in pixrects that sun won't fix */
  87.         print("message too big to display using this font");
  88.         return 0;
  89.     }
  90.     if (x < msg_rect.r_height) /* make it at least as big as the window */
  91.         x = msg_rect.r_height;
  92.     /* If the window isn't big enough, an infinite loop occurs in Addstr */
  93.     if (x < 2 * l_height(curfont) || msg_rect.r_width < 3*l_width(curfont))
  94.         return 0;
  95.     do_clear();
  96.     lock_cursors();
  97.     /* msg_pix is for Addstr() */
  98.     if (!(msg_pix = mem_create(msg_rect.r_width, x, 1))) {
  99.         error("mem_create");
  100.         return 0;
  101.     }
  102.     pr_rop(msg_pix, 0,0, msg_rect.r_width-1, x-1, PIX_CLR, 0,0,0);
  103.     on_hdr = 1;
  104.     }
  105. #endif /* SUNTOOL */
  106.     if (ison(flags, INDENT)) {
  107.     if ((indent_str = do_set(set_options, "pre_indent_str"))) {
  108.         char *old_fmt = hdr_format;
  109.         hdr_format = indent_str;
  110.         fprintf(fp, "%s\n", compose_hdr(n) + 9); /* magic number 9 !! */
  111.         hdr_format = old_fmt;
  112.     }
  113.     if (!(indent_str = do_set(set_options, "indent_str")))
  114.         indent_str = DEF_INDENT_STR;
  115.     }
  116.     /* "line" used as dummy here, since 0 bytes read */
  117.     if (!msg_get(n, line, 0)) {
  118.     error("Unable to find msg %d", n+1);
  119.     return -1;
  120.     }
  121.     while (still_more < msg[n].m_size && fgets(line, sizeof (line), tmpf)) {
  122.     still_more += strlen(line);
  123. #ifdef MMDF
  124.     if (ison(flags, NO_SEPARATOR)) {
  125.         if (!strncmp(line, MSG_SEPARATOR, 4))
  126.         continue;
  127.     }
  128. #endif /* MMDF */
  129.     /*
  130.      * If squeeze is one, all blanks lines squeeze down to one blank line.
  131.      * If squeeze is two, squeezing is in progress so wait for the next \n.
  132.      */
  133.     if (*line == '\n') {
  134.         if (on_hdr)    /* blank line -- end of header */
  135.         turnoff(flags, NO_HEADER), on_hdr = 0;
  136.         if (squeeze > 1)
  137.         continue;
  138.         else if (squeeze)
  139.         squeeze = 2;
  140.     } else if (squeeze > 1)
  141.         squeeze = 1;
  142.  
  143.     if (ison(flags, UPDATE_STATUS))
  144.         if (!strncmp(line, "Status:", 7))
  145.         continue; /* ignore this and other "Status" lines */
  146.         else if (!on_hdr) {
  147.         /* preserve NEW/UNREAD status on preserved messages */
  148.         register char *p = line;
  149.         p += Strcpy(p, "Status: O");
  150.         if (isoff(msg[n].m_flags, UNREAD) &&
  151.             isoff(msg[n].m_flags, PRESERVE))
  152.             *p++ = 'R';
  153.         if (ison(msg[n].m_flags, SAVED))
  154.             *p++ = 'S';
  155.         if (ison(msg[n].m_flags, REPLIED))
  156.             *p++ = 'r';
  157.         *p++ = '\n', *p = 0;
  158.         fputs(line, fp);
  159.         (void) strcpy(line, "\n");
  160.         turnoff(flags, UPDATE_STATUS);
  161.         }
  162.     if (on_hdr && (isoff(flags, NO_IGNORE) || ison(flags, FORWARD))) {
  163.         register char *p = any(line, " \t:");
  164.         if (!p)
  165.         ignoring = 0, on_hdr = 0;
  166.         else if (ignoring)
  167.         if (*p != ':') {
  168.             Debug("Ignoring: %s", line);
  169.             continue;
  170.         } else
  171.             ignoring = 0;
  172.         if (p && *p == ':') {
  173.         *p = 0;
  174.         ignoring = 0;
  175.         if (show_hdrs) {
  176.             if (!chk_two_lists(line, show_hdrs, ":, \t"))
  177.             ignoring = 1;
  178.         } else if (ison(flags, FORWARD)) {
  179.             if (chk_two_lists(line, IGNORE_ON_FWD, ":, \t"))
  180.             ignoring = 1;
  181.         } else {
  182.             register struct options *opts;
  183.             for (opts = ignore_hdr; opts; opts = opts->next)
  184.             if (!lcase_strncmp(opts->option, line, -1)) {
  185.                 ignoring = 1;
  186.                 break;
  187.             }
  188.         }
  189.         *p = ':';
  190.         if (ignoring) {
  191.             Debug("Ignoring: %s", line);
  192.             continue;
  193.         }
  194.         }
  195.     }
  196.     if (!on_hdr && ison(flags, M_TOP) && !--top)
  197.         break;
  198.     if (isoff(flags, NO_HEADER)) {
  199.         /* note that function returns the number of lines */
  200.         lines++;
  201. #ifdef SUNTOOL
  202.         if (istool && (!fp || fp == stdout)) {
  203.         Addstr(line);
  204.         continue;
  205.         }
  206. #endif /* SUNTOOL */
  207.         if (ison(flags, INDENT))
  208.         fputs(indent_str, fp);
  209.         if (!fp) {
  210.         if (do_pager(line, FALSE) == EOF)
  211.             return -1;
  212.         } else if (fputs(line, fp) == EOF)
  213.         /* Pipe broken, out of file space, etc */
  214.         return -1;
  215.     }
  216.     }
  217.     if (ison(flags, INDENT) &&
  218.     (indent_str = do_set(set_options, "post_indent_str")) && *indent_str) {
  219.     char *old_fmt = hdr_format;
  220.     hdr_format = indent_str;
  221.     fprintf(fp, "%s\n", compose_hdr(n)+9); /* magic number 9 !! */
  222.     hdr_format = old_fmt;
  223.     }
  224. #ifdef SUNTOOL
  225.     if (istool && (!fp || fp == stdout)) {
  226.     unlock_cursors();
  227.     txt.y = still_more = msg_rect.r_height;
  228.     scroll_win(0);  /* causes a display */
  229.     }
  230. #endif /* SUNTOOL */
  231.     return lines;
  232. }
  233.  
  234. /*
  235.  * copy tempfile back to folder.
  236.  * Return 1 on success, 0 on failure.
  237.  */
  238. copyback(prompt)
  239. char *prompt;
  240. {
  241.     register int    i=0, j=0, k=0;
  242.     register long    flg = 0;
  243.     register FILE    *mbox = NULL_FILE, *mail_fp = NULL_FILE;
  244. #ifndef DOT_LOCK
  245. #ifdef SYSV
  246.     FILE         *save_mail_fp = NULL_FILE;
  247. #endif /* SYSV */
  248. #endif /* !DOT_LOCK */
  249.     char        *mbox_file, action = 0;
  250.     int         hold = 0, delete_it = 0, dont_unlink = FALSE;
  251.     int            isspool, keepsave;
  252.     static int        first = 1;
  253.  
  254.     /*
  255.      * if there is new mail in this folder, the user is notified and
  256.      * prompted if he really wants to update the folder.  He's either
  257.      * quitting or changing folders, so let him read the new mail first.
  258.      */
  259.     if (!first && check_new_mail() > 0) {
  260.     if (!istool) {
  261.         char buf[16];
  262.         if (iscurses)
  263.         putchar('\n'), turnon(glob_flags, CNTD_CMD);
  264.         print("%s [n] ", prompt);
  265.         buf[0] = 0;
  266.         if (!Getstr(buf, sizeof (buf), 0) || lower(*buf) != 'y')
  267.         return 0;
  268.     }
  269.     }
  270.     first = 0;
  271.  
  272.     /* If the user hasn't changed anything, just return true */
  273.     if (isoff(glob_flags, DO_UPDATE))
  274.     return 1;
  275.     if (ison(glob_flags, READ_ONLY)) {
  276.     print("Unable to update %s: read only\n", mailfile);
  277.     return 0; /* user should use "exit" instead of "quit". */
  278.     }
  279.     if (!msg_cnt) /* prevent unnecessary overwrite */
  280.     return 1;
  281.  
  282. #ifdef SUNTOOL
  283.     if (istool) {
  284.     timerclear(&(mail_timer.it_interval));
  285.     timerclear(&(mail_timer.it_value));
  286.     }
  287. #endif /* SUNTOOL */
  288.  
  289.     /* open mbox if: "autodelete" AND "hold" are NOT set. */
  290.     if (!strcmp(mailfile, spoolfile)
  291.         && !(delete_it = !!do_set(set_options, "autodelete"))
  292.         && !(hold = !!do_set(set_options, "hold"))) {
  293.     register char *p;
  294.     int x = 1; /* tell getpath to ignore "ENOENT" if file not found */
  295.  
  296.     if (!(p = do_set(set_options, "mbox")))
  297.         p = DEF_MBOX;
  298.     mbox_file = getpath(p, &x);
  299.     if (x) {
  300.         if (x > 0)
  301.         print("%s is a directory.\n", mbox_file);
  302.         else
  303.         print("Unable to open %s: %s\n", p, mbox_file);
  304.         mbox = NULL_FILE;
  305.     } else {
  306.         if (Access(mbox_file, F_OK) == -1) /* does it exist? */
  307.         mbox = mask_fopen(mbox_file, "w");
  308.         else
  309.         mbox = mask_fopen(mbox_file, "a");
  310.         if (!mbox)
  311.         error("Unable to write to %s", mbox_file);
  312.     }
  313.     }
  314. #ifdef DOT_LOCK
  315.     if ((i = dot_lock(mailfile)) == 0)
  316. #endif /* DOT_LOCK */
  317. #ifdef DOT_LOCK
  318.     mail_fp = mask_fopen(mailfile, "w+");
  319. #else /* !DOT_LOCK */
  320.     /* We can't lock a file unless we have an fd, but "w+" will zero
  321.      * the file.  If the lock later failed for any reason (possible
  322.      * race condition with an MTA), we would lose all current mail.
  323.      * So, open read/write (if possible) and truncate later.
  324.      */
  325.     mail_fp = mask_fopen(mailfile, "r+");
  326. #endif /* DOT_LOCK */
  327.     if (!mail_fp) {
  328.     error("Unable to rewrite %s", mailfile);
  329.     if (mbox)
  330.         fclose(mbox);
  331.     return 0;
  332.     }
  333.     if (i != 0 || lock_file(mailfile, mail_fp) == -1) {
  334. #ifndef DOT_LOCK
  335.     error("WARNING: unable to lock %s", mailfile);
  336. #endif /* DOT_LOCK */
  337.     if (mail_fp)
  338.         close_lock(mailfile, mail_fp);
  339.     if (mbox)
  340.         fclose(mbox);
  341.     return 0;
  342.     }
  343. #if !defined(DOT_LOCK) && defined(SYSV)
  344.     /* SysV can't truncate a file in the middle, so we can't just
  345.      * write to mail_fp and close.  Instead, we save the mail_fp
  346.      * and reopen for writing, ignoring our own lock.  After updating,
  347.      * we can safely fclose both file pointers.
  348.      */
  349.     save_mail_fp = mail_fp;
  350.     /* This could fail if we run out of file descriptors */
  351.     if (!(mail_fp = fopen(mailfile, "w"))) {
  352.     error("WARNING: unable to reopen %s for update", mailfile);
  353.     if (save_mail_fp)
  354.         close_lock(mailfile, save_mail_fp);
  355.     if (mbox)
  356.         fclose(mbox);
  357.     return 0;
  358.     }
  359. #endif /* SYSV && !DOT_LOCK */
  360.  
  361.     print("Updating \"%s\"", mailfile);
  362.  
  363.     turnon(flg, UPDATE_STATUS);
  364.     turnon(glob_flags, IGN_SIGS);
  365.  
  366.     keepsave = !!do_set(set_options, "keepsave");
  367.     isspool = !strcmp(mailfile, spoolfile);
  368.  
  369.     for (i = 0; i < msg_cnt; i++)
  370.     /* check to see if message is marked for deletion or, if read and not
  371.      * preserved, delete it if autodelete is set. Otherwise, save the
  372.      * message in the spool file if hold is set. If all fails, save in mbox.
  373.      */
  374.     if (ison(msg[i].m_flags, DELETE)
  375.     ||  ison(msg[i].m_flags, SAVED) && !keepsave &&
  376.         isoff(msg[i].m_flags, PRESERVE) && isspool
  377.     ||  isoff(msg[i].m_flags, UNREAD) && isoff(msg[i].m_flags, PRESERVE) 
  378.         && delete_it) {
  379.         Debug("%s %d",
  380.         (action!='d')? "\ndeleting message:" : "", i+1), action = 'd';
  381.         continue;
  382.     } else if (ison(msg[i].m_flags, UNREAD) ||
  383.          ison(msg[i].m_flags, PRESERVE) || hold || !mbox) {
  384.         j++;
  385.         Debug("%s %d",
  386.         (action!='s')? "\nsaving in spool:" : "", i+1), action = 's';
  387.         if (copy_msg(i, mail_fp, flg) == -1) {
  388.         error("WARNING: unable to write back to spool");
  389.         print("ALL mail left in %s\n", tempfile);
  390.         print("Spool mailbox may be corrupted.\n");
  391.         dont_unlink = TRUE;
  392.         break;
  393.         }
  394.     } else if (isspool) {   /* copy back to mbox */
  395.         k++;
  396.         if (copy_msg(i, mbox, flg) == -1) {
  397.         error("WARNING: unable to write to mbox");
  398.         print("Unresolved mail left in %s\n", tempfile);
  399.         dont_unlink = TRUE;
  400.         break;
  401.         }
  402.         Debug("%s %d",
  403.         (action!='m')? "\nsaving in mbox:" : "", i+1), action = 'm';
  404.     }
  405.     Debug("\n%s", mailfile);
  406.  
  407. #ifndef DOT_LOCK
  408. #ifdef SYSV
  409.     /* Close the write file pointer first */
  410.     fclose(mail_fp);
  411.     mail_fp = save_mail_fp;
  412. #else /* !SYSV */
  413.     /* Truncate the file at the end of what we just wrote.
  414.      * If you aren't SYSV and you still can't ftruncate(),
  415.      * you're out of luck?
  416.      */
  417.     (void) ftruncate(fileno(mail_fp), ftell(mail_fp));
  418. #endif /* SYSV */
  419. #endif /* !DOT_LOCK */
  420.  
  421.     close_lock(mailfile, mail_fp);
  422.  
  423. #ifdef SUNTOOL
  424.     if (istool) {
  425.     mail_timer.it_value.tv_sec = time_out;
  426.     setitimer(ITIMER_REAL, &mail_timer, NULL);
  427.     }
  428. #endif /* SUNTOOL */
  429.  
  430.     /* some users like to have zero length folders for frequent usage */
  431.     if (mbox)
  432.     fclose(mbox);
  433.     if (j) {
  434.     long times[2];
  435.     times[1] = time(×[0]) - (long)2;
  436.     if (!strcmp(mailfile, spoolfile) && utime(mailfile, times))
  437.         error("utime");
  438.     print_more(": saved %d message%s\n", j, (j==1)? NO_STRING: "s");
  439.     } else
  440. #ifdef HOMEMAIL
  441.     if (!dont_unlink && !do_set(set_options, "save_empty"))
  442. #else /* HOMEMAIL */
  443.     if (strcmp(mailfile, spoolfile) && !dont_unlink &&
  444.     !do_set(set_options, "save_empty"))
  445. #endif /* HOMEMAIL */
  446.     if (unlink(mailfile))
  447.         turnon(glob_flags, CONT_PRNT), error(": cannot remove");
  448.     else
  449.         print_more(": removed\n");
  450.     else
  451.     print_more(": empty\n");
  452.     if (k)
  453.     print("saved %d message%s in %s\n",k,(k==1)? NO_STRING:"s", mbox_file);
  454.  
  455.     turnoff(glob_flags, IGN_SIGS);
  456.  
  457.     return 1;
  458. }
  459.  
  460. /*
  461.  * check the sizes of the current folder (file) and the spool file.
  462.  * spool_size is the size in bytes of the user's main mailbox.
  463.  * last_size is the size of the _current_ folder the last time we checked.
  464.  * return true if the current folder has new mail.  check_new_mail() checks
  465.  * for new mail in the system mailbox since it checks against last_spool_size.
  466.  */
  467. mail_size()
  468. {
  469.     struct stat buf;
  470.     if (strcmp(mailfile, spoolfile) && !stat(spoolfile, &buf))
  471.     spool_size = buf.st_size;
  472.     if (!*mailfile)
  473.     return 0;
  474.     if (stat(mailfile, &buf)) {
  475.     if (errno != ENOENT)
  476.         error("Unable to stat %s", mailfile);
  477.     return 0;
  478.     }
  479.     if (!strcmp(mailfile, spoolfile))
  480.     spool_size = buf.st_size;
  481.     if (buf.st_size != last_size) {
  482.     last_size = buf.st_size;
  483.     return 1;
  484.     }
  485.     return 0;
  486. }
  487.  
  488. void
  489. mail_status(as_prompt)
  490. {
  491.     static char buf[256];
  492.     register int cnt = 0, new = 0, unread = 0, deleted = 0;
  493.  
  494.     for ( ; cnt < msg_cnt; cnt++) {
  495.     if (ison(msg[cnt].m_flags, UNREAD))
  496.         unread++;
  497.     if (ison(msg[cnt].m_flags, DELETE))
  498.         deleted++;
  499.     if (isoff(msg[cnt].m_flags, OLD))
  500.         new++;
  501.     }
  502.     if (as_prompt) {
  503.     register char *p, *b = buf;
  504.     for (p = prompt; *p; p++)
  505.         if (*p == '\\')
  506.         switch (*++p) {
  507.             case 'n': case 'r': *b++ = '\n';
  508.             when 't': *b++ = '\t';
  509.             otherwise: *b++ = *p;
  510.         }
  511.         else if (*p == '%')
  512.         switch (*++p) {
  513.             case 'm':
  514.             b += strlen(sprintf(b,"%d",(msg_cnt)? current_msg+1:0));
  515.             when 't':
  516.             b += strlen(sprintf(b, "%d", msg_cnt));
  517.             when 'd':
  518.             b += strlen(sprintf(b, "%d", deleted));
  519.             when 'u':
  520.             b += strlen(sprintf(b, "%d", unread));
  521.             when 'n':
  522.             b += strlen(sprintf(b, "%d", new));
  523.             when 'f':
  524.             {
  525.             char *tail = rindex(mailfile, '/'); 
  526.             if (tail && tail[1])
  527.                 b += Strcpy(b, tail+1);
  528.             else
  529.                 /* Fall through */
  530.             case 'F':
  531.             b += Strcpy(b, mailfile);
  532.             if (ison(glob_flags, READ_ONLY))
  533.                 b += Strcpy(b, " [read-only]");
  534.             }
  535.             when 'T': case 'D': case 'Y': case 'y':
  536.             case 'M': case 'N': case 'W':
  537.             b += Strcpy(b, Time(p, (long)0));
  538.             otherwise: *b++ = *p;
  539.         }
  540.         else if (*p == '!')
  541.         b += strlen(sprintf(b, "%d", hist_no+1));
  542.         else
  543.         *b++ = *p;
  544.     *b = 0;
  545.     print("%s", buf); /* use %s in case "buf" has any %'s in it */
  546.     return;
  547.     }
  548.     (void) sprintf(buf,"\"%s\"%s: %d message%s, %d new, %d unread",
  549.     mailfile, ison(glob_flags, READ_ONLY)? " [read only]" : "",
  550.     msg_cnt, (msg_cnt != 1)? "s": NO_STRING, new, unread);
  551.     if (istool || iscurses)
  552.     (void) sprintf(buf+strlen(buf), ", %d deleted", deleted);
  553. #ifdef SUNTOOL
  554.     if (istool) {
  555.     static char ic_text[4];
  556.     extern struct pixrect mail_icon_image1, mail_icon_image2;
  557.     (void) sprintf(ic_text, "%3d", msg_cnt);
  558.     tool_set_attributes(tool,
  559.         WIN_LABEL, buf,
  560.         WIN_ICON_LABEL, ic_text,
  561.         WIN_ICON_IMAGE, ison(glob_flags, NEW_MAIL)?
  562.         &mail_icon_image2 : &mail_icon_image1,
  563.         0);
  564.     } else
  565. #endif /* SUNTOOL */
  566. #ifdef CURSES
  567.     if (iscurses) {
  568.         move (0, 0);
  569.         printw("%-3d %-.*s",
  570.         ((msg_cnt)? current_msg+1 : 0), COLS-5, buf), clrtoeol();
  571.     } else
  572. #endif /* CURSES */
  573.         puts(buf);
  574.     return;
  575. }
  576.  
  577. /*
  578.  *  For uucp mailers that use >From lines with "remote from <path>":
  579.  * (where "path" is a hostname or pathnames)
  580.  *
  581.  *  a. Set the return_path to the empty string.
  582.  *  b. For each From_ or >From_ line:
  583.  *  c. Save the username (second token).
  584.  *  d. Save the date (3-7 tokens).
  585.  *  e. If it has a "remote from" then append the remote host
  586.  *    (last token) followed by a "!" to the return_path.
  587.  *  f. If the saved username has a '@' but no '!' then convert it
  588.  *    to UUCP path form.
  589.  *  g. Append the saved username to return_path.
  590.  */
  591. parse_from(fp, path)
  592. FILE *fp;
  593. char path[];
  594. {
  595.     char user[256], buf[256]; /* max size for each line in a mail file */
  596.     register char *p;
  597.     long save_offset = ftell(fp);
  598.  
  599.     path[0] = '\0';
  600.     while (fgets(buf, sizeof buf, fp)) {
  601.     if (strncmp(buf, ">From ", 6))
  602.         break;
  603.     p = buf + 6;
  604.  
  605.     (void) sscanf(p, "%s", user);
  606.  
  607.     while (p = index(p+1, 'r')) {
  608.         if (!strncmp(p, "remote from ", 12)) {
  609.         char *p2 = path+strlen(path);
  610.         skipspaces(12);
  611.         sscanf(p, "%s", p2); /* add the new machine to current path */
  612.         (void) strcat(p2, "!");
  613.         break;
  614.         }
  615.     }
  616.  
  617.     if (p)
  618.         (void) bang_form(path + strlen(path), user);
  619.     save_offset = ftell(fp);
  620.     }
  621.     fseek(fp, save_offset, L_SET);
  622. }
  623.  
  624. /*
  625.  * Scan a file and select messages from it and append them to the current folder
  626.  *
  627.  * If "append" is 1, start where we left off (held in msg[cnt].m_offset)
  628.  * and scan for messages.  Append all messages found until EOF.
  629.  *
  630.  * If "append" is 2, we're merging in a new file, so start at the end of
  631.  * the present folder and append all messages found until EOF.
  632.  *
  633.  * If "append" is 0, then the message separator must exist once and
  634.  * only once.  All extra occurrences of the separator is preceded by a '>'.
  635.  * The list argument will be the message number to replace in the current
  636.  * folder with the message read in from other filename.
  637.  */
  638. load_folder(file, append, list)
  639. char *file, *list;
  640. int append;
  641. {
  642.     char    buf[BUFSIZ];
  643.     int        lines = 0, msg_found = 0, had_error = 1;
  644.     int        get_status = 1, cnt;
  645.     long    bytes, ftell();
  646.     struct msg  old;
  647.     char    wkday[4], month[4];
  648.     int        day, year, mins, hour;
  649.     FILE       *fp;
  650. #ifdef MMDF
  651.     int        begin_sep = 0; /* track beginning vs ending separators */
  652. #endif /* MMDF */
  653.  
  654.     if (!(fp = fopen(file, "r"))) {
  655.     error("Unable to open %s", file);
  656.     return -1;
  657.     }
  658.  
  659.     if (append) {
  660.     cnt = msg_cnt;
  661.     (void) fseek(fp, append == 1 ? msg[cnt].m_offset : 0L, L_SET);
  662.     } else {
  663.     cnt = (int)list;
  664.     old = msg[cnt];
  665.     }
  666.  
  667.     if (isoff(glob_flags, READ_ONLY)) {
  668.     if (tmpf)
  669.         (void) fclose(tmpf);
  670.     if (!(tmpf = mask_fopen(tempfile, "a"))) {
  671.         error("Unable to open %s for appending", tempfile);
  672.         (void) fclose(fp);
  673.         return -1;
  674.     }
  675.     (void) fseek(tmpf, 0L, 2); /* assure we're at the end of the file */
  676.     } else if (append == 2) {
  677.     /* you can't merge in a folder to a read-only folder */
  678.     (void) fclose(fp);
  679.     return -1;
  680.     }
  681.  
  682. #ifdef MMDF
  683.     if (!append) {
  684.     strcpy(buf, MSG_SEPARATOR);
  685.     goto do_headers;
  686.     }
  687. #endif /* MMDF */
  688.     while (fgets(buf, sizeof (buf), fp)) {
  689. #ifndef MSG_SEPARATOR
  690.     if (!strncmp(buf, "From ", 5) &&
  691.         /* From uucp Wed Jan 11 20:40:00 1989 */
  692.         (sscanf(buf+5, "%*s %3s %3s %d %d:%d:%*d %d",
  693.         wkday, month, &day, &hour, &mins, &year) == 6 ||
  694.         /* From uucp Wed Jan 11 20:40:00 PST 1989 */
  695.         sscanf(buf+5, "%*s %3s %3s %d %d:%d:%*d %*s %d",
  696.             wkday, month, &day, &hour, &mins, &year) == 6 ||
  697.         /* From uucp Wed Jan 11 20:40 PST 1989 */
  698.         sscanf(buf+5, "%*s %3s %3s %d %d:%d %*s %d",
  699.             wkday, month, &day, &hour, &mins, &year) == 6))
  700. #else /* MSG_SEPARATOR */
  701.     if (!strncmp(buf, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
  702. #endif /* MSG_SEPARATOR */
  703.     {
  704. #ifdef MMDF
  705.         if (!append)
  706.         fputc('>', tmpf);
  707.         else if (begin_sep = !begin_sep)
  708. do_headers:
  709. #else /* MMDF */
  710.         if (!append && msg_found)
  711.         fputc('>', tmpf);
  712.         else
  713. #endif /* MMDF */
  714.         {
  715.         msg_found++;
  716.         had_error = 0;
  717.         if (append && cnt == MAXMSGS-2) {
  718.             wprint("WARNING: exceeded %d messages.\n", MAXMSGS);
  719.             wprint("Not all messages have been loaded.\n");
  720.             had_error++;
  721.             break;
  722.         }
  723.         if (ison(glob_flags, READ_ONLY))
  724.             bytes = ftell(fp) - strlen(buf);
  725.         else {
  726.             char path[256];
  727.             parse_from(fp, path);
  728.             if (path[0])
  729.             (void) sprintf(buf, "From %s %s %s %d %d:%d:00 %d\n",
  730.                 path, wkday, month, day, hour, mins, year);
  731.             bytes = ftell(tmpf);
  732.         }
  733.         /* finish up message structure from previous message.
  734.          * if this is incorporating new mail, check "lines" to
  735.          * see if previous message has already been set!
  736.          */
  737.         if (cnt && lines) {
  738.             msg[cnt-1].m_size = bytes - msg[cnt-1].m_offset;
  739.             msg[cnt-1].m_lines = lines;
  740.         }
  741.         if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) {
  742.             error(tempfile);
  743.             had_error++;
  744.             break;
  745.         }
  746.         msg[cnt].m_offset = bytes;
  747.         msg[cnt].m_flags = 0L;
  748.         lines = 0;
  749. #ifndef MSG_SEPARATOR
  750.         if (year > 1900)
  751.             year -= 1900;
  752.         (void) sprintf(buf, "%02d%02d%02d%02d%02d%.3s",
  753.             year, month_to_n(month), day, hour, mins, wkday);
  754.         strdup(msg[cnt].m_date_recv, buf);
  755. #endif /* MSG_SEPARATOR */
  756.         turnon(msg[cnt].m_flags, UNREAD); /* initialize */
  757.  
  758.         /* we've read the "From " line(s), now read the rest of
  759.          * the message headers till we get to a blank line.
  760.          */
  761.         while (fgets(buf, sizeof (buf), fp) && (*buf != '\n')) {
  762.             register char *p = buf;
  763.             if (!strncmp(buf, "Date:", 5))
  764.             strdup(msg[cnt].m_date_sent, parse_date(p+5));
  765.             if (get_status &&
  766.             !(get_status = strncmp(p, "Status:", 7))) {
  767.             /* new mail should not have a Status: field! */
  768.             turnon(msg[cnt].m_flags, OLD);
  769.             for (p += 8 ; *p != '\n'; p++)
  770.                 switch(*p) {
  771.                 case 'R': turnoff(msg[cnt].m_flags, UNREAD);
  772.                 when 'P': turnon(msg[cnt].m_flags, UNREAD);
  773.                 when 'S': turnon(msg[cnt].m_flags, SAVED);
  774.                 when 'r': turnon(msg[cnt].m_flags, REPLIED);
  775.                 when 'O': ; /* do nothing */
  776.                 otherwise :
  777.                     if (ison(glob_flags, WARNING))
  778.                     print("unknown msg status flag: %c",*p);
  779.                 }
  780.             }
  781.             if (isoff(glob_flags,READ_ONLY) && fputs(buf, tmpf) == -1) {
  782.             error(tempfile);
  783.             had_error++;
  784.             break;
  785.             }
  786.             lines++;
  787.         }
  788.         if (!msg[cnt].m_date_sent || !*msg[cnt].m_date_sent)
  789.             if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv) {
  790.             wprint("Message %d has *no* date!?\n", cnt+1);
  791.             msg[cnt].m_date_sent = msg[cnt].m_date_recv =
  792.                 "0000000000XXX";
  793.             } else
  794.             strdup(msg[cnt].m_date_sent, msg[cnt].m_date_recv);
  795.         else if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv)
  796.             strdup(msg[cnt].m_date_recv, msg[cnt].m_date_sent);
  797.         if (had_error)
  798.             break;
  799.         if (append && list)
  800.             set_msg_bit(list, cnt);
  801.         if (append)
  802.             cnt = ++msg_cnt;
  803.         get_status = 1;
  804.         }
  805.     }
  806.     if (msg_found) {
  807.         lines++;
  808.         if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) {
  809.         error(tempfile);
  810.         had_error++;
  811.         break;
  812.         }
  813.     }
  814.     }
  815.     if (msg_found && append != 1)
  816.     turnon(glob_flags, DO_UPDATE);
  817. #ifdef MMDF
  818.     if (!append)
  819.     fputs(END_MSG_SEP, tmpf);
  820. #endif /* MMDF */
  821.     if (had_error) {
  822.     if (!append)
  823.         msg[cnt] = old;
  824.     if (!msg_found && !append)
  825.         print("File not left in correct message format.\n");
  826.     } else {
  827.     if (append)
  828.         cnt--;
  829.     if (isoff(glob_flags, READ_ONLY))
  830.         msg[cnt].m_size = ftell(tmpf) - msg[cnt].m_offset;
  831.     else
  832.         msg[cnt].m_size = ftell(fp) - msg[cnt].m_offset;
  833.     msg[cnt].m_lines = lines;
  834.     /* remember where we were to seek to for when we append new mail */ 
  835.     if (append)
  836.         cnt++;
  837.     }
  838.     if (append)
  839.     msg[cnt].m_offset = ftell(fp);
  840.     fclose(fp);
  841.     if (isoff(glob_flags, READ_ONLY)) {
  842.     fclose(tmpf);
  843.     if (!(tmpf = fopen(tempfile, "r"))) {
  844.         error("Unable to open %s for reading", tempfile);
  845.         return -1;
  846.     }
  847.     }
  848.     return !had_error;
  849. }
  850.