allbery@ncoast.UUCP (Brandon S. Allbery) (07/22/86)
IMS is a simple ``folder''-oriented mail reader (think of a baby MH). It can be used in interactive mode, or combined with shell scripts to manipulate mail a' la MH. (One simple idea is a shell script: #! /bin/sh exec ims "$0" "$@" which is linked to IMS command names and executes the IMS commands.) The manual page describes its use. I have found that it is faster than mailx (Mail) in most things, faster than /bin/mail in many... and ENORMOUSLY faster than msg (although I haven't tried its new incarnation as ``elm'' yet). But it's not full-screen oriented. This mailer is still tiny and simple at present. I'll be adding to it, in particular adding to the folder support, as only the current folder and the save folder are generally accessible. But for now it's fast and does the things I want it to do. It has been tested under System III and System V; it should work under 4.2BSD if you #define BSD (it uses BSD-compatible directory routines under USG unices) but it won't work as is under V7. It also doesn't store timezones in messages under 4.2; I haven't the faintest idea how to retrieve the timezone. Cut at the dotted line, feed to /bin/sh, make, and enjoy! ++Brandon -------------------------------- coupe ici ---------------------------------- #! /bin/sh # # Shell archive created Thu., Jul. 17, 1986 by tdi2!brandon. # Contents: # # -rw-r--r-- 1 brandon 20 8881 Jul 17 08:54 ims.c # -rw-r--r-- 1 brandon 20 10207 Jul 17 08:55 imsread.c # -rw-r--r-- 1 brandon 20 3279 Jul 17 09:04 imsdel.c # -rw-r--r-- 1 brandon 20 5932 Jul 17 11:11 imsinc.c # -rw-r--r-- 1 brandon 20 12610 Jul 17 09:42 imssend.c # -rw-r--r-- 1 brandon 20 4618 Jul 17 09:07 imsset.c # -rw-r--r-- 1 brandon sys 5411 Jul 17 09:11 imsalias.c # -rw-r--r-- 1 brandon 20 1934 Jul 4 19:47 ndir.c # -rw-r--r-- 1 brandon 20 1540 Jul 4 20:01 eopen.c # -rw-r--r-- 1 brandon sys 1756 Jul 17 09:47 ims.h # -rw-rw-rw- 1 brandon 20 2471 Jul 3 19:52 ndir.h # -rw-r--r-- 1 brandon 20 18403 Jul 17 10:44 ims.1 # -rw-r--r-- 1 brandon 20 1501 Jul 17 11:26 Makefile # # You may unpack this archive with sh or ksh, but not csh. # if test -r "ims.c"; then echo "File ims.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="ims.c" esac else newname="ims.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:ims.c--' > "$newname" X#include "ims.h" X Xstruct cmdtab { X char *c_cmd; X int (*c_func)(); X char *c_help; X} cmdtab[] = { X "delete", delmsg, "Delete a message", X "undelete", undelmsg, "Recover a deleted message", X "expunge", expunge, "Recover space occupied by deleted messages", X "type", readmsg, "Display a message", X "print", printmsg, "Print a message on printer", X "save", savemsg, "Save a message in a file or folder", X "set", varops, "Display or modify IMS variables", X "next", nextmsg, "Go to the next message", X "+", nextmsg, "Go to the next message", X "previous", prevmsg, "Go to the previous message", X "-", prevmsg, "Go to the previous message", X "write", savemsg, "Save a message in a file or folder", X "reply", reply, "Reply to a message", X "goto", gomsg, "Set the current message", X "mail", mailto, "Send mail to users", X "send", mailto, "Send mail to users", X "list", listmsg, "List the headers of messages", X "headers", listmsg, "List the headers of messages", X "forward", forward, "Forward a message to another person", X "from", listmsg, "List the headers of messages", X "quit", byebye, "Leave IMS, expunging deleted messages", X "exit", nxbyebye, "Leave IMS without expunging messages", X "xit", nxbyebye, "Leave IMS without expunging messages", X "?", help, "Get help on a command", X "help", help, "Get help on a command", X "folder", setfolder, "Set or show the current folder", X "read", readmbox, "Read old-style mailbox into folder", X "inc", readmbox, "Read old-style mailbox into folder", X "folders", foldlist, "List the existing folders", X "alias", aliasops, "Display or create mail aliases", X "unalias", unalias, "Delete mail aliases", X (char *) 0, readmsg, "Read the named or numbered message", X}; X Xchar folder[256]; Xchar cabinet[256]; Xchar mailbox[1024]; Xchar prompt[256]; Xint msg; Xjmp_buf mainloop; Xchar sysmbox[1024]; Xchar autoread[256] = "No"; Xchar lines[256] = "24"; Xint _x; X Xintr() { X longjmp(mainloop, 1); X} X Xmain(argc, argv) Xchar *argv[]; { X char line[512]; X char *cp; X int nmsg, incf; X struct stat sbuf; X X if ((cp = getenv("HOME")) == (char *) 0) X cp = "/usr/guest"; X sprintf(cabinet, "%s/.mail", cp); X sprintf(sysmbox, SYSMAILBOX, getlogin()); X strcpy(mailbox, sysmbox); X strcpy(line, "incoming-mail"); X strcpy(prompt, "IMS> "); X readvars(); X readalias(); X if (access(cabinet, 0) < 0) X if (mkdir(cabinet) < 0) { X puts("Can't create your mail cabinet. Please check your CABINET and your home\ndirectory."); X exit(1); X } X if ((cp = getenv("FOLDER")) != (char *) 0) X strcpy(line, cp); X if (setfolder(line) < 0) { X puts("Please check your CABINET and FOLDER."); X exit(1); X } X if ((cp = getenv("MAIL")) != (char *) 0) X strcpy(mailbox, cp); X if ((cp = getenv("PAGER")) != (char *) 0) X strcpy(pager, cp); X if ((cp = getenv("VISUAL")) == (char *) 0) X if ((cp = getenv("EDITOR")) == (char *) 0) X cp = (char *) 0; X if (cp != (char *) 0) X strcpy(editor, cp); X if ((cp = getenv("PRINTMSG")) == (char *) 0) X strcpy(printcmd, "pr -h \"Printed by: ${LOGNAME:-${USER:-anonymous}} \" | lpr"); X else X strcpy(printcmd, cp); X if ((cp = getenv("SAVEFOLDER")) != (char *) 0) X strcpy(savefolder, cp); X if ((cp = getenv("LINES")) != (char *) 0) X strcpy(lines, cp); X incf = 1; X nmsg = 1; X if (argc >= nmsg + 1 && strcmp(argv[nmsg], "-i") == 0) { X incf = 0; X nmsg++; X } X line[0] = '\0'; X for (; nmsg < argc; nmsg++) { X strcat(line, " "); X strcat(line, argv[nmsg]); X } X if (line[0] != '\0') { X dispatch(line); X exit(0); X } X if (incf) { X msg = receive(mailbox); X if (msg == -1) X puts("Your system mailbox has been deleted. Please contact your system administrator\nin order to have it restored."); X if (msg != 0) X printf("New messages start at %d.\n", msg); X else { X listmsg(""); X msg = 1; X }; X } X _x = 0; X if (isatty(2)) { X stat(ttyname(2), &sbuf); X if (sbuf.st_mode & 0111) { X _x = 1; X chmod(ttyname(2), sbuf.st_mode & ~0111); X } X } X signal(SIGINT, intr); X signal(SIGQUIT, SIG_IGN); X signal(SIGPIPE, SIG_IGN); X if (setjmp(mainloop) != 0) X puts("\nCommand interrupted."); X for (;;) { X if (newmail(mailbox)) { X puts("New mail has arrived. Reading your mailbox..."); X if (autoread[0] == 'Y' || autoread[0] == 'y' || autoread[0] == 'T' || autoread[0] == 't') { X nmsg = receive(mailbox); X if (nmsg == -1) X puts("Your system mailbox has been deleted. Please contact your system administrator\nin order to have it restored."); X if (nmsg != 0) X printf("New messages start at %d.\n", nmsg); X } X } X printf("%s", prompt); X if (gets(line) == (char *) 0) { X putchar('\n'); X expunge(""); X break; X } X for (cp = line; *cp == ' ' || *cp == '\t'; cp++) X ; X if (*cp == '!') { X system(cp + 1); X continue; X } X if (dispatch(cp) == 0) X break; X } X if (_x) { X stat(ttyname(2), &sbuf); X chmod(ttyname(2), sbuf.st_mode | 0111); X } X exit(0); X} X Xdispatch(cmd) Xchar *cmd; { X char *cp, *cmdp, *nextp; X int cnt, status, ran; X X for (;;) { X if ((nextp = strchr(cmd, ';')) == (char *) 0) X nextp = "\376"; X else X *nextp++ = '\0'; X for (cp = cmd; *cp == ' ' || *cp == '\t'; cp++) X ; X for (cmdp = cp; *cp != '\0' && *cp != '\t' && *cp != ' '; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X if (*cmdp == '\376') X break; X ran = 0; X cnt = 0; X if (strlen(cmdp) != 0) { X for (cnt = 0; cmdtab[cnt].c_cmd != (char *) 0; cnt++) { X if (strlen(cmdp) > strlen(cmdtab[cnt].c_cmd)) X continue; X if (strncmp(cmdp, cmdtab[cnt].c_cmd, strlen(cmdp)) == 0) X if ((status = (*cmdtab[cnt].c_func)(cp)) < 1) X return status; X else { X ran = 1; X break; X } X } X } X while (cmdtab[cnt].c_cmd != (char *) 0) X cnt++; X if (!ran) { X if (cmdtab[cnt].c_func != (int (*)()) 0) { X if ((status = (*cmdtab[cnt].c_func)(cmdp)) < 1) X return status; X } X else { X printf("Unknown command: \"%s\". Type \"help\" for help.\n", cmdp); X return -1; X } X } X cmd = nextp; X } X return status; X} X Xhelp(cmdp) Xchar *cmdp; { X char *cp, *dp; X int cnt, icnt; X X for (cp = cmdp; *cp == ' ' || *cp == '\t'; cp++) X ; X for (dp = cp; *dp != ' ' && *dp != '\t' && *dp != '\0'; dp++) X ; X if (*dp != '\0') X *dp++ = '\0'; X while (*dp == ' ' || *dp == '\t') X ; X if (*dp != '\0') { X puts("Usage: help [topic]"); X return -1; X } X icnt = 0; X if (atoi(lines) <= 3) X strcpy(lines, "24"); X for (cnt = 0; cmdtab[cnt].c_cmd != (char *) 0; cnt++) { X if (strlen(cp) > strlen(cmdtab[cnt].c_cmd)) X continue; X if (*cp == '\0' || strncmp(cp, cmdtab[cnt].c_cmd, strlen(cp)) == 0) { X printf(" %-16s %s\n", cmdtab[cnt].c_cmd, cmdtab[cnt].c_help); X icnt++; X if (icnt % (atoi(lines) - 1) == 0) X getcont(); X } X } X if (*cp != '\0' && icnt == 0) X if (strcmp(cp, "default") == 0) X printf(" %-16s %s\n", "Default:", cmdtab[cnt].c_help); X else { X printf("Unknown topic: \"%s\".\n", cp); X return -1; X } X else if (*cp == '\0') X printf(" %-16s %s\n", "Default:", cmdtab[cnt].c_help); X return 1; X} X Xsetfolder(cmdp) Xchar *cmdp; { X char *cp; X X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp == '\0') { X printf("The current folder is \"%s\".\n", folder); X return 1; X } X for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X while (*cp != '\0') X if (*cp != ' ' || *cp != '\t') { X puts("Too many arguments. Usage: folder [folder-name]"); X return -1; X } X if (access(location(cmdp), 0) < 0) { X if (mkdir(location(cmdp)) < 0) { X fprintf(stderr, "Can't create \"%s\" folder.\n", cmdp); X return -1; X } X if (access(location(cmdp), 0) < 0) { X fprintf(stderr, "I can't get at your \"%s\" folder.\n, cmdp"); X return -1; X } X } X strcpy(folder, cmdp); X return 1; X} X Xmkdir(dir) Xchar *dir; { X int pid, status; X X switch (pid = fork()) { X case -1: X perror(""); X printf("Can't create directory \"%s\".\n", dir); X return -1; X case 0: X execl("/bin/mkdir", "mkdir", dir, (char *) 0); X _exit(-100); X default: X while (wait(&status) != pid) X ; X if (status != 0) X return -1; X } X return 0; X} X Xchar *location(folder) Xchar *folder; { X static char buf[1024]; X X if (folder[0] == '/' || folder[0] == '.') X return folder; X sprintf(buf, "%s/%s", cabinet, folder); X return buf; X} X Xbyebye(cmdp) Xchar *cmdp; { X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp != '\0') { X puts("Too many arguments. Usage: quit\n Or: xit"); X return -1; X } X if (expunge("") < 0) X return -1; X return 0; X} X Xnxbyebye(cmdp) Xchar *cmdp; { X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp != '\0') { X puts("Too many arguments. Usage: xit"); X return -1; X } X return 0; X} X Xchar *basename(s) Xchar *s; { X char *cp; X X if ((cp = strrchr(s, '/')) != (char *) 0) X return cp + 1; X return s; X} X Xisfolder(f) Xchar *f; { X struct stat s; X X if (stat(location(f), &s) < 0) X return 0; X return (s.st_mode & S_IFMT) == S_IFDIR; X} X Xissysmbox(mbox) Xchar *mbox; { X return strcmp(mbox, sysmbox) == 0; X} --EOF:ims.c-- fi if test -r "imsread.c"; then echo "File imsread.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="imsread.c" esac else newname="imsread.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:imsread.c--' > "$newname" X#include "ims.h" X Xchar pager[1024] = "/usr/ucb/more"; Xchar printcmd[1024]; Xchar savefolder[256] = "saved-mail"; Xchar askappend[] = "Yes"; X Xnextmsg(cmdp) Xchar *cmdp; { X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp != '\0') { X puts("Usage: next"); X return -1; X } X msg++; X if (autonext[0] == 'y' || autonext[0] == 'Y' || autonext[0] == 't' || autonext[0] == 'T') X if (readmsg("-q") < 0) { X puts("No next message."); X return -1; X } X else if (!ismsg(msg)) { X puts("No next message."); X return -1; X } X return 1; X} X Xprevmsg(cmdp) Xchar *cmdp; { X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp != '\0') { X puts("Usage: previous"); X return -1; X } X msg--; X if (autonext[0] == 'y' || autonext[0] == 'Y' || autonext[0] == 't' || autonext[0] == 'T') X if (readmsg("-q") < 0) { X puts("No next message."); X return -1; X } X else if (!ismsg(msg)) { X puts("No next message."); X return -1; X } X return 1; X} X Xreadmsg(cmdp) Xchar *cmdp; { X char *cp; X int foldmsg, quiet; X char mname[80]; X X quiet = 0; X X_again: X foldmsg = 0; X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp != '\0') { X for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) X if (strchr("0123456789", *cp) == (char *) 0) X foldmsg = 1; X if (*cp != '\0') X *cp++ = '\0'; X if (strcmp(cmdp, "-q") == 0) { X if (quiet) { X puts("Usage: type [-q] [message-number]"); X return -1; X } X else { X quiet = 1; X cmdp = cp; X goto _again; X } X } X while (*cp != '\0') X if (*cp != '\t' && *cp != ' ') { X puts("Too many arguments. Usage: type [-q] [message-number]"); X return -1; X } X if (!ismsg(cmdp)) { X if (!quiet) X puts("No such message."); X return -1; X } X if (!foldmsg) X msg = atoi(cmdp); X } X if (foldmsg) X return dorms(cmdp, pager); X sprintf(mname, ".%d", msg); X if (ismsg(mname)) X return dorms(mname, pager); X sprintf(mname, "%d", msg); X if (!ismsg(mname)) { X if (!quiet) X printf("Message %d doesn't exist.\n", msg); X return -1; X } X return dorms(mname, pager); X} X Xchar *mlocation(msg) Xchar *msg; { X static char path[1024]; X X if ((msg[0] == '.' && msg[1] == '/') || msg[0] == '/') X strcpy(path, msg); X else X sprintf(path, "%s/%s", location(folder), msg); X return path; X} X Xchar *mflocation(folder, msg) Xchar *folder, *msg; { X static char path[1024]; X X if ((msg[0] == '.' && msg[1] == '/') || msg[0] == '/') X strcpy(path, msg); X else X sprintf(path, "%s/%s", location(folder), msg); X return path; X} X Xdorms(msg, cmd) Xchar *msg, *cmd; { X FILE *fp; X int status; X X if (cmd == (char *) 0) X fp = (FILE *) 0; X else if ((fp = epopen(cmd, "w")) == (FILE *) 0) { X printf("Can't open pipe to command: %s\n", cmd); X return -1; X } X status = docopy(msg, fp); X if (fp != (FILE *) 0) X pclose(fp); X return 1; X} X Xdosave(msg, file) Xchar *msg, *file; { X FILE *fp; X int status; X char yesno[512]; X char *cp; X X if ((askappend[0] == 'Y' || askappend[0] == 'y' || askappend[0] == 'T' || askappend[0] == 't') && file != (char *) 0 && access(file, 0) == 0) { X printf("File exists. Do you wish to append to it? "); X if (gets(yesno) == (char *) 0) { X puts("No"); X return -1; X } X for (cp = yesno; *cp != ' ' && *cp != '\t'; cp++) X ; X if (*cp != 'y' && *cp != 'Y') X return -1; X } X if (file == (char *) 0) X fp = (FILE *) 0; X else if ((fp = efopen(file, "a")) == (FILE *) 0) { X printf("Can't open file: %s\n", file); X return -1; X } X status = docopy(msg, fp); X if (fp != (FILE *) 0) X fclose(fp); X return status; X} X Xdocopy(msg, mfp) Xchar *msg; XFILE *mfp; { X char line[1024]; X FILE *fp; X X if ((fp = efopen(mlocation(msg), "r")) == (FILE *) 0) { X printf("Message %s doesn't exist.\n", msg); X return -1; X } X if (mfp == (FILE *) 0) X mfp = stdout; X if (msg[0] == '.') X fprintf(mfp, "Message %s (deleted):\n", msg + 1); X else X fprintf(mfp, "Message %s:\n", msg); X dopipe(fp, mfp); X fclose(fp); X return 1; X} X Xdopipe(msg, outp) XFILE *msg, *outp; { X char ch; X X while ((ch = getc(msg)) != EOF) X putc(ch, outp); X} X Xismsg(msg) Xchar *msg; { X char delmsg[256]; X struct stat sbuf; X X strcpy(delmsg, "."); X strcat(delmsg, msg); X if (access(mlocation(delmsg), 0) == 0) { X stat(mlocation(delmsg), &sbuf); X return (sbuf.st_mode & S_IFMT) != S_IFDIR; X } X if (access(mlocation(msg), 0) < 0) X return 0; X stat(mlocation(msg), &sbuf); X return (sbuf.st_mode & S_IFMT) != S_IFDIR; X} X Xisdeleted(msg) Xchar *msg; { X char delmsg[256]; X X strcpy(delmsg, "."); X strcat(delmsg, msg); X return access(mlocation(delmsg), 0) == 0; X} X Xprintmsg(cmdp) Xchar *cmdp; { X char *cp; X int foldmsg; X char mname[80]; X X foldmsg = 0; X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp != '\0') { X for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) X if (strchr("0123456789", *cp) == (char *) 0) X foldmsg = 1; X if (*cp != '\0') X *cp++ = '\0'; X while (*cp != '\0') X if (*cp != '\t' && *cp != ' ') { X puts("Too many arguments. Usage: print [message-number]"); X return -1; X } X if (!ismsg(cmdp)) { X puts("No such message."); X return -1; X } X if (!foldmsg) X msg = atoi(cmdp); X } X if (foldmsg) X return dorms(cmdp, printcmd); X sprintf(mname, ".%d", msg); X if (ismsg(mname)) X return dorms(mname, printcmd); X sprintf(mname, "%d", msg); X if (!ismsg(mname)) { X printf("Message %d doesn't exist.\n", msg); X return -1; X } X return dorms(mname, printcmd); X} X Xsavemsg(cmdp) Xchar *cmdp; { X char *cp, *savep; X int foldmsg, status; X char mname[80], savefile[80]; X X foldmsg = 0; X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp == '\0') X sprintf(savefile, "%s/%s", location(savefolder), folder); X else { X for (cp = cmdp; *cp != ' ' && *cp != '\t' && *cp != '\0'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X if (strchr(cmdp, '/') != (char *) 0) X strcpy(savefile, cmdp); X else X sprintf(savefile, "%s/%s", location(savefolder), cmdp); X for (savep = cp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) X if (strchr("0123456789", *cp) == (char *) 0) X foldmsg = 1; X if (*cp != '\0') X *cp++ = '\0'; X while (*cp == ' ' || *cp == '\t') X cp++; X if (*cp != '\0') { X puts("Too many arguments. Usage: save file [message-number]"); X return -1; X } X if (*savep != '\0') { X if (!ismsg(savep)) { X puts("No such message."); X return -1; X } X if (!foldmsg) X msg = atoi(savep); X } X } X if (foldmsg) X return dosave(savep, savefile); X sprintf(mname, ".%d", msg); X if (ismsg(mname)) X status = dosave(mname, savefile); X else { X sprintf(mname, "%d", msg); X if (!ismsg(mname)) { X printf("Message %d doesn't exist.\n", msg); X return -1; X } X status = dosave(mname, savefile); X } X if (status < 1) X return status; X return delmsg(""); X} X Xgomsg(cmdp) Xchar *cmdp; { X char *cp; X X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp == '\0') { X puts("Usage: goto message-number"); X return -1; X } X for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) X if (strchr("0123456789", *cp) == (char *) 0) { X puts("Invalid message number. Usage: goto message-number"); X return -1; X } X if (*cp != '\0') X *cp++ = '\0'; X while (*cp != '\0') X if (*cp != '\t' && *cp != ' ') { X puts("Too many arguments. Usage: goto message-number"); X return -1; X } X if (!ismsg(cmdp)) { X puts("No such message."); X return -1; X } X msg = atoi(cmdp); X if (autonext[0] == 'y' || autonext[0] == 'Y' || autonext[0] == 't' || autonext[0] == 'T') X return readmsg(""); X return 1; X} X Xlistmsg(cmdp) Xchar *cmdp; { X char *cp; X DIR *dp; X struct direct *entry; X extern int errno; X extern char *sys_errlist[]; X FILE *mp; X char mline[2048], from[21], subj[51]; X int cnt, cmsg; X X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp == '\0') X cmdp = folder; X else { X for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X while (*cp != '\0') X if (*cp != '\t' && *cp != ' ') { X puts("Too many arguments. Usage: list [folder-name]\nOr: list folders"); X return -1; X } X if (!isfolder(cmdp)) { X puts("No such folder."); X return -1; X } X } X if ((dp = opendir(location(cmdp))) == (DIR *) 0) { X puts("Can't open folder for listing."); X return -1; X } X cnt = 0; X if (atoi(lines) < 3) X strcpy(lines, "24"); X while ((entry = readdir(dp)) != (struct direct *) 0) { X if (entry->d_name[0] == '.' && (entry->d_name[1] == '\0' || (entry->d_name[1] == '.' && entry->d_name[2] == '\0'))) X continue; X from[0] = '\0'; X subj[0] = '\0'; X cnt++; X if (cnt == 1) X printf("Contents of folder \"%s\":\nSt Name From Subject\n", cmdp); X if (sscanf(entry->d_name, "%d", &cmsg) != 1) X putchar(' '); X else if (cmsg == msg) X putchar('*'); X else X putchar(' '); X if (entry->d_name[0] == '.') X printf("D %-8.8s ", &entry->d_name[1]); X else X printf(" %-8.8s ", entry->d_name); X if ((mp = efopen(mflocation(cmdp, entry->d_name), "r")) == (FILE *) 0) { X puts("unreadable"); X if (cnt % (atoi(lines) - 1) == 0) X getcont(); X continue; X } X while (fgets(mline, sizeof mline, mp) != (char *) 0) { X if (mline[0] == '\n') X break; X if (strncmp(mline, "Subject: ", 9) == 0) { X mline[strlen(mline) - 1] = '\0'; X strncpy(subj, &mline[9], 50); X subj[50] = '\0'; X } X if (strncmp(mline, "From: ", 6) == 0) { X mline[strlen(mline) - 1] = '\0'; X strncpy(from, &mline[6], 20); X from[20] = '\0'; X } X } X printf("%-20.20s", from); X if (subj[0] != '\0') X printf(" \"%.50s\"", subj); X putchar('\n'); X if (cnt % (atoi(lines) - 1) == 0) X getcont(); X fclose(mp); X } X if (cnt == 0) X printf("No messages in folder \"%s\".\n", folder); X return 1; X} X Xfoldlist(cmdp) Xchar *cmdp; { X DIR *dp; X struct direct *entry; X int cnt; X X while (*cmdp == '\t' || *cmdp == ' ') X cmdp++; X if (*cmdp != '\0') { X puts("Usage: folders"); X return -1; X } X if ((dp = opendir(cabinet)) == (DIR *) 0) { X puts("Can't open cabinet to list folders."); X return -1; X } X puts("The following folders exist in the cabinet:"); X if (atoi(lines) <= 3) X strcpy(lines, "24"); X while ((entry = readdir(dp)) != (struct direct *) 0) { X if (entry->d_name[0] == '.' && (entry->d_name[1] == '\0' || (entry->d_name[1] == '.' && entry->d_name[2] == '\0'))) X continue; X printf(" %s\n", entry->d_name); X if (++cnt % atoi(lines) - 1 == 0) X getcont(); X } X return 1; X} --EOF:imsread.c-- fi if test -r "imsdel.c"; then echo "File imsdel.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="imsdel.c" esac else newname="imsdel.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:imsdel.c--' > "$newname" X#include "ims.h" X Xchar autonext[128] = "No"; X Xdelmsg(cmdp) Xchar *cmdp; { X char *cp; X char mname[80], curmsg[80], mt1[100], mt2[100]; X X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp != '\0') { X for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X while (*cp != '\0') X if (*cp != '\t' && *cp != ' ') { X puts("Too many arguments. Usage: delete [message-number]"); X return -1; X } X if (!ismsg(cmdp)) { X puts("No such message."); X return -1; X } X } X else { X sprintf(curmsg, "%d", msg); X cmdp = curmsg; X } X sprintf(mname, ".%s", cmdp); X if (ismsg(mname)) { X puts("The message is already deleted. Type \"expunge\" to free its space."); X return -1; X } X if (!ismsg(cmdp)) { X puts("There is no such message."); X return -1; X } X strcpy(mname, "."); X strcat(mname, cmdp); X strcpy(mt1, mlocation(cmdp)); X strcpy(mt2, mlocation(mname)); X if (link(mt1, mt2) < 0) { X puts("Could not flag the message as deleted."); X return -1; X } X if (unlink(mt1) < 0) { X puts("Could not flag the message as deleted."); X unlink(mt2); X return -1; X } X msg++; X if (autonext[0] == 'y' || autonext[0] == 'Y' || autonext[0] == 't' || autonext[0] == 'T') X if (readmsg("-q") < 0) { X puts("No next message."); X return -1; X } X return 1; X} X Xundelmsg(cmdp) Xchar *cmdp; { X char *cp; X char mname[80], curmsg[80], mt1[100], mt2[100]; X X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp != '\0') { X for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X while (*cp != '\0') X if (*cp != '\t' && *cp != ' ') { X puts("Too many arguments. Usage: undelete [message-number]"); X return -1; X } X if (!ismsg(cmdp)) { X puts("No such message."); X return -1; X } X } X else { X sprintf(curmsg, "%d", msg); X cmdp = curmsg; X } X sprintf(mname, ".%s", cmdp); X if (!ismsg(mname)) { X puts("The message isn't deleted."); X return -1; X } X strcpy(mname, "."); X strcat(mname, cmdp); X strcpy(mt1, mlocation(cmdp)); X strcpy(mt2, mlocation(mname)); X if (link(mt2, mt1) < 0) { X puts("Could not flag the message as restored."); X return -1; X } X if (unlink(mt2) < 0) { X puts("Could not flag the message as restored."); X unlink(mt1); X return -1; X } X return 1; X} X Xexpunge(cmdp) Xchar *cmdp; { X char *cp; X DIR *dp; X struct direct *entry; X extern int errno; X extern char *sys_errlist[]; X X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp == '\0') X cmdp = folder; X else { X for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X while (*cp != '\0') X if (*cp != '\t' && *cp != ' ') { X puts("Too many arguments. Usage: expunge [folder-name]"); X return -1; X } X if (!isfolder(cmdp)) { X puts("No such folder."); X return -1; X } X } X if ((dp = opendir(location(cmdp))) == (DIR *) 0) { X puts("Can't open folder for expunging."); X return -1; X } X while ((entry = readdir(dp)) != (struct direct *) 0) { X if (entry->d_name[0] != '.') X continue; X if (entry->d_name[1] == '\0' || (entry->d_name[1] == '.') && entry->d_name[2] == '\0') X continue; X if (unlink(mflocation(cmdp, entry->d_name)) < 0) X printf("Couldn't expunge message: %s (%s)\n", &entry->d_name[1], sys_errlist[errno]); X } X return 1; X} --EOF:imsdel.c-- fi if test -r "imsinc.c"; then echo "File imsinc.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="imsinc.c" esac else newname="imsinc.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:imsinc.c--' > "$newname" X#include "ims.h" X Xreadmbox(cmdp) Xchar *cmdp; { X char *cp; X int cnt; X X for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++) X ; X if (*cmdp != '\0') { X for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X while (*cp != '\0') X if (*cp != '\t' && *cp != ' ') { X puts("Too many arguments. Usage: read [mailbox-name]"); X return -1; X } X } X else X cmdp = mailbox; X if ((cnt = receive(cmdp)) == -1) { X puts("No mailbox."); X return -1; X } X return 1; X} X Xreceive(mbox) Xchar *mbox; { X FILE *mbp, *mp; X char line[1024], from[512], subj[512], date[512], msgn[40], path[1024]; X static char cc[10240], to[10240]; X char *cp; X int first, next, cnt; X enum { X Initial, X HLine1, X Header, X Body, X } state; X X next = 0; X do X sprintf(msgn, "%d", ++next); X while (access(mlocation(msgn), 0) == 0); X if (issysmbox(mbox)) X if (lockmbox(1) < 0) { X puts("Mailbox is locked. Try again in a few minutes."); X return 0; X } X if ((mbp = efopen(mbox, "r")) == (FILE *) 0) { X printf("Can't open mailbox: %s\n", mbox); X if (issysmbox(mbox)) X lockmbox(0); X return 0; X } X first = next; X state = Initial; X cnt = 0; X while (fgets(line, sizeof line, mbp) != (char *) 0) { X if (strncmp(line, "From ", 5) == 0) { X if (state != Initial) { X fclose(mp); X do X sprintf(msgn, "%d", ++next); X while (ismsg(msgn)); X } X if ((mp = efopen(mlocation(msgn), "w")) == (FILE *) 0) { X printf("Error: can't create new message %d. Mailbox restored.\n", next); X fclose(mbp); X if (issysmbox(mbox)) X lockmbox(0); X return 0; X } X cnt++; X strcpy(to, ""); X strcpy(from, ""); X strcpy(path, "Path: "); X strcpy(cc, ""); X strcpy(subj, ""); X strcpy(date, "Date: "); X for (cp = line + 5; *cp != ' '; cp++) X ; X *cp++ = '\0'; X strcat(path, line + 5); X strcat(path, "\n"); X while (*cp == ' ') X cp++; X strcat(date, cp); X state = HLine1; X continue; X } X if (state == HLine1) { X state = Body; X if (strncmp(line, ">From ", 6) == 0 && rmtinc(path, line)) { X state = HLine1; X continue; X } X for (cp = line; *cp != '\0'; cp++) X if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01235456789_-", *cp) == (char *) 0) X break; X if (*cp == ':' && *(cp + 1) == ' ') X state = Header; X else { X if (from[0] == '\0') { X strcpy(from, "From: "); X strcat(from, &path[6]); X } X fputs(date, mp); X fputs(path, mp); X fputs(from, mp); X fputs(subj, mp); X fputs(to, mp); X fputs(cc, mp); X putc('\n', mp); X if (cnt == 1) X printf("New mail in folder \"%s\":\n", folder); X printf(" %5d %-20.*s", next, (strlen(from) > 27? 20: strlen(from) - 7), &from[6]); X if (subj[0] != '\0') X printf(" \"%.*s\"", (subj[0] == '\0'? 0: (strlen(subj) < 50? strlen(subj) - 10: 40)), &subj[9]); X putchar('\n'); X } X } X if (state == Header && line[0] == '\n') { X if (from[0] == '\0') { X strcpy(from, "From: "); X strcat(from, &path[6]); X } X fputs(date, mp); X fputs(path, mp); X fputs(from, mp); X fputs(subj, mp); X fputs(to, mp); X fputs(cc, mp); X if (cnt == 1) X printf("New mail in folder \"%s\":\n", folder); X printf(" %5d %-20.*s", next, (strlen(from) > 27? 20: strlen(from) - 7), &from[6]); X if (subj[0] != '\0') X printf(" \"%.*s\"", (subj[0] == '\0'? 0: (strlen(subj) < 50? strlen(subj) - 10: 40)), &subj[9]); X putchar('\n'); X state = Body; X } X if (state == Body) { X fputs(line, mp); X continue; X } X if (strncmp(line, "Date: ", 6) == 0) { X strcpy(date, line); X continue; X } X if (strncmp(line, "From: ", 6) == 0) { X strcpy(from, line); X continue; X } X if (strncmp(line, "Subject: ", 9) == 0) { X strcpy(subj, line); X continue; X } X if (strncmp(line, "To: ", 4) == 0) { X strcat(to, line); X continue; X } X if (strncmp(line, "Cc: ", 4) == 0) { X strcat(cc, line); X continue; X } X } X if (state != Initial) X fclose(mp); X fclose(mbp); X if (!issysmbox(mbox)) { X if (unlink(mbox) < 0) X puts("Couldn't delete the mailbox."); X } X else { X if ((mbp = efopen(mbox, "w")) == (FILE *) 0) X puts("Couldn't empty your mailbox; check the ownership."); X else X fclose(mbp); X if (lockmbox(0) < 0) X puts("Can't unlock your mailbox (please inform a system administrator)."); X } X if (cnt == 0) { X puts("No new messages."); X return 0; X } X printf("Received %d new message%s into folder.\n", cnt, (cnt == 1? "": "s")); X return first; X} X Xlockmbox(flag) { X char lockname[1024]; X struct stat sbuf; X long now; X int lfd; X X strcpy(lockname, sysmbox); X strcat(lockname, ".lock"); X if (flag == 0) X return unlink(lockname); X if (stat(lockname, &sbuf) == 0) { X time(&now); X if (now - sbuf.st_ctime < 300) X return -1; X else if (unlink(lockname) < 0) { X puts("Can't unlock your mailbox (fatal error)."); X exit(1); X } X } X if ((lfd = creat(lockname, 0600)) < 0) { X puts("Can't lock your mailbox (fatal error)."); X exit(1); X } X close(lfd); X return 0; X} X Xnewmail(f) Xchar *f; { X struct stat sbuf; X X if (stat(f, &sbuf) < 0) X return 0; X return sbuf.st_size > 0L; X} X X/* X * line contains ``>From user ...'' X * if after date comes ``remote from ...'' then generate new path from it X */ X Xrmtinc(path, line) Xchar *path, *line; { X char *cp, *rpath; X X if (line[strlen(line) - 1] == '\n') X line[strlen(line) - 1] = '\0'; X for (cp = line + strlen(line) - 1; *cp == ' '; cp--) X if (cp == line) X return 0; X *(cp + 1) = '\0'; X while (*cp != ' ') X if (--cp == line) X return 0; X rpath = cp + 1; X while (*cp == ' ') X if (--cp == line) X return 0; X *(cp + 1) = '\0'; X while (*cp != ' ') X if (--cp == line) X return 0; X if (strcmp(cp + 1, "from") != 0) X return 0; X while (*cp == ' ') X if (--cp == line) X return 0; X *(cp + 1) = '\0'; X while (*cp != ' ') X if (--cp == line) X return 0; X if (strcmp(cp + 1, "remote") != 0) X return 0; X cp = line + 6; X while (*cp != ' ') X cp++; X *cp = '\0'; X sprintf(path, "Path: %s!%s\n", rpath, line + 6); X return 1; X} --EOF:imsinc.c-- fi if test -r "imssend.c"; then echo "File imssend.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="imssend.c" esac else newname="imssend.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:imssend.c--' > "$newname" X#include "ims.h" X Xchar *mdate(); X Xchar sender[1024] = "/bin/mail"; Xchar editor[1024] = "/usr/ucb/vi"; Xchar edforward[256] = "No"; Xchar alicount[256] = "20"; X Xstatic char *_month_[] = { X "January", X "February", X "March", X "April", X "May", X "June", X "July", X "August", X "September", X "October", X "November", X "December", X}; X Xstatic char *_weekday_[] = { X "Sunday", X "Monday", X "Tuesday", X "Wednesday", X "Thursday", X "Friday", X "Saturday", X}; X Xsendmail(fd, to, cc, subj, bcc) XFILE *fd; Xchar *to, *cc, *subj, *bcc; { X char *cp; X FILE *rmail; X char name[512]; X static char toline[512], ccline[512]; X struct passwd *curuser; X X if (fd == (FILE *) 0) X return 0; X if ((curuser = getpwnam(getlogin())) == (struct passwd *) 0) { X puts("Who are you, anyway? I can't send mail from nobody!"); X return -1; X } X strcpy(name, curuser->pw_gecos); X if ((cp = strchr(name, ',')) != (char *) 0) X *cp = '\0'; X strcpy(toline, to); X strcpy(ccline, cc); X while (*to == ' ' || *to == '\t') X to++; X if (*to == '\0') { X puts("Empty To: list."); X return 0; X } X sendlist(to, name, toline, ccline, subj, fd, 0); X sendlist(cc, name, toline, ccline, subj, fd, 0); X sendlist(bcc, name, toline, ccline, subj, fd, 0); X return 1; X} X Xsendlist(list, from, toline, ccline, subj, fd, acount) Xchar *list, *from, *toline, *ccline, *subj; XFILE *fd; { X char *cp; X char aexp[1024]; X X if (atoi(alicount) < 0) X strcpy(alicount, "20"); X if (acount > atoi(alicount)) { X puts("Alias loop."); X return -1; X } X while (*list != '\0') { X while (*list == ' ' || *list == '\t') X list++; X for (cp = list; *cp != ',' && *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X if (*list == '\0') X break; X if (xalias(list, aexp)) X return sendlist(aexp, from, toline, ccline, subj, fd, acount + 1); X smtp(from, list, toline, ccline, subj, fd); X list = cp; X } X return 1; X} X Xsmtp(from, to, toline, ccline, subjline, fp) Xchar *from, *to, *toline, *ccline, *subjline; XFILE *fp; { X char cmd[256]; X char ch; X FILE *rmail; X X sprintf(cmd, "exec %s %s", sender, to); X if ((rmail = epopen(cmd, "w")) == (FILE *) 0) { X puts("Can't run mailer."); X return 0; X } X fprintf(rmail, "Date: %s\nFrom: %s <%s>\nSubject: %s\nTo: %s\n%s%s\n", mdate(), from, getlogin(), subjline, toline, (ccline[0] == '\0'? "": "Cc: "), ccline, (ccline[0] == '\0'? "": "\n")); X rewind(fp); X while ((ch = getc(fp)) != EOF) X putc(ch, rmail); X if (pclose(rmail) != 0) X printf("Mailer failed to %s.\n", to); X} X Xreply(cmdp) Xchar *cmdp; { X char *cp; X char curbuf[256], to[256], cc[256], subj[256], bcc[256], tmpf[80], mline[5120]; X FILE *fp, *mfp; X X while (*cmdp == ' ' || *cmdp == '\t') X cmdp++; X if (*cmdp != '\0') { X for (cp = cmdp; *cp != ' ' && *cp != '\t' && *cp != '\0'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X while (*cp == ' ' || *cp == '\t') X cp++; X if (*cp != '\0') { X puts("Wrong number of arguments. Usage: reply [message-number]"); X return -1; X } X if (!ismsg(cmdp)) { X puts("No such message."); X return -1; X } X if (isdeleted(cmdp)) { X sprintf(curbuf, ".%s", cmdp); X cmdp = curbuf; X } X } X else { X sprintf(curbuf, "%d", msg); X if (isdeleted(curbuf)) X sprintf(curbuf, ".%d", msg); X cmdp = curbuf; X } X bcc[0] = '\0'; X gettcs(cmdp, to, cc, subj); X edenv(to, cc, subj, bcc); X sprintf(tmpf, "/tmp/ms%05dr", getpid()); X if ((fp = efopen(tmpf, "w")) == (FILE *) 0) { X puts("Can't open message temp file."); X return -1; X } X if ((mfp = efopen(mlocation(cmdp), "r")) == (FILE *) 0) { X perror(mlocation(cmdp)); X puts("Can't open original message."); X fputs("> Couldn't copy the original message.\n", fp); X fclose(fp); X } X else { X fputs("+---------------\n", fp); X while (fgets(mline, sizeof mline, mfp) != (char *) 0) { X fputs("| ", fp); X fputs(mline, fp); X } X fputs("+---------------\n\n\n", fp); X fclose(fp); X fclose(mfp); X } X enter(tmpf); X if (!suresend()) { X unlink(tmpf); X puts("Reply aborted."); X return 1; X } X puts("Please check the envelope below and make any necessary changes."); X if (!edenv(to, cc, subj, bcc)) X return -1; X if ((fp = efopen(tmpf, "r")) == (FILE *) 0) { X puts("Can't open reply file."); X return -1; X } X if (!sendmail(fp, to, cc, subj, bcc)) { X fclose(fp); X dead(tmpf); X } X fclose(fp); X unlink(tmpf); X return 1; X} X Xmailto(cmdp) Xchar *cmdp; { X char *cp; X char curbuf[256], to[256], cc[256], subj[256], bcc[256], tmpf[80]; X FILE *fp; X X while (*cmdp == ' ' || *cmdp == '\t') X cmdp++; X if (*cmdp != '\0') { X for (cp = cmdp; *cp != ' ' && *cp != '\t' && *cp != '\0'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X while (*cp == ' ' || *cp == '\t') X cp++; X if (*cp != '\0') { X puts("Wrong number of arguments. Usage: mail [user-name]"); X return -1; X } X } X bcc[0] = '\0'; X strcpy(to, cmdp); X subj[0] = '\0'; X cc[0] = '\0'; X edenv(to, cc, subj, bcc); X sprintf(tmpf, "/tmp/ms%05ds", getpid()); X if ((fp = efopen(tmpf, "w")) == (FILE *) 0) { X puts("Can't open message temp file."); X return -1; X } X fclose(fp); X enter(tmpf); X if (!suresend()) { X unlink(tmpf); X puts("Mail aborted."); X return 1; X } X puts("Please check the envelope below and make any necessary changes."); X if (!edenv(to, cc, subj, bcc)) X return -1; X if ((fp = efopen(tmpf, "r")) == (FILE *) 0) { X puts("Can't open message temp file."); X return -1; X } X if (!sendmail(fp, to, cc, subj, bcc)) { X fclose(fp); X dead(tmpf); X } X fclose(fp); X unlink(tmpf); X return 1; X} X Xforward(cmdp) Xchar *cmdp; { X char *cp; X char curbuf[256], to[256], cc[256], subj[256], bcc[256], tmpf[80]; X static char mline[5120]; X FILE *fp, *mfp; X X while (*cmdp == ' ' || *cmdp == '\t') X cmdp++; X if (*cmdp == '\0') { X puts("Wrong number of arguments. Usage: forward user-name [message-number]"); X return -1; X } X for (cp = cmdp; *cp != ' ' && *cp != '\t' && *cp != '\0'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X strcpy(to, cmdp); X cmdp = cp; X if (*cmdp != '\0') { X for (cp = cmdp; *cp != ' ' && *cp != '\t' && *cp != '\0'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X while (*cp == ' ' || *cp == '\t') X cp++; X if (*cp != '\0') { X puts("Wrong number of arguments. Usage: forward user-name [message-number]"); X return -1; X } X if (!ismsg(cmdp)) { X puts("No such message."); X return -1; X } X if (isdeleted(cmdp)) { X sprintf(curbuf, ".%s", cmdp); X cmdp = curbuf; X } X } X else { X sprintf(curbuf, "%d", msg); X if (isdeleted(curbuf)) X sprintf(curbuf, ".%d", msg); X cmdp = curbuf; X } X gettcs(cmdp, (char *) 0, (char *) 0, subj); X if (subj[0] == '\0') X sprintf(subj, "Mail forwarded from \"%s\"", getlogin()); X bcc[0] = '\0'; X cc[0] = '\0'; X edenv(to, cc, subj, bcc); X sprintf(tmpf, "/tmp/ms%05df", getpid()); X if ((fp = efopen(tmpf, "w")) == (FILE *) 0) { X puts("Can't open message temp file."); X return -1; X } X if ((mfp = efopen(mlocation(cmdp), "r")) == (FILE *) 0) { X perror(mlocation(cmdp)); X puts("Can't open original message."); X fclose(fp); X unlink(tmpf); X return -1; X } X else { X while (fgets(mline, sizeof mline, mfp) != (char *) 0) X fputs(mline, fp); X fclose(fp); X fclose(mfp); X } X if ((edforward[0] == 'Y' || edforward[0] == 'y' || edforward[0] == 'T' || edforward[0] == 't') && isatty(0)) X enter(tmpf); X if (!suresend()) { X unlink(tmpf); X puts("Forward aborted."); X return 1; X } X if (edforward[0] == 'Y' || edforward[0] == 'y' || edforward[0] == 'T' || edforward[0] == 't') X edenv(to, cc, subj, bcc); X if ((fp = efopen(tmpf, "r")) == (FILE *) 0) { X puts("Can't open message temp file."); X return -1; X } X if (!sendmail(fp, to, cc, subj, bcc)) { X fclose(fp); X dead(tmpf); X } X fclose(fp); X unlink(tmpf); X return 1; X} X Xenter(file) Xchar *file; { X int (*intr)(), (*quit)(); X int pid, status; X X if (!isatty(0)) { X FILE *fp; X char iline[1024]; X X if ((fp = efopen(file, "w")) == (FILE *) 0) { X printf("Can't open file \"%s\".\n", file); X return; X } X while (gets(iline) != (char *) 0) X fprintf(fp, "%s\n", iline); X fclose(fp); X return; X } X switch (pid = fork()) { X case -1: X puts("Couldn't fork."); X break; X case 0: X setgid(getgid()); X setuid(getuid()); X execlp(editor, editor, file, (char *) 0); X perror(editor); X exit(0); X default: X intr = signal(SIGINT, SIG_IGN); X quit = signal(SIGQUIT, SIG_IGN); X while (wait(&status) != pid) X ; X signal(SIGINT, intr); X signal(SIGQUIT, quit); X if (status != 0) X puts("Editor failure detected."); X } X} X Xdead(file) Xchar *file; { X/* X * Usually, the real mailer (rmail) will deal with dead.letter files. If X * yours doesn't, change this function. X */ X} X Xedenv(to, cc, subj, bcc) Xchar *to, *subj, *cc, *bcc; { X printf("To: "); X edstr(to); X printf("Subject: "); X edstr(subj); X printf("Cc: "); X edstr(cc); X printf("Bcc: "); X edstr(bcc); X} X Xedstr(str) Xchar *str; { X char ch; X char *sp; X struct TERMIO ottyp, nttyp; X int (*intr)(), (*quit)(); X X if (ioctl(0, TIO_GET, &ottyp) < 0) X return; X intr = signal(SIGINT, SIG_IGN); X quit = signal(SIGQUIT, SIG_IGN); X nttyp = ottyp; X#ifdef USG X nttyp.c_lflag &= ~(ICANON|ECHO|ECHOE); X nttyp.c_cc[VMIN] = 1; X nttyp.c_cc[VTIME] = 0; X#else USG X nttyp.sg_flags |= CBREAK; X nttyp.sg_flags &= ~ECHO; X#endif USG X ioctl(0, TIO_SET, &nttyp); X for (sp = str; *sp != '\0'; sp++) X putchar(*sp); X for (;;) { X if ((ch = (getchar() & 0x7f)) == '\n') X break; X if (ch == nttyp.TIO_ERASE) { X if (sp == str) { X putchar('\7'); X continue; X } X putchar('\b'); X putchar(' '); X putchar('\b'); X sp--; X continue; X } X if (ch < ' ') { X putchar('\7'); X continue; X } X putchar(ch); X *sp++ = ch; X } X ioctl(0, TIO_SET, &ottyp); X putchar('\n'); X *sp = '\0'; X signal(SIGINT, intr); X signal(SIGQUIT, quit); X} X Xgettcs(msg, to, cc, subj) Xchar *msg, *to, *cc, *subj; { X FILE *fp; X char mline[5120]; X char *cp; X X if ((fp = efopen(mlocation(msg), "r")) == (FILE *) 0) { X puts("Can't read envelope of message."); X return; X } X if (to != (char *) 0) X to[0] = '\0'; X if (cc != (char *) 0) X cc[0] = '\0'; X if (subj != (char *) 0) X subj[0] = '\0'; X while (fgets(mline, sizeof mline, fp) != (char *) 0) { X if (mline[0] == '\n' || mline[0] == ' ') X break; X if ((cp = strrchr(mline, '\n')) != (char *) 0) X *cp = '\0'; X if (to != (char *) 0 && strncmp(mline, "Path: ", 6) == 0) { X if (to[0] != '\0') X strcat(to, ", "); X strcat(to, &mline[6]); X continue; X } X if (to != (char *) 0 && strncmp(mline, "To: ", 4) == 0) { X if (to[0] != '\0') X strcat(to, ", "); X strcat(to, &mline[4]); X continue; X } X if (subj != (char *) 0 && strncmp(mline, "Subject: ", 9) == 0) { X strcpy(subj, &mline[9]); X continue; X } X if (cc != (char *) 0 && strncmp(mline, "Cc: ", 4) == 0) { X if (cc[0] != '\0') X strcat(cc, ", "); X strcat(cc, &mline[4]); X continue; X } X } X fclose(fp); X} X Xchar *mdate() { X long now; X struct tm *today; X static char dbuf[80]; X int hr; X char ap; X#ifdef USG X extern int daylight; X extern char *tzname[]; X#endif USG X X time(&now); X today = localtime(&now); X if (today->tm_hour < 12) { X ap = 'A'; X hr = today->tm_hour; X } X else { X ap = 'P'; X hr = today->tm_hour - 12; X } X if (hr == 0) X hr = 12; X sprintf(dbuf, "%s, %s %d, 19%d at %d:%02d %c.M.", _weekday_[today->tm_wday], _month_[today->tm_mon], today->tm_mday, today->tm_year, hr, today->tm_min, ap); X#ifdef USG X tzset(); X strcat(dbuf, " "); X strcat(dbuf, tzname[daylight]); X#endif USG X return dbuf; X} X Xsuresend() { X char ch; X struct TERMIO ottyp, nttyp; X int (*intr)(), (*quit)(); X X if (ioctl(0, TIO_GET, &ottyp) < 0) X return 1; X intr = signal(SIGINT, SIG_IGN); X quit = signal(SIGQUIT, SIG_IGN); X nttyp = ottyp; X#ifdef USG X nttyp.c_lflag &= ~(ICANON|ECHO|ECHOE); X nttyp.c_cc[VMIN] = 1; X nttyp.c_cc[VTIME] = 0; X#else USG X nttyp.sg_flags |= CBREAK; X nttyp.sg_flags &= ~ECHO; X#endif USG X ioctl(0, TIO_SET, &nttyp); X printf("Are you sure you want to send this (Y)? "); X while ((ch = getchar()) == EOF || (ch < ' ' && ch != '\r' && ch != '\n' && ch != '\t') || ch > '~') X ; X if (ch == 'N' || ch == 'n' || ch == '\t') X puts("No"); X else X puts("Yes"); X ioctl(0, TIO_SET, &ottyp); X signal(SIGINT, intr); X signal(SIGQUIT, quit); X return ch != 'N' && ch != 'n' && ch != '\t'; X} X Xgetcont() { X struct TERMIO ottyp, nttyp; X int (*intr)(), (*quit)(); X X intr = signal(SIGINT, SIG_IGN); X quit = signal(SIGQUIT, SIG_IGN); X if (ioctl(0, TIO_GET, &ottyp) < 0) X return; X nttyp = ottyp; X#ifdef USG X nttyp.c_lflag &= ~(ICANON|ECHO|ECHOE); X nttyp.c_cc[VMIN] = 1; X nttyp.c_cc[VTIME] = 0; X#else USG X nttyp.sg_flags |= CBREAK; X nttyp.sg_flags &= ~ECHO; X#endif USG X ioctl(0, TIO_SET, &nttyp); X printf("--- Press any key to continue ---"); X getchar(); X printf("\r \r"); X ioctl(0, TIO_SET, &ottyp); X signal(SIGINT, intr); X signal(SIGQUIT, quit); X} --EOF:imssend.c-- fi if test -r "imsset.c"; then echo "File imsset.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="imsset.c" esac else newname="imsset.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:imsset.c--' > "$newname" X#include "ims.h" X Xstruct var { X char *v_name; X char *v_val; X} var[] = { X "folder", folder, X "cabinet", cabinet, X "prompt", prompt, X "pager", pager, X "system-mailbox", sysmbox, X "mail-sending-command", sender, X "mailbox", mailbox, X "editor", editor, X "save-folder", savefolder, X "print-command", printcmd, X "type-next-automatically", autonext, X "read-new-mail-automatically", autoread, X "ask-before-append", askappend, X "lines", lines, X "edit-forwarded-mail", edforward, X "alias-recursion-level", alicount, X (char *) 0, (char *) 0, X}; X Xreadvars() { X char vfile[256]; X char *cp; X X varead(IMSINIT); X if ((cp = getenv("IMSINIT")) != (char *) 0) X strcpy(vfile, cp); X else { X if ((cp = getenv("HOME")) == (char *) 0) X cp = "/usr/guest"; X sprintf(vfile, "%s/.imsinit", cp); X } X varead(vfile); X} X Xvaread(vfile) Xchar *vfile; { X char vline[512], v[80], val[128]; X char *cp, *dp, *ip; X FILE *fp; X int lineno, canon; X X if ((fp = efopen(vfile, "r")) == (FILE *) 0) X return; X lineno = 0; X while (fgets(vline, sizeof vline, fp) != (char *) 0) { X lineno++; X if ((cp = strchr(vline, '\n')) != (char *) 0) X *cp = '\0'; X if ((cp = strchr(vline, '#')) != (char *) 0) X *cp = '\0'; X for (cp = vline; *cp == ' ' || *cp == '\t'; cp++) X ; X if (*cp == '\0') X continue; X for (dp = v; *cp != '\0' && strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01235456789_-", *cp) != (char *) 0; cp++) X *dp++ = *cp; X *dp = '\0'; X if (v[0] == '\0') { X printf("Error in \"%s\", line %d: Missing or invalid variable name\n", vfile, lineno); X continue; X } X while (*cp == ' ' || *cp == '\t') X cp++; X if (*cp != '=') { X printf("Error in \"%s\", line %d: Missing ``=''\n", vfile, lineno); X continue; X } X cp++; X while (*cp == ' ' || *cp == '\t') X cp++; X canon = 0; X if (*cp == '"') { X canon = 1; X cp++; X } X for (dp = val; *cp != '\0' && (canon? *cp != '"': *cp != ' ' && *cp != '\t'); cp++) { X if (*cp == '\\' && *(cp + 1) != '\0') X *dp++ = *++cp; X else if (*cp != '\\') X *dp++ = *cp; X else { X *dp++ = '\n'; X if (fgets(vline, sizeof vline, fp) == (char *) 0) { X cp++; X printf("Unexpected end of file in \"%s\", line %d\n", vfile, lineno + 1); X break; X } X lineno++; X if ((ip = strchr(vline, '\n')) != (char *) 0) X *ip = '\0'; X if ((ip = strchr(vline, '#')) != (char *) 0) X *ip = '\0'; X cp = vline; X *dp++ = *cp; X } X } X if (canon) { X if (*cp == '\0') { X printf("Error in \"%s\", line %d: No closing quote\n", vfile, lineno); X continue; X } X cp++; X } X *dp = '\0'; X while (*cp == ' ' || *cp == '\t') X cp++; X if (*cp != '\0') { X printf("Error in \"%s\", line %d: Text after set command\n", vfile, lineno); X continue; X } X setvar(v, val); X } X fclose(fp); X} X Xsetvar(v, val) Xchar *v, *val; { X struct var *vp; X X for (vp = var; vp->v_name != (char *) 0; vp++) X if (strcmp(vp->v_name, v) == 0) X break; X if (vp->v_name == (char *) 0) { X printf("Unknown variable: %s\n", v); X return -1; X } X strcpy(vp->v_val, val); X return 0; X} X Xvarops(cmdp) Xchar *cmdp; { X char *cp, *dp; X char v[80], val[128]; X int canon; X X while (*cmdp == ' ' || *cmdp == '\t') X ; X if (*cmdp == '\0') { X listvar(""); X return 1; X } X for (dp = v, cp = cmdp; *cp != '\0' && strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01235456789_-", *cp) != (char *) 0; cp++) X *dp++ = *cp; X *dp = '\0'; X while (*cp == ' ' || *cp == '\t') X cp++; X if (*cp == '\0') { X listvar(v); X return 1; X } X if (*cp != '=') { X puts("Invalid assignment statement syntax. Usage: set [variable [= value]]"); X return -1; X } X cp++; X while (*cp == ' ' || *cp == '\t') X cp++; X canon = 0; X if (*cp == '"') { X canon = 1; X cp++; X } X for (dp = val; *cp != '\0' && (canon? *cp != '"': *cp != ' ' && *cp != '\t'); cp++) { X if (*cp == '\\' && *(cp + 1) != '\0') X *dp++ = *++cp; X else if (*cp != '\\') X *dp++ = *cp; X else { X puts("Multiline variables invalid on command line."); X return -1; X } X } X if (canon) { X if (*cp == '\0') { X printf("Missing closing quote."); X return -1; X } X cp++; X } X *dp = '\0'; X while (*cp == ' ' || *cp == '\t') X cp++; X if (*cp != '\0') { X printf("Extra text after assignment."); X return -1; X } X setvar(v, val); X return 1; X} X Xlistvar(v) Xchar *v; { X struct var *vp; X int cnt; X X cnt = 0; X for (vp = var; vp->v_name != (char *) 0; vp++) X if (v[0] == '\0' || strcmp(vp->v_name, v) == 0) { X printf("%s => \"%s\"\n", vp->v_name, vp->v_val); X cnt++; X } X if (cnt == 0) X if (v[0] == '\0') X puts("There are no variables in this version of IMS."); X else X printf("Unknown variable: \"%s\".\n", v); X} --EOF:imsset.c-- fi if test -r "imsalias.c"; then echo "File imsalias.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="imsalias.c" esac else newname="imsalias.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:imsalias.c--' > "$newname" X#include "ims.h" X Xstruct alias { X char *a_name; X char *a_value; X struct alias *a_next; X} *alias = (struct alias *) 0; X Xreadalias() { X char vfile[256]; X char *cp; X X aliread(IMSALIAS); X if ((cp = getenv("IMSALIAS")) != (char *) 0) X strcpy(vfile, cp); X else { X if ((cp = getenv("HOME")) == (char *) 0) X cp = "/usr/guest"; X sprintf(vfile, "%s/.imsalias", cp); X } X aliread(vfile); X} X Xaliread(vfile) Xchar *vfile; { X char vline[1024], v[80], val[1024]; X char *cp, *dp, *ip; X FILE *fp; X int lineno; X X if ((fp = efopen(vfile, "r")) == (FILE *) 0) X return; X lineno = 0; X while (fgets(vline, sizeof vline, fp) != (char *) 0) { X lineno++; X if ((cp = strchr(vline, '\n')) != (char *) 0) X *cp = '\0'; X if ((cp = strchr(vline, '#')) != (char *) 0) X *cp = '\0'; X for (cp = vline; *cp == ' ' || *cp == '\t'; cp++) X ; X if (*cp == '\0') X continue; X for (dp = v; *cp != '\0' && strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01235456789_-", *cp) != (char *) 0; cp++) X *dp++ = *cp; X *dp = '\0'; X if (v[0] == '\0') { X printf("Error in \"%s\", line %d: Missing or invalid alias name\n", vfile, lineno); X continue; X } X while (*cp == ' ' || *cp == '\t') X cp++; X if (*cp != ':') { X printf("Error in \"%s\", line %d: Missing ``:''\n", vfile, lineno); X continue; X } X cp++; X while (*cp == ' ' || *cp == '\t') X cp++; X for (dp = val; *cp != '\0'; cp++) { X if (*cp == '\\' && *(cp + 1) != '\0') X *dp++ = *++cp; X else if (*cp != '\\') X *dp++ = *cp; X else { X *dp++ = '\n'; X if (fgets(vline, sizeof vline, fp) == (char *) 0) { X cp++; X printf("Unexpected end of file in \"%s\", line %d\n", vfile, lineno + 1); X break; X } X lineno++; X if ((ip = strchr(vline, '\n')) != (char *) 0) X *ip = '\0'; X if ((ip = strchr(vline, '#')) != (char *) 0) X *ip = '\0'; X cp = vline; X *dp++ = *cp; X } X } X setalias(v, val); X } X fclose(fp); X} X Xsetalias(ali, value) Xchar *ali, *value; { X struct alias *ap, *newa; X X for (ap = alias; ap->a_name != (char *) 0; ap = ap->a_next) X if (strcmp(ap->a_name, ali) == 0) X break; X if (ap->a_name == (char *) 0) { X if (value == (char *) 0 || value[0] == '\0') { X printf("No such alias: %s.\n", ali); X return -1; X } X if ((newa = (struct alias *) calloc(1, sizeof *newa)) == (struct alias *) 0) { X fprintf(stderr, "No room for new alias: %s.\n", ali); X return -1; X } X if ((newa->a_name = calloc(strlen(ali) + 1, sizeof *newa->a_name)) == (char *) 0) { X fprintf(stderr, "No room for new alias name: %s.\n", ali); X free((char *) newa); X return -1; X } X if ((newa->a_value = calloc(strlen(value) + 1, sizeof *newa->a_value)) == (char *) 0) { X fprintf(stderr, "No room for new alias value: %s.\n", ali); X free(newa->a_name); X free((char *) newa); X return -1; X } X strcpy(newa->a_name, ali); X strcpy(newa->a_value, value); X newa->a_next = alias; X alias = newa; X return 2; X } X free(ap->a_value); X if (value == (char *) 0 || value[0] == '\0') { X free(ap->a_name); X for (newa = alias; newa->a_next != (struct alias *) 0; newa = ap->a_next) X if (newa->a_next == ap) X break; X if (newa == (struct alias *) 0) X alias = ap->a_next; X else X newa->a_next = ap->a_next; X free((char *) ap); X return 0; X } X if ((ap->a_value = calloc(strlen(value), sizeof *ap->a_value)) == (char *) 0) { X fprintf(stderr, "No space for new value of alias: %s. Alias deleted.\n", ali); X for (newa = alias; newa->a_next != (struct alias *) 0; newa = newa->a_next) X if (newa->a_next == ap) X break; X if (newa == (struct alias *) 0) X alias = ap->a_next; X else X newa->a_next = ap->a_next; X free(ap->a_name); X free((char *) ap); X return -1; X } X strcpy(ap->a_value, value); X return 1; X} X Xxalias(to, buf) Xchar *to, *buf; { X struct alias *ap; X X for (ap = alias; ap != (struct alias *) 0; ap = ap->a_next) X if (strcmp(ap->a_name, to) == 0) X break; X if (ap == (struct alias *) 0) { X strcpy(buf, to); X return 0; X } X strcpy(buf, ap->a_value); X return 1; X} X Xunalias(cmdp) Xchar *cmdp; { X char *cp; X int didalias; X X didalias = 0; X X while (*cmdp != '\0') { X while (*cmdp == ' ' || *cmdp == '\t') X cmdp++; X if (*cmdp == '\0') X break; X for (cp = cmdp; *cp != ',' && *cp != ' ' && *cp != '\t'; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X didalias++; X setalias(cmdp, ""); X cmdp = cp; X } X if (didalias == 0) { X puts("Usage: unalias alias-list\n"); X return -1; X } X return 1; X} X Xaliasops(cmdp) Xchar *cmdp; { X char *cp, *dp; X char aexp[1024]; X X while (*cmdp == ' ' || *cmdp == '\t') X cmdp++; X if (*cmdp == '\0') X return listalias(); X for (cp = cmdp; *cp != '\0' && *cp != '\t' && *cp != ' '; cp++) X ; X if (*cp != '\0') X *cp++ = '\0'; X for (dp = cmdp; *dp != '\0' && strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01235456789_-", *dp) != (char *) 0; dp++) X ; X if (*dp != '\0') { X printf("Illegal alias name: %s.\n", cmdp); X return -1; X } X while (*cp == ' ' || *cp == '\t') X cp++; X if (*cp == '\0') X if (xalias(cmdp, aexp)) { X printf("Alias %s: %s\n", cmdp, aexp); X return 1; X } X else { X printf("Unknown alias: %s.\n", cmdp); X return -1; X } X if (setalias(cmdp, cp) < 0) X return -1; X return 1; X} X Xlistalias() { X struct alias *ap; X int nalias; X X nalias = 0; X for (ap = alias; ap != (struct alias *) 0; ap = ap->a_next, nalias++) X printf(" %s: %s\n", ap->a_name, ap->a_value); X if (nalias != 0) X return 1; X puts("No aliases defined."); X return -1; X} --EOF:imsalias.c-- fi exit 0 -- ---------------- **** Brandon S. Allbery UUCP: / / **** Tridelta Industries, Inc. decvax!cwruecmp!ncoast! ---- -------- **** 7350 Corporate Blvd. tdi2!brandon / / /---, /--/ Mentor, Ohio 44060 PHONE: (home) / / / / / / -- HOME -- +1 216 974 9210 / / / / / / 6615 Center St. Apt. A1-105 ARPA: ncoast!allbery% ---- /----~ /--/ Mentor, Ohio 44060-4101 case.CSNET@csnet-relay ------------------------------------------------------------------------------- Space -- The Final Frontier
allbery@ncoast.UUCP (Brandon S. Allbery) (07/22/86)
#! /bin/sh if test -r "ndir.c"; then echo "File ndir.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="ndir.c" esac else newname="ndir.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:ndir.c--' > "$newname" X#include <sys/types.h> X#include "ndir.h" X X#ifndef BSD X X/* X * close a directory. X */ Xclosedir(dirp) X register DIR *dirp; X{ X close(dirp->dd_fd); X dirp->dd_fd = -1; X dirp->dd_loc = 0; X free(dirp); X} X X X X/* X * open a directory. X */ XDIR * Xopendir(name) X char *name; X{ X register DIR *dirp; X register int fd; X X if ((fd = eopen(name, 0)) == -1) X return NULL; X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { X close (fd); X return NULL; X } X dirp->dd_fd = fd; X dirp->dd_loc = 0; X return dirp; X} X X X X/* X * read an old style directory entry and present it as a new one X */ X#define ODIRSIZ 14 X Xstruct olddirect { X ino_t od_ino; X char od_name[ODIRSIZ]; X}; X X/* X * get next entry in a directory. X */ Xstruct direct * Xreaddir(dirp) X register DIR *dirp; X{ X register struct olddirect *dp; X static struct direct dir; X X for (;;) { X if (dirp->dd_loc == 0) { X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, X DIRBLKSIZ); X if (dirp->dd_size <= 0) X return NULL; X } X if (dirp->dd_loc >= dirp->dd_size) { X dirp->dd_loc = 0; X continue; X } X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc); X dirp->dd_loc += sizeof(struct olddirect); X if (dp->od_ino == 0) X continue; X dir.d_ino = dp->od_ino; X strncpy(dir.d_name, dp->od_name, ODIRSIZ); X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */ X dir.d_namlen = strlen(dir.d_name); X dir.d_reclen = DIRBLKSIZ; X return (&dir); X } X} X X#endif BSD --EOF:ndir.c-- fi if test -r "eopen.c"; then echo "File eopen.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="eopen.c" esac else newname="eopen.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:eopen.c--' > "$newname" X#include <stdio.h> X#include <errno.h> X Xextern int errno; Xstatic int __pop_pid = -1; X XFILE *efopen(file, mode) Xchar *file, *mode; { X int alevel, chmg; X FILE *fp; X X switch (mode[0]) { X case 'r': X alevel = 4; X break; X case 'w': X case 'a': X alevel = 2; X break; X } X if (mode[1] == '+') X alevel = 6; X chmg = 0; X if (access(file, alevel) < 0) X if (errno != ENOENT) X return (FILE *) 0; X else X chmg = 1; X if ((fp = fopen(file, mode)) == (FILE *) 0) X return (FILE *) 0; X if (chmg) X chown(file, getuid(), getgid()); X return fp; X} X Xeopen(file, mode) Xchar *file; { X int alevel, fd, chmg; X X switch (mode & 3) { X case 0: X alevel = 4; X break; X case 1: X alevel = 2; X break; X case 2: X alevel = 6; X break; X } X chmg = 0; X if (access(file, alevel) < 0) X if (errno != ENOENT) X return -1; X else X chmg = 1; X if ((fd = open(file, mode)) == -1) X return -1; X if (chmg) X chown(file, getuid(), getgid()); X return fd; X} X XFILE *epopen(cmd, mode) Xchar *mode; { X FILE *pfp; X int pfd[2]; X int pmode; X X pmode = (*mode == 'r'? 1: 0); X pipe(pfd); X switch (__pop_pid = fork()) { X case -1: X return (FILE *) 0; X case 0: X setgid(getgid()); X setuid(getuid()); X close(pmode); X dup(pfd[pmode]); X close(pfd[!pmode]); X close(pfd[pmode]); X execl("/bin/sh", "sh", "-c", cmd, (char *) 0); X _exit(100); X default: X close(pfd[pmode]); X return fdopen(pfd[!pmode], mode); X } X} X Xpclose(fp) XFILE *fp; { X int status; X X fclose(fp); X if (__pop_pid == -1) X return -1; X while (wait(&status) != __pop_pid) X ; X return status; X} --EOF:eopen.c-- fi if test -r "ims.h"; then echo "File ims.h exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="ims.h" esac else newname="ims.h" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:ims.h--' > "$newname" X#include <stdio.h> X#include <signal.h> X#include <setjmp.h> X#include <pwd.h> X#include <time.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <sys/ioctl.h> X#include "ndir.h" X X#define IMSINIT "/usr/lib/imsinit" X#define IMSALIAS "/usr/lib/imsaliases" X X#ifndef USG X#define strchr index X#define strrchr rindex X#endif USG X Xextern int readmsg(), printmsg(), reply(), gomsg(), mailto(), listmsg(), X forward(), byebye(), help(), setfolder(), readmbox(), savemsg(), X delmsg(), undelmsg(), nxbyebye(), expunge(), nextmsg(), prevmsg(), X varops(), foldlist(), aliasops(), unalias(); X Xextern char *location(); Xextern char *strchr(); Xextern char *strrchr(); Xextern char *getenv(); Xextern FILE *efopen(); Xextern char *mlocation(); Xextern char *mflocation(); Xextern char *calloc(); Xextern char *realloc(); Xextern FILE *epopen(); Xextern char *basename(); Xextern char *getlogin(); Xextern struct passwd *getpwnam(); Xextern struct tm *localtime(); X Xextern char folder[]; Xextern char cabinet[]; Xextern char pager[]; Xextern char sysmbox[]; Xextern char prompt[]; Xextern char sender[]; Xextern char mailbox[]; Xextern char editor[]; Xextern char printcmd[]; Xextern char savefolder[]; Xextern char autonext[]; Xextern char autoread[]; Xextern char askappend[]; Xextern char lines[]; Xextern char edforward[]; Xextern char alicount[]; Xextern int msg; X X#ifdef USG X#define SYSMAILBOX "/usr/mail/%s" X#else X#define SYSMAILBOX "/usr/spool/mail/%s" X#define strchr index X#define strrchr rindex X#endif USG X X#ifndef USG X#include <sgtty.h> X#define TERMIO sgttyb X#define TIO_GET TIOCGETP X#define TIO_SET TIOCSETN X#define TIO_ERASE sg_erase X#else USG X#include <termio.h> X#define TERMIO termio X#define TIO_GET TCGETA X#define TIO_SET TCSETAW X#define TIO_ERASE c_cc[VERASE] X#endif USG --EOF:ims.h-- fi if test -r "ndir.h"; then echo "File ndir.h exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="ndir.h" esac else newname="ndir.h" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:ndir.h--' > "$newname" X/* dir.h 4.4 82/07/25 */ X X#ifdef BSD X#include <sys/dir.h> X#else X X/* X * A directory consists of some number of blocks of DIRBLKSIZ X * bytes, where DIRBLKSIZ is chosen such that it can be transferred X * to disk in a single atomic operation (e.g. 512 bytes on most machines). X * X * Each DIRBLKSIZ byte block contains some number of directory entry X * structures, which are of variable length. Each directory entry has X * a struct direct at the front of it, containing its inode number, X * the length of the entry, and the length of the name contained in X * the entry. These are followed by the name padded to a 4 byte boundary X * with null bytes. All names are guaranteed null terminated. X * The maximum length of a name in a directory is MAXNAMLEN. X * X * The macro DIRSIZ(dp) gives the amount of space required to represent X * a directory entry. Free space in a directory is represented by X * entries which have dp->d_reclen >= DIRSIZ(dp). All DIRBLKSIZ bytes X * in a directory block are claimed by the directory entries. This X * usually results in the last entry in a directory having a large X * dp->d_reclen. When entries are deleted from a directory, the X * space is returned to the previous entry in the same directory X * block by increasing its dp->d_reclen. If the first entry of X * a directory block is free, then its dp->d_ino is set to 0. X * Entries other than the first in a directory do not normally have X * dp->d_ino set to 0. X */ X#define DIRBLKSIZ 512 X#define MAXNAMLEN 255 X Xstruct direct { X long d_ino; /* inode number of entry */ X short d_reclen; /* length of this record */ X short d_namlen; /* length of string in d_name */ X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ X}; X X/* X * The DIRSIZ macro gives the minimum record length which will hold X * the directory entry. This requires the amount of space in struct direct X * without the d_name field, plus enough space for the name with a terminating X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. X */ X#ifdef DIRSIZ X#undef DIRSIZ X#endif X#define DIRSIZ(dp) \ X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) X X#ifndef KERNEL X/* X * Definitions for library routines operating on directories. X */ Xtypedef struct _dirdesc { X int dd_fd; X long dd_loc; X long dd_size; X char dd_buf[DIRBLKSIZ]; X} DIR; X#ifndef NULL X#define NULL 0 X#endif Xextern DIR *opendir(); Xextern struct direct *readdir(); Xextern closedir(); X#endif KERNEL X X#endif BSD --EOF:ndir.h-- fi if test -r "ims.1"; then echo "File ims.1 exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="ims.1" esac else newname="ims.1" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:ims.1--' > "$newname" X.TH IMS LOCAL X.ds i \fBims\fR X.SH NAME X\*i \- Intelligent Message System X.SH SYNOPSIS X.B \*i X[ -i ] X.br X.B \*i X.I \*i-command-string X.SH DESCRIPTION X\*i is a mail system intended to replace X.BR mail (1) Xfor regular use. It uses X.B mail Xto send messages, in order to retain compatibility with other mailers. X.PP X\*i implements a true ``folder'' mechanism for handling mail. A mail Xcabinet (by default X.IR $HOME/.mail ) Xis established the first time the program is run, as is a standard Xfolder (by default X.IR incoming-mail ). XOn entry, mail is read into files in the standard folder, unless the X.I -i Xoption is given or an X.I \*i-command-string Xis specified. The message pointer is then set to the first new message Xand a command prompt is issued. X.PP XThere are two ways to use \*i: X.IR "interactive mode" , Xwhich issues a prompt until a X.I quit Xor X.I xit Xcommand is issued or a X.I control-D Xis typed, and X.IR "command mode" , Xwhich executes the command line and then exits as if the X.I xit Xcommand had been issued. The two modes are described in detail below. X.SH SETUP X\*i understands a number of environment variables, supports variables of Xits own, and provides reasonable defaults for anything not specified. XThe environment variables, \*i variables, and their meanings are described Xin Table 1 at the end of this document. X.PP XEnvironment variables are specified in the usual way (see X.IR sh (1) Xor X.IR csh (1) Xfor examples). \*i variables are set in the file specified by the X.I IMSINIT Xvariable, or $HOME/.imsinit if no X.I IMSINIT Xenvironment variable exists. They may also be set by the X.I set Xcommand from within \*i. XThere is also a system IMSINIT file, X.IR /usr/lib/imsinit . X.PP XThe X.I IMSINIT Xfile contains assignment statements of the form: X.sp X.nf X.ce X\fIvariable\fR = \fIvalue\fR X.fi X.sp XA X.I value Xmay be a single word or quoted text; if quoted, the value may comprise Xseveral lines of the X.I IMSINIT Xfile, but this is discouraged because few, if any, \*i commands make use Xof multiple-line values. The X.I print-command Xvariable is a possible exception. X.SH COMMANDS X\*i supports a large number of commands for manipulating messages and Xfolders. They are detailed below. X.nr i) 5 X.de LS X.PP X.ns X.in +5n+\\n(i)n X.ll -5n X.. X.de LI X.sp X.ti -\\n(i)n X\fB\\$1\fR \- X.. X.de L+ X.sp X.ti -\\n(i)n X\fB\\$1\fR X.br X.ns X.. X.de LE X.ll X.in X.PP X.ns X.. X.LS X.LI delete XDelete the named message, or the current message. If X.I type-next-automatically Xis affirmative, a X.I type Xcommand is executed with no arguments afterward. X.LI undelete XRestore a message deleted with the X.I delete Xcommand. Note that if X.I xit Xis used to exit \*i, deleted messages will remain deleted but will also Xremain recoverable; an X.I expunge Xcommand, either explicit or via the X.I quit Xcommand, is required to physically delete messages. X.LI expunge XPhysically delete messages marked for deletion with the X.I delete Xcommand. An implicit X.I expunge Xis done by the X.I quit Xcommand. Unless an X.I expunge Xis performed, deleted messages still exist and are recoverable with X.IR undelete . X