home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume12 / mush / part14 < prev    next >
Encoding:
Text File  |  1990-05-05  |  54.0 KB  |  1,812 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v12i042: Mail User's Shell, Part14/19
  3. from: argv@Eng.Sun.COM (Dan Heller)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 12, Issue 42
  7. Submitted-by: argv@Eng.Sun.COM (Dan Heller)
  8. Archive-name: mush/part14
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then feed it
  12. # into a shell via "sh file" or similar.  To overwrite existing files,
  13. # type "sh file -c".
  14. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  15. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  16. # If this archive is complete, you will see the following message at the end:
  17. #        "End of archive 14 (of 19)."
  18. # Contents:  mush/bind.c mush/folders.c mush/signals.c
  19. # Wrapped by argv@turnpike on Wed May  2 13:59:44 1990
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'mush/bind.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'mush/bind.c'\"
  23. else
  24. echo shar: Extracting \"'mush/bind.c'\" \(20570 characters\)
  25. sed "s/^X//" >'mush/bind.c' <<'END_OF_FILE'
  26. X/* bind.c */
  27. X
  28. X#include "bindings.h"
  29. X#include "mush.h"
  30. X
  31. Xextern char *c_macro();
  32. Xstatic un_bind();
  33. X
  34. Xstruct cmd_map *cmd_map, *line_map, *bang_map;
  35. X
  36. X/*
  37. X * Bindings are added here in REVERSE of the order that
  38. X * they will be displayed!  Display order is based on a
  39. X * guess about the frequency of use and (to a lesser
  40. X * extent) how hard they are to remember.
  41. X *
  42. X * The user's own new bindings, if any, will be displayed
  43. X * before any of these default bindings.
  44. X */
  45. Xinit_bindings()
  46. X{
  47. X#ifdef CURSES
  48. X    /* Help gets displayed last */
  49. X    add_bind("?", C_HELP, NULL, &cmd_map);
  50. X    add_bind("V", C_VERSION, NULL, &cmd_map);
  51. X
  52. X    /* Miscellaneous shell commands */
  53. X    add_bind("%", C_CHDIR, NULL, &cmd_map);
  54. X    add_bind("|", C_PRINT_MSG, NULL, &cmd_map);
  55. X    add_bind("!", C_SHELL_ESC, NULL, &cmd_map);
  56. X    add_bind(":", C_CURSES_ESC, NULL, &cmd_map);
  57. X
  58. X    /* Mush customization commands */
  59. X    /* NOTE: No default C_MACRO bindings */
  60. X    add_bind(")", C_SAVEOPTS, NULL, &cmd_map);
  61. X    add_bind("(", C_SOURCE, NULL, &cmd_map);
  62. X    add_bind("&!", C_MAP_BANG, NULL, &cmd_map);
  63. X    add_bind("&:", C_MAP, NULL, &cmd_map);
  64. X    add_bind("&&", C_BIND_MACRO, NULL, &cmd_map);
  65. X    add_bind("v", C_VAR_SET, NULL, &cmd_map);
  66. X    add_bind("i", C_IGNORE, NULL, &cmd_map);
  67. X    add_bind("h", C_OWN_HDR, NULL, &cmd_map);
  68. X    add_bind("B", C_UNBIND, NULL, &cmd_map);
  69. X    add_bind("b", C_BIND, NULL, &cmd_map);
  70. X    add_bind("a", C_ALIAS, NULL, &cmd_map);
  71. X
  72. X    /* Display modification commands */
  73. X    add_bind("\022", C_REVERSE, NULL, &cmd_map);    /* ^R */
  74. X    add_bind("\014", C_REDRAW, NULL, &cmd_map);        /* ^L */
  75. X    add_bind("Z", C_PREV_SCREEN, NULL, &cmd_map);
  76. X    add_bind("z", C_NEXT_SCREEN, NULL, &cmd_map);
  77. X
  78. X    /* Searching and sorting commands */
  79. X    add_bind("\016", C_CONT_SEARCH, NULL, &cmd_map);    /* ^N */
  80. X    add_bind("\037", C_PREV_SEARCH, NULL, &cmd_map);    /* ^/ */
  81. X    add_bind("/", C_NEXT_SEARCH, NULL, &cmd_map);
  82. X    add_bind("O", C_REV_SORT, NULL, &cmd_map);
  83. X    add_bind("o", C_SORT, NULL, &cmd_map);
  84. X
  85. X    /* Ways to get out */
  86. X    add_bind("X", C_EXIT_HARD, NULL, &cmd_map);
  87. X    add_bind("x", C_EXIT, NULL, &cmd_map);
  88. X    add_bind("Q", C_QUIT_HARD, NULL, &cmd_map);
  89. X    add_bind("q", C_QUIT, NULL, &cmd_map);
  90. X
  91. X    /* Folder modification commands */
  92. X    add_bind("\025", C_UPDATE, NULL, &cmd_map);        /* ^U */
  93. X    add_bind("\020", C_PRESERVE, NULL, &cmd_map);    /* ^P */
  94. X    add_bind("W", C_WRITE_LIST, NULL, &cmd_map);
  95. X    add_bind("w", C_WRITE_MSG, NULL, &cmd_map);
  96. X    add_bind("U", C_UNDEL_LIST, NULL, &cmd_map);
  97. X    add_bind("u", C_UNDEL_MSG, NULL, &cmd_map);
  98. X    add_bind("S", C_SAVE_LIST, NULL, &cmd_map);
  99. X    add_bind("s", C_SAVE_MSG, NULL, &cmd_map);
  100. X    add_bind("f", C_FOLDER, NULL, &cmd_map);
  101. X    add_bind("D", C_DELETE_LIST, NULL, &cmd_map);
  102. X    add_bind("d", C_DELETE_MSG, NULL, &cmd_map);
  103. X    add_bind("C", C_COPY_LIST, NULL, &cmd_map);
  104. X    add_bind("c", C_COPY_MSG, NULL, &cmd_map);
  105. X
  106. X    /* Cursor movement and message selection */
  107. X    add_bind("g", C_GOTO_MSG, NULL, &cmd_map);
  108. X    add_bind("}", C_BOTTOM_PAGE, NULL, &cmd_map);
  109. X    add_bind("{", C_TOP_PAGE, NULL, &cmd_map);
  110. X    add_bind("$", C_LAST_MSG, NULL, &cmd_map);
  111. X    add_bind("^", C_FIRST_MSG, NULL, &cmd_map);
  112. X    add_bind("\013",C_PREV_MSG, NULL, &cmd_map);    /* ^K */
  113. X    add_bind("\012", C_NEXT_MSG, NULL, &cmd_map);    /* ^J */
  114. X    add_bind("-",C_PREV_MSG, NULL, &cmd_map);
  115. X    add_bind("+",C_NEXT_MSG, NULL, &cmd_map);
  116. X    add_bind("K", C_PREV_MSG, NULL, &cmd_map);
  117. X    add_bind("k", C_PREV_MSG, NULL, &cmd_map);
  118. X    add_bind("J", C_NEXT_MSG, NULL, &cmd_map);
  119. X    add_bind("j", C_NEXT_MSG, NULL, &cmd_map);
  120. X
  121. X    /* Mail-sending commands */
  122. X    add_bind("R", C_REPLY_ALL, NULL, &cmd_map);
  123. X    add_bind("r", C_REPLY_SENDER, NULL, &cmd_map);
  124. X    add_bind("M", C_MAIL_FLAGS, NULL, &cmd_map);
  125. X    add_bind("m", C_MAIL, NULL, &cmd_map);
  126. X
  127. X    /* Mail-reading commands */
  128. X    add_bind(".", C_DISPLAY_MSG, NULL, &cmd_map);
  129. X    add_bind("T", C_TOP_MSG, NULL, &cmd_map);
  130. X    add_bind("t", C_DISPLAY_MSG, NULL, &cmd_map);
  131. X    add_bind("p", C_DISPLAY_MSG, NULL, &cmd_map);
  132. X    add_bind("n", C_DISPLAY_NEXT, NULL, &cmd_map);
  133. X
  134. X#endif /* CURSES */
  135. X}
  136. X
  137. X/* Bindable function names.
  138. X *  Most of these can't be used if CURSES is not defined,
  139. X *  but help and lookups get confused if they aren't all here.
  140. X */
  141. Xstruct cmd_map map_func_names[] = {
  142. X    /* These MUST be in numerical order; see bindings.h */
  143. X    { C_NULL,        "no-op",        NULL, NULL_MAP },
  144. X    { C_GOTO_MSG,    "goto-msg",        NULL, NULL_MAP },
  145. X    { C_WRITE_LIST,    "write-list",        NULL, NULL_MAP },
  146. X    { C_WRITE_MSG,    "write",        NULL, NULL_MAP },
  147. X    { C_SAVE_LIST,    "save-list",        NULL, NULL_MAP },
  148. X    { C_SAVE_MSG,    "save",            NULL, NULL_MAP },
  149. X    { C_COPY_LIST,    "copy-list",        NULL, NULL_MAP },
  150. X    { C_COPY_MSG,    "copy",            NULL, NULL_MAP },
  151. X    { C_DELETE_LIST,    "delete-list",        NULL, NULL_MAP },
  152. X    { C_DELETE_MSG,    "delete",        NULL, NULL_MAP },
  153. X    { C_UNDEL_LIST,    "undelete-list",    NULL, NULL_MAP },
  154. X    { C_UNDEL_MSG,    "undelete",        NULL, NULL_MAP },
  155. X    { C_REDRAW,        "redraw",        NULL, NULL_MAP },
  156. X    { C_REVERSE,    "reverse-video",    NULL, NULL_MAP },
  157. X    { C_NEXT_MSG,    "next-msg",        NULL, NULL_MAP },
  158. X    { C_PREV_MSG,    "back-msg",        NULL, NULL_MAP },
  159. X    { C_FIRST_MSG,    "first-msg",        NULL, NULL_MAP },
  160. X    { C_LAST_MSG,    "last-msg",        NULL, NULL_MAP },
  161. X    { C_TOP_PAGE,    "top-page",        NULL, NULL_MAP },
  162. X    { C_BOTTOM_PAGE,    "bottom-page",        NULL, NULL_MAP },
  163. X    { C_NEXT_SCREEN,    "screen-next",        NULL, NULL_MAP },
  164. X    { C_PREV_SCREEN,    "screen-back",        NULL, NULL_MAP },
  165. X    { C_SOURCE,        "source",        NULL, NULL_MAP },
  166. X    { C_SAVEOPTS,    "saveopts",        NULL, NULL_MAP },
  167. X    { C_NEXT_SEARCH,    "search-next",        NULL, NULL_MAP },
  168. X    { C_PREV_SEARCH,    "search-back",        NULL, NULL_MAP },
  169. X    { C_CONT_SEARCH,    "search-again",        NULL, NULL_MAP },
  170. X    { C_PRESERVE,    "preserve",        NULL, NULL_MAP },
  171. X    { C_REV_SORT,    "sort-reverse",        NULL, NULL_MAP },
  172. X    { C_SORT,        "sort",            NULL, NULL_MAP },
  173. X    { C_QUIT_HARD,    "quit!",        NULL, NULL_MAP },
  174. X    { C_QUIT,        "quit",            NULL, NULL_MAP },
  175. X    { C_EXIT_HARD,    "exit!",        NULL, NULL_MAP },
  176. X    { C_EXIT,        "exit",            NULL, NULL_MAP },
  177. X    { C_UPDATE,        "update",        NULL, NULL_MAP },
  178. X    { C_FOLDER,        "folder",        NULL, NULL_MAP },
  179. X    { C_SHELL_ESC,    "shell-escape",        NULL, NULL_MAP },
  180. X    { C_CURSES_ESC,    "line-mode",        NULL, NULL_MAP },
  181. X    { C_PRINT_MSG,    "lpr",            NULL, NULL_MAP },
  182. X    { C_CHDIR,        "chdir",        NULL, NULL_MAP },
  183. X    { C_VAR_SET,    "variable",        NULL, NULL_MAP },
  184. X    { C_IGNORE,        "ignore",        NULL, NULL_MAP },
  185. X    { C_ALIAS,        "alias",        NULL, NULL_MAP },
  186. X    { C_OWN_HDR,    "my-hdrs",        NULL, NULL_MAP },
  187. X    { C_VERSION,    "version",        NULL, NULL_MAP },
  188. X    { C_MAIL_FLAGS,    "mail-flags",        NULL, NULL_MAP },
  189. X    { C_MAIL,        "mail",            NULL, NULL_MAP },
  190. X    { C_REPLY_ALL,    "reply-all",        NULL, NULL_MAP },
  191. X    { C_REPLY_SENDER,    "reply",        NULL, NULL_MAP },
  192. X    { C_DISPLAY_NEXT,    "display-next",        NULL, NULL_MAP },
  193. X    { C_DISPLAY_MSG,    "display",        NULL, NULL_MAP },
  194. X    { C_TOP_MSG,    "top",            NULL, NULL_MAP },
  195. X    { C_BIND_MACRO,    "bind-macro",        NULL, NULL_MAP },
  196. X    { C_BIND,        "bind",            NULL, NULL_MAP },
  197. X    { C_UNBIND,        "unbind",        NULL, NULL_MAP },
  198. X    { C_MAP_BANG,    "map!",            NULL, NULL_MAP },
  199. X    { C_MAP,        "map",            NULL, NULL_MAP },
  200. X    { C_MACRO,        "macro",        NULL, NULL_MAP },
  201. X    /* C_HELP Must be the last one! */
  202. X    { C_HELP,        "help",            NULL, NULL_MAP }
  203. X};
  204. X
  205. X#ifdef CURSES
  206. X
  207. X/*
  208. X * getcmd() is called from curses mode only.  It waits for char input from
  209. X * the user via m_getchar() (which means that a macro could provide input)
  210. X * and then compares the chars input against the "bind"ings set up by the
  211. X * user (or the defaults).  For example, 'j' could bind to "next msg" which
  212. X * is interpreted by the big switch statement in curses_command() (curses.c).
  213. X * getcmd() returns the int-value of the curses command the input is "bound"
  214. X * to.  If the input is unrecognized, C_NULL is returned (curses_command()
  215. X * might require some cleanup, so this is valid, too).
  216. X *
  217. X * Since the input could originate from a macro rather than the terminal,
  218. X * check to see if this is the case and search for a '[' char which indicates
  219. X * that there is a curses command or other "long" command to be executed.
  220. X */
  221. Xgetcmd()
  222. X{
  223. X    char         buf[MAX_BIND_LEN * 3];
  224. X    register int     c, m, match;
  225. X    register char    *p = buf;
  226. X    register struct cmd_map *list;
  227. X
  228. X    bzero(buf, MAX_BIND_LEN);
  229. X    active_cmd = NULL_MAP;
  230. X    c = m_getchar();
  231. X    /* If user did job control (^Z), then the interrupt flag will be
  232. X     * set.  Be sure it's unset before continuing.
  233. X     */
  234. X    turnoff(glob_flags, WAS_INTR);
  235. X    if (isdigit(c)) {
  236. X    buf[0] = c;
  237. X    buf[1] = '\0';
  238. X    Ungetstr(buf); /* So mac_flush can clear on error */
  239. X    return C_GOTO_MSG;
  240. X    }
  241. X    for (;;) {
  242. X    if (ison(glob_flags, IN_MACRO) && c == MAC_LONG_CMD)
  243. X        return long_mac_cmd(c, TRUE);
  244. X    else
  245. X        *p++ = c;
  246. X    m = 0;
  247. X    for (list = cmd_map; list; list = list->m_next) {
  248. X        if ((match = prefix(buf, list->m_str)) == MATCH) {
  249. X        if (debug)
  250. X            print("\"%s\" ",
  251. X            ctrl_strcpy(buf,
  252. X                    map_func_names[list->m_cmd].m_str,
  253. X                    TRUE));
  254. X        if (list->m_cmd == C_MACRO) {
  255. X            curs_macro(list->x_str);
  256. X            return getcmd();
  257. X        }
  258. X        active_cmd = list;
  259. X        return (int)list->m_cmd;
  260. X        } else if (match != NO_MATCH)
  261. X        m++;
  262. X    }
  263. X    if (m == 0) {
  264. X        if (debug) {
  265. X        char tmp[sizeof buf];
  266. X        print("No binding for \"%s\" found.",
  267. X            ctrl_strcpy(tmp, buf, TRUE));
  268. X        }
  269. X        return C_NULL;
  270. X    }
  271. X    c = m_getchar();
  272. X    }
  273. X}
  274. X
  275. X#endif /* CURSES */
  276. X
  277. X/*
  278. X * bind_it() is used to set or unset bind, map and map! settings.
  279. X * bind is used to accelerate curses commands by mapping key sequences
  280. X * to curses commands.  map is used to accelerate command mode keysequences
  281. X * by simulating stdin.  map! is the same, but used when in compose mode.
  282. X *
  283. X * bind_it() doesn't touch messages; return -1 for curses mode.
  284. X * return -2 to have curses command set CNTD_CMD to prevent screen refresh
  285. X * to allow user to read output in case of multiple lines.
  286. X *
  287. X * Since this routine deals with a lot of binding and unbinding of things
  288. X * like line-mode "map"s and is interactive (calls Getstr()), be very careful
  289. X * not to allow expansions during interaction.
  290. X */
  291. Xbind_it(len, argv)
  292. Xchar **argv;
  293. X{
  294. X    char string[MAX_BIND_LEN], buf[256], *name = NULL;
  295. X    char *rawstr; /* raw format of string (ptr to string if no argv avail) */
  296. X    char ascii[MAX_BIND_LEN*2]; /* printable ascii version of string */
  297. X    register int x;
  298. X    SIGRET (*oldint)(), (*oldquit)();
  299. X    struct cmd_map **map_list;
  300. X    int unbind = (argv && **argv == 'u');
  301. X    int map = 0, is_bind_macro = 0;
  302. X    int ret = 0 - iscurses; /* return value */
  303. X
  304. X    if (argv && !strcmp(name = *argv, "bind-macro"))
  305. X    is_bind_macro++;
  306. X
  307. X    if (map = (argv && (!strcmp(name, "map!") || !strcmp(name, "unmap!"))))
  308. X    map_list = &bang_map;
  309. X    else if (map = (argv && (!strcmp(name, "map") || !strcmp(name, "unmap"))))
  310. X    map_list = &line_map;
  311. X    else
  312. X    map_list = &cmd_map;
  313. X
  314. X    if (argv && *++argv && !strcmp(*argv, "-?"))
  315. X    /* Subtract ret and iscurses to signal output */
  316. X    return help(0, unbind? name+2 : name, cmd_help) - ret - iscurses;
  317. X
  318. X    if (iscurses)
  319. X    on_intr();
  320. X
  321. X    if (unbind) {
  322. X    if (!*argv) {
  323. X        char savec = complete;
  324. X        complete = 0;
  325. X        print("%s what? ", name);
  326. X        len = Getstr(buf, sizeof buf, 0);
  327. X        complete = savec;
  328. X        if (len <= 0) {
  329. X        if (iscurses)
  330. X            off_intr();
  331. X        return -1;
  332. X        }
  333. X        rawstr = m_xlate(buf);
  334. X    } else
  335. X        rawstr = m_xlate(*argv);
  336. X    if (!un_bind(rawstr, map_list)) {
  337. X        (void) ctrl_strcpy(ascii, rawstr, TRUE);
  338. X        print("\"%s\" isn't bound to a command.\n", ascii);
  339. X    }
  340. X    if (iscurses)
  341. X        off_intr();
  342. X    return ret;
  343. X    }
  344. X    if (argv && *argv) {
  345. X    rawstr = m_xlate(*argv);
  346. X    (void) ctrl_strcpy(ascii, rawstr, TRUE);
  347. X    if (!*++argv) {
  348. X        /*
  349. X         * determine whether "argv" references a "map" or a "bind"
  350. X         */
  351. X        int binding = c_bind(rawstr, *map_list);
  352. X        if (binding == C_MACRO) {
  353. X        char *mapping = c_macro(NULL, rawstr, *map_list);
  354. X        if (mapping) {
  355. X            print("\"%s\" is mapped to ", ascii);
  356. X            print_more("\"%s\".\n",
  357. X            ctrl_strcpy(buf, mapping, FALSE));
  358. X        } else
  359. X            print("\"%s\" isn't mapped.\n", ascii);
  360. X        } else if (binding)
  361. X        print("\"%s\" is %s to \"%s\".\n", ascii,
  362. X            map? "mapped" : "bound", map_func_names[binding].m_str);
  363. X        else if (map)
  364. X        print("\"%s\" isn't mapped.\n", ascii);
  365. X        else
  366. X        print("\"%s\" isn't bound to a command.\n", ascii);
  367. X        if (iscurses)
  368. X        off_intr();
  369. X        return ret;
  370. X    }
  371. X    } else {
  372. X    char savec = complete;
  373. X    complete = 0;
  374. X    print("%s [<CR>=all, -?=help]: ", name);
  375. X    len = Getstr(string, MAX_BIND_LEN-1, 0);
  376. X    complete = savec;
  377. X    if (len == 0) {
  378. X        int add_to_ret = iscurses;
  379. X#ifdef CURSES
  380. X        if (iscurses)
  381. X        move(LINES-1, 0), refresh();
  382. X#endif
  383. X        if (map || is_bind_macro)
  384. X        add_to_ret = !c_macro(name, NULL, *map_list);
  385. X        else
  386. X        add_to_ret = !c_bind(NULL, *map_list);
  387. X        if (iscurses)
  388. X        off_intr();
  389. X        /* signal CTND_CMD if there was output */
  390. X        return ret - add_to_ret;
  391. X    }
  392. X    if (len < 0) {
  393. X        if (iscurses)
  394. X        off_intr();
  395. X        return ret;
  396. X    }
  397. X    rawstr = m_xlate(string);
  398. X    (void) ctrl_strcpy(ascii, rawstr, TRUE);
  399. X    }
  400. X    /* if a binding was given on the command line */
  401. X    if (argv && *argv && !map)
  402. X    if (is_bind_macro)
  403. X        (void) strcpy(buf, "macro");
  404. X    else
  405. X        (void) strcpy(buf, *argv++);
  406. X    else {
  407. X    /* at this point, "rawstr" and "ascii" should both be set */
  408. X    int binding;
  409. X
  410. X    if (!strcmp(ascii, "-?")) {
  411. X        if (iscurses)
  412. X        clr_bot_line();
  413. X        ret -= help(0, name, cmd_help);
  414. X        if (iscurses)
  415. X        off_intr();
  416. X        /* Subtract iscurses to signal CNTD_CMD */
  417. X        return ret - iscurses;
  418. X    }
  419. X
  420. X    if (!map && !is_bind_macro) {
  421. X        binding = c_bind(rawstr, *map_list);
  422. X
  423. X        for (len = 0; len == 0; ) {
  424. X        print("\"%s\" = <%s>: New binding [<CR> for list]: ",
  425. X            ascii, (binding? map_func_names[binding].m_str : "unset"));
  426. X        len = Getstr(buf, sizeof buf, 0);
  427. X        if (iscurses)
  428. X            clr_bot_line();
  429. X        /* strip any trailing whitespace */
  430. X        if (len > 0)
  431. X            len = no_newln(buf) - buf;
  432. X        if (len == 0) {
  433. X            (void) do_pager(NULL, TRUE);
  434. X            if (iscurses)
  435. X            putchar('\n');
  436. X            for (x = 1; x <= C_HELP; x++) {
  437. X            if (!(x % 4))
  438. X                if (do_pager("\n", FALSE) == EOF)
  439. X                break;
  440. X            (void) do_pager(sprintf(buf, "%-15.15s  ",
  441. X                        map_func_names[x].m_str), FALSE);
  442. X            }
  443. X            (void) do_pager("\n", FALSE);
  444. X            (void) do_pager(NULL, FALSE);
  445. X            ret -= iscurses;
  446. X        }
  447. X        }
  448. X    } else /* map */
  449. X        (void) strcpy(buf, "macro"), len = 5;
  450. X    /* if list was printed, ret < -1 -- tells CNTD_CMD to be set and
  451. X     * prevents screen from being refreshed (lets user read output
  452. X     */
  453. X    if (len == -1) {
  454. X        if (iscurses)
  455. X        off_intr();
  456. X        return ret;
  457. X    }
  458. X    }
  459. X    for (x = 1; x <= C_HELP; x++) {
  460. X    if (prefix(buf, map_func_names[x].m_str) == MATCH) {
  461. X        int add_to_ret;
  462. X        if (debug)
  463. X        print("\"%s\" will execute \"%s\".\n", ascii, buf);
  464. X        if (map_func_names[x].m_cmd == C_MACRO) {
  465. X        if (argv && *argv) {
  466. X            (void) argv_to_string(buf, argv);
  467. X            (void) m_xlate(buf); /* Convert buf to raw chars */
  468. X            add_to_ret =
  469. X            do_bind(rawstr, map_func_names[x].m_cmd, buf, map_list);
  470. X        } else {
  471. X            char exp[MAX_MACRO_LEN*2]; /* printable expansion */
  472. X            char *mapping = c_macro(NULL, rawstr, *map_list);
  473. X
  474. X            if (mapping)
  475. X            (void) ctrl_strcpy(exp, mapping, TRUE);
  476. X            print("\"%s\" = <%s>", ascii, mapping ? exp : "unset");
  477. X            putchar('\n'), print("New macro: ");
  478. X            ret -= iscurses; /* To signal screen messed up */
  479. X            /* we are done with buf, so we can trash over it */
  480. X            len = Getstr(buf, MAX_MACRO_LEN, 0);
  481. X            if (len > 0) {
  482. X            if (iscurses)
  483. X                clr_bot_line();
  484. X            (void) m_xlate(buf); /* Convert buf to raw chars */
  485. X            add_to_ret =
  486. X                do_bind(rawstr, C_MACRO, buf, map_list);
  487. X            if (debug) {
  488. X                (void) ctrl_strcpy(exp, buf, TRUE);
  489. X                print("\"%s\" will execute \"%s\".\n", ascii, exp);
  490. X            }
  491. X            } else if (len < 0) {
  492. X            if (iscurses)
  493. X                off_intr();
  494. X            return ret;
  495. X            } else
  496. X            print("Can't bind to null macro"), putchar('\n');
  497. X        }
  498. X        } else /* not a macro */ {
  499. X        (void) argv_to_string(buf, argv);
  500. X        add_to_ret =
  501. X            do_bind(rawstr, map_func_names[x].m_cmd, buf, map_list);
  502. X        }
  503. X        /* if do_bind had no errors, it returned -1.  If we already
  504. X         * messed up the screen, then ret is less than -1.  return the
  505. X         * lesser of the two to make sure that CNTD_CMD gets set right
  506. X         */
  507. X        if (iscurses)
  508. X        off_intr();
  509. X        return min(add_to_ret, ret);
  510. X    }
  511. X    }
  512. X    print("\"%s\": Unknown function.\n", buf);
  513. X    if (iscurses)
  514. X    off_intr();
  515. X    return ret;
  516. X}
  517. X
  518. X/*
  519. X * print current key to command bindings if "str" is NULL.
  520. X * else return the integer "m_cmd" which the str is bound to.
  521. X */
  522. Xc_bind(str, opts)
  523. Xregister char *str;
  524. Xregister struct cmd_map *opts;
  525. X{
  526. X    register int    incurses = iscurses;
  527. X
  528. X    if (!str) {
  529. X    if (!opts) {
  530. X        print("No command bindings.\n");
  531. X        return C_ERROR;
  532. X    }
  533. X    if (incurses)
  534. X        clr_bot_line(), iscurses = FALSE;
  535. X    (void) do_pager(NULL, TRUE);
  536. X    (void) do_pager("Current key to command bindings:\n", FALSE);
  537. X    (void) do_pager("\n", FALSE);
  538. X    }
  539. X
  540. X    for (; opts; opts = opts->m_next) {
  541. X    char buf[BUFSIZ], buf2[MAX_BIND_LEN], exp[MAX_MACRO_LEN*2], *xp;
  542. X    if (!str) {
  543. X        (void) ctrl_strcpy(buf2, opts->m_str, FALSE);
  544. X        if ((xp = opts->x_str) && opts->m_cmd == C_MACRO)
  545. X        xp = ctrl_strcpy(exp, opts->x_str, TRUE);
  546. X        if (do_pager(sprintf(buf, "%s\t%-15.15s %s\n",
  547. X             buf2, map_func_names[opts->m_cmd].m_str,
  548. X             xp? xp : ""),
  549. X             FALSE) == EOF)
  550. X        break;
  551. X    } else
  552. X        if (strcmp(str, opts->m_str))
  553. X        continue;
  554. X        else
  555. X        return opts->m_cmd;
  556. X    }
  557. X
  558. X    iscurses = incurses;
  559. X    if (!str)
  560. X    (void) do_pager(NULL, FALSE);
  561. X    return C_NULL;
  562. X}
  563. X
  564. X/*
  565. X * Doesn't touch messages, but changes macros: return -1.
  566. X * Error output causes return < -1.
  567. X *  args is currently the execute string of a macro mapping, but may be
  568. X *  used in the future as an argument string for any curses command.
  569. X */
  570. Xdo_bind(str, func, args, map_list)
  571. Xregister char *str, *args;
  572. Xstruct cmd_map **map_list;
  573. Xlong func;
  574. X{
  575. X    register int ret = -1;
  576. X    register struct cmd_map *list;
  577. X    int match;
  578. X
  579. X    if (func == C_MACRO && !check_mac_bindings(args))
  580. X    --ret;
  581. X    (void) un_bind(str, map_list);
  582. X    for (list = *map_list; list; list = list->m_next)
  583. X    if ((match = prefix(str, list->m_str)) != NO_MATCH) {
  584. X        ret--;
  585. X        switch (match) {
  586. X        case MATCH:
  587. X            puts("Something impossible just happened.");
  588. X        when A_PREFIX_B:
  589. X            wprint("Warning: \"%s\" prefixes \"%s\" (%s)\n", str,
  590. X            list->m_str, map_func_names[list->m_cmd].m_str);
  591. X        when B_PREFIX_A:
  592. X            wprint("Warning: \"%s\" (%s) prefixes: \"%s\"\n",
  593. X            list->m_str, map_func_names[list->m_cmd].m_str, str);
  594. X        }
  595. X    }
  596. X    add_bind(str, func, args, map_list);
  597. X    /* errors decrement ret.  If ret returns less than -1, CNTD_CMD is set
  598. X     * and no redrawing is done so user can see the warning signs
  599. X     */
  600. X    return ret;
  601. X}
  602. X
  603. X/*
  604. X * add a binding to a list.  This may include "map"s or other mappings since
  605. X * the map_list argument can control that.  The "func" is an int defined in
  606. X * bindings.h ... the "str" passed is the string the user would have to type
  607. X * to get the macro/map/binding expanded.  This must in in raw format: no
  608. X * \n's to mean \015.  Convert first using m_xlate().
  609. X */
  610. Xadd_bind(str, func, args, map_list)
  611. Xregister char *str, *args;
  612. Xstruct cmd_map **map_list;
  613. Xlong func;
  614. X{
  615. X    register struct cmd_map *tmp;
  616. X
  617. X    if (!str || !*str)
  618. X    return;
  619. X
  620. X    /* now make a new option struct and set fields */
  621. X    if (!(tmp = (struct cmd_map *)calloc((unsigned)1,sizeof(struct cmd_map)))) {
  622. X    error("calloc");
  623. X    return;
  624. X    }
  625. X    tmp->m_next = *map_list;
  626. X    *map_list = tmp;
  627. X
  628. X    tmp->m_str = savestr(str);
  629. X    tmp->m_cmd = func; /* strdup handles the NULL case */
  630. X    if (args && *args)
  631. X    tmp->x_str = savestr(args);
  632. X    else
  633. X    tmp->x_str = NULL;
  634. X}
  635. X
  636. Xstatic
  637. Xun_bind(p, map_list)
  638. Xregister char *p;
  639. Xstruct cmd_map **map_list;
  640. X{
  641. X    register struct cmd_map *list = *map_list, *tmp;
  642. X
  643. X    if (!list || !*list->m_str || !p || !*p)
  644. X    return 0;
  645. X
  646. X    if (!strcmp(p, (*map_list)->m_str)) {
  647. X    *map_list = (*map_list)->m_next;
  648. X    xfree (list->m_str);
  649. X    if (list->x_str)
  650. X        xfree (list->x_str);
  651. X    xfree((char *)list);
  652. X    return 1;
  653. X    }
  654. X    for ( ; list->m_next; list = list->m_next)
  655. X    if (!strcmp(p, list->m_next->m_str)) {
  656. X        tmp = list->m_next;
  657. X        list->m_next = list->m_next->m_next;
  658. X        xfree (tmp->m_str);
  659. X        if (tmp->x_str)
  660. X        xfree (tmp->x_str);
  661. X        xfree ((char *)tmp);
  662. X        return 1;
  663. X    }
  664. X    return 0;
  665. X}
  666. X
  667. Xprefix(a, b)
  668. Xregister char *a, *b;
  669. X{
  670. X    if (!a || !b)
  671. X    return NO_MATCH;
  672. X
  673. X    while (*a && *b && *a == *b)
  674. X    a++, b++;
  675. X    if (!*a && !*b)
  676. X    return MATCH;
  677. X    if (!*a && *b)
  678. X    return A_PREFIX_B;
  679. X    if (*a && !*b)
  680. X    return B_PREFIX_A;
  681. X    return NO_MATCH;
  682. X}
  683. END_OF_FILE
  684. if test 20570 -ne `wc -c <'mush/bind.c'`; then
  685.     echo shar: \"'mush/bind.c'\" unpacked with wrong size!
  686. fi
  687. # end of 'mush/bind.c'
  688. fi
  689. if test -f 'mush/folders.c' -a "${1}" != "-c" ; then 
  690.   echo shar: Will not clobber existing file \"'mush/folders.c'\"
  691. else
  692. echo shar: Extracting \"'mush/folders.c'\" \(19662 characters\)
  693. sed "s/^X//" >'mush/folders.c' <<'END_OF_FILE'
  694. X/* @(#)folders.c    (c) copyright 10/18/86 (Dan Heller) */
  695. X
  696. X#include "mush.h"
  697. X
  698. Xstatic char oldfolder[MAXPATHLEN];
  699. X
  700. X/* folder %[user]  --new mailfile is the spool/mail/login file [user].
  701. X * folder #  --new mailfile is the folder previous to the current folder
  702. X * folder &  --new mailfile is ~/mbox (or whatever "mbox" is set to)
  703. X * folder +file --new mailfile is in the directory "folder"; name is 'file'
  704. X * folder "path" --full path name or the one in current working directory.
  705. X *
  706. X * in all cases, changes are updated unless a '!' is specified after the
  707. X * folder command (e.g. "f!", "folder !" "fo!" .. all permutations)
  708. X * as usual, if new mail has arrived before the file is copied back, then
  709. X * user will be notified beforehand.
  710. X *
  711. X * RETURN -1 on error -- else return 0. All bits in msg_list are set to true.
  712. X */
  713. Xfolder(argc, argv, list)
  714. Xregister char **argv;
  715. Xchar list[];
  716. X{
  717. X    int n, updating = !strcmp(*argv, "update"), do_read_only = 0, no_hdrs = 0;
  718. X    char *tmp, *newfolder = NULL, buf[MAXPATHLEN];
  719. X    struct stat statbuf;
  720. X    extern long last_spool_size;
  721. X
  722. X    if (ison(glob_flags, IS_PIPE)) {
  723. X    print("You can't pipe to the %s command.\n", *argv);
  724. X    return -1;
  725. X    } else if (ison(glob_flags, IS_SENDING)) {
  726. X    print("You can't use the %s command when sending.\n", *argv);
  727. X    return -1;
  728. X    } else if (!tempfile || !*tempfile) {
  729. X    print("You can't use the %s command in init files.\n", *argv);
  730. X    return -1;
  731. X    }
  732. X    while (*++argv && (**argv == '-' || **argv == '!'))
  733. X    if (!strcmp(*argv, "-N"))
  734. X        no_hdrs = !(iscurses || ison(glob_flags, PRE_CURSES));
  735. X    else if (!updating && !strcmp(*argv, "-n"))
  736. X        turnoff(glob_flags, DO_UPDATE);
  737. X    else if (!strcmp(*argv, "-r"))
  738. X        do_read_only = 1;
  739. X    else if (!strcmp(*argv, "!")) {
  740. X        if (updating)
  741. X        turnon(glob_flags, DO_UPDATE);    /* useful? */
  742. X        else
  743. X        turnoff(glob_flags, DO_UPDATE);
  744. X    } else
  745. X        return help(0, "folder", cmd_help);
  746. X
  747. X    if (updating) {
  748. X    (void) strcpy(buf, mailfile);
  749. X    if (ison(glob_flags, READ_ONLY))
  750. X        do_read_only = 1;
  751. X    } else {
  752. X    if (!*argv) {
  753. X        mail_status(0);
  754. X        return 0;
  755. X    }
  756. X    if (!strcmp(*argv, "#"))
  757. X        if (!*oldfolder) {
  758. X        print("No previous folder\n");
  759. X        return -1;
  760. X        } else
  761. X        newfolder = oldfolder;
  762. X    else if (!strcmp(*argv, "&")) {
  763. X        if (!(newfolder = do_set(set_options, "mbox")) || !*newfolder)
  764. X        newfolder = DEF_MBOX;
  765. X    } else
  766. X        newfolder = *argv;
  767. X    n = 0;
  768. X    tmp = getpath(newfolder, &n);
  769. X    if (n == -1) {
  770. X        print("%s: %s\n", newfolder, tmp);
  771. X        return -1;
  772. X    } else if (n == 1) {
  773. X        print("%s: is a directory\n", tmp);
  774. X        return -1;
  775. X    }
  776. X    /* strcpy so copyback() below (which calls getpath) doesn't change
  777. X     * the data that tmp intended to point to.  Get the cwd if necessary.
  778. X     */
  779. X    n = 0;
  780. X    if (*tmp != '/') {
  781. X#ifdef SYSV
  782. X        extern char *getcwd();
  783. X        if (!getcwd(buf, MAXPATHLEN))
  784. X#else /* SYSV */
  785. X        extern char *getwd();
  786. X        if (!getwd(buf))
  787. X#endif /* SYSV */
  788. X        {
  789. X        error("getcwd: %s",buf);
  790. X        return -1;
  791. X        }
  792. X        n = strlen(buf);
  793. X        buf[n++] = '/';
  794. X    }
  795. X    (void) strcpy(&buf[n], tmp);
  796. X    }
  797. X#ifdef SUNTOOL
  798. X    if (istool > 1)
  799. X    timeout_cursors(TRUE);
  800. X#endif /* SUNTOOL */
  801. X    if (stat(buf, &statbuf) == -1 || !(statbuf.st_mode & 0400)) {
  802. X    error("Unable to read %s", buf);
  803. X#ifdef SUNTOOL
  804. X    if (istool > 1)
  805. X        timeout_cursors(FALSE);
  806. X#endif /* SUNTOOL */
  807. X    return -1;
  808. X    }
  809. X    /* If the file can't be opened for writing, autoset READ_ONLY */
  810. X    if (!(statbuf.st_mode & 0200))
  811. X    do_read_only = 1;
  812. X
  813. X    if (!(n = copyback(updating ? "Update folder?" : "Change anyway?"))) {
  814. X#ifdef SUNTOOL
  815. X    if (istool > 1)
  816. X        timeout_cursors(FALSE);
  817. X#endif /* SUNTOOL */
  818. X    /* an error occured updating the folder */
  819. X    return -1;
  820. X    }
  821. X    /* Assure that both oldfolder and mailfile are full paths */
  822. X    if (strcmp(mailfile, buf) || !*oldfolder) {
  823. X    n = 1; /* force load of new folder */
  824. X    if (!updating)
  825. X        (void) strcpy(oldfolder, *oldfolder? mailfile : buf);
  826. X    strdup(mailfile, buf);
  827. X    }
  828. X    do_read_only? turnon(glob_flags,READ_ONLY) : turnoff(glob_flags,READ_ONLY);
  829. X    last_size = spool_size = 0L;
  830. X    while (msg_cnt--) {
  831. X    xfree(msg[msg_cnt].m_date_recv);
  832. X    xfree(msg[msg_cnt].m_date_sent);
  833. X    msg[msg_cnt].m_date_recv = msg[msg_cnt].m_date_sent = NO_STRING;
  834. X    }
  835. X    msg_cnt = 0, msg[0].m_offset = 0L;
  836. X    turnoff(glob_flags, CONT_PRNT);
  837. X
  838. X    turnon(glob_flags, IGN_SIGS);
  839. X    /* clear the tempfile */
  840. X    if (tmpf)
  841. X    (void) fclose(tmpf);
  842. X    if (!do_read_only) {
  843. X    if (!(tmpf = mask_fopen(tempfile, "w"))) {
  844. X        error("error truncating %s", tempfile);
  845. X        turnoff(glob_flags, IGN_SIGS);
  846. X        return -1;
  847. X    }
  848. X    }
  849. X    /* Don't reload the folder if it was removed */
  850. X    if (n > 0) {
  851. X    if (load_folder(mailfile, TRUE, NULL) < 1) {
  852. X        last_msg_cnt = 0;
  853. X        last_size = statbuf.st_size; /* Disable check_new_mail() */
  854. X        turnoff(glob_flags, IGN_SIGS);
  855. X        return -1;
  856. X    }
  857. X    if (do_read_only && !(tmpf = fopen(mailfile, "r"))) {
  858. X        error(mailfile);
  859. X        turnoff(glob_flags, IGN_SIGS);
  860. X        return -1;
  861. X    }
  862. X    }
  863. X    last_msg_cnt = msg_cnt;  /* for check_new_mail */
  864. X    /* Prevent both bogus "new mail" messages and missed new mail */
  865. X    last_size = msg[msg_cnt].m_offset;
  866. X    if (!strcmp(mailfile, spoolfile))
  867. X    spool_size = last_spool_size = last_size;
  868. X#ifdef SUNTOOL
  869. X    if (istool) {
  870. X    extern Panel_item folder_text_item;
  871. X    Rect *rect = (Rect *)window_get(hdr_sw, WIN_RECT);
  872. X    (void) pw_rop(hdr_win, 0,0, rect->r_width, rect->r_height, PIX_CLR,
  873. X        (struct pixrect *) 0,0,0);
  874. X    panel_set_value(folder_text_item, mailfile);
  875. X    }
  876. X#endif /* SUNTOOL */
  877. X
  878. X    if (!updating || current_msg >= msg_cnt)
  879. X    current_msg = (msg_cnt? 0 : -1);
  880. X    turnoff(glob_flags, IGN_SIGS);
  881. X
  882. X    /* now sort messages according a user-defined default */
  883. X    if (!updating && msg_cnt > 1 && !strcmp(mailfile, spoolfile) &&
  884. X        (tmp = do_set(set_options, "sort"))) {
  885. X    (void) sprintf(buf, "sort %s", tmp);
  886. X    if ((argv = mk_argv(buf, &argc, TRUE)) && argc > 0) {
  887. X        /* msg_list can't be null for do_command and since we're not
  888. X         * interested in the result, call sort directly
  889. X         */
  890. X        (void) sort(argc, argv, NULL);
  891. X        free_vec(argv);
  892. X        if (!updating)
  893. X        current_msg = 0;    /* Sort may move the current message */
  894. X    }
  895. X    }
  896. X    turnoff(glob_flags, DO_UPDATE);
  897. X
  898. X    /* go to first NEW message */
  899. X    for (n = 0; n < msg_cnt && ison(msg[n].m_flags, OLD); n++)
  900. X    ;
  901. X    if (n == msg_cnt) {
  902. X    turnoff(glob_flags, NEW_MAIL);
  903. X    if (!updating) {
  904. X        /* no new message found -- try first unread message */
  905. X        for (n = 0; n < msg_cnt && isoff(msg[n].m_flags, UNREAD); n++)
  906. X        ;
  907. X    }
  908. X    } else {
  909. X    turnon(glob_flags, NEW_MAIL);
  910. X    /* default for toolmode is true */
  911. X    if (istool && !chk_option("quiet", "tool"))
  912. X        bell();
  913. X    }
  914. X    if (msg_cnt && (!updating || current_msg < 0))
  915. X    current_msg = (n == msg_cnt ? 0 : n);
  916. X
  917. X    if ((!istool || istool && !msg_cnt) && !iscurses)
  918. X    mail_status(0);
  919. X    /* be quiet if we're piping */
  920. X    if (!istool && !updating && !no_hdrs && msg_cnt
  921. X        && isoff(glob_flags, DO_PIPE))
  922. X    (void) cmd_line(sprintf(buf, "headers %d", current_msg+1), msg_list);
  923. X#ifdef SUNTOOL
  924. X    if (istool > 1) {
  925. X    if (!msg_cnt)
  926. X        print("No Mail in %s\n", mailfile);
  927. X    if (msg_cnt) {
  928. X        display_msg(current_msg, (long)0);
  929. X        do_hdrs(0, DUBL_NULL, NULL);
  930. X    }
  931. X    timeout_cursors(FALSE);
  932. X    }
  933. X#endif /* SUNTOOL */
  934. X    if (list) {
  935. X    clear_msg_list(list);
  936. X    bitput(list, list, msg_cnt, =~); /* macro */
  937. X    }
  938. X    return 0;
  939. X}
  940. X
  941. Xfolders(argc, argv)
  942. Xregister char **argv;
  943. X{
  944. X    register char *p;
  945. X    char buf[128], unused[MAXMSGS_BITS];
  946. X
  947. X    if (argv && argv[1] && !strcmp(argv[1], "-?"))
  948. X    return help(0, "folders", cmd_help);
  949. X
  950. X    if (!(p = do_set(set_options, "folder")) || !*p)
  951. X    p = DEF_FOLDER;
  952. X    (void) sprintf(buf, "ls -FR %s", p);
  953. X    if (argv = make_command(buf, TRPL_NULL, &argc))
  954. X    return do_command(argc, argv, unused);
  955. X    return -1;
  956. X}
  957. X
  958. X/*
  959. X * Determine whether a file could be a folder.  If prompt is non-NULL,
  960. X * ask the user whether we should treat the file as a folder anyway.
  961. X */
  962. Xtest_folder(name, prompt)
  963. Xchar *name, *prompt;
  964. X{
  965. X    char line[BUFSIZ], *p;
  966. X    FILE *fp = fopen(name, "r");
  967. X    int retval = FALSE;
  968. X
  969. X    if (!fp)
  970. X    return 0;
  971. X    if (fgets(line, sizeof line - 1, fp)) {
  972. X#ifndef MSG_SEPARATOR
  973. X    if (p = any(line, " \t")) {
  974. X        skipspaces(1);
  975. X        p = any(p, " \t");
  976. X    }
  977. X    if (p && !strncmp(line, "From ", 5) && (p = parse_date(p + 1)))
  978. X#else /* MSG_SEPARATOR */
  979. X    if (!strncmp(line, MSG_SEPARATOR, strlen(MSG_SEPARATOR)))
  980. X#endif /* MSG_SEPARATOR */
  981. X        retval = TRUE;
  982. X    } else
  983. X    retval = TRUE;    /* Empty files are legitimate folders */
  984. X    (void) fclose(fp);
  985. X    if (prompt && !retval) {
  986. X    char buf[BUFSIZ];
  987. X#ifdef SUNTOOL
  988. X    if (istool) {
  989. X        (void) sprintf(buf, "\"%s\": %s", name, prompt);
  990. X        return ask(buf);
  991. X    }
  992. X#endif /* SUNTOOL */
  993. X    print("\"%s\": %s [n] ", name, prompt);
  994. X    buf[0] = 0;
  995. X    retval = (Getstr(buf, sizeof (buf), 0) && lower(*buf) == 'y');
  996. X    }
  997. X    return retval;
  998. X}
  999. X
  1000. X/* merge_folders filename  -- concatenate the folder specified by filename
  1001. X *                            to the current folder.
  1002. X *
  1003. X * RETURN -1 on error -- else return 0.  A bit in msg_list is set to true
  1004. X * for each of the "new" messages read in to the current folder.
  1005. X */
  1006. Xmerge_folders(n, argv, list)
  1007. Xregister char **argv, list[];
  1008. X{
  1009. X    int no_hdrs = 0, newest_msg;
  1010. X    long orig_offset;
  1011. X    char *tmp, *newfolder = NULL, buf[MAXPATHLEN];
  1012. X
  1013. X    if (ison(glob_flags, IS_PIPE)) {
  1014. X    print("You can't pipe to the %s command.\n", *argv);
  1015. X    return -1;
  1016. X    } else if (ison(glob_flags, IS_SENDING)) {
  1017. X    print("You can't use the %s command while sending.\n", *argv);
  1018. X    return -1;
  1019. X    }
  1020. X
  1021. X    while (*++argv && **argv == '-')
  1022. X    if (!strcmp(*argv, "-?"))
  1023. X        return help(0, "merge", cmd_help);
  1024. X    else if (!strcmp(*argv, "-N"))
  1025. X        no_hdrs = !(iscurses || ison(glob_flags, PRE_CURSES));
  1026. X
  1027. X    if (!*argv)
  1028. X    return 0;
  1029. X
  1030. X    if (ison(glob_flags, READ_ONLY)) {
  1031. X    print("Folder is read-only.\n");
  1032. X    return -1;
  1033. X    }
  1034. X
  1035. X    if (!strcmp(*argv, "#"))
  1036. X    if (!*oldfolder) {
  1037. X        print("No previous folder\n");
  1038. X        return -1;
  1039. X    } else
  1040. X        newfolder = oldfolder;
  1041. X    else if (!strcmp(*argv, "&")) {
  1042. X    if (!(newfolder = do_set(set_options, "mbox")) || !*newfolder)
  1043. X        newfolder = DEF_MBOX;
  1044. X    } else
  1045. X    newfolder = *argv;
  1046. X    n = 0;
  1047. X    tmp = getpath(newfolder, &n);
  1048. X    if (n == -1) {
  1049. X    print("%s: %s\n", newfolder, tmp);
  1050. X    return -1;
  1051. X    } else if (n == 1) {
  1052. X    print("%s: is a directory\n", tmp);
  1053. X    return -1;
  1054. X    }
  1055. X
  1056. X    turnon(glob_flags, IGN_SIGS);
  1057. X    orig_offset = msg[msg_cnt].m_offset;
  1058. X    (void) load_folder(tmp, 2, list);
  1059. X    msg[msg_cnt].m_offset = orig_offset;
  1060. X    newest_msg = last_msg_cnt;
  1061. X    Debug("newest_msg = %d\n", newest_msg);
  1062. X    last_msg_cnt = msg_cnt;  /* for check_new_mail */
  1063. X    Debug("msg_cnt = %d\n", msg_cnt);
  1064. X    (void) mail_size();
  1065. X    turnoff(glob_flags, IGN_SIGS);
  1066. X
  1067. X    if ((!istool || istool && !msg_cnt)
  1068. X        && !iscurses && !ison(glob_flags, PRE_CURSES))
  1069. X    mail_status(0);
  1070. X    /* be quiet if we're piping or if told not to show headers */
  1071. X    if ((istool || !no_hdrs) && isoff(glob_flags, DO_PIPE)
  1072. X        && newest_msg < msg_cnt)
  1073. X    (void) cmd_line(sprintf(buf, "headers %d", newest_msg + 1), NULL);
  1074. X    return 0;
  1075. X}
  1076. X
  1077. X/*
  1078. X * Default digest article separator
  1079. X */
  1080. X#define ARTICLE_SEP "--------"
  1081. X
  1082. X/*
  1083. X * Undigestify messages.  If a message is in digest-format, there are many
  1084. X * messages within this message which are to be extracted.  Kinda like a
  1085. X * folder within a folder.  By default, this routine will create a new
  1086. X * folder that contains the new messages.  -m option will merge the new
  1087. X * messages into the current folder.
  1088. X */
  1089. Xdo_undigest(n, argv, list)
  1090. Xchar *argv[], list[];
  1091. X{
  1092. X    int r, articles = 0, merge = 0, appending = 0;
  1093. X    char buf[MAXPATHLEN], cmdbuf[MAXPATHLEN], newlist[MAXMSGS_BITS], *dir;
  1094. X    char *art_sep = ARTICLE_SEP, *mktemp();
  1095. X    FILE *fp;
  1096. X
  1097. X    while (argv && *++argv && **argv == '-') {
  1098. X    switch(argv[0][1]) {
  1099. X        case 'm':
  1100. X        if (ison(glob_flags, READ_ONLY)) {
  1101. X            print("Folder is read only.\n");
  1102. X            return -1;
  1103. X        }
  1104. X        merge++;
  1105. X        when 'p':
  1106. X        if (*++argv)
  1107. X            art_sep = *argv;
  1108. X        else {
  1109. X            print("Specify separator pattern with -p.\n");
  1110. X            return -1;
  1111. X        }
  1112. X        otherwise: return help(0, "undigest", cmd_help);
  1113. X    }
  1114. X    }
  1115. X
  1116. X    if ((n = get_msg_list(argv, list)) == -1)
  1117. X    return -1;
  1118. X
  1119. X    argv += n;
  1120. X
  1121. X    if (*argv) {
  1122. X    int isdir = 1; /* Ignore file nonexistance errors */
  1123. X    (void) strcpy(buf, getpath(*argv, &isdir));
  1124. X    if (isdir < 0) {
  1125. X        print("%s: %s\n", *argv, buf);
  1126. X        return -1;
  1127. X    } else if (isdir == 1) {
  1128. X        print("%s: is a directory\n", buf);
  1129. X        return -1;
  1130. X    }
  1131. X    } else {
  1132. X    register char *p, *p2;
  1133. X    if (Access(dir = ".", W_OK) == 0 ||
  1134. X        (dir = do_set(set_options, "folder")) ||
  1135. X        (dir = do_set(set_options, "tmpdir")))
  1136. X        dir = getdir(dir); /* expand metachars */
  1137. X    if (!dir)
  1138. Xalted:
  1139. X        dir = ALTERNATE_HOME;
  1140. X    for (n = 0; n < msg_cnt; n++)
  1141. X        if (msg_bit(list, n))
  1142. X        break;
  1143. X
  1144. X    if (!(p = header_field(n, "subject")))
  1145. X        (void) mktemp(sprintf(buf, "%s/digestXXXXX", dir));
  1146. X    else {
  1147. X        if (!lcase_strncmp(p, "re: ", 4))
  1148. X        p += 4;
  1149. X        for (p2 = p; *p2; p2++)
  1150. X        if (!isalnum(*p2) && *p2 != '-' && *p2 != '.') {
  1151. X            *p2 = 0;
  1152. X            break;
  1153. X        }
  1154. X        p2 = buf + Strcpy(buf, dir);
  1155. X        *p2++ = '/';
  1156. X        (void) strcpy(p2, p);
  1157. X    }
  1158. X    }
  1159. X
  1160. X    if (!Access(buf, W_OK))
  1161. X    appending = ((fp = mask_fopen(buf, "a")) != NULL_FILE);
  1162. X    else
  1163. X    fp = mask_fopen(buf, "w");
  1164. X    if (!fp) {
  1165. X    if (!*argv && strcmp(dir, ALTERNATE_HOME))
  1166. X        goto alted;
  1167. X    error("can't create %s", buf);
  1168. X    return -1;
  1169. X    }
  1170. X
  1171. X    for (n = 0; n < msg_cnt; n++) {
  1172. X    if (!msg_bit(list, n))
  1173. X        continue;
  1174. X
  1175. X    print("undigesting message %d\n", n+1);
  1176. X    /* copy message into file making sure all headers exist. */
  1177. X    r = undigest(n, fp, art_sep);
  1178. X    if (r <= 0)
  1179. X        break;
  1180. X    articles += r;
  1181. X    }
  1182. X    (void) fclose(fp);
  1183. X    if (r <= 0) {
  1184. X    if (!appending)
  1185. X        (void) unlink(buf);
  1186. X    return -1;
  1187. X    }
  1188. X    if (merge) {
  1189. X    (void) cmd_line(sprintf(cmdbuf, "\\merge -N %s", buf), newlist);
  1190. X    (void) unlink(buf);
  1191. X    print("Merged in %d messages.\n", articles);
  1192. X    } else
  1193. X    print("Added %d messages to \"%s\".\n", articles, buf);
  1194. X    clear_msg_list(list);
  1195. X    for (n = 0; n < msg_cnt; n++)
  1196. X    if (msg_bit(newlist, n))
  1197. X        set_msg_bit(list, n);
  1198. X    return 0;
  1199. X}
  1200. X
  1201. X/*
  1202. X * split digest-message 'n' to file "fp" using article separator "sep".
  1203. X * return number of articles copied or -1 if system error on fputs.
  1204. X * A digest is a folder-in-a-message in a special, semi-standard form.
  1205. X */
  1206. Xundigest(n, fp, sep)
  1207. Xint n;
  1208. XFILE *fp;
  1209. Xchar *sep;
  1210. X{
  1211. X    int  art_cnt = 0, on_hdr = -1; /* on_hdr is -1 if hdr not yet found */
  1212. X    int  sep_len = (sep ? strlen(sep) : strlen(sep = ARTICLE_SEP));
  1213. X    long get_hdr = 0L;
  1214. X    char from[HDRSIZ], line[HDRSIZ], last_sep[HDRSIZ];
  1215. X    char from_hdr[256], afrom[256], adate[64];
  1216. X    char *fdate = "Xxx Xxx 00 00:00:00 0000"; /* Dummy date in ctime form */
  1217. X    SIGRET (*oldint)(), (*oldquit)();
  1218. X
  1219. X    if (!msg_get(n, from, sizeof from)) {
  1220. X    error("Unable to find msg %d", n+1);
  1221. X    return -1;
  1222. X    }
  1223. X#ifndef MSG_SEPARATOR
  1224. X    else {
  1225. X    char *p = from + 5;
  1226. X    skipspaces(0);
  1227. X    p = index(p, ' ');
  1228. X    if (p) {
  1229. X        skipspaces(0);
  1230. X        fdate = p;
  1231. X    }
  1232. X    if (fputs(from, fp) == EOF)
  1233. X        return -1;
  1234. X    }
  1235. X#endif /* !MSG_SEPARATOR */
  1236. X
  1237. X    on_intr();
  1238. X    *afrom = *adate = *last_sep = '\0';
  1239. X    while (ftell(tmpf) < msg[n].m_offset + msg[n].m_size &&
  1240. X       fgets(line, sizeof (line), tmpf)) {
  1241. X    if (ison(glob_flags, WAS_INTR))
  1242. X        goto handle_error;
  1243. X    if (*line == '\n' && on_hdr > 0)    /* blank line -- end of header */
  1244. X        on_hdr = 0;
  1245. X
  1246. X    /* Check for the beginning of a digest article */
  1247. X    if (!strncmp(line, sep, sep_len)) {
  1248. X        if (get_hdr) {
  1249. X        if (do_set(set_options, "warning"))
  1250. X            print("Article with no header? (added to article #%d)\n",
  1251. X                art_cnt);
  1252. X        /* Don't start a new message for whatever this is,
  1253. X         * just fseek back and keep appending to the last one.
  1254. X         */
  1255. X        if (fseek(tmpf, get_hdr, L_SET) < 0 ||
  1256. X            fputs(last_sep, fp) == EOF) {
  1257. X            art_cnt = -1;
  1258. X            goto handle_error;
  1259. X        }
  1260. X        get_hdr = 0L;
  1261. X        on_hdr = 0;
  1262. X        } else {
  1263. X        (void) strcpy(last_sep, line);
  1264. X        get_hdr = ftell(tmpf);
  1265. X        *afrom = *adate = '\0';
  1266. X        on_hdr = -1;    /* Haven't found the new header yet */
  1267. X        }
  1268. X        continue;
  1269. X    }
  1270. X
  1271. X    if (get_hdr) {
  1272. X        char *p = *line == '>' ? line + 1 : line;
  1273. X        if (*line == '\n') {
  1274. X        if (*afrom || *adate) {
  1275. X            (void) fseek(tmpf, get_hdr, L_SET);
  1276. X            /* Terminate the previous article */
  1277. X            art_cnt++;
  1278. X#ifdef MSG_SEPARATOR
  1279. X#ifdef END_MSG_SEP
  1280. X            if (fputs(END_MSG_SEP, fp) == EOF) {
  1281. X            art_cnt = -1;
  1282. X            goto handle_error;
  1283. X            }
  1284. X#endif /* END_MSG_SEP */
  1285. X#ifdef MMDF
  1286. X            /* MMDF has a newline in MSG_SEPARATOR */
  1287. X            if (fputs(MSG_SEPARATOR, fp) == EOF)
  1288. X#else /* !MMDF */
  1289. X            /* Other MSG_SEPARATORs need a newline */
  1290. X            if (fputs(MSG_SEPARATOR, fp) == EOF ||
  1291. X                fputc('\n', fp) == EOF)
  1292. X#endif /* MMDF */
  1293. X#else /* !MSG_SEPARATOR */
  1294. X            /* Everybody else needs a From_ line */
  1295. X            if (fprintf(fp, "From %s  %s", *afrom ? afrom : "unknown",
  1296. X                *adate ? date_to_ctime(adate) : fdate) == EOF)
  1297. X#endif /* MSG_SEPARATOR */
  1298. X            {
  1299. X            art_cnt = -1;
  1300. X            goto handle_error;
  1301. X            }
  1302. X            /* Make sure there is a From: without a leading > */
  1303. X            if (*afrom && *from_hdr && fputs(from_hdr, fp) == EOF) {
  1304. X            art_cnt = -1;
  1305. X            goto handle_error;
  1306. X            }
  1307. X            get_hdr = 0L;
  1308. X        } else if (on_hdr < 0)
  1309. X            /* Skip blanks between "--------" and the hdr */
  1310. X            get_hdr = ftell(tmpf);
  1311. X        } else if (on_hdr < 0)
  1312. X        on_hdr = 1;
  1313. X        if (on_hdr > 0 && !strncmp(p, "From: ", 6)) {
  1314. X        (void) get_name_n_addr(p + 6, NULL, afrom);
  1315. X        (void) no_newln(afrom);
  1316. X        /* Get the From: minus the leading > */
  1317. X        if (p != line)
  1318. X            (void) strcpy(from_hdr, p);
  1319. X        else /* We don't need From: twice! */
  1320. X            *from_hdr = '\0';
  1321. X        } else if (on_hdr > 0 && !strncmp(line, "Date: ", 6)) {
  1322. X        if (p = parse_date(line+6))
  1323. X            (void) strcpy(adate, p);
  1324. X        } else if (on_hdr > 0 && !lcase_strncmp(line, "end", 3)) {
  1325. X        if (!*afrom && !*adate)
  1326. X            break;
  1327. X        }
  1328. X    } else if (fputs(line, fp) == EOF) {
  1329. X        /* Pipe broken, out of file space, etc */
  1330. X        art_cnt = -1;
  1331. X        goto handle_error;
  1332. X    }
  1333. X    }
  1334. X    ++art_cnt;
  1335. X#ifdef END_MSG_SEP
  1336. X    if (art_cnt > 0 && fputs(END_MSG_SEP, fp) == EOF) {
  1337. X    art_cnt = -1;
  1338. X    goto handle_error;
  1339. X    }
  1340. X#endif /* END_MSG_SEP */
  1341. X    /* If we're still looking for a header, there is some stuff left
  1342. X     * at the end of the digest.  Create an extra article for it.
  1343. X     */
  1344. X    if (get_hdr) {
  1345. X    char *p;
  1346. X    (void) fseek(tmpf, get_hdr, L_SET);
  1347. X    if (ftell(tmpf) >= msg[n].m_offset + msg[n].m_size)
  1348. X        goto handle_error;
  1349. X#ifdef MSG_SEPARATOR
  1350. X#ifdef MMDF
  1351. X    if (fputs(MSG_SEPARATOR, fp) == EOF)
  1352. X#else /* !MMDF */
  1353. X    if (fputs(MSG_SEPARATOR, fp) == EOF ||
  1354. X        fputc('\n', fp) == EOF)
  1355. X#endif /* MMDF */
  1356. X#else /* !MSG_SEPARATOR */
  1357. X    if (fputs(from, fp) == EOF)
  1358. X#endif /* MSG_SEPARATOR */
  1359. X        art_cnt = -1;
  1360. X    if (!(p = header_field(n, "from")))
  1361. X        p = "Mush-Undigest (Real author unknown)";
  1362. X    if (fprintf(fp, "From: %s\n", p) == EOF)
  1363. X        art_cnt = -1;
  1364. X    if (!(p = header_field(n, "date")))
  1365. X        p = fdate, (void) no_newln(p);
  1366. X    if (fprintf(fp, "Date: %s\n", p) == EOF)
  1367. X        art_cnt = -1;
  1368. X    if (!(p = header_field(n, "subject")))
  1369. X        p = "Digest";
  1370. X    if (fprintf(fp, "Subject: Trailing part of %s\n\n", p) == EOF)
  1371. X        art_cnt = -1;
  1372. X    /* header_field() moves the pointer, so seek again */
  1373. X    (void) fseek(tmpf, get_hdr, L_SET);
  1374. X    while (art_cnt > 0 && ftell(tmpf) < msg[n].m_offset + msg[n].m_size
  1375. X        && fgets(line, sizeof (line), tmpf)) {
  1376. X        if (fputs(line, fp) == EOF)
  1377. X        art_cnt = -1;
  1378. X#ifdef END_MSG_SEP
  1379. X        if (!strncmp(line, END_MSG_SEP, strlen(END_MSG_SEP)))
  1380. X        break;
  1381. X#endif /* END_MSG_SEP */
  1382. X    }
  1383. X    /* The END_MSG_SEP, if any, of the digest will have been output
  1384. X     * by the while loop above, so we don't need to add one here.
  1385. X     */
  1386. X    ++art_cnt;
  1387. X    }
  1388. Xhandle_error:
  1389. X    if (art_cnt == -1)
  1390. X    error("cannot completely undigest");
  1391. X    else if (ison(glob_flags, WAS_INTR))
  1392. X    art_cnt = -1;
  1393. X    off_intr();
  1394. X    return art_cnt;
  1395. X}
  1396. END_OF_FILE
  1397. if test 19662 -ne `wc -c <'mush/folders.c'`; then
  1398.     echo shar: \"'mush/folders.c'\" unpacked with wrong size!
  1399. fi
  1400. # end of 'mush/folders.c'
  1401. fi
  1402. if test -f 'mush/signals.c' -a "${1}" != "-c" ; then 
  1403.   echo shar: Will not clobber existing file \"'mush/signals.c'\"
  1404. else
  1405. echo shar: Extracting \"'mush/signals.c'\" \(10857 characters\)
  1406. sed "s/^X//" >'mush/signals.c' <<'END_OF_FILE'
  1407. X/* @(#)signals.c    (c) copyright 10/18/86 (Dan Heller) */
  1408. X
  1409. X#include "mush.h"
  1410. X
  1411. X#ifndef SYSV
  1412. Xextern char *sys_siglist[];
  1413. X#else
  1414. X/* sys-v doesn't have normal sys_siglist */
  1415. Xstatic char    *sys_siglist[] = {
  1416. X/* no error */  "no error",
  1417. X/* SIGHUP */    "hangup",
  1418. X/* SIGINT */    "interrupt (rubout)",
  1419. X/* SIGQUIT */    "quit (ASCII FS)",
  1420. X/* SIGILL */    "illegal instruction (not reset when caught)",
  1421. X/* SIGTRAP */    "trace trap (not reset when caught)",
  1422. X/* SIGIOT */    "IOT instruction",
  1423. X/* SIGEMT */    "EMT instruction",
  1424. X/* SIGFPE */    "floating point exception",
  1425. X/* SIGKILL */    "kill (cannot be caught or ignored)",
  1426. X/* SIGBUS */    "bus error",
  1427. X/* SIGSEGV */    "segmentation violation",
  1428. X/* SIGSYS */    "bad argument to system call",
  1429. X/* SIGPIPE */    "write on a pipe with no one to read it",
  1430. X/* SIGALRM */    "alarm clock",
  1431. X/* SIGTERM */    "software termination signal from kill",
  1432. X/* SIGUSR1 */    "user defined signal 1",
  1433. X/* SIGUSR2 */    "user defined signal 2",
  1434. X/* SIGCLD */    "death of a child",
  1435. X/* SIGPWR */    "power-fail restart"
  1436. X};
  1437. X#endif /* SYSV */
  1438. X
  1439. XSIGRET
  1440. Xintrpt(sig)
  1441. X{
  1442. X    Debug("interrupt() caught: %d\n", sig);
  1443. X    mac_flush();
  1444. X    turnon(glob_flags, WAS_INTR);
  1445. X}
  1446. X
  1447. X/*
  1448. X * catch signals to reset state of the machine.  Always print signal caught.
  1449. X * If signals are ignored, return.  If we're running the shell, longjmp back.
  1450. X */
  1451. X/*ARGSUSED*/
  1452. XSIGRET
  1453. Xcatch(sig)
  1454. X{
  1455. X    Debug("Caught signal: %d\n", sig);
  1456. X    (void) signal(sig, catch);
  1457. X    if (ison(glob_flags, IGN_SIGS) && sig != SIGTERM && sig != SIGHUP)
  1458. X    return;
  1459. X    mac_flush();
  1460. X    print("%s: %s\n", prog_name, sys_siglist[sig]);
  1461. X    turnoff(glob_flags, IS_PIPE);
  1462. X    if (istool || sig == SIGTERM || sig == SIGHUP) {
  1463. X    if (istool) { /* istool is 2 if tool is complete */
  1464. X#if defined(SUNTOOL) && !defined(SUN_4_0)
  1465. X        if (sig == SIGHUP && window_get(tool, WIN_SHOW))
  1466. X        return;
  1467. X#endif /* SUNTOOL && !SUN_4_0 */
  1468. X        istool = 1;
  1469. X    }
  1470. X    (void) setjmp(jmpbuf);
  1471. X    if (ison(glob_flags, IS_GETTING))
  1472. X        rm_edfile(-1);
  1473. X    cleanup(sig);
  1474. X    }
  1475. X    if (ison(glob_flags, DO_SHELL)) {
  1476. X    /* wrapcolumn may have been trashed -- restore it */
  1477. X    if (ison(glob_flags, IS_GETTING)) {
  1478. X        char *fix = do_set(set_options, "wrapcolumn");
  1479. X        if (fix && *fix)
  1480. X        wrapcolumn = atoi(fix);
  1481. X    }
  1482. X    turnoff(glob_flags, IS_GETTING);
  1483. X    longjmp(jmpbuf, 1);
  1484. X    } else
  1485. X    puts("exiting"), cleanup(sig);
  1486. X}
  1487. X
  1488. X#ifdef SIGCONT
  1489. XSIGRET
  1490. Xstop_start(sig)
  1491. X{
  1492. X    extern FILE *ed_fp;
  1493. X
  1494. X    Debug("Caught signal: %d", sig);
  1495. X    if (sig == SIGCONT) {
  1496. X    (void) signal(SIGTSTP, stop_start);
  1497. X    (void) signal(SIGCONT, stop_start);
  1498. X    echo_off();
  1499. X    if (istool || ison(glob_flags, IGN_SIGS) && !iscurses)
  1500. X        return;
  1501. X    /* we're not in an editor but we're editing a letter */
  1502. X    if (ison(glob_flags, IS_GETTING)) {
  1503. X        if (ed_fp)
  1504. X        print("(Continue editing letter)\n");
  1505. X    }
  1506. X#ifdef CURSES
  1507. X    else if (iscurses)
  1508. X        if (ison(glob_flags, IGN_SIGS)) {
  1509. X        clr_bot_line();
  1510. X        if (msg_cnt)
  1511. X            puts(compose_hdr(current_msg));
  1512. X        mail_status(1), addstr("...continue... ");
  1513. X        refresh();
  1514. X        } else {
  1515. X        int curlin = max(1, current_msg - n_array[0] + 1);
  1516. X        redraw();
  1517. X        print("Continue");
  1518. X        move(curlin, 0);
  1519. X        refresh();
  1520. X        /* make sure we lose reverse video on continuation */
  1521. X        if (ison(glob_flags, REV_VIDEO) && msg_cnt) {
  1522. X            char buf[256];
  1523. X            (void) strncpy(buf, compose_hdr(current_msg), COLS-1);
  1524. X            buf[COLS-1] = 0; /* strncpy does not null terminate */
  1525. X            mvaddstr(curlin, 0, buf);
  1526. X        }
  1527. X        }
  1528. X#endif /* CURSES */
  1529. X    else
  1530. X        mail_status(1), (void) fflush(stdout);
  1531. X    } else {
  1532. X#ifdef CURSES
  1533. X    if (iscurses) {
  1534. X        /* when user stops mush, the current header is not in reverse
  1535. X         * video -- note that a refresh() has not been called in curses.c!
  1536. X         * so, make sure that when a continue is called, the reverse video
  1537. X         * for the current message returns.
  1538. X         */
  1539. X        turnon(glob_flags, WAS_INTR);
  1540. X        if (isoff(glob_flags, IGN_SIGS) && ison(glob_flags, REV_VIDEO) &&
  1541. X            msg_cnt) {
  1542. X        int curlin = max(1, current_msg - n_array[0] + 1);
  1543. X        char buf[256];
  1544. X        scrn_line(curlin, buf);
  1545. X        STANDOUT(curlin, 0, buf);
  1546. X        }
  1547. X        print("Stopping...");
  1548. X    }
  1549. X#endif /* CURSES */
  1550. X    echo_on();
  1551. X    (void) signal(SIGTSTP, SIG_DFL);
  1552. X    (void) signal(SIGCONT, stop_start);
  1553. X    (void) kill(getpid(), sig);
  1554. X    }
  1555. X}
  1556. X#endif /* SIGCONT */
  1557. X
  1558. X/*ARGSUSED*/
  1559. Xvoid
  1560. Xcleanup(sig)
  1561. X{
  1562. X    char buf[128], c;
  1563. X
  1564. X    if (sig != SIGTERM && sig != SIGHUP && ison(glob_flags, IGN_SIGS))
  1565. X    c = 'n';
  1566. X    else
  1567. X    c = 'y';
  1568. X
  1569. X#ifdef CURSES
  1570. X    if (iscurses && sig != SIGHUP)
  1571. X    iscurses = FALSE, endwin();
  1572. X#endif /* CURSES */
  1573. X
  1574. X    echo_on();
  1575. X
  1576. X    if (ison(glob_flags, IS_GETTING))
  1577. X    turnoff(glob_flags, IS_GETTING), dead_letter(sig);
  1578. X    if ((sig == SIGSEGV || sig == SIGBUS) && isoff(glob_flags, IGN_SIGS)
  1579. X        && *tempfile && !istool) {
  1580. X    (void) fprintf(stderr, "remove %s [y]? ", tempfile), (void) fflush(stderr);
  1581. X    if (fgets(buf, sizeof(buf), stdin))
  1582. X        c = lower(*buf);
  1583. X    }
  1584. X    if (c != 'n' && *tempfile) {
  1585. X    if (sig == SIGHUP && do_set(set_options, "hangup") && copyback(NULL))
  1586. X        (void) unlink(tempfile);
  1587. X    else if (unlink(tempfile) && !sig && errno != ENOENT)
  1588. X        error(tempfile);
  1589. X    }
  1590. X    if (sig == SIGSEGV || sig == SIGBUS) {
  1591. X    if (isoff(glob_flags, IGN_SIGS) && !istool) {
  1592. X        (void) fprintf(stderr, "coredump [n]? "), (void) fflush(stderr);
  1593. X        if (fgets(buf, sizeof(buf), stdin))
  1594. X        c = lower(*buf);
  1595. X    }
  1596. X    if (c == 'y') {
  1597. X        if (!istool)
  1598. X        puts("dumping core for debugging");
  1599. X        abort();
  1600. X    }
  1601. X    }
  1602. X    exit(sig);
  1603. X}
  1604. X
  1605. Xlong    last_spool_size = -1;    /* declared here cuz it's initialized here */
  1606. X
  1607. X#ifdef SUNTOOL
  1608. XNotify_value
  1609. Xdo_check()
  1610. X{
  1611. X    if (isoff(glob_flags, IGN_SIGS))
  1612. X    (void) check_new_mail();
  1613. X    return (NOTIFY_DONE) ;
  1614. X}
  1615. X#endif /* SUNTOOL */
  1616. X
  1617. X/*
  1618. X * Get any new mail that has arrived.  This function assumes that a
  1619. X * call to mail_size() has already been done, so that last_spool_size
  1620. X * can be compared to spool_size to decide what should be done.
  1621. X *
  1622. X * The value for last_spool_size is updated to the new spool_size only
  1623. X * if update_size is TRUE.  check_new_mail() depends on the -1 initial
  1624. X * value of last_spool_size for correct "New mail" messages, so it
  1625. X * uses FALSE and updates last_spool_size itself.
  1626. X */
  1627. Xget_new_mail(update_size)
  1628. Xint update_size;
  1629. X{
  1630. X    if (last_spool_size > spool_size && !strcmp(mailfile, spoolfile)) {
  1631. X    print("Someone changed \"%s\"!  ", mailfile);
  1632. X    if (update_size)
  1633. X        return 1;    /* Don't reinit if called from copyback() */
  1634. X    print_more("Reinitializing...\n");
  1635. X    if (isoff(glob_flags, READ_ONLY))
  1636. X        (void) emptyfile(&tmpf, tempfile);
  1637. X    current_msg = msg_cnt = 0;
  1638. X    }
  1639. X    if (load_folder(mailfile, 1, NULL) < 1) {
  1640. X    print("Can't load new mail: \"%s\" may be corrupted!\n", mailfile);
  1641. X    turnon(glob_flags, DO_UPDATE);    /* Don't reload without rewrite */
  1642. X    return update_size;
  1643. X    /* NOTE: The above is used to stop check_new_mail() from calling
  1644. X     * show_new_mail(), while still allowing copyback() to detect the
  1645. X     * possible error and to query about updating the folder.  There
  1646. X     * should be a better-defined way to handle this.
  1647. X     */
  1648. X    }
  1649. X    if (last_spool_size != spool_size) {
  1650. X    if (update_size)
  1651. X        last_spool_size = spool_size;
  1652. X    if (msg_cnt < last_msg_cnt)
  1653. X        turnoff(glob_flags, NEW_MAIL);
  1654. X    else {
  1655. X        turnon(glob_flags, NEW_MAIL);
  1656. X        if (current_msg < 0)
  1657. X        current_msg = 0;
  1658. X    }
  1659. X    return 1;
  1660. X    }
  1661. X    return 0;
  1662. X}
  1663. X
  1664. X#ifdef SUNTOOL
  1665. Xint is_iconic, was_iconic;
  1666. X#endif /* SUNTOOL */
  1667. X
  1668. X/*
  1669. X * Display a summary when new mail has come in.  sprintf it all into one
  1670. X * buffer and print that instead of separate print statements to allow
  1671. X * the tool mode to make one print statement. The reason for this is that
  1672. X * when the tool is refreshed (caused by a resize, reopen, move, top, etc)
  1673. X * the last thing printed is displayed -- display the entire line.
  1674. X */
  1675. Xshow_new_mail()
  1676. X{
  1677. X    char        buf[BUFSIZ];
  1678. X    register char  *p = buf;
  1679. X    int           noisy = !chk_option("quiet", "newmail");
  1680. X#ifdef CURSES
  1681. X    int new_hdrs = last_msg_cnt;
  1682. X#endif /* CURSES */
  1683. X
  1684. X    if (msg_cnt == last_msg_cnt)
  1685. X    return 1;    /* Nothing to print */
  1686. X#ifdef SUNTOOL
  1687. X    if (istool) {
  1688. X    mail_status(0);
  1689. X    (void) do_hdrs(0, DUBL_NULL, NULL);
  1690. X    if (noisy && !chk_option("quiet", "tool"))
  1691. X        bell();
  1692. X    }
  1693. X#endif /* SUNTOOL */
  1694. X    if (msg_cnt < last_msg_cnt) {
  1695. X    last_msg_cnt = msg_cnt;
  1696. X    if (!istool)
  1697. X        mail_status(0);
  1698. X    if (iscurses && isoff(glob_flags, CNTD_CMD))
  1699. X        (void) do_hdrs(0, DUBL_NULL, NULL);
  1700. X    return 0;
  1701. X    }
  1702. X    if (noisy) {
  1703. X    p += Strcpy(p, "New mail ");
  1704. X    if (msg_cnt - last_msg_cnt <= 1)
  1705. X        p += strlen(sprintf(p, "(#%d) ", msg_cnt));
  1706. X    else
  1707. X        p += strlen(sprintf(p, "(#%d thru #%d)\n", last_msg_cnt+1,msg_cnt));
  1708. X    }
  1709. X#ifdef SUNTOOL
  1710. X    /*
  1711. X     * If mush is in tool mode and in icon form, don't update
  1712. X     * last_msg_cnt so that when the tool is opened, print() will
  1713. X     * print the correct number of "new" messages.
  1714. X     */
  1715. X    if (istool && (was_iconic = (int) window_get(tool, FRAME_CLOSED)))
  1716. X    (void) strcpy(p, "\n");
  1717. X    else
  1718. X#endif /* SUNTOOL */
  1719. X    {
  1720. X    if (!noisy || iscurses && isoff(glob_flags, CNTD_CMD))
  1721. X        last_msg_cnt = msg_cnt;
  1722. X    else while (last_msg_cnt < msg_cnt) {
  1723. X        char *p2 = compose_hdr(last_msg_cnt++) + 9;
  1724. X        if (strlen(p2) + (p - buf) >= BUFSIZ-5) {
  1725. X        (void) strcpy(p, "...\n");
  1726. X        /* force a break by setting last_msg_cnt correctly */
  1727. X        last_msg_cnt = msg_cnt;
  1728. X        } else
  1729. X        p += strlen(sprintf(p, " %s\n", p2));
  1730. X    }
  1731. X    }
  1732. X#ifdef CURSES
  1733. X    if (iscurses && isoff(glob_flags, CNTD_CMD)) {
  1734. X    if (new_hdrs - n_array[screen-1] < screen)
  1735. X        (void) do_hdrs(0, DUBL_NULL, NULL);
  1736. X    print("%s ...", buf);
  1737. X    } else
  1738. X#endif /* CURSES */
  1739. X    if (noisy)
  1740. X        print("%s", buf); /* buf might have %'s in them!!! */
  1741. X    return 1;
  1742. X}
  1743. X
  1744. X/*
  1745. X * Look for new mail and read it in if any has arrived.
  1746. X * return 0 if no new mail, 1 if new mail and -1 if new mail is in system
  1747. X * folder, but current mbox is not system mbox.
  1748. X */
  1749. Xcheck_new_mail()
  1750. X{
  1751. X    int        ret_value;
  1752. X
  1753. X    /* if fullscreen access in progress (help), don't do anything */
  1754. X    if (ret_value = mail_size()) {
  1755. X#ifdef SUNTOOL
  1756. X    /* if our status has changed from icon to open window, then
  1757. X     * there will already be a message stating number of new
  1758. X     * messages.  reset `n' to msg_cnt so we don't restate
  1759. X     * the same # of new messages upon receipt of yet another new message.
  1760. X     */
  1761. X    if (istool && !(is_iconic = ((int) window_get(tool, FRAME_CLOSED))) &&
  1762. X        was_iconic)
  1763. X        last_msg_cnt = msg_cnt;
  1764. X#endif /* SUNTOOL */
  1765. X    if (get_new_mail(0) && !show_new_mail())
  1766. X        return 0;
  1767. X    } else
  1768. X#ifdef SUNTOOL
  1769. X    if (!istool || !is_iconic)
  1770. X#endif /* SUNTOOL */
  1771. X        turnoff(glob_flags, NEW_MAIL);
  1772. X    if (last_spool_size > -1 && /* handle first case */
  1773. X        strcmp(mailfile, spoolfile) && last_spool_size < spool_size)
  1774. X    print("You have new mail in your system mailbox.\n"), ret_value = -1;
  1775. X    last_spool_size = spool_size;
  1776. X    return ret_value;
  1777. X}
  1778. X
  1779. X/*ARGSUSED*/   /* we ignore the sigstack, cpu-usage, etc... */
  1780. XSIGRET
  1781. Xbus_n_seg(sig)
  1782. X{
  1783. X    (void) signal(sig, SIG_DFL);
  1784. X    (void) fprintf(stderr, "%s: %s\n", prog_name,
  1785. X    (sig == SIGSEGV)? "Segmentation violation": "Bus error");
  1786. X    cleanup(sig);
  1787. X}
  1788. END_OF_FILE
  1789. if test 10857 -ne `wc -c <'mush/signals.c'`; then
  1790.     echo shar: \"'mush/signals.c'\" unpacked with wrong size!
  1791. fi
  1792. # end of 'mush/signals.c'
  1793. fi
  1794. echo shar: End of archive 14 \(of 19\).
  1795. cp /dev/null ark14isdone
  1796. MISSING=""
  1797. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1798.     if test ! -f ark${I}isdone ; then
  1799.     MISSING="${MISSING} ${I}"
  1800.     fi
  1801. done
  1802. if test "${MISSING}" = "" ; then
  1803.     echo You have unpacked all 19 archives.
  1804.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1805. else
  1806.     echo You still need to unpack the following archives:
  1807.     echo "        " ${MISSING}
  1808. fi
  1809. ##  End of shell archive.
  1810. exit 0
  1811.  
  1812.