/* @(#)folders.c	(c) copyright 10/18/86 (Dan Heller) */

#include "mush.h"

static char oldfolder[MAXPATHLEN];

/* folder %[user]  --new mailfile is the spool/mail/login file [user].
 * folder #  --new mailfile is the folder previous to the current folder
 * folder &  --new mailfile is ~/mbox (or whatever "mbox" is set to)
 * folder +file --new mailfile is in the directory "folder"; name is 'file'
 * folder "path" --full path name or the one in current working directory.
 *
 * in all cases, changes are updated unless a '!' is specified after the
 * folder command (e.g. "f!", "folder !" "fo!" .. all permutations)
 * as usual, if new mail has arrived before the file is copied back, then
 * user will be notified beforehand.
 *
 * RETURN -1 on error -- else return 0. All bits in msg_list are set to true.
 */
folder(argc, argv, list)
register char **argv;
char list[];
{
    int n, updating = !strcmp(*argv, "update"), do_read_only = 0, no_hdrs = 0;
    char *tmp, *newfolder = NULL, buf[MAXPATHLEN];
    struct stat statbuf;
    extern long last_spool_size;

    if (ison(glob_flags, IS_PIPE)) {
	print("You can't pipe to the %s command.\n", *argv);
	return -1;
    } else if (ison(glob_flags, IS_SENDING)) {
	print("You can't use the %s command when sending.\n", *argv);
	return -1;
    } else if (!tempfile || !*tempfile) {
	print("You can't use the %s command in init files.\n", *argv);
	return -1;
    }
    while (*++argv && (**argv == '-' || **argv == '!'))
	if (!strcmp(*argv, "-N"))
	    no_hdrs = !iscurses;
	else if (!updating && !strcmp(*argv, "-n"))
	    turnoff(glob_flags, DO_UPDATE);
	else if (!strcmp(*argv, "-r"))
	    do_read_only = 1;
	else if (!strcmp(*argv, "!")) {
	    if (updating)
		turnon(glob_flags, DO_UPDATE);	/* useful? */
	    else
		turnoff(glob_flags, DO_UPDATE);
	} else
	    return help(0, "folder", cmd_help);

    if (updating) {
	(void) strcpy(buf, mailfile);
	if (ison(glob_flags, READ_ONLY))
	    do_read_only = 1;
    } else {
	if (!*argv) {
	    mail_status(0);
	    return 0;
	}
	if (!strcmp(*argv, "#"))
	    if (!*oldfolder) {
		print("No previous folder\n");
		return -1;
	    } else
		newfolder = oldfolder;
	else if (!strcmp(*argv, "&")) {
	    if (!(newfolder = do_set(set_options, "mbox")) || !*newfolder)
		newfolder = DEF_MBOX;
	} else
	    newfolder = *argv;
	n = 0;
	tmp = getpath(newfolder, &n);
	if (n == -1) {
	    print("%s: %s\n", newfolder, tmp);
	    return -1;
	} else if (n == 1) {
	    print("%s: is a directory\n", tmp);
	    return -1;
	}
	/* strcpy so copyback() below (which calls getpath) doesn't change
	 * the data that tmp intended to point to.  Get the cwd if necessary.
	 */
	n = 0;
	if (*tmp != '/') {
	    if (!GetCwd(buf, sizeof buf)) {
		error("getcwd: %s",buf);
		return -1;
	    }
	    n = strlen(buf);
	    buf[n++] = '/';
	}
	(void) strcpy(&buf[n], tmp);
    }
#ifdef SUNTOOL
    if (istool > 1)
	timeout_cursors(TRUE);
#endif /* SUNTOOL */
    if (stat(buf, &statbuf) == -1 || !(statbuf.st_mode & 0400)) {
	error("Unable to read %s", buf);
#ifdef SUNTOOL
	if (istool > 1)
	    timeout_cursors(FALSE);
#endif /* SUNTOOL */
	return -1;
    }
    /* If the file can't be opened for writing, autoset READ_ONLY */
    if (!(statbuf.st_mode & 0200))
	do_read_only = 1;

    if (!(n=copyback(updating?"Update folder?":"Change anyway?",!updating))) {
#ifdef SUNTOOL
	if (istool > 1)
	    timeout_cursors(FALSE);
#endif /* SUNTOOL */
	/* an error occured updating the folder */
	return -1;
    }
    turnoff(glob_flags, CORRUPTED);	/* copyback() was successful */
    /* Assure that both oldfolder and mailfile are full paths */
    if (strcmp(mailfile, buf) || !*oldfolder) {
	n = 1; /* force load of new folder */
	if (!updating)
	    (void) strcpy(oldfolder, *oldfolder? mailfile : buf);
	strdup(mailfile, buf);
    }
    do_read_only? turnon(glob_flags,READ_ONLY) : turnoff(glob_flags,READ_ONLY);
    last_size = spool_size = 0L;
    while (msg_cnt--) {
	xfree(msg[msg_cnt].m_date_recv);
	xfree(msg[msg_cnt].m_date_sent);
	msg[msg_cnt].m_date_recv = msg[msg_cnt].m_date_sent = NO_STRING;
    }
    msg_cnt = 0, msg[0].m_offset = 0L;
    turnoff(glob_flags, CONT_PRNT);

    turnon(glob_flags, IGN_SIGS);
    /* clear the tempfile */
    if (tmpf)
	(void) fclose(tmpf);
    if (!do_read_only) {
	if (!(tmpf = mask_fopen(tempfile, "w"))) {
	    error("error truncating %s", tempfile);
	    turnoff(glob_flags, IGN_SIGS);
#ifdef SUNTOOL
	    if (istool > 1)
		timeout_cursors(FALSE);
#endif /* SUNTOOL */
	    return -1;
	}
    }
    /* Don't reload the folder if it was removed */
    if (n > 0) {
	if (load_folder(mailfile, TRUE, NULL) < 1) {
	    last_msg_cnt = 0;
	    last_size = statbuf.st_size; /* Disable check_new_mail() */
	    turnoff(glob_flags, IGN_SIGS);
#ifdef SUNTOOL
	    if (istool > 1)
		timeout_cursors(FALSE);
#endif /* SUNTOOL */
	    return -1;
	}
	if (do_read_only && !(tmpf = fopen(mailfile, "r"))) {
	    error(mailfile);
	    turnoff(glob_flags, IGN_SIGS);
#ifdef SUNTOOL
	    if (istool > 1)
		timeout_cursors(FALSE);
#endif /* SUNTOOL */
	    return -1;
	}
    }
    last_msg_cnt = msg_cnt;  /* for check_new_mail */
    /* Prevent both bogus "new mail" messages and missed new mail */
    last_size = msg[msg_cnt].m_offset;
    if (!strcmp(mailfile, spoolfile))
	spool_size = last_spool_size = last_size;
#ifdef SUNTOOL
    if (istool) {
	extern Panel_item folder_text_item;
	Rect *rect = (Rect *)window_get(hdr_sw, WIN_RECT);
	(void) pw_rop(hdr_win, 0,0, rect->r_width, rect->r_height, PIX_CLR,
	    (struct pixrect *) 0,0,0);
	panel_set_value(folder_text_item, mailfile);
    }
#endif /* SUNTOOL */

    if (!updating || current_msg >= msg_cnt)
	current_msg = (msg_cnt? 0 : -1);
    turnoff(glob_flags, IGN_SIGS);

    /* now sort messages according a user-defined default */
    if (!updating && msg_cnt > 1 && !strcmp(mailfile, spoolfile) &&
		(tmp = do_set(set_options, "sort"))) {
	(void) sprintf(buf, "sort %s", tmp);
	if ((argv = mk_argv(buf, &argc, TRUE)) && argc > 0) {
	    /* msg_list can't be null for do_command and since we're not
	     * interested in the result, call sort directly
	     */
	    (void) sort(argc, argv, NULL);
	    free_vec(argv);
	    if (!updating)
		current_msg = 0;	/* Sort may move the current message */
	}
    }
    turnoff(glob_flags, DO_UPDATE);

    /* go to first NEW message */
    for (n = 0; n < msg_cnt && ison(msg[n].m_flags, OLD); n++)
	;
    if (n == msg_cnt) {
	turnoff(glob_flags, NEW_MAIL);
	if (!updating) {
	    /* no new message found -- try first unread message */
	    for (n = 0; n < msg_cnt && isoff(msg[n].m_flags, UNREAD); n++)
		;
	}
    } else {
	turnon(glob_flags, NEW_MAIL);
	/* default for toolmode is true */
	if (istool && !chk_option("quiet", "tool"))
	    bell();
    }
    if (msg_cnt && (!updating || current_msg < 0))
	current_msg = (n == msg_cnt ? 0 : n);

    /* be quiet if we're piping */
    if (!istool && !updating && !no_hdrs && msg_cnt
	    && isoff(glob_flags, DO_PIPE)) {
	if ((!istool || istool && !msg_cnt) && !iscurses)
	    mail_status(0);
	(void) cmd_line(sprintf(buf, "headers %d", current_msg+1), msg_list);
    }
#ifdef SUNTOOL
    if (istool > 1) {
	if (!msg_cnt)
	    print("No Mail in %s\n", mailfile);
	if (msg_cnt) {
	    display_msg(current_msg, (long)0);
	    do_hdrs(0, DUBL_NULL, NULL);
	    /* Automatic display should not "touch" this message */
	    turnoff(msg[current_msg].m_flags, DO_UPDATE);
	    /* don't update folder just because a message is displayed */
	    turnoff(glob_flags, DO_UPDATE);
	}
	timeout_cursors(FALSE);
    }
#endif /* SUNTOOL */
    if (list) {
	clear_msg_list(list);
	bitput(list, list, msg_cnt, =~); /* macro */
    }
    return 0;
}

folders(argc, argv)
register char **argv;
{
    register char *p;
    char buf[128];
#ifndef MSGS_DYNAMIC
    char *unused[MAXMSGS_BITS];
#else
    char *unused = (char *) alloca(MSGS_BITS(msg_cnt));
#endif

    if (argv && argv[1] && !strcmp(argv[1], "-?"))
	return help(0, "folders", cmd_help);

    if (!(p = do_set(set_options, "folder")) || !*p)
	p = DEF_FOLDER;
    (void) sprintf(buf, "ls -FR %s", p);
    if (argv = make_command(buf, TRPL_NULL, &argc))
	return do_command(argc, argv, unused);
    return -1;
}

/*
 * Determine whether a file could be a folder.  If prompt is non-NULL,
 * ask the user whether we should treat the file as a folder anyway.
 */
test_folder(name, prompt)
char *name, *prompt;
{
    char line[BUFSIZ], *p;
    FILE *fp = fopen(name, "r");
    int retval = FALSE;

    if (!fp)
	return 0;
    if (fgets(line, sizeof line - 1, fp)) {
#ifndef MSG_SEPARATOR
	if (p = any(line, " \t")) {
	    skipspaces(1);
	    p = any(p, " \t");
	}
	if (p && !strncmp(line, "From ", 5) && (p = parse_date(p + 1)))
#else /* MSG_SEPARATOR */
	if (!strncmp(line, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
#endif /* MSG_SEPARATOR */
	    retval = TRUE;
    } else
	retval = TRUE;	/* Empty files are legitimate folders */
    (void) fclose(fp);
    if (prompt && !retval) {
	char buf[BUFSIZ];
#ifdef SUNTOOL
	if (istool) {
	    (void) sprintf(buf, "\"%s\": %s", name, prompt);
	    return ask(buf);
	}
#endif /* SUNTOOL */
	print("\"%s\": %s [n] ", name, prompt);
	buf[0] = 0;
	retval = (Getstr(buf, sizeof (buf), 0) && lower(*buf) == 'y');
    }
    return retval;
}

/* merge_folders filename  -- concatenate the folder specified by filename
 *                            to the current folder.
 *
 * RETURN -1 on error -- else return 0.  A bit in msg_list is set to true
 * for each of the "new" messages read in to the current folder.
 */
merge_folders(n, argv, list)
register char **argv, list[];
{
    int no_hdrs = 0, newest_msg;
    long orig_offset;
    char *tmp, *newfolder = NULL, buf[MAXPATHLEN];

    if (ison(glob_flags, IS_PIPE)) {
	print("You can't pipe to the %s command.\n", *argv);
	return -1;
    } else if (ison(glob_flags, IS_SENDING)) {
	print("You can't use the %s command while sending.\n", *argv);
	return -1;
    }

    while (*++argv && **argv == '-')
	if (!strcmp(*argv, "-?"))
	    return help(0, "merge", cmd_help);
	else if (!strcmp(*argv, "-N"))
	    no_hdrs = !(iscurses || ison(glob_flags, PRE_CURSES));

    if (!*argv)
	return 0;

    if (ison(glob_flags, READ_ONLY)) {
	print("Folder is read-only.\n");
	return -1;
    }

    if (!strcmp(*argv, "#"))
	if (!*oldfolder) {
	    print("No previous folder\n");
	    return -1;
	} else
	    newfolder = oldfolder;
    else if (!strcmp(*argv, "&")) {
	if (!(newfolder = do_set(set_options, "mbox")) || !*newfolder)
	    newfolder = DEF_MBOX;
    } else
	newfolder = *argv;
    n = 0;
    tmp = getpath(newfolder, &n);
    if (n == -1) {
	print("%s: %s\n", newfolder, tmp);
	return -1;
    } else if (n == 1) {
	print("%s: is a directory\n", tmp);
	return -1;
    }

    turnon(glob_flags, IGN_SIGS);
    orig_offset = msg[msg_cnt].m_offset;
    (void) load_folder(tmp, 2, list);
    msg[msg_cnt].m_offset = orig_offset;
    newest_msg = last_msg_cnt;
    Debug("newest_msg = %d\n", newest_msg);
    last_msg_cnt = msg_cnt;  /* for check_new_mail */
    Debug("msg_cnt = %d\n", msg_cnt);
    if (current_msg < 0)
	current_msg = 0;
    (void) mail_size();
    turnoff(glob_flags, IGN_SIGS);

    if ((!istool || istool && !msg_cnt)
	    && !iscurses && !ison(glob_flags, PRE_CURSES))
	mail_status(0);
    /* be quiet if we're piping or if told not to show headers */
    if ((istool || !no_hdrs) && isoff(glob_flags, DO_PIPE)
	    && newest_msg < msg_cnt)
	(void) cmd_line(sprintf(buf, "headers %d", newest_msg + 1), NULL);
    return 0;
}

/*
 * Default digest article separator
 */
#define ARTICLE_SEP "--------"

/*
 * Undigestify messages.  If a message is in digest-format, there are many
 * messages within this message which are to be extracted.  Kinda like a
 * folder within a folder.  By default, this routine will create a new
 * folder that contains the new messages.  -m option will merge the new
 * messages into the current folder.
 */
do_undigest(n, argv, list)
char *argv[], list[];
{
    int r, articles = 0, merge = 0, appending = 0;
    char buf[MAXPATHLEN], cmdbuf[MAXPATHLEN], *dir;
#ifndef MSGS_DYNAMIC
    char newlist[MAXMSGS_BITS];
#else
    char *newlist = (char *) alloca(MSGS_BITS(msg_cnt));
#endif
    char *art_sep = ARTICLE_SEP, *mktemp();
    FILE *fp;

    while (argv && *++argv && **argv == '-') {
	switch(argv[0][1]) {
	    case 'm':
		if (ison(glob_flags, READ_ONLY)) {
		    print("Folder is read only.\n");
		    return -1;
		}
		merge++;
	    when 'p':
		if (*++argv)
		    art_sep = *argv;
		else {
		    print("Specify separator pattern with -p.\n");
		    return -1;
		}
	    otherwise: return help(0, "undigest", cmd_help);
	}
    }

    if ((n = get_msg_list(argv, list)) == -1)
	return -1;

    argv += n;

    if (*argv) {
	int isdir = 1; /* Ignore file nonexistance errors */
	(void) strcpy(buf, getpath(*argv, &isdir));
	if (isdir < 0) {
	    print("%s: %s\n", *argv, buf);
	    return -1;
	} else if (isdir == 1) {
	    print("%s: is a directory\n", buf);
	    return -1;
	}
    } else {
	register char *p, *p2;
	if (Access(dir = ".", W_OK) == 0 ||
		(dir = do_set(set_options, "folder")) ||
		(dir = do_set(set_options, "tmpdir")))
	    dir = getdir(dir); /* expand metachars */
	if (!dir)
alted:
	    dir = ALTERNATE_HOME;
	for (n = 0; n < msg_cnt; n++)
	    if (msg_bit(list, n))
		break;

	if (!(p = header_field(n, "subject")))
	    (void) mktemp(sprintf(buf, "%s/digestXXXXX", dir));
	else {
	    if (!lcase_strncmp(p, "re: ", 4))
		p += 4;
	    for (p2 = p; *p2; p2++)
		if (!isalnum(*p2) && *p2 != '-' && *p2 != '.') {
		    *p2 = 0;
		    break;
		}
	    p2 = buf + Strcpy(buf, dir);
	    *p2++ = '/';
	    (void) strcpy(p2, p);
	}
    }

    if (!Access(buf, W_OK))
	appending = ((fp = mask_fopen(buf, "a")) != NULL_FILE);
    else
	fp = mask_fopen(buf, "w");
    if (!fp) {
	if (!*argv && strcmp(dir, ALTERNATE_HOME))
	    goto alted;
	error("can't create %s", buf);
	return -1;
    }

    for (n = 0; n < msg_cnt; n++) {
	if (!msg_bit(list, n))
	    continue;

	print("undigesting message %d\n", n+1);
	/* copy message into file making sure all headers exist. */
	r = undigest(n, fp, art_sep);
	if (r <= 0)
	    break;
	articles += r;
    }
    (void) fclose(fp);
    if (r <= 0) {
	if (!appending)
	    (void) unlink(buf);
	return -1;
    }
    if (merge) {
	(void) cmd_line(sprintf(cmdbuf, "\\merge -N %s", buf), newlist);
	(void) unlink(buf);
	print("Merged in %d messages.\n", articles);
    } else
	print("Added %d messages to \"%s\".\n", articles, buf);
    clear_msg_list(list);
    for (n = 0; n < msg_cnt; n++)
	if (msg_bit(newlist, n))
	    set_msg_bit(list, n);
    return 0;
}

/*
 * split digest-message 'n' to file "fp" using article separator "sep".
 * return number of articles copied or -1 if system error on fputs.
 * A digest is a folder-in-a-message in a special, semi-standard form.
 */
undigest(n, fp, sep)
int n;
FILE *fp;
char *sep;
{
    int  art_cnt = 0, on_hdr = -1; /* on_hdr is -1 if hdr not yet found */
    int  sep_len = (sep ? strlen(sep) : strlen(sep = ARTICLE_SEP));
    long get_hdr = 0L;
    char from[HDRSIZ], line[HDRSIZ], last_sep[HDRSIZ];
    char from_hdr[256], afrom[256], adate[64];
    char *fdate = "Xxx Xxx 00 00:00:00 0000"; /* Dummy date in ctime form */
    SIGRET (*oldint)(), (*oldquit)();

    if (!msg_get(n, from, sizeof from)) {
	error("Unable to find msg %d", n+1);
	return -1;
    }
#ifndef MSG_SEPARATOR
    else {
	char *p = from + 5;
	skipspaces(0);
	p = index(p, ' ');
	if (p) {
	    skipspaces(0);
	    fdate = p;
	}
	if (fputs(from, fp) == EOF)
	    return -1;
    }
#endif /* !MSG_SEPARATOR */

    on_intr();
    *afrom = *adate = *last_sep = '\0';
    while (ftell(tmpf) < msg[n].m_offset + msg[n].m_size &&
	   fgets(line, sizeof (line), tmpf)) {
	if (ison(glob_flags, WAS_INTR))
	    goto handle_error;
	if (*line == '\n' && on_hdr > 0)    /* blank line -- end of header */
	    on_hdr = 0;

	/* Check for the beginning of a digest article */
	if (!strncmp(line, sep, sep_len)) {
	    if (get_hdr) {
		if (do_set(set_options, "warning"))
		    print("Article with no header? (added to article #%d)\n",
				art_cnt);
		/* Don't start a new message for whatever this is,
		 * just fseek back and keep appending to the last one.
		 */
		if (fseek(tmpf, get_hdr, L_SET) < 0 ||
			fputs(last_sep, fp) == EOF) {
		    art_cnt = -1;
		    goto handle_error;
		}
		get_hdr = 0L;
		on_hdr = 0;
	    } else {
		(void) strcpy(last_sep, line);
		get_hdr = ftell(tmpf);
		*afrom = *adate = '\0';
		on_hdr = -1;	/* Haven't found the new header yet */
	    }
	    continue;
	}

	if (get_hdr) {
	    char *p = *line == '>' ? line + 1 : line;
	    if (*line == '\n') {
		if (*afrom || *adate) {
		    (void) fseek(tmpf, get_hdr, L_SET);
		    /* Terminate the previous article */
		    art_cnt++;
#ifdef MSG_SEPARATOR
#ifdef END_MSG_SEP
		    if (fputs(END_MSG_SEP, fp) == EOF) {
			art_cnt = -1;
			goto handle_error;
		    }
#endif /* END_MSG_SEP */
#ifdef MMDF
		    /* MMDF has a newline in MSG_SEPARATOR */
		    if (fputs(MSG_SEPARATOR, fp) == EOF)
#else /* !MMDF */
		    /* Other MSG_SEPARATORs need a newline */
		    if (fputs(MSG_SEPARATOR, fp) == EOF ||
			    fputc('\n', fp) == EOF)
#endif /* MMDF */
#else /* !MSG_SEPARATOR */
		    /* Everybody else needs a From_ line */
		    if (fprintf(fp, "From %s  %s", *afrom ? afrom : "unknown",
				*adate ? date_to_ctime(adate) : fdate) == EOF)
#endif /* MSG_SEPARATOR */
		    {
			art_cnt = -1;
			goto handle_error;
		    }
		    /* Make sure there is a From: without a leading > */
		    if (*afrom && *from_hdr && fputs(from_hdr, fp) == EOF) {
			art_cnt = -1;
			goto handle_error;
		    }
		    get_hdr = 0L;
		} else if (on_hdr < 0)
		    /* Skip blanks between "--------" and the hdr */
		    get_hdr = ftell(tmpf);
	    } else if (on_hdr < 0)
		on_hdr = 1;
	    if (on_hdr > 0 && !strncmp(p, "From: ", 6)) {
		(void) get_name_n_addr(p + 6, NULL, afrom);
		(void) no_newln(afrom);
		/* Get the From: minus the leading > */
		if (p != line)
		    (void) strcpy(from_hdr, p);
		else /* We don't need From: twice! */
		    *from_hdr = '\0';
	    } else if (on_hdr > 0 && !strncmp(line, "Date: ", 6)) {
		if (p = parse_date(line+6))
		    (void) strcpy(adate, p);
	    } else if (on_hdr > 0 && !lcase_strncmp(line, "end", 3)) {
		if (!*afrom && !*adate)
		    break;
	    }
	} else if (fputs(line, fp) == EOF) {
	    /* Pipe broken, out of file space, etc */
	    art_cnt = -1;
	    goto handle_error;
	}
    }
    ++art_cnt;
#ifdef END_MSG_SEP
    if (art_cnt > 0 && fputs(END_MSG_SEP, fp) == EOF) {
	art_cnt = -1;
	goto handle_error;
    }
#endif /* END_MSG_SEP */
    /* If we're still looking for a header, there is some stuff left
     * at the end of the digest.  Create an extra article for it.
     */
    if (get_hdr) {
	char *p;
	(void) fseek(tmpf, get_hdr, L_SET);
	if (ftell(tmpf) >= msg[n].m_offset + msg[n].m_size)
	    goto handle_error;
#ifdef MSG_SEPARATOR
#ifdef MMDF
	if (fputs(MSG_SEPARATOR, fp) == EOF)
#else /* !MMDF */
	if (fputs(MSG_SEPARATOR, fp) == EOF ||
		fputc('\n', fp) == EOF)
#endif /* MMDF */
#else /* !MSG_SEPARATOR */
	if (fputs(from, fp) == EOF)
#endif /* MSG_SEPARATOR */
	    art_cnt = -1;
	if (!(p = header_field(n, "from")))
	    p = "Mush-Undigest (Real author unknown)";
	if (fprintf(fp, "From: %s\n", p) == EOF)
	    art_cnt = -1;
	if (!(p = header_field(n, "date")))
	    p = fdate, (void) no_newln(p);
	if (fprintf(fp, "Date: %s\n", p) == EOF)
	    art_cnt = -1;
	if (!(p = header_field(n, "subject")))
	    p = "Digest";
	if (fprintf(fp, "Subject: Trailing part of %s\n\n", p) == EOF)
	    art_cnt = -1;
	/* header_field() moves the pointer, so seek again */
	(void) fseek(tmpf, get_hdr, L_SET);
	while (art_cnt > 0 && ftell(tmpf) < msg[n].m_offset + msg[n].m_size
		&& fgets(line, sizeof (line), tmpf)) {
	    if (fputs(line, fp) == EOF)
		art_cnt = -1;
#ifdef END_MSG_SEP
	    if (!strncmp(line, END_MSG_SEP, strlen(END_MSG_SEP)))
		break;
#endif /* END_MSG_SEP */
	}
	/* The END_MSG_SEP, if any, of the digest will have been output
	 * by the while loop above, so we don't need to add one here.
	 */
	++art_cnt;
    }
handle_error:
    if (art_cnt == -1)
	error("cannot completely undigest");
    else if (ison(glob_flags, WAS_INTR))
	art_cnt = -1;
    off_intr();
    return art_cnt;
}
