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

  1. From: argv@zipcode.com (Dan Heller)
  2. Newsgroups: comp.sources.misc
  3. Subject: v18i071:  mush - Mail User's Shell, Part14/22
  4. Message-ID: <1991Apr22.000446.18972@sparky.IMD.Sterling.COM>
  5. Date: 22 Apr 91 00:04:46 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: d6fbf485 37198fd0 8aa00f78 e9891882
  8.  
  9. Submitted-by: Dan Heller <argv@zipcode.com>
  10. Posting-number: Volume 18, Issue 71
  11. Archive-name: mush/part14
  12. Supersedes: mush: Volume 12, Issue 28-47
  13.  
  14. #!/bin/sh
  15. # do not concatenate these parts, unpack them in order with /bin/sh
  16. # file misc_frame.c continued
  17. #
  18. if test ! -r _shar_seq_.tmp; then
  19.     echo 'Please unpack part 1 first!'
  20.     exit 1
  21. fi
  22. (read Scheck
  23.  if test "$Scheck" != 14; then
  24.     echo Please unpack part "$Scheck" next!
  25.     exit 1
  26.  else
  27.     exit 0
  28.  fi
  29. ) < _shar_seq_.tmp || exit 1
  30. if test ! -f _shar_wnt_.tmp; then
  31.     echo 'x - still skipping misc_frame.c'
  32. else
  33. echo 'x - continuing file misc_frame.c'
  34. sed 's/^X//' << 'SHAR_EOF' >> 'misc_frame.c' &&
  35. X        PANEL_LABEL_STRING, "",
  36. X        NULL);
  37. X    free_vec(argv);
  38. X    panel_set_value(ignore_name, "");
  39. X    return PANEL_NONE;
  40. }
  41. X
  42. static void
  43. ignore_done()
  44. {
  45. X    window_destroy(ignore_frame);
  46. X    ignore_frame = (Frame) 0;
  47. }
  48. X
  49. void
  50. do_ignore()
  51. {
  52. X    Panel    panel;
  53. X
  54. X    if (ignore_frame) {
  55. X    window_set(ignore_frame, WIN_SHOW, TRUE, NULL);
  56. X    return;
  57. X    }
  58. #ifdef SUN_3_5
  59. X    if (nopenfiles(0) < 5) {
  60. X    print("Too many frames; close one first!\n");
  61. X    return;
  62. X    }
  63. #endif /* SUN_3_5 */
  64. X
  65. X    ignore_frame = window_create(tool, FRAME,
  66. X    FRAME_SHOW_LABEL,    TRUE,
  67. X    FRAME_LABEL,        "Ignored Headers",
  68. X    FRAME_NO_CONFIRM,    TRUE,
  69. X    FRAME_DONE_PROC,    ignore_done,
  70. X    WIN_SHOW,        TRUE,
  71. X    WIN_WIDTH,        MY_FRAME_WIDTH,
  72. X    NULL);
  73. X
  74. X    panel = window_create(ignore_frame, PANEL,
  75. X    PANEL_WIDTH,        MY_FRAME_WIDTH,
  76. X    NULL);
  77. X    (void) notify_interpose_event_func(panel, fkey_interposer, NOTIFY_SAFE);
  78. X    (void) panel_create_item(panel, PANEL_BUTTON,
  79. X    PANEL_LABEL_IMAGE,    
  80. X        panel_button_image(panel, "Help", 4, mush_font),
  81. X    PANEL_NOTIFY_PROC,    frame_help,
  82. X    PANEL_CLIENT_DATA,    "ignore",
  83. X    NULL);
  84. X    (void) panel_create_item(panel, PANEL_BUTTON,
  85. X    PANEL_LABEL_IMAGE,    
  86. X        panel_button_image(panel, "Set", 3, mush_font),
  87. X    PANEL_NOTIFY_PROC,    set_ignore,
  88. X    PANEL_CLIENT_DATA,    TRUE,
  89. X    NULL);
  90. X    panel_create_item(panel, PANEL_BUTTON,
  91. X    PANEL_LABEL_IMAGE,    
  92. X        panel_button_image(panel, "Unset", 5, mush_font),
  93. X    PANEL_NOTIFY_PROC,    set_ignore,
  94. X    PANEL_CLIENT_DATA,    FALSE,
  95. X    NULL);
  96. X
  97. X    ignore_msg = panel_create_item(panel, PANEL_MESSAGE,
  98. X    PANEL_LABEL_STRING,
  99. X        "Type name of header to ignore and then <set> or <unset>",
  100. X    NULL);
  101. X
  102. X    ignore_name = panel_create_item(panel, PANEL_TEXT,
  103. X    PANEL_LABEL_STRING,    "Ignored Header:",
  104. X    PANEL_NOTIFY_PROC,    set_ignore,
  105. X    PANEL_CLIENT_DATA,    1,
  106. X    PANEL_VALUE_DISPLAY_LENGTH, 60,
  107. X    NULL);
  108. X    window_fit_height(panel);
  109. X
  110. X    ignore_list_textsw = window_create(ignore_frame, TEXTSW,
  111. X    WIN_BELOW,        panel,
  112. X    WIN_WIDTH,        MY_FRAME_WIDTH,
  113. X    WIN_HEIGHT,        15 * l_height(),
  114. #ifdef SUN_4_0 /* SunOS 4.0+ */
  115. X    TEXTSW_LINE_BREAK_ACTION,    TEXTSW_WRAP_AT_WORD,
  116. #else /* SUN_4_0 */
  117. X    TEXTSW_LINE_BREAK_ACTION,    TEXTSW_WRAP_AT_CHAR,
  118. #endif /* SUN_4_0 */
  119. X    NULL);
  120. X    (void) notify_interpose_event_func(ignore_list_textsw,
  121. X    fkey_interposer, NOTIFY_SAFE);
  122. X
  123. X    window_fit_height(ignore_frame);
  124. X    update_list_textsw(&ignore_hdr);
  125. }
  126. SHAR_EOF
  127. echo 'File misc_frame.c is complete' &&
  128. chmod 0644 misc_frame.c ||
  129. echo 'restore of misc_frame.c failed'
  130. Wc_c="`wc -c < 'misc_frame.c'`"
  131. test 7659 -eq "$Wc_c" ||
  132.     echo 'misc_frame.c: original size 7659, current size' "$Wc_c"
  133. rm -f _shar_wnt_.tmp
  134. fi
  135. # ============= msgs.c ==============
  136. if test -f 'msgs.c' -a X"$1" != X"-c"; then
  137.     echo 'x - skipping msgs.c (File already exists)'
  138.     rm -f _shar_wnt_.tmp
  139. else
  140. > _shar_wnt_.tmp
  141. echo 'x - extracting msgs.c (Text)'
  142. sed 's/^X//' << 'SHAR_EOF' > 'msgs.c' &&
  143. /* @(#)msgs.c    (c) copyright 10/18/86 (Dan Heller) */
  144. X
  145. #include "mush.h"
  146. X
  147. void
  148. display_msg(n, flg)
  149. register int n;
  150. u_long flg;
  151. {
  152. X    char buf[32], *pager = NULL;
  153. X
  154. X    if (ison(msg[n].m_flags, DELETE) && !do_set(set_options, "show_deleted")) {
  155. X    print("Message %d deleted; ", n+1);
  156. #ifdef SUNTOOL
  157. X    if (istool)
  158. X        wprint("Select UNDELETE to read.\n");
  159. X    else
  160. #endif /* SUNTOOL */
  161. X    if (iscurses)
  162. X        print_more("Type 'u' to undelete.");
  163. X    else
  164. X        wprint("Type 'undelete %d' to undelete\n", n+1);
  165. X    return;
  166. X    }
  167. X    set_isread(n);
  168. X    if (ison(flg, M_TOP)) {
  169. X    turnon(flg, NO_HEADER);
  170. X    print("Top of "), turnon(glob_flags, CONT_PRNT);
  171. X    }
  172. X
  173. #ifdef MSG_SEPARATOR
  174. X    turnon(flg, NO_SEPARATOR);
  175. #endif /* MMDF */
  176. X    if (!istool && isoff(flg, NO_PAGE) &&
  177. X        crt < msg[n].m_lines && isoff(flg, M_TOP)) {
  178. X    if (!(pager = do_set(set_options, "pager")))
  179. X        pager = DEF_PAGER;
  180. X    if (!*pager || !strcmp(pager, "internal"))
  181. X        pager = NULL; /* default to internal pager if pager set to "" */
  182. X    }
  183. X    (void) do_pager(pager, TRUE); /* start pager */
  184. X    (void) do_pager(sprintf(buf, "Message #%d (%d lines)\n",
  185. X             n+1, msg[n].m_lines), FALSE);
  186. X    (void) copy_msg(n, NULL_FILE, flg, NULL);
  187. X    (void) do_pager(NULL, FALSE); /* end pager */
  188. }
  189. X
  190. /*
  191. X * copy message 'n' to file "fp" according to various flag arguments
  192. X * return number of lines copied or -1 if system error on fputs.
  193. X * If "fp" is null, send to internal pager.  This can only happen from
  194. X * display_msg above.
  195. X */
  196. copy_msg(n, fp, flags, pattern)
  197. register int n;
  198. register FILE *fp;
  199. u_long flags;
  200. char *pattern;
  201. {
  202. X    register int  ignoring = 0, lines = 0;
  203. X    register char *indent_str, *p, *end_pat = NULL;
  204. X    int          on_hdr = 1, top, squeeze = 0;
  205. X    long      still_more = 0;
  206. X    int          pat_len, pat_seek;
  207. X    char       line[BUFSIZ], *show_hdrs = NULL;
  208. X
  209. X    if (ison(flags, M_TOP)) {
  210. X    p = do_set(set_options, "toplines");
  211. X    top = (p)? atoi(p) : crt;
  212. X    }
  213. X    /* When updating to a folder, always write all headers! */
  214. X    if (ison(flags, UPDATE_STATUS))
  215. X    turnon(flags, NO_IGNORE);
  216. X    else if (ison(flags, NO_IGNORE) &&
  217. X        (p = do_set(set_options, "alwaysignore")) && !*p)
  218. X    turnoff(flags, NO_IGNORE);    /* preserve historic behavior */
  219. X    if (isoff(flags, NO_IGNORE)) {
  220. X    if (do_set(set_options, "squeeze"))
  221. X        squeeze = 1;
  222. X    show_hdrs = do_set(set_options, "show_hdrs");
  223. X    }
  224. X    if (pattern && *pattern == '/' && (end_pat = index(pattern+1, '/'))) {
  225. X    if (end_pat[1] == ',') {
  226. X        pattern++;
  227. X        *end_pat++ = 0;
  228. X    } else
  229. X        end_pat = NULL;
  230. X    }
  231. X    pat_len = pattern? strlen(pattern) : 0;
  232. X    pat_seek = !!pat_len;
  233. X
  234. #ifdef SUNTOOL
  235. X    xfree(more_prompt), more_prompt = NULL;
  236. #endif /* SUNTOOL */
  237. X
  238. X    if (ison(flags, INDENT)) {
  239. X    if ((indent_str = do_set(set_options, "pre_indent_str"))) {
  240. X        fputs(format_hdr(n, indent_str, FALSE) + 9, fp); /* magic 9 !! */
  241. X        fputc('\n', fp);
  242. X    }
  243. X    if (!(indent_str = do_set(set_options, "indent_str")))
  244. X        indent_str = DEF_INDENT_STR;
  245. X    indent_str = format_hdr(n, indent_str, FALSE) + 9; /* magic 9 !! */
  246. X    }
  247. X    /* "line" used as dummy here, since 0 bytes read */
  248. X    if (!msg_get(n, line, 0)) {
  249. X    error("Unable to find msg %d", n+1);
  250. X    return -1;
  251. X    }
  252. X    while (still_more < msg[n].m_size && fgets(line, sizeof (line), tmpf)) {
  253. X    still_more += strlen(line);
  254. #ifdef MSG_SEPARATOR
  255. X    if (ison(flags, NO_SEPARATOR)) {
  256. #ifdef MMDF
  257. X        if (!strncmp(line, MSG_SEPARATOR, 4))
  258. #else /* !MMDF */
  259. X        if (!strncmp(line, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
  260. #endif /* MMDF */
  261. X        continue;
  262. X    }
  263. #endif /* MMDF */
  264. X    /*
  265. X     * If squeeze is one, all blanks lines squeeze down to one blank line.
  266. X     * If squeeze is two, squeezing is in progress so wait for the next \n.
  267. X     */
  268. X    if (*line == '\n') {
  269. X        if (on_hdr) {  /* blank line -- end of header */
  270. X        on_hdr = 0;
  271. X        if (ison(flags, NO_HEADER))
  272. X            continue;
  273. X        }
  274. X        if (squeeze > 1 || pat_len && pat_seek)
  275. X        continue;
  276. X        else if (squeeze)
  277. X        squeeze = 2;
  278. X    } else {
  279. X        if (squeeze > 1)
  280. X        squeeze = 1;
  281. X        if (pat_len && (!on_hdr || isoff(flags, NO_HEADER))) {
  282. X        /* If we're looking for a pattern for mush-pipe, then
  283. X         * continue if this line doesn't match the pattern.
  284. X         */
  285. X        if (pat_len == 0)
  286. X            continue;
  287. X        Debug("Seeking (%s) in (%s)", pattern, line);
  288. X        if (strncmp(line, pattern, pat_len)) {
  289. X            if (pat_seek)
  290. X            continue;
  291. X        } else if (end_pat && *end_pat++ == ',') {
  292. X            pattern = end_pat;
  293. X            if (*pattern == '/') {
  294. X            pattern++;
  295. X            if (end_pat = index(pattern, '/'))
  296. X                *end_pat++ = 0;
  297. X            }
  298. X            pat_len = pattern? strlen(pattern) : 0;
  299. X            pat_seek = !pat_seek;
  300. X        } else {
  301. X            pat_len = 0;
  302. X            pat_seek = !pat_seek;
  303. X        }
  304. X        }
  305. X    }
  306. X
  307. X    if (ison(flags, UPDATE_STATUS))
  308. X        if (!strncmp(line, "Status:", 7) || !strncmp(line, "Priority:", 9))
  309. X        continue; /* ignore "Status" and "Priority" lines */
  310. X        else if (!on_hdr) {
  311. X        int i, write_priority = 0;
  312. X        p = line;
  313. X        p += Strcpy(p, "Priority:");
  314. X        for (i = 0; i < MAX_PRIORITY; i++)
  315. X            if (ison(msg[n].m_flags, M_PRIORITY(i + 1))) {
  316. X            write_priority = 1;
  317. X            *p++ = ' ';
  318. X            *p++ = i + 'A';
  319. X            }
  320. X        if (write_priority) {
  321. X            *p++ = '\n', *p = 0;
  322. X            (void) fputs(line, fp);
  323. X        }
  324. X        /* PRESERVE here avoids changing new message status */
  325. X        if (isoff(flags, PRESERVE) || /* NOT msg[n].m_flags */
  326. X            ison(msg[n].m_flags, OLD) ||
  327. X            isoff(msg[n].m_flags, UNREAD)) {
  328. X            p = line;
  329. X            p += Strcpy(p, "Status: O");
  330. X            if (isoff(msg[n].m_flags, UNREAD))
  331. X            *p++ = 'R';
  332. X            if (ison(msg[n].m_flags, SAVED))
  333. X            *p++ = 'S';
  334. X            if (ison(msg[n].m_flags, REPLIED))
  335. X            *p++ = 'r';
  336. X            if (ison(msg[n].m_flags, PRINTED))
  337. X            *p++ = 'p';
  338. X            if (ison(msg[n].m_flags, FORWARD))
  339. X            *p++ = 'f';
  340. X            *p++ = '\n', *p = 0;
  341. X            (void) fputs(line, fp);
  342. X        }
  343. X        turnoff(flags, UPDATE_STATUS);
  344. X        line[0] = '\n', line[1] = '\0';
  345. X        }
  346. X    if (on_hdr && (isoff(flags, NO_IGNORE) || ison(flags, FORWARD))) {
  347. X        p = any(line, " \t:");
  348. X        if (!p)
  349. X        ignoring = 0, on_hdr = 0;
  350. X        else if (ignoring)
  351. X        if (*p != ':') {
  352. X            Debug("Ignoring: %s", line);
  353. X            continue;
  354. X        } else
  355. X            ignoring = 0;
  356. X        if (p && *p == ':') {
  357. X        *p = 0;
  358. X        ignoring = 0;
  359. X        if (ison(flags, FORWARD)) {
  360. X            if (chk_two_lists(line, IGNORE_ON_FWD, ":, \t"))
  361. X            ignoring = 1;
  362. X        } else if (show_hdrs) {
  363. X            if (!chk_two_lists(line, show_hdrs, ":, \t"))
  364. X            ignoring = 1;
  365. X        } else {
  366. X            register struct options *opts;
  367. X            for (opts = ignore_hdr; opts; opts = opts->next)
  368. X            if (!lcase_strncmp(opts->option, line, -1)) {
  369. X                ignoring = 1;
  370. X                break;
  371. X            }
  372. X        }
  373. X        *p = ':';
  374. X        if (ignoring) {
  375. X            Debug("Ignoring: %s", line);
  376. X            continue;
  377. X        }
  378. X        }
  379. X    }
  380. X    if (!on_hdr && ison(flags, M_TOP) && !--top)
  381. X        break;
  382. X    if (!on_hdr && (still_more < msg[n].m_size || line[0] != '\n') ||
  383. X        isoff(flags, NO_HEADER)) {
  384. X        /* note that function returns the number of lines */
  385. X        lines++;
  386. X        if (ison(flags, INDENT))
  387. X        (void) fputs(indent_str, fp);
  388. X        if (!fp) {
  389. X        if (do_pager(line, FALSE) == EOF)
  390. X            return -1;
  391. X        } else if (fputs(line, fp) == EOF)
  392. X        /* Pipe broken, out of file space, etc */
  393. X        return -1;
  394. X    }
  395. X    if (pat_seek && !pat_len)
  396. X        break; /* Skip the rest */
  397. X    }
  398. X    if (ison(flags, INDENT) &&
  399. X    (indent_str = do_set(set_options, "post_indent_str")) && *indent_str) {
  400. X    (void) fprintf(fp, "%s\n", format_hdr(n, indent_str, FALSE)+9);
  401. X    }
  402. X    if (fp && fflush(fp) == EOF)
  403. X    return -1;    /* Write failure? */
  404. X    return lines;
  405. }
  406. X
  407. /*
  408. X * copy tempfile back to folder.
  409. X * Return 1 on success, 0 on failure.
  410. X */
  411. copyback(prompt, final)
  412. char *prompt;
  413. int final;    /* Are we exiting or updating? */
  414. {
  415. X    register int    i = 0, held = 0, saved = 0;
  416. X    register u_long    flg = 0;
  417. X    register FILE    *mbox = NULL_FILE, *mail_fp = NULL_FILE;
  418. #ifdef SYSV
  419. X    FILE         *save_mail_fp = NULL_FILE;
  420. #endif /* SYSV */
  421. X    char        *mbox_file, action = 0;
  422. X    int         hold = 0, delete_it = 0, dont_unlink = !final;
  423. X    int            isspool, keepsave, write_err = FALSE;
  424. X    static int        first = 1;
  425. X
  426. X    /*
  427. X     * if there is new mail in this folder, the user is notified and
  428. X     * prompted if he really wants to update the folder.  He's either
  429. X     * quitting or changing folders, so let him read the new mail first.
  430. X     */
  431. X    if (!first && mail_size()) {
  432. lost_lock:
  433. X    if ((ison(glob_flags, CORRUPTED) || get_new_mail(TRUE)) &&
  434. X        prompt && isoff(glob_flags, REDIRECT) && show_new_mail()) {
  435. X        char buf[80];
  436. X        if (iscurses)
  437. X        putchar('\n'), turnon(glob_flags, CNTD_CMD);
  438. X        if (!istool)
  439. X        print("%s [n] ", prompt);
  440. X        buf[0] = 0;
  441. #ifdef SUNTOOL
  442. X        if (istool) {
  443. X        (void) sprintf(buf, "%s -- %s",
  444. X            ison(glob_flags, CORRUPTED) ? "Error" : "New mail",
  445. X            prompt);
  446. X        if (ask(buf) != TRUE)
  447. X            return 0;
  448. X        } else
  449. #endif /* SUNTOOL */
  450. X        if (!Getstr(buf, sizeof (buf), 0) || lower(*buf) != 'y')
  451. X            return 0;
  452. X        turnoff(glob_flags, CORRUPTED); /* User says go ahead */
  453. X    }
  454. X    }
  455. X    first = 0;
  456. X
  457. X    /* If the user hasn't changed anything, just return true */
  458. X    if (isoff(glob_flags, DO_UPDATE) || ison(glob_flags, CORRUPTED))
  459. X    return 1;
  460. X    if (ison(glob_flags, READ_ONLY)) {
  461. X    print("Unable to update %s: read only\n", mailfile);
  462. X    return 0; /* user should use "exit" instead of "quit". */
  463. X    }
  464. X    if (!msg_cnt) /* prevent unnecessary overwrite */
  465. X    return 1;
  466. X
  467. #ifdef SUNTOOL
  468. X    if (istool) {
  469. X    (void) notify_set_itimer_func(tool, do_check,
  470. X        ITIMER_REAL, (struct itimerval *) 0, (struct itimerval *) 0);
  471. X    }
  472. #endif /* SUNTOOL */
  473. X
  474. X    /* We can't lock a file unless we have an fd, but "w+" will zero
  475. X     * the file.  If the lock later failed for any reason (possible
  476. X     * race condition with an MTA), we would lose all current mail.
  477. X     * So, open read/write (if possible) and truncate later.
  478. X     */
  479. X    if (!(mail_fp = lock_fopen(mailfile, "r+"))) {
  480. X    error("WARNING: unable to lock %s -- update aborted", mailfile);
  481. #ifdef SUNTOOL
  482. X    if (istool) {
  483. X        write_err = 1;    /* forces return 0; below */
  484. X        goto resume_timer;    /* blecch */
  485. X    }
  486. #else /* !SUNTOOL */
  487. X    return 0;
  488. #endif /* SUNTOOL */
  489. X    }
  490. X    /* Make sure no mail arrived between the last check and when we
  491. X     * got the lock.  If it did, release the lock and try again.
  492. X     */
  493. X    if (mail_size()) {
  494. X    (void) close_lock(mailfile, mail_fp);
  495. X    goto lost_lock;
  496. X    }
  497. X
  498. X    /* open mbox if: "autodelete" AND "hold" are NOT set. */
  499. X    if (!strcmp(mailfile, spoolfile)
  500. X        && !(delete_it = !!do_set(set_options, "autodelete"))
  501. X        && !(hold = !!do_set(set_options, "hold"))) {
  502. X    register char *p;
  503. X    int x = 1; /* tell getpath to ignore "ENOENT" if file not found */
  504. X
  505. X    if (!(p = do_set(set_options, "mbox")))
  506. X        p = DEF_MBOX;
  507. X    mbox_file = getpath(p, &x); /* static data -- copy? */
  508. X    if (x) {
  509. X        if (x > 0)
  510. X        print("%s is a directory.\n", mbox_file);
  511. X        else
  512. X        print("Unable to open %s: %s\n", p, mbox_file);
  513. X        mbox = NULL_FILE;
  514. X    } else {
  515. X        if (Access(mbox_file, F_OK) == -1) /* does it exist? */
  516. X        mbox = lock_fopen(mbox_file, "w");
  517. X        else
  518. X        mbox = lock_fopen(mbox_file, "a");
  519. X        if (!mbox)
  520. X        error("Unable to write to %s", mbox_file);
  521. X    }
  522. X    }
  523. X
  524. X    /* ignore signals before truncating */
  525. X    turnon(glob_flags, IGN_SIGS);
  526. #ifdef SYSV
  527. X    /* SysV can't truncate a file in the middle, so we can't just
  528. X     * write to mail_fp and close.  Instead, we save the mail_fp
  529. X     * and reopen for writing, ignoring our own lock.  After updating,
  530. X     * we can safely fclose both file pointers.
  531. X     */
  532. X    save_mail_fp = mail_fp;
  533. X    /* This could fail if we run out of file descriptors */
  534. X    if (!(mail_fp = fopen(mailfile, "w"))) {
  535. X    error("WARNING: unable to reopen %s for update", mailfile);
  536. X    if (save_mail_fp)
  537. X        (void) close_lock(mailfile, save_mail_fp);
  538. X    if (mbox)
  539. X        (void) close_lock(mbox_file, mbox);
  540. X    turnoff(glob_flags, IGN_SIGS);
  541. X    return 0;
  542. X    }
  543. #endif /* SYSV */
  544. X
  545. X    print("Updating \"%s\"", mailfile);
  546. X
  547. X    turnon(flg, UPDATE_STATUS);
  548. X    /* Don't set OLD for new messages on update. */
  549. X    if (!final)
  550. X    turnon(flg, PRESERVE);
  551. X
  552. X    keepsave = !!do_set(set_options, "keepsave");
  553. X    isspool = !strcmp(mailfile, spoolfile);
  554. X
  555. X    for (i = 0; i < msg_cnt; i++) {
  556. X    /* Maintain the current message across update; if this turns out
  557. X     * to be unnecessary (changing folders), folder() will reset it.
  558. X     */
  559. X    if (current_msg == i)
  560. X        current_msg = held;
  561. X    /* Check to see if message is marked for deletion or, if read and not
  562. X     * preserved, delete it if autodelete is set.  Otherwise, if hold is
  563. X     * set save the message in the spool file.  If all fails, save in mbox.
  564. X     */
  565. X    if (ison(msg[i].m_flags, DELETE)
  566. X    ||  ison(msg[i].m_flags, SAVED) && !keepsave &&
  567. X        isoff(msg[i].m_flags, PRESERVE) && isspool
  568. X    ||  isoff(msg[i].m_flags, UNREAD) && isoff(msg[i].m_flags, PRESERVE) 
  569. X        && delete_it) {
  570. X        Debug("%s %d",
  571. X        (action!='d')? "\ndeleting message:" : "", i+1), action = 'd';
  572. X        continue;
  573. X    } else if (isoff(msg[i].m_flags, DO_UPDATE) || hold || !mbox ||
  574. X        ison(msg[i].m_flags, UNREAD) ||
  575. X        ison(msg[i].m_flags, PRESERVE)) {
  576. X        Debug("%s %d",
  577. X        (action!='s')? "\nsaving in spool:" : "", i+1), action = 's';
  578. X        if (copy_msg(i, mail_fp, flg, NULL) == -1) {
  579. X        error("WARNING: unable to write back to spool");
  580. X        print_more("ALL mail left in %s\n", tempfile);
  581. X        print_more("Spool mailbox may be corrupted.\n");
  582. X        dont_unlink = TRUE;
  583. X        write_err = TRUE;
  584. X        break;
  585. X        }
  586. X        held++;
  587. X    } else if (isspool) {   /* copy back to mbox */
  588. X        if (copy_msg(i, mbox, flg, NULL) == -1) {
  589. X        error("WARNING: unable to write to mbox");
  590. X        print_more("Unresolved mail left in %s\n", tempfile);
  591. X        dont_unlink = TRUE;
  592. X        write_err = TRUE;
  593. X        break;
  594. X        }
  595. X        saved++;
  596. X        Debug("%s %d",
  597. X        (action!='m')? "\nsaving in mbox:" : "", i+1), action = 'm';
  598. X    }
  599. X    }
  600. X    if (write_err)
  601. X    current_msg = 0;
  602. X    else if (current_msg == held)
  603. X    current_msg--;    /* Don't point to a message that got deleted */
  604. X    Debug("\n%s", mailfile);
  605. X
  606. #ifdef SYSV
  607. X    /* Close the write file pointer first */
  608. X    (void) fclose(mail_fp);
  609. X    mail_fp = save_mail_fp;
  610. #else /* !SYSV */
  611. X    /* Truncate the file at the end of what we just wrote.
  612. X     * If you aren't SYSV and you still can't ftruncate(),
  613. X     * you're out of luck?
  614. X     */
  615. X    (void) ftruncate(fileno(mail_fp), ftell(mail_fp));
  616. #endif /* SYSV */
  617. X
  618. X    /* some users like to have zero length folders for frequent usage */
  619. X    if (mbox && close_lock(mbox_file, mbox) == EOF) {
  620. X    error("WARNING: unable to close mbox");
  621. X    print_more("Unresolved mail left in %s\n", tempfile);
  622. X    dont_unlink = TRUE;
  623. X    write_err = TRUE;
  624. X    }
  625. X    if (held) {
  626. X    print_more(": saved %d message%s\n", held, (held==1)? NO_STRING: "s");
  627. X    } else
  628. #ifdef HOMEMAIL
  629. X    if (!dont_unlink && !do_set(set_options, "save_empty"))
  630. #else /* HOMEMAIL */
  631. X    if (strcmp(mailfile, spoolfile) && !dont_unlink &&
  632. X    !do_set(set_options, "save_empty"))
  633. #endif /* HOMEMAIL */
  634. X    if (unlink(mailfile))
  635. X        turnon(glob_flags, CONT_PRNT), error(": cannot remove");
  636. X    else {
  637. X        print_more(": removed\n");
  638. X        held = -1;
  639. X    }
  640. X    else
  641. X    print_more(": empty\n");
  642. X    if (saved)
  643. X    print("saved %d message%s in %s\n",
  644. X                saved,(saved==1)? NO_STRING:"s", mbox_file);
  645. X
  646. X    if (held > 0) {
  647. X    /* Reset the access time of the spool file to prevent
  648. X     * bogus "new mail" messages from the shell.
  649. X     */
  650. X    long times[2];
  651. X    (void) fflush(mail_fp); /* just in case */
  652. X    times[1] = time(×[0]) - (long)2;
  653. X    if (!strcmp(mailfile, spoolfile) && utime(mailfile, times))
  654. X        error("utime");
  655. X    }
  656. X
  657. X    if (close_lock(mailfile, mail_fp) == EOF) {
  658. X    error("WARNING: unable to close spool");
  659. X    print_more("ALL mail left in %s\n", tempfile);
  660. X    print_more("Spool mailbox may be corrupted.\n");
  661. X    write_err = TRUE;
  662. X    }
  663. X
  664. #ifdef SUNTOOL
  665. X    if (istool) {
  666. resume_timer:
  667. X    mail_timer.it_value.tv_sec = time_out;
  668. X    mail_timer.it_interval.tv_sec = time_out;
  669. X    (void) notify_set_itimer_func(tool, do_check,
  670. X        ITIMER_REAL, &mail_timer, (struct itimerval *) 0);
  671. X    }
  672. #endif /* SUNTOOL */
  673. X
  674. X    turnoff(glob_flags, IGN_SIGS);
  675. X
  676. X    /* Return nonzero for success, -1 if file removed */
  677. X    if (write_err)
  678. X    return 0;
  679. X    else if (held < 0)
  680. X    return -1;
  681. X    else
  682. X    return 1;
  683. }
  684. X
  685. /*
  686. X * check the sizes of the current folder (file) and the spool file.
  687. X * spool_size is the size in bytes of the user's main mailbox.
  688. X * last_size is the size of the _current_ folder the last time we checked.
  689. X * return true if the current folder has new mail.  check_new_mail() checks
  690. X * for new mail in the system mailbox since it checks against last_spool_size.
  691. X */
  692. mail_size()
  693. {
  694. X    struct stat buf;
  695. X
  696. X    if (!stat(spoolfile, &buf))
  697. X    spool_size = buf.st_size;
  698. X    else if (!strcmp(mailfile, spoolfile))
  699. X    return 0;
  700. X    if (!is_shell || ison(glob_flags, IS_SENDING))
  701. X    return 0;
  702. X    if (strcmp(mailfile, spoolfile) && stat(mailfile, &buf)) {
  703. X    if (errno != ENOENT)
  704. X        error("Unable to stat %s", mailfile);
  705. X    return 0;
  706. X    }
  707. X    if (buf.st_size != last_size) {
  708. X    last_size = buf.st_size;
  709. X    return 1;
  710. X    }
  711. X    return 0;
  712. }
  713. X
  714. static
  715. struct mailstat {
  716. X    int new, unread, deleted;
  717. } mail_stat;
  718. X
  719. void
  720. mail_status(as_prompt)
  721. {
  722. X    char buf[MAXPATHLEN];
  723. X    register int cnt;
  724. X
  725. X    mail_stat.new = mail_stat.unread = mail_stat.deleted = 0;
  726. X
  727. X    for (cnt = 0; cnt < msg_cnt; cnt++) {
  728. X    if (ison(msg[cnt].m_flags, UNREAD))
  729. X        mail_stat.unread++;
  730. X    if (ison(msg[cnt].m_flags, DELETE))
  731. X        mail_stat.deleted++;
  732. X    if (isoff(msg[cnt].m_flags, OLD))
  733. X        mail_stat.new++;
  734. X    }
  735. X    if (as_prompt) {
  736. X    /* use %s in case prompt has any %'s in it */
  737. X    print("%s", format_prompt(current_msg, prompt));
  738. X    return;
  739. X    }
  740. X    (void) sprintf(buf,"\"%s\"%s: %d message%s, %d new, %d unread",
  741. X    trim_filename(mailfile),
  742. X    ison(glob_flags, READ_ONLY)? " [read only]" : "",
  743. X    msg_cnt, (msg_cnt != 1)? "s": NO_STRING,
  744. X    mail_stat.new, mail_stat.unread);
  745. X    if (istool || iscurses)
  746. X    (void) sprintf(buf+strlen(buf), ", %d deleted", mail_stat.deleted);
  747. #ifdef SUNTOOL
  748. X    if (istool) {
  749. X    static char ic_text[4];
  750. X    char *lbl;
  751. X    Icon icon;
  752. X    extern struct pixrect mail_icon_image1, mail_icon_image2;
  753. X    (void) sprintf(ic_text, "%3d", msg_cnt);
  754. X    if (!(lbl = (char *)window_get(tool, FRAME_LABEL)) || strcmp(lbl, buf))
  755. X        (void) window_set(tool, FRAME_LABEL, buf, NULL);
  756. X    icon = (Icon) window_get(tool, FRAME_ICON);
  757. X    (void) icon_set(icon,
  758. X        ICON_IMAGE, ison(glob_flags, NEW_MAIL)?
  759. X                &mail_icon_image2 : &mail_icon_image1,
  760. X        NULL);
  761. X    if (!chk_option("quiet", "iconlabel"))
  762. X        (void) icon_set(icon, ICON_LABEL, ic_text, NULL);
  763. X    else
  764. X        (void) icon_set(icon, ICON_LABEL, NO_STRING, NULL);
  765. X    (void) window_set(tool, FRAME_ICON, icon, NULL);
  766. X    } else
  767. #endif /* SUNTOOL */
  768. X
  769. #ifdef CURSES
  770. X    if (iscurses) {
  771. X        move (0, 0);
  772. X        printw("%-3d %-.*s",
  773. X        ((msg_cnt)? current_msg+1 : 0), COLS-5, buf), clrtoeol();
  774. X    } else
  775. #endif /* CURSES */
  776. X        puts(buf);
  777. X    return;
  778. }
  779. X
  780. /*
  781. X * Construct a prompt for the given message number using the given format
  782. X */
  783. char *
  784. format_prompt(num, fmt)
  785. int num;
  786. char *fmt;
  787. {
  788. X    static char buf[MAXPATHLEN];
  789. X    register char *p, *b = buf, *mf;
  790. X
  791. X    if (is_shell)
  792. X    mf = mailfile;
  793. X    else
  794. X    mf = "[no folder]";
  795. X
  796. X    for (p = fmt; *p; p++)
  797. X    if (*p == '\\')
  798. X        switch (*++p) {
  799. X        case 'n': case 'r': *b++ = '\n';
  800. X        when 't': *b++ = '\t';
  801. X        otherwise: *b++ = *p;
  802. X        }
  803. X    else if (*p == '%')
  804. X        switch (*++p) {
  805. X        case 'm':
  806. X            b += strlen(sprintf(b,"%d",(msg_cnt)? num + 1 : 0));
  807. X        when 't':
  808. X            b += strlen(sprintf(b, "%d", msg_cnt));
  809. X        when 'd':
  810. X            b += strlen(sprintf(b, "%d", mail_stat.deleted));
  811. X        when 'u':
  812. X            b += strlen(sprintf(b, "%d", mail_stat.unread));
  813. X        when 'n':
  814. X            b += strlen(sprintf(b, "%d", mail_stat.new));
  815. X        when 'f':
  816. X        {
  817. X            char *tail = rindex(mf, '/'); 
  818. X            if (tail && tail[1])
  819. X            b += Strcpy(b, tail+1);
  820. X            else {
  821. X            /* Fall through */
  822. X        case 'F':
  823. X            b += Strcpy(b, mf);
  824. X            }
  825. X            if (ison(glob_flags, READ_ONLY))
  826. X            b += Strcpy(b, " [read-only]");
  827. X        }
  828. X        when 'T': case 'D': case 'Y': case 'y':
  829. X        case 'M': case 'N': case 'W':
  830. X            b += Strcpy(b, Time(p, (long)0));
  831. X        when '$':
  832. X        {
  833. X            struct expand var;
  834. X            var.orig = p;
  835. X            if (varexp(&var)) {
  836. X            b += Strcpy(b, var.exp);
  837. X            xfree(var.exp);
  838. X            p = var.rest - 1;
  839. X            }
  840. X        }
  841. X        otherwise: *b++ = *p;
  842. X        }
  843. X    else if (*p == '!')
  844. X        b += strlen(sprintf(b, "%d", hist_no+1));
  845. X    else
  846. X        *b++ = *p;
  847. X    *b = 0;
  848. X    return buf;
  849. }
  850. X
  851. /*
  852. X *  For uucp mailers that use >From lines with "remote from <path>":
  853. X * (where "path" is a hostname or pathnames)
  854. X *
  855. X *  a. Set the return_path to the empty string.
  856. X *  b. For each From_ or >From_ line:
  857. X *  c. Save the username (second token).
  858. X *  d. Save the date (3-7 tokens).
  859. X *  e. If it has a "remote from" then append the remote host
  860. X *    (last token) followed by a "!" to the return_path.
  861. X *  f. If the saved username has a '@' but no '!' then convert it
  862. X *    to UUCP path form.
  863. X *  g. Append the saved username to return_path.
  864. X */
  865. parse_from(fp, path)
  866. FILE *fp;
  867. char path[];
  868. {
  869. X    char user[256], buf[256]; /* max size for each line in a mail file */
  870. X    register char *p;
  871. X    long save_offset = ftell(fp);
  872. X
  873. X    path[0] = '\0';
  874. X    while (fgets(buf, sizeof buf, fp)) {
  875. X    if (strncmp(buf, ">From ", 6))
  876. X        break;
  877. X    p = buf + 6;
  878. X
  879. X    (void) sscanf(p, "%s", user);
  880. X
  881. X    while (p = index(p+1, 'r')) {
  882. X        if (!strncmp(p, "remote from ", 12)) {
  883. X        char *p2 = path+strlen(path);
  884. X        skipspaces(12);
  885. X        (void) sscanf(p, "%s", p2); /* add the new machine to current path */
  886. X        (void) strcat(p2, "!");
  887. X        break;
  888. X        }
  889. X    }
  890. X
  891. X    if (p)
  892. X        (void) bang_form(path + strlen(path), user);
  893. X    save_offset = ftell(fp);
  894. X    }
  895. X    (void) fseek(fp, save_offset, L_SET);
  896. }
  897. X
  898. /*
  899. X * Scan a file and select messages from it and append them to the current folder
  900. X *
  901. X * If "append" is 1, start where we left off (held in msg[cnt].m_offset)
  902. X * and scan for messages.  Append all messages found until EOF.
  903. X *
  904. X * If "append" is 2, we're merging in a new file, so start at the end of
  905. X * the present folder and append all messages found until EOF.
  906. X *
  907. X * If "append" is 0, then the message separator must exist once and
  908. X * only once.  All extra occurrences of the separator is preceded by a '>'.
  909. X * The list argument will be the message number to replace in the current
  910. X * folder with the message read in from other filename.
  911. X */
  912. load_folder(file, append, list)
  913. char *file, *list;
  914. int append;
  915. {
  916. X    char    buf[BUFSIZ];
  917. X    int        lines = 0, msg_found = 0, had_error = 1;
  918. X    int        get_status = 1, cnt;
  919. X    long    bytes, ftell();
  920. X    struct msg  old;
  921. X    char    *p, date[64];
  922. X    FILE    *fp;
  923. X    int         warn = ison(glob_flags, WARNING);
  924. #ifdef MMDF
  925. X    int        begin_sep = 0; /* track beginning vs ending separators */
  926. #endif /* MMDF */
  927. X
  928. X    if (!(fp = lock_fopen(file, "r"))) {
  929. X    error("Unable to open %s", file);
  930. X    return -1;
  931. X    }
  932. X
  933. X    if (append) {
  934. X    cnt = msg_cnt;
  935. X    (void) fseek(fp, append == 1 ? msg[cnt].m_offset : 0L, L_SET);
  936. X    } else {
  937. X    cnt = (int)list;
  938. X    old = msg[cnt];
  939. X    }
  940. X
  941. X    if (isoff(glob_flags, READ_ONLY)) {
  942. X    if (tmpf)
  943. X        (void) fclose(tmpf);
  944. X    if (!(tmpf = mask_fopen(tempfile, "a"))) {
  945. X        error("Unable to open %s for appending", tempfile);
  946. X        close_lock(file, fp);
  947. X        return -1;
  948. X    }
  949. X    (void) fseek(tmpf, 0L, 2); /* assure we're at the end of the file */
  950. X    } else if (append == 2) {
  951. X    /* you can't merge in a folder to a read-only folder */
  952. X    close_lock(file, fp);
  953. X    return -1;
  954. X    }
  955. X
  956. #ifdef MMDF
  957. X    if (!append) {
  958. X    (void) strcpy(buf, MSG_SEPARATOR);
  959. X    goto do_headers;
  960. X    }
  961. #endif /* MMDF */
  962. X    buf[0] = 0;
  963. X    while (fgets(buf, sizeof (buf), fp)) {
  964. #ifndef MSG_SEPARATOR
  965. X    turnoff(glob_flags, WARNING);
  966. X    if (!strncmp(buf, "From ", 5)) {
  967. X        p = buf + 5;    /* skip "From " */
  968. X        skipspaces(0);
  969. X        p = any(p, " \t");    /* skip the address */
  970. X    } else
  971. X        p = buf;
  972. X    if (p > buf && (p = parse_date(p + 1)) && strcpy(date, p))
  973. #else /* MSG_SEPARATOR */
  974. X    if (!strncmp(buf, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
  975. #endif /* MSG_SEPARATOR */
  976. X    {
  977. #ifdef MMDF
  978. X        if (!append)
  979. X        (void) fputc('>', tmpf);
  980. X        else if (begin_sep = !begin_sep)
  981. do_headers:
  982. #else /* MMDF */
  983. X        if (!append && msg_found)
  984. X        (void) fputc('>', tmpf);
  985. X        else
  986. #endif /* MMDF */
  987. X        {
  988. X        msg_found++;
  989. X        had_error = 0;
  990. X        if (append && cnt == MAXMSGS-append) {
  991. X            wprint("WARNING: exceeded %d messages.\n", MAXMSGS-append);
  992. X            wprint("Not all messages have been loaded.\n");
  993. X            msg_cnt--;
  994. X            had_error++;
  995. X            break;
  996. X        }
  997. X        if (ison(glob_flags, READ_ONLY))
  998. X            bytes = ftell(fp) - strlen(buf);
  999. X        else {
  1000. X            char path[256];
  1001. X            parse_from(fp, path);
  1002. X            if (path[0])
  1003. X            (void)sprintf(buf,"From %s %s", path,
  1004. X                        date_to_ctime(date));
  1005. X            bytes = ftell(tmpf);
  1006. X        }
  1007. X        /* finish up message structure from previous message.
  1008. X         * if this is incorporating new mail, check "lines" to
  1009. X         * see if previous message has already been set!
  1010. X         */
  1011. X        if (cnt && lines) {
  1012. X            msg[cnt-1].m_size = bytes - msg[cnt-1].m_offset;
  1013. X            msg[cnt-1].m_lines = lines;
  1014. X        }
  1015. X        if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) {
  1016. X            error(tempfile);
  1017. X            had_error++;
  1018. X            break;
  1019. X        }
  1020. X        msg[cnt].m_offset = bytes;
  1021. X        msg[cnt].m_flags = 0L;
  1022. #ifdef MSG_SEPARATOR
  1023. X        lines = 0;
  1024. #else /* MSG_SEPARATOR */
  1025. X        lines = 1; /* count the From_ line */
  1026. X        if (warn)
  1027. X            turnon(glob_flags, WARNING);
  1028. X        strdup(msg[cnt].m_date_recv, date);
  1029. #endif /* MSG_SEPARATOR */
  1030. X        turnon(msg[cnt].m_flags, UNREAD); /* initialize */
  1031. X        /* we've read the "From " line(s), now read the rest of
  1032. X         * the message headers till we get to a blank line.
  1033. X         */
  1034. X        while (fgets(buf, sizeof (buf), fp) && (*buf != '\n')) {
  1035. X            p = buf;
  1036. X            if (!strncmp(buf, "Date:", 5))
  1037. X            strdup(msg[cnt].m_date_sent, parse_date(p+5));
  1038. X            if (!strncmp(buf, "Priority:", 9)) {
  1039. X            for (p += 9 ; *p != '\n'; p++) {
  1040. X                if (!isalpha(*p) || upper(*p) > 'A' + MAX_PRIORITY)
  1041. X                continue;
  1042. X                turnon(msg[cnt].m_flags,
  1043. X                M_PRIORITY(upper(*p) - 'A' + 1));
  1044. X            }
  1045. X            }
  1046. X            if (get_status &&
  1047. X                !(get_status = strncmp(p, "Status:", 7))) {
  1048. X            /* new mail should not have a Status: field! */
  1049. X            turnon(msg[cnt].m_flags, OLD);
  1050. X            for (p += 7 ; *p != '\n'; p++) {
  1051. X                if (isspace(*p))
  1052. X                continue;
  1053. X                switch(*p) {
  1054. X                case 'R': turnoff(msg[cnt].m_flags, UNREAD);
  1055. X                when 'P': turnon(msg[cnt].m_flags, UNREAD);
  1056. X                when 'N': turnon(msg[cnt].m_flags, UNREAD);
  1057. X                      turnoff(msg[cnt].m_flags, OLD);
  1058. X                when 'S': turnon(msg[cnt].m_flags, SAVED);
  1059. X                when 'r': turnon(msg[cnt].m_flags, REPLIED);
  1060. X                when 'O': ; /* do nothing */
  1061. X                when 'f': turnon(msg[cnt].m_flags, FORWARD);
  1062. X                when 'p': turnon(msg[cnt].m_flags, PRINTED);
  1063. X                otherwise :
  1064. X                    if (ison(glob_flags, WARNING))
  1065. X                    print("unknown msg status flag: %c\n",
  1066. X                        *p);
  1067. X                }
  1068. X            }
  1069. X            }
  1070. X            if (isoff(glob_flags,READ_ONLY) && fputs(buf, tmpf) == -1) {
  1071. X            error(tempfile);
  1072. X            had_error++;
  1073. X            break;
  1074. X            }
  1075. X            lines++;
  1076. X        }
  1077. X        if (!msg[cnt].m_date_sent || !*msg[cnt].m_date_sent)
  1078. X            if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv) {
  1079. X            wprint("Message %d has *no* date!?\n", cnt+1);
  1080. X            msg[cnt].m_date_sent = msg[cnt].m_date_recv =
  1081. X                "0000000000XXX";
  1082. X            } else
  1083. X            strdup(msg[cnt].m_date_sent, msg[cnt].m_date_recv);
  1084. X        else if (!msg[cnt].m_date_recv || !*msg[cnt].m_date_recv)
  1085. X            strdup(msg[cnt].m_date_recv, msg[cnt].m_date_sent);
  1086. X        if (had_error)
  1087. X            break;
  1088. X        if (append && list)
  1089. X            set_msg_bit(list, cnt);
  1090. X        if (append)
  1091. X            cnt = ++msg_cnt;
  1092. X        get_status = 1;
  1093. X        }
  1094. X    } else if (!msg_found && buf[0] != '\n') {
  1095. X        /* Allow leading blank lines, but anything else is wrong */
  1096. X        lines++;
  1097. X        had_error++;
  1098. X        break;
  1099. X    }
  1100. X    if (msg_found) {
  1101. X        lines++;
  1102. X        if (isoff(glob_flags, READ_ONLY) && fputs(buf, tmpf) == -1) {
  1103. X        error(tempfile);
  1104. X        had_error++;
  1105. X        break;
  1106. X        }
  1107. X    }
  1108. X    }
  1109. #ifndef MSG_SEPARATOR
  1110. X    if (warn)
  1111. X    turnon(glob_flags, WARNING);
  1112. #endif /* !MSG_SEPARATOR */
  1113. X    if (msg_found && append != 1)
  1114. X    turnon(glob_flags, DO_UPDATE);
  1115. #ifdef MMDF
  1116. X    if (!append)
  1117. X    (void) fputs(END_MSG_SEP, tmpf);
  1118. #endif /* MMDF */
  1119. X    if (had_error) {
  1120. X    if (!append)
  1121. X        msg[cnt] = old;
  1122. X    else if (msg_found && append == 1 && cnt == MAXMSGS-append) {
  1123. X        /* reset fp to the beginning of the not-loaded message */
  1124. X        bytes = ftell(fp) - strlen(buf);
  1125. X        (void) fseek(fp, bytes, L_SET);
  1126. X    }
  1127. X    if (!msg_found) {
  1128. X        if (!append)
  1129. X        print("File not left in correct message format.\n");
  1130. X        else if (cnt == 0) {
  1131. X        if (buf[0]) 
  1132. X            print("\"%s\" does not seem to be a folder\n", file);
  1133. X        else
  1134. X            had_error = 0;    /* empty files are OK */
  1135. X        }
  1136. X    }
  1137. X    } else {
  1138. X    if (append)
  1139. X        cnt--;
  1140. X    if (isoff(glob_flags, READ_ONLY))
  1141. X        msg[cnt].m_size = ftell(tmpf) - msg[cnt].m_offset;
  1142. X    else
  1143. X        msg[cnt].m_size = ftell(fp) - msg[cnt].m_offset;
  1144. X    msg[cnt].m_lines = lines;
  1145. X    /* remember where we were to seek to for when we append new mail */ 
  1146. X    if (append)
  1147. X        cnt++;
  1148. X    }
  1149. X    if (append == 1) /* merge_folders takes care of this for append == 2 */
  1150. X    msg[cnt].m_offset = ftell(fp);
  1151. X    close_lock(file, fp);
  1152. X    if (isoff(glob_flags, READ_ONLY)) {
  1153. X    if (had_error && msg_found && append == 1 && cnt == MAXMSGS-append) {
  1154. X        wprint("Using read-only mode.\n");
  1155. X        turnon(glob_flags, READ_ONLY);
  1156. X        had_error = 0;    /* return successfully anyway */
  1157. X    }
  1158. X    (void) fclose(tmpf);
  1159. X    if (!(tmpf = fopen(tempfile, "r"))) {
  1160. X        error("Unable to open %s for reading", tempfile);
  1161. X        return -1;
  1162. X    }
  1163. X    }
  1164. X    return !had_error;
  1165. }
  1166. SHAR_EOF
  1167. chmod 0644 msgs.c ||
  1168. echo 'restore of msgs.c failed'
  1169. Wc_c="`wc -c < 'msgs.c'`"
  1170. test 28895 -eq "$Wc_c" ||
  1171.     echo 'msgs.c: original size 28895, current size' "$Wc_c"
  1172. rm -f _shar_wnt_.tmp
  1173. fi
  1174. # ============= mush.1 ==============
  1175. if test -f 'mush.1' -a X"$1" != X"-c"; then
  1176.     echo 'x - skipping mush.1 (File already exists)'
  1177.     rm -f _shar_wnt_.tmp
  1178. else
  1179. > _shar_wnt_.tmp
  1180. echo 'x - extracting mush.1 (Text)'
  1181. sed 's/^X//' << 'SHAR_EOF' > 'mush.1' &&
  1182. .\" Mush Man Page: Copyright (c) 1987, 1989, 1990 Dan Heller
  1183. .\" Cleaned up January 1988 by Bart Schaefer <schaefer@cse.ogc.edu>
  1184. .\" Patched again December 1989 by Bart Schaefer <schaefer@cse.ogi.edu>
  1185. .\" 1990 updates by Bart Schaefer and Bill Randle <billr@saab.cna.tek.com>
  1186. .\"
  1187. .if n .ds Q \&"
  1188. .if n .ds U \&"
  1189. .if t .ds Q \&``
  1190. .if t .ds U \&''
  1191. .if n .ds - --
  1192. .if t .ds - \(em
  1193. .nh
  1194. .TH MUSH 1 "March 17, 1991" "Version 7.2.2"
  1195. .SH NAME
  1196. The Mail User's Shell \- Shell for electronic mail.
  1197. .SH SYNOPSIS
  1198. .B mush
  1199. [
  1200. .B \-n
  1201. ]
  1202. [
  1203. .B \-v
  1204. ]
  1205. [
  1206. .B \-s
  1207. subject
  1208. ]
  1209. [
  1210. .B \-c
  1211. cc-list
  1212. ]
  1213. [
  1214. .B \-b
  1215. bcc-list
  1216. ]
  1217. [
  1218. address-list
  1219. ]
  1220. .br
  1221. .B mush
  1222. [
  1223. .B \-n
  1224. ]
  1225. [
  1226. .B \-v
  1227. ]
  1228. [
  1229. .BR \-U [ ! ]
  1230. ]
  1231. .B \-h
  1232. draft-file
  1233. .br
  1234. .B mush
  1235. [
  1236. mode-options
  1237. ]
  1238. [
  1239. file-options
  1240. ]
  1241. .SH INTRODUCTION
  1242. The Mail User's Shell (Mush) is an interface for sending and manipulating
  1243. a database of electronic mail messages under the
  1244. .IR UNIX (TM)
  1245. environment.
  1246. There are three user interfaces that allow the user to interact with
  1247. .I Mush.
  1248. The default interface is the conventional tty-based line mode
  1249. similar to command line interpreters such as
  1250. .I csh
  1251. as well as other mailers, such as University of California, Berkeley's
  1252. .I Mail
  1253. and Bell Lab's System V
  1254. .I mailx
  1255. interface.
  1256. This mode requires nothing from the terminal in terms of screen
  1257. capability and may be run on many different versions of the
  1258. .IR UNIX (TM)
  1259. operating system.
  1260. .PP
  1261. The text-graphics
  1262. .RI ( curses )
  1263. interface is reminiscent of the
  1264. .I vi
  1265. visual editor, but is user-configurable to simulate other editors.
  1266. This interface does not require graphics capabilities of
  1267. the computer or the terminal on which it is run, but the terminal must
  1268. have the minimum capabilities required by any visual screen editor.
  1269. .PP
  1270. The
  1271. .I window
  1272. interface for the Sun Workstation utilizes the icon and
  1273. menu based (mouse selectable) windowing system.
  1274. This
  1275. .I tool
  1276. (graphics) mode is highly subject to the version of operating system
  1277. your Sun may be running.
  1278. It is intended to be run on Sun versions 3.5 and higher (those that have the
  1279. SunView window system).
  1280. .PP
  1281. See the corresponding sections for more information on the user
  1282. interface desired.
  1283. Most of this manual deals with commands, variables
  1284. and actions that are common to all three interfaces although
  1285. some attention is paid to individual characteristics of each interface.
  1286. .PP
  1287. The following command line arguments are understood by
  1288. .I Mush
  1289. (full word forms in parentheses):
  1290. .TP
  1291. \-b bcc-list
  1292. (\-blindcarbon, \-blind)
  1293. The list of Blind Carbon Copy recipients is set on the command line.
  1294. If more than one address or an address containing spaces is specified, the
  1295. entire list should be enclosed in quotes.
  1296. This option applies when sending mail only.
  1297. If you are entering the shell, curses mode, or the tool mode, this option is
  1298. ignored.
  1299. .TP
  1300. \-C
  1301. (\-curses)
  1302. Enter the mailer in curses mode upon startup.
  1303. .TP
  1304. \-c cc-list
  1305. (\-carbon, \-copy)
  1306. The list of Carbon Copy recipients is set on the command line.
  1307. If more than one address or an address containing spaces is specified, the
  1308. entire list should be enclosed in quotes.
  1309. This option applies when sending mail only.
  1310. If you are entering the shell, curses mode, or the tool mode, this option is
  1311. ignored.
  1312. .TP
  1313. \-d
  1314. (\-debug)
  1315. Turns on the debugging level to 1.
  1316. You can change debugging levels from within the shell using the
  1317. .B debug
  1318. command.
  1319. .TP
  1320. \-e
  1321. (\-echo)
  1322. Normally, the program runs with the local echo off and each character
  1323. typed is processed individually so as to process certain macros and
  1324. keyboard mappings.
  1325. This option suppresses this from taking place
  1326. and the program only processes input after a carriage return has
  1327. been hit.
  1328. Under normal circumstances, this action is transparent to
  1329. the user and the use of this option is discouraged except when using
  1330. a debugger with the program.
  1331. Note that if this option is specified,
  1332. any key sequences set by map or map! do not substitute their expansions.
  1333. This option is ignored for curses mode.
  1334. .TP
  1335. \-F[!] filename
  1336. (\-source)
  1337. This file is the same type as the initialization file read on startup
  1338. (see INITIALIZATION) with the exception that commands that manipulate
  1339. or search messages may be given.
  1340. Normally, such commands may not appear in the initialization file since
  1341. that file is read before the folder is scanned.
  1342. The file specified by \-F is read after the folder is scanned, so
  1343. commands that affect messages are allowed.
  1344. The optional `!' argument prevents the shell from running after the
  1345. file has been sourced.
  1346. Otherwise,
  1347. .I Mush
  1348. continues into whatever interface has been specified.
  1349. .TP
  1350. \-f [ filename ]
  1351. (\-folder)
  1352. The optional filename argument specifies a folder containing mail messages.
  1353. With no argument,
  1354. .B mbox
  1355. in the current directory (or the variable
  1356. .BR mbox )
  1357. is used.
  1358. If no filename is given, this option must be last on the command line.
  1359. .TP
  1360. \-H[:c]
  1361. (\-headers)
  1362. Have
  1363. .I Mush
  1364. display mail headers without entering the shell.
  1365. See the
  1366. .B headers
  1367. command for information on the
  1368. .B :c
  1369. argument.
  1370. No colon modifier is equivalent to \*Q\-H:a\*U.
  1371. This option prevents the shell from running, so this option turns off the
  1372. \-S and \-C flags.
  1373. This option is ignored if the tool mode is in effect.
  1374. .TP
  1375. \-h draft-file
  1376. (-draft)
  1377. This option specifies a previously prepared message file (called a draft)
  1378. which is read in as a new message to be sent.
  1379. The current implementation requires that the draft file must contain all the
  1380. message headers;
  1381. .I Mush
  1382. adds only a new \*QDate:\*U and a \*QFrom:\*U header if there is none.
  1383. If there is no \*QTo:\*U header, the draft is not sent.
  1384. See the
  1385. .B mail
  1386. command and the section on \*QSending mail\*U for more information.
  1387. .TP
  1388. \-I[!] filename
  1389. (\-init)
  1390. This option specifies an initialization file to be read
  1391. .I before
  1392. any of the other
  1393. .I Mush
  1394. initialization is done.
  1395. The file specified by \-I is read before the default system initialization
  1396. file is read (see the INITIALIZATION section for details).
  1397. The optional `!' argument prevents
  1398. .I Mush
  1399. from reading the default system file, so \-I! can be used to specify a
  1400. substitute default file.
  1401. The user's personal initialization file is read normally.
  1402. .TP
  1403. \-i
  1404. (\-interact)
  1405. Forces interactive mode even if input has been redirected to the program.
  1406. This is intended for remote host mail sessions (with -e) but also allows
  1407. the user to redirect input from a \*Qscript\*U of
  1408. .I Mush
  1409. commands.
  1410. See the INITIALIZATION and MUSH SCRIPTS sections for information on how to
  1411. write scripts that deal with mail.
  1412. Note that this flag is different from the \*Qignore\*U flag of UCB Mail.
  1413. .TP
  1414. \-m mailbox-path
  1415. (\-mailbox)
  1416. The mailbox specified is interpreted as if it is the user's main
  1417. (system) mailbox in place of /usr/spool/mail/$USER (or whatever path is
  1418. applicable for your system and Mail Transport Agent).
  1419. .TP
  1420. \-N
  1421. (\-noheaders)
  1422. Enter
  1423. .I Mush
  1424. without displaying any message headers.
  1425. This argument is passed to the
  1426. .B folder
  1427. command.
  1428. .TP
  1429. \-n[!]
  1430. (\-noinit)
  1431. No initialization is done on start up.
  1432. That is, do not source the default system initialization files.
  1433. If the `!' argument is given, reading of the user's personal
  1434. .I .mushrc
  1435. or
  1436. .I .mailrc
  1437. files is also suppressed.
  1438. See the INITIALIZATION section for more information on
  1439. startup and the significance of these files.
  1440. .TP
  1441. \-r
  1442. (\-readonly)
  1443. Initialize the folder in Read-Only mode; no modification of the folder is
  1444. permitted.
  1445. This argument is passed on to the
  1446. .B folder
  1447. command.
  1448. .TP
  1449. \-S
  1450. (\-shell)
  1451. This flag allows the user to enter the shell even if the system
  1452. mailbox or specified folder is empty or doesn't exist.
  1453. .TP
  1454. \-s subject
  1455. (\-subject)
  1456. The subject is set on the command line using this flag.
  1457. If the subject has
  1458. any spaces or tabs, the entire subject should be enclosed in quotes.
  1459. This applies when sending mail only.
  1460. If you are entering the shell,
  1461. curses mode, or the tool mode, this option is ignored.
  1462. .TP
  1463. \-T timeout
  1464. (\-timeout)
  1465. In the tool mode (Sun only),
  1466. .I timeout
  1467. specifies the length of time (seconds) to wait between each check for new mail.
  1468. 30 seconds is the smallest time allowed for performance reasons;
  1469. 60 seconds is the default value.
  1470. This option should be used either in place of \-t or immediately after it.
  1471. .TP
  1472. \-t
  1473. (\-tool)
  1474. Use the graphics tool mode (Sun only).
  1475. This option must be the first one on the command line, before any Sun window
  1476. system flags or other \fIMush\fR options.
  1477. .sp
  1478. .I
  1479. NOTE:  The \-t option is obsolete and may be eliminated in future revisions.
  1480. The preferred way to run the tool mode of \fIMush\fR is to use the command
  1481. .BR mushtool ,
  1482. which is a link to
  1483. .BR mush .
  1484. .TP
  1485. \-u [ user ]
  1486. (\-user)
  1487. The mailbox to use is /usr/spool/mail/\fBuser\fR.
  1488. If the login name for user is not specified, then root is used.
  1489. .TP
  1490. \-U[!]
  1491. (-send)
  1492. This option may be used only with \-h (\-draft).
  1493. It causes the draft file to be sent immediately without further editing
  1494. (\*Qunedited\*U, hence \-U).
  1495. If the optional `!' is appended, signatures and fortunes are suppressed.
  1496. See the
  1497. .B mail
  1498. command and the section on \*QSending mail\*U for more information.
  1499. .TP
  1500. \-v
  1501. (\-verbose)
  1502. Verbose mode is turned on.
  1503. This option is passed to the actual mail delivery
  1504. subsystem internal to your version of
  1505. .IR UNIX (TM).
  1506. Some mailers do not have a verbose option, so this flag may not apply
  1507. to your system (System V, for example).
  1508. This applies when sending mail only.
  1509. If you are entering the shell,
  1510. curses mode, or the tool mode, this option is ignored.
  1511. .SH "GENERAL USAGE"
  1512. Because there are three different interfaces available to the user,
  1513. the tty characteristics (backspace, kill-word, kill-line, redraw line)
  1514. are simulated identically in all interfaces.
  1515. When the user has to type something, the 4.2BSD style of tty driver interface
  1516. is simulated whether you're in the window system, the curses mode, or
  1517. the tty-line mode, and even on System-V machines.
  1518. This means that backspacing causes a
  1519. backspace-space-backspace effect (erasing the character backspaced over).
  1520. The user may reset his tty characteristics using the
  1521. .B stty
  1522. command.
  1523. .PP
  1524. .IR "New mail" .
  1525. .PP
  1526. If during a
  1527. .I Mush
  1528. session, new mail arrives for you, it is automatically incorporated into
  1529. your system mailbox and you are told that new mail has arrived.
  1530. .PP
  1531. In the default line mode, new mail is checked between each command
  1532. issued.
  1533. In the curses mode, new mail is checked on each
  1534. command and is displayed in the bottom line of the screen.
  1535. In the tool based graphics mode, new mail is checked approximately
  1536. every minute or the number of seconds specified by the
  1537. .B -T
  1538. option on the command line.
  1539. .PP
  1540. If you are using your system mailbox as your \*Qcurrent folder,\*U then the
  1541. new mail is added immediately to your current
  1542. list of messages and information similar to the following example is
  1543. displayed, to tell you whom the mail is from:
  1544. .sp
  1545. .ti +2
  1546. New mail: (#15) argv@zipcode.com (Dan Heller)
  1547. .sp
  1548. If you are not in your system mailbox, then the new mail is not added
  1549. to your list of messages, but you are instead informed of the new arrival.
  1550. .sp
  1551. If you are using the tool based mode and
  1552. .I Mush
  1553. is closed to an iconic state, then the number of messages in the current
  1554. folder is displayed on the mailbox icon and the flag on the mailbox goes up.
  1555. .PP
  1556. .IR "Displaying messages" .
  1557. .PP
  1558. Depending on the interface you use, you can display any message in your
  1559. list of messages as long as the message is not marked for deletion.
  1560. If the message is marked as deleted, then use the 
  1561. .B undelete
  1562. command supplied by the interface you are using.
  1563. To display a message in line mode, specify the message using
  1564. .BR print ,
  1565. .BR type ,
  1566. .BR p ,
  1567. .BR t ,
  1568. or type a message number to display that message on the screen.
  1569. .PP
  1570. In curses mode, move the cursor over the message you want and type
  1571. a `t' or `p' to read the message.
  1572. You may \*Qbind\*U other keys to call
  1573. the function that displays messages if `t' and `p' are uncomfortable.
  1574. .PP
  1575. In the tool mode, move the cursor over the header summary of the
  1576. message you wish to be displayed and select the LEFT mouse button.
  1577. The MIDDLE mouse button deletes the message, and the RIGHT button
  1578. brings up a menu of additional options, including help.
  1579. If the message you want is not visible (in the header subwindow), you may type
  1580. the number of the message in the \*QRange:\*U item, and press return.
  1581. That message number is displayed.
  1582. Finally, the \*QNext\*U item in the panel below the header display
  1583. can be used to step through the folder, one message at a time.
  1584. .PP
  1585. In the line or curses mode, if the message has more lines than the variable
  1586. .BR crt ,
  1587. then a
  1588. .I pager
  1589. is invoked to allow the user to page through the message without
  1590. having it scroll off the screen.
  1591. The pager used is determined by the variable
  1592. .BR pager .
  1593. If that variable is unset, then a default pager is used.
  1594. Note that if pager is set, but not to a value, or is set to the value
  1595. of \*Qinternal\*U, then the internal pager is used.
  1596. The internal pager
  1597. is very simple; the spacebar displays the next
  1598. .B crt
  1599. lines, carriage return prints the next line, and \*Qq\*U quits the pager.
  1600. .PP
  1601. In the tool mode, if a message is larger than the size of the message
  1602. subwindow, the scrollbar at the left side of the window may be used to
  1603. page the message forwards and backwards.
  1604. The variable
  1605. .B crt_win
  1606. may be set in an initialization file to preset the size of the
  1607. message display subwindow.
  1608. .PP
  1609. An alternative to displaying messages is the
  1610. .B top
  1611. command.
  1612. This command prints just the top few lines of a message.
  1613. The number of lines is determined by the variable
  1614. .BR toplines .
  1615. If this variable isn't set,
  1616. .B top
  1617. prints a number of lines equal to the value of the variable
  1618. .BR crt .
  1619. .PP
  1620. .IR "Sorting mail" .
  1621. .PP
  1622. .I Mush
  1623. allows you to sort your mail according to various constraints such
  1624. as time, size, status (new, unread, deleted, etc.), author and subject.
  1625. See the
  1626. .B sort
  1627. command in the COMMANDS section for more information on sorting.
  1628. Sorting has a panel item in the tool mode, and is bound by default
  1629. to the `o' (sort) and `O' (sort reverse) keys in curses mode.
  1630. .PP
  1631. .IR "Picking specific messages" .
  1632. .PP
  1633. You can select messages that contain unique information, or from
  1634. messages that have special attributes.
  1635. You have the option of restricting your search to messages between dates,
  1636. message numbers, author names and other constraints.
  1637. See the
  1638. .B pick
  1639. command in the COMMANDS section for complete details.
  1640. This feature is not directly accessible from the tool mode, and is
  1641. available only as a search action in curses mode (see, however, the
  1642. CURSES INTERFACE section for temporary escapes to line mode).
  1643. .PP
  1644. .IR "Sending mail" .
  1645. .PP
  1646. You can send mail by listing addresses on the command line when
  1647. .I Mush
  1648. is started, by using the
  1649. .B mail
  1650. command from within
  1651. .IR Mush ,
  1652. or by responding to other mail.
  1653. In curses mode, the `m' key invokes mail, and the `r' key begins a response.
  1654. In the tool mode, selecting the \*QCompose\*U or \*QReply\*U items on the main
  1655. panel opens a separate frame for message composition.
  1656. The message replied-to is either the current message or one specified in
  1657. the \*QRange:\*U item.
  1658. .PP
  1659. When you are sending mail, you are in a mode where everything
  1660. you type is added to the contents of the message.
  1661. When you are done typing your message in line or curses modes,
  1662. you can type `^D' (control-D) to signify the end of the message.
  1663. If you have the variable
  1664. .B dot
  1665. set, then you can end a message with a `.' on a line by itself.
  1666. In the tool mode, select the \*QSend\*U item in the composition frame
  1667. to finish and send the message.
  1668. .PP
  1669. While you are composing a message,
  1670. .I Mush
  1671. treats lines beginning with the character `~' specially.
  1672. This is called a
  1673. .BR "tilde escape" .
  1674. For instance, typing \*Q~i\*U (alone on a line) places a copy
  1675. of the \*Qcurrent message\*U into your message body.
  1676. It does not include the message headers of the message, just the body of
  1677. text that comprises the message.
  1678. A subset of these escapes are available in the tool mode, and others are
  1679. provided as panel items or as menu selections from the \*QInclude\*U item.
  1680. Tilde escapes which alter message headers are not usable when the variable
  1681. .B edit_hdrs
  1682. is set or when the \-E option was passed to the
  1683. .B mail
  1684. command.
  1685. .PP
  1686. The tool mode composition window uses header editing at all times, but
  1687. provides some of these escapes anyway; see the descriptions below, and the
  1688. description of the
  1689. .B edit_hdrs
  1690. variable, for complete details.
  1691. .PP
  1692. Available
  1693. .BR "tilde escapes" :
  1694. [OPTIONAL arguments in square brackets]
  1695. .TP
  1696. ~a file
  1697. Append message buffer to file name.
  1698. Accessed via the \*QExport\*U panel item in tool mode.
  1699. .TP
  1700. ~b [bcc-list]
  1701. Modify blind carbon recipients; otherwise identical to ~t.
  1702. In tool mode, moves the cursor to the Bcc: header, adding one if necessary.
  1703. .TP
  1704. ~c [cc-list]
  1705. Modify carbon copy recipients; otherwise identical to ~t.
  1706. In tool mode, moves the cursor to the Cc: header, adding one if necessary.
  1707. .TP
  1708. ~E[!]
  1709. Erase message buffer; not available in tool mode.
  1710. SHAR_EOF
  1711. true || echo 'restore of mush.1 failed'
  1712. fi
  1713. echo 'End of  part 14'
  1714. echo 'File mush.1 is continued in part 15'
  1715. echo 15 > _shar_seq_.tmp
  1716. exit 0
  1717. exit 0 # Just in case...
  1718. -- 
  1719. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1720. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1721. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1722. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1723.