home *** CD-ROM | disk | FTP | other *** search
- /* @(#)msgs.c (c) copyright 10/18/86 (Dan Heller) */
-
- #include "mush.h"
- #ifdef SYSV
- #ifndef USG
- #include <sys/locking.h>
- #else /* USG */
- #include <unistd.h>
- #endif /* USG */
- #endif /* SYSV */
-
- lock_file(filename, fd)
- char *filename;
- {
- #ifdef SYSV
- #ifndef USG
- (void) locking(fd, LK_LOCK, 0); /* xenix */
- #else
- /* if unable to lock, tell them */
- if (Access(filename, W_OK) || lockf(fd, F_TLOCK, 0)) /* system-v */
- return -1;
- #endif /* USG */
- #else
- #ifdef BSD
- if (flock(fd, LOCK_SH)) /* if exclusively locked, flock blocks */
- return -1;
- #else /* BSD */
- "There is no supported file locking function compiled in this version!";
- #endif /* BSD */
- #endif /* SYSV */
- return 0;
- }
-
- close_lock(fp)
- FILE *fp;
- {
- #ifdef SYSV
- #ifndef USG
- locking(fileno(fp), LK_UNLCK, 0);
- #else
- lockf(fileno(fp), F_ULOCK, 0);
- #endif /* USG */
- #endif /* SYSV */
- fclose(fp); /* implicit unlock for BSD */
- }
-
- void
- display_msg(n, flg)
- register int n;
- long flg;
- {
- register FILE *pp;
-
- if (ison(msg[n].m_flags, DELETE)) {
- print("Message %d deleted; ", n+1);
- #ifdef SUNTOOL
- if (istool)
- print_more("Select UNDELETE to read."), do_clear();
- else
- #endif /* SUNTOOL */
- if (iscurses)
- print_more("Type 'u' to undelete.");
- else
- print("Type 'undelete %d' to undelete\n", n+1);
- return;
- }
- set_isread(n);
- if (ison(flg, TOP)) {
- turnon(flg, NO_HEADER);
- print("Top of "), turnon(glob_flags, CONT_PRNT);
- }
-
- if (!istool && isoff(flg, NO_PAGE) &&
- crt < msg[n].m_lines && isoff(flg, TOP)) {
- char buf[32], *pager = do_set(set_options, "pager");
- if (!pager)
- pager = DEF_PAGER;
- if (!*pager || !strcmp(pager, "internal"))
- pager = NULL; /* default to internal pager if pager set to "" */
- (void) do_pager(pager, TRUE); /* start pager */
- (void) do_pager(sprintf(buf, "Message #%d (%d lines)\n",
- n+1, msg[n].m_lines), FALSE);
- (void) copy_msg(n, NULL_FILE, flg);
- (void) do_pager(NULL, FALSE); /* end pager */
- } else {
- print("Message #%d (%d lines)\n", n+1, msg[n].m_lines);
- (void) copy_msg(n, stdout, flg);
- }
- }
-
- /*
- * copy message 'n' to file "fp" according to various flag arguments
- * return number of lines copied or -1 if system error on fputs.
- * If "fp" is null, send to internal pager. This can only happen from
- * display_msg above.
- */
- copy_msg(n, fp, flags)
- register int n;
- long flags;
- register FILE *fp;
- {
- register int ignoring = 0, lines = 0;
- register char *indent_str;
- int on_hdr = 1, top, squeeze = FALSE;
- char line[BUFSIZ], *show_hdrs = NULL;
-
- still_more = 0;
- if (ison(flags, TOP)) {
- register char *p = do_set(set_options, "toplines");
- top = (p)? atoi(p) : crt;
- }
- /* When updating to a folder, always write all headers! */
- if (ison(flags, UPDATE_STATUS))
- turnon(flags, NO_IGNORE);
- else if (do_set(set_options, "alwaysignore"))
- turnoff(flags, NO_IGNORE);
- if (isoff(flags, NO_IGNORE)) {
- if (do_set(set_options, "squeeze"))
- squeeze = TRUE;
- show_hdrs = do_set(set_options, "show_hdrs");
- }
-
- #ifdef SUNTOOL
- if (istool && (!fp || fp == stdout)) {
- register int x = (msg[n].m_lines + 2) * l_height(curfont);
-
- if (x > 32765) { /* to overcome a bug in pixrects that sun won't fix */
- print("message too big to display using this font");
- return 0;
- }
- if (x < msg_rect.r_height) /* make it at least as big as the window */
- x = msg_rect.r_height;
- /* If the window isn't big enough, an inifite loop occurs in Addstr */
- if (x < 2 * l_height(curfont) || msg_rect.r_width < 3*l_width(curfont))
- return 0;
- do_clear();
- lock_cursors();
- /* msg_pix is for Addstr() */
- if (!(msg_pix = mem_create(msg_rect.r_width, x, 1))) {
- error("mem_create");
- return 0;
- }
- pr_rop(msg_pix, 0,0, msg_rect.r_width-1, x-1, PIX_CLR, 0,0,0);
- on_hdr = 1;
- }
- #endif /* SUNTOOL */
- if (ison(flags, INDENT)) {
- if ((indent_str = do_set(set_options, "pre_indent_str"))) {
- char *old_fmt = hdr_format;
- hdr_format = indent_str;
- fprintf(fp, "%s\n", compose_hdr(n) + 9); /* magic number 9 !! */
- hdr_format = old_fmt;
- }
- if (!(indent_str = do_set(set_options, "indent_str")))
- indent_str = DEF_INDENT_STR;
- }
- if (fseek(tmpf, msg[n].m_offset, L_SET) == -1) {
- error("Unable to find msg %d", n+1);
- return -1;
- }
- while (still_more < msg[n].m_size && fgets(line, BUFSIZ, tmpf)) {
- still_more += strlen(line);
- /*
- * If squeeze is one, all blanks lines squeeze down to one blank line.
- * If squeeze is two, squeezing is in progress so wait for the next \n.
- */
- if (*line == '\n') {
- if (on_hdr) /* blank line -- end of header */
- turnoff(flags, NO_HEADER), on_hdr = 0;
- if (squeeze > 1)
- continue;
- else if (squeeze)
- squeeze = 2;
- } else if (squeeze > 1)
- squeeze = 1;
-
- if (ison(flags, UPDATE_STATUS))
- if (!strncmp(line, "Status:", 7))
- continue; /* ignore this and other "Status" lines */
- else if (!on_hdr) {
- /* preserve NEW/UNREAD status on preserved messages */
- register char *p = line;
- p += Strcpy(p, "Status: O");
- if (isoff(msg[n].m_flags, UNREAD) &&
- isoff(msg[n].m_flags, PRESERVE))
- *p++ = 'R';
- if (ison(msg[n].m_flags, REPLIED))
- *p++ = 'r';
- *p++ = '\n', *p = 0;
- fputs(line, fp);
- (void) strcpy(line, "\n");
- turnoff(flags, UPDATE_STATUS);
- }
- if (on_hdr && isoff(flags, NO_IGNORE)) {
- register char *p = any(line, " \t:");
- if (!p)
- ignoring = 0, on_hdr = 0;
- else if (ignoring)
- if (*p != ':') {
- Debug("Ignoring: %s", line);
- continue;
- } else
- ignoring = 0;
- if (p && *p == ':') {
- *p = 0;
- ignoring = 0;
- if (show_hdrs) {
- if (!chk_two_lists(line, show_hdrs, ":, \t"))
- ignoring = 1;
- } else {
- register struct options *opts;
- for (opts = ignore_hdr; opts; opts = opts->next)
- if (!lcase_strcmp(opts->option, line)) {
- ignoring = 1;
- break;
- }
- }
- *p = ':';
- if (ignoring) {
- Debug("Ignoring: %s", line);
- continue;
- }
- }
- }
- if (!on_hdr && ison(flags, TOP) && !--top)
- break;
- if (isoff(flags, NO_HEADER)) {
- /* note that function returns the number of lines */
- lines++;
- #ifdef SUNTOOL
- if (istool && (!fp || fp == stdout)) {
- Addstr(line);
- continue;
- }
- #endif /* SUNTOOL */
- if (ison(flags, INDENT))
- fputs(indent_str, fp);
- if (!fp) {
- if (do_pager(line, FALSE) == EOF)
- return -1;
- } else if (fputs(line, fp) == EOF)
- /* Pipe broken, out of filespace, etc */
- return -1;
- }
- }
- if (ison(flags, INDENT) &&
- (indent_str = do_set(set_options, "post_indent_str")) && *indent_str) {
- char *old_fmt = hdr_format;
- hdr_format = indent_str;
- fprintf(fp, "%s\n", compose_hdr(n)+9); /* magic number 9 !! */
- hdr_format = old_fmt;
- }
- #ifdef SUNTOOL
- if (istool && (!fp || fp == stdout)) {
- unlock_cursors();
- txt.y = still_more = msg_rect.r_height;
- scroll_win(0); /* causes a display */
- }
- #endif /* SUNTOOL */
- return lines;
- }
-
- /* get mail from whatever the mailfile points to. open a tempfile for
- * appending, then close it and reopen it for read-only. some systems
- * have flakey read/write access.
- */
- void
- getmail()
- {
- register FILE *mail_fp;
- int lines = 0, get_status = 1, len;
- long ftell(), bytes;
- char line[BUFSIZ];
-
- #ifdef SYSV
- /* for SVID systems to lock, the file must be open for read/write */
- if (isoff(glob_flags, READ_ONLY))
- mail_fp = fopen(mailfile, "r+");
- else
- #endif /* SYSV */
- mail_fp = fopen(mailfile, "r");
-
- if (!mail_fp) {
- error("Unable to open %s", mailfile);
- return;
- }
- /*
- * since this file is usually open for read-only, close it and then
- * reopen it for appending. This is done to compensate for errors
- * in XENIX and to play it safe with non-essentially writable files.
- * see more notes below (end of proc).
- */
- if (isoff(glob_flags, READ_ONLY)) {
- int omask = umask(077);
-
- (void) fclose(tmpf);
- tmpf = fopen(tempfile, "a");
- (void) umask(omask);
- if (!tmpf) {
- error("Unable to open %s for appending", tempfile);
- (void) fclose(mail_fp);
- return;
- }
- } else if (msg_cnt)
- (void) fseek(tmpf, msg[msg_cnt-1].m_offset+msg[msg_cnt-1].m_size,L_SET);
-
- if (isoff(glob_flags, READ_ONLY) && lock_file(mailfile, fileno(mail_fp)))
- error("WARNING: unable to lock %s", mailfile);
-
- (void) fseek(mail_fp, ftell(tmpf), L_SET);
-
- #ifdef MSG_SEPARATOR
- len = strlen(MSG_SEPARATOR);
- #endif /* MSG_SEPARATOR */
-
- while (fgets(line, BUFSIZ, mail_fp) != NULL) {
- #ifndef MSG_SEPARATOR
- if (!strncmp(line, "From ", 5) &&
- !sscanf(line+5, "%*s %*s %*s %*d %*d:%*d"))
- #else /* MSG_SEPARATOR */
- if (!strncmp(line, MSG_SEPARATOR, len))
- #endif /* MSG_SEPARATOR */
- {
- if (msg_cnt == MAXMSGS-1) {
- print("WARNING: exceeded %d messages.\n", MAXMSGS);
- print("You should split \"%s\" into smaller files.\n",mailfile);
- /* make sure that tempfile isn't removed!! */
- turnon(glob_flags, IGN_SIGS);
- cleanup(0); /* probably a more elegant way to exit, but... */
- }
- bytes = ftell(tmpf);
- /* finish up message structure from previous message.
- * if this is incorporating new mail, check "lines" to
- * see if previous message has already been set!
- */
- if (msg_cnt && lines) {
- msg[msg_cnt-1].m_size = bytes - msg[msg_cnt-1].m_offset;
- msg[msg_cnt-1].m_lines = lines;
- }
- msg[msg_cnt].m_offset = bytes;
- msg[msg_cnt].m_flags = lines = 0;
- turnon(msg[msg_cnt].m_flags, UNREAD); /* initialize */
-
- if (isoff(glob_flags, READ_ONLY)) {
- fputs(line, tmpf);
- if (errno == ENOSPC)
- fs_error();
- }
- /* we've read the "From " line, now read the rest of
- * the message headers till we get to a blank line.
- */
- while (fgets(line, BUFSIZ, mail_fp) && (*line != '\n')) {
- register char *p = line;
- if (get_status && !(get_status = strncmp(p, "Status:", 7))) {
- turnon(msg[msg_cnt].m_flags, OLD);
- for (p += 8 ; *p != '\n'; p++)
- switch(*p) {
- when 'R': turnoff(msg[msg_cnt].m_flags, UNREAD);
- when 'P': turnon(msg[msg_cnt].m_flags, UNREAD);
- when 'r': turnon(msg[msg_cnt].m_flags, REPLIED);
- otherwise :
- if (ison(glob_flags, WARNING))
- print("unknown msg status flag: %c", *p);
- }
- }
- lines++;
- if (isoff(glob_flags, READ_ONLY)) {
- fputs(line, tmpf);
- if (errno == ENOSPC)
- fs_error();
- }
- }
- msg_cnt++, get_status = 1;
- }
- lines++;
- if (isoff(glob_flags, READ_ONLY)) {
- fputs(line, tmpf);
- if (errno == ENOSPC)
- fs_error();
- } else
- (void) fseek(tmpf, ftell(mail_fp), L_SET);
- }
- /* msg_cnt may be 0 if there is an error with the format of mailfile */
- if (msg_cnt) {
- msg[msg_cnt-1].m_size = ftell(tmpf) - msg[msg_cnt-1].m_offset;
- msg[msg_cnt-1].m_lines = lines;
- }
-
- close_lock(mail_fp);
-
- /* I've had problems with sys-v opening a file for read/write. I'd
- * try fgets after a seek to an arbitrary place and get NULL. "w+"
- * could be broken (XENIX), so play it safe anyway.
- */
- if (isoff(glob_flags, READ_ONLY)) {
- fclose(tmpf);
- if (!(tmpf = fopen(tempfile, "r")))
- error("unable to open %s for reading", tempfile);
- }
- }
-
- fs_error()
- {
- error("WARNING: unable to write to \"%s\"", tempfile);
- print("Read the manual on what to do on full file systems.\n");
- cleanup(0);
- }
-
- /*
- * copy temp or whatever back to mailfile
- * Return 0 if new mail came and user doesn't want to exit.
- */
- copyback()
- {
- register int new = 0, i, j=0, k=0;
- register long flg = 0;
- register FILE *mbox = NULL_FILE, *mail_fp;
- char *mbox_file, action = 0;
- int hold = 0, delete_it = 0, dont_unlink = FALSE;
-
- #ifdef SUNTOOL
- if (istool) {
- timerclear(&(mail_timer.it_interval));
- timerclear(&(mail_timer.it_value));
- }
- #endif /* SUNTOOL */
- if (ison(glob_flags, READ_ONLY)) {
- print("Unable to update %s: read only\n", mailfile);
- return 1;
- }
- if (check_new_mail()) {
- new = 1;
- if (!istool) {
- char buf[256];
- if (iscurses)
- putchar('\n');
- print("Really quit? ");
- buf[0] = 0;
- if (!Getstr(buf, 256, 0) || lower(*buf) != 'y')
- return 0;
- }
- } else if (!msg_cnt) /* prevent unnecessary overwrite */
- return 0;
- /* open mbox if: "autodelete" AND "hold" are NOT set. */
- if (!strcmp(mailfile, spoolfile)
- && !(delete_it = !!do_set(set_options, "autodelete"))
- && !(hold = !!do_set(set_options, "hold"))) {
- register char *p;
- int x = 1; /* tell getpath to ignore "ENOENT" if file not found */
-
- if (!(p = do_set(set_options, "mbox")))
- p = DEF_MBOX;
- mbox_file = getpath(p, &x);
- if (x) {
- if (x > 0)
- print("%s is a directory.\n", mbox_file);
- else
- print("Unable to open %s: %s\n", p, mbox_file);
- mbox = NULL_FILE;
- } else {
- if (Access(mbox_file, F_OK) == -1) /* does it exist? */
- mbox = fopen(mbox_file, "w");
- else
- mbox = fopen(mbox_file, "a");
- if (!mbox)
- error("Unable to write to %s", mbox_file);
- }
- }
- /* reopen the mailfile; set umask accordingly */
- {
- int omask = umask(077);
- mail_fp = fopen(mailfile, "w+");
- (void) umask(omask);
- if (!mail_fp) {
- error("Unable to rewrite %s", mailfile);
- return 0;
- }
- }
- turnon(glob_flags, IGN_SIGS);
- print("Updating \"%s\"", mailfile);
-
- if (lock_file(mailfile, fileno(mail_fp)))
- error("WARNING: unable to lock %s", mailfile);
-
- turnon(flg, UPDATE_STATUS);
- turnon(flg, NO_IGNORE);
-
- for (i = 0; i < msg_cnt; i++)
- /* check to see if message is marked for deletion or, if read and not
- * preserved, delete it if autodelete is set. Otherwise, save the
- * message in the spool file if hold is set. If all fails, save in mbox.
- */
- if (ison(msg[i].m_flags, DELETE)
- || isoff(msg[i].m_flags, UNREAD) && isoff(msg[i].m_flags, PRESERVE)
- && delete_it) {
- Debug("%s %d",
- (action!='d')? "\ndeleting message:" : "", i+1), action = 'd';
- continue;
- } else if (ison(msg[i].m_flags, UNREAD) ||
- ison(msg[i].m_flags, PRESERVE) || hold || !mbox) {
- j++;
- Debug("%s %d",
- (action!='s')? "\nsaving in spool:" : "", i+1), action = 's';
- if (copy_msg(i, mail_fp, flg) == -1) {
- error("WARNING: unable to write back to spool");
- print("ALL mail left in %s\n", tempfile);
- print("Spool mailbox may be corrupted.\n");
- if (new)
- print("New mail may be lost. :-(\n");
- dont_unlink = TRUE;
- break;
- }
- } else if (!strcmp(mailfile, spoolfile)) { /* copy back to mbox */
- k++;
- if (copy_msg(i, mbox, flg) == -1) {
- error("WARNING: unable to write to mbox");
- print("Unresolved mail left in %s\n", tempfile);
- dont_unlink = TRUE;
- break;
- }
- Debug("%s %d",
- (action!='m')? "\nsaving in mbox:" : "", i+1), action = 'm';
- }
- Debug("\n%s", mailfile);
-
- close_lock(mail_fp);
-
- if (mbox)
- fclose(mbox);
- if (j) {
- long times[2];
- times[1] = time(×[0]) - (long)2;
- if (!strcmp(mailfile, spoolfile) && utime(mailfile, times))
- error("utime");
- print_more(": saved %d message%s\n", j, (j==1)? NO_STRING: "s");
- } else if (strcmp(mailfile, spoolfile) && !dont_unlink && !new)
- if (unlink(mailfile))
- turnon(glob_flags, CONT_PRNT), error(": cannot remove");
- else
- print_more(": removed\n");
- else
- print_more(": empty\n");
- if (k)
- print("saved %d message%s in %s\n",k,(k==1)? NO_STRING: "s",mbox_file);
- if (new && !istool)
- print("New mail has arrived.\n");
- turnoff(glob_flags, IGN_SIGS);
- #ifdef SUNTOOL
- if (istool) {
- mail_timer.it_value.tv_sec = time_out;
- setitimer(ITIMER_REAL, &mail_timer, NULL);
- }
- #endif /* SUNTOOL */
- return 1;
- }
-
- mail_size()
- {
- struct stat buf;
- if (strcmp(mailfile, spoolfile)) {
- char tmp[128];
- if (!stat(sprintf(tmp, "%s/%s", MAILDIR, login), &buf))
- spool_size = buf.st_size;
- }
- if (!*mailfile)
- return 0;
- if (stat(mailfile, &buf)) {
- if (errno != ENOENT)
- error("Unable to stat %s", mailfile);
- return 0;
- }
- if (!strcmp(mailfile, spoolfile))
- spool_size = buf.st_size;
- if (buf.st_size > last_size) {
- last_size = buf.st_size;
- return 1;
- }
- return 0;
- }
-
- void
- mail_status(as_prompt)
- {
- static char buf[256];
- register int cnt = 0, new = 0, unread = 0, deleted = 0;
-
- for ( ; cnt < msg_cnt; cnt++) {
- if (ison(msg[cnt].m_flags, UNREAD))
- unread++;
- if (ison(msg[cnt].m_flags, DELETE))
- deleted++;
- if (isoff(msg[cnt].m_flags, OLD))
- new++;
- }
- if (as_prompt) {
- register char *p, *b = buf;
- for (p = prompt; *p; p++)
- if (*p == '\\')
- switch (*++p) {
- case 'n': case 'r': *b++ = '\n';
- when 't': *b++ = '\t';
- otherwise: *b++ = *p;
- }
- else if (*p == '%')
- switch (*++p) {
- case 'm':
- b += strlen(sprintf(b,"%d",(msg_cnt)? current_msg+1:0));
- when 't':
- b += strlen(sprintf(b, "%d", msg_cnt));
- when 'd':
- b += strlen(sprintf(b, "%d", deleted));
- when 'u':
- b += strlen(sprintf(b, "%d", unread));
- when 'n':
- b += strlen(sprintf(b, "%d", new));
- when 'f':
- b += Strcpy(b, mailfile);
- if (ison(glob_flags, READ_ONLY))
- b += Strcpy(b, " [read only]");
- when 'T': case 'D': case 'Y': case 'M': case 'N':
- b += Strcpy(b, Time(p, (long)0));
- otherwise: *b++ = *p;
- }
- else if (*p == '!')
- b += strlen(sprintf(b, "%d", hist_no+1));
- else
- *b++ = *p;
- *b = 0;
- print("%s", buf); /* buf MIGHT have a % in it... don't pass as fmt */
- return;
- }
- (void) sprintf(buf,"\"%s\"%s: %d message%s, %d new, %d unread",
- mailfile, ison(glob_flags, READ_ONLY)? " [read only]" : "",
- msg_cnt, (msg_cnt != 1)? "s": NO_STRING, new, unread);
- if (istool || iscurses)
- (void) sprintf(buf+strlen(buf), ", %d deleted", deleted);
- #ifdef SUNTOOL
- if (istool) {
- static char ic_text[4];
- extern struct pixrect mail_icon_image1, mail_icon_image2;
- (void) sprintf(ic_text, "%3d", msg_cnt);
- tool_set_attributes(tool,
- WIN_LABEL, buf,
- WIN_ICON_LABEL, ic_text,
- WIN_ICON_IMAGE, ison(glob_flags, NEW_MAIL)?
- &mail_icon_image2 : &mail_icon_image1,
- 0);
- } else
- #endif /* SUNTOOL */
- #ifdef CURSES
- if (iscurses)
- mvprintw(0, 0, "%-3d %-.*s",
- ((msg_cnt)? current_msg+1 : 0), COLS-5, buf), clrtoeol();
- else
- #endif /* CURSES */
- puts(buf);
- return;
- }
-
- /* return -1 since function doesn't affect messages */
- check_flags(flags)
- u_long flags;
- {
- print_more(" ");
- if (ison(flags, VERBOSE))
- print_more("VERBOSE ");
- if (ison(flags, INCLUDE))
- print_more("INCLUDE ");
- if (ison(flags, INCLUDE_H))
- print_more("INCLUDE_H ");
- if (ison(flags, EDIT))
- print_more("EDIT ");
- if (ison(flags, SIGN))
- print_more("SIGN ");
- if (ison(flags, DO_FORTUNE))
- print_more("DO_FORTUNE ");
- if (ison(flags, NO_HEADER))
- print_more("NO_HEADER ");
- if (ison(flags, DELETE))
- print_more("DELETE ");
- if (ison(flags, OLD))
- print_more("OLD ");
- if (ison(flags, UNREAD))
- print_more("UNREAD ");
- if (ison(flags, UPDATE_STATUS))
- print_more("UPDATE_STATUS ");
- if (ison(flags, NO_PAGE))
- print_more("NO_PAGE ");
- if (ison(flags, INDENT))
- print_more("INDENT ");
- if (ison(flags, NO_IGNORE))
- print_more("NO_IGNORE ");
- if (ison(flags, PRESERVE))
- print_more("PRESERVE ");
- print_more("\n");
- return -1;
- }
-