home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / mush.lzh / mush.14 < prev    next >
Encoding:
Text File  |  1990-05-06  |  53.7 KB  |  1,805 lines

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