home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / mush6.4 / part12 / curses.c
C/C++ Source or Header  |  1989-03-12  |  28KB  |  993 lines

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