home *** CD-ROM | disk | FTP | other *** search
- From: argv@zipcode.com (Dan Heller)
- Newsgroups: comp.sources.misc
- Subject: v18i066: mush - Mail User's Shell, Part09/22
- Message-ID: <1991Apr22.000206.18669@sparky.IMD.Sterling.COM>
- Date: 22 Apr 91 00:02:06 GMT
- Approved: kent@sparky.imd.sterling.com
- X-Checksum-Snefru: ef1e24ca b89364a3 9c0f9304 5cef0d36
-
- Submitted-by: Dan Heller <argv@zipcode.com>
- Posting-number: Volume 18, Issue 66
- Archive-name: mush/part09
- Supersedes: mush: Volume 12, Issue 28-47
-
- #!/bin/sh
- # this is Part.09 (part 9 of a multipart archive)
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file glob.c continued
- #
- if test ! -r _shar_seq_.tmp; then
- echo 'Please unpack part 1 first!'
- exit 1
- fi
- (read Scheck
- if test "$Scheck" != 9; 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 glob.c'
- else
- echo 'x - continuing file glob.c'
- sed 's/^X//' << 'SHAR_EOF' >> 'glob.c' &&
- X if (!*pat || *pat == ']' || *pat == '\\' && !*++pat) {
- X done = TRUE;
- X break;
- X }
- X /* Check for a range. */
- X if (*(pat + 1) == '-') {
- X char c = *pat++;
- X /* We don't handle open-ended ranges. */
- X if (*++pat == ']' || *pat == '\\' && !*++pat) {
- X done = TRUE;
- X break;
- X }
- X if (*str < c || *str > *pat) {
- X pat++;
- X goto repeat;
- X }
- X } else if (*pat != *str) {
- X pat++;
- X goto repeat;
- X }
- X /*
- X * We matched either the range or a literal member of
- X * the set. Skip to the end of the set.
- X */
- X pat++;
- X while (*pat && *pat != ']')
- X if (*pat++ == '\\' && *pat)
- X pat++;
- X /*
- X * If no pattern remains, the set was never closed,
- X * so don't increment. This will cause a FALSE return.
- X */
- X if (*pat) {
- X pat++;
- X str++;
- X }
- X break;
- X case '?': /* Match any one character */
- X str++;
- X break;
- X case '{': /* } Match any of a set of patterns */
- X return sglob(str, pat - 1, TRPL_NULL);
- X break;
- X default:
- X done = TRUE;
- X }
- X }
- X while (*pat == '*')
- X pat++;
- X return ((*str == '\0') && (*pat == '\0'));
- }
- X
- /*
- X * Match a pattern set {s1,s2,...} followed by any other pattern.
- X * Pattern sets and other patterns may nest arbitrarily.
- X *
- X * If "mat" is not a null pointer, a vector of possible expansions
- X * is generated and placed in *mat; otherwise, the expansions are
- X * matched against str and a truth value is returned ("/" is NOT
- X * treated as a directory separator in this case). NOTE: The vector
- X * of expansions may still contain nested pattern sets, which must
- X * be expanded separately. See sxp().
- X *
- X * Currently allows at most 256 alternatives per set. Enough? :-)
- X */
- static
- sglob(str, pat, mat)
- char *str, *pat, ***mat;
- {
- X char *p, *newpat[256], *oldpat[256], buf[MAXPATHLEN], *b = buf;
- X int copy = 1, nest = 0, i = 0, ret = 0;
- X
- X if (!pat)
- X return FALSE;
- X
- X while (*pat) {
- X if (copy)
- X if (*pat != '{') /*}*/ {
- X if (*pat == '\\' && pat[1])
- X *b++ = *pat++;
- X *b++ = *pat++;
- X continue;
- X } else {
- X copy = 0;
- X pat++;
- X }
- X p = pat;
- X while (*pat && (nest || *pat != ',' && /*{*/ *pat != '}')) {
- X if (*pat == '\\')
- X pat++;
- X else if (*pat == '{')
- X nest++;
- X else if (*pat == '}')
- X nest--;
- X if (*pat)
- X pat++;
- X }
- X if (*pat) {
- X oldpat[i] = pat;
- X newpat[i++] = p;
- X if (*pat != ',') {
- X *pat++ = 0;
- X break;
- X } else
- X *pat++ = 0;
- X }
- X }
- X oldpat[i] = NULL;
- X if (i > 0 && mat) {
- X *mat = (char **)malloc((unsigned)((i + 1) * sizeof(char *)));
- X if (*mat)
- X (*mat)[i] = NULL;
- X else
- X return -1;
- X ret = i;
- X }
- X while (!mat && i-- > 0)
- X if (ret = glob2(str, newpat[i], pat))
- X break;
- X for (i = 0; oldpat[i]; i++) {
- X if (mat && *mat) {
- X (void) sprintf(b, "%s%s", newpat[i], pat);
- X (*mat)[i] = savestr(buf);
- X }
- X if (oldpat[i + 1])
- X oldpat[i][0] = ',';
- X else
- X oldpat[i][0] = /*{*/ '}';
- X }
- X if (ret == 0 && b > buf && mat) {
- X *b = 0;
- X ret = ((*mat = unitv(buf)) ? 1 : -1);
- X }
- X return ret;
- }
- X
- /*
- X * Pre-expand pattern set notations so sets containing "/" separators
- X * can be globbed successfully. Returns the number of expansions.
- X */
- sxp(pat, exp)
- char *pat, ***exp;
- {
- X char **t1 = DUBL_NULL, **t2;
- X int n, new, cnt = 0;
- X
- X if ((n = sglob(NULL, pat, &t1)) < 2) {
- X *exp = t1;
- X return n;
- X }
- X *exp = DUBL_NULL;
- X while (n-- && cnt >= 0) {
- X new = sxp(t1[n], &t2);
- X cnt = catv(cnt, exp, new, t2);
- X }
- X xfree(t1);
- X return cnt;
- }
- X
- /*
- X * Generate the "glob difference" of two vectors (*argvp and patv).
- X * The "glob difference" means to remove all strings from argv that
- X * match any of the glob patterns in patv.
- X *
- X * Returns the number of strings remaining in *argvp. The strings "removed"
- X * from argv are actually left at the end of *argvp, so they can still be
- X * accessed; their number will of course be argc - (returned value).
- X */
- gdiffv(argc, argvp, patc, patv)
- int argc, patc;
- char ***argvp, **patv;
- {
- X char **argv, *t;
- X int ac, pc, oldac = argc;
- X
- X if (argc < 1 || patc < 1 || !patv || !*patv)
- X return argc;
- X if (!argvp || !(argv = *argvp) || !*argv)
- X return -1;
- X for (ac = 0; ac < argc && argv[ac]; ac++) {
- X for (pc = 0; ac < argc && pc < patc && patv[pc]; pc++) {
- X /*
- X * We shouldn't cross '/' characters, so test
- X * only the "tail" of each element of argv.
- X */
- X if (!(t = rindex(argv[ac], '/')))
- X t = argv[ac];
- X if (glob(t, patv[pc])) {
- X /* Move matches to the end and reduce argc */
- X t = argv[ac];
- X argv[ac] = argv[--argc];
- X argv[argc] = t;
- X /* Start patterns over on the new string */
- X pc = -1; /* It'll be incremented to 0 */
- X }
- X }
- X }
- X /*
- X * Sort the two parts of the argv. uniqcmp() works here only if
- X * there already are no duplicates, but we assume that for now.
- X */
- X if (argc)
- X qsort((char *)argv, argc, sizeof(char *), uniqcmp);
- X if (oldac > argc)
- X qsort((char *)&argv[argc], oldac - argc, sizeof(char *), uniqcmp);
- X return argc;
- }
- X
- /*
- X * Generate the longest common prefix from all strings in a vector
- X * If "skip" is nonzero, that many chars are assumed to be in common
- X * and are not tested. WARNING: skip must be <= than the length of
- X * the shortest string in the vector! Safest to call with skip = 0.
- X *
- X * Returns the length of the longest common prefix.
- X */
- lcprefix(vec, skip)
- char **vec;
- int skip;
- {
- X char c, **v;
- X int done = FALSE;
- X
- X if (!vec || !*vec || skip < 0)
- X return 0;
- X do {
- X for (v = vec + 1, c = vec[0][skip]; c && *v; v++)
- X if (v[0][skip] != c) {
- X done = TRUE;
- X break;
- X }
- X } while (!done && c && ++skip);
- X return skip;
- }
- X
- #define MAXCOLS 8 /* Max number of columns of words to make */
- #define MINWIDTH 10 /* Minimum width of each column of words */
- #ifdef CURSES
- #define MAXWIDTH (iscurses? COLS : 80)
- #else /* CURSES */
- #define MAXWIDTH 80 /* Maximum width of all columns */
- #endif /* CURSES */
- X
- /*
- X * Print a vector in columns
- X *
- X * If "skip" is nonzero, that many chars are assumed to be in common
- X * and are not printed. WARNING: skip must be <= than the length of
- X * the shortest string in the vector! Safest to call with skip = 0.
- X */
- columnate(argc, argv, skip)
- int argc;
- char **argv;
- int skip;
- {
- X int colstep, colwidth[MAXCOLS + 1];
- X int maxcols = min(argc, MAXCOLS);
- X int minwidth, maxwidth, *widths;
- X int maxword = 0, n, c;
- X
- X if (argc <= 0 || !argv || !*argv)
- X return -1;
- X if (!(widths = (int *)malloc((unsigned)((argc + 1) * sizeof(int)))))
- X return -1;
- X
- X /*
- X * Compute the widths of all words in the vector, and
- X * remember the maximum width and which word had it.
- X * Also remember the minimum width.
- X */
- X for (minwidth = MAXWIDTH, maxwidth = n = 0; n < argc; n++) {
- X widths[n] = max(strlen(argv[n] + skip) + 2, MINWIDTH);
- X if (widths[n] > MAXWIDTH - MINWIDTH)
- X break;
- X if (widths[n] > maxwidth) {
- X maxwidth = widths[n];
- X maxword = n;
- X }
- X if (widths[n] < minwidth)
- X minwidth = widths[n];
- X }
- X
- X for (; maxcols > 0; maxcols--) {
- X if (argc % maxcols)
- X colstep = argc / maxcols + 1;
- X else
- X colstep = argc / maxcols;
- X colwidth[MAXCOLS] = 0;
- X for (c = 0; c < maxcols; c++) {
- X colwidth[c] = 0;
- X for (n = c * colstep; n < (c + 1) * colstep && n < argc; n++)
- X colwidth[c] = max(colwidth[c], widths[n]);
- X colwidth[MAXCOLS] += colwidth[c];
- X }
- X if (colwidth[MAXCOLS] <= MAXWIDTH)
- X break;
- X }
- X xfree(widths);
- X
- X if (maxcols < 2 && minwidth <= MAXWIDTH / 2) {
- X /*
- X * The maxword fills too much screen, so redo everything
- X * above it, print maxword, then do everything below it.
- X */
- X if (maxword > 0 && columnate(maxword, argv, skip) < 0)
- X return -1;
- X wprint("%s\n", argv[maxword] + skip);
- X if (argc - maxword < 2)
- X return 0;
- X return columnate(argc - maxword - 1, &argv[maxword + 1], skip);
- X }
- X
- X for (n = 0; n < colstep; n++) {
- X for (c = 0; c < maxcols && n + c * colstep < argc - colstep; c++)
- X wprint("%-*.*s", colwidth[c], colwidth[c],
- X argv[n + c * colstep] + skip);
- X wprint("%s\n", argv[n + c * colstep] + skip);
- X }
- X
- X return 0;
- }
- X
- #ifndef DIRECTORY
- X
- #undef NULL
- #define NULL 0
- X
- /*
- X * 4.2BSD directory access emulation for non-4.2 systems.
- X * Based upon routines in appendix D of Portable C and Unix System
- X * Programming by J. E. Lapin (Rabbit Software).
- X *
- X * No responsibility is taken for any error in accuracies inherent
- X * either to the comments or the code of this program, but if
- X * reported to me then an attempt will be made to fix them.
- X */
- X
- /* Support for Berkeley directory reading routines on a V7/SysV file
- X * system.
- X */
- X
- /* Open a directory. */
- X
- DIR *
- opendir(name)
- char *name ;
- {
- X register DIR *dirp ;
- X register int fd ;
- X
- X if ((fd = open(name, 0)) == -1) return NULL ;
- X if ((dirp = (DIR *) malloc(sizeof(DIR))) == NULL)
- X {
- X close(fd) ;
- X return NULL ;
- X }
- X dirp->dd_fd = fd ;
- X dirp->dd_loc = 0 ;
- X return dirp ;
- }
- X
- X
- /* Read an old style directory entry and present it as a new one. */
- X
- #define ODIRSIZ 14
- X
- struct olddirent
- {
- X short od_ino ;
- X char od_name[ODIRSIZ] ;
- } ;
- X
- X
- /* Get next entry in a directory. */
- X
- struct dirent *
- readdir(dirp)
- register DIR *dirp ;
- {
- X register struct olddirent *dp ;
- X static struct dirent dir ;
- X
- X for (;;)
- X {
- X if (dirp->dd_loc == 0)
- X {
- X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ) ;
- X if (dirp->dd_size <= 0) return NULL ;
- X }
- X if (dirp->dd_loc >= dirp->dd_size)
- X {
- X dirp->dd_loc = 0 ;
- X continue ;
- X }
- X
- X dp = (struct olddirent *)(dirp->dd_buf + dirp->dd_loc) ;
- X dirp->dd_loc += sizeof(struct olddirent) ;
- X
- X if (dp->od_ino == 0) continue ;
- X
- X dir.d_fileno = dp->od_ino ;
- X strncpy(dir.d_name, dp->od_name, ODIRSIZ) ;
- X dir.d_name[ODIRSIZ] = '\0' ; /* Ensure termination. */
- X dir.d_namlen = strlen(dir.d_name) ;
- X dir.d_reclen = DIRSIZ(&dir) ;
- X return(&dir) ;
- X }
- }
- X
- X
- /* Close a directory. */
- X
- void
- closedir(dirp)
- register DIR *dirp ;
- {
- X close(dirp->dd_fd) ;
- X dirp->dd_fd = -1 ;
- X dirp->dd_loc = 0 ;
- X xfree(dirp) ;
- }
- X
- #endif /* DIRECTORY */
- SHAR_EOF
- echo 'File glob.c is complete' &&
- chmod 0644 glob.c ||
- echo 'restore of glob.c failed'
- Wc_c="`wc -c < 'glob.c'`"
- test 19617 -eq "$Wc_c" ||
- echo 'glob.c: original size 19617, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= glob.h ==============
- if test -f 'glob.h' -a X"$1" != X"-c"; then
- echo 'x - skipping glob.h (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting glob.h (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'glob.h' &&
- #ifdef BSD
- #define DIRECTORY
- #endif /* BSD */
- X
- #ifdef DIRECTORY
- #ifdef SYSV /* Some SysV 3.0 or higher */
- #include <dirent.h>
- #else /* SYSV */
- #include <sys/dir.h>
- #define dirent direct
- #endif
- #else /* !DIRECTORY */
- X
- /*
- X * 4.2BSD directory access emulation for non-4.2 systems.
- X * Based upon routines in appendix D of Portable C and Unix System
- X * Programming by J. E. Lapin (Rabbit Software).
- X *
- X * No responsibility is taken for any error in accuracies inherent
- X * either to the comments or the code of this program, but if
- X * reported to me then an attempt will be made to fix them.
- X */
- X
- #ifndef DEV_BSIZE
- #define DEV_BSIZE 512 /* Device block size. */
- #endif
- X
- #define DIRBLKSIZ DEV_BSIZE
- #define MAXNAMLEN 255 /* Name must be no longer than this. */
- X
- struct dirent
- {
- X long d_fileno ; /* Inode number of entry. */
- X short d_reclen ; /* Length of this record. */
- X short d_namlen ; /* Length of d_name string. */
- X char d_name[MAXNAMLEN + 1] ; /* Directory name. */
- } ;
- X
- /* The DIRSIZ macro gives the minimum record length that will hold the
- X * 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
- X * terminating null byte (dp->d_namlen+1), rounded up to a 4 byte
- X * boundary.
- X */
- X
- #undef DIRSIZ
- #define DIRSIZ(dp) \
- X ((sizeof (struct dirent) - (MAXNAMLEN+1)) \
- X + (((dp)->d_namlen+1 + 3) &~ 3))
- X
- /* Definitions for library routines operating on directories. */
- X
- typedef struct _dirdesc
- {
- X int dd_fd ;
- X long dd_loc ;
- X long dd_size ;
- X char dd_buf[DIRBLKSIZ] ;
- } DIR ;
- X
- #ifndef NULL
- #define NULL 0
- #endif
- X
- extern DIR *opendir() ;
- extern struct dirent *readdir() ;
- extern long telldir() ;
- extern void seekdir() ;
- #define rewinddir(dirp) seekdir((dirp), (long) 0)
- extern void closedir() ;
- X
- #endif /* DIRECTORY */
- X
- #define DELIM " \t;|"
- #define META "/?*[{"
- #define FMETA "?*[{"
- SHAR_EOF
- chmod 0644 glob.h ||
- echo 'restore of glob.h failed'
- Wc_c="`wc -c < 'glob.h'`"
- test 2071 -eq "$Wc_c" ||
- echo 'glob.h: original size 2071, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= hdr_sw.c ==============
- if test -f 'hdr_sw.c' -a X"$1" != X"-c"; then
- echo 'x - skipping hdr_sw.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting hdr_sw.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'hdr_sw.c' &&
- /* @(#)hdr_sw.c (c) copyright 2/17/90 (Dan Heller) */
- X
- /* This file handles all the header subwindow code. It would be much
- X * better if this subwindow, which displays the headers for the current
- X * folder, were a textsw. That way, this file would go away completely.
- X * Until then, we have to create the window (canvas), define an event
- X * handler for when events happen in this window, create our own scrollbar,
- X * figure out when the user scrolls with it, attach our own popup menu to
- X * the canvas, handle events for that, let's see... kitchen sink? Oh,
- X * that's over there in the corner.
- X */
- #include "mush.h"
- #ifdef SUN_4_0 /* SunOS 4.0+ */
- #include <sunwindow/win_keymap.h>
- #endif /* SUN_4_0 */
- X
- extern Panel hdr_panel;
- extern void hdr_io(), fkey_interposer();
- X
- static Notify_value scroll_hdr();
- static void msg_menu_func(), do_menu(), msg_menu_notify();
- Menu msg_menu;
- X
- void
- make_hdr_sw(parent)
- Frame parent;
- {
- X Textsw tmpsw;
- X
- X if (!(hdr_sw = window_create(parent, CANVAS,
- X WIN_HEIGHT, 10 + screen*l_height(),
- X WIN_WIDTH, WIN_EXTEND_TO_EDGE,
- X WIN_BELOW, hdr_panel,
- X WIN_EVENT_PROC, hdr_io,
- X CANVAS_AUTO_CLEAR, TRUE,
- X CANVAS_RETAINED, TRUE,
- X WIN_CONSUME_KBD_EVENTS,
- X WIN_ASCII_EVENTS, WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, NULL,
- X WIN_IGNORE_KBD_EVENTS,
- X WIN_UP_ASCII_EVENTS, NULL,
- X WIN_CONSUME_PICK_EVENTS,
- X LOC_WINENTER, WIN_MOUSE_BUTTONS, LOC_MOVE, NULL,
- X WIN_VERTICAL_SCROLLBAR, scrollbar_create(0),
- X NULL)))
- X perror("hdr_sw"), cleanup(0);
- X hdr_win = canvas_pixwin(hdr_sw);
- X (void) notify_interpose_event_func(hdr_sw, fkey_interposer, NOTIFY_SAFE);
- X (void) notify_interpose_event_func(hdr_sw, scroll_hdr, NOTIFY_SAFE);
- X scrollbar_set((Scrollbar)window_get(hdr_sw, WIN_VERTICAL_SCROLLBAR),
- X SCROLL_NORMALIZE, FALSE,
- X SCROLL_ADVANCED_MODE, TRUE,
- X SCROLL_LINE_HEIGHT, l_height(),
- X SCROLL_VIEW_LENGTH, screen,
- X NULL);
- #ifdef SUN_4_0 /* SunOS 4.0+ */
- X /* This is a particularly ugly hack. If Sun only documented the correct
- X * way to set up the key mapping for a window the way that textsw's do
- X * then we wouldn't have to do anything this awful. Maybe in 4.2.....
- X *
- X * The object here is to get the same translation table for our header
- X * canvas as for a textsw (more or less anyway). This way the arrow
- X * keys and such work right.
- X */
- X tmpsw = window_create(parent, TEXTSW, NULL);
- #ifdef SUN_4_1
- X keymap_from_fd[(int)window_get(hdr_sw, WIN_FD)].keymap =
- X keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].keymap;
- X keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].keymap = (Keymap *) 0;
- #else /* !SUN_4_1 */
- X keymap_from_fd[(int)window_get(hdr_sw, WIN_FD)].kf_keymap =
- X keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].kf_keymap;
- X keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].kf_keymap = (Keymap *) 0;
- #endif /* SUN_4_1 */
- X (void) window_destroy(tmpsw);
- #endif /* SUN_4_0 */
- }
- X
- static Notify_value
- scroll_hdr(canvas, event, arg, type)
- Canvas canvas;
- Event *event;
- Notify_arg arg;
- Notify_event_type type;
- {
- X int amount, count, i;
- X int show_deleted = !!do_set(set_options, "show_deleted");
- X char *argv[3], msgnum[8];
- X Scrollbar sb;
- X argv[0] = "headers";
- X argv[1] = msgnum;
- X argv[2] = NULL;
- X
- X switch (decode_scroll((Notify_client) canvas, event, screen, &amount)) {
- X case MUSH_SCROLL_PASS_EVENT:
- X switch(ID) {
- X case SCROLL_ENTER:
- X case SCROLL_EXIT:
- X return NOTIFY_IGNORED;
- X case SCROLL_REQUEST:
- X sb = (Scrollbar)arg;
- X switch( (Scroll_motion)
- X scrollbar_get(sb, SCROLL_REQUEST_MOTION)) {
- X case SCROLL_LINE_FORWARD:
- X amount = 1;
- X break;
- X case SCROLL_LINE_BACKWARD:
- X amount = -1;
- X break;
- X case SCROLL_ABSOLUTE:
- X i = (int)scrollbar_get(sb, SCROLL_VIEW_START);
- X if (!show_deleted) {
- X count = i;
- X for (i = 0; i < msg_cnt-1; i++)
- X if (!ison(msg[i].m_flags, DELETE) &&
- X count-- == 0)
- X break;
- X }
- X (void) sprintf(msgnum, "%d", i+1);
- X argv[1] = msgnum;
- X (void) do_hdrs(2, argv, NULL);
- X return(NOTIFY_DONE);
- X default:
- X amount =
- X (int)scrollbar_get(sb, SCROLL_VIEW_START) -
- X (int)scrollbar_get(sb, SCROLL_LAST_VIEW_START);
- X break;
- X }
- X break;
- X default:
- X return notify_next_event_func(canvas, event, arg, type);
- X }
- X break;
- X case MUSH_SCROLL_IGNORE:
- X return NOTIFY_IGNORED;
- X case MUSH_SCROLL_TO:
- X if (amount == 1) {
- X argv[1] = "1";
- X (void) do_hdrs(2, argv, NULL);
- X return NOTIFY_DONE;
- X } else {
- X (void) sprintf(msgnum, "%d", msg_cnt - screen + 1);
- X argv[1] = msgnum;
- X (void) do_hdrs(2, argv, NULL);
- X return NOTIFY_DONE;
- X }
- X }
- X if (amount == screen)
- X argv[1] = "+";
- X else if (amount == -screen)
- X argv[1] = "-";
- X else if (amount >= 0) {
- X if (amount < screen)
- X (void) sprintf(msgnum, "%d", min(n_array[amount]+1, msg_cnt-1));
- X else {
- X /* so much for layering */
- X for (i = n_array[0]+1; i < msg_cnt-1 && amount > 0; i++)
- X if (show_deleted || !ison(msg[i].m_flags, DELETE))
- X amount--;
- X (void) sprintf(msgnum, "%d", i);
- X }
- X } else {
- X /* so much for layering */
- X for (i = n_array[0]; i > 0 && amount < 0; i--)
- X if (show_deleted || !ison(msg[i-1].m_flags, DELETE))
- X amount++;
- X (void) sprintf(msgnum, "%d", i + 1);
- X }
- X (void) do_hdrs(2, argv, NULL);
- X return NOTIFY_DONE;
- }
- X
- /*
- X * Routines to handle io on the hdr_sw (canvas).
- X */
- X
- /* if MENU button goes down on a hdr, drawbox around hdr and popup menu */
- #define draw(x1,y1,x2,y2) (void) pw_vector(hdr_win, x1,y1,x2,y2,PIX_XOR,1)
- #define box(x1,y1,x2,y2) \
- X draw(x1,y1, x1,y2), draw(x1,y2, x2,y2), \
- X draw(x2,y2, x2,y1), draw(x2,y1, x1,y1)
- X
- #define READ_MSG (char *)'r'
- #define DEL_MSG (char *)'d'
- #define UNDEL_MSG (char *)'u'
- #define REPL_MSG (char *)'R'
- #define SAVE_MSG (char *)'s'
- #define PRNT_MSG (char *)'p'
- #define PRE_MSG (char *)'P'
- #define MARK_MSG (char *)'m'
- #define HELP_MSG (char *)'H'
- X
- #define MARK_TOGGLE (char *)'T'
- #define MARK_A (char *)'A'
- #define MARK_B (char *)'B'
- #define MARK_C (char *)'C'
- #define MARK_D (char *)'D'
- #define MARK_E (char *)'E'
- #define MARK_CLEAR (char *)'c'
- #define MARK_HELP (char *)'h'
- X
- /*ARGSUSED*/
- void
- hdr_io(canvas, event, arg)
- Canvas canvas;
- Event *event;
- caddr_t arg;
- {
- X static int which_cursor;
- X int line;
- X
- X if (ID == WIN_REPAINT) {
- X if (is_iconic != (int) window_get(tool, FRAME_CLOSED)) {
- X check_new_mail();
- X
- X /* Reload time with value of timeout upon timer expiration. */
- X mail_timer.it_interval.tv_sec = time_out;
- X
- X mail_timer.it_value.tv_sec = time_out;
- X (void) notify_set_itimer_func(tool, do_check,
- X ITIMER_REAL, &mail_timer, (struct itimerval *) 0);
- X is_iconic = 0;
- X }
- X }
- X
- X /* make cursor change which button is lit */
- X switch (which_cursor) {
- X case 0 : (void) window_set(canvas, WIN_CURSOR, l_cursor, NULL);
- X when 1 : (void) window_set(canvas, WIN_CURSOR, m_cursor, NULL);
- X when 2 : (void) window_set(canvas, WIN_CURSOR, r_cursor, NULL);
- X }
- X
- X which_cursor = (which_cursor+1) % 3;
- X
- X /* just return -- we just wanted to make the cursor flicker */
- X if (ID == LOC_STILL || ID == LOC_MOVE || ID == LOC_WINENTER ||
- X ID == LOC_RGNENTER || ID == KBD_USE || ID == KBD_DONE)
- X return;
- X
- X if (event_is_button(event) && event_is_down(event)) {
- X line = (event_y(event) - 5) / l_height();
- X if (line < 0)
- X line = 0;
- X else if (line >= screen)
- X line = screen - 1;
- X if (!msg_cnt || n_array[line] > msg_cnt)
- X return;
- X if (ID == MS_RIGHT)
- X do_menu(hdr_sw, event, window_get(hdr_sw, WIN_FD), n_array[line]);
- X else if (ID == MS_MIDDLE) {
- X set_isread(n_array[line]);
- X msg_menu_func((int)DEL_MSG, n_array[line]);
- X } else {
- X int do_do_hdrs = 0;
- X if (current_msg != n_array[line]) {
- X current_msg = n_array[line];
- X do_do_hdrs++;
- X }
- X if (ison(msg[current_msg].m_flags, UNREAD))
- X do_do_hdrs++;
- X (void) display_msg(n_array[line], (u_long)0);
- X if (do_do_hdrs)
- X (void) do_hdrs(0, DUBL_NULL, NULL);
- X }
- X } else
- X window_default_event_proc(canvas, event, NULL);
- }
- X
- static struct menu_rec {
- X char *str; /* Menu item label. */
- X char *data; /* Menu item client data. */
- };
- X
- void
- get_msg_menu()
- {
- X int i;
- X Menu_item mi = NULL, sub_mi;
- X
- X static struct menu_rec msg_items[] = {
- X { "Read", READ_MSG },
- X { "Delete", DEL_MSG },
- X { "Undelete", UNDEL_MSG },
- X { "Reply", REPL_MSG },
- X { "Save", SAVE_MSG },
- X { "Preserve", PRE_MSG },
- X { "Mark", MARK_MSG },
- X { "Print", PRNT_MSG },
- X { "Help", HELP_MSG },
- X };
- X static struct menu_rec mark_msg_items[] = {
- X { "Toggle Mark", MARK_TOGGLE},
- X { "Priority A", MARK_A },
- X { "Priority B", MARK_B },
- X { "Priority C", MARK_C },
- X { "Priority D", MARK_D },
- X { "Priority E", MARK_E },
- X { "Clear Priority", MARK_CLEAR },
- X { "Help", MARK_HELP },
- X };
- X
- X msg_menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, NULL);
- X for (i = 0; i < ArraySize(msg_items); i++) {
- X mi = menu_create_item(MENU_STRING, msg_items[i].str,
- X MENU_CLIENT_DATA, msg_items[i].data,
- X NULL);
- X if (msg_items[i].data == MARK_MSG) {
- X int j;
- X /* get the menu from <Mark> and set as this item's pullright */
- X Menu the_menu = menu_create(
- X MENU_NOTIFY_PROC, menu_return_item, NULL);
- X for (j = 0; j < ArraySize(mark_msg_items); j++) {
- X sub_mi = menu_create_item(
- X MENU_STRING, mark_msg_items[j].str,
- X MENU_CLIENT_DATA, mark_msg_items[j].data,
- X NULL);
- X (void) menu_set(the_menu, MENU_APPEND_ITEM, sub_mi, NULL);
- X }
- X menu_set(mi, MENU_PULLRIGHT, the_menu, NULL);
- X }
- X (void) menu_set(msg_menu, MENU_APPEND_ITEM, mi, NULL);
- X }
- }
- X
- static void
- do_menu(can_sw, event, fd, message)
- Canvas can_sw;
- Event *event;
- int fd, message;
- {
- X char *action;
- X char *save_place;
- X Menu_item cur_msg_item;
- X static char buf[16];
- X
- X if (!msg_cnt) {
- X wprint("No Messages.\n");
- X return;
- X }
- X if (fd) {
- X int line;
- X Rect *hdr_rect;
- X extern Menu hdr_save_menu;
- X
- X if (!msg_menu)
- X get_msg_menu();
- X (void) sprintf(buf, "Message #%d", message+1);
- X /* provide feedback about what message the menu references */
- X for (line = 0; line <= n_array[screen-1]; line++)
- X if (n_array[line] == message)
- X break;
- X hdr_rect = (Rect *)window_get(hdr_sw, WIN_RECT);
- X box(0, 5 + line * l_height(),
- X hdr_rect->r_width, 5 + (line+1) * l_height());
- X /* show menu */
- X cur_msg_item = menu_show(msg_menu, can_sw, event, NULL);
- X /* remove feedback */
- X box(0, 5 + line * l_height(),
- X hdr_rect->r_width, 5 + (line+1) * l_height());
- X /* if user selected something, figure out what was selected. */
- X if (!cur_msg_item)
- X return;
- #ifndef NO_WALK_MENUS
- X if ((Menu)menu_get(cur_msg_item, MENU_PARENT) == hdr_save_menu) {
- X save_place = (char *)menu_get(cur_msg_item, MENU_CLIENT_DATA);
- X action = SAVE_MSG;
- X } else
- #endif /* NO_WALK_MENUS */
- X action = (char *) menu_get(cur_msg_item, MENU_CLIENT_DATA);
- X } else
- X action = (char *) event;
- X
- X set_isread(message);
- X switch ((int) action) {
- X case SAVE_MSG : {
- X extern Panel_item msg_num_item, save_item;
- X (void) panel_set(msg_num_item, PANEL_VALUE,
- X sprintf(buf, "%d", message+1), NULL);
- #ifndef NO_WALK_MENUS
- X if (*save_place == '\0') /* magic to mean "use Filename:" */
- X do_file_dir(save_item, event);
- X else
- X xx_file_dir(save_item, save_place);
- #else /* NO_WALK_MENUS */
- X event_id(event) = MS_LEFT;
- X do_file_dir(save_item, 0, event);
- #endif /* NO_WALK_MENUS */
- X (void) panel_set(msg_num_item, PANEL_VALUE, NO_STRING, NULL);
- X }
- X when HELP_MSG :
- X help(0, "headers", tool_help);
- X when REPL_MSG : {
- X extern Panel_item reply_item;
- X open_compose();
- X if (!compose_frame)
- X break; /* open failed */
- X /* reply_item shouldn't be here */
- X respond_mail(reply_item, message, NO_EVENT);
- X }
- X when READ_MSG :
- X if (current_msg != message) {
- X current_msg = message;
- X (void) do_hdrs(0, DUBL_NULL, NULL);
- X }
- #ifdef SUN_3_5
- X /* Test for a shortage of file descriptors */
- X if (nopenfiles(0) > 3)
- #endif /* SUN_3_5 */
- X turnon(glob_flags, NEW_FRAME);
- X more_prompt = compose_hdr(message);
- X display_msg(message, (u_long)0);
- X
- X otherwise :
- X msg_menu_func((int)action, message);
- X }
- }
- X
- /* msg_menu_func() is a function called to perform message menu actions
- X * that are either selected from the popup menu in the header window or
- X * from mouse actions that function as accelerators.
- X */
- static void
- msg_menu_func(action, message)
- int action;
- {
- X int argc;
- X register char **argv;
- X char buf[32];
- X
- X switch (action) {
- X case PRNT_MSG :
- X wprint("Message #%d sent to printer.\n", message+1);
- X (void) strcpy(buf, "lpr");
- X when UNDEL_MSG : case DEL_MSG :
- X (void) sprintf(buf, "%selete", (action == (int)DEL_MSG)?"d":"und");
- X when PRE_MSG :
- X (void) strcpy(buf, "preserve");
- X when MARK_MSG : case MARK_TOGGLE :
- X (void) sprintf(buf, "%smark",
- X ison(msg[message].m_flags, M_PRIORITY(0))? "un" : "");
- X when MARK_A : case MARK_B : case MARK_C : case MARK_D : case MARK_E :
- X (void) sprintf(buf, "mark -%c", action);
- X when MARK_CLEAR :
- X (void) strcpy(buf, "mark -");
- X when MARK_HELP :
- X (void) help(0, "mark", tool_help);
- X return;
- X otherwise :
- X print("unknown switch: %c\n", action);
- X }
- X (void) sprintf(&buf[strlen(buf)], " %d", message+1);
- X
- X if (argv = make_command(buf, (char ***) DUBL_NULL, &argc))
- X (void) do_command(argc, argv, msg_list);
- }
- SHAR_EOF
- chmod 0644 hdr_sw.c ||
- echo 'restore of hdr_sw.c failed'
- Wc_c="`wc -c < 'hdr_sw.c'`"
- test 13462 -eq "$Wc_c" ||
- echo 'hdr_sw.c: original size 13462, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= hdrs.c ==============
- if test -f 'hdrs.c' -a X"$1" != X"-c"; then
- echo 'x - skipping hdrs.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting hdrs.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'hdrs.c' &&
- /* hdrs.c (c) copyright 1986 (Dan Heller) */
- X
- /*
- X * Routines that deal with message headers inside messages
- X * msg_get(n, from, count) -- get the From_ line in msg n into "from".
- X * header_field(n, str) -- get the header named "str" from msg n.
- X * do_hdrs(argc, argv, list) -- diplay message headers.
- X * specl_hdrs(argv, list) -- display msgs that share common attributes.
- X * compose_hdr(cnt) -- compose a message header from msg n.
- X * reply_to(n, all, buf) -- construct a header based on the To: header of n.
- X * subject_to(n, buf) -- get the subject for replying to msg n.
- X * cc_to(n, buf) -- construct a Cc header based on the Cc of message n.
- X */
- #include "mush.h"
- X
- #ifdef SUNTOOL
- #define highlight(win,x,y,s) \
- X (void) (pw_text(win,x,y, PIX_SRC, mush_font, s), \
- X pw_text(win,x+1,y, \
- X (ison(glob_flags, REV_VIDEO))? PIX_NOT(PIX_SRC): PIX_SRC|PIX_DST, \
- X mush_font, s))
- #endif /* SUNTOOL */
- X
- /*
- X * Get a message from the current folder by its offset.
- X * Copy the From_ line to the second argument if the third arg > 0,
- X * and return the second argument, or NULL on an error.
- X */
- char *
- msg_get(n, from, count)
- int n, count;
- char *from;
- {
- X if (fseek(tmpf, msg[n].m_offset, L_SET) == -1) {
- X error("fseek in %s (msg %d, folder=%s)", tempfile, n+1, mailfile);
- X turnon(glob_flags, READ_ONLY);
- X return NULL;
- X }
- X if (count)
- #ifndef MSG_SEPARATOR
- X return fgets(from, count, tmpf);
- #else
- X *from = '\0';
- #endif
- X return from;
- }
- X
- /*
- X * get which message via the offset and search for the headers which
- X * match the string "str". there may be more than one of a field (like Cc:)
- X * so get them all and "cat" them together into the static buffer
- X * "buf" and return its address.
- X */
- char *
- header_field(n, str)
- char *str;
- {
- X static char buf[HDRSIZ];
- X char tmp[HDRSIZ];
- X register char *p, *p2, *b = buf;
- X int contd_hdr; /* true if next line is a continuation of the hdr we want */
- X
- X /* use msg_get as a test for fseek() -- don't let it fgets() (pass 0) */
- X if (!msg_get(n, tmp, 0))
- X return NULL;
- X *b = 0;
- X while((p = fgets(tmp, sizeof(tmp), tmpf)) && *p != '\n') {
- X if (*p != ' ' && *p != '\t') {
- X contd_hdr = 0;
- X /* strcmp ignoring case */
- X for(p2 = str; *p && *p2 && lower(*p2) == lower(*p); ++p, ++p2);
- X /* MATCH is true if p2 is at the end of str and *p is ':' */
- X if (*p2 || *p++ != ':')
- X continue;
- X else
- X contd_hdr = 1;
- X if (b > buf && (b - buf) < sizeof buf - 2)
- X *b++ = ',';
- X } else if (!contd_hdr)
- X continue;
- X skipspaces(0);
- X (void) no_newln(p);
- X if (strlen(p) + (b - buf) < sizeof buf - 1) {
- X if (b > buf)
- X *b++ = ' ';
- X b += Strcpy(b, p);
- X }
- X }
- X if (b > buf && *--b == ',')
- X *b = 0;
- X return (*buf)? buf: NULL;
- }
- X
- do_hdrs(argc, argv, list)
- register char **argv, list[];
- {
- X register int pageful = 0;
- X SIGRET (*oldint)(), (*oldquit)();
- X int show_deleted, srch = 1; /* search forward by default */
- X static int cnt, oldscrn = 1;
- X register char *p;
- X char first_char = (argc) ? **argv: 'h';
- X
- X if (argc > 1 && !strcmp(argv[1], "-?"))
- X return help(0, "headers", cmd_help);
- X
- X if (!msg_cnt) {
- X if (ison(glob_flags, DO_PIPE) && !istool)
- X return 0;
- #ifdef CURSES
- X if (iscurses)
- X clear();
- #endif /* CURSES */
- #ifdef SUNTOOL
- X if (istool)
- X mail_status(0);
- #endif /* SUNTOOL */
- X return 0;
- X }
- X if (first_char == ':' || (argc > 1 && argv[1][0] == ':')) {
- X if (first_char != ':')
- X argv++;
- X return specl_hdrs(argv, list);
- X } else if (argc > 1 && !strncmp(argv[1], "-H:", 3)) {
- X argv[1][0] = ':';
- X argv[1][1] = argv[1][3];
- X argv[1][2] = 0;
- X return specl_hdrs(&argv[1], list);
- X }
- X
- X on_intr();
- X
- X if (argc && (argv[0][1] == '-' || argc > 1 && !strcmp(argv[1], "-"))) {
- X cnt = max(n_array[0], 0);
- X srch = -1; /* search backwards */
- X } else if (argc && (argv[0][1] == '+' ||
- X argc > 1 && !strcmp(argv[1], "+")) ||
- X first_char == 'z' && !argv[1]) {
- X if (msg_cnt > screen)
- X cnt = min(msg_cnt - screen, n_array[0] + screen);
- X else
- X cnt = 0;
- X } else if (argc && *++argv &&
- X (isdigit(**argv) || **argv == '^' ||
- X **argv == '$' || **argv == '.') ||
- X ison(glob_flags, IS_PIPE) && list) {
- X /* if we're coming from a pipe, start display at the first msg bit
- X * set in the msg_list
- X */
- X int fnd;
- X if (ison(glob_flags, IS_PIPE)) {
- X if (isoff(glob_flags, DO_PIPE))
- X for (fnd = 0; fnd < msg_cnt; fnd++)
- X if (msg_bit(list, fnd))
- X wprint("%s\n", compose_hdr(fnd));
- X off_intr();
- X return 0;
- X }
- X /* if a number was given, use it */
- X if (!(fnd = chk_msg(*argv))) {
- X off_intr();
- X return -1;
- X }
- X for (cnt = fnd - 1; cnt > 0 && cnt + screen > msg_cnt; cnt--)
- X ;
- X } else if (current_msg < n_array[0] || current_msg > n_array[oldscrn-1] ||
- X (iscurses || oldscrn != screen) &&
- X (cnt > current_msg + screen || cnt < current_msg - screen))
- X cnt = current_msg; /* adjust if reads have passed screen bounds */
- X else if (cnt >= msg_cnt || !argc || !*argv)
- X /* adjust window to maintain position */
- X cnt = (n_array[0] > msg_cnt) ? current_msg : n_array[0];
- X
- X oldscrn = screen;
- X show_deleted = !!do_set(set_options, "show_deleted");
- X
- X /* Make sure we have at least $screen headers to print */
- X if (cnt > 0 && !iscurses && first_char == 'h') {
- X int top, bot = cnt;
- X /* first count how many messages we can print without adjusting */
- X for (pageful = 0; pageful<screen && bot<msg_cnt && bot; bot += srch)
- X if (show_deleted || isoff(msg[bot].m_flags, DELETE))
- X pageful++;
- X /* if we can't print a pagefull of hdrs, back up till we can */
- X for (top = cnt-srch; pageful<screen && top && top<msg_cnt; top -= srch)
- X if (show_deleted || isoff(msg[top].m_flags, DELETE))
- X pageful++;
- X if (srch < 0)
- X cnt = bot; /* the search was upside down */
- X else
- X cnt = top + (pageful == screen);
- X pageful = 0; /* Used later as an index, so reset */
- X } else if (cnt > 0 && srch < 0)
- X cnt = max(cnt - screen, 0);
- X else
- X cnt = max(cnt, 0);
- X
- X for (;pageful<screen && cnt<msg_cnt && isoff(glob_flags, WAS_INTR); cnt++) {
- X if (!iscurses && !show_deleted && first_char == 'h'
- X && ison(msg[cnt].m_flags, DELETE))
- X continue;
- X n_array[pageful++] = cnt;
- X /* this message was displayed -- set the bit */
- X if (list)
- X set_msg_bit(list, cnt);
- X /* if do_pipe, don't output anything */
- X if (ison(glob_flags, DO_PIPE) && !istool)
- X continue;
- X p = compose_hdr(cnt);
- X if (!istool && (!iscurses || ison(glob_flags, IS_GETTING)))
- X puts(p);
- #ifdef SUNTOOL
- X else if (istool) {
- X if (cnt == current_msg) /* embolden or reverse-video */
- X highlight(hdr_win, 0,pageful*l_height(), p);
- X else
- X (void) pw_text(hdr_win, 0, pageful * l_height(), PIX_SRC,
- X mush_font, p);
- X Clrtoeol(hdr_win, strlen(p)*l_width(), pageful*l_height());
- X }
- #endif /* SUNTOOL */
- X
- #ifdef CURSES
- X else if (iscurses) {
- X move(pageful, 0);
- X printw("%-.*s", COLS-2, p), clrtoeol();
- X }
- #endif /* CURSES */
- X }
- X /* just in case a signal stopped us */
- X off_intr();
- X pageful++;
- #ifdef CURSES
- X if (iscurses && pageful < screen)
- X move(pageful, 0), clrtobot();
- #endif /* CURSES */
- X if (cnt == msg_cnt) {
- X while (pageful <= screen) {
- X n_array[pageful-1] = msg_cnt+1; /* assign out-of-range values */
- #ifdef SUNTOOL
- X if (istool)
- X Clrtoeol(hdr_win, 0, pageful * l_height());
- #endif /* SUNTOOL */
- X ++pageful;
- X }
- X }
- #ifdef SUNTOOL
- X if (istool) {
- X Scrollbar sb = (Scrollbar) window_get(hdr_sw, WIN_VERTICAL_SCROLLBAR);
- X
- X if (show_deleted) {
- X scrollbar_set(sb,
- X SCROLL_OBJECT_LENGTH, msg_cnt,
- X SCROLL_VIEW_START, n_array[0],
- X 0);
- X } else {
- X int i, not_deleted, start;
- X
- X for (i = start = 0; i < n_array[0]; i++)
- X if (!ison(msg[i].m_flags, DELETE))
- X start++;
- X for (not_deleted = start; i < msg_cnt; i++)
- X if (!ison(msg[i].m_flags, DELETE))
- X not_deleted++;
- X scrollbar_set(sb,
- X SCROLL_OBJECT_LENGTH, not_deleted,
- X SCROLL_VIEW_START, start,
- X 0);
- X }
- X
- X scrollbar_paint(sb);
- X mail_status(0);
- X }
- #endif /* SUNTOOL */
- X
- X return 0;
- }
- X
- #define NEW 1
- #define ALL 2
- X
- specl_hdrs(argv, list)
- char **argv, list[];
- {
- X u_long special = 0;
- X int n = 0;
- X
- X while (argv[0][++n])
- X switch(argv[0][n]) {
- X case 'a': special = ALL;
- X when 'd': special = DELETE;
- X when 'm': special = M_PRIORITY(0);
- X when 'n': special = NEW;
- X when 'o': special = OLD;
- X when 'p': special = PRESERVE;
- X when 'r': special = REPLIED;
- X when 's': special = SAVED;
- X when 'u': special = UNREAD;
- X otherwise: print("choose from d,m,n,o,p,r,s,u or a"); return -1;
- X }
- X if (debug)
- X (void) check_flags(special);
- X
- X for (n = 0; n < msg_cnt; n++) {
- X /*
- X * First, see if we're looking for NEW messages.
- X * If so, then check to see if the msg is unread and not old.
- X * If special > ALL, then special has a mask of bits describing
- X * the state of the message.
- X */
- X if (ison(glob_flags, IS_PIPE)&& !msg_bit(list, n))
- X continue;
- X if (special == ALL || special == NEW &&
- X (ison(msg[n].m_flags, UNREAD) && isoff(msg[n].m_flags, OLD))) {
- X if (isoff(glob_flags, DO_PIPE))
- X print("%s\n", compose_hdr(n));
- X if (list)
- X set_msg_bit(list, n);
- X } else if (special > ALL && ison(msg[n].m_flags, special)) {
- X if (isoff(glob_flags, DO_PIPE))
- X print("%s\n", compose_hdr(n));
- X if (list)
- X set_msg_bit(list, n);
- X } else {
- X if (list)
- X unset_msg_bit(list, n);
- X if (debug) {
- X (void) printf("msg[%d].m_flags: %d", n, msg[n].m_flags);
- X (void) check_flags(msg[n].m_flags);
- X }
- X }
- X }
- X return 0;
- }
- X
- #define Strncpy(buf,p) (void)(strncpy(buf,p,sizeof(buf)),buf[sizeof(buf)-1]=0)
- X
- /*
- X * format a header from the information about a message (from, to, date,
- X * subject, etc..). The header for message number "cnt" is built and is
- X * returned in the static buffer "buf". There will be *at least* 9 chars
- X * in the buffer which will be something like: " 123 >N " The breakdown
- X * is as follows: 4 chars for the message number, 1 space, 1 char for '>'
- X * (if current message) and two spaces for message status (new, unread, etc)
- X * followed by 1 terminating space.
- X * Read other comments in the routine for more info.
- X */
- char *
- format_hdr(cnt, hdr_fmt, show_to)
- int cnt, show_to;
- char *hdr_fmt;
- {
- X static char buf[256];
- X register char *p, *p2, *b;
- X int len, do_pad = FALSE, val, pad, got_dot, isauthor = 0, n;
- X char from[HDRSIZ], subject[256], date[64], lines[16];
- X char to[256], addr[256], name[256], user[256], status[4];
- X char Day[3], Mon[4], Tm[8], Yr[5], Wkday[4], Zone[8], *date_p;
- X
- X /* status of the message */
- X if (ison(msg[cnt].m_flags, DELETE))
- X status[0] = '*';
- X else if (ison(msg[cnt].m_flags, PRESERVE))
- X status[0] = 'P';
- X else if (ison(msg[cnt].m_flags, SAVED))
- X status[0] = 'S';
- X else if (ison(msg[cnt].m_flags, OLD) && ison(msg[cnt].m_flags, UNREAD))
- X status[0] = 'U';
- X else if (ison(msg[cnt].m_flags, PRINTED))
- X status[0] = 'p';
- X else if (ison(msg[cnt].m_flags, FORWARD))
- X status[0] = 'f';
- X else if (isoff(msg[cnt].m_flags, UNREAD))
- X status[0] = ' ';
- X else
- X status[0] = 'N';
- X
- X if (ison(msg[cnt].m_flags, REPLIED))
- X status[1] = 'r';
- X else
- X status[1] = ' ';
- X status[2] = 0;
- X
- X to[0] = from[0] = subject[0] = date[0] = lines[0] = addr[0] =
- X user[0] = name[0] = Day[0] = Mon[0] = Tm[0] = Yr[0] = Wkday[0] = 0;
- X
- X /* who's the message to */
- X if ((p = header_field(cnt, "resent-to")) ||
- X (p = header_field(cnt, "to")) ||
- X (p = header_field(cnt, "apparently-to")))
- X Strncpy(to, p);
- X
- X /* who's the message from */
- X if ((p = header_field(cnt, "from")) && strcpy(from, p)
- X || (p = reply_to(cnt, 0, from))) {
- X /* NOTE: this fails if the sender has '<' or '!' in
- X * the RFC822 comment fields -- leading "comment"
- X * or trailing (comment) -- but that isn't critical
- X */
- X if ((p2 = rindex(p, '!')) || (p2 = index(p, '<')))
- X p = p2 + 1;
- X } else
- X p = strcpy(from, "unknown"); /* just in case */
- X /* If the From field contains the user's login name, then the message
- X * could be from the user -- attempt to give more useful information
- X * by telling to whom the message was sent. This is not possible if
- X * the "to" header failed to get info (which is probably impossible).
- X * Use take_me_off() to be sure the message really is from the current
- X * user and not just someone with the same login at another site.
- X */
- X if (show_to && !strncmp(p, login, strlen(login)))
- X (void) take_me_off(from);
- X if (show_to && (isauthor = !*from)) { /* assign and test */
- X (void) get_name_n_addr(to, name+4, addr+4);
- X if (addr[4])
- X (void) strncpy(addr, "TO: ", 4);
- X if (name[4]) { /* check to see if a name got added */
- X (void) strncpy(name, "TO: ", 4);
- X Strncpy(from, name);
- X } else
- X Strncpy(from, addr);
- X } else
- X (void) get_name_n_addr(from, name, addr);
- X
- X if (ison(glob_flags, DATE_RECV))
- X date_p = msg[cnt].m_date_recv;
- X else
- X date_p = msg[cnt].m_date_sent;
- X (void) date_to_string(date_p, Yr, Mon, Day, Wkday, Tm, Zone, date);
- X
- X /* and the subject */
- X if (p = header_field(cnt, "subject"))
- X Strncpy(subject, p);
- X
- X /* now, construct a header out of a format string */
- X if (!hdr_fmt)
- X hdr_fmt = hdr_format;
- X {
- X int i;
- X for (i = MAX_PRIORITY; i > 0; i--)
- X if (ison(msg[cnt].m_flags, M_PRIORITY(i))) {
- X p2 = sprintf(lines, "%d", i);
- X break;
- X }
- X (void) sprintf(buf, "%c%3.d%s%c%s ",
- X ((cnt == current_msg && !iscurses)? '>': ' '),
- X cnt+1, cnt < 999 ? " " : "",
- X (ison(msg[cnt].m_flags, M_PRIORITY(0)) ? '+' :
- X i > 0 ? 'A' + i - 1 : ' '),
- X status);
- X }
- X /* Count chars since beginning of buf. Initialize to 9 (strlen(buf) so far)
- X * This magic number is used in other places in msgs.c and mail.c
- X */
- X n = 9;
- X b = buf+9;
- X for (p = hdr_fmt; *p; p++)
- X if (*p == '\\')
- X switch (*++p) {
- X case 't':
- X while (n % 8)
- X n++, *b++ = ' ';
- X when 'n':
- X n = 1, *b++ = '\n';
- X otherwise: n++, *b++ = *p;
- X }
- X else if (*p == '%') {
- X char fmt[64];
- X
- X p2 = fmt;
- X /* first check for string padding: %5n, %.4a, %10.5f, %-.3l etc. */
- X do_pad = pad = val = got_dot = 0;
- X *p2++ = '%';
- X if (p[1] != '-')
- X *p2++ = '-';
- X else
- X ++p;
- X while (isdigit(*++p) || !got_dot && *p == '.') {
- X if (*p == '.')
- X got_dot = TRUE, val = pad, pad = 0;
- X else
- X pad = pad * 10 + *p - '0';
- X *p2++ = *p;
- X }
- X if (!got_dot && isdigit(p[-1])) {
- X *p2 = 0; /* assure null termination */
- X val = atoi(fmt+1);
- X if (val < 0)
- X val = -val;
- X p2 += strlen(sprintf(p2, ".%d", val));
- X }
- X pad = min(pad, val);
- X *p2++ = 's', *p2 = 0;
- X if (!*p)
- X break;
- X switch (*p) {
- X case 'f': p2 = from, do_pad = TRUE;
- X when 'a':
- X if (!*(p2 = addr))
- X p2 = from;
- X do_pad = TRUE;
- X when 'u' :
- X if (!user[0])
- X (void) bang_form(user, addr);
- X if (p2 = rindex(user, '!'))
- X p2++;
- X else
- X p2 = user;
- X when 'n':
- X if (!*(p2 = name))
- X p2 = from, do_pad = TRUE;
- X when '%': p2 = "%";
- X when 't': p2 = to;
- X when 's': p2 = subject;
- X when 'l': p2 = sprintf(lines, "%d", msg[cnt].m_lines);
- X when 'c': p2 = sprintf(lines, "%ld", msg[cnt].m_size);
- X when 'i': (p2 = header_field(cnt, "message-id")) || (p2 = "");
- X /* date formatting chars */
- X when 'd': p2 = date; /* the full date */
- X when 'T': p2 = Tm;
- X when 'M': p2 = Mon;
- X when 'Y': p2 = Yr;
- X when 'y': p2 = Yr+2;
- X when 'N': p2 = Day;
- X when 'D': case 'W': p2 = Wkday;
- X when 'Z': p2 = Zone;
- X /* Any selected header */
- X when '?': {
- X p2 = p + 1;
- X p = index(p2, '?');
- X if (p) {
- X *p = 0;
- X if (!(p2 = header_field(cnt, p2)))
- X p2 = "";
- X *p = '?';
- X } else {
- X p = p2 + (strlen(p2) - 1);
- X if (!(p2 = header_field(cnt, p2)))
- X p2 = "";
- X }
- X }
- X otherwise: continue; /* unknown formatting char */
- X }
- X if (do_pad && pad && strlen(p2) > pad) {
- X char *old_p2 = p2, *p3;
- X int is_bangform = 0;
- X /* if addr is too long, move pointer forward till the
- X * "important" part is readable only for ! paths/addresses.
- X */
- X while (p3 = index(p2, '!')) {
- X is_bangform = 1;
- X len = strlen(p3+1); /* xenix has compiler problems */
- X p2 = p3+1;
- X if (len + isauthor*4 < pad) {
- X if (isauthor && (p2 -= 4) < old_p2)
- X p2 = old_p2;
- X break;
- X }
- X }
- X if (isauthor && p2 > old_p2+4 && !p3 && strlen(p2) + 4 > pad)
- X p2 -= 4;
- X if (is_bangform && (p3 = rindex(p2, '@'))) {
- X len = strlen(p3);
- X while (len-- && --p2 > old_p2) {
- X if (*(p2 + isauthor*4 - 1) == '!')
- X break;
- X }
- X }
- X if (old_p2 != p2 && isauthor)
- X (void) strncpy(p2, "TO: ", 4); /* doesn't null terminate */
- X }
- X len = strlen(sprintf(b, fmt, p2));
- X n += len, b += len;
- X /* Get around a bug in 5.5 IBM RT which pads with NULs not ' ' */
- X while (n && !*(b-1))
- X b--, n--;
- X } else
- X n++, *b++ = *p;
- X /* Since show_to is true only when called from compose_hdr() below,
- X * use it to decide whether trailing whitespace should be trimmed.
- X */
- X if (show_to)
- X for (*b-- = 0; isspace(*b) && *b != '\n'; --b)
- X *b = 0;
- X else
- X *b = 0;
- X return buf;
- }
- X
- char *
- compose_hdr(cnt)
- int cnt;
- {
- X if (!hdr_format)
- X hdr_format = DEF_HDR_FMT;
- X return format_hdr(cnt, hdr_format, TRUE);
- }
- X
- /*
- X * Using message "n", build a list of recipients that you would mail to if
- X * you were to reply to this message. If "all" is true, then it will take
- X * everyone from the To line in addition to the original sender.
- X * route_addresses() is called from mail.c, not from here. There are too many
- X * other uses for reply_to to always require reconstruction of return paths.
- X * Note that we do NOT deal with Cc paths here either.
- X * Check to make sure that we in fact return a legit address (i.e. not blanks
- X * or null). If such a case occurs, return login name. Always pad end w/blank.
- X */
- char *
- reply_to(n, all, buf)
- char buf[];
- {
- X register char *p = NULL, *p2, *b = buf, *field;
- X char line[256], name[256], addr[256], *unscramble_addr();
- X
- X if (field = do_set(set_options, "reply_to_hdr")) {
- #ifndef MSG_SEPARATOR
- X if (!*field)
- X goto DoFrom; /* special case -- get the colon-less From line */
- #endif /* MSG_SEPARATOR */
- X field = lcase_strcpy(line, field);
- X while (*field) {
- X if (p2 = any(field, " \t,:"))
- X *p2 = 0;
- #ifndef MSG_SEPARATOR
- X if (!lcase_strncmp(field, "from_", -1))
- X goto DoFrom;
- #endif /* MSG_SEPARATOR */
- X if ((p = header_field(n, field)) || !p2)
- X break;
- X else {
- X field = p2+1;
- X while (isspace(*field) || *field == ':' || *field == ',')
- X field++;
- X }
- X }
- X if (!p)
- X print("Warning: message contains no `reply_to_hdr' headers.\n");
- X }
- X if (p || (!p && ((p = header_field(n, field = "reply-to")) ||
- X (p = header_field(n, field = "from")) ||
- X (p = header_field(n, field = "return-path")))))
- X skipspaces(0);
- X else if (!p) {
- #ifndef MSG_SEPARATOR
- DoFrom:
- X field = "from_";
- X /* if all else fails, then get the first token in "From" line */
- X if (p2 = msg_get(n, line, sizeof line))
- X p = index(p2, ' ');
- X else
- X return "";
- X skipspaces(1);
- X if (p2 = index(p, ' '))
- X *p2 = 0;
- X (void) unscramble_addr(p, line); /* p is safely recopied to line */
- X p = line;
- #else /* MSG_SEPARATOR */
- X wprint("Warning: unable to find who msg %d is from!\n", n+1);
- #endif /* MSG_SEPARATOR */
- X }
- X (void) get_name_n_addr(p, name, addr);
- X if (!name[0] && (!lcase_strncmp(field, "return-path", -1) ||
- X !lcase_strncmp(field, "from_", -1))) {
- X /*
- X * Get the name of the author of the message we're replying to from the
- X * From: header since that header contains the author's name. Only do
- X * this if the address was gotten from the return-path or from_ lines
- X * because this is the only way to guarantee that the return address
- X * matches the author's name. Reply-To: may not be the same person!
- X * Check Resent-From: if the address came from the from_ line, else
- X * check From:, and finally Sender: or Name:.
- X */
- X if (!lcase_strncmp(field, "from_", -1) &&
- X (p = header_field(n, "resent-from")) ||
- X (p = header_field(n, "from")) ||
- X (p = header_field(n, "sender")))
- X (void) get_name_n_addr(p, name, NULL);
- X if (!name[0] && (p = header_field(n, "name")))
- X (void) strcpy(name, p);
- X if (name[0]) {
- X if ((p = any(name, "(<,\"")) && (*p == ',' || *p == '<'))
- X *b++ = '"';
- X b += Strcpy(b, name);
- X if (p && (*p == ',' || *p == '<'))
- X *b++ = '"';
- X *b++ = ' ', *b++ = '<';
- X }
- X b += Strcpy(b, addr);
- X if (name[0])
- X *b++ = '>', *b = 0;
- X } else
- X b += Strcpy(buf, p);
- X
- X /*
- X * if `all' is true, append everyone on the "To:" line(s).
- X * cc_to(), called separately, will catch the cc's
- X */
- X if (all) {
- X int lim = HDRSIZ - (b - buf) - 2;
- X /* Check for overflow on each copy.
- X * The assumption that HDRSIZ is correct is unwise, but I know it
- X * to be true for Mush. Be forewarned if you call this routine.
- X */
- X if (lim > 0 && (p = header_field(n, "resent-to")) && *p) {
- X *b++ = ',', *b++ = ' ';
- X p[lim] = '\0'; /* prevent overflow */
- X b += Strcpy(b, p);
- X lim = HDRSIZ - (b - buf) - 2;
- X }
- X if (lim > 0 && (p = header_field(n, "to")) && *p) {
- X *b++ = ',', *b++ = ' ';
- X p[lim] = '\0'; /* prevent overflow */
- X b += Strcpy(b, p);
- X lim = HDRSIZ - (b - buf) - 2;
- X }
- X if (lim > 0 && (p = header_field(n, "apparently-to")) && *p) {
- X *b++ = ',', *b++ = ' ';
- X p[lim] = '\0'; /* prevent overflow */
- X b += Strcpy(b, p);
- X lim = HDRSIZ - (b - buf) - 2;
- X }
- X /* Also append the Resent-From address if there is one. */
- X if (lim > 0 && (p = header_field(n, "resent-from")) && *p) {
- SHAR_EOF
- true || echo 'restore of hdrs.c failed'
- fi
- echo 'End of part 9'
- echo 'File hdrs.c is continued in part 10'
- echo 10 > _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.
-