home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume18 / mush / part09 < prev    next >
Internet Message Format  |  1991-04-22  |  51KB

  1. From: argv@zipcode.com (Dan Heller)
  2. Newsgroups: comp.sources.misc
  3. Subject: v18i066:  mush - Mail User's Shell, Part09/22
  4. Message-ID: <1991Apr22.000206.18669@sparky.IMD.Sterling.COM>
  5. Date: 22 Apr 91 00:02:06 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: ef1e24ca b89364a3 9c0f9304 5cef0d36
  8.  
  9. Submitted-by: Dan Heller <argv@zipcode.com>
  10. Posting-number: Volume 18, Issue 66
  11. Archive-name: mush/part09
  12. Supersedes: mush: Volume 12, Issue 28-47
  13.  
  14. #!/bin/sh
  15. # this is Part.09 (part 9 of a multipart archive)
  16. # do not concatenate these parts, unpack them in order with /bin/sh
  17. # file glob.c continued
  18. #
  19. if test ! -r _shar_seq_.tmp; then
  20.     echo 'Please unpack part 1 first!'
  21.     exit 1
  22. fi
  23. (read Scheck
  24.  if test "$Scheck" != 9; then
  25.     echo Please unpack part "$Scheck" next!
  26.     exit 1
  27.  else
  28.     exit 0
  29.  fi
  30. ) < _shar_seq_.tmp || exit 1
  31. if test ! -f _shar_wnt_.tmp; then
  32.     echo 'x - still skipping glob.c'
  33. else
  34. echo 'x - continuing file glob.c'
  35. sed 's/^X//' << 'SHAR_EOF' >> 'glob.c' &&
  36. X        if (!*pat || *pat == ']' || *pat == '\\' && !*++pat) {
  37. X            done = TRUE;
  38. X            break;
  39. X        }
  40. X        /* Check for a range. */
  41. X        if (*(pat + 1) == '-') {
  42. X            char c = *pat++;
  43. X            /* We don't handle open-ended ranges. */
  44. X            if (*++pat == ']' || *pat == '\\' && !*++pat) {
  45. X            done = TRUE;
  46. X            break;
  47. X            }
  48. X            if (*str < c || *str > *pat) {
  49. X            pat++;
  50. X            goto repeat;
  51. X            }
  52. X        } else if (*pat != *str) {
  53. X            pat++;
  54. X            goto repeat;
  55. X        }
  56. X        /*
  57. X         * We matched either the range or a literal member of
  58. X         * the set.  Skip to the end of the set.
  59. X         */
  60. X        pat++;
  61. X        while (*pat && *pat != ']')
  62. X            if (*pat++ == '\\' && *pat)
  63. X            pat++;
  64. X        /*
  65. X         * If no pattern remains, the set was never closed,
  66. X         * so don't increment.  This will cause a FALSE return.
  67. X         */
  68. X        if (*pat) {
  69. X            pat++;
  70. X            str++;
  71. X        }
  72. X        break;
  73. X        case '?':    /* Match any one character */
  74. X        str++;
  75. X        break;
  76. X        case '{':    /* } Match any of a set of patterns */
  77. X        return sglob(str, pat - 1, TRPL_NULL);
  78. X        break;
  79. X        default:
  80. X        done = TRUE;
  81. X    }
  82. X    }
  83. X    while (*pat == '*')
  84. X    pat++;
  85. X    return ((*str == '\0') && (*pat == '\0'));
  86. }
  87. X
  88. /*
  89. X * Match a pattern set {s1,s2,...} followed by any other pattern.
  90. X * Pattern sets and other patterns may nest arbitrarily.
  91. X *
  92. X * If "mat" is not a null pointer, a vector of possible expansions
  93. X * is generated and placed in *mat; otherwise, the expansions are
  94. X * matched against str and a truth value is returned ("/" is NOT
  95. X * treated as a directory separator in this case).  NOTE: The vector
  96. X * of expansions may still contain nested pattern sets, which must
  97. X * be expanded separately.  See sxp().
  98. X *
  99. X * Currently allows at most 256 alternatives per set.  Enough? :-)
  100. X */
  101. static
  102. sglob(str, pat, mat)
  103. char *str, *pat, ***mat;
  104. {
  105. X    char *p, *newpat[256], *oldpat[256], buf[MAXPATHLEN], *b = buf;
  106. X    int copy = 1, nest = 0, i = 0, ret = 0;
  107. X
  108. X    if (!pat)
  109. X    return FALSE;
  110. X
  111. X    while (*pat) {
  112. X    if (copy)
  113. X        if (*pat != '{') /*}*/ {
  114. X        if (*pat == '\\' && pat[1])
  115. X            *b++ = *pat++;
  116. X        *b++ = *pat++;
  117. X        continue;
  118. X        } else {
  119. X        copy = 0;
  120. X        pat++;
  121. X        }
  122. X    p = pat;
  123. X    while (*pat && (nest || *pat != ',' && /*{*/ *pat != '}')) {
  124. X        if (*pat == '\\')
  125. X        pat++;
  126. X        else if (*pat == '{')
  127. X        nest++;
  128. X        else if (*pat == '}')
  129. X        nest--;
  130. X        if (*pat)
  131. X        pat++;
  132. X    }
  133. X    if (*pat) {
  134. X        oldpat[i] = pat;
  135. X        newpat[i++] = p;
  136. X        if (*pat != ',') {
  137. X        *pat++ = 0;
  138. X        break;
  139. X        } else
  140. X        *pat++ = 0;
  141. X    }
  142. X    }
  143. X    oldpat[i] = NULL;
  144. X    if (i > 0 && mat) {
  145. X    *mat = (char **)malloc((unsigned)((i + 1) * sizeof(char *)));
  146. X    if (*mat)
  147. X        (*mat)[i] = NULL;
  148. X    else
  149. X        return -1;
  150. X    ret = i;
  151. X    }
  152. X    while (!mat && i-- > 0)
  153. X    if (ret = glob2(str, newpat[i], pat))
  154. X        break;
  155. X    for (i = 0; oldpat[i]; i++) {
  156. X    if (mat && *mat) {
  157. X        (void) sprintf(b, "%s%s", newpat[i], pat);
  158. X        (*mat)[i] = savestr(buf);
  159. X    }
  160. X    if (oldpat[i + 1])
  161. X        oldpat[i][0] = ',';
  162. X    else
  163. X        oldpat[i][0] = /*{*/ '}';
  164. X    }
  165. X    if (ret == 0 && b > buf && mat) {
  166. X    *b = 0;
  167. X    ret = ((*mat = unitv(buf)) ? 1 : -1);
  168. X    }
  169. X    return ret;
  170. }
  171. X
  172. /*
  173. X * Pre-expand pattern set notations so sets containing "/" separators
  174. X * can be globbed successfully.  Returns the number of expansions.
  175. X */
  176. sxp(pat, exp)
  177. char *pat, ***exp;
  178. {
  179. X    char **t1 = DUBL_NULL, **t2;
  180. X    int n, new, cnt = 0;
  181. X
  182. X    if ((n = sglob(NULL, pat, &t1)) < 2) {
  183. X    *exp = t1;
  184. X    return n;
  185. X    }
  186. X    *exp = DUBL_NULL;
  187. X    while (n-- && cnt >= 0) {
  188. X    new = sxp(t1[n], &t2);
  189. X    cnt = catv(cnt, exp, new, t2);
  190. X    }
  191. X    xfree(t1);
  192. X    return cnt;
  193. }
  194. X
  195. /*
  196. X * Generate the "glob difference" of two vectors (*argvp and patv).
  197. X * The "glob difference" means to remove all strings from argv that
  198. X * match any of the glob patterns in patv.
  199. X *
  200. X * Returns the number of strings remaining in *argvp.  The strings "removed"
  201. X * from argv are actually left at the end of *argvp, so they can still be
  202. X * accessed; their number will of course be argc - (returned value).
  203. X */
  204. gdiffv(argc, argvp, patc, patv)
  205. int argc, patc;
  206. char ***argvp, **patv;
  207. {
  208. X    char **argv, *t;
  209. X    int ac, pc, oldac = argc;
  210. X
  211. X    if (argc < 1 || patc < 1 || !patv || !*patv)
  212. X    return argc;
  213. X    if (!argvp || !(argv = *argvp) || !*argv)
  214. X    return -1;
  215. X    for (ac = 0; ac < argc && argv[ac]; ac++) {
  216. X    for (pc = 0; ac < argc && pc < patc && patv[pc]; pc++) {
  217. X        /*
  218. X         * We shouldn't cross '/' characters, so test
  219. X         * only the "tail" of each element of argv.
  220. X         */
  221. X        if (!(t = rindex(argv[ac], '/')))
  222. X            t = argv[ac];
  223. X        if (glob(t, patv[pc])) {
  224. X        /* Move matches to the end and reduce argc */
  225. X        t = argv[ac];
  226. X        argv[ac] = argv[--argc];
  227. X        argv[argc] = t;
  228. X        /* Start patterns over on the new string */
  229. X        pc = -1; /* It'll be incremented to 0 */
  230. X        }
  231. X    }
  232. X    }
  233. X    /*
  234. X     * Sort the two parts of the argv.  uniqcmp() works here only if
  235. X     * there already are no duplicates, but we assume that for now.
  236. X     */
  237. X    if (argc)
  238. X    qsort((char *)argv, argc, sizeof(char *), uniqcmp);
  239. X    if (oldac > argc)
  240. X    qsort((char *)&argv[argc], oldac - argc, sizeof(char *), uniqcmp);
  241. X    return argc;
  242. }
  243. X
  244. /*
  245. X * Generate the longest common prefix from all strings in a vector
  246. X * If "skip" is nonzero, that many chars are assumed to be in common
  247. X * and are not tested.  WARNING: skip must be <= than the length of
  248. X * the shortest string in the vector!  Safest to call with skip = 0.
  249. X *
  250. X * Returns the length of the longest common prefix.
  251. X */
  252. lcprefix(vec, skip)
  253. char **vec;
  254. int skip;
  255. {
  256. X    char c, **v;
  257. X    int done = FALSE;
  258. X
  259. X    if (!vec || !*vec || skip < 0)
  260. X    return 0;
  261. X    do {
  262. X    for (v = vec + 1, c = vec[0][skip]; c && *v; v++)
  263. X        if (v[0][skip] != c) {
  264. X        done = TRUE;
  265. X        break;
  266. X        }
  267. X    } while (!done && c && ++skip);
  268. X    return skip;
  269. }
  270. X
  271. #define MAXCOLS 8    /* Max number of columns of words to make */
  272. #define MINWIDTH 10    /* Minimum width of each column of words */
  273. #ifdef CURSES
  274. #define MAXWIDTH (iscurses? COLS : 80)
  275. #else /* CURSES */
  276. #define MAXWIDTH 80    /* Maximum width of all columns */
  277. #endif /* CURSES */
  278. X
  279. /*
  280. X * Print a vector in columns
  281. X *
  282. X * If "skip" is nonzero, that many chars are assumed to be in common
  283. X * and are not printed.  WARNING: skip must be <= than the length of
  284. X * the shortest string in the vector!  Safest to call with skip = 0.
  285. X */
  286. columnate(argc, argv, skip)
  287. int argc;
  288. char **argv;
  289. int skip;
  290. {
  291. X    int colstep, colwidth[MAXCOLS + 1];
  292. X    int maxcols = min(argc, MAXCOLS);
  293. X    int minwidth, maxwidth, *widths;
  294. X    int maxword = 0, n, c;
  295. X
  296. X    if (argc <= 0 || !argv || !*argv)
  297. X    return -1;
  298. X    if (!(widths = (int *)malloc((unsigned)((argc + 1) * sizeof(int)))))
  299. X    return -1;
  300. X
  301. X    /*
  302. X     * Compute the widths of all words in the vector, and
  303. X     * remember the maximum width and which word had it.
  304. X     * Also remember the minimum width.
  305. X     */
  306. X    for (minwidth = MAXWIDTH, maxwidth = n = 0; n < argc; n++) {
  307. X    widths[n] = max(strlen(argv[n] + skip) + 2, MINWIDTH);
  308. X    if (widths[n] > MAXWIDTH - MINWIDTH)
  309. X        break;
  310. X    if (widths[n] > maxwidth) {
  311. X        maxwidth = widths[n];
  312. X        maxword = n;
  313. X    } 
  314. X    if (widths[n] < minwidth)
  315. X        minwidth = widths[n];
  316. X    }
  317. X
  318. X    for (; maxcols > 0; maxcols--) {
  319. X    if (argc % maxcols)
  320. X        colstep = argc / maxcols + 1;
  321. X    else
  322. X        colstep = argc / maxcols;
  323. X    colwidth[MAXCOLS] = 0;
  324. X    for (c = 0; c < maxcols; c++) {
  325. X        colwidth[c] = 0;
  326. X        for (n = c * colstep; n < (c + 1) * colstep && n < argc; n++)
  327. X        colwidth[c] = max(colwidth[c], widths[n]);
  328. X        colwidth[MAXCOLS] += colwidth[c];
  329. X    }
  330. X    if (colwidth[MAXCOLS] <= MAXWIDTH)
  331. X        break;
  332. X    }
  333. X    xfree(widths);
  334. X
  335. X    if (maxcols < 2 && minwidth <= MAXWIDTH / 2) {
  336. X    /*
  337. X     * The maxword fills too much screen, so redo everything
  338. X     * above it, print maxword, then do everything below it.
  339. X     */
  340. X    if (maxword > 0 && columnate(maxword, argv, skip) < 0)
  341. X        return -1;
  342. X    wprint("%s\n", argv[maxword] + skip);
  343. X    if (argc - maxword < 2)
  344. X        return 0;
  345. X    return columnate(argc - maxword - 1, &argv[maxword + 1], skip);
  346. X    }
  347. X
  348. X    for (n = 0; n < colstep; n++) {
  349. X    for (c = 0; c < maxcols && n + c * colstep < argc - colstep; c++)
  350. X        wprint("%-*.*s", colwidth[c], colwidth[c],
  351. X                        argv[n + c * colstep] + skip);
  352. X    wprint("%s\n", argv[n + c * colstep] + skip);
  353. X    }
  354. X
  355. X    return 0;
  356. }
  357. X
  358. #ifndef DIRECTORY
  359. X
  360. #undef NULL
  361. #define NULL 0
  362. X
  363. /*
  364. X *  4.2BSD directory access emulation for non-4.2 systems.
  365. X *  Based upon routines in appendix D of Portable C and Unix System
  366. X *  Programming by J. E. Lapin (Rabbit Software).
  367. X *
  368. X *  No responsibility is taken for any error in accuracies inherent
  369. X *  either to the comments or the code of this program, but if
  370. X *  reported to me then an attempt will be made to fix them.
  371. X */
  372. X
  373. /*  Support for Berkeley directory reading routines on a V7/SysV file
  374. X *  system.
  375. X */
  376. X
  377. /*  Open a directory. */
  378. X
  379. DIR *
  380. opendir(name)
  381. char *name ;
  382. {
  383. X  register DIR *dirp ;
  384. X  register int fd ;
  385. X
  386. X  if ((fd = open(name, 0)) == -1) return NULL ;
  387. X  if ((dirp = (DIR *) malloc(sizeof(DIR))) == NULL)
  388. X    {
  389. X      close(fd) ;
  390. X      return NULL ;
  391. X    }
  392. X  dirp->dd_fd = fd ;
  393. X  dirp->dd_loc = 0 ;
  394. X  return dirp ;
  395. }
  396. X
  397. X
  398. /*  Read an old style directory entry and present it as a new one. */
  399. X
  400. #define  ODIRSIZ  14
  401. X
  402. struct olddirent
  403. {
  404. X  short  od_ino ;
  405. X  char   od_name[ODIRSIZ] ;
  406. } ;
  407. X
  408. X
  409. /*  Get next entry in a directory. */
  410. X
  411. struct dirent *
  412. readdir(dirp)
  413. register DIR *dirp ;
  414. {
  415. X  register struct olddirent *dp ;
  416. X  static struct dirent dir ;
  417. X
  418. X  for (;;)
  419. X    {
  420. X      if (dirp->dd_loc == 0)
  421. X        {
  422. X          dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ) ;
  423. X          if (dirp->dd_size <= 0) return NULL ;
  424. X        }
  425. X      if (dirp->dd_loc >= dirp->dd_size)
  426. X        {
  427. X          dirp->dd_loc = 0 ;
  428. X          continue ;
  429. X        }
  430. X
  431. X      dp = (struct olddirent *)(dirp->dd_buf + dirp->dd_loc) ;
  432. X      dirp->dd_loc += sizeof(struct olddirent) ;
  433. X
  434. X      if (dp->od_ino == 0) continue ;
  435. X
  436. X      dir.d_fileno = dp->od_ino ;
  437. X      strncpy(dir.d_name, dp->od_name, ODIRSIZ) ;
  438. X      dir.d_name[ODIRSIZ] = '\0' ;       /* Ensure termination. */
  439. X      dir.d_namlen = strlen(dir.d_name) ;
  440. X      dir.d_reclen = DIRSIZ(&dir) ;
  441. X      return(&dir) ;
  442. X    }
  443. }
  444. X
  445. X
  446. /*  Close a directory. */
  447. X
  448. void
  449. closedir(dirp)
  450. register DIR *dirp ;
  451. {
  452. X  close(dirp->dd_fd) ;
  453. X  dirp->dd_fd = -1 ;
  454. X  dirp->dd_loc = 0 ;
  455. X  xfree(dirp) ;
  456. X
  457. #endif /* DIRECTORY */
  458. SHAR_EOF
  459. echo 'File glob.c is complete' &&
  460. chmod 0644 glob.c ||
  461. echo 'restore of glob.c failed'
  462. Wc_c="`wc -c < 'glob.c'`"
  463. test 19617 -eq "$Wc_c" ||
  464.     echo 'glob.c: original size 19617, current size' "$Wc_c"
  465. rm -f _shar_wnt_.tmp
  466. fi
  467. # ============= glob.h ==============
  468. if test -f 'glob.h' -a X"$1" != X"-c"; then
  469.     echo 'x - skipping glob.h (File already exists)'
  470.     rm -f _shar_wnt_.tmp
  471. else
  472. > _shar_wnt_.tmp
  473. echo 'x - extracting glob.h (Text)'
  474. sed 's/^X//' << 'SHAR_EOF' > 'glob.h' &&
  475. #ifdef BSD
  476. #define DIRECTORY
  477. #endif /* BSD */
  478. X
  479. #ifdef DIRECTORY
  480. #ifdef SYSV /* Some SysV 3.0 or higher */
  481. #include <dirent.h>
  482. #else /* SYSV */
  483. #include <sys/dir.h>
  484. #define dirent direct
  485. #endif
  486. #else /* !DIRECTORY */
  487. X
  488. /*
  489. X *  4.2BSD directory access emulation for non-4.2 systems.
  490. X *  Based upon routines in appendix D of Portable C and Unix System
  491. X *  Programming by J. E. Lapin (Rabbit Software).
  492. X *
  493. X *  No responsibility is taken for any error in accuracies inherent
  494. X *  either to the comments or the code of this program, but if
  495. X *  reported to me then an attempt will be made to fix them.
  496. X */
  497. X
  498. #ifndef  DEV_BSIZE
  499. #define  DEV_BSIZE  512           /* Device block size. */
  500. #endif
  501. X
  502. #define  DIRBLKSIZ  DEV_BSIZE
  503. #define  MAXNAMLEN  255           /* Name must be no longer than this. */
  504. X
  505. struct dirent
  506. {
  507. X  long  d_fileno ;                /* Inode number of entry. */
  508. X  short d_reclen ;                /* Length of this record. */
  509. X  short d_namlen ;                /* Length of d_name string. */
  510. X  char  d_name[MAXNAMLEN + 1] ;   /* Directory name. */
  511. } ;
  512. X
  513. /*  The DIRSIZ macro gives the minimum record length that will hold the
  514. X *  directory entry. This requires the amount of space in struct direct
  515. X *  without the d_name field, plus enough space for the name with a
  516. X *  terminating null byte (dp->d_namlen+1), rounded up to a 4 byte
  517. X *  boundary.
  518. X */
  519. X
  520. #undef   DIRSIZ
  521. #define  DIRSIZ(dp)                                \
  522. X         ((sizeof (struct dirent) - (MAXNAMLEN+1)) \
  523. X         + (((dp)->d_namlen+1 + 3) &~ 3))
  524. X
  525. /*  Definitions for library routines operating on directories. */
  526. X
  527. typedef struct _dirdesc
  528. {
  529. X  int    dd_fd ;
  530. X  long   dd_loc ;
  531. X  long   dd_size ;
  532. X  char   dd_buf[DIRBLKSIZ] ;
  533. } DIR ;
  534. X
  535. #ifndef  NULL
  536. #define  NULL  0
  537. #endif
  538. X
  539. extern  DIR              *opendir() ;
  540. extern  struct dirent    *readdir() ;
  541. extern  long             telldir() ;
  542. extern  void             seekdir() ;
  543. #define rewinddir(dirp)  seekdir((dirp), (long) 0)
  544. extern  void             closedir() ;
  545. X
  546. #endif /* DIRECTORY */
  547. X
  548. #define DELIM " \t;|"
  549. #define META "/?*[{"
  550. #define FMETA "?*[{"
  551. SHAR_EOF
  552. chmod 0644 glob.h ||
  553. echo 'restore of glob.h failed'
  554. Wc_c="`wc -c < 'glob.h'`"
  555. test 2071 -eq "$Wc_c" ||
  556.     echo 'glob.h: original size 2071, current size' "$Wc_c"
  557. rm -f _shar_wnt_.tmp
  558. fi
  559. # ============= hdr_sw.c ==============
  560. if test -f 'hdr_sw.c' -a X"$1" != X"-c"; then
  561.     echo 'x - skipping hdr_sw.c (File already exists)'
  562.     rm -f _shar_wnt_.tmp
  563. else
  564. > _shar_wnt_.tmp
  565. echo 'x - extracting hdr_sw.c (Text)'
  566. sed 's/^X//' << 'SHAR_EOF' > 'hdr_sw.c' &&
  567. /* @(#)hdr_sw.c    (c) copyright    2/17/90 (Dan Heller) */
  568. X
  569. /* This file handles all the header subwindow code.  It would be much
  570. X * better if this subwindow, which displays the headers for the current
  571. X * folder, were a textsw.  That way, this file would go away completely.
  572. X * Until then, we have to create the window (canvas), define an event
  573. X * handler for when events happen in this window, create our own scrollbar,
  574. X * figure out when the user scrolls with it, attach our own popup menu to
  575. X * the canvas, handle events for that, let's see... kitchen sink?  Oh,
  576. X * that's over there in the corner.
  577. X */
  578. #include "mush.h"
  579. #ifdef SUN_4_0 /* SunOS 4.0+ */
  580. #include <sunwindow/win_keymap.h>
  581. #endif /* SUN_4_0 */
  582. X
  583. extern Panel hdr_panel;
  584. extern void hdr_io(), fkey_interposer();
  585. X
  586. static Notify_value scroll_hdr();
  587. static void msg_menu_func(), do_menu(), msg_menu_notify();
  588. Menu msg_menu;
  589. X
  590. void
  591. make_hdr_sw(parent)
  592. Frame parent;
  593. {
  594. X    Textsw tmpsw;
  595. X
  596. X    if (!(hdr_sw = window_create(parent, CANVAS,
  597. X    WIN_HEIGHT,        10 + screen*l_height(),
  598. X    WIN_WIDTH,        WIN_EXTEND_TO_EDGE,
  599. X    WIN_BELOW,        hdr_panel,
  600. X    WIN_EVENT_PROC,        hdr_io,
  601. X    CANVAS_AUTO_CLEAR,    TRUE,
  602. X    CANVAS_RETAINED,    TRUE,
  603. X    WIN_CONSUME_KBD_EVENTS,
  604. X        WIN_ASCII_EVENTS, WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, NULL,
  605. X    WIN_IGNORE_KBD_EVENTS,
  606. X        WIN_UP_ASCII_EVENTS, NULL,
  607. X    WIN_CONSUME_PICK_EVENTS,
  608. X        LOC_WINENTER, WIN_MOUSE_BUTTONS, LOC_MOVE, NULL,
  609. X    WIN_VERTICAL_SCROLLBAR, scrollbar_create(0),
  610. X    NULL)))
  611. X    perror("hdr_sw"), cleanup(0);
  612. X    hdr_win = canvas_pixwin(hdr_sw);
  613. X    (void) notify_interpose_event_func(hdr_sw, fkey_interposer, NOTIFY_SAFE);
  614. X    (void) notify_interpose_event_func(hdr_sw, scroll_hdr, NOTIFY_SAFE);
  615. X    scrollbar_set((Scrollbar)window_get(hdr_sw, WIN_VERTICAL_SCROLLBAR),
  616. X    SCROLL_NORMALIZE,    FALSE,
  617. X    SCROLL_ADVANCED_MODE,    TRUE,
  618. X    SCROLL_LINE_HEIGHT,    l_height(),
  619. X    SCROLL_VIEW_LENGTH,    screen,
  620. X    NULL);
  621. #ifdef SUN_4_0 /* SunOS 4.0+ */
  622. X    /* This is a particularly ugly hack.  If Sun only documented the correct
  623. X     * way to set up the key mapping for a window the way that textsw's do
  624. X     * then we wouldn't have to do anything this awful.  Maybe in 4.2.....
  625. X     *
  626. X     * The object here is to get the same translation table for our header
  627. X     * canvas as for a textsw (more or less anyway).  This way the arrow
  628. X     * keys and such work right.
  629. X     */
  630. X    tmpsw = window_create(parent, TEXTSW, NULL);
  631. #ifdef SUN_4_1
  632. X    keymap_from_fd[(int)window_get(hdr_sw, WIN_FD)].keymap =
  633. X    keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].keymap;
  634. X    keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].keymap = (Keymap *) 0;
  635. #else /* !SUN_4_1 */
  636. X    keymap_from_fd[(int)window_get(hdr_sw, WIN_FD)].kf_keymap =
  637. X    keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].kf_keymap;
  638. X    keymap_from_fd[(int)window_get(tmpsw, WIN_FD)].kf_keymap = (Keymap *) 0;
  639. #endif /* SUN_4_1 */
  640. X    (void) window_destroy(tmpsw);
  641. #endif /* SUN_4_0 */
  642. }
  643. X
  644. static Notify_value
  645. scroll_hdr(canvas, event, arg, type)
  646. Canvas    canvas;
  647. Event    *event;
  648. Notify_arg    arg;
  649. Notify_event_type    type;
  650. {
  651. X    int amount, count, i;
  652. X    int show_deleted = !!do_set(set_options, "show_deleted");
  653. X    char *argv[3], msgnum[8];
  654. X    Scrollbar sb;
  655. X    argv[0] = "headers";
  656. X    argv[1] = msgnum;
  657. X    argv[2] = NULL;
  658. X
  659. X    switch (decode_scroll((Notify_client) canvas, event, screen, &amount)) {
  660. X    case MUSH_SCROLL_PASS_EVENT:
  661. X        switch(ID) {
  662. X        case SCROLL_ENTER:
  663. X        case SCROLL_EXIT:
  664. X            return NOTIFY_IGNORED;
  665. X        case SCROLL_REQUEST:
  666. X            sb = (Scrollbar)arg;
  667. X            switch( (Scroll_motion)
  668. X             scrollbar_get(sb, SCROLL_REQUEST_MOTION)) {
  669. X            case SCROLL_LINE_FORWARD:
  670. X                amount = 1;
  671. X                break;
  672. X            case SCROLL_LINE_BACKWARD:
  673. X                amount = -1;
  674. X                break;
  675. X            case SCROLL_ABSOLUTE:
  676. X                i = (int)scrollbar_get(sb, SCROLL_VIEW_START);
  677. X                if (!show_deleted) {
  678. X                count = i;
  679. X                for (i = 0; i < msg_cnt-1; i++)
  680. X                        if (!ison(msg[i].m_flags, DELETE) &&
  681. X                        count-- == 0)
  682. X                    break;
  683. X                }
  684. X                (void) sprintf(msgnum, "%d", i+1);
  685. X                argv[1] = msgnum;
  686. X                (void) do_hdrs(2, argv, NULL);
  687. X                return(NOTIFY_DONE);
  688. X            default:
  689. X                amount =
  690. X                (int)scrollbar_get(sb, SCROLL_VIEW_START) -
  691. X                (int)scrollbar_get(sb, SCROLL_LAST_VIEW_START);
  692. X                break;
  693. X            }
  694. X            break;
  695. X        default:
  696. X            return notify_next_event_func(canvas, event, arg, type);
  697. X        }
  698. X        break;
  699. X    case MUSH_SCROLL_IGNORE:
  700. X        return NOTIFY_IGNORED;
  701. X    case MUSH_SCROLL_TO:
  702. X        if (amount == 1) {
  703. X        argv[1] = "1";
  704. X        (void) do_hdrs(2, argv, NULL);
  705. X        return NOTIFY_DONE;
  706. X        } else {
  707. X        (void) sprintf(msgnum, "%d", msg_cnt - screen + 1);
  708. X        argv[1] = msgnum;
  709. X        (void) do_hdrs(2, argv, NULL);
  710. X        return NOTIFY_DONE;
  711. X        }
  712. X    }
  713. X    if (amount == screen)
  714. X    argv[1] = "+";
  715. X    else if (amount == -screen)
  716. X    argv[1] = "-";
  717. X    else if (amount >= 0) {
  718. X    if (amount < screen)
  719. X        (void) sprintf(msgnum, "%d", min(n_array[amount]+1, msg_cnt-1));
  720. X    else {
  721. X        /* so much for layering */
  722. X        for (i = n_array[0]+1; i < msg_cnt-1 && amount > 0; i++)
  723. X        if (show_deleted || !ison(msg[i].m_flags, DELETE))
  724. X            amount--;
  725. X        (void) sprintf(msgnum, "%d", i);
  726. X    }
  727. X    } else {
  728. X    /* so much for layering */
  729. X    for (i = n_array[0]; i > 0 && amount < 0; i--)
  730. X        if (show_deleted || !ison(msg[i-1].m_flags, DELETE))
  731. X        amount++;
  732. X    (void) sprintf(msgnum, "%d", i + 1);
  733. X    }
  734. X    (void) do_hdrs(2, argv, NULL);
  735. X    return NOTIFY_DONE;
  736. }
  737. X
  738. /*
  739. X * Routines to handle io on the hdr_sw (canvas).
  740. X */
  741. X
  742. /* if MENU button goes down on a hdr, drawbox around hdr and popup menu */
  743. #define draw(x1,y1,x2,y2) (void) pw_vector(hdr_win, x1,y1,x2,y2,PIX_XOR,1)
  744. #define box(x1,y1,x2,y2)  \
  745. X    draw(x1,y1, x1,y2), draw(x1,y2, x2,y2), \
  746. X    draw(x2,y2, x2,y1), draw(x2,y1, x1,y1)
  747. X
  748. #define READ_MSG    (char *)'r'
  749. #define DEL_MSG        (char *)'d'
  750. #define UNDEL_MSG    (char *)'u'
  751. #define REPL_MSG    (char *)'R'
  752. #define SAVE_MSG    (char *)'s'
  753. #define PRNT_MSG    (char *)'p'
  754. #define PRE_MSG        (char *)'P'
  755. #define MARK_MSG    (char *)'m'
  756. #define HELP_MSG    (char *)'H'
  757. X
  758. #define MARK_TOGGLE    (char *)'T'
  759. #define MARK_A        (char *)'A'
  760. #define MARK_B        (char *)'B'
  761. #define MARK_C        (char *)'C'
  762. #define MARK_D        (char *)'D'
  763. #define MARK_E        (char *)'E'
  764. #define MARK_CLEAR    (char *)'c'
  765. #define MARK_HELP    (char *)'h'
  766. X
  767. /*ARGSUSED*/
  768. void
  769. hdr_io(canvas, event, arg)
  770. Canvas canvas;
  771. Event *event;
  772. caddr_t arg;
  773. {
  774. X    static int    which_cursor;
  775. X    int     line;
  776. X
  777. X    if (ID == WIN_REPAINT) {
  778. X    if (is_iconic != (int) window_get(tool, FRAME_CLOSED)) {
  779. X        check_new_mail();
  780. X
  781. X        /*  Reload time with value of timeout upon timer expiration. */
  782. X        mail_timer.it_interval.tv_sec = time_out;
  783. X
  784. X        mail_timer.it_value.tv_sec = time_out;
  785. X        (void) notify_set_itimer_func(tool, do_check,
  786. X        ITIMER_REAL, &mail_timer, (struct itimerval *) 0);
  787. X        is_iconic = 0;
  788. X    }
  789. X    }
  790. X
  791. X    /* make cursor change which button is lit */
  792. X    switch (which_cursor) {
  793. X    case 0 : (void) window_set(canvas, WIN_CURSOR, l_cursor, NULL);
  794. X    when 1 : (void) window_set(canvas, WIN_CURSOR, m_cursor, NULL);
  795. X    when 2 : (void) window_set(canvas, WIN_CURSOR, r_cursor, NULL);
  796. X    }
  797. X
  798. X    which_cursor = (which_cursor+1) % 3;
  799. X
  800. X    /* just return -- we just wanted to make the cursor flicker */
  801. X    if (ID == LOC_STILL || ID == LOC_MOVE || ID == LOC_WINENTER ||
  802. X    ID == LOC_RGNENTER || ID == KBD_USE || ID == KBD_DONE)
  803. X    return;
  804. X
  805. X    if (event_is_button(event) && event_is_down(event)) {
  806. X    line = (event_y(event) - 5) / l_height();
  807. X    if (line < 0)
  808. X        line = 0;
  809. X    else if (line >= screen)
  810. X        line = screen - 1;
  811. X    if (!msg_cnt || n_array[line] > msg_cnt)
  812. X        return;
  813. X    if (ID == MS_RIGHT)
  814. X        do_menu(hdr_sw, event, window_get(hdr_sw, WIN_FD), n_array[line]);
  815. X    else if (ID == MS_MIDDLE) {
  816. X        set_isread(n_array[line]);
  817. X        msg_menu_func((int)DEL_MSG, n_array[line]);
  818. X    } else {
  819. X        int do_do_hdrs = 0;
  820. X        if (current_msg != n_array[line]) {
  821. X        current_msg = n_array[line];
  822. X        do_do_hdrs++;
  823. X        }
  824. X        if (ison(msg[current_msg].m_flags, UNREAD))
  825. X        do_do_hdrs++;
  826. X        (void) display_msg(n_array[line], (u_long)0);
  827. X        if (do_do_hdrs)
  828. X        (void) do_hdrs(0, DUBL_NULL, NULL);
  829. X    }
  830. X    } else
  831. X    window_default_event_proc(canvas, event, NULL);
  832. }
  833. X
  834. static struct menu_rec {
  835. X    char *str;    /* Menu item label. */
  836. X    char *data;    /* Menu item client data. */
  837. };
  838. X
  839. void
  840. get_msg_menu()
  841. {
  842. X    int i;
  843. X    Menu_item mi = NULL, sub_mi;
  844. X
  845. X    static struct menu_rec msg_items[] = {
  846. X    { "Read",            READ_MSG  },
  847. X    { "Delete",          DEL_MSG   },
  848. X    { "Undelete",        UNDEL_MSG },
  849. X    { "Reply",           REPL_MSG  },
  850. X    { "Save",            SAVE_MSG  },
  851. X    { "Preserve",        PRE_MSG   },
  852. X    { "Mark",         MARK_MSG  },
  853. X    { "Print",           PRNT_MSG  },
  854. X    { "Help",            HELP_MSG  },
  855. X    };
  856. X    static struct menu_rec mark_msg_items[] = {
  857. X    { "Toggle Mark",    MARK_TOGGLE},
  858. X    { "Priority A",     MARK_A     },
  859. X    { "Priority B",     MARK_B     },
  860. X    { "Priority C",     MARK_C     },
  861. X    { "Priority D",     MARK_D     },
  862. X    { "Priority E",     MARK_E     },
  863. X    { "Clear Priority", MARK_CLEAR },
  864. X    { "Help",           MARK_HELP  },
  865. X    };
  866. X
  867. X    msg_menu = menu_create(MENU_NOTIFY_PROC, menu_return_item, NULL);
  868. X    for (i = 0; i < ArraySize(msg_items); i++) {
  869. X    mi = menu_create_item(MENU_STRING,    msg_items[i].str,
  870. X                  MENU_CLIENT_DATA,    msg_items[i].data,
  871. X                  NULL);
  872. X    if (msg_items[i].data == MARK_MSG) {
  873. X        int j;
  874. X        /* get the menu from <Mark> and set as this item's pullright */
  875. X        Menu the_menu = menu_create(
  876. X        MENU_NOTIFY_PROC, menu_return_item, NULL);
  877. X        for (j = 0; j < ArraySize(mark_msg_items); j++) {
  878. X        sub_mi = menu_create_item(
  879. X            MENU_STRING,    mark_msg_items[j].str,
  880. X            MENU_CLIENT_DATA,    mark_msg_items[j].data,
  881. X            NULL);
  882. X        (void) menu_set(the_menu, MENU_APPEND_ITEM, sub_mi, NULL);
  883. X        }
  884. X        menu_set(mi, MENU_PULLRIGHT, the_menu, NULL);
  885. X    }
  886. X    (void) menu_set(msg_menu, MENU_APPEND_ITEM, mi, NULL);
  887. X    }
  888. }
  889. X
  890. static void
  891. do_menu(can_sw, event, fd, message)
  892. Canvas can_sw;
  893. Event *event;
  894. int fd, message;
  895. {
  896. X    char *action;
  897. X    char *save_place;
  898. X    Menu_item cur_msg_item;
  899. X    static char buf[16];
  900. X
  901. X    if (!msg_cnt) {
  902. X    wprint("No Messages.\n");
  903. X    return;
  904. X    }
  905. X    if (fd) {
  906. X    int line;
  907. X    Rect *hdr_rect;
  908. X    extern Menu hdr_save_menu;
  909. X
  910. X    if (!msg_menu)
  911. X        get_msg_menu();
  912. X    (void) sprintf(buf, "Message #%d", message+1);
  913. X    /* provide feedback about what message the menu references */
  914. X    for (line = 0; line <= n_array[screen-1]; line++)
  915. X        if (n_array[line] == message)
  916. X        break;
  917. X    hdr_rect = (Rect *)window_get(hdr_sw, WIN_RECT);
  918. X    box(0, 5 + line * l_height(),
  919. X        hdr_rect->r_width, 5 + (line+1) * l_height());
  920. X    /* show menu */
  921. X    cur_msg_item = menu_show(msg_menu, can_sw, event, NULL);
  922. X    /* remove feedback */
  923. X    box(0, 5 + line * l_height(),
  924. X        hdr_rect->r_width, 5 + (line+1) * l_height());
  925. X    /* if user selected something, figure out what was selected. */
  926. X    if (!cur_msg_item)
  927. X        return;
  928. #ifndef NO_WALK_MENUS
  929. X    if ((Menu)menu_get(cur_msg_item, MENU_PARENT) == hdr_save_menu) {
  930. X        save_place = (char *)menu_get(cur_msg_item, MENU_CLIENT_DATA);
  931. X        action = SAVE_MSG;
  932. X    } else
  933. #endif /* NO_WALK_MENUS */
  934. X        action = (char *) menu_get(cur_msg_item, MENU_CLIENT_DATA);
  935. X    } else
  936. X    action = (char *) event;
  937. X
  938. X    set_isread(message);
  939. X    switch ((int) action) {
  940. X    case SAVE_MSG : {
  941. X        extern Panel_item msg_num_item, save_item;
  942. X        (void) panel_set(msg_num_item, PANEL_VALUE,
  943. X                    sprintf(buf, "%d", message+1), NULL);
  944. #ifndef NO_WALK_MENUS
  945. X        if (*save_place == '\0') /* magic to mean "use Filename:" */
  946. X            do_file_dir(save_item, event);
  947. X        else
  948. X            xx_file_dir(save_item, save_place);
  949. #else /* NO_WALK_MENUS */
  950. X        event_id(event) = MS_LEFT;
  951. X        do_file_dir(save_item, 0, event);
  952. #endif /* NO_WALK_MENUS */
  953. X        (void) panel_set(msg_num_item, PANEL_VALUE, NO_STRING, NULL);
  954. X    }
  955. X    when HELP_MSG :
  956. X        help(0, "headers", tool_help);
  957. X    when REPL_MSG : {
  958. X        extern Panel_item reply_item;
  959. X        open_compose();
  960. X        if (!compose_frame)
  961. X        break;    /* open failed */
  962. X        /* reply_item shouldn't be here */
  963. X        respond_mail(reply_item, message, NO_EVENT);
  964. X    }
  965. X    when READ_MSG :
  966. X        if (current_msg != message) {
  967. X        current_msg = message;
  968. X        (void) do_hdrs(0, DUBL_NULL, NULL);
  969. X        }
  970. #ifdef SUN_3_5
  971. X        /* Test for a shortage of file descriptors */
  972. X        if (nopenfiles(0) > 3)
  973. #endif /* SUN_3_5 */
  974. X        turnon(glob_flags, NEW_FRAME);
  975. X        more_prompt = compose_hdr(message);
  976. X        display_msg(message, (u_long)0);
  977. X
  978. X    otherwise :
  979. X        msg_menu_func((int)action, message);
  980. X    }
  981. }
  982. X
  983. /* msg_menu_func() is a function called to perform message menu actions
  984. X * that are either selected from the popup menu in the header window or
  985. X * from mouse actions that function as accelerators.
  986. X */
  987. static void
  988. msg_menu_func(action, message)
  989. int action;
  990. {
  991. X    int argc;
  992. X    register char **argv;
  993. X    char buf[32];
  994. X
  995. X    switch (action) {
  996. X        case PRNT_MSG :
  997. X        wprint("Message #%d sent to printer.\n", message+1);
  998. X        (void) strcpy(buf, "lpr");
  999. X    when UNDEL_MSG : case DEL_MSG :
  1000. X        (void) sprintf(buf, "%selete", (action == (int)DEL_MSG)?"d":"und");
  1001. X        when PRE_MSG :
  1002. X        (void) strcpy(buf, "preserve");
  1003. X        when MARK_MSG : case MARK_TOGGLE :
  1004. X        (void) sprintf(buf, "%smark",
  1005. X        ison(msg[message].m_flags, M_PRIORITY(0))? "un" : "");
  1006. X    when MARK_A : case MARK_B : case MARK_C : case MARK_D : case MARK_E :
  1007. X        (void) sprintf(buf, "mark -%c", action);
  1008. X    when MARK_CLEAR    :
  1009. X        (void) strcpy(buf, "mark -");
  1010. X    when MARK_HELP :
  1011. X        (void) help(0, "mark", tool_help);
  1012. X        return;
  1013. X    otherwise :
  1014. X        print("unknown switch: %c\n", action);
  1015. X    }
  1016. X    (void) sprintf(&buf[strlen(buf)], " %d", message+1);
  1017. X
  1018. X    if (argv = make_command(buf, (char ***) DUBL_NULL, &argc))
  1019. X    (void) do_command(argc, argv, msg_list);
  1020. }
  1021. SHAR_EOF
  1022. chmod 0644 hdr_sw.c ||
  1023. echo 'restore of hdr_sw.c failed'
  1024. Wc_c="`wc -c < 'hdr_sw.c'`"
  1025. test 13462 -eq "$Wc_c" ||
  1026.     echo 'hdr_sw.c: original size 13462, current size' "$Wc_c"
  1027. rm -f _shar_wnt_.tmp
  1028. fi
  1029. # ============= hdrs.c ==============
  1030. if test -f 'hdrs.c' -a X"$1" != X"-c"; then
  1031.     echo 'x - skipping hdrs.c (File already exists)'
  1032.     rm -f _shar_wnt_.tmp
  1033. else
  1034. > _shar_wnt_.tmp
  1035. echo 'x - extracting hdrs.c (Text)'
  1036. sed 's/^X//' << 'SHAR_EOF' > 'hdrs.c' &&
  1037. /* hdrs.c     (c) copyright 1986 (Dan Heller) */
  1038. X
  1039. /*
  1040. X * Routines that deal with message headers inside messages
  1041. X * msg_get(n, from, count) -- get the From_ line in msg n into "from".
  1042. X * header_field(n, str) -- get the header named "str" from msg n.
  1043. X * do_hdrs(argc, argv, list) -- diplay message headers.
  1044. X * specl_hdrs(argv, list) -- display msgs that share common attributes.
  1045. X * compose_hdr(cnt) -- compose a message header from msg n.
  1046. X * reply_to(n, all, buf) -- construct a header based on the To: header of n.
  1047. X * subject_to(n, buf) -- get the subject for replying to msg n.
  1048. X * cc_to(n, buf) -- construct a Cc header based on the Cc of message n.
  1049. X */
  1050. #include "mush.h"
  1051. X
  1052. #ifdef SUNTOOL
  1053. #define highlight(win,x,y,s) \
  1054. X    (void) (pw_text(win,x,y, PIX_SRC, mush_font, s), \
  1055. X    pw_text(win,x+1,y, \
  1056. X    (ison(glob_flags, REV_VIDEO))? PIX_NOT(PIX_SRC): PIX_SRC|PIX_DST, \
  1057. X    mush_font, s))
  1058. #endif /* SUNTOOL */
  1059. X
  1060. /*
  1061. X * Get a message from the current folder by its offset.
  1062. X * Copy the From_ line to the second argument if the third arg > 0,
  1063. X * and return the second argument, or NULL on an error.
  1064. X */
  1065. char *
  1066. msg_get(n, from, count)
  1067. int n, count;
  1068. char *from;
  1069. {
  1070. X    if (fseek(tmpf, msg[n].m_offset, L_SET) == -1) {
  1071. X    error("fseek in %s (msg %d, folder=%s)", tempfile, n+1, mailfile);
  1072. X    turnon(glob_flags, READ_ONLY);
  1073. X    return NULL;
  1074. X    }
  1075. X    if (count)
  1076. #ifndef MSG_SEPARATOR
  1077. X    return fgets(from, count, tmpf);
  1078. #else
  1079. X    *from = '\0';
  1080. #endif
  1081. X    return from;
  1082. }
  1083. X
  1084. /*
  1085. X * get which message via the offset and search for the headers which
  1086. X * match the string "str". there may be more than one of a field (like Cc:)
  1087. X * so get them all and "cat" them together into the static buffer
  1088. X * "buf" and return its address.
  1089. X */
  1090. char *
  1091. header_field(n, str)
  1092. char *str;
  1093. {
  1094. X    static char    buf[HDRSIZ];
  1095. X    char        tmp[HDRSIZ];
  1096. X    register char  *p, *p2, *b = buf;
  1097. X    int contd_hdr;  /* true if next line is a continuation of the hdr we want */
  1098. X
  1099. X    /* use msg_get as a test for fseek() -- don't let it fgets() (pass 0) */
  1100. X    if (!msg_get(n, tmp, 0))
  1101. X    return NULL;
  1102. X    *b = 0;
  1103. X    while((p = fgets(tmp, sizeof(tmp), tmpf)) && *p != '\n') {
  1104. X    if (*p != ' ' && *p != '\t') {
  1105. X        contd_hdr = 0;
  1106. X        /* strcmp ignoring case */
  1107. X        for(p2 = str; *p && *p2 && lower(*p2) == lower(*p); ++p, ++p2);
  1108. X        /* MATCH is true if p2 is at the end of str and *p is ':' */
  1109. X        if (*p2 || *p++ != ':')
  1110. X        continue;
  1111. X        else
  1112. X        contd_hdr = 1;
  1113. X        if (b > buf && (b - buf) < sizeof buf - 2)
  1114. X        *b++ = ',';
  1115. X    } else if (!contd_hdr)
  1116. X        continue;
  1117. X    skipspaces(0);
  1118. X    (void) no_newln(p);
  1119. X    if (strlen(p) + (b - buf) < sizeof buf - 1) {
  1120. X        if (b > buf)
  1121. X        *b++ = ' ';
  1122. X        b += Strcpy(b, p);
  1123. X    }
  1124. X    }
  1125. X    if (b > buf && *--b == ',')
  1126. X    *b = 0;
  1127. X    return (*buf)? buf: NULL;
  1128. }
  1129. X
  1130. do_hdrs(argc, argv, list)
  1131. register char **argv, list[];
  1132. {
  1133. X    register int   pageful = 0;
  1134. X    SIGRET        (*oldint)(), (*oldquit)();
  1135. X    int           show_deleted, srch = 1; /* search forward by default */
  1136. X    static int     cnt, oldscrn = 1;
  1137. X    register char  *p;
  1138. X    char        first_char = (argc) ? **argv: 'h';
  1139. X
  1140. X    if (argc > 1 && !strcmp(argv[1], "-?"))
  1141. X    return help(0, "headers", cmd_help);
  1142. X
  1143. X    if (!msg_cnt) {
  1144. X    if (ison(glob_flags, DO_PIPE) && !istool)
  1145. X        return 0;
  1146. #ifdef CURSES
  1147. X    if (iscurses)
  1148. X        clear();
  1149. #endif /* CURSES */
  1150. #ifdef SUNTOOL
  1151. X    if (istool)
  1152. X        mail_status(0);
  1153. #endif /* SUNTOOL */
  1154. X    return 0;
  1155. X    }
  1156. X    if (first_char == ':' || (argc > 1 && argv[1][0] == ':')) {
  1157. X    if (first_char != ':')
  1158. X        argv++;
  1159. X    return specl_hdrs(argv, list);
  1160. X    } else if (argc > 1 && !strncmp(argv[1], "-H:", 3)) {
  1161. X    argv[1][0] = ':';
  1162. X    argv[1][1] = argv[1][3];
  1163. X    argv[1][2] = 0;
  1164. X    return specl_hdrs(&argv[1], list);
  1165. X    }
  1166. X
  1167. X    on_intr();
  1168. X
  1169. X    if (argc && (argv[0][1] == '-' || argc > 1 && !strcmp(argv[1], "-"))) {
  1170. X    cnt = max(n_array[0], 0);
  1171. X    srch = -1;    /* search backwards */
  1172. X    } else if (argc && (argv[0][1] == '+' ||
  1173. X        argc > 1 && !strcmp(argv[1], "+")) ||
  1174. X        first_char == 'z' && !argv[1]) {
  1175. X    if (msg_cnt > screen)
  1176. X        cnt = min(msg_cnt - screen, n_array[0] + screen);
  1177. X    else
  1178. X        cnt = 0;
  1179. X    } else if (argc && *++argv &&
  1180. X        (isdigit(**argv) || **argv == '^' ||
  1181. X        **argv == '$' || **argv == '.') ||
  1182. X        ison(glob_flags, IS_PIPE) && list) {
  1183. X    /* if we're coming from a pipe, start display at the first msg bit
  1184. X     * set in the msg_list
  1185. X     */
  1186. X    int fnd;
  1187. X    if (ison(glob_flags, IS_PIPE)) {
  1188. X        if (isoff(glob_flags, DO_PIPE))
  1189. X        for (fnd = 0; fnd < msg_cnt; fnd++)
  1190. X            if (msg_bit(list, fnd))
  1191. X            wprint("%s\n", compose_hdr(fnd));
  1192. X        off_intr();
  1193. X        return 0;
  1194. X    }
  1195. X    /* if a number was given, use it */
  1196. X    if (!(fnd = chk_msg(*argv))) {
  1197. X        off_intr();
  1198. X        return -1;
  1199. X    }
  1200. X    for (cnt = fnd - 1; cnt > 0 && cnt + screen > msg_cnt; cnt--)
  1201. X        ;
  1202. X    } else if (current_msg < n_array[0] || current_msg > n_array[oldscrn-1] ||
  1203. X        (iscurses || oldscrn != screen) &&
  1204. X        (cnt > current_msg + screen || cnt < current_msg - screen))
  1205. X    cnt = current_msg; /* adjust if reads have passed screen bounds */
  1206. X    else if (cnt >= msg_cnt || !argc || !*argv)
  1207. X    /* adjust window to maintain position */
  1208. X    cnt = (n_array[0] > msg_cnt) ? current_msg : n_array[0];
  1209. X
  1210. X    oldscrn = screen;
  1211. X    show_deleted = !!do_set(set_options, "show_deleted");
  1212. X
  1213. X    /* Make sure we have at least $screen headers to print */
  1214. X    if (cnt > 0 && !iscurses && first_char == 'h') {
  1215. X    int top, bot = cnt;
  1216. X    /* first count how many messages we can print without adjusting */
  1217. X    for (pageful = 0; pageful<screen && bot<msg_cnt && bot; bot += srch)
  1218. X        if (show_deleted || isoff(msg[bot].m_flags, DELETE))
  1219. X        pageful++;
  1220. X    /* if we can't print a pagefull of hdrs, back up till we can */
  1221. X    for (top = cnt-srch; pageful<screen && top && top<msg_cnt; top -= srch)
  1222. X        if (show_deleted || isoff(msg[top].m_flags, DELETE))
  1223. X        pageful++;
  1224. X    if (srch < 0)
  1225. X        cnt = bot;    /* the search was upside down */
  1226. X    else
  1227. X        cnt = top + (pageful == screen);
  1228. X    pageful = 0;    /* Used later as an index, so reset */
  1229. X    } else if (cnt > 0 && srch < 0)
  1230. X    cnt = max(cnt - screen, 0);
  1231. X    else
  1232. X    cnt = max(cnt, 0);
  1233. X
  1234. X    for (;pageful<screen && cnt<msg_cnt && isoff(glob_flags, WAS_INTR); cnt++) {
  1235. X    if (!iscurses && !show_deleted && first_char == 'h'
  1236. X        && ison(msg[cnt].m_flags, DELETE))
  1237. X        continue;
  1238. X    n_array[pageful++] = cnt;
  1239. X    /* this message was displayed -- set the bit */
  1240. X    if (list)
  1241. X        set_msg_bit(list, cnt);
  1242. X    /* if do_pipe, don't output anything */
  1243. X    if (ison(glob_flags, DO_PIPE) && !istool)
  1244. X        continue;
  1245. X    p = compose_hdr(cnt);
  1246. X    if (!istool && (!iscurses || ison(glob_flags, IS_GETTING)))
  1247. X        puts(p);
  1248. #ifdef SUNTOOL
  1249. X    else if (istool) {
  1250. X        if (cnt == current_msg) /* embolden or reverse-video */
  1251. X        highlight(hdr_win, 0,pageful*l_height(), p);
  1252. X        else
  1253. X        (void) pw_text(hdr_win, 0, pageful * l_height(), PIX_SRC,
  1254. X                            mush_font, p);
  1255. X        Clrtoeol(hdr_win, strlen(p)*l_width(), pageful*l_height());
  1256. X    }
  1257. #endif /* SUNTOOL */
  1258. X
  1259. #ifdef CURSES
  1260. X    else if (iscurses) {
  1261. X        move(pageful, 0);
  1262. X        printw("%-.*s", COLS-2, p), clrtoeol();
  1263. X    }
  1264. #endif /* CURSES */
  1265. X    }
  1266. X    /* just in case a signal stopped us */
  1267. X    off_intr();
  1268. X    pageful++;
  1269. #ifdef CURSES
  1270. X    if (iscurses && pageful < screen)
  1271. X    move(pageful, 0), clrtobot();
  1272. #endif /* CURSES */
  1273. X    if (cnt == msg_cnt) {
  1274. X    while (pageful <= screen) {
  1275. X        n_array[pageful-1] = msg_cnt+1; /* assign out-of-range values */
  1276. #ifdef SUNTOOL
  1277. X        if (istool)
  1278. X        Clrtoeol(hdr_win, 0, pageful * l_height());
  1279. #endif /* SUNTOOL */
  1280. X        ++pageful;
  1281. X    }
  1282. X    }
  1283. #ifdef SUNTOOL
  1284. X    if (istool) {
  1285. X    Scrollbar sb = (Scrollbar) window_get(hdr_sw, WIN_VERTICAL_SCROLLBAR);
  1286. X
  1287. X    if (show_deleted) {
  1288. X        scrollbar_set(sb,
  1289. X        SCROLL_OBJECT_LENGTH,    msg_cnt,
  1290. X        SCROLL_VIEW_START,    n_array[0],
  1291. X        0);
  1292. X    } else {
  1293. X        int i, not_deleted, start;
  1294. X
  1295. X        for (i = start = 0; i < n_array[0]; i++)
  1296. X        if (!ison(msg[i].m_flags, DELETE))
  1297. X            start++;
  1298. X        for (not_deleted = start; i < msg_cnt; i++)
  1299. X        if (!ison(msg[i].m_flags, DELETE))
  1300. X            not_deleted++;
  1301. X        scrollbar_set(sb,
  1302. X        SCROLL_OBJECT_LENGTH,    not_deleted,
  1303. X        SCROLL_VIEW_START,    start,
  1304. X        0);
  1305. X        }
  1306. X
  1307. X    scrollbar_paint(sb);
  1308. X    mail_status(0);
  1309. X    }
  1310. #endif /* SUNTOOL */
  1311. X
  1312. X    return 0;
  1313. }
  1314. X
  1315. #define NEW 1
  1316. #define ALL 2
  1317. X
  1318. specl_hdrs(argv, list)
  1319. char **argv, list[];
  1320. {
  1321. X    u_long    special = 0;
  1322. X    int     n = 0;
  1323. X
  1324. X    while (argv[0][++n])
  1325. X    switch(argv[0][n]) {
  1326. X        case 'a': special = ALL;
  1327. X        when 'd': special = DELETE;
  1328. X        when 'm': special = M_PRIORITY(0);
  1329. X        when 'n': special = NEW;
  1330. X        when 'o': special = OLD;
  1331. X        when 'p': special = PRESERVE;
  1332. X        when 'r': special = REPLIED;
  1333. X        when 's': special = SAVED;
  1334. X        when 'u': special = UNREAD;
  1335. X        otherwise: print("choose from d,m,n,o,p,r,s,u or a"); return -1;
  1336. X    }
  1337. X    if (debug)
  1338. X    (void) check_flags(special);
  1339. X
  1340. X    for (n = 0; n < msg_cnt; n++) {
  1341. X    /*
  1342. X     * First, see if we're looking for NEW messages.
  1343. X     * If so, then check to see if the msg is unread and not old.
  1344. X     * If special > ALL, then special has a mask of bits describing
  1345. X     * the state of the message.
  1346. X     */
  1347. X    if (ison(glob_flags, IS_PIPE)&& !msg_bit(list, n))
  1348. X        continue;
  1349. X    if (special == ALL || special == NEW &&
  1350. X           (ison(msg[n].m_flags, UNREAD) && isoff(msg[n].m_flags, OLD))) {
  1351. X        if (isoff(glob_flags, DO_PIPE))
  1352. X        print("%s\n", compose_hdr(n));
  1353. X        if (list)
  1354. X        set_msg_bit(list, n);
  1355. X    } else if (special > ALL && ison(msg[n].m_flags, special)) {
  1356. X        if (isoff(glob_flags, DO_PIPE))
  1357. X        print("%s\n", compose_hdr(n));
  1358. X        if (list)
  1359. X        set_msg_bit(list, n);
  1360. X    } else {
  1361. X        if (list)
  1362. X        unset_msg_bit(list, n);
  1363. X        if (debug) {
  1364. X        (void) printf("msg[%d].m_flags: %d", n, msg[n].m_flags);
  1365. X        (void) check_flags(msg[n].m_flags);
  1366. X        }
  1367. X    }
  1368. X    }
  1369. X    return 0;
  1370. }
  1371. X
  1372. #define Strncpy(buf,p) (void)(strncpy(buf,p,sizeof(buf)),buf[sizeof(buf)-1]=0)
  1373. X
  1374. /*
  1375. X * format a header from the information about a message (from, to, date,
  1376. X * subject, etc..).  The header for message number "cnt" is built and is
  1377. X * returned in the static buffer "buf".  There will be *at least* 9 chars
  1378. X * in the buffer which will be something like: " 123 >N " The breakdown
  1379. X * is as follows: 4 chars for the message number, 1 space, 1 char for '>'
  1380. X * (if current message) and two spaces for message status (new, unread, etc)
  1381. X * followed by 1 terminating space.
  1382. X * Read other comments in the routine for more info.
  1383. X */
  1384. char *
  1385. format_hdr(cnt, hdr_fmt, show_to)
  1386. int cnt, show_to;
  1387. char *hdr_fmt;
  1388. {
  1389. X    static char        buf[256];
  1390. X    register char    *p, *p2, *b;
  1391. X    int            len, do_pad = FALSE, val, pad, got_dot, isauthor = 0, n;
  1392. X    char from[HDRSIZ], subject[256], date[64], lines[16];
  1393. X    char to[256], addr[256], name[256], user[256], status[4];
  1394. X    char Day[3], Mon[4], Tm[8], Yr[5], Wkday[4], Zone[8], *date_p;
  1395. X
  1396. X    /* status of the message */
  1397. X    if (ison(msg[cnt].m_flags, DELETE))
  1398. X    status[0] = '*';
  1399. X    else if (ison(msg[cnt].m_flags, PRESERVE))
  1400. X    status[0] = 'P';
  1401. X    else if (ison(msg[cnt].m_flags, SAVED))
  1402. X    status[0] = 'S';
  1403. X    else if (ison(msg[cnt].m_flags, OLD) && ison(msg[cnt].m_flags, UNREAD))
  1404. X    status[0] = 'U';
  1405. X    else if (ison(msg[cnt].m_flags, PRINTED))
  1406. X    status[0] = 'p';
  1407. X    else if (ison(msg[cnt].m_flags, FORWARD))
  1408. X    status[0] = 'f';
  1409. X    else if (isoff(msg[cnt].m_flags, UNREAD))
  1410. X    status[0] = ' ';
  1411. X    else
  1412. X    status[0] = 'N';
  1413. X
  1414. X    if (ison(msg[cnt].m_flags, REPLIED))
  1415. X    status[1] = 'r';
  1416. X    else
  1417. X    status[1] = ' ';
  1418. X    status[2] = 0;
  1419. X
  1420. X    to[0] = from[0] = subject[0] = date[0] = lines[0] = addr[0] =
  1421. X    user[0] = name[0] = Day[0] = Mon[0] = Tm[0] = Yr[0] = Wkday[0] = 0;
  1422. X
  1423. X    /* who's the message to */
  1424. X    if ((p = header_field(cnt, "resent-to")) ||
  1425. X    (p = header_field(cnt, "to")) ||
  1426. X    (p = header_field(cnt, "apparently-to")))
  1427. X    Strncpy(to, p);
  1428. X
  1429. X    /* who's the message from */
  1430. X    if ((p = header_field(cnt, "from")) && strcpy(from, p)
  1431. X        || (p = reply_to(cnt, 0, from))) {
  1432. X    /* NOTE:  this fails if the sender has '<' or '!' in
  1433. X     * the RFC822 comment fields -- leading "comment"
  1434. X     * or trailing (comment) -- but that isn't critical
  1435. X     */
  1436. X    if ((p2 = rindex(p, '!')) || (p2 = index(p, '<')))
  1437. X        p = p2 + 1;
  1438. X    } else
  1439. X    p = strcpy(from, "unknown"); /* just in case */
  1440. X    /* If the From field contains the user's login name, then the message
  1441. X     * could be from the user -- attempt to give more useful information
  1442. X     * by telling to whom the message was sent.  This is not possible if
  1443. X     * the "to" header failed to get info (which is probably impossible).
  1444. X     * Use take_me_off() to be sure the message really is from the current
  1445. X     * user and not just someone with the same login at another site.
  1446. X     */
  1447. X    if (show_to && !strncmp(p, login, strlen(login)))
  1448. X    (void) take_me_off(from);
  1449. X    if (show_to && (isauthor = !*from)) {  /* assign and test */
  1450. X    (void) get_name_n_addr(to, name+4, addr+4);
  1451. X    if (addr[4])
  1452. X        (void) strncpy(addr, "TO: ", 4);
  1453. X    if (name[4]) {  /* check to see if a name got added */
  1454. X        (void) strncpy(name, "TO: ", 4);
  1455. X        Strncpy(from, name);
  1456. X    } else
  1457. X        Strncpy(from, addr);
  1458. X    } else
  1459. X    (void) get_name_n_addr(from, name, addr);
  1460. X
  1461. X    if (ison(glob_flags, DATE_RECV))
  1462. X    date_p = msg[cnt].m_date_recv;
  1463. X    else
  1464. X    date_p = msg[cnt].m_date_sent;
  1465. X    (void) date_to_string(date_p, Yr, Mon, Day, Wkday, Tm, Zone, date);
  1466. X
  1467. X    /* and the subject */
  1468. X    if (p = header_field(cnt, "subject"))
  1469. X    Strncpy(subject, p);
  1470. X
  1471. X    /* now, construct a header out of a format string */
  1472. X    if (!hdr_fmt)
  1473. X    hdr_fmt = hdr_format;
  1474. X    {
  1475. X    int i;
  1476. X    for (i = MAX_PRIORITY; i > 0; i--)
  1477. X        if (ison(msg[cnt].m_flags, M_PRIORITY(i))) {
  1478. X        p2 = sprintf(lines, "%d", i);
  1479. X        break;
  1480. X        }
  1481. X    (void) sprintf(buf, "%c%3.d%s%c%s ",
  1482. X        ((cnt == current_msg && !iscurses)? '>': ' '),
  1483. X        cnt+1, cnt < 999 ? " " : "",
  1484. X        (ison(msg[cnt].m_flags, M_PRIORITY(0)) ? '+' :
  1485. X                    i > 0 ? 'A' + i - 1 : ' '),
  1486. X        status);
  1487. X    }
  1488. X    /* Count chars since beginning of buf. Initialize to 9 (strlen(buf) so far)
  1489. X     * This magic number is used in other places in msgs.c and mail.c
  1490. X     */
  1491. X    n = 9;
  1492. X    b = buf+9;
  1493. X    for (p = hdr_fmt; *p; p++)
  1494. X    if (*p == '\\')
  1495. X        switch (*++p) {
  1496. X        case 't':
  1497. X            while (n % 8)
  1498. X            n++, *b++ = ' ';
  1499. X        when 'n':
  1500. X            n = 1, *b++ = '\n';
  1501. X        otherwise: n++, *b++ = *p;
  1502. X        }
  1503. X    else if (*p == '%') {
  1504. X        char fmt[64];
  1505. X
  1506. X        p2 = fmt;
  1507. X        /* first check for string padding: %5n, %.4a, %10.5f, %-.3l etc. */
  1508. X        do_pad = pad = val = got_dot = 0;
  1509. X        *p2++ = '%';
  1510. X        if (p[1] != '-')
  1511. X        *p2++ = '-';
  1512. X        else
  1513. X        ++p;
  1514. X        while (isdigit(*++p) || !got_dot && *p == '.') {
  1515. X        if (*p == '.')
  1516. X            got_dot = TRUE, val = pad, pad = 0;
  1517. X        else
  1518. X            pad = pad * 10 + *p - '0';
  1519. X        *p2++ = *p;
  1520. X        }
  1521. X        if (!got_dot && isdigit(p[-1])) {
  1522. X        *p2 = 0; /* assure null termination */
  1523. X        val = atoi(fmt+1);
  1524. X        if (val < 0)
  1525. X            val = -val;
  1526. X        p2 += strlen(sprintf(p2, ".%d", val));
  1527. X        }
  1528. X        pad = min(pad, val);
  1529. X        *p2++ = 's', *p2 = 0;
  1530. X        if (!*p)
  1531. X        break;
  1532. X        switch (*p) {
  1533. X        case 'f': p2 = from, do_pad = TRUE;
  1534. X        when 'a':
  1535. X            if (!*(p2 = addr))
  1536. X            p2 = from;
  1537. X            do_pad = TRUE;
  1538. X        when 'u' :
  1539. X            if (!user[0])
  1540. X            (void) bang_form(user, addr);
  1541. X            if (p2 = rindex(user, '!'))
  1542. X            p2++;
  1543. X            else
  1544. X            p2 = user;
  1545. X        when 'n':
  1546. X            if (!*(p2 = name))
  1547. X            p2 = from, do_pad = TRUE;
  1548. X        when '%': p2 = "%";
  1549. X        when 't': p2 = to;
  1550. X        when 's': p2 = subject;
  1551. X        when 'l': p2 = sprintf(lines, "%d", msg[cnt].m_lines);
  1552. X        when 'c': p2 = sprintf(lines, "%ld", msg[cnt].m_size);
  1553. X        when 'i': (p2 = header_field(cnt, "message-id")) || (p2 = "");
  1554. X        /* date formatting chars */
  1555. X        when 'd': p2 = date; /* the full date */
  1556. X        when 'T': p2 = Tm;
  1557. X        when 'M': p2 = Mon;
  1558. X        when 'Y': p2 = Yr;
  1559. X        when 'y': p2 = Yr+2;
  1560. X        when 'N': p2 = Day;
  1561. X        when 'D': case 'W': p2 = Wkday;
  1562. X        when 'Z': p2 = Zone;
  1563. X        /* Any selected header */
  1564. X        when '?': {
  1565. X            p2 = p + 1;
  1566. X            p = index(p2, '?');
  1567. X            if (p) {
  1568. X            *p = 0;
  1569. X            if (!(p2 = header_field(cnt, p2)))
  1570. X                p2 = "";
  1571. X            *p = '?';
  1572. X            } else {
  1573. X            p = p2 + (strlen(p2) - 1);
  1574. X            if (!(p2 = header_field(cnt, p2)))
  1575. X                p2 = "";
  1576. X            }
  1577. X        }
  1578. X        otherwise: continue; /* unknown formatting char */
  1579. X        }
  1580. X        if (do_pad && pad && strlen(p2) > pad) {
  1581. X        char *old_p2 = p2, *p3;
  1582. X        int is_bangform = 0;
  1583. X        /* if addr is too long, move pointer forward till the
  1584. X         * "important" part is readable only for ! paths/addresses.
  1585. X         */
  1586. X        while (p3 = index(p2, '!')) {
  1587. X            is_bangform = 1;
  1588. X            len = strlen(p3+1); /* xenix has compiler problems */
  1589. X            p2 = p3+1;
  1590. X            if (len + isauthor*4 < pad) {
  1591. X            if (isauthor && (p2 -= 4) < old_p2)
  1592. X                p2 = old_p2;
  1593. X            break;
  1594. X            }
  1595. X        }
  1596. X        if (isauthor && p2 > old_p2+4 && !p3 && strlen(p2) + 4 > pad)
  1597. X            p2 -= 4;
  1598. X        if (is_bangform && (p3 = rindex(p2, '@'))) {
  1599. X            len = strlen(p3);
  1600. X            while (len-- && --p2 > old_p2) {
  1601. X            if (*(p2 + isauthor*4 - 1) == '!')
  1602. X                break;
  1603. X            }
  1604. X        }
  1605. X        if (old_p2 != p2 && isauthor)
  1606. X            (void) strncpy(p2, "TO: ", 4); /* doesn't null terminate */
  1607. X        }
  1608. X        len = strlen(sprintf(b, fmt, p2));
  1609. X        n += len, b += len;
  1610. X        /* Get around a bug in 5.5 IBM RT which pads with NULs not ' ' */
  1611. X        while (n && !*(b-1))
  1612. X        b--, n--;
  1613. X    } else
  1614. X        n++, *b++ = *p;
  1615. X    /* Since show_to is true only when called from compose_hdr() below,
  1616. X     * use it to decide whether trailing whitespace should be trimmed.
  1617. X     */
  1618. X    if (show_to)
  1619. X    for (*b-- = 0; isspace(*b) && *b != '\n'; --b)
  1620. X        *b = 0;
  1621. X    else
  1622. X    *b = 0;
  1623. X    return buf;
  1624. }
  1625. X
  1626. char *
  1627. compose_hdr(cnt)
  1628. int cnt;
  1629. {
  1630. X    if (!hdr_format)
  1631. X    hdr_format = DEF_HDR_FMT;
  1632. X    return format_hdr(cnt, hdr_format, TRUE);
  1633. }
  1634. X
  1635. /*
  1636. X * Using message "n", build a list of recipients that you would mail to if
  1637. X * you were to reply to this message.  If "all" is true, then it will take
  1638. X * everyone from the To line in addition to the original sender.
  1639. X * route_addresses() is called from mail.c, not from here.  There are too many
  1640. X * other uses for reply_to to always require reconstruction of return paths.
  1641. X * Note that we do NOT deal with Cc paths here either.
  1642. X * Check to make sure that we in fact return a legit address (i.e. not blanks
  1643. X * or null). If such a case occurs, return login name.  Always pad end w/blank.
  1644. X */
  1645. char *
  1646. reply_to(n, all, buf)
  1647. char buf[];
  1648. {
  1649. X    register char *p = NULL, *p2, *b = buf, *field;
  1650. X    char line[256], name[256], addr[256], *unscramble_addr();
  1651. X
  1652. X    if (field = do_set(set_options, "reply_to_hdr")) {
  1653. #ifndef MSG_SEPARATOR
  1654. X    if (!*field)
  1655. X        goto DoFrom; /* special case -- get the colon-less From line */
  1656. #endif /* MSG_SEPARATOR */
  1657. X    field = lcase_strcpy(line, field);
  1658. X    while (*field) {
  1659. X        if (p2 = any(field, " \t,:"))
  1660. X        *p2 = 0;
  1661. #ifndef MSG_SEPARATOR
  1662. X        if (!lcase_strncmp(field, "from_", -1))
  1663. X        goto DoFrom;
  1664. #endif /* MSG_SEPARATOR */
  1665. X        if ((p = header_field(n, field)) || !p2)
  1666. X        break;
  1667. X        else {
  1668. X        field = p2+1;
  1669. X        while (isspace(*field) || *field == ':' || *field == ',')
  1670. X            field++;
  1671. X        }
  1672. X    }
  1673. X    if (!p)
  1674. X        print("Warning: message contains no `reply_to_hdr' headers.\n");
  1675. X    }
  1676. X    if (p || (!p && ((p = header_field(n, field = "reply-to")) ||
  1677. X            (p = header_field(n, field = "from")) ||
  1678. X            (p = header_field(n, field = "return-path")))))
  1679. X    skipspaces(0);
  1680. X    else if (!p) {
  1681. #ifndef MSG_SEPARATOR
  1682. DoFrom:
  1683. X    field = "from_";
  1684. X    /* if all else fails, then get the first token in "From" line */
  1685. X    if (p2 = msg_get(n, line, sizeof line))
  1686. X        p = index(p2, ' ');
  1687. X    else
  1688. X        return "";
  1689. X    skipspaces(1);
  1690. X    if (p2 = index(p, ' '))
  1691. X        *p2 = 0;
  1692. X    (void) unscramble_addr(p, line); /* p is safely recopied to line */
  1693. X    p = line;
  1694. #else /* MSG_SEPARATOR */
  1695. X    wprint("Warning: unable to find who msg %d is from!\n", n+1);
  1696. #endif /* MSG_SEPARATOR */
  1697. X    }
  1698. X    (void) get_name_n_addr(p, name, addr);
  1699. X    if (!name[0] && (!lcase_strncmp(field, "return-path", -1) ||
  1700. X             !lcase_strncmp(field, "from_", -1))) {
  1701. X    /*
  1702. X     * Get the name of the author of the message we're replying to from the
  1703. X     * From: header since that header contains the author's name.  Only do
  1704. X     * this if the address was gotten from the return-path or from_ lines
  1705. X     * because this is the only way to guarantee that the return address
  1706. X     * matches the author's name.  Reply-To: may not be the same person!
  1707. X     * Check Resent-From: if the address came from the from_ line, else
  1708. X     * check From:, and finally Sender: or Name:.
  1709. X     */
  1710. X    if (!lcase_strncmp(field, "from_", -1) &&
  1711. X        (p = header_field(n, "resent-from")) ||
  1712. X            (p = header_field(n, "from")) ||
  1713. X            (p = header_field(n, "sender")))
  1714. X        (void) get_name_n_addr(p, name, NULL);
  1715. X    if (!name[0] && (p = header_field(n, "name")))
  1716. X        (void) strcpy(name, p);
  1717. X    if (name[0]) {
  1718. X        if ((p = any(name, "(<,\"")) && (*p == ',' || *p == '<'))
  1719. X        *b++ = '"';
  1720. X        b += Strcpy(b, name);
  1721. X        if (p && (*p == ',' || *p == '<'))
  1722. X        *b++ = '"';
  1723. X        *b++ = ' ', *b++ = '<';
  1724. X    }
  1725. X    b += Strcpy(b, addr);
  1726. X    if (name[0])
  1727. X        *b++ = '>', *b = 0;
  1728. X    } else
  1729. X    b += Strcpy(buf, p);
  1730. X
  1731. X    /*
  1732. X     * if `all' is true, append everyone on the "To:" line(s).
  1733. X     * cc_to(), called separately, will catch the cc's
  1734. X     */
  1735. X    if (all) {
  1736. X    int lim = HDRSIZ - (b - buf) - 2;
  1737. X    /* Check for overflow on each copy.
  1738. X     * The assumption that HDRSIZ is correct is unwise, but I know it
  1739. X     * to be true for Mush.  Be forewarned if you call this routine.
  1740. X     */
  1741. X    if (lim > 0 && (p = header_field(n, "resent-to")) && *p) {
  1742. X        *b++ = ',', *b++ = ' ';
  1743. X        p[lim] = '\0'; /* prevent overflow */
  1744. X        b += Strcpy(b, p);
  1745. X        lim = HDRSIZ - (b - buf) - 2;
  1746. X    }
  1747. X    if (lim > 0 && (p = header_field(n, "to")) && *p) {
  1748. X        *b++ = ',', *b++ = ' ';
  1749. X        p[lim] = '\0'; /* prevent overflow */
  1750. X        b += Strcpy(b, p);
  1751. X        lim = HDRSIZ - (b - buf) - 2;
  1752. X    }
  1753. X    if (lim > 0 && (p = header_field(n, "apparently-to")) && *p) {
  1754. X        *b++ = ',', *b++ = ' ';
  1755. X        p[lim] = '\0'; /* prevent overflow */
  1756. X        b += Strcpy(b, p);
  1757. X        lim = HDRSIZ - (b - buf) - 2;
  1758. X    }
  1759. X    /* Also append the Resent-From address if there is one. */
  1760. X    if (lim > 0 && (p = header_field(n, "resent-from")) && *p) {
  1761. SHAR_EOF
  1762. true || echo 'restore of hdrs.c failed'
  1763. fi
  1764. echo 'End of  part 9'
  1765. echo 'File hdrs.c is continued in part 10'
  1766. echo 10 > _shar_seq_.tmp
  1767. exit 0
  1768. exit 0 # Just in case...
  1769. -- 
  1770. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1771. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1772. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1773. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1774.