home *** CD-ROM | disk | FTP | other *** search
- From: argv@zipcode.com (Dan Heller)
- Newsgroups: comp.sources.misc
- Subject: v18i065: mush - Mail User's Shell, Part08/22
- Message-ID: <1991Apr21.025028.11432@sparky.IMD.Sterling.COM>
- Date: 21 Apr 91 02:50:28 GMT
- Approved: kent@sparky.imd.sterling.com
- X-Checksum-Snefru: 66a5696c f93bd72d c9b78bc9 6dad1564
-
- Submitted-by: Dan Heller <argv@zipcode.com>
- Posting-number: Volume 18, Issue 65
- Archive-name: mush/part08
- Supersedes: mush: Volume 12, Issue 28-47
-
- #!/bin/sh
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file expr.c continued
- #
- if test ! -r _shar_seq_.tmp; then
- echo 'Please unpack part 1 first!'
- exit 1
- fi
- (read Scheck
- if test "$Scheck" != 8; then
- echo Please unpack part "$Scheck" next!
- exit 1
- else
- exit 0
- fi
- ) < _shar_seq_.tmp || exit 1
- if test ! -f _shar_wnt_.tmp; then
- echo 'x - still skipping expr.c'
- else
- echo 'x - continuing file expr.c'
- sed 's/^X//' << 'SHAR_EOF' >> 'expr.c' &&
- X */
- char *
- eval_expr(p, new_list)
- register char *p, new_list[];
- {
- X register char *p2, **argv;
- X int argc;
- X u_long save_flags = glob_flags;
- X
- X if (!(p2 = index(++p, '`'))) {
- X print("unmatched backquote (`)\n");
- X return NULL;
- X }
- X *p2 = 0;
- X
- X skipspaces(0);
- X if (!*p) {
- X print("Invalid null command\n");
- X return NULL;
- X }
- X turnon(glob_flags, DO_PIPE);
- X /* ignore sigs only because if user interrupts the do_command,
- X * the longjmp will corrupt the stack and the program is hosed.
- X * fix is to have layers of jmp_bufs to return to different levels.
- X */
- X turnon(glob_flags, IGN_SIGS);
- X if (*p && (argv = make_command(p, TRPL_NULL, &argc)))
- X (void) do_command(argc, argv, new_list);
- X glob_flags = save_flags;
- X *p2 = '`';
- X return p2+1;
- }
- SHAR_EOF
- echo 'File expr.c is complete' &&
- chmod 0644 expr.c ||
- echo 'restore of expr.c failed'
- Wc_c="`wc -c < 'expr.c'`"
- test 4685 -eq "$Wc_c" ||
- echo 'expr.c: original size 4685, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= file.c ==============
- if test -f 'file.c' -a X"$1" != X"-c"; then
- echo 'x - skipping file.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting file.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'file.c' &&
- /* file.c -- Copyright (1988) Dan Heller */
- X
- #include "mush.h"
- #include <pwd.h>
- X
- /* takes string 'p' and address of int (isdir). If p uses the ~ to reference
- X * a home directory of some sort, then expand it. find out what sort of
- X * file final path is. set isdir to 1 if a directory, 0 if not, -1 on error
- X * return final path. If an error occurs, return string indicating error.
- X * if isdir has a value of 1 when passed, it ignores "No such file or directory"
- X */
- char *
- getpath(p, isdir)
- register char *p;
- int *isdir;
- {
- X static char buf[MAXPATHLEN];
- X struct stat stat_buf;
- X
- X if (p != buf) { /* Just in case */
- X if (!p || !*p || !strcmp(p, "~")) {
- X char *home = do_set(set_options, "home");
- X if (!home || !*home)
- X home = ALTERNATE_HOME;
- X (void) strcpy(buf, home); /* no arg means home */
- X } else if (*p == '~') {
- X if (p[1] != '/') {
- X /* not our home, but someone else's
- X * look for ~user or ~user/subpath
- X * if '/' exists, separate into tmp="user" p="subpath"
- X */
- X struct passwd *ent, *getpwnam();
- X char *p2 = p+1;
- X if (p = index(p2, '/'))
- X *p++ = 0;
- X if (!(ent = getpwnam(p2))) {
- X *isdir = -1;
- X return sprintf(buf, "no such user: %s", p2);
- X }
- X /* append subpath to pathname */
- X if (p && *p)
- X (void) sprintf(buf, "%s/%s", ent->pw_dir, p);
- X /* if *p == NULL, pathname is done (buf), set isdir = 1 */
- X else {
- X *isdir = 1;
- X return strcpy(buf, ent->pw_dir);
- X }
- X } else {
- X char *home = do_set(set_options, "home");
- X if (!home || !*home)
- X home = ALTERNATE_HOME;
- X (void) sprintf(buf, "%s/%s", home, p+2);
- X }
- X } else if (*p == '%') {
- X /* if %user, append user name... else, it's just us */
- X if (!*++p || *p == ' ' || *p == '\t')
- X (void) strcpy(buf, spoolfile);
- X else
- #ifndef HOMEMAIL
- X (void) sprintf(buf, "%s/%s", MAILDIR, p);
- #else /* HOMEMAIL */
- X {
- X /* If it's NOT us, recur to get the path for ~user/MAILFILE */
- X int t_isdir = *isdir;
- X char *t, tmp[MAXPATHLEN];
- X (void) sprintf(tmp, "~%s/%s", p, MAILFILE);
- X t = getpath(tmp, &t_isdir);
- X if (t_isdir == -1) {
- X *isdir = -1;
- X return t;
- X }
- X /* strcpy(buf, t); --buf already has info because it's static */
- X }
- #endif /* HOMEMAIL */
- X } else if (*p == '+') {
- X register char *p2 = do_set(set_options, "folder");
- X if (!p2 || !*p2)
- X p2 = DEF_FOLDER;
- X if (*++p)
- X (void) sprintf(buf, "%s/%s", p2, p);
- X else
- X (void) strcpy(buf, p2);
- X if (*buf != '/') {
- X int t_isdir = *isdir;
- X char *t, tmp[MAXPATHLEN];
- X if (*buf != '~')
- X (void) sprintf(tmp, "~/%s", buf);
- X else
- X (void) strcpy(tmp, buf);
- X t = getpath(tmp, &t_isdir);
- X if (t_isdir == -1) {
- X *isdir = -1;
- X return t;
- X }
- X /* strcpy(buf, t); --buf already has info because it's static */
- X }
- X } else { /* allow \ to escape the special chars, +, %, ~ */
- X if (*p == '\\')
- X p++;
- X (void) strcpy(buf, p);
- X }
- X }
- X if (stat(buf, &stat_buf)) {
- X (void) access(buf, F_OK); /* set errno to the "real" reason */
- X if (errno == ENOENT && *isdir == 1) {
- X *isdir = 0; /* say it's a regular file even tho it doesn't exist */
- X return buf; /* it may be wanted for creating */
- X }
- X *isdir = -1;
- X return sys_errlist[errno];
- X }
- X *isdir = ((stat_buf.st_mode & S_IFMT) == S_IFDIR);
- X return buf;
- }
- X
- /*
- X * Given a (possibly NULL or empty) string, return the name of a a valid
- X * directory. The string may contain the usual filename metachars (see
- X * above). Returns the current user's home directory if the input string
- X * does not refer to a directory, the ALTERNATE_HOME if the user's home
- X * directory cannot be found, or NULL if none of the above are accessible.
- X *
- X * NOTE: Returns the getpath() static buffer, so the same caveats apply.
- X */
- char *
- getdir(path)
- char *path;
- {
- X int isdir = 0;
- X
- X /* getpath() already handles the NULL and empty cases */
- X if (!(path = getpath(path, &isdir)) || isdir != 1) {
- X isdir = 0;
- X path = getpath(ALTERNATE_HOME, &isdir);
- X if (isdir != 1)
- X path = NULL;
- X }
- X return path;
- }
- X
- /*
- X * Given a filename[pointer] (p), a file pointer, and a mode, file_to_fp
- X * opens the file with the mode.
- X * If the mode is "r" then we read the file into the file pointer at the
- X * end (fseek(fp, 2, 0)). If the file is opened for writing, then read
- X * from the beginning of fp and write it into the file.
- X * This is usually called to read .signatures into messages (thus,
- X * opening .signature with "r" and writing to the end of fp which is probably
- X * the sendmail process or the message file pointer) or to write fortunes into
- X * the message buffer: reading fp (the popened fortune) and writing into file.
- X */
- file_to_fp(p, fp, mode)
- register char *p;
- register FILE *fp;
- char *mode;
- {
- X int x = 1;
- X char *file, buf[BUFSIZ];
- X FILE *tmp_fp;
- X
- X if (!p || !*p) {
- X print("specify filename");
- X return -1;
- X }
- X /* Special case for IS_SENDING && !IS_GETTING should eventually go away */
- X if (ison(glob_flags, IS_SENDING) && isoff(glob_flags, IS_GETTING) &&
- X strcmp(p, "-") == 0) {
- X file = p;
- X if (*mode == 'r')
- X tmp_fp = stdin;
- X else
- X tmp_fp = stdout;
- X } else {
- X file = getpath(p, &x);
- X if (x == -1) { /* on error, file contains error message */
- X wprint(file);
- X return -1;
- X }
- X wprint("%s: ", file);
- X if (x) {
- X /* if x == 1, then path is a directory */
- X wprint("is a directory.\n");
- X return -1;
- X } else if (!(tmp_fp = fopen(file, mode))) {
- X wprint("%s\n", sys_errlist[errno]);
- X return -1;
- X }
- X }
- X if (*mode != 'r') {
- X rewind(fp);
- X for(x = 0; fgets(buf, BUFSIZ, fp); x++)
- X (void) fputs(buf, tmp_fp);
- X } else {
- X for(x = 0; fgets(buf, BUFSIZ, tmp_fp); x++)
- X (void) fputs(buf, fp);
- X (void) fflush(fp);
- X }
- X wprint("%s%d line%s\n", (*mode == 'a')? "added ": "",
- X x, (x == 1)? "": "s");
- X if (file != p || strcmp(file, "-") != 0)
- X (void) fclose(tmp_fp);
- X return 0;
- }
- X
- /* clear all contents of the file. Careful that the file is opened for
- X * _writing_ --tempfile is opened for reading, so don't try to empty it
- X * if you're using ftruncate. Return -1 on error, 0 on success.
- X */
- emptyfile(fp, fname)
- register FILE **fp;
- register char *fname;
- {
- X Debug("Emptying \"%s\"\n", fname);
- #ifndef SYSV
- X return ftruncate(fileno(*fp), 0L);
- #else
- X {
- X int omask = umask(077), ret;
- X (void) fclose(*fp);
- X if (!(*fp = fopen(fname, "w")))
- X ret = -1;
- X else
- X ret = 0;
- X (void) umask(omask);
- X return ret;
- X }
- #endif /* SYSV */
- }
- X
- /*
- X * Finds out how many file descriptors are opened. Useful for making sure
- X * no files got opened in subprocedures which were not subsequently closed.
- X * If argc is 0, returns the number of available fds.
- X */
- nopenfiles(argc)
- {
- #ifdef MAXFILES
- X register int size = MAXFILES;
- #else
- X register int size = getdtablesize();
- #endif /* MAXFILES */
- X register int nfiles = 0, totalfiles = size;
- X
- X if (argc > 1)
- X return -1;
- X
- X if (argc == 1)
- X wprint("open file descriptors:");
- X while (--size >= 0)
- X if (fcntl(size, F_GETFL, 0) != -1) {
- X if (argc == 1)
- X wprint(" %d", size);
- X ++nfiles;
- X }
- X if (argc == 1) {
- X wprint("\n");
- X return 0;
- X }
- X return totalfiles - nfiles;
- }
- X
- /*
- X * Close all "extraneous" file descriptors; return the number closed
- X */
- closefileds (n)
- {
- X register int nfiles = 0;
- #ifdef MAXFILES
- X register int size = MAXFILES;
- #else
- X register int size = getdtablesize();
- #endif /* MAXFILES */
- X
- X while (--size >= n)
- X if (fcntl(size, F_GETFL, 0) != -1) {
- X (void) close(size);
- X ++nfiles;
- X }
- X return nfiles;
- }
- X
- /*
- X * Open a path for writing or appending -- return a FILE pointer.
- X * If program is TRUE, then use popen, not fopen and don't check
- X * to see if the file is writable. If program is FALSE and lockit
- X * is TRUE, then lock on open.
- X */
- FILE *
- open_file(p, program, lockit)
- register char *p;
- {
- X register FILE *newfile = NULL_FILE;
- X register char *tmp;
- X int x = 1;
- X
- X if (program)
- X tmp = p, x = 0;
- X else
- X tmp = getpath(p, &x);
- X if (x == 1)
- X print("%s is a directory.\n", tmp);
- X else if (x == -1)
- X print("%s: %s\n", p, tmp);
- X else {
- X register char *mode = NULL;
- X /* if it doesn't exist open for "w" */
- X if (program || Access(tmp, F_OK))
- X mode = "w";
- X /* if we can't write to it, forget it */
- X else if (Access(tmp, W_OK))
- X error(tmp);
- X else
- X mode = "a";
- X if (mode)
- X if (program) {
- X if (!(newfile = popen(tmp, mode)))
- X error("Can't execute %s\n", tmp);
- X } else if (lockit) {
- X /* Lock on open */
- X if (!(newfile = lock_fopen(tmp, mode)))
- X error("Can't write to %s", tmp);
- X } else {
- X /* Ordinary open */
- X if (!(newfile = mask_fopen(tmp, mode)))
- X error("Can't write to %s", tmp);
- X }
- X if (newfile != NULL_FILE)
- X Debug("Successfully opened %s\n", tmp);
- X }
- X return newfile;
- }
- X
- /*
- X * Open each file in the vector names[] and place the corresponding
- X * file descriptor in files[]. If the file is really a program (pipe),
- X * delete the name after opening; otherwise lock the file.
- X * Tokens beginning with a "/, ~, or + are files; tokens beginning
- X * with a | are programs.
- X */
- open_list(names, files, size)
- char *names[];
- FILE *files[];
- {
- X register int total = 0, prog;
- X register char *fpath;
- X
- X Debug("opening "), print_argv(names);
- X for (total = 0; size && total < size; ) {
- X fpath = names[total] + (prog = (names[total][0] == '|'));
- X /* open_file() locks the file here only if prog is false */
- X if ((files[total] = open_file(fpath, prog, TRUE))) {
- X if (prog) {
- X xfree(names[total]);
- X names[total++] = NULL;
- X } else {
- X /* Seek to end of file AFTER locking */
- X (void) fseek(files[total++], 0L, 2);
- X }
- X } else {
- X Debug("Failed to open %s\n", names[total]);
- X /* Swap the failed file with the last in the list */
- X if (size--) {
- X xfree(names[total]);
- X names[total] = names[size];
- X names[size] = NULL;
- X }
- X }
- X }
- X return size;
- }
- X
- /*
- X * find_files gets a set of addresses and an array of
- X * char pointers and the maximum size that array can be.
- X * The object is to find the files or programs listed in "s". If the
- X * size is 0, then just extract the file names and give error messages
- X * for each one since they will not be opened. Return the number of
- X * files found and delete all files from the list in * "s".
- X * The string "s" is modified to be a list of address -- all names AND
- X * files are stripped out of the list.
- X * The force parameter causes names to be interpreted as files even if
- X * they would normally appear to be addresses.
- X */
- find_files(s, names, size, force)
- register char *s;
- char *names[];
- {
- X register int total = 0;
- X char file[MAXPATHLEN], buf[HDRSIZ], *start = s, c;
- X register char *p, *b = buf, *fpath;
- X
- X do {
- X if (!(p = get_name_n_addr(s, NULL, file)))
- X break;
- X c = *p, *p = 0;
- X /* See if it's a file. This doesn't get written back
- X * onto "buf" since it is supposed to be extracted anyway.
- X * The check for '@' in names beginning with '/' is to
- X * avoid mis-identifying X.400 addresses as file names.
- X */
- X if (force || *file == '+' || *file == '~' ||
- X *file == '|' || *file == '/' && !index(file, '@')) {
- X int isdir;
- X /* open either "file" or &file[1] */
- X if (*file == '|') {
- X isdir = 0;
- X fpath = file;
- X } else {
- X isdir = 1;
- X /* if successful, getpath will reset isdir to 0 */
- X fpath = getpath(file, &isdir);
- X }
- X if (!isdir) {
- X if (size && total < size)
- X names[total++] = savestr(fpath);
- X else
- X print("No open space for %s\n", file);
- X } else if (isdir == 1)
- X print("%s: is a directory\n", file);
- X else
- X print("%s: %s\n", file, fpath);
- X } else {
- X b += Strcpy(b, s);
- X *b++ = ',', *b++ = ' ';
- X }
- X for (*p = c, s = p; *s == ',' || isspace(*s); s++)
- X ;
- X } while (*s);
- X for (*b-- = 0; b > buf && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X (void) strcpy(start, buf);
- X names[total] = NULL; /* for free_vec() */
- X return total;
- }
- X
- /*
- X * access(2) has an undocumented feature which ignores suid. If you are
- X * su'ed and try to read your mail, you will be unable to because access()
- X * will give the illusion that you cannot read/write to your mbox. Solve
- X * the problem by using stat() instead.
- X */
- Access(file, mode)
- register char *file;
- {
- X struct stat buf;
- X
- X if (stat(file, &buf) == -1)
- X return -1;
- X if (mode == R_OK)
- X return (buf.st_mode & 0400)? 0 : -1;
- X if (mode == W_OK)
- X return (buf.st_mode & 0200)? 0 : -1;
- X return 0;
- }
- X
- /*
- X * Open a file for read/write/whatever but make sure umask is rw by user only.
- X */
- FILE *
- mask_fopen(file, mode)
- char *file, *mode;
- {
- X int omask = umask(077);
- X FILE *fp = fopen(file, mode);
- X (void) umask(omask);
- X return fp;
- }
- X
- /*
- X * Shorten a file name, replacing its full path name with one using an
- X * accepted mush abbreviation:
- X * ~ home directory
- X * + folder directory
- X * For files in the current directory, the path is simply skipped.
- X * Returns a pointer into a static buffer holding the trimmed path.
- X */
- char *
- trim_filename(name)
- char *name;
- {
- X static char buf[MAXPATHLEN];
- X char *fldr = do_set(set_options, "folder"),
- X *home = do_set(set_options, "home");
- X int len;
- X
- X /* Handling $folder is tough, because if it is not set then we should
- X * trim DEF_FOLDER; but DEF_FOLDER may not be a full path, and we can't
- X * call getpath() because the "name" parameter may point to gepath()'s
- X * static buffer. So we handle the special case of DEF_FOLDER starting
- X * with a tilde ($home), and forget about it otherwise. Yuck.
- X */
- X if ((!fldr || !*fldr) && (fldr = DEF_FOLDER) && *fldr == '~' && home) {
- X (void) sprintf(buf, "%s%s", home, fldr + 1);
- X fldr = buf; /* buf will get overwritten again below */
- X }
- X /* One more special case: if $folder and $home are the same, then we
- X * trim as $home, otherwise we trim as $folder. This prevents strange
- X * contractions like "+.cshrc" for "~/.cshrc".
- X */
- X if ((!home || strcmp(home, fldr)) && (len = strlen(fldr)) &&
- X !strncmp(fldr, name, len) && (name[len] == '/' || !name[len])) {
- X buf[0] = '+';
- X if (name[len] && name[len + 1])
- X (void) strcpy(buf + 1, name + len + 1);
- X else
- X buf[1] = 0;
- X return buf;
- X } else if (home && (len = strlen(home)) && !strncmp(home, name, len) &&
- X (name[len] == '/' || !name[len])) {
- X buf[0] = '~';
- X (void) strcpy(buf + 1, name + len);
- X return buf;
- X } else if ((fldr = do_set(set_options, "cwd")) &&
- X (len = strlen(fldr)) && !strncmp(fldr, name, len) &&
- X name[len] == '/')
- X return strcpy(buf, name + len + 1);
- X return strcpy(buf, name);
- }
- SHAR_EOF
- chmod 0644 file.c ||
- echo 'restore of file.c failed'
- Wc_c="`wc -c < 'file.c'`"
- test 14503 -eq "$Wc_c" ||
- echo 'file.c: original size 14503, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= fkeys.c ==============
- if test -f 'fkeys.c' -a X"$1" != X"-c"; then
- echo 'x - skipping fkeys.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting fkeys.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'fkeys.c' &&
- /* @(#)fkeys.c (c) copyright 10/18/86 (Dan Heller) */
- X
- #include "mush.h"
- X
- #define L(n) KEY_LEFTFIRST+(n)-1
- #define R(n) KEY_RIGHTFIRST+(n)-1
- #define F(n) KEY_TOPFIRST+(n)-1
- #define BREAK_KEY KEY_TOPLAST
- X
- static int func_key();
- X
- Notify_value
- fkey_interposer(client, event, arg, type)
- Frame client;
- Event *event;
- Notify_arg arg;
- Notify_event_type type;
- {
- X if ((event_is_key_left(event) || event_is_key_right(event) ||
- X event_is_key_top(event)) &&
- X event_is_down(event) && func_key(event_id(event)))
- X return NOTIFY_DONE;
- X
- X return notify_next_event_func(client, event, arg, type);
- }
- X
- /*
- X * Execute commands defined by a function key.
- X * Left keys:
- X * L1 = (null) can't be set
- X * L2 ... L10
- X * Top function keys
- X * F1 ... F9, BREAK/backspace (key not definable)
- X * Right function keys
- X * R1 ... R15
- X * Usually, the last Function key displays the others' settings.
- X */
- static int
- func_key(key)
- register int key;
- {
- X register char **argv, *p;
- X char buf[256];
- X int n;
- X
- X if (key >= KEY_LEFTFIRST && key <= KEY_LEFTLAST)
- X buf[0] = 'L', n = key - KEY_LEFTFIRST;
- X else if (key >= KEY_TOPFIRST && key <= KEY_TOPLAST)
- X buf[0] = 'F', n = key - KEY_TOPFIRST;
- X else if (key >= KEY_RIGHTFIRST && key <= KEY_RIGHTLAST)
- X buf[0] = 'R', n = key - KEY_RIGHTFIRST;
- X (void) sprintf(buf+1, "%d", n+1);
- X
- X if (!(p = do_set(fkeys, buf))) {
- X if (!chk_option("quiet", "fkey"))
- X wprint("Function key \"%s\" not set.\n", buf);
- X return FALSE;
- X }
- X /* make_command will screw up "p", so copy it first */
- X (void) strcpy(buf, p);
- X Debug("(%s) \"%s\": ", key, p), turnon(glob_flags, CONT_PRNT);
- X if (argv = make_command(buf, TRPL_NULL, &n))
- X (void) do_command(n, argv, msg_list);
- X return TRUE;
- }
- SHAR_EOF
- chmod 0644 fkeys.c ||
- echo 'restore of fkeys.c failed'
- Wc_c="`wc -c < 'fkeys.c'`"
- test 1717 -eq "$Wc_c" ||
- echo 'fkeys.c: original size 1717, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= folders.c ==============
- if test -f 'folders.c' -a X"$1" != X"-c"; then
- echo 'x - skipping folders.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting folders.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'folders.c' &&
- /* @(#)folders.c (c) copyright 10/18/86 (Dan Heller) */
- X
- #include "mush.h"
- X
- static char oldfolder[MAXPATHLEN];
- X
- /* folder %[user] --new mailfile is the spool/mail/login file [user].
- X * folder # --new mailfile is the folder previous to the current folder
- X * folder & --new mailfile is ~/mbox (or whatever "mbox" is set to)
- X * folder +file --new mailfile is in the directory "folder"; name is 'file'
- X * folder "path" --full path name or the one in current working directory.
- X *
- X * in all cases, changes are updated unless a '!' is specified after the
- X * folder command (e.g. "f!", "folder !" "fo!" .. all permutations)
- X * as usual, if new mail has arrived before the file is copied back, then
- X * user will be notified beforehand.
- X *
- X * RETURN -1 on error -- else return 0. All bits in msg_list are set to true.
- X */
- folder(argc, argv, list)
- register char **argv;
- char list[];
- {
- X int n, updating = !strcmp(*argv, "update"), do_read_only = 0, no_hdrs = 0;
- X char *tmp, *newfolder = NULL, buf[MAXPATHLEN];
- X struct stat statbuf;
- X extern long last_spool_size;
- X
- X if (ison(glob_flags, IS_PIPE)) {
- X print("You can't pipe to the %s command.\n", *argv);
- X return -1;
- X } else if (ison(glob_flags, IS_SENDING)) {
- X print("You can't use the %s command when sending.\n", *argv);
- X return -1;
- X } else if (!tempfile || !*tempfile) {
- X print("You can't use the %s command in init files.\n", *argv);
- X return -1;
- X }
- X while (*++argv && (**argv == '-' || **argv == '!'))
- X if (!strcmp(*argv, "-N"))
- X no_hdrs = !iscurses;
- X else if (!updating && !strcmp(*argv, "-n"))
- X turnoff(glob_flags, DO_UPDATE);
- X else if (!strcmp(*argv, "-r"))
- X do_read_only = 1;
- X else if (!strcmp(*argv, "!")) {
- X if (updating)
- X turnon(glob_flags, DO_UPDATE); /* useful? */
- X else
- X turnoff(glob_flags, DO_UPDATE);
- X } else
- X return help(0, "folder", cmd_help);
- X
- X if (updating) {
- X (void) strcpy(buf, mailfile);
- X if (ison(glob_flags, READ_ONLY))
- X do_read_only = 1;
- X } else {
- X if (!*argv) {
- X mail_status(0);
- X return 0;
- X }
- X if (!strcmp(*argv, "#"))
- X if (!*oldfolder) {
- X print("No previous folder\n");
- X return -1;
- X } else
- X newfolder = oldfolder;
- X else if (!strcmp(*argv, "&")) {
- X if (!(newfolder = do_set(set_options, "mbox")) || !*newfolder)
- X newfolder = DEF_MBOX;
- X } else
- X newfolder = *argv;
- X n = 0;
- X tmp = getpath(newfolder, &n);
- X if (n == -1) {
- X print("%s: %s\n", newfolder, tmp);
- X return -1;
- X } else if (n == 1) {
- X print("%s: is a directory\n", tmp);
- X return -1;
- X }
- X /* strcpy so copyback() below (which calls getpath) doesn't change
- X * the data that tmp intended to point to. Get the cwd if necessary.
- X */
- X n = 0;
- X if (*tmp != '/') {
- X if (!GetCwd(buf, sizeof buf)) {
- X error("getcwd: %s",buf);
- X return -1;
- X }
- X n = strlen(buf);
- X buf[n++] = '/';
- X }
- X (void) strcpy(&buf[n], tmp);
- X }
- #ifdef SUNTOOL
- X if (istool > 1)
- X timeout_cursors(TRUE);
- #endif /* SUNTOOL */
- X if (stat(buf, &statbuf) == -1 || !(statbuf.st_mode & 0400)) {
- X error("Unable to read %s", buf);
- #ifdef SUNTOOL
- X if (istool > 1)
- X timeout_cursors(FALSE);
- #endif /* SUNTOOL */
- X return -1;
- X }
- X /* If the file can't be opened for writing, autoset READ_ONLY */
- X if (!(statbuf.st_mode & 0200))
- X do_read_only = 1;
- X
- X if (!(n=copyback(updating?"Update folder?":"Change anyway?",!updating))) {
- #ifdef SUNTOOL
- X if (istool > 1)
- X timeout_cursors(FALSE);
- #endif /* SUNTOOL */
- X /* an error occured updating the folder */
- X return -1;
- X }
- X turnoff(glob_flags, CORRUPTED); /* copyback() was successful */
- X /* Assure that both oldfolder and mailfile are full paths */
- X if (strcmp(mailfile, buf) || !*oldfolder) {
- X n = 1; /* force load of new folder */
- X if (!updating)
- X (void) strcpy(oldfolder, *oldfolder? mailfile : buf);
- X strdup(mailfile, buf);
- X }
- X do_read_only? turnon(glob_flags,READ_ONLY) : turnoff(glob_flags,READ_ONLY);
- X last_size = spool_size = 0L;
- X while (msg_cnt--) {
- X xfree(msg[msg_cnt].m_date_recv);
- X xfree(msg[msg_cnt].m_date_sent);
- X msg[msg_cnt].m_date_recv = msg[msg_cnt].m_date_sent = NO_STRING;
- X }
- X msg_cnt = 0, msg[0].m_offset = 0L;
- X turnoff(glob_flags, CONT_PRNT);
- X
- X turnon(glob_flags, IGN_SIGS);
- X /* clear the tempfile */
- X if (tmpf)
- X (void) fclose(tmpf);
- X if (!do_read_only) {
- X if (!(tmpf = mask_fopen(tempfile, "w"))) {
- X error("error truncating %s", tempfile);
- X turnoff(glob_flags, IGN_SIGS);
- #ifdef SUNTOOL
- X if (istool > 1)
- X timeout_cursors(FALSE);
- #endif /* SUNTOOL */
- X return -1;
- X }
- X }
- X /* Don't reload the folder if it was removed */
- X if (n > 0) {
- X if (load_folder(mailfile, TRUE, NULL) < 1) {
- X last_msg_cnt = 0;
- X last_size = statbuf.st_size; /* Disable check_new_mail() */
- X turnoff(glob_flags, IGN_SIGS);
- #ifdef SUNTOOL
- X if (istool > 1)
- X timeout_cursors(FALSE);
- #endif /* SUNTOOL */
- X return -1;
- X }
- X if (do_read_only && !(tmpf = fopen(mailfile, "r"))) {
- X error(mailfile);
- X turnoff(glob_flags, IGN_SIGS);
- #ifdef SUNTOOL
- X if (istool > 1)
- X timeout_cursors(FALSE);
- #endif /* SUNTOOL */
- X return -1;
- X }
- X }
- X last_msg_cnt = msg_cnt; /* for check_new_mail */
- X /* Prevent both bogus "new mail" messages and missed new mail */
- X last_size = msg[msg_cnt].m_offset;
- X if (!strcmp(mailfile, spoolfile))
- X spool_size = last_spool_size = last_size;
- #ifdef SUNTOOL
- X if (istool) {
- X extern Panel_item folder_text_item;
- X Rect *rect = (Rect *)window_get(hdr_sw, WIN_RECT);
- X (void) pw_rop(hdr_win, 0,0, rect->r_width, rect->r_height, PIX_CLR,
- X (struct pixrect *) 0,0,0);
- X panel_set_value(folder_text_item, mailfile);
- X }
- #endif /* SUNTOOL */
- X
- X if (!updating || current_msg >= msg_cnt)
- X current_msg = (msg_cnt? 0 : -1);
- X turnoff(glob_flags, IGN_SIGS);
- X
- X /* now sort messages according a user-defined default */
- X if (!updating && msg_cnt > 1 && !strcmp(mailfile, spoolfile) &&
- X (tmp = do_set(set_options, "sort"))) {
- X (void) sprintf(buf, "sort %s", tmp);
- X if ((argv = mk_argv(buf, &argc, TRUE)) && argc > 0) {
- X /* msg_list can't be null for do_command and since we're not
- X * interested in the result, call sort directly
- X */
- X (void) sort(argc, argv, NULL);
- X free_vec(argv);
- X if (!updating)
- X current_msg = 0; /* Sort may move the current message */
- X }
- X }
- X turnoff(glob_flags, DO_UPDATE);
- X
- X /* go to first NEW message */
- X for (n = 0; n < msg_cnt && ison(msg[n].m_flags, OLD); n++)
- X ;
- X if (n == msg_cnt) {
- X turnoff(glob_flags, NEW_MAIL);
- X if (!updating) {
- X /* no new message found -- try first unread message */
- X for (n = 0; n < msg_cnt && isoff(msg[n].m_flags, UNREAD); n++)
- X ;
- X }
- X } else {
- X turnon(glob_flags, NEW_MAIL);
- X /* default for toolmode is true */
- X if (istool && !chk_option("quiet", "tool"))
- X bell();
- X }
- X if (msg_cnt && (!updating || current_msg < 0))
- X current_msg = (n == msg_cnt ? 0 : n);
- X
- X if ((!istool || istool && !msg_cnt) && !iscurses)
- X mail_status(0);
- X /* be quiet if we're piping */
- X if (!istool && !updating && !no_hdrs && msg_cnt
- X && isoff(glob_flags, DO_PIPE))
- X (void) cmd_line(sprintf(buf, "headers %d", current_msg+1), msg_list);
- #ifdef SUNTOOL
- X if (istool > 1) {
- X if (!msg_cnt)
- X print("No Mail in %s\n", mailfile);
- X if (msg_cnt) {
- X display_msg(current_msg, (long)0);
- X do_hdrs(0, DUBL_NULL, NULL);
- X /* Automatic display should not "touch" this message */
- X turnoff(msg[current_msg].m_flags, DO_UPDATE);
- X /* don't update folder just because a message is displayed */
- X turnoff(glob_flags, DO_UPDATE);
- X }
- X timeout_cursors(FALSE);
- X }
- #endif /* SUNTOOL */
- X if (list) {
- X clear_msg_list(list);
- X bitput(list, list, msg_cnt, =~); /* macro */
- X }
- X return 0;
- }
- X
- folders(argc, argv)
- register char **argv;
- {
- X register char *p;
- X char buf[128], unused[MAXMSGS_BITS];
- X
- X if (argv && argv[1] && !strcmp(argv[1], "-?"))
- X return help(0, "folders", cmd_help);
- X
- X if (!(p = do_set(set_options, "folder")) || !*p)
- X p = DEF_FOLDER;
- X (void) sprintf(buf, "ls -FR %s", p);
- X if (argv = make_command(buf, TRPL_NULL, &argc))
- X return do_command(argc, argv, unused);
- X return -1;
- }
- X
- /*
- X * Determine whether a file could be a folder. If prompt is non-NULL,
- X * ask the user whether we should treat the file as a folder anyway.
- X */
- test_folder(name, prompt)
- char *name, *prompt;
- {
- X char line[BUFSIZ], *p;
- X FILE *fp = fopen(name, "r");
- X int retval = FALSE;
- X
- X if (!fp)
- X return 0;
- X if (fgets(line, sizeof line - 1, fp)) {
- #ifndef MSG_SEPARATOR
- X if (p = any(line, " \t")) {
- X skipspaces(1);
- X p = any(p, " \t");
- X }
- X if (p && !strncmp(line, "From ", 5) && (p = parse_date(p + 1)))
- #else /* MSG_SEPARATOR */
- X if (!strncmp(line, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
- #endif /* MSG_SEPARATOR */
- X retval = TRUE;
- X } else
- X retval = TRUE; /* Empty files are legitimate folders */
- X (void) fclose(fp);
- X if (prompt && !retval) {
- X char buf[BUFSIZ];
- #ifdef SUNTOOL
- X if (istool) {
- X (void) sprintf(buf, "\"%s\": %s", name, prompt);
- X return ask(buf);
- X }
- #endif /* SUNTOOL */
- X print("\"%s\": %s [n] ", name, prompt);
- X buf[0] = 0;
- X retval = (Getstr(buf, sizeof (buf), 0) && lower(*buf) == 'y');
- X }
- X return retval;
- }
- X
- /* merge_folders filename -- concatenate the folder specified by filename
- X * to the current folder.
- X *
- X * RETURN -1 on error -- else return 0. A bit in msg_list is set to true
- X * for each of the "new" messages read in to the current folder.
- X */
- merge_folders(n, argv, list)
- register char **argv, list[];
- {
- X int no_hdrs = 0, newest_msg;
- X long orig_offset;
- X char *tmp, *newfolder = NULL, buf[MAXPATHLEN];
- X
- X if (ison(glob_flags, IS_PIPE)) {
- X print("You can't pipe to the %s command.\n", *argv);
- X return -1;
- X } else if (ison(glob_flags, IS_SENDING)) {
- X print("You can't use the %s command while sending.\n", *argv);
- X return -1;
- X }
- X
- X while (*++argv && **argv == '-')
- X if (!strcmp(*argv, "-?"))
- X return help(0, "merge", cmd_help);
- X else if (!strcmp(*argv, "-N"))
- X no_hdrs = !(iscurses || ison(glob_flags, PRE_CURSES));
- X
- X if (!*argv)
- X return 0;
- X
- X if (ison(glob_flags, READ_ONLY)) {
- X print("Folder is read-only.\n");
- X return -1;
- X }
- X
- X if (!strcmp(*argv, "#"))
- X if (!*oldfolder) {
- X print("No previous folder\n");
- X return -1;
- X } else
- X newfolder = oldfolder;
- X else if (!strcmp(*argv, "&")) {
- X if (!(newfolder = do_set(set_options, "mbox")) || !*newfolder)
- X newfolder = DEF_MBOX;
- X } else
- X newfolder = *argv;
- X n = 0;
- X tmp = getpath(newfolder, &n);
- X if (n == -1) {
- X print("%s: %s\n", newfolder, tmp);
- X return -1;
- X } else if (n == 1) {
- X print("%s: is a directory\n", tmp);
- X return -1;
- X }
- X
- X turnon(glob_flags, IGN_SIGS);
- X orig_offset = msg[msg_cnt].m_offset;
- X (void) load_folder(tmp, 2, list);
- X msg[msg_cnt].m_offset = orig_offset;
- X newest_msg = last_msg_cnt;
- X Debug("newest_msg = %d\n", newest_msg);
- X last_msg_cnt = msg_cnt; /* for check_new_mail */
- X Debug("msg_cnt = %d\n", msg_cnt);
- X if (current_msg < 0)
- X current_msg = 0;
- X (void) mail_size();
- X turnoff(glob_flags, IGN_SIGS);
- X
- X if ((!istool || istool && !msg_cnt)
- X && !iscurses && !ison(glob_flags, PRE_CURSES))
- X mail_status(0);
- X /* be quiet if we're piping or if told not to show headers */
- X if ((istool || !no_hdrs) && isoff(glob_flags, DO_PIPE)
- X && newest_msg < msg_cnt)
- X (void) cmd_line(sprintf(buf, "headers %d", newest_msg + 1), NULL);
- X return 0;
- }
- X
- /*
- X * Default digest article separator
- X */
- #define ARTICLE_SEP "--------"
- X
- /*
- X * Undigestify messages. If a message is in digest-format, there are many
- X * messages within this message which are to be extracted. Kinda like a
- X * folder within a folder. By default, this routine will create a new
- X * folder that contains the new messages. -m option will merge the new
- X * messages into the current folder.
- X */
- do_undigest(n, argv, list)
- char *argv[], list[];
- {
- X int r, articles = 0, merge = 0, appending = 0;
- X char buf[MAXPATHLEN], cmdbuf[MAXPATHLEN], newlist[MAXMSGS_BITS], *dir;
- X char *art_sep = ARTICLE_SEP, *mktemp();
- X FILE *fp;
- X
- X while (argv && *++argv && **argv == '-') {
- X switch(argv[0][1]) {
- X case 'm':
- X if (ison(glob_flags, READ_ONLY)) {
- X print("Folder is read only.\n");
- X return -1;
- X }
- X merge++;
- X when 'p':
- X if (*++argv)
- X art_sep = *argv;
- X else {
- X print("Specify separator pattern with -p.\n");
- X return -1;
- X }
- X otherwise: return help(0, "undigest", cmd_help);
- X }
- X }
- X
- X if ((n = get_msg_list(argv, list)) == -1)
- X return -1;
- X
- X argv += n;
- X
- X if (*argv) {
- X int isdir = 1; /* Ignore file nonexistance errors */
- X (void) strcpy(buf, getpath(*argv, &isdir));
- X if (isdir < 0) {
- X print("%s: %s\n", *argv, buf);
- X return -1;
- X } else if (isdir == 1) {
- X print("%s: is a directory\n", buf);
- X return -1;
- X }
- X } else {
- X register char *p, *p2;
- X if (Access(dir = ".", W_OK) == 0 ||
- X (dir = do_set(set_options, "folder")) ||
- X (dir = do_set(set_options, "tmpdir")))
- X dir = getdir(dir); /* expand metachars */
- X if (!dir)
- alted:
- X dir = ALTERNATE_HOME;
- X for (n = 0; n < msg_cnt; n++)
- X if (msg_bit(list, n))
- X break;
- X
- X if (!(p = header_field(n, "subject")))
- X (void) mktemp(sprintf(buf, "%s/digestXXXXX", dir));
- X else {
- X if (!lcase_strncmp(p, "re: ", 4))
- X p += 4;
- X for (p2 = p; *p2; p2++)
- X if (!isalnum(*p2) && *p2 != '-' && *p2 != '.') {
- X *p2 = 0;
- X break;
- X }
- X p2 = buf + Strcpy(buf, dir);
- X *p2++ = '/';
- X (void) strcpy(p2, p);
- X }
- X }
- X
- X if (!Access(buf, W_OK))
- X appending = ((fp = mask_fopen(buf, "a")) != NULL_FILE);
- X else
- X fp = mask_fopen(buf, "w");
- X if (!fp) {
- X if (!*argv && strcmp(dir, ALTERNATE_HOME))
- X goto alted;
- X error("can't create %s", buf);
- X return -1;
- X }
- X
- X for (n = 0; n < msg_cnt; n++) {
- X if (!msg_bit(list, n))
- X continue;
- X
- X print("undigesting message %d\n", n+1);
- X /* copy message into file making sure all headers exist. */
- X r = undigest(n, fp, art_sep);
- X if (r <= 0)
- X break;
- X articles += r;
- X }
- X (void) fclose(fp);
- X if (r <= 0) {
- X if (!appending)
- X (void) unlink(buf);
- X return -1;
- X }
- X if (merge) {
- X (void) cmd_line(sprintf(cmdbuf, "\\merge -N %s", buf), newlist);
- X (void) unlink(buf);
- X print("Merged in %d messages.\n", articles);
- X } else
- X print("Added %d messages to \"%s\".\n", articles, buf);
- X clear_msg_list(list);
- X for (n = 0; n < msg_cnt; n++)
- X if (msg_bit(newlist, n))
- X set_msg_bit(list, n);
- X return 0;
- }
- X
- /*
- X * split digest-message 'n' to file "fp" using article separator "sep".
- X * return number of articles copied or -1 if system error on fputs.
- X * A digest is a folder-in-a-message in a special, semi-standard form.
- X */
- undigest(n, fp, sep)
- int n;
- FILE *fp;
- char *sep;
- {
- X int art_cnt = 0, on_hdr = -1; /* on_hdr is -1 if hdr not yet found */
- X int sep_len = (sep ? strlen(sep) : strlen(sep = ARTICLE_SEP));
- X long get_hdr = 0L;
- X char from[HDRSIZ], line[HDRSIZ], last_sep[HDRSIZ];
- X char from_hdr[256], afrom[256], adate[64];
- X char *fdate = "Xxx Xxx 00 00:00:00 0000"; /* Dummy date in ctime form */
- X SIGRET (*oldint)(), (*oldquit)();
- X
- X if (!msg_get(n, from, sizeof from)) {
- X error("Unable to find msg %d", n+1);
- X return -1;
- X }
- #ifndef MSG_SEPARATOR
- X else {
- X char *p = from + 5;
- X skipspaces(0);
- X p = index(p, ' ');
- X if (p) {
- X skipspaces(0);
- X fdate = p;
- X }
- X if (fputs(from, fp) == EOF)
- X return -1;
- X }
- #endif /* !MSG_SEPARATOR */
- X
- X on_intr();
- X *afrom = *adate = *last_sep = '\0';
- X while (ftell(tmpf) < msg[n].m_offset + msg[n].m_size &&
- X fgets(line, sizeof (line), tmpf)) {
- X if (ison(glob_flags, WAS_INTR))
- X goto handle_error;
- X if (*line == '\n' && on_hdr > 0) /* blank line -- end of header */
- X on_hdr = 0;
- X
- X /* Check for the beginning of a digest article */
- X if (!strncmp(line, sep, sep_len)) {
- X if (get_hdr) {
- X if (do_set(set_options, "warning"))
- X print("Article with no header? (added to article #%d)\n",
- X art_cnt);
- X /* Don't start a new message for whatever this is,
- X * just fseek back and keep appending to the last one.
- X */
- X if (fseek(tmpf, get_hdr, L_SET) < 0 ||
- X fputs(last_sep, fp) == EOF) {
- X art_cnt = -1;
- X goto handle_error;
- X }
- X get_hdr = 0L;
- X on_hdr = 0;
- X } else {
- X (void) strcpy(last_sep, line);
- X get_hdr = ftell(tmpf);
- X *afrom = *adate = '\0';
- X on_hdr = -1; /* Haven't found the new header yet */
- X }
- X continue;
- X }
- X
- X if (get_hdr) {
- X char *p = *line == '>' ? line + 1 : line;
- X if (*line == '\n') {
- X if (*afrom || *adate) {
- X (void) fseek(tmpf, get_hdr, L_SET);
- X /* Terminate the previous article */
- X art_cnt++;
- #ifdef MSG_SEPARATOR
- #ifdef END_MSG_SEP
- X if (fputs(END_MSG_SEP, fp) == EOF) {
- X art_cnt = -1;
- X goto handle_error;
- X }
- #endif /* END_MSG_SEP */
- #ifdef MMDF
- X /* MMDF has a newline in MSG_SEPARATOR */
- X if (fputs(MSG_SEPARATOR, fp) == EOF)
- #else /* !MMDF */
- X /* Other MSG_SEPARATORs need a newline */
- X if (fputs(MSG_SEPARATOR, fp) == EOF ||
- X fputc('\n', fp) == EOF)
- #endif /* MMDF */
- #else /* !MSG_SEPARATOR */
- X /* Everybody else needs a From_ line */
- X if (fprintf(fp, "From %s %s", *afrom ? afrom : "unknown",
- X *adate ? date_to_ctime(adate) : fdate) == EOF)
- #endif /* MSG_SEPARATOR */
- X {
- X art_cnt = -1;
- X goto handle_error;
- X }
- X /* Make sure there is a From: without a leading > */
- X if (*afrom && *from_hdr && fputs(from_hdr, fp) == EOF) {
- X art_cnt = -1;
- X goto handle_error;
- X }
- X get_hdr = 0L;
- X } else if (on_hdr < 0)
- X /* Skip blanks between "--------" and the hdr */
- X get_hdr = ftell(tmpf);
- X } else if (on_hdr < 0)
- X on_hdr = 1;
- X if (on_hdr > 0 && !strncmp(p, "From: ", 6)) {
- X (void) get_name_n_addr(p + 6, NULL, afrom);
- X (void) no_newln(afrom);
- X /* Get the From: minus the leading > */
- X if (p != line)
- X (void) strcpy(from_hdr, p);
- X else /* We don't need From: twice! */
- X *from_hdr = '\0';
- X } else if (on_hdr > 0 && !strncmp(line, "Date: ", 6)) {
- X if (p = parse_date(line+6))
- X (void) strcpy(adate, p);
- X } else if (on_hdr > 0 && !lcase_strncmp(line, "end", 3)) {
- X if (!*afrom && !*adate)
- X break;
- X }
- X } else if (fputs(line, fp) == EOF) {
- X /* Pipe broken, out of file space, etc */
- X art_cnt = -1;
- X goto handle_error;
- X }
- X }
- X ++art_cnt;
- #ifdef END_MSG_SEP
- X if (art_cnt > 0 && fputs(END_MSG_SEP, fp) == EOF) {
- X art_cnt = -1;
- X goto handle_error;
- X }
- #endif /* END_MSG_SEP */
- X /* If we're still looking for a header, there is some stuff left
- X * at the end of the digest. Create an extra article for it.
- X */
- X if (get_hdr) {
- X char *p;
- X (void) fseek(tmpf, get_hdr, L_SET);
- X if (ftell(tmpf) >= msg[n].m_offset + msg[n].m_size)
- X goto handle_error;
- #ifdef MSG_SEPARATOR
- #ifdef MMDF
- X if (fputs(MSG_SEPARATOR, fp) == EOF)
- #else /* !MMDF */
- X if (fputs(MSG_SEPARATOR, fp) == EOF ||
- X fputc('\n', fp) == EOF)
- #endif /* MMDF */
- #else /* !MSG_SEPARATOR */
- X if (fputs(from, fp) == EOF)
- #endif /* MSG_SEPARATOR */
- X art_cnt = -1;
- X if (!(p = header_field(n, "from")))
- X p = "Mush-Undigest (Real author unknown)";
- X if (fprintf(fp, "From: %s\n", p) == EOF)
- X art_cnt = -1;
- X if (!(p = header_field(n, "date")))
- X p = fdate, (void) no_newln(p);
- X if (fprintf(fp, "Date: %s\n", p) == EOF)
- X art_cnt = -1;
- X if (!(p = header_field(n, "subject")))
- X p = "Digest";
- X if (fprintf(fp, "Subject: Trailing part of %s\n\n", p) == EOF)
- X art_cnt = -1;
- X /* header_field() moves the pointer, so seek again */
- X (void) fseek(tmpf, get_hdr, L_SET);
- X while (art_cnt > 0 && ftell(tmpf) < msg[n].m_offset + msg[n].m_size
- X && fgets(line, sizeof (line), tmpf)) {
- X if (fputs(line, fp) == EOF)
- X art_cnt = -1;
- #ifdef END_MSG_SEP
- X if (!strncmp(line, END_MSG_SEP, strlen(END_MSG_SEP)))
- X break;
- #endif /* END_MSG_SEP */
- X }
- X /* The END_MSG_SEP, if any, of the digest will have been output
- X * by the while loop above, so we don't need to add one here.
- X */
- X ++art_cnt;
- X }
- handle_error:
- X if (art_cnt == -1)
- X error("cannot completely undigest");
- X else if (ison(glob_flags, WAS_INTR))
- X art_cnt = -1;
- X off_intr();
- X return art_cnt;
- }
- SHAR_EOF
- chmod 0644 folders.c ||
- echo 'restore of folders.c failed'
- Wc_c="`wc -c < 'folders.c'`"
- test 20079 -eq "$Wc_c" ||
- echo 'folders.c: original size 20079, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= glob.c ==============
- if test -f 'glob.c' -a X"$1" != X"-c"; then
- echo 'x - skipping glob.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting glob.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'glob.c' &&
- #include "mush.h"
- #include "glob.h"
- X
- /*
- X * Buried somewhere in here is the skeleton of a pattern matcher posted
- X * by koblas@mips.COM (David Koblas). It has been hacked almost beyond
- X * recognition to handle more complex patterns, and directory search has
- X * been added (patterns are split at '/' characters when file globbing).
- X */
- X
- #ifdef TEST /* Define TEST to build a stand-alone file globbing program */
- X
- extern char *malloc(), *realloc();
- X
- #define getpath(x,y) (*(y) = 0, (x))
- #define Access access
- #define Strcpy(x,y) (strcpy(x,y), strlen(x))
- #define savestr(x) (strcpy(malloc(strlen(x)+1),x))
- #ifndef max
- #define max(x,y) ((x) > (y) ? (x) : (y))
- #endif /* max */
- #ifndef min
- #define min(x,y) ((x) > (y) ? (y) : (x))
- #endif /* min */
- #define xfree free
- #undef wprint
- #define wprint printf
- #define debug 0
- #undef sprintf
- X
- #define TESTGLOB(str1,str2) \
- X printf("%s %s = %s\n",str1,str2,glob(str1,str2)?"TRUE":"FALSE")
- X
- main(argc, argv)
- int argc;
- char **argv;
- {
- X char **e;
- X int f;
- X
- X if (argc > 1)
- X while (*++argv) {
- X (void) printf("%s -->\n", *argv);
- X if (f = filexp(*argv, &e)) {
- X columnate(f, e, 0);
- X }
- X }
- #ifdef TEST2 /* Define TEST2 to automatically run these test cases */
- X TESTGLOB("abcdefg", "abcdefg");
- X TESTGLOB("abcdefg", "a?cd?fg");
- X TESTGLOB("abcdefg", "ab[cde]defg");
- X TESTGLOB("abcdefg", "ab[a-z]defg");
- X TESTGLOB("abcdefg", "ab[a-z]defg");
- X TESTGLOB("ab]defg", "ab[a]c]defg");
- X TESTGLOB("ab]defg", "ab[a\\]c]defg");
- X TESTGLOB("abcdefg", "ab*fg");
- X TESTGLOB("./bc/def/gh/ij", "*de*");
- X TESTGLOB("./der/den/deq/der/", "*deq*");
- X TESTGLOB("./bc/def/gh/ij", "*ij");
- X TESTGLOB("./ij", ".?ij");
- X TESTGLOB("./bc/def/gh/ij", "./*");
- X TESTGLOB("abcdef", "*def");
- X TESTGLOB("abcdef", "*abcdef");
- X TESTGLOB("abcdef", "abc*");
- X TESTGLOB("abcdef", "abcdef*");
- X TESTGLOB("abcdef", "*?*{xxx,,yy}");
- X TESTGLOB("abcdef", "abcde{f}");
- X TESTGLOB("abcdef", "abcdef{xxx,,yyy}");
- X TESTGLOB("abcdef", "abc{def,qwrx}");
- X TESTGLOB("abcdef", "abc{ab,def,qwrx}");
- X TESTGLOB("abcdef", "{naqrwer,fuwnwer,as,abc,a}{ab,def,qwrx}");
- X TESTGLOB("abcdef", "{naqrwer,*,as,abc,a}{ab,def,qwrx}");
- X TESTGLOB("abcdef", "{{a*,b*},as,a}{ab,def,qwrx}");
- X TESTGLOB("abcdef", "{{c*,b*},as,a}{ab,def,qwrx}");
- X TESTGLOB("abcdef", "{{c*,?b*},as,a}{ab,def,qwrx}");
- X TESTGLOB("abcdef", "{naqrwer,fuwnwer,as,abc,a}{ab,d*f,qwrx}");
- #endif /* TEST2 */
- }
- X
- char *
- any(s1, s2)
- register char *s1, *s2;
- {
- X register char *p;
- X if (!s1 || !*s1 || !s2 || !*s2)
- X return 0;
- X for( ; *s1; s1++) {
- X for(p = s2; *p; p++)
- X if (*p == *s1)
- X return s1;
- X }
- X return 0;
- }
- X
- #endif /* TEST */
- X
- /*
- X * Make a string into a one-element vector
- X */
- char **
- unitv(s)
- char *s;
- {
- X char **v;
- X
- X if (v = (char **)malloc((unsigned)(2 * sizeof(char *)))) {
- X v[0] = savestr(s);
- X v[1] = NULL;
- X }
- X return v;
- }
- X
- /*
- X * Append one vector to another
- X */
- catv(s1, v1, s2, v2)
- int s1, s2;
- char ***v1, **v2;
- {
- X int i;
- X
- X if (s1 < 0 || !v1)
- X return -1;
- X if (s2 < 0 || !v2)
- X return s1;
- X
- X /* realloc(NULL, size) should be legal, but Sun doesn't support it. */
- X if (*v1)
- X *v1 = (char **)realloc(*v1,(unsigned)((s1+s2+1) * sizeof(char **)));
- X else
- X *v1 = (char **)malloc((unsigned)((s1+s2+1) * sizeof(char **)));
- X
- X if (*v1) {
- X for (i = 0; i < s2 && v2[i]; i++)
- X (*v1)[s1 + i] = v2[i];
- X (*v1)[s1 + i] = NULL;
- X xfree(v2);
- X return s1 + i;
- X }
- X return -1;
- }
- X
- /*
- X * A duplicate-eliminating comparison for sorting. It treats an empty
- X * string as greater than any other string, and forces empty one of any
- X * pair of of equal strings. Two passes are sufficient to move the empty
- X * strings to the end where they can be deleted by the calling function.
- X *
- X * This is NOT compatible with the ANSI C qsort(), which requires that the
- X * comparison function will not modify its arguments!
- X */
- uniqcmp(p1, p2)
- char **p1, **p2;
- {
- X int cmp;
- X
- X if (**p1 && !**p2)
- X return -1;
- X if (**p2 && !**p1)
- X return 1;
- X if (cmp = strcmp(*p1, *p2))
- X return cmp;
- X **p2 = 0;
- X return -1;
- }
- X
- /*
- X * Expand a pattern into a list of file names. Returns the number of
- X * matches. As in csh, names generated from pattern sets are returned
- X * even if there are no actual matches.
- X */
- filexp(pat, exp)
- char *pat, ***exp;
- {
- X char **t1, **t2;
- X int n, new, cnt;
- X
- X if (!exp)
- X return -1;
- X if (!pat || !*pat)
- X return 0;
- X
- X if ((n = sxp(pat, &t1)) > 0)
- X cnt = 0;
- X else
- X return n;
- X *exp = DUBL_NULL;
- X while (n--)
- X if ((new = fxp(t1[n], &t2)) > 0 || new++ == 0 && t2)
- X cnt = catv(cnt, exp, new, t2);
- X if (cnt > 1) {
- X /* Two sort passes to eliminate duplicates -- see uniqcmp() */
- X qsort((char *)*exp, cnt, sizeof(char *), uniqcmp);
- X qsort((char *)*exp, cnt, sizeof(char *), uniqcmp);
- X while (!(*exp)[cnt - 1][0]) {
- X xfree((*exp)[--cnt]);
- X (*exp)[cnt] = NULL;
- X }
- X }
- X return cnt;
- }
- X
- /*
- X * Expand a filename with globbing chars into a list of matching filenames.
- X * Pattern set notatation which crosses directories is not handled, e.g.
- X * "fi{le/exp,nger/h}and" will NOT expand to "file/expand finger/hand".
- X * Such patterns must be pre-expanded by sxp() before calling fxp().
- X *
- X * The list of expansions is placed in *exp, and the number of matches
- X * is returned, or -1 on an error.
- X */
- fxp(name, exp)
- char *name, ***exp;
- {
- X char *p;
- X int isdir;
- X
- X if (!exp)
- X return -1;
- X
- X isdir = 1; /* ignore no such file */
- X p = getpath(name, &isdir);
- X if (isdir < 0)
- X return -1;
- X else if (isdir)
- X return ((*exp = unitv(p)) ? 1 : -1);
- X return pglob(p, 0, exp);
- }
- X
- /*
- X * Match all globbings in a path. Mutually recursive with dglob(), below.
- X * The first "skip" characters of the path are not globbed, see dglob().
- X *
- X * Returns the number of matches, or -1 on an error. *exp is set to the
- X * list of matches.
- X *
- X * If the path has no metachars, it is returned in *exp whether it matches
- X * a real file or not. This allows patterns built by sxp() to be recognized
- X * and returned even when there are no matches (ala csh generation of names
- X * from pattern sets). pglob() still returns zero in this case.
- X */
- pglob(path, skip, exp)
- char *path, ***exp;
- int skip;
- {
- X char *t, *t2;
- X int ret = 0;
- X
- X if (!path || !exp || skip < 0)
- X return -1;
- X *exp = DUBL_NULL; /* Must be null in case of zero matches and no sets */
- X
- X for (t = t2 = path + skip; (t2 = any(t2, META)) && *t2 == '/'; t = t2++)
- X ;
- X if (!t2) {
- X ret = ((*exp = unitv(path)) ? 1 : -1);
- X if (ret > 0 && Access(path, F_OK) < 0)
- X ret = 0;
- X } else {
- X if (t2 = index(t + 1, '/'))
- X *t2++ = 0;
- X if (*t == '/') {
- X *t++ = 0;
- X if (!*path)
- X ret = dglob("/", t, t2, exp);
- X else
- X ret = dglob(path, t, t2, exp);
- X } else {
- X ret = dglob("", t, t2, exp);
- X }
- X }
- X return ret;
- }
- X
- /*
- X * Search a directory (possibly recursively) for glob matches.
- X * Argument pat1 is a pattern to be matched in this directory,
- X * and pat2 is a pattern to be matched in matched subdirectories.
- X *
- X * Matches are returned through *exp.
- X */
- dglob(dir, pat1, pat2, exp)
- char *dir, *pat1, *pat2, ***exp;
- {
- X DIR *dirp;
- X struct dirent *dp;
- X char *b, *d, buf[MAXPATHLEN], **tmp;
- X int n, ret = 0, skip;
- X
- X if (!dir || !exp)
- X return -1;
- X d = (*dir ? dir : ".");
- X if (!(dirp = opendir(d)))
- X return -1;
- X b = buf + Strcpy(buf, dir);
- X if (b > buf && *(b - 1) != '/')
- X *b++ = '/';
- X skip = b - buf; /* We know this much matches, don't glob it again */
- X while (ret >= 0 && (dp = readdir(dirp))) {
- X if (fglob(dp->d_name, pat1)) {
- X if (pat2) {
- X (void) sprintf(b, "%s/%s", dp->d_name, pat2);
- X n = pglob(buf, skip, &tmp);
- X ret = catv(ret, exp, n, tmp);
- X } else {
- X (void) strcpy(b, dp->d_name);
- X ret = catv(ret, exp, 1, unitv(buf));
- X }
- X }
- X }
- X closedir(dirp);
- X return ret;
- }
- X
- /*
- X * Match file names. This means that metachars do not match leading ".".
- X */
- fglob(str, pat)
- char *str, *pat;
- {
- X if (!str || !pat || *str == '.' && *pat != '.')
- X return FALSE;
- X else
- X return glob(str, pat);
- }
- X
- /*
- X * Match two concatenated patterns. Mainly for use by sglob().
- X */
- static
- glob2(str, pat1, pat2)
- char *str, *pat1, *pat2;
- {
- X char buf[MAXPATHLEN];
- X
- X if (!str || !pat1 && !pat2)
- X return FALSE;
- X (void) sprintf(buf, "%s%s", pat1? pat1 : "", pat2? pat2 : "");
- X return glob(str, buf);
- }
- X
- /*
- X * The basic globbing matcher.
- X *
- X * "*" = match 0 or more occurances of anything
- X * "[abc]" = match any of "abc" (ranges supported)
- X * "{xx,yy,...}" = match any of "xx", "yy", ... where
- X * "xx", "yy" can be any pattern or empty
- X * "?" = match any character
- X */
- glob(str, pat)
- char *str, *pat;
- {
- X int done = FALSE, ret = FALSE;
- X
- X if (!str || !pat)
- X return FALSE;
- X
- X while (*pat && !done && (*str || (*pat == '{' || *pat == '*'))) /*}*/ {
- X /*
- X * First look for a literal match, stepping over backslashes
- X * in the pattern to match against the "protected" character.
- X * Ordering and precendence are important in this expression!
- X */
- X if (*pat == '\\' && *str == *++pat || *str == *pat) {
- X str++;
- X pat++;
- X } else switch (*pat++) {
- X case '*': /* Match any string */
- X if (!*pat) {
- X while (*str)
- X str++;
- X break;
- X }
- X /*
- X * Try the rest of the glob against every
- X * possible suffix of the string. A bit
- X * inefficient in cases that eventually fail.
- X */
- X while (*str && !(ret = glob(str++, pat)))
- X ;
- X return ret;
- X break;
- X case '[': /* Match a set */
- X repeat:
- X /* If we've hit the end of the set, give up. */
- SHAR_EOF
- true || echo 'restore of glob.c failed'
- fi
- echo 'End of part 8'
- echo 'File glob.c is continued in part 9'
- echo 9 > _shar_seq_.tmp
- exit 0
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-