home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-03-13 | 34.2 KB | 1,417 lines |
- Article 999 of comp.sources.unix:
- Path: s.cc.purdue.edu!h.cc.purdue.edu!j.cc.purdue.edu!pur-ee!iuvax!inuxc!ihnp4!ptsfa!ames!amdcad!sun!pitstop!sundc!seismo!uunet!munnari!jz
- From: jz@mulga.oz.au (Justin Zobel)
- Newsgroups: comp.sources.unix
- Subject: v12i005: vmail - screen-based mail handler, Part02/03
- Message-ID: <1855@munnari.oz>
- Date: 13 Oct 87 21:15:31 GMT
- Sender: kre@munnari.oz
- Lines: 1403
- Approved: kre@munnari.oz.au
-
- Submitted by: jz@mulga.oz.au
- Posting-number: Volume 12, Issue 5
- Archive-name: vmail/Part02
-
- This is the second of three parts of vmail, an interactive mail handler
- that sits on top of MH.
- vmail has a number of advantages over raw MH. It is screen-based and
- faster (and more convenient) than the MH show-scan-rmm refile cycle.
- vmail makes it feasible for users to organise and keep track of moderate
- volumes of mail without wasting too much time, and is very simple to use.
- It has been in use at Melbourne University Computer Science Department
- for about six months without any problems, and has become the interface of
- choice for many users.
-
- : ---------------------------------------- cut here
-
- echo x - "call.c" 2>&1
- sed "s/^X//" >"call.c" <<'!The!End!'
- X/* --------------------
- X vmail -- call.c
- X
- X Routines that call MH equivalents, editor, shell.
- X
- X Copyright (C) J. Zobel, University of Melbourne, October 1987.
- X-------------------- */
- X
- X#include "defs.h"
- X#include <signal.h>
- X
- X#define WARNING "Warning -- mail headers may be out of date"
- X
- Xunion wait status;
- X
- X/* --------------------
- X Fork a call to `comp'.
- X Terminal type must be reset before call.
- X-------------------- */
- Xvoid
- Xcomp()
- X{
- X char *tmp, *argv[20], str[LEN], s1[LEN], *next_token();
- X int i, (*oldint)(), (*oldquit)(), (*signal())();
- X
- X *s1 = '\0';
- X if(comp_args) {
- X sprintf(str, "(give options to) comp ");
- X get_string(str, s1);
- X }
- X clear();
- X addstatus("composing mail ...", false);
- X move(STATUS+1, 0);
- X refresh();
- X top_level = false; /* used by tstp() so that right thing is done
- X when process is restarted */
- X if(! vfork()) {
- X argv[0] = COMP;
- X for(i=1, tmp=s1 ; *tmp != '\0' ; i++) {
- X argv[i] = tmp;
- X tmp = next_token(tmp);
- X }
- X argv[i] = 0;
- X no_control();
- X execv(COMP, argv);
- X printf("Warning: can't execute %s\n", COMP);
- X exit(0);
- X }
- X oldint = signal(SIGINT, SIG_IGN);
- X oldquit = signal(SIGQUIT, SIG_IGN);
- X wait(&status);
- X signal(SIGINT, oldint);
- X signal(SIGQUIT, oldquit);
- X top_level = true;
- X to_control();
- X hold_end(); /* wait for user to want to continue - may wish
- X to read error messages */
- X display_page();
- X addstatus(WARNING, true); /* vmail's data structures not updated */
- X}
- X
- X
- X/* --------------------
- X Fork a call to `forw'.
- X Terminal type must be reset before call.
- X-------------------- */
- Xvoid
- Xforw()
- X{
- X char *tmp, *argv[20], str[LEN], s1[LEN], s2[10], *next_token();
- X int i, (*oldint)(), (*oldquit)(), (*signal())();
- X
- X sprintf(s2, "%d", curmail->number);
- X *s1 = '\0';
- X if(forw_args) {
- X sprintf(str, "(give options to) forw +%s %s ", curflr->name, s2);
- X get_string(str, s1);
- X }
- X clear();
- X addstatus("forwarding mail ...", false);
- X move(STATUS+1, 0);
- X refresh();
- X top_level = false; /* used by tstp() so that right thing is done
- X when process is restarted */
- X if(! vfork()) {
- X sprintf(str, "+%s", curflr->name);
- X argv[0] = FORW; argv[1] = str; argv[2] = s2;
- X for(i=3, tmp=s1 ; *tmp != '\0' ; i++) {
- X argv[i] = tmp;
- X tmp = next_token(tmp);
- X }
- X argv[i] = 0;
- X no_control();
- X execv(FORW, argv);
- X printf("Warning: can't execute %s\n", FORW);
- X exit(0);
- X }
- X oldint = signal(SIGINT, SIG_IGN);
- X oldquit = signal(SIGQUIT, SIG_IGN);
- X wait(&status);
- X signal(SIGINT, oldint);
- X signal(SIGQUIT, oldquit);
- X top_level = true;
- X to_control();
- X hold_end(); /* wait for user to want to continue - may wish
- X to read error messages */
- X display_page();
- X addstatus(WARNING, true); /* vmail's data structures not updated */
- X}
- X
- X
- X/* --------------------
- X Fork a call to `repl'.
- X Terminal type must be reset before call.
- X-------------------- */
- Xvoid
- Xrepl()
- X{
- X char *tmp, *argv[20], str[LEN], s1[LEN], s2[10], *next_token();
- X int i, (*oldint)(), (*oldquit)(), (*signal())();
- X
- X sprintf(s2, "%d", curmail->number);
- X *s1 = '\0';
- X if(repl_args) {
- X sprintf(str, "(give options to) repl +%s %s ", curflr->name, s2);
- X get_string(str, s1);
- X }
- X clear();
- X addstatus("answering mail ...", false);
- X move(STATUS+1, 0);
- X refresh();
- X top_level = false; /* used by tstp() so that right thing is done
- X when process is restarted */
- X if(! vfork()) {
- X sprintf(str, "+%s", curflr->name);
- X argv[0] = REPL; argv[1] = str; argv[2] = s2;
- X for(i=3, tmp=s1 ; *tmp != '\0' ; i++) {
- X argv[i] = tmp;
- X tmp = next_token(tmp);
- X }
- X argv[i] = 0;
- X no_control();
- X execv(REPL, argv);
- X printf("Warning: can't execute %s\n", REPL);
- X exit(0);
- X }
- X oldint = signal(SIGINT, SIG_IGN);
- X oldquit = signal(SIGQUIT, SIG_IGN);
- X wait(&status);
- X signal(SIGINT, oldint);
- X signal(SIGQUIT, oldquit);
- X top_level = true;
- X to_control();
- X hold_end(); /* wait for user to want to continue - may wish
- X to read error messages */
- X display_page();
- X addstatus(WARNING, true); /* vmail's data structures not updated */
- X}
- X
- X
- X/* --------------------
- X Fork a call to editor.
- X Terminal type must be reset before call.
- X-------------------- */
- Xvoid
- Xedit()
- X{
- X char str[LEN];
- X int (*oldint)(), (*oldquit)(), (*signal())();
- X
- X clear();
- X mvaddstr(TITLE, 0, "editing mail ...");
- X move(STATUS, 0);
- X refresh();
- X top_level = false; /* used by tstp() so that right thing is done
- X when process is restarted */
- X if(! vfork()) {
- X no_control();
- X sprintf(str, "%s/%s/%d", mail_dir, curflr->name, curmail->number);
- X execlp(editor, editor, str, 0);
- X printf("Warning: can't execute %s\n", editor);
- X exit(0);
- X }
- X oldint = signal(SIGINT, SIG_IGN);
- X oldquit = signal(SIGQUIT, SIG_IGN);
- X wait(&status);
- X signal(SIGINT, oldint);
- X signal(SIGQUIT, oldquit);
- X top_level = true;
- X to_control();
- X hold_end(); /* wait for user to want to continue - may wish
- X to read error messages */
- X display_page();
- X}
- X
- X
- X/* --------------------
- X Fork a call to shell.
- X Terminal type must be reset before call.
- X
- X This should perhaps be modified so that only a single command can be
- X issued, as in vi ... but this was simpler to do.
- X-------------------- */
- Xvoid
- Xcall_shell()
- X{
- X int (*oldint)(), (*oldquit)(), (*signal())();
- X
- X clear();
- X mvaddstr(TITLE, 0, "calling shell ...");
- X move(STATUS, 0);
- X refresh();
- X top_level = false; /* used by tstp() so that right thing is done
- X when process is restarted */
- X if(! vfork()) {
- X no_control();
- X fix_mh();
- X execlp(shell, shell, "-i", 0);
- X printf("Warning: can't execute %s\n", shell);
- X exit(0);
- X }
- X oldint = signal(SIGINT, SIG_IGN);
- X oldquit = signal(SIGQUIT, SIG_IGN);
- X wait(&status);
- X signal(SIGINT, oldint);
- X signal(SIGQUIT, oldquit);
- X top_level = true;
- X to_control();
- X hold_end(); /* wait for user to want to continue - may wish
- X to read error messages */
- X display_page();
- X}
- X
- X
- X/* --------------------
- X Pipe current mail item into given command.
- X-------------------- */
- Xvoid
- Xdo_pipe()
- X{
- X char str[LEN], s1[LEN];
- X int (*oldint)(), (*oldquit)(), (*signal())();
- X
- X *s1 = '\0';
- X sprintf(str, "(give command to) show +%s %d | ", curflr->name,
- X curmail->number);
- X get_string(str, s1);
- X clear();
- X addstatus("piping mail ...", false);
- X move(STATUS+1, 0);
- X refresh();
- X sprintf(str, "%s %s/%s/%d | %s", CAT, mail_dir, curflr->name,
- X curmail->number, s1);
- X top_level = false; /* used by tstp() so that right thing is done
- X when process is restarted */
- X no_control();
- X oldint = signal(SIGINT, SIG_IGN);
- X oldquit = signal(SIGQUIT, SIG_IGN);
- X system(str); /* exec needs full path of command => use system */
- X signal(SIGINT, oldint);
- X signal(SIGQUIT, oldquit);
- X top_level = true;
- X to_control();
- X hold_end(); /* wait for user to want to continue - may wish
- X to read error messages */
- X display_page();
- X}
- !The!End!
-
- echo x - "choose.c" 2>&1
- sed "s/^X//" >"choose.c" <<'!The!End!'
- X/* --------------------
- X vmail -- choose.c
- X
- X Tty-based folder selection.
- X
- X Copyright (C) J. Zobel, University of Melbourne, October 1987.
- X-------------------- */
- X
- X#include "defs.h"
- X
- X#define START 10 /* offset from margin of screen */
- X#define RESET() toggle=false, /* left- or right- hand indicator */ \
- X i=FIRST+1, /* initial row */ \
- X j=START, /* initial column */ \
- X f=first /* first folder */
- X
- XWINDOW *chooser = (WINDOW *) NULL;
- X
- X/* --------------------
- X Display folder selection page, read commands to move around page and
- X select folders.
- X-------------------- */
- Xvoid
- Xchoose()
- X{
- X int n, i, j;
- X bool toggle;
- X folder next, f, showing(),
- X first = folders, /* first folder on screen */
- X last; /* folder after last folder on screen */
- X char c, str[LEN], flushin();
- X
- X RESET();
- X if(chooser == (WINDOW *) NULL)
- X chooser = newwin(0, 0, 0, 0);
- X last = showing(first);
- Xrestart:
- X while((c = flushin()) != ' ' && c != 'q') switch(c) {
- X case '\r': /* go to next screen of folder names */
- X case '\n':
- X if(last == (folder) NULL)
- X beep();
- X else {
- X first = last;
- X last = showing(first);
- X RESET();
- X }
- X break;
- X case '\b': /* go back one page of folders */
- X if(first == folders)
- X beep();
- X else {
- X for(i=(lines-FIRST)*2 ; i > FIRST && first->prev != (folder) NULL ; i--, first=first->prev)
- X ;
- X last = showing(first);
- X RESET();
- X }
- X break;
- X case CTRL_L: /* redraw */
- X last = showing(first);
- X break;
- X case 'h': /* move left */
- X if(! toggle) /* already at left */
- X beep();
- X else {
- X next = f;
- X FRST_OF_NAME(next);
- X next = next->prev;
- X if(next == (folder) NULL)
- X beep();
- X else {
- X f = next; j = START; toggle = false;
- X wmove(chooser, i, j);
- X wrefresh(chooser);
- X }
- X }
- X break;
- X case 'j': /* move down */
- X if(i+1 >= lines) /* at bottom */
- X beep();
- X else {
- X next = f;
- X for(n=0 ; n < 2 && next != (folder) NULL ; n++) {
- X LAST_OF_NAME(next);
- X next = next->next;
- X }
- X if(next == (folder) NULL)
- X beep();
- X else {
- X i++; f = next;
- X wmove(chooser, i, j);
- X wrefresh(chooser);
- X }
- X }
- X break;
- X case 'k': /* move up */
- X if(i <= FIRST+1) /* at top */
- X beep();
- X else {
- X next = f;
- X for(n=0 ; n < 2 && next != (folder) NULL ; n++) {
- X FRST_OF_NAME(next);
- X next = next->prev;
- X }
- X if(next == (folder) NULL)
- X beep();
- X else {
- X i--; f = next;
- X wmove(chooser, i, j);
- X wrefresh(chooser);
- X }
- X }
- X break;
- X case 'l': /* move right */
- X if(toggle) /* at right */
- X beep();
- X else {
- X next = f;
- X LAST_OF_NAME(next);
- X next = next->next;
- X if(next == (folder) NULL)
- X beep();
- X else {
- X f = next; j = cols/2; toggle = true;
- X wmove(chooser, i, j);
- X wrefresh(chooser);
- X }
- X }
- X break;
- X default:
- X beep();
- X break;
- X }
- X if(c == ' ') { /* attempt to go to folder */
- X if(! f->valid) { /* load folder */
- X mvwaddstr(chooser, FIRST, 0, "Reading mail headers ...");
- X wmove(chooser, i, j);
- X wrefresh(chooser);
- X f->valid = true;
- X find_mail(f, false);
- X }
- X if(f->valid == EMPTY) { /* folder is empty */
- X /* Go back to chooser, display "empty" message */
- X sprintf(str, "%s -- folder empty", f->name);
- X if(first == f) /* find new first folder for page */
- X if(f->next != (folder) NULL)
- X first = f->next;
- X else
- X first = folders;
- X last = showing(first);
- X RESET();
- X mvwaddstr(chooser, FIRST, 0, str);
- X wmove(chooser, i, j);
- X wrefresh(chooser);
- X goto restart;
- X }
- X curflr = f;
- X curmail = f->mail;
- X y = FIRST;
- X }
- X display_page();
- X}
- X
- X
- X/* --------------------
- X Show all folder names starting with "start" ending with last folder or
- X when page is full.
- X-------------------- */
- Xfolder
- Xshowing(start)
- X folder start;
- X{
- X int count, i = FIRST+1, j = START;
- X bool toggle = false;
- X folder p, f;
- X item m;
- X char str[LEN];
- X
- X wclear(chooser);
- X mvwaddstr(chooser, TITLE, 0,
- X"h,j,k,l -- left,down,up,right <return>,<bs> -- next/prev page of folders");
- X mvwaddstr(chooser, STATUS, 0,
- X"<space> -- select folder q -- quit, no change ^L -- refresh");
- X for(p=f=start ; i < lines && f != (folder) NULL ; p=f=p->next) {
- X if(f->valid) {
- X /* find last page of folder, count items in folders */
- X for(count=0, p=f ; p->next != (folder) NULL &&
- X p->next->name == f->name ; p=p->next)
- X for(m=p->mail ; m != (item) NULL ; m=m->next, count++)
- X ;
- X for(m=p->mail ; m != (item) NULL ; m=m->next, count++)
- X ;
- X if(count == 1)
- X sprintf(str, "%s: %d, 1 item", f->name, f->mail->number);
- X else
- X sprintf(str, "%s: %d-%d, %d items", f->name, f->mail->number,
- X p->last->number, count);
- X } else
- X sprintf(str, "%-15s(inactive)", f->name);
- X if(f == curflr) standout();
- X mvwaddstr(chooser, i, j, str);
- X if(f == curflr) standend();
- X if(toggle)
- X j = START, i++;
- X else
- X j = cols/2;
- X toggle = ! toggle;
- X }
- X wmove(chooser, FIRST+1, START);
- X wrefresh(chooser);
- X return(f);
- X}
- X
- X
- XWINDOW *folwin = (WINDOW *) NULL;
- X
- X/* --------------------
- X List all folders, active or otherwise.
- X-------------------- */
- Xvoid
- Xlist_folders()
- X{
- X folder f = folders, p;
- X int count, i = FIRST, half = cols/2;
- X bool toggle = false;
- X char str[LEN];
- X WINDOW *newwin();
- X item m;
- X
- X if(folwin == (WINDOW *) NULL)
- X folwin = newwin(0, 0, 0, 0);
- X wclear(folwin);
- X for(p=f ; ; p=f=p->next) {
- X if((i+2) % lines == 0) {
- X if(use_prompt(folwin) == 'q')
- X break;
- X i = FIRST;
- X wclear(folwin);
- X }
- X if(f == (folder) NULL) {
- X use_prompt(folwin);
- X break;
- X }
- X if(f->valid) {
- X /* find last page of folder, count items in folders */
- X for(count=0, p=f ; p->next != (folder) NULL &&
- X p->next->name == f->name ; p=p->next)
- X for(m=p->mail ; m != (item) NULL ; m=m->next, count++)
- X ;
- X for(m=p->mail ; m != (item) NULL ; m=m->next, count++)
- X ;
- X if(count == 1)
- X sprintf(str, "%s: %d, 1 item", f->name, f->mail->number);
- X else
- X sprintf(str, "%s: %d-%d, %d items", f->name, f->mail->number,
- X p->last->number, count);
- X } else
- X sprintf(str, "%-15s(inactive)", f->name);
- X if(f == curflr)
- X wstandout(folwin);
- X if(toggle) {
- X mvwaddstr(folwin, i, half, str);
- X i++;
- X } else
- X mvwaddstr(folwin, i, 10, str);
- X if(f == curflr)
- X wstandend(folwin);
- X toggle = !toggle;
- X }
- X display_page();
- X}
- !The!End!
-
- echo x - "cmds.c" 2>&1
- sed "s/^X//" >"cmds.c" <<'!The!End!'
- X/* --------------------
- X vmail -- cmds.c
- X
- X Commands not included in page.c or move.c.
- X
- X Copyright (C) J. Zobel, University of Melbourne, October 1987.
- X-------------------- */
- X
- X#include "defs.h"
- X#include <signal.h>
- X
- X/* --------------------
- X Print the name of the alternate folder.
- X-------------------- */
- Xvoid
- Xshow_folder()
- X{
- X char str[LEN];
- X
- X if(alternate == (folder) NULL)
- X addstatus("No alternate folder", false);
- X else {
- X sprintf(str, "alternate folder is %s\n", alternate->name);
- X addstatus(str, false);
- X }
- X}
- X
- X
- X/* --------------------
- X Make current folder inactive - remove list of mail headers, set valid
- X to false.
- X-------------------- */
- Xvoid
- Xinactive()
- X{
- X folder f, p;
- X
- X /* find first page of folder */
- X p = curflr; FRST_OF_NAME(p);
- X /* find last page of folder */
- X f = curflr; LAST_OF_NAME(f);
- X p->next = f->next;
- X p->valid = false;
- X/* should free records */
- X p->mail = p->last = (item) NULL;
- X p->pagenum = p->pages = 1;
- X if(p->next != (folder) NULL)
- X p->next->prev = p;
- X curflr = p;
- X NEXT_VALID(curflr);
- X if(curflr == (folder) NULL) {
- X curflr = p;
- X PREV_VALID(curflr);
- X }
- X if(curflr == (folder) NULL) {
- X addstatus("Making last active folder inactive", true);
- X to_normal();
- X exit(0);
- X } else {
- X curmail = curflr->mail;
- X y = FIRST;
- X display_page();
- X }
- X}
- X
- X
- X/* --------------------
- X Show current mail item with fork to pager.
- X-------------------- */
- Xvoid
- Xshow_mail()
- X{
- X int (*oldint)(), (*oldquit)(), (*signal())();
- X char str[LEN];
- X union wait status;
- X
- X clear();
- X refresh();
- X top_level = false; /* used by tstp() so that right thing is done
- X when process is restarted */
- X if(! vfork()) {
- X no_control();
- X sprintf(str, "%s/%s/%d", mail_dir, curflr->name, curmail->number);
- X execlp(pager, pager, str, 0);
- X printf("Warning: can't execute %s\n", pager);
- X exit(0);
- X }
- X oldint = signal(SIGINT, SIG_IGN);
- X oldquit = signal(SIGQUIT, SIG_IGN);
- X wait(&status);
- X signal(SIGINT, oldint);
- X signal(SIGQUIT, oldquit);
- X top_level = true;
- X to_control();
- X hold_end(); /* wait for user to want to continue - may wish
- X to read error messages */
- X display_page();
- X}
- X
- X
- X/* --------------------
- X Save current mail item to named file. If first non-space character
- X is ~, expand it.
- X-------------------- */
- Xvoid
- Xsave_item()
- X{
- X struct passwd *pwent, *getpwnam();
- X char *tmp, buf[LEN], *str = buf, save[LEN];
- X FILE *fi, *fo, *fopen();
- X
- X sprintf(save, "%s.%d", curflr->name, curmail->number);
- X sprintf(str, "file (%s)? ", save);
- X get_string(str, str);
- X for(; *str == ' ' ; str++)
- X ;
- X for(tmp=str ; *tmp != '\0' && *tmp != ' ' ; tmp++)
- X ;
- X *tmp = '\0';
- X if(*str != '\0') /* don't take default */
- X if(*str == '~') { /* expand home directory name */
- X tmp = str + 2;
- X if(*(str+1) == '/')
- X pwent = getpwnam(user);
- X else {
- X for( ; *tmp != '\0' && *tmp != '/' ; tmp++)
- X ;
- X *(tmp++) = '\0';
- X if((pwent = getpwnam(str+1)) == (struct passwd *) NULL) {
- X sprintf(save, "%s: no such user", str+1);
- X addstatus(save, true);
- X return;
- X }
- X }
- X sprintf(save, "%s/%s", pwent->pw_dir, tmp);
- X } else /* take str as given */
- X strcpy(save, str);
- X if((fo = fopen(save, "w")) == (FILE *) NULL) {
- X sprintf(str, "%s: no write permission", save);
- X addstatus(str, true);
- X return;
- X }
- X addstatus("saving ...", false);
- X sprintf(str, "%s/%s/%d", mail_dir, curflr->name, curmail->number);
- X fi = fopen(str, "r");
- X while(fgets(str, LEN, fi) != (char *) NULL)
- X fprintf(fo, "%s", str);
- X fclose(fi); fclose(fo);
- X addstatus("saved", false);
- X}
- !The!End!
-
- echo x - "find.c" 2>&1
- sed "s/^X//" >"find.c" <<'!The!End!'
- X/* --------------------
- X vmail -- find.c
- X
- X Searching titles for strings.
- X
- X Copyright (C) J. Zobel, University of Melbourne, October 1987.
- X-------------------- */
- X
- X#include "defs.h"
- X
- Xstatic char str[LEN] = "^.*";
- X
- X/* --------------------
- X Get string for searching, either forwards (forwards = true) or backwards
- X (forwards = false). Then scan mail headers using regex().
- X-------------------- */
- Xvoid
- Xsearch(forwards)
- X int forwards;
- X{
- X char s1[LEN], *s2, *re_comp();
- X int i;
- X bool found = false;
- X folder f;
- X item m;
- X
- X get_string((forwards) ? "/" : "?", s1);
- X if((i = strlen(s1)) > 0) {
- X /* new search string */
- X strcpy(str+3, s1);
- X str[i+=3] = '.', str[++i] = '*', str[++i] = '\0';
- X } else if(strlen(str+3) == 0) {
- X addstatus("", false);
- X return;
- X }
- X if((s2 = re_comp(str)) != (char *) NULL) {
- X addstatus(s2, false);
- X return;
- X }
- X addstatus("searching ...", false);
- X if(forwards)
- X for(i=y+1, f=curflr, m=curmail->next ; ! found && m != curmail ; ) {
- X if(m == (item) NULL) {
- X f = f->next; NEXT_VALID(f);
- X if(f == (folder) NULL) {
- X f = folders;
- X NEXT_VALID(f);
- X }
- X m = f->mail;
- X i = FIRST;
- X }
- X if(! (found = re_exec(m->title)))
- X m = m->next, i++;
- X }
- X else
- X for(i=y-1, f=curflr, m=curmail->prev ; ! found && m != curmail ; ) {
- X if(m == (item) NULL) {
- X f = f->prev; PREV_VALID(f);
- X if(f == (folder) NULL) {
- X /* find last folder */
- X for(f=folders ; f->next != (folder) NULL ; f=f->next)
- X ;
- X PREV_VALID(f);
- X }
- X /* find last mail item with count */
- X for(i=FIRST, m=f->mail ; m->next != (item) NULL ; i++,m=m->next)
- X ;
- X }
- X if(! (found = re_exec(m->title)))
- X m = m->prev, i--;
- X }
- X curmail = m, y = i;
- X if(f != curflr) {
- X curflr = f;
- X display_page();
- X } else if(! found) /* come back to current folder (known to be valid) */
- X addstatus("pattern not found", true);
- X else
- X addstatus("", false);
- X}
- !The!End!
-
- echo x - "inc.c" 2>&1
- sed "s/^X//" >"inc.c" <<'!The!End!'
- X/* --------------------
- X vmail -- inc.c
- X
- X Incorporate new mail with "inc", parse output and update appropriate
- X folder-pages.
- X
- X Copyright (C) J. Zobel, University of Melbourne, October 1987.
- X-------------------- */
- X
- X#include "defs.h"
- X
- X#define INCORP "Incorporating new mail into "
- X#define TAIL "...\n"
- X
- Xstatic folder isfol; /* folder into which mail is being incorporated */
- Xstatic item ismail; /* last item of mail on isfol page */
- Xstatic int count; /* number of items on isfol page */
- X
- X/* --------------------
- X Call, inc, parse output to work out what items have been read and into
- X what folders.
- X-------------------- */
- Xvoid
- Xinc()
- X{
- X char str[LEN], line[LEN], *tmp, *fgets();
- X FILE *pp, *fdopen();
- X int num, pd[2], len = strlen(INCORP), numbers();
- X bool redraw = true;
- X union wait status;
- X
- X addstatus("incorporating mail ... ", true);
- X pipe(pd);
- X if(! vfork()) {
- X close(pd[0]);
- X dup2(pd[1], 1);
- X close(pd[1]);
- X dup2(1, 2);
- X execl(INC, "inc", 0);
- X }
- X close(pd[1]);
- X if((pp = fdopen(pd[0], "r")) == (FILE *) NULL) {
- X addstatus("panic, can't incorporate mail", true);
- X return;
- X }
- X while((tmp = fgets(str, LEN, pp)) != (char *) NULL) /* read "inc" output */
- X if(strncmp(tmp, INCORP, len) == 0) { /* reading into new folder */
- X tmp += len;
- X tmp[strlen(tmp)-strlen(TAIL)] = '\0';
- X goto_incorp_folder(tmp);
- X if(isfol == (folder) NULL) {
- X sprintf(line, "can't go to folder %s", tmp);
- X addstatus(line, true);
- X redraw = false;
- X break;
- X } else {
- X sprintf(line, "incorporating mail into folder %s", tmp);
- X addstatus(line, true);
- X }
- X } else if(num = numbers(tmp)) /* continuing to read into folder */
- X create_mail_record(num);
- X else if(strlen(str) > 2) { /* vmail is confused - break */
- X str[strlen(str)-1] = '\0';
- X addstatus(str, true);
- X redraw = false;
- X break;
- X }
- X if(redraw) {
- X if(isfol != curflr)
- X alternate = curflr;
- X curflr = isfol;
- X curmail = ismail;
- X y = count;
- X display_page();
- X }
- X fclose(pp);
- X wait(&status);
- X}
- X
- X
- X/* --------------------
- X Extract the first number from str.
- X-------------------- */
- Xint
- Xnumbers(str)
- X char *str;
- X{
- X char save, *tmp;
- X int i;
- X
- X for(; *str == ' ' ; str++)
- X ;
- X for(tmp=str ; *str >= '0' && *str <= '9' ; str++)
- X ;
- X save = *str, *str = '\0', i = atoi(tmp), *str = save;
- X return(i);
- X}
- X
- X
- X/* --------------------
- X Find the folder into which mail is being incorporated, set isfol,
- X ismail, count.
- X-------------------- */
- Xvoid
- Xgoto_incorp_folder(str)
- X char *str;
- X{
- X folder create_folder();
- X
- X GOTO_NAME(isfol, str);
- X if(isfol == (folder) NULL) { /* new folder */
- X isfol = create_folder(str);
- X isfol->valid = true;
- X ismail = (item) NULL;
- X count = FIRST-1;
- X } else {
- X if(! isfol->valid) {
- X isfol->valid = true;
- X find_mail(isfol, false);
- X }
- X /* find last appropriate folder record */
- X LAST_OF_NAME(isfol);
- X for(count=FIRST, ismail=isfol->mail ; ismail->next != (item) NULL ;
- X count++, ismail=ismail->next)
- X ;
- X }
- X}
- X
- X
- X/* --------------------
- X Create and insert new item record into isfol, may need to create new page.
- X-------------------- */
- Xvoid
- Xcreate_mail_record(num)
- X int num;
- X{
- X item m;
- X folder new_folder();
- X
- X m = NEW(mail_item);
- X get_title(isfol, m, num);
- X m->next = (item) NULL;
- X if(count > lines) {
- X /* create new folder record */
- X isfol = new_folder(isfol);
- X ismail = (item) NULL;
- X count = FIRST;
- X } else
- X count++;
- X if(ismail == (item) NULL) {
- X /* new record, possibly new folder */
- X m->prev = (item) NULL;
- X isfol->mail = isfol->last = m;
- X } else {
- X /* insert at end of list of mail items */
- X m->prev = ismail;
- X ismail->next = isfol->last = m;
- X }
- X ismail = m;
- X}
- !The!End!
-
- echo x - "init.c" 2>&1
- sed "s/^X//" >"init.c" <<'!The!End!'
- X/* --------------------
- X vmail -- init.c
- X
- X Initialisation routines - setting ttystate, finding valid folders,
- X trapping signals.
- X
- X Ttystate is controlled by a mix of curses and ioctl. For simplicity,
- X initial setups are done with curses. Curses is also used for basic
- X screen manipulation. However, for speed ioctl is used in switching
- X in and out of normal terminal state.
- X
- X Copyright (C) J. Zobel, University of Melbourne, October 1987.
- X-------------------- */
- X
- X#include "defs.h"
- X#include <signal.h>
- X
- Xstatic struct sgttyb tty, t_tty; /* for holding tty state */
- Xstatic struct tchars chrs, t_chrs;
- Xstatic struct ltchars lchrs, t_lchrs;
- X
- Xstatic char termcap[1024], /* termcap entry */
- X *cur_folder; /* initial current folder */
- X
- X/* --------------------
- X Start-up routine - set terminal control, signals, etc.
- X-------------------- */
- Xvoid
- Xinit(argc, argv)
- X int argc;
- X char **argv;
- X{
- X folder ftmp, find_mail();
- X char *pargv[20], /* argv from profile */
- X *profile = (char *) NULL, /* location of MH profile */
- X *home = (char *) NULL, /* home directory */
- X *term = (char *) NULL; /* terminal type */
- X int pargc = 0; /* argc from profile */
- X
- X get_home(&home);
- X get_env(&term, &profile, home);
- X tgetent(termcap, term);
- X cols = tgetnum("co");
- X /* lines holds no. of lines for headers, ie "li" less STATUS, TITLE */
- X lines = tgetnum("li") - 2;
- X ioctl(0, TIOCGETP, &tty);
- X ioctl(0, TIOCGETP, &chrs);
- X ioctl(0, TIOCGETP, &lchrs);
- X
- X read_profile(&pargc, pargv, profile, home);
- X process_args(pargc, pargv);
- X find_folders();
- X mark_valid_folders(pargc, pargv);
- X /* give precedence to command line args => process second */
- X mark_valid_folders(argc, argv);
- X for(ftmp=folders ; ftmp != (folder) NULL ;)
- X if(ftmp->valid)
- X ftmp = find_mail(ftmp, true);
- X else
- X ftmp = ftmp->next;
- X if(curflr->valid == EMPTY) {
- X printf("%s: folder empty.\n", curflr->name);
- X exit(1);
- X }
- X /* find last instance of initial folder */
- X LAST_OF_NAME(curflr);
- X curmail = curflr->mail;
- X
- X initscr();
- X crmode();
- X noecho();
- X nonl();
- X
- X signal(SIGTSTP, tstp);
- X signal(SIGINT, tint);
- X
- X ioctl(0, TIOCGETP, &t_tty);
- X ioctl(0, TIOCGETP, &t_chrs);
- X ioctl(0, TIOCGETP, &t_lchrs);
- X
- X y = FIRST;
- X display_page();
- X}
- X
- X
- X/* --------------------
- X Find user name, home directory.
- X-------------------- */
- Xvoid
- Xget_home(home)
- X char **home;
- X{
- X struct passwd *pwent, *getpwuid();
- X
- X pwent = getpwuid(getuid());
- X *home = NEWSTR(strlen(pwent->pw_dir)+1);
- X strcpy(*home, pwent->pw_dir);
- X if(access(*home, R_OK | W_OK | X_OK)) {
- X printf("%s: no permissions.\n", *home);
- X exit(1);
- X }
- X user = NEWSTR(strlen(pwent->pw_name)+1);
- X strcpy(user, pwent->pw_name);
- X}
- X
- X
- X/* --------------------
- X Find pager, editor, shell, terminal type, MH profile - defaults are PAGER,
- X EDITOR, SHELL, none, PROFILE. Set by PAGER, EDITOR, SHELL, TERM, MH
- X environment variables.
- X-------------------- */
- Xvoid
- Xget_env(term, profile, home)
- X char **term, **profile, *home;
- X{
- X char **tmp;
- X
- X for(tmp = environ ; *tmp != (char *) NULL ; tmp++)
- X if(!strncmp("PAGER=", *tmp, 6)) {
- X pager = NEWSTR(strlen(*tmp)-4);
- X strcpy(pager, *tmp+6);
- X } else if(!strncmp("EDITOR=", *tmp, 7)) {
- X editor = NEWSTR(strlen(*tmp)-5);
- X strcpy(editor, *tmp+7);
- X } else if(!strncmp("SHELL=", *tmp, 6)) {
- X shell = NEWSTR(strlen(*tmp)-4);
- X strcpy(shell, *tmp+6);
- X } else if(!strncmp("TERM=", *tmp, 5)) {
- X *term = NEWSTR(strlen(*tmp)-3);
- X strcpy(*term, *tmp+5);
- X } else if(!strncmp("MH=", *tmp, 3)) {
- X *profile = NEWSTR(strlen(*tmp)-1);
- X strcpy(*profile, *tmp+3);
- X }
- X if(*term == (char *) NULL) {
- X printf("Terminal type unknown\n");
- X exit(1);
- X }
- X if(*profile == (char *) NULL) {
- X *profile = NEWSTR(strlen(home)+strlen(PROFILE)+2);
- X sprintf(*profile, "%s/%s", home, PROFILE);
- X }
- X if(pager == (char *) NULL) {
- X pager = NEWSTR(strlen(PAGER)+1);
- X strcpy(pager, PAGER);
- X }
- X if(shell == (char *) NULL) {
- X shell = NEWSTR(strlen(SHELL)+1);
- X strcpy(shell, SHELL);
- X }
- X if(editor == (char *) NULL) {
- X editor = NEWSTR(strlen(EDITOR)+1);
- X strcpy(editor, EDITOR);
- X }
- X}
- X
- X
- Xstatic char argkeep[LEN]; /* storage for args from profile */
- X
- X/* --------------------
- X Find mail directory, current-folder, context, default options.
- X-------------------- */
- Xvoid
- Xread_profile(pargc, pargv, profile, home)
- X int *pargc;
- X char **pargv, *profile, *home;
- X{
- X FILE *fp, *fopen();
- X char str[LEN], *ptr, iscontext[LEN], *index(), *next_token();
- X
- X if((fp = fopen(profile, "r")) == (FILE *) NULL) {
- X printf("Profile: %s: cannot open.\n", profile);
- X exit(1);
- X }
- X *iscontext = '\0';
- X while(fgets(str, LEN, fp) != (char *) NULL) {
- X /* get entries from profile */
- X if(lstrncmp("context:", str, 8) == 0 && *(ptr=str+8) != '\0') {
- X squash(str);
- X strcpy(iscontext, str+8);
- X } else if(lstrncmp("vmail:", str, 6) == 0 && *(ptr=str+6) != '\0') {
- X for( ; *ptr == ' ' || *ptr == '\t' ; ptr++)
- X ;
- X *index(ptr, '\n') = '\0';
- X strcpy(argkeep, ptr);
- X for(ptr=argkeep ; *ptr != '\0' ; ) {
- X pargv[(*pargc)++] = ptr;
- X ptr = next_token(ptr);
- X }
- X } else if(lstrncmp("path:", str, 5) == 0 && *(ptr=str+5) != '\0') {
- X squash(str);
- X if(*ptr == '/') { /* full pathname */
- X mail_dir = NEWSTR(strlen(ptr)+1);
- X strcpy(mail_dir, ptr);
- X } else {
- X mail_dir = NEWSTR(strlen(home)+strlen(ptr)+1);
- X sprintf(mail_dir, "%s/%s", home, ptr);
- X }
- X } else if(lstrncmp("folder-protect:", str, 15) == 0 &&
- X *(str+15) != '\0') {
- X squash(str);
- X folder_protect = atoo(str+15);
- X } else if(lstrncmp("current-folder:", str, 15) == 0 &&
- X *(str+15) != '\0') {
- X squash(str);
- X cur_folder = NEWSTR(strlen(str+15)+1);
- X strcpy(cur_folder, str);
- X }
- X }
- X fclose(fp);
- X if(mail_dir == (char *) NULL) {
- X mail_dir = NEWSTR(strlen(home)+strlen(MAILDIR)+2);
- X sprintf(mail_dir, "%s/%s", home, str+6);
- X }
- X if(access(mail_dir, R_OK | W_OK | X_OK)) {
- X printf("%s: no permissions.\n", mail_dir);
- X exit(1);
- X }
- X if(*iscontext == '\0')
- X strcpy(iscontext, CONTEXT);
- X context = NEWSTR(strlen(mail_dir)+strlen(iscontext)+2);
- X sprintf(context, "%s/%s", mail_dir, iscontext);
- X if(access(context, R_OK | W_OK)) {
- X printf("%s: no permissions.\n", context);
- X exit(1);
- X }
- X if(cur_folder == (char *) NULL)
- X cur_folder = CURFOL;
- X}
- X
- X
- X/* --------------------
- X Squash spaces, tabs, newlines out of given string.
- X-------------------- */
- Xvoid
- Xsquash(str)
- X char *str;
- X{
- X int i, j;
- X
- X for(i=0, j=0 ; (str[j] = str[i]) != '\0' ; i++)
- X if(str[j] != ' ' && str[j] != '\t' && str[j] != '\n')
- X j++;
- X}
- X
- X
- X/* --------------------
- X Mark folders as specified by setenv, command line. At startup, default
- X is for only active folder to be cur_folder.
- X-------------------- */
- Xvoid
- Xmark_valid_folders(argc, argv)
- X int argc;
- X char **argv;
- X{
- X char *name;
- X folder f;
- X
- X name = cur_folder;
- X /* find valid folders - mark all folders from argv as valid */
- X for(; argc > 0 ; argc--, argv++)
- X if(**argv == '+') /* startup folder */
- X name = (*argv) + 1;
- X else if(**argv != '-') { /* not a flag */
- X GOTO_NAME(f, *argv);
- X if(f == (folder) NULL)
- X printf("Warning: no such folder as %s\n", *argv);
- X else
- X f->valid = true;
- X }
- X GOTO_NAME(f, name);
- X if(f == (folder) NULL) {
- X printf("%s does not exist\n", name);
- X exit(1);
- X }
- X f->valid = true;
- X curflr = f;
- X}
- X
- X
- X/* --------------------
- X Reset terminal, clean up.
- X-------------------- */
- Xvoid
- Xto_normal()
- X{
- X move(lines+FIRST-1, 0);
- X refresh();
- X no_control();
- X printf("\n");
- X}
- X
- X
- X/* --------------------
- X Reset terminal.
- X-------------------- */
- Xvoid
- Xno_control()
- X{
- X ioctl(0, TIOCSETP, &tty);
- X ioctl(0, TIOCSETP, &chrs);
- X ioctl(0, TIOCSETP, &lchrs);
- X}
- X
- X
- X/* --------------------
- X Set terminal.
- X-------------------- */
- Xvoid
- Xto_control()
- X{
- X ioctl(0, TIOCSETP, &t_tty);
- X ioctl(0, TIOCSETP, &t_chrs);
- X ioctl(0, TIOCSETP, &t_lchrs);
- X}
- X
- X
- X#define mask(s) (1 << ((s)-1))
- X
- X/* --------------------
- X Trap for ^Z.
- X-------------------- */
- Xvoid
- Xtstp()
- X{
- X int x, y;
- X
- X getyx(curscr, y, x);
- X to_normal();
- X fix_mh();
- X
- X signal(SIGTSTP, SIG_DFL);
- X sigsetmask(sigblock(0) &~ mask(SIGTSTP));
- X kill(0, SIGTSTP);
- X sigblock(mask(SIGTSTP));
- X signal(SIGTSTP, tstp);
- X
- X if(top_level) {
- X to_control();
- X touchwin(curscr);
- X wmove(curscr, y, x);
- X wrefresh(curscr);
- X }
- X}
- X
- X
- X/* --------------------
- X Trap for ^?.
- X-------------------- */
- Xvoid
- Xtint()
- X{
- X touchwin(stdscr);
- X addstatus("-- interrupt --", true);
- X longjmp(env, 0); /* jump to main */
- X}
- X
- X
- X/* --------------------
- X Convert an ascii string to octal.
- X-------------------- */
- Xint
- Xatoo(str)
- X char *str;
- X{
- X int i;
- X
- X for(; *str < '0' && *str > '7' ; str++)
- X ;
- X for(i=0 ; *str >= '0' && *str <= '7' ; str++)
- X i = i*8 + *str - '0';
- X return(i);
- X}
- X
- X
- X/* --------------------
- X Update MH environment - context and current mail item of current folder.
- X-------------------- */
- Xfix_mh()
- X{
- X char str[LEN], buf[20];
- X
- X update(context, "Current-Folder:", curflr->name, 15);
- X sprintf(str, "%s/%s/%s", mail_dir, curflr->name, SEQU);
- X sprintf(buf, "%d", curmail->number);
- X update(str, "cur:", buf, 4);
- X}
- X
- X
- X/* --------------------
- X Update file, replacing line beginning with match of len by "match new".
- X-------------------- */
- Xupdate(file, match, new, len)
- X char *file, *match, *new;
- X int len;
- X{
- X FILE *fp, *tmp, *fopen();
- X bool change = false;
- X char *mktemp(), *fgets();
- X char str[LEN], *name = mktemp("/tmp/vmail.XXXXXX");
- X
- X if((fp = fopen(file, "r")) == (FILE *) NULL) {
- X if((fp = fopen(file, "w+")) == (FILE *) NULL)
- X printf("Can't open %s for writing\n", file);
- X else {
- X fprintf(fp, "%s %s\n", match, new);
- X close(fp);
- X }
- X } else {
- X if((tmp = fopen(name, "w+")) == (FILE *) NULL)
- X printf("Can't open %s\n", file);
- X else {
- X while(fgets(str, LEN, fp) != (char *) NULL)
- X if(lstrncmp(str, match, len) == 0) {
- X change = true;
- X fprintf(tmp, "%s %s\n", match, new);
- X } else
- X fprintf(tmp, "%s", str);
- X if(! change)
- X fprintf(tmp, "%s %s\n", match, new);
- X fclose(fp);
- X fclose(tmp);
- X if((fp = fopen(file, "w+")) == (FILE *) NULL)
- X printf("Can't open %s for writing\n", file);
- X else {
- X tmp = fopen(name, "r");
- X while(fgets(str, LEN, tmp) != (char *) NULL)
- X fprintf(fp, "%s", str);
- X fclose(fp);
- X fclose(tmp);
- X unlink(name);
- X }
- X }
- X }
- X}
- !The!End!
- exit
-
-
-