home *** CD-ROM | disk | FTP | other *** search
/ ftp.freefriends.org / ftp.freefriends.org.tar / ftp.freefriends.org / arnold / Source / mush.rstevens.tar.gz / mush.tar / curses.c < prev    next >
C/C++ Source or Header  |  1992-10-30  |  29KB  |  1,037 lines

  1. /* @(#)curses.c    (c) copyright 3/18/87 (Dan Heller) */
  2.  
  3. /* curses.c -- routine to deal with the curses interface */
  4.  
  5. #include "mush.h"
  6. #ifdef CURSES
  7. #include "bindings.h"
  8.  
  9. curses_init(argc, argv)
  10. register char **argv;
  11. {
  12.     char buf[80];
  13.     extern char *UP;
  14. #ifndef M_UNIX
  15.     extern char ttytype[];
  16. #endif /* M_UNIX */
  17.  
  18.     if (argv && *++argv && !strcmp(*argv, "-?"))
  19.     return help(0, "curses", cmd_help);
  20. #ifdef SUNTOOL
  21.     if (istool) {
  22.     print("Sorry, can't change to curses mode from tool.\n");
  23.     return -1;
  24.     } else
  25. #endif /* SUNTOOL */
  26.     if (!is_shell) {
  27.     /*
  28.      * Can't start curses, but we can prepare to.
  29.      * Also allow -C switch to be shut off.
  30.      */
  31.     if (argv && *argv && !lcase_strncmp(*argv, "off", -1))
  32.         turnoff(glob_flags, PRE_CURSES);
  33.     else
  34.         turnon(glob_flags, PRE_CURSES);
  35.     return 0;
  36.     } else if (argc && (iscurses || ison(glob_flags, PRE_CURSES))) {
  37.     print("You are already using curses mode.\n");
  38.     return -1;
  39.     } else if (ison(glob_flags, IS_GETTING)) {
  40.     print("Finish your letter first.\n");
  41.     return -1;
  42.     }
  43.  
  44. #ifndef attrset        /* terminfo version of curses */
  45.     /* you can not start curses in no echo mode.. must be in normal mode */
  46.     echom();
  47.     nocrmode();
  48. #endif /* attrset */
  49.     (void) initscr();
  50. #ifdef SIGCONT
  51.     /* initscr will play with signals -- make sure they're set right. */
  52.     (void) signal(SIGTSTP, stop_start);
  53.     (void) signal(SIGCONT, stop_start);
  54. #endif /* SIGCONT */
  55. #if !defined(SYSV) && !defined(USG)
  56.     if (!UP || !*UP)
  57. #else /* ~SYSV && ~USG */
  58.     if (!stdscr)
  59. #endif /* ~SYSV && ~USG */
  60.          {
  61.     print("Terminal type %s can not use the curses interface.\n", ttytype);
  62.     return -1;
  63.     }
  64.     iscurses = TRUE;
  65.     noechom(); /* reset tty state -- */
  66.     crmode(); /* do not use "echo_on/off()" */
  67.     scrollok(stdscr, TRUE);
  68.     /* if the user hasn't set his screen explicitly, set it for him */
  69.     set_screen_size();
  70.     if (crt > LINES - 1 || !do_set(set_options, "crt")) {
  71.     crt = LINES;
  72.     (void)cmd_line(sprintf(buf, "\\set screen = %d crt = %d", screen, crt),
  73.         msg_list);
  74.     } else
  75.     (void)cmd_line(sprintf(buf, "\\set screen = %d", screen), msg_list);
  76.     if (argc) {
  77.     (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1), msg_list);
  78.     (void) curses_help_msg(TRUE);
  79.     }
  80.     if (!do_set(set_options, "no_reverse"))
  81.     turnon(glob_flags, REV_VIDEO);
  82.     turnoff(glob_flags, CONT_PRNT);
  83.     return 0; /* doesn't affect messages */
  84. }
  85.  
  86. struct cmd_map *active_cmd;    /* See bindings.h for description */
  87.  
  88. /*
  89.  * get input in cbreak mode and execute the appropriate command.
  90.  * when the command is done (usually), the user is prompted to
  91.  * hit any key to continue. At this point, the user may enter a
  92.  * new command so no screen refreshing needs to be done. This
  93.  * new command is returned to caller and may be passed back.
  94.  *
  95.  * The flag CNTD_CMD (continued command) is set if
  96.  * this routine is called with the passed parameter (c) != 0. If
  97.  * so, then the character passed is the character input by the
  98.  * user at the last "hit return" prompt indicating that he wants
  99.  * to execute a new command and not draw the screen.
  100.  *
  101.  * CNTD_CMD is also set if the command that the user invokes
  102.  * causes any sort of output that requires a screen refresh.  The
  103.  * variable redo is set to 1 if the header page not only requires
  104.  * redrawing, but updating ... (new call to do_hdrs)
  105.  *
  106.  * calls that say: print("%s", compose_hdr(current_msg)) are constructed
  107.  * that way because if the header has a `%' in it, then print will try to
  108.  * expand it.
  109.  */
  110. curses_command(c)
  111. register int c;
  112. {
  113.     char    buf[BUFSIZ], file[128], list[128];
  114.     int     n, curlin;
  115.     static int  redo = 0;  /* set if headers should be redrawn */
  116.  
  117.     if (c != 0)
  118.     turnon(glob_flags, CNTD_CMD);
  119.     else
  120.     turnoff(glob_flags, CNTD_CMD);
  121.     clear_msg_list(msg_list); /* play it safe */
  122.     if (isoff(glob_flags, CNTD_CMD)) {
  123.     (void) check_new_mail();
  124.     curlin = max(1, current_msg - n_array[0] + 1);
  125.     if (ison(glob_flags, REV_VIDEO) && msg_cnt) {
  126.         scrn_line(curlin, buf);
  127.         STANDOUT(curlin, 0, buf);
  128.     }
  129.     mail_status(0);
  130.     move(curlin, 0), refresh();
  131.     /* reprint to remove reverse video from current line (don't refresh) */
  132.     if (ison(glob_flags, REV_VIDEO) && msg_cnt)
  133.         mvaddstr(curlin, 0, buf);
  134.     c = getcmd(); /* get input AFTER line redrawn without reverse video */
  135.     }
  136.     buf[0] = list[0] = file[0] = '\0';
  137.  
  138.     if (c == C_WRITE_LIST || c == C_SAVE_LIST || c == C_COPY_LIST
  139.        || c == C_DELETE_LIST || c == C_UNDEL_LIST) {
  140.     if (msg_cnt < 1) {
  141.         mac_flush();
  142.         print("Not enough messages.");
  143.         c = C_NULL;
  144.     } else if (c == C_DELETE_LIST && ison(glob_flags, READ_ONLY)) {
  145.         mac_flush();
  146.         print("Folder is read-only.");
  147.         c = C_NULL;
  148.     } else if (!curses_msg_list(sprintf(buf, "%s msg list: ",
  149.         (c == C_WRITE_LIST)? "write" : (c == C_SAVE_LIST)?  "save" :
  150.         (c == C_COPY_LIST)? "copy" :
  151.         (c == C_DELETE_LIST)? "delete" : "undelete"), list, msg_list))
  152.         c = C_NULL;
  153.     if (ison(glob_flags, CNTD_CMD))
  154.         putchar('\n');
  155.     }
  156.  
  157.     /* first do non-mail command type stuff */
  158.     switch (c) {
  159.     case C_ERROR :
  160.         bell();
  161.         mac_flush();
  162.  
  163.     when C_NULL :
  164.         if (isoff(glob_flags, CNTD_CMD))
  165.         bell();
  166.  
  167.     /* goto a specific message number */
  168.     when C_GOTO_MSG :
  169.         if (curses_msg_list(strcpy(buf, "goto msg: "), list, msg_list)) {
  170.         /*
  171.          * Reset the current message in case a 
  172.          * backquoted command (like `from`) changed it
  173.          */
  174.         n = current_msg;
  175.         do if (++n >= msg_cnt)
  176.             n = 0;
  177.         while (n != current_msg && !msg_bit(msg_list, n));
  178.         if (n == current_msg && !msg_bit(msg_list, n)) {
  179.             mac_flush(); /* bail out if in macro processing */
  180.             print("Message not found.");
  181.         }
  182.         else if ((current_msg = n) < n_array[0]
  183.             || n > n_array[screen-1])
  184.             redo = 1;
  185.         } else {
  186.         mac_flush();
  187.         bell();
  188.         }
  189.         if (ison(glob_flags, CNTD_CMD) && msg_cnt)
  190.         print("%-.*s", COLS-2, compose_hdr(current_msg));
  191.         if (ison(glob_flags, CNTD_CMD))
  192.         putchar('\n');
  193.  
  194.     /* screen optimization stuff */
  195.     when C_REVERSE :
  196.         if (ison(glob_flags, REV_VIDEO))
  197.         turnoff(glob_flags, REV_VIDEO);
  198.         else
  199.         turnon(glob_flags, REV_VIDEO);
  200.  
  201.     when C_REDRAW : redo = 1;
  202.  
  203.     /*
  204.      * screen movement
  205.      */
  206.     when C_NEXT_MSG :
  207.         if (current_msg + 2 > msg_cnt ||
  208.         isoff(glob_flags, CNTD_CMD) && curlin == LINES-2) {
  209.         mac_flush();    /* Bail out if in macro processing */
  210.         bell();        /* reached the end */
  211.         } else {
  212.         if (ison(glob_flags, CNTD_CMD)) {
  213.             if (++current_msg > n_array[screen-1])
  214.             redo = 1;
  215.             print("%-.*s", COLS-2, compose_hdr(current_msg));
  216.             putchar('\n');
  217.         } else {
  218.             if (++current_msg > n_array[screen-1])
  219.             n_array[screen++] = current_msg;
  220.             move(++curlin, 0);
  221.             printw("%-.*s", COLS-2, compose_hdr(current_msg));
  222.             clrtoeol();
  223.         }
  224.         }
  225.  
  226.     when C_PREV_MSG :
  227.         if (isoff(glob_flags, CNTD_CMD) && curlin == 1 ||
  228.             current_msg == 0 || msg_cnt == 0) {
  229.         mac_flush();    /* Bail out if in macro processing */
  230.         bell();      /* at the beginning */
  231.         } else {
  232.         if (--current_msg < n_array[0])
  233.             redo = 1;
  234.         if (ison(glob_flags, CNTD_CMD)) {
  235.             print("%-.*s", COLS-2, compose_hdr(current_msg));
  236.             putchar('\n');
  237.         }
  238.         }
  239.  
  240.     when C_FIRST_MSG : case C_LAST_MSG :
  241.         if (!msg_cnt) {
  242.         mac_flush();
  243.         bell();
  244.         break;
  245.         }
  246.         n = current_msg;
  247.         move(LINES-1, 0), refresh();
  248.         if (c == C_FIRST_MSG && (current_msg = 0) < n_array[0] ||
  249.         c == C_LAST_MSG && (current_msg = msg_cnt-1)> n_array[screen-1])
  250.         if (isoff(glob_flags, CNTD_CMD))
  251.             (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1),
  252.                  msg_list);
  253.         else
  254.             redo = 1;
  255.         if (ison(glob_flags, CNTD_CMD) && n != current_msg)
  256.         print("%-.*s", COLS-2, compose_hdr(current_msg)), putchar('\n');
  257.  
  258.     /* top and bottom of headers screen */
  259.     when C_TOP_PAGE : case C_BOTTOM_PAGE :
  260.         if (msg_cnt && isoff(glob_flags, CNTD_CMD))
  261.         if (c == C_TOP_PAGE)
  262.             current_msg = n_array[0];
  263.         else
  264.             current_msg = min(n_array[screen-1], msg_cnt-1);
  265.         else {
  266.         mac_flush();
  267.         bell();
  268.         }
  269.  
  270.     when C_NEXT_SCREEN : /* next page */
  271.         move(LINES-1, 0), refresh();
  272.         if (msg_cnt-1 > n_array[screen-1]) {
  273.         clear();
  274.         set_screen_size();
  275.         (void) cmd_line(strcpy(buf, "\\headers +"), msg_list);
  276.         if (current_msg < n_array[0])
  277.             current_msg = n_array[0];
  278.         (void) curses_help_msg(TRUE);
  279.         return redo = 0;
  280.         } else {
  281.         mac_flush();
  282.         bell();
  283.         }
  284.  
  285.     when C_PREV_SCREEN : /* previous page */
  286.         move(LINES-1, 0), refresh();
  287.         if (n_array[0] > 0) {
  288.         clear();
  289.         set_screen_size();
  290.         (void) cmd_line(strcpy(buf, "\\headers -"), msg_list);
  291.         if (current_msg > n_array[screen-1])
  292.             current_msg = n_array[screen-1];
  293.         (void) curses_help_msg(TRUE);
  294.         return redo = 0;
  295.         } else {
  296.         mac_flush();
  297.         bell();
  298.         }
  299.  
  300.     /* read from/save to record file (.mushrc) */
  301.     when C_SOURCE : case C_SAVEOPTS : {
  302.         int argc;
  303.         char *argv[3];
  304.         print("%s filename [default]: ",
  305.         (c == C_SOURCE)? "source" : "save options to");
  306.         argc = Getstr(file, COLS-40, 0);
  307.         clr_bot_line();
  308.         if (argc < 0)
  309.         break;
  310.         if (argc > 0)
  311.         argv[1] = file, argc = 2;
  312.         else
  313.         argc = 1;
  314.         argv[argc] = NULL;
  315.         turnon(glob_flags, PRE_CURSES);
  316.         if (c == C_SOURCE) {
  317.         (void) source(argc, argv);
  318.         mac_flush(); /* can't change things in mid-macro */
  319.         redo = isoff(glob_flags, CNTD_CMD);
  320.         } else
  321.         (void) save_opts(argc, argv);
  322.         turnoff(glob_flags, PRE_CURSES);
  323.     }
  324.  
  325.     /*
  326.      * search commands
  327.      */
  328.     when C_NEXT_SEARCH : case C_PREV_SEARCH : case C_CONT_SEARCH :
  329.         if (c != C_CONT_SEARCH)
  330.         c = search(0 + (c == C_PREV_SEARCH));
  331.         else
  332.         c = search(-1);
  333.         if (ison(glob_flags, CNTD_CMD))
  334.         putchar('\n');
  335.         if (c == 0)
  336.         break;
  337.         if (ison(glob_flags, CNTD_CMD))
  338.         print("%-.*s",COLS-2, compose_hdr(current_msg)), putchar('\n');
  339.         if (n_array[0] > current_msg || n_array[screen-1] < current_msg) {
  340.         redo = 1;
  341.         if (isoff(glob_flags, CNTD_CMD))
  342.             (void) cmd_line(sprintf(buf, "\\headers %d",
  343.                         current_msg+1), msg_list);
  344.         }
  345.  
  346.     /*
  347.      * actions on messages
  348.      */
  349.     /* delete/undelete */
  350.     when C_DELETE_MSG : case C_DELETE_LIST :
  351.     case C_UNDEL_MSG : case C_UNDEL_LIST :
  352.         if (!msg_cnt) {
  353.         print("No messages.");
  354.         if (ison(glob_flags, CNTD_CMD))
  355.             putchar('\n');
  356.         break;
  357.         }
  358.         if (ison(glob_flags, READ_ONLY)) {
  359.         mac_flush();
  360.         print("Folder is read-only.");
  361.         if (ison(glob_flags, CNTD_CMD))
  362.             putchar('\n');
  363.         break;
  364.         }
  365.         Debug("current message = %d", current_msg + 1);
  366.         if (!*list)
  367.         set_msg_bit(msg_list, current_msg);
  368.         turnon(glob_flags, DO_UPDATE);
  369.         for (n = 0; n < msg_cnt; n++)
  370.         if (msg_bit(msg_list, n)) {
  371.             if (c == C_DELETE_MSG || c == C_DELETE_LIST)
  372.             turnon(msg[n].m_flags, DELETE|DO_UPDATE);
  373.             else
  374.             turnoff(msg[n].m_flags, DELETE);
  375.             if (isoff(glob_flags, CNTD_CMD) && (msg_cnt < screen ||
  376.             n >= n_array[0] && n <= n_array[screen-1])) {
  377.             move(max(1, n - n_array[0] + 1), 0);
  378.             printw("%-.*s", COLS-1, compose_hdr(n));
  379.             } else
  380.             redo = 1;
  381.         }
  382.         if (ison(glob_flags, CNTD_CMD) || *list) {
  383.         /* print(), THEN putchar() -- overwrite line */
  384.         if (ison(glob_flags, CNTD_CMD)) {
  385.             print("%sdeleted %s",
  386.             (c == C_DELETE_MSG || c == C_DELETE_LIST)? "":"un", list);
  387.             putchar('\n');
  388.         }
  389.         if (c == C_DELETE_MSG || c == C_DELETE_LIST) {
  390.             if (ison(msg[current_msg].m_flags, DELETE) ||
  391.                 ison(msg[current_msg].m_flags, SAVED))
  392.             (void) next_msg();
  393.             if (isoff(msg[current_msg].m_flags, DELETE) &&
  394.                 do_set(set_options, "autoprint"))
  395.             return C_DISPLAY_MSG;
  396.         }
  397.         if (ison(glob_flags, CNTD_CMD))
  398.             puts(compose_hdr(current_msg));
  399.         else if (current_msg < n_array[0]
  400.             || current_msg > n_array[screen-1])
  401.             redo = 1;
  402.         }
  403.  
  404.     /*
  405.      * write/save messages.  If a list is necessary, the user already
  406.      * entered it above since he must have used a capital letter. If so,
  407.      * list will contain good data (already been validated above).
  408.      * if a list is given, set iscurses to 0 so that print statements
  409.      * will scroll and the user sees the multiple output. else, one
  410.      * line can go on the bottom line just fine.
  411.      */
  412.     when C_WRITE_MSG : case C_SAVE_MSG : case C_COPY_MSG :
  413.     case C_WRITE_LIST : case C_SAVE_LIST : case C_COPY_LIST : {
  414.         register char *p =
  415.         (c == C_WRITE_MSG || c == C_WRITE_LIST)? "write" :
  416.         (c == C_SAVE_MSG  || c == C_SAVE_LIST)? "save" : "copy";
  417.         if (!msg_cnt) {
  418.         print("No messages.");
  419.         if (ison(glob_flags, CNTD_CMD))
  420.             putchar('\n');
  421.         break;
  422.         }
  423.         if (c != C_WRITE_MSG && c != C_WRITE_LIST) {
  424.         char *f = do_set(set_options, "mbox");
  425.         if (f)
  426.             (void) sprintf(file, "[%s]", f);
  427.         else
  428.             (void) sprintf(file, "[%s]", DEF_MBOX);
  429.         } /* else file is already init'd to "" */
  430.         print(sprintf(buf, "filename to %s%s: ", p, file));
  431.         if (Getstr(file, COLS-1-strlen(buf), 0) >= 0) {
  432.         char *argv[3];
  433.         clr_bot_line();
  434.         argv[0] = strcpy(buf, p);
  435.         p = file; skipspaces(0);
  436.         argv[1] = (*p) ? p : NULL;
  437.         argv[2] = NULL;
  438.         if (!*list)
  439.             set_msg_bit(msg_list, current_msg);
  440.         move(LINES-1, 0), refresh();
  441.         if (*list)
  442.             iscurses = FALSE;
  443.         /* Turn on piping to make save_msg look at msg_list */
  444.         turnon(glob_flags, IS_PIPE);
  445.         if (save_msg(1 + (*file != '\0'), argv, msg_list) < 0)
  446.             *list = 0;
  447.         turnoff(glob_flags, IS_PIPE);
  448.         if (ison(glob_flags, CNTD_CMD))
  449.             redo = 1, putchar('\n'), puts(compose_hdr(current_msg));
  450.         if (*list)
  451.             iscurses = redo = TRUE, turnon(glob_flags, CNTD_CMD);
  452.         else if (isoff(glob_flags, CNTD_CMD) && msg_cnt) {
  453.             move(curlin, 0);
  454.             printw("%-.*s", COLS-1, compose_hdr(current_msg));
  455.             }
  456.         } else {
  457.         print("No messages saved.");
  458.         if (ison(glob_flags, CNTD_CMD))
  459.             putchar('\n');
  460.         }
  461.     }
  462.  
  463.     /* preserve message or place mark on message */
  464.     when C_PRESERVE : case C_MARK_MSG :
  465.         if (!msg_cnt) {
  466.         print("No messages.");
  467.         if (ison(glob_flags, CNTD_CMD))
  468.             putchar('\n');
  469.         break;
  470.         }
  471.         if (ison(msg[current_msg].m_flags,
  472.             c == C_MARK_MSG ? M_PRIORITY(0) : PRESERVE))
  473.         turnoff(msg[current_msg].m_flags,
  474.             c == C_MARK_MSG ? M_PRIORITY(0) : PRESERVE);
  475.         else
  476.         turnon(msg[current_msg].m_flags,
  477.             c == C_MARK_MSG ? M_PRIORITY(0) : PRESERVE);
  478.         if (c != C_MARK_MSG)
  479.         turnon(glob_flags, DO_UPDATE);
  480.         if (ison(glob_flags, CNTD_CMD)) {
  481.         wprint("%-.*s\n", COLS-1, compose_hdr(current_msg));
  482.         redo = 1;
  483.         } else {
  484.         move(curlin, 0);
  485.         printw("%-.*s", COLS-1, compose_hdr(current_msg));
  486.         }
  487.  
  488.     /* order messages (sort) and redisplay the headers */
  489.     when C_SORT : case C_REV_SORT :
  490.         (void) strcpy(file, "sort");
  491.         if (c == C_REV_SORT) {
  492.         print("Reverse "), turnon(glob_flags, CONT_PRNT);
  493.         (void) strcat(file, " -");
  494.         }
  495.         print(
  496.     "Order messages by [author, date, length, Status, subject, priority]: "
  497.         );
  498.         if ((c = m_getchar()) == 'a' || c == 'd' || c == 'l' ||
  499.             c == 'S' || c == 's' || c == 'R' || c == 'p') {
  500.         print("reordering messages...");
  501.         (void) cmd_line(sprintf(buf, "%s %c", file, c), msg_list);
  502.         print_more("done.");
  503.         if (ison(glob_flags, CNTD_CMD))
  504.             putchar('\n'), puts(compose_hdr(current_msg));
  505.         redo = 1;
  506.         } else
  507.         clr_bot_line();
  508.  
  509.     when C_QUIT_HARD :
  510.         (void) mush_quit(0, DUBL_NULL);
  511.         redo = 1; /* new mail must have come in */
  512.  
  513.     /* quit or update -- vrfy_update (returns 1 if updated) */
  514.     when C_QUIT : case C_UPDATE : {
  515.         clr_bot_line();
  516.         redo = (c == C_UPDATE);
  517.         if (!vrfy_update(&redo))
  518.         if (c == C_UPDATE)
  519.             break;
  520.         if (isoff(glob_flags, CNTD_CMD))
  521.         (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1),
  522.                 msg_list);
  523.     }
  524.  
  525.     when C_EXIT : case C_EXIT_HARD :
  526.         clr_bot_line();
  527.         iscurses = FALSE;
  528.         if (c != C_EXIT && c != C_EXIT_HARD)
  529.         putchar('\n');
  530.         cleanup(0);
  531.  
  532.     /* change to a new folder */
  533.     when C_FOLDER :
  534.         for (;;) {
  535.         SIGRET (*oldint)(), (*oldquit)();
  536.         on_intr();
  537.         print("New folder (?=list): ");
  538.         c = Getstr(file, COLS-22, 0);
  539.         off_intr();
  540.         if (c > 0) {
  541.             int do_up = 0;
  542.             if (!strcmp(file, "?")) {
  543.             clr_bot_line();
  544.             iscurses = 0;
  545.             puts("folders in your folder directory:");
  546.             (void) cmd_line(strcpy(buf, "\\folders"), msg_list);
  547.     puts("Precede folder names with a +. `%' to specify system mailbox.");
  548.             turnon(glob_flags, CNTD_CMD), iscurses = 1;
  549.             continue;
  550.             }
  551.             clearok(stdscr, FALSE);
  552.             /* if vrfy_update doesn't verify, but folder command fails,
  553.              * then we need to reset the updatability of current folder
  554.              */
  555.             c = (ison(glob_flags, DO_UPDATE))? TRUE : FALSE;
  556.             if (strcmp(file, "-?") != 0) {
  557.             redo = -1; /* so vrfy_update() won't update or quit */
  558.             do_up = vrfy_update(&redo);
  559.             }
  560.             move(LINES-1, 0), refresh();
  561.             if (cmd_line(sprintf(buf, "folder %s -N %s",
  562.                     do_up? "" : "!", file), msg_list) == -1) {
  563.             if (c) /* remember state of updatability of folder */
  564.                 turnon(glob_flags, DO_UPDATE);
  565.             if (ison(glob_flags, CNTD_CMD))
  566.                 putchar('\n');
  567.             } else
  568.             redo = 1, turnoff(glob_flags, CNTD_CMD);
  569.             break;
  570.         } else {
  571.             print("\"%s\" unchanged.", mailfile);
  572.             if (ison(glob_flags, CNTD_CMD))
  573.             putchar('\n');
  574.             break;
  575.         }
  576.         }
  577.  
  578.     /* shell escape */
  579.     when C_SHELL_ESC :
  580.         print("Shell command: ");
  581.         if (Getstr(file, COLS-24, 0) < 0)
  582.         clr_bot_line();
  583.         else {
  584.         putchar('\n');
  585.         iscurses = FALSE;
  586.         (void) cmd_line(sprintf(buf, "sh %s", file), msg_list);
  587.         iscurses = TRUE;
  588.         turnon(glob_flags, CNTD_CMD);
  589.         }
  590.  
  591.     /* do a line-mode like command */
  592.     when C_CURSES_ESC :
  593.         print(":");
  594.         if (Getstr(buf, COLS-2, 0) < 0)
  595.         break;
  596.         putchar('\n');
  597.         iscurses = FALSE;
  598.         if (!*buf) {
  599.         /* return -1 because iscurses = 0 is not enough! */
  600.         redo = 0;
  601.         endwin(); /* this turns echoing back on! */
  602.         echo_off();
  603.         return -1;
  604.         }
  605.         /* The "source" and "curses" commands need some indication
  606.          * that we are in curses mode, so use the PRE_CURSES flag.
  607.          */
  608.         turnon(glob_flags, PRE_CURSES);
  609.         (void) cmd_line(buf, msg_list);
  610.         /* they may have affected message status or had text output */
  611.         turnon(glob_flags, CNTD_CMD), redo = 1;
  612.         turnoff(glob_flags, PRE_CURSES);
  613.         iscurses = TRUE;
  614.         if (msg_cnt)
  615.         puts(compose_hdr(current_msg));
  616.  
  617.     /* send message to printer, redo to display 'p' status */
  618.     when C_PRINT_MSG : redo = (lpr(0, DUBL_NULL, msg_list) == 0);
  619.  
  620.     /* cd */
  621.     when C_CHDIR :
  622.         print("chdir to [~]: ");
  623.         if (Getstr(file, COLS-12, 0) < 0)
  624.         break;
  625.         clr_bot_line();
  626.         (void) cmd_line(sprintf(buf, "cd %s", file), msg_list);
  627.         if (ison(glob_flags, CNTD_CMD))
  628.         putchar('\n');
  629.  
  630.     /* variable settings */
  631.     when C_VAR_SET : case C_IGNORE : case C_ALIAS : case C_OWN_HDR :
  632.         curs_vars(c); /* CNTD_CMD is reset if there's output! */
  633.  
  634.     when C_VERSION :
  635.         (void) do_version();
  636.         if (ison(glob_flags, CNTD_CMD))
  637.         putchar('\n');
  638.  
  639.     when C_MAIL_FLAGS :
  640.         print("flags [-?]: ");
  641.         if ((c = Getstr(file, COLS-12, 0)) < 0)
  642.         break;
  643.         putchar('\n');
  644.         if (c == 0)
  645.         (void) strcpy(file, "-?");
  646.         else
  647.         redo = 1; /* In case of -f flag, to display the 'f' status */
  648.     /* Fall thru */
  649.     case C_MAIL : {
  650.         u_long flgs = glob_flags;
  651.         turnon(glob_flags, IGN_BANG);
  652.         clr_bot_line();
  653.         iscurses = FALSE;
  654.         (void) cmd_line(sprintf(buf, "mail %s", file), msg_list);
  655.         glob_flags = flgs;
  656.         iscurses = TRUE, turnon(glob_flags, CNTD_CMD);
  657.         if (msg_cnt)
  658.         print("%-.*s", COLS-2, compose_hdr(current_msg)), putchar('\n');
  659.     }
  660.  
  661.     /* reply to mail */
  662.     when C_REPLY_SENDER : case C_REPLY_ALL : {
  663.         register char *p = (c == C_REPLY_ALL)? "replyall" : "replysender";
  664.         clr_bot_line();
  665.         iscurses = FALSE;
  666.         if (isoff(msg[current_msg].m_flags, REPLIED))
  667.         redo = 1;
  668.         (void) cmd_line(sprintf(buf, "%s %d", p, current_msg+1),
  669.         msg_list);
  670.         if (msg_cnt)
  671.         puts(compose_hdr(current_msg));
  672.         iscurses = TRUE, turnon(glob_flags, CNTD_CMD);
  673.     }
  674.  
  675.     /* type out a message */
  676.     when C_DISPLAY_MSG : case C_TOP_MSG : case C_DISPLAY_NEXT :
  677.         if (!msg_cnt ||
  678.         c != C_DISPLAY_NEXT && ison(msg[current_msg].m_flags, DELETE)) {
  679.         if (!msg_cnt)
  680.             print("No messages.");
  681.         else
  682.             print("Message %d deleted; type 'u' to undelete.",
  683.                       current_msg+1);
  684.         if (ison(glob_flags, CNTD_CMD))
  685.             putchar('\n');
  686.         break;
  687.         }
  688.         clr_bot_line();
  689.         iscurses = FALSE;
  690.         if (ison(glob_flags, CNTD_CMD))
  691.         putchar('\n');
  692.         if (c == C_DISPLAY_MSG)
  693.         c = cmd_line(strcpy(buf, "type"), msg_list);
  694.         else if (c == C_TOP_MSG)
  695.         c = cmd_line(strcpy(buf, "top"), msg_list);
  696.         else {
  697.         /* "next" screws up the screen whether it displays or not */
  698.         (void) cmd_line(strcpy(buf, "next"), msg_list);
  699.         c = 0;
  700.         }
  701.         if (c > -1)
  702.         turnon(glob_flags, CNTD_CMD), redo = 1;
  703.         iscurses = TRUE;
  704.         puts(compose_hdr(current_msg));
  705.  
  706.     /* bind a key or string to a curses-mode command */
  707.     when C_BIND :  case C_UNBIND : case C_MAP : case C_BIND_MACRO :
  708.     case C_MAP_BANG : {
  709.         char *argv[2];
  710.         argv[0] = (c == C_BIND) ? "bind" :
  711.               (c == C_UNBIND) ? "unbind" :
  712.               (c == C_MAP) ? "map" :
  713.               (c == C_MAP_BANG) ? "map!" : "bind-macro";
  714.         argv[1] = NULL;
  715.         if (bind_it(1, argv) < -1)
  716.         turnon(glob_flags, CNTD_CMD);
  717.         else if (ison(glob_flags, CNTD_CMD)) /* if it was set anyway */
  718.         putchar('\n');
  719.         else
  720.         (void) curses_help_msg(TRUE);
  721.     }
  722.  
  723.     when C_MACRO : 
  724.         turnon(glob_flags, IN_MACRO);
  725.         /* Current macro should already be in the mac_stack, so
  726.          * all we have to do here is look for the next character
  727.          */
  728.  
  729.     /* help stuff */
  730.     when C_HELP :
  731.         move(LINES-1, 0), refresh();
  732.         (void) help(0, "curses", cmd_help);
  733.         turnon(glob_flags, CNTD_CMD);
  734.         if (msg_cnt)
  735.         puts(compose_hdr(current_msg));
  736.  
  737.     otherwise :
  738.         mac_flush();
  739.         bell();
  740.         if (ison(glob_flags, CNTD_CMD)) {
  741.         /* use print instead of puts to overwrite hit_return msg */
  742.         print("unknown command"), putchar('\n');
  743.         redo = 1;
  744.         }
  745.     }
  746.  
  747.     if (ison(glob_flags, CNTD_CMD)) {
  748.     int old_cnt = msg_cnt;
  749.     if (!(c = hit_return()) && !redo && msg_cnt == old_cnt)
  750.         redraw();
  751.     clr_bot_line();
  752.     if (old_cnt !=  msg_cnt)
  753.         redo = 1;
  754.     if (c)
  755.         return c;
  756.     }
  757.     if (redo) {
  758.     set_screen_size(); /* it may have changed */
  759.     n = current_msg;
  760.     clear();
  761.     if (/* msg_cnt < screen || */ n_array[0] < n && n < n_array[screen-1])
  762.         (void) do_hdrs(0, DUBL_NULL, NULL);
  763.     else
  764.         (void) cmd_line(sprintf(buf, "\\headers %d", n+1), msg_list);
  765.     (void) curses_help_msg(TRUE);
  766.     redo = 0;
  767.     }
  768.     return 0;
  769. }
  770.  
  771. vrfy_update(redo)
  772. int *redo;
  773. {
  774.     char buf[16];
  775.     int c;
  776.  
  777.     /* update current folder */
  778.     if (ison(glob_flags, DO_UPDATE)) {
  779.     if (ison(glob_flags, READ_ONLY)) {
  780.         mac_flush();
  781.         print("Folder is read-only.");
  782.         if (ison(glob_flags, CNTD_CMD))
  783.         putchar('\n');
  784.         return 0;
  785.     }
  786.     print("Update folder [y]? ");
  787.     if ((c = getchar()) != 'y' && c != 'Y' && c != '\n' && !isspace(c)) {
  788.         print("Folder unchanged.");
  789.         if (ison(glob_flags, CNTD_CMD))
  790.         putchar('\n');
  791.         return 0;
  792.     }
  793.     if (*redo < 0)
  794.         return 1;
  795.     } else if (*redo)
  796.     return 1;
  797.     if (cmd_line(strcpy(buf, *redo? "update" : "quit"), msg_list) != -1
  798.         && ison(glob_flags, CNTD_CMD))
  799.     *redo = 1, turnoff(glob_flags, CNTD_CMD);
  800.     turnoff(glob_flags, DO_UPDATE);
  801.     return 1; /* make sure bottom line is clear and no reverse video */
  802. }
  803.  
  804. scrn_line(line, buf)
  805. char *buf;
  806. {
  807. #ifndef AIX
  808. #ifndef A_CHARTEXT
  809.     (void) strncpy(buf, stdscr->_y[line], COLS-1);
  810.     buf[COLS-1] = 0; /* strncpy does not null terminate */
  811. #else
  812.     int n;
  813.  
  814.     for (n = 0; n < COLS; n++)
  815.     if ((buf[n] = (mvinch(line, n) & A_CHARTEXT)) == '\0')
  816.         break;
  817.     buf[n] = '\0';
  818. #endif /* A_CHARTEXT */
  819. #else /* AIX */
  820.     (void) strncpy(buf, compose_hdr(n_array[line-1]), COLS - 1);
  821. #endif /* AIX */
  822. }
  823.  
  824. /*
  825.  * Generate the help message from the variable curses_help.
  826.  *  If visible is true, the message is displayed,
  827.  *  otherwise its size (in lines) is computed and returned.
  828.  */
  829. curses_help_msg(visible)
  830. int visible;
  831. {
  832.     int count, i, len, siz = 0, mxm = 0;
  833.     static int old_siz = 0;
  834.     register struct cmd_map *list;
  835.     extern struct cmd_map map_func_names[];
  836.     char *curs_help = do_set(set_options, "curses_help"), **format;
  837.  
  838.     if (!curs_help) {
  839.     if (old_siz && visible) {
  840.         int bot = min(n_array[screen-1], msg_cnt-1);
  841.         move(max(0, bot - n_array[0]) + 2, 0), clrtobot();
  842.         old_siz = 0;
  843.     }
  844.     return 0;
  845.     } else if (!*curs_help)
  846.     curs_help = DEF_CURSES_HELP;
  847.     /* Split the help string into words */
  848.     if (!(format = mk_argv(curs_help, &count, FALSE)) || count <= 0)
  849.     return 0;
  850.     /* Generate a help message for each word */
  851.     for (i = 0; i < count; i++) {
  852.     char buf[MAX_BIND_LEN*2+MAX_LONG_CMD+5], asc[MAX_BIND_LEN*2];
  853.  
  854.     buf[0] = '\0'; /* default to empty in case of no match */
  855.     for (list = cmd_map; list; list = list->m_next) {
  856.         if (!strcmp(format[i], map_func_names[list->m_cmd].m_str)) {
  857.         len = strlen(sprintf(buf, "(%s) %s  ",
  858.                 ctrl_strcpy(asc, list->m_str, FALSE),
  859.                 map_func_names[list->m_cmd].m_str));
  860.         if (len > mxm)
  861.             mxm = len;
  862.         break;
  863.         }
  864.     }
  865.     strdup(format[i], buf); /* replace word with its "definition" */
  866.     }
  867.     /* Columnate the output nicely */
  868.     if (mxm > 0) {
  869.     len = (COLS - 1) / mxm;
  870.     if (len == 0) {
  871.         if (visible)
  872.         print("Curses help message too long!");
  873.         return 0;
  874.     }
  875.     siz = count / len;
  876.     if (count % len)
  877.         siz++;
  878.     if (siz > LINES / 3) {
  879.         if (visible)
  880.         print("Curses help message too long!");
  881.         return 0;
  882.     }
  883.     if (visible) {
  884.         int next = LINES - 1 - siz;
  885.         if (old_siz > siz) {
  886.         int bot = min(n_array[screen-1], msg_cnt-1);
  887.         move(max(0, bot - n_array[0]) + 2, 0), clrtobot();
  888.         }
  889.         old_siz = siz;
  890.         for (i = 0; i < count; i++) {
  891.         if (!(i % len))
  892.             move(next, 0), clrtoeol(), ++next;
  893.         if (format[i][0])
  894.             printw("%-*.*s", mxm, mxm, format[i]);
  895.         }
  896.         refresh();
  897.     }
  898.     }
  899.     free_vec(format);
  900.     return siz;
  901. }
  902.  
  903. set_screen_size()
  904. {
  905.     int hlp_siz = LINES - 2 - curses_help_msg(FALSE); 
  906.  
  907.     if (!do_set(set_options, "screen"))
  908. #ifdef USG
  909.     switch (_tty.sg_ospeed & CBAUD)
  910. #else /* USG */
  911.     switch (_tty.sg_ospeed)
  912. #endif /* USG */
  913.     {
  914.         case B300 :  screen = min(hlp_siz, 7);
  915.         when B1200 : screen = min(hlp_siz, 14);
  916.         when B2400 : screen = min(hlp_siz, 22);
  917.         otherwise :  screen = hlp_siz;
  918.     }
  919.     else
  920.     screen = min(screen, hlp_siz);
  921. }
  922.  
  923. /*
  924.  * prompt for a carriage return, but return whatever user types unless
  925.  * it's a character which he might regret (like 'q' or 'x'). Ignore
  926.  * interrupts (kind of) because we have nowhere to longjmp to.  When we
  927.  * return, we'll setjmp again (top of loop.c)
  928.  */
  929. hit_return()
  930. {
  931.     int c;
  932.  
  933.     turnon(glob_flags, IGN_SIGS);
  934.     iscurses = FALSE;
  935.     (void) check_new_mail();
  936.     iscurses = TRUE;
  937.     mail_status(1), addstr("...continue... "), refresh();
  938.     c = getcmd();
  939.     turnoff(glob_flags, IGN_SIGS);
  940.  
  941.     /* don't let the user type something he might regret */
  942.     if (c == C_QUIT || c == C_EXIT)
  943.     return C_NULL;
  944.     return c;
  945. }
  946.  
  947. curses_msg_list(str, list, m_list)
  948. register char *str, *list;
  949. char m_list[];
  950. {
  951.     register char *p = NULL;
  952.     int c, sv_cur_msg = current_msg;
  953.  
  954.     print(str);
  955.     c = Getstr(list, COLS-13, 0);
  956.     move(LINES-1, 0), refresh();
  957.     if (c <= 0 || !(p = do_range(list, m_list)) ||
  958.     (p == list && *p && *p != '$' && *p != '^')) {
  959.     if (p)
  960.         print("Invalid message list: %s", p);
  961.     current_msg = sv_cur_msg;
  962.     return 0;
  963.     }
  964.     current_msg = sv_cur_msg;
  965.     return 1;
  966. }
  967.  
  968. curs_vars(which)
  969. int which;  /* really, a char */
  970. {
  971.     char c, buf[128], buf2[128], *string;
  972.     struct options **list;
  973.  
  974.     switch(which) {
  975.     case C_OWN_HDR : string = "my_hdr", list = &own_hdrs;
  976.     when C_ALIAS : string = "alias", list = &aliases;
  977.     when C_IGNORE : string = "ignore", list = &ignore_hdr;
  978.     when C_VAR_SET : string = "set", list = &set_options;
  979.     otherwise : clr_bot_line(); return;
  980.     }
  981.  
  982.     print("%s [? Set Unset All]: ", string);
  983.     c = m_getchar();
  984.     clr_bot_line();
  985.     switch (Lower(c)) {
  986.     /* if help, print help -- if "all", show all settings. */
  987.     case '?' : case 'a' :
  988.         if (c == '?') {
  989.         if (!strcmp(string, "set")) {
  990.             print("which variable? [all <var>]: ");
  991.             if ((c = Getstr(buf+1, COLS-40, 0)) < 0)
  992.             return;
  993.             clr_bot_line();
  994.             buf[0] = '?';
  995.             if (c > 0) {
  996.             char *argv[3];
  997.             argv[0] = string;
  998.             argv[1] = buf;
  999.             argv[2] = NULL;
  1000.             Lower(buf[1]);
  1001.             if (!strcmp(buf+1, "a"))
  1002.                 (void) strcpy(buf+1, "all");
  1003.             if (!strcmp(buf+1, "all"))
  1004.                 turnon(glob_flags, CNTD_CMD);
  1005.             (void) set(2, argv, (char *) 0);
  1006.             break;
  1007.             }
  1008.         }
  1009.         /* help returns next command (hit_return) */
  1010.         (void) help(0, string, cmd_help);
  1011.         turnon(glob_flags, CNTD_CMD);
  1012.         return;
  1013.         }
  1014.         turnon(glob_flags, CNTD_CMD);
  1015.         (void) do_set(*list, NULL);
  1016.  
  1017.     /* if set, prompt for string and let user type */
  1018.     when 's' :
  1019.         print("set: ");
  1020.         c = Getstr(buf, COLS-18, 0);
  1021.         clr_bot_line();
  1022.         if (c > 0)
  1023.         (void) cmd_line(sprintf(buf2, "%s %s", string, buf), msg_list);
  1024.  
  1025.     /* if unset, just as easy as set! */
  1026.     when 'u' :
  1027.         print("unset: ", string);
  1028.         if (Getstr(buf, COLS-18, 0) > 0 && !un_set(list, buf))
  1029.         print("%s isn't set", buf);
  1030.     }
  1031.     if (ison(glob_flags, CNTD_CMD))
  1032.     putchar('\n');
  1033.     else
  1034.     (void) curses_help_msg(TRUE);
  1035. }
  1036. #endif /* CURSES */
  1037.