v18i034: Mail user's shell version 6.4, Part12/19
Rich Salz
rsalz at bbn.com
Fri Mar 17 02:00:24 AEST 1989
Submitted-by: Dan Heller <island!argv at sun.com>
Posting-number: Volume 18, Issue 34
Archive-name: mush6.4/part12
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 12 (of 19)."
# Contents: curses.c
# Wrapped by rsalz at papaya.bbn.com on Mon Mar 13 19:25:18 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'curses.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'curses.c'\"
else
echo shar: Extracting \"'curses.c'\" \(27579 characters\)
sed "s/^X//" >'curses.c' <<'END_OF_FILE'
X/* @(#)curses.c (c) copyright 3/18/87 (Dan Heller) */
X
X/* curses.c -- routine to deal with the curses interface */
X#ifdef CURSES
X
X#include "mush.h"
X#include "bindings.h"
X
Xcurses_init(argc, argv)
Xregister char **argv;
X{
X char buf[80];
X extern char *UP, ttytype[];
X
X if (argv && *++argv && !strcmp(*argv, "-?"))
X return help(0, "curses", cmd_help);
X if (iscurses) {
X print("You can't run curses from the curses mode (silly).");
X return -1;
X }
X if (ison(glob_flags, IS_GETTING)) {
X print("Finish your letter first.\n");
X return -1;
X }
X#ifdef SUNTOOL
X if (istool) {
X print("My, aren't we the adventuresome type!");
X timerclear(&(mail_timer.it_interval));
X timerclear(&(mail_timer.it_value));
X istool = FALSE, tool_destroy(tool);
X curses_init(0, 0);
X do_loop(); /* doesn't return */
X }
X#endif /* SUNTOOL */
X
X#ifndef attrset /* terminfo version of curses */
X /* you can not start curses in no echo mode.. must be in normal mode */
X echom();
X nocrmode();
X#endif /* attrset */
X (void) initscr();
X#ifdef SIGCONT
X /* initscr will play with signals -- make sure they're set right. */
X (void) signal(SIGTSTP, stop_start);
X (void) signal(SIGCONT, stop_start);
X#endif /* SIGCONT */
X#if !defined(SYSV) && !defined(USG)
X if (!UP || !*UP)
X#else /* ~SYSV && ~USG */
X if (!stdscr)
X#endif /* ~SYSV && ~USG */
X {
X print("Terminal type %s can not use the curses interface.\n", ttytype);
X return -1;
X }
X iscurses = TRUE;
X noechom(); /* reset tty state -- */
X crmode(); /* do not use "echo_on/off()" */
X scrollok(stdscr, TRUE);
X /* if the user hasn't set his screen explicitly, set it for him */
X set_screen_size();
X crt = LINES;
X (void) cmd_line(sprintf(buf, "\\set screen = %d crt = %d", screen, crt),
X msg_list);
X if (argc) {
X (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1), msg_list);
X (void) curses_help_msg(TRUE);
X }
X if (!do_set(set_options, "no_reverse"))
X turnon(glob_flags, REV_VIDEO);
X turnoff(glob_flags, CONT_PRNT);
X return 0; /* doesn't affect messages */
X}
X
Xstruct cmd_map *active_cmd; /* See bindings.h for description */
X
X/*
X * get input in cbreak mode and execute the appropriate command.
X * when the command is done (usually), the user is prompted to
X * hit any key to continue. At this point, the user may enter a
X * new command so no screen refreshing needs to be done. This
X * new command is returned to caller and may be passed back.
X *
X * The flag CNTD_CMD (continued command) is set if
X * this routine is called with the passed parameter (c) != 0. If
X * so, then the character passed is the character input by the
X * user at the last "hit return" prompt indicating that he wants
X * to execute a new command and not draw the screen.
X *
X * CNTD_CMD is also set if the command that the user invokes
X * causes any sort of output that requires a screen refresh. The
X * variable redo is set to 1 if the header page not only requires
X * redrawing, but updating ... (new call to do_hdrs)
X *
X * calls that say: print("%s", compose_hdr(current_msg)) are constructed
X * that way because if the header has a `%' in it, then print will try to
X * expand it.
X */
Xcurses_command(c)
Xregister int c;
X{
X char buf[BUFSIZ], file[128], list[128];
X int n, curlin;
X static int redo = 0; /* set if headers should be redrawn */
X
X if (c != 0)
X turnon(glob_flags, CNTD_CMD);
X else
X turnoff(glob_flags, CNTD_CMD);
X clear_msg_list(msg_list); /* play it safe */
X if (isoff(glob_flags, CNTD_CMD)) {
X (void) check_new_mail();
X curlin = max(1, current_msg - n_array[0] + 1);
X scrn_line(curlin, buf);
X if (ison(glob_flags, REV_VIDEO) && msg_cnt)
X STANDOUT(curlin, 0, buf);
X mail_status(0);
X move(curlin, 0), refresh();
X /* reprint to remove reverse video from current line (don't refresh) */
X if (ison(glob_flags, REV_VIDEO))
X mvaddstr(curlin, 0, buf);
X c = getcmd(); /* get input AFTER line redrawn without reverse video */
X }
X buf[0] = list[0] = file[0] = '\0';
X
X if (c == C_WRITE_LIST || c == C_SAVE_LIST || c == C_COPY_LIST
X || c == C_DELETE_LIST || c == C_UNDEL_LIST) {
X if (msg_cnt < 1) {
X mac_flush();
X print("Not enough messages.");
X c = C_NULL;
X } else if (c == C_DELETE_LIST && ison(glob_flags, READ_ONLY)) {
X mac_flush();
X print("Folder is read-only.");
X c = C_NULL;
X } else if (!curses_msg_list(sprintf(buf, "%s msg list: ",
X (c == C_WRITE_LIST)? "write" : (c == C_SAVE_LIST)? "save" :
X (c == C_COPY_LIST)? "copy" :
X (c == C_DELETE_LIST)? "delete" : "undelete"), list, msg_list))
X c = C_NULL;
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X }
X
X /* first do non-mail command type stuff */
X switch (c) {
X case C_ERROR :
X bell();
X mac_flush();
X
X when C_NULL :
X if (isoff(glob_flags, CNTD_CMD))
X bell();
X
X /* goto a specific message number */
X when C_GOTO_MSG :
X if (msg_cnt <= 1) {
X print("Not enough messages.");
X mac_flush(); /* Flush any digit or other macros */
X } else
X if (curses_msg_list(strcpy(buf, "goto msg: "), list, msg_list)) {
X /*
X * Reset the current message in case a
X * backquoted command (like `from`) changed it
X */
X n = current_msg;
X do if (++n >= msg_cnt)
X n = 0;
X while (n != current_msg && !msg_bit(msg_list, n));
X if (n == current_msg && !msg_bit(msg_list, n)) {
X mac_flush(); /* bail out if in macro processing */
X print("Message not found.");
X }
X else if ((current_msg = n) < n_array[0]
X || n > n_array[screen-1])
X redo = 1;
X } else {
X mac_flush();
X bell();
X }
X if (ison(glob_flags, CNTD_CMD) && msg_cnt)
X print("%-.*s", COLS-2, compose_hdr(current_msg));
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X
X /* screen optimization stuff */
X when C_REVERSE :
X if (ison(glob_flags, REV_VIDEO))
X turnoff(glob_flags, REV_VIDEO);
X else
X turnon(glob_flags, REV_VIDEO);
X
X when C_REDRAW : redo = 1;
X
X /*
X * screen movement
X */
X when C_NEXT_MSG :
X if (current_msg + 2 > msg_cnt ||
X isoff(glob_flags, CNTD_CMD) && curlin == LINES-2) {
X mac_flush(); /* Bail out if in macro processing */
X bell(); /* reached the end */
X } else {
X if (ison(glob_flags, CNTD_CMD)) {
X if (++current_msg > n_array[screen-1])
X redo = 1;
X print("%-.*s", COLS-2, compose_hdr(current_msg));
X putchar('\n');
X } else {
X if (++current_msg > n_array[screen-1])
X n_array[screen++] = current_msg;
X move(++curlin, 0);
X printw("%-.*s", COLS-2, compose_hdr(current_msg));
X clrtoeol();
X }
X }
X
X when C_PREV_MSG :
X if (isoff(glob_flags, CNTD_CMD) && curlin == 1 || current_msg == 0)
X {
X mac_flush(); /* Bail out if in macro processing */
X bell(); /* at the beginning */
X } else {
X if (--current_msg < n_array[0])
X redo = 1;
X if (ison(glob_flags, CNTD_CMD)) {
X print("%-.*s", COLS-2, compose_hdr(current_msg));
X putchar('\n');
X }
X }
X
X when C_FIRST_MSG : case C_LAST_MSG :
X n = current_msg;
X move(LINES-1, 0), refresh();
X if (c == C_FIRST_MSG && (current_msg = 0) < n_array[0] ||
X c == C_LAST_MSG && (current_msg = msg_cnt-1)> n_array[screen-1])
X if (isoff(glob_flags, CNTD_CMD))
X (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1),
X msg_list);
X else
X redo = 1;
X if (ison(glob_flags, CNTD_CMD) && n != current_msg)
X print("%-.*s", COLS-2, compose_hdr(current_msg)), putchar('\n');
X
X /* top and bottom of headers screen */
X when C_TOP_PAGE : case C_BOTTOM_PAGE :
X if (isoff(glob_flags, CNTD_CMD))
X if (c == C_TOP_PAGE)
X current_msg = n_array[0];
X else
X current_msg = min(n_array[screen-1], msg_cnt-1);
X else {
X mac_flush();
X bell();
X }
X
X when C_NEXT_SCREEN : /* next page */
X move(LINES-1, 0), refresh();
X if (msg_cnt-1 > n_array[screen-1]) {
X clear();
X set_screen_size();
X (void) cmd_line(strcpy(buf, "\\headers +"), msg_list);
X if (current_msg < n_array[0])
X current_msg = n_array[0];
X (void) curses_help_msg(TRUE);
X return redo = 0;
X } else {
X mac_flush();
X bell();
X }
X
X when C_PREV_SCREEN : /* previous page */
X move(LINES-1, 0), refresh();
X if (n_array[0] > 0) {
X clear();
X set_screen_size();
X (void) cmd_line(strcpy(buf, "\\headers -"), msg_list);
X if (current_msg > n_array[screen-1])
X current_msg = n_array[screen-1];
X (void) curses_help_msg(TRUE);
X return redo = 0;
X } else {
X mac_flush();
X bell();
X }
X
X /* read from/save to record file (.mushrc) */
X when C_SOURCE : case C_SAVEOPTS : {
X int argc;
X char *argv[3];
X print("%s filename [default]: ",
X (c == C_SOURCE)? "source" : "save options to");
X argc = Getstr(file, LINES-40, 0);
X clr_bot_line();
X if (argc < 0)
X return 0;
X if (argc > 0)
X argv[1] = file, argc = 2;
X else
X argc = 1;
X argv[argc] = NULL;
X turnon(glob_flags, PRE_CURSES);
X if (c == C_SOURCE)
X (void) source(argc, argv);
X else
X (void) save_opts(argc, argv);
X turnoff(glob_flags, PRE_CURSES);
X }
X
X /*
X * search commands
X */
X when C_NEXT_SEARCH : case C_PREV_SEARCH : case C_CONT_SEARCH :
X if (c != C_CONT_SEARCH)
X c = search(0 + (c == C_PREV_SEARCH));
X else
X c = search(-1);
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X if (c == 0)
X break;
X if (ison(glob_flags, CNTD_CMD))
X print("%-.*s",COLS-2, compose_hdr(current_msg)), putchar('\n');
X if (n_array[0] > current_msg || n_array[screen-1] < current_msg) {
X redo = 1;
X if (isoff(glob_flags, CNTD_CMD))
X (void) cmd_line(sprintf(buf, "\\headers %d",
X current_msg+1), msg_list);
X }
X
X /*
X * actions on messages
X */
X /* delete/undelete */
X when C_DELETE_MSG : case C_DELETE_LIST :
X case C_UNDEL_MSG : case C_UNDEL_LIST :
X if (!msg_cnt) {
X print("No messages.");
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X break;
X }
X if (ison(glob_flags, READ_ONLY)) {
X mac_flush();
X print("Folder is read-only.");
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X break;
X }
X Debug("current message = %d", current_msg + 1);
X if (!*list)
X set_msg_bit(msg_list, current_msg);
X turnon(glob_flags, DO_UPDATE);
X for (n = 0; n < msg_cnt; n++)
X if (msg_bit(msg_list, n)) {
X if (c == C_DELETE_MSG || c == C_DELETE_LIST)
X turnon(msg[n].m_flags, DELETE);
X else
X turnoff(msg[n].m_flags, DELETE);
X if (isoff(glob_flags, CNTD_CMD) && (msg_cnt < screen ||
X n >= n_array[0] && n <= n_array[screen-1])) {
X move(max(1, n - n_array[0] + 1), 0);
X printw("%-.*s", COLS-1, compose_hdr(n));
X } else
X redo = 1;
X }
X if (ison(glob_flags, CNTD_CMD) || *list) {
X /* print(), THEN putchar() -- overwrite line */
X if (ison(glob_flags, CNTD_CMD)) {
X print("%sdeleted %s",
X (c == C_DELETE_MSG || c == C_DELETE_LIST)? "":"un", list);
X putchar('\n');
X }
X if (ison(msg[current_msg].m_flags, DELETE) ||
X ison(msg[current_msg].m_flags, SAVED))
X (void) next_msg();
X if (isoff(msg[current_msg].m_flags, DELETE) &&
X do_set(set_options, "autoprint"))
X return C_DISPLAY_MSG;
X if (ison(glob_flags, CNTD_CMD))
X puts(compose_hdr(current_msg));
X else if (current_msg < n_array[0]
X || current_msg > n_array[screen-1])
X redo = 1;
X }
X
X /*
X * write/save messages. If a list is necessary, the user already
X * entered it above since he must have used a capital letter. If so,
X * list will contain good data (already been validated above).
X * if a list is given, set iscurses to 0 so that print statements
X * will scroll and the user sees the multiple output. else, one
X * line can go on the bottom line just fine.
X */
X when C_WRITE_MSG : case C_SAVE_MSG : case C_COPY_MSG :
X case C_WRITE_LIST : case C_SAVE_LIST : case C_COPY_LIST : {
X register char *p =
X (c == C_WRITE_MSG || c == C_WRITE_LIST)? "write" :
X (c == C_SAVE_MSG || c == C_SAVE_LIST)? "save" : "copy";
X if (!msg_cnt) {
X print("No messages.");
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X break;
X }
X print(sprintf(buf, "filename to %s%s: ", p,
X (c != C_WRITE_MSG && c != C_WRITE_LIST)? " [mbox]" : ""));
X if (Getstr(file, COLS-1-strlen(buf), 0) >= 0) {
X char *argv[3];
X clr_bot_line();
X argv[0] = strcpy(buf, p);
X argv[1] = (*file) ? file : NULL;
X argv[2] = NULL;
X if (!*list)
X set_msg_bit(msg_list, current_msg);
X move(LINES-1, 0), refresh();
X if (*list)
X iscurses = FALSE;
X /* Turn on piping to make save_msg look at msg_list */
X turnon(glob_flags, IS_PIPE);
X if (save_msg(1 + (*file != '\0'), argv, msg_list) < 0)
X *list = 0;
X turnoff(glob_flags, IS_PIPE);
X if (ison(glob_flags, CNTD_CMD))
X redo = 1, putchar('\n'), puts(compose_hdr(current_msg));
X if (*list)
X iscurses = redo = TRUE, turnon(glob_flags, CNTD_CMD);
X else if (isoff(glob_flags, CNTD_CMD) && msg_cnt) {
X move(curlin, 0);
X printw("%-.*s", COLS-1, compose_hdr(current_msg));
X }
X } else {
X print("No messages saved.");
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X }
X }
X
X /* preserve message */
X when C_PRESERVE :
X if (!msg_cnt) {
X print("No messages.");
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X break;
X }
X if (ison(msg[current_msg].m_flags, PRESERVE))
X turnoff(msg[current_msg].m_flags, PRESERVE);
X else
X turnon(msg[current_msg].m_flags, PRESERVE);
X turnon(glob_flags, DO_UPDATE);
X if (ison(glob_flags, CNTD_CMD)) {
X wprint("%-.*s\n", COLS-1, compose_hdr(current_msg));
X redo = 1;
X } else {
X move(curlin, 0);
X printw("%-.*s", COLS-1, compose_hdr(current_msg));
X }
X
X /* order messages (sort) and redisplay the headers */
X when C_SORT : case C_REV_SORT :
X (void) strcpy(file, "sort");
X if (c == C_REV_SORT) {
X print("Reverse "), turnon(glob_flags, CONT_PRNT);
X (void) strcat(file, " -");
X }
X print("Order messages by [Status, date, subject, author]: ");
X if ((c = m_getchar()) == 's' || c == 'S' || c == 'd' || c == 'a') {
X print("reordering messages...");
X (void) cmd_line(sprintf(buf, "%s %c", file, c), msg_list);
X print_more("done.");
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n'), puts(compose_hdr(current_msg));
X redo = 1;
X } else
X clr_bot_line();
X
X when C_QUIT_HARD :
X (void) quit(0, DUBL_NULL);
X redo = 1; /* new mail must have come in */
X
X /* quit or update -- vrfy_update (returns 1 if updated) */
X when C_QUIT : case C_UPDATE : {
X u_long do_update = ison(glob_flags, DO_UPDATE);
X clr_bot_line();
X if (!vrfy_update(&redo))
X if (c == C_UPDATE)
X break;
X else
X turnoff(glob_flags, DO_UPDATE);
X if (c == C_QUIT) {
X if (do_update)
X putchar('\n');
X cleanup(0);
X redo = 1;
X } else if (isoff(glob_flags, CNTD_CMD))
X (void) cmd_line(sprintf(buf, "\\headers %d", current_msg+1),
X msg_list);
X }
X
X when C_EXIT : case C_EXIT_HARD :
X clr_bot_line();
X iscurses = FALSE;
X if (c != C_EXIT && c != C_EXIT_HARD)
X putchar('\n');
X cleanup(0);
X
X /* change to a new folder */
X when C_FOLDER :
X for (;;) {
X SIGRET (*oldint)(), (*oldquit)();
X on_intr();
X print("New folder (?=list): ");
X c = Getstr(file, COLS-22, 0);
X off_intr();
X if (c > 0) {
X if (!strcmp(file, "?")) {
X clr_bot_line();
X iscurses = 0;
X puts("folders in your folder directory:");
X (void) cmd_line(strcpy(buf, "\\folders"), msg_list);
X puts("Precede folder names with a +. `%' to specify system mailbox.");
X turnon(glob_flags, CNTD_CMD), iscurses = 1;
X continue;
X }
X clearok(stdscr, FALSE);
X /* if vrfy_update doesn't verify, but folder command fails,
X * then we need to reset the updatability of current folder
X */
X c = (ison(glob_flags, DO_UPDATE))? TRUE : FALSE;
X if (strcmp(file, "-?"))
X (void) vrfy_update(&redo);
X move(LINES-1, 0), refresh();
X if (cmd_line(sprintf(buf, "folder ! -N %s", file),
X msg_list) == -1) {
X if (c) /* remember state of updatability of folder */
X turnon(glob_flags, DO_UPDATE);
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X } else
X redo = 1, turnoff(glob_flags, CNTD_CMD);
X break;
X } else {
X print("\"%s\" unchanged.", mailfile);
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X break;
X }
X }
X
X /* shell escape */
X when C_SHELL_ESC :
X print("Shell command: ");
X if (Getstr(file, COLS-24, 0) < 0)
X clr_bot_line();
X else {
X putchar('\n');
X iscurses = FALSE;
X (void) cmd_line(sprintf(buf, "sh %s", file), msg_list);
X iscurses = TRUE;
X turnon(glob_flags, CNTD_CMD);
X }
X
X /* do a line-mode like command */
X when C_CURSES_ESC :
X print(":");
X if (Getstr(buf, COLS-2, 0) < 0)
X break;
X putchar('\n');
X iscurses = FALSE;
X if (!*buf) {
X /* return -1 because iscurses = 0 is not enough! */
X redo = 0;
X endwin(); /* this turns echoing back on! */
X echo_off();
X return -1;
X }
X (void) cmd_line(buf, msg_list);
X /* they may have affected message status or had text output */
X turnon(glob_flags, CNTD_CMD), redo = 1;
X iscurses = TRUE;
X if (msg_cnt)
X puts(compose_hdr(current_msg));
X
X /* send message to printer */
X when C_PRINT_MSG : (void) lpr(0, DUBL_NULL, msg_list);
X
X /* cd */
X when C_CHDIR :
X print("chdir to [~]: ");
X if (Getstr(file, COLS-12, 0) < 0)
X break;
X clr_bot_line();
X (void) cmd_line(sprintf(buf, "cd %s", file), msg_list);
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X
X /* variable settings */
X when C_VAR_SET : case C_IGNORE : case C_ALIAS : case C_OWN_HDR :
X curs_vars(c); /* CNTD_CMD is reset if there's output! */
X
X when C_VERSION :
X (void) do_version();
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X
X when C_MAIL_FLAGS :
X print("flags [-?]: ");
X if ((c = Getstr(file, COLS-12, 0)) < 0)
X break;
X putchar('\n');
X if (c == 0)
X (void) strcpy(file, "-?");
X /* Fall thru */
X case C_MAIL : {
X u_long flgs = glob_flags;
X turnon(glob_flags, IGN_BANG);
X clr_bot_line();
X iscurses = FALSE;
X (void) cmd_line(sprintf(buf, "mail %s", file), msg_list);
X glob_flags = flgs;
X iscurses = TRUE, turnon(glob_flags, CNTD_CMD);
X if (msg_cnt)
X print("%-.*s", COLS-2, compose_hdr(current_msg)), putchar('\n');
X }
X
X /* reply to mail */
X when C_REPLY_SENDER : case C_REPLY_ALL : {
X register char *p = (c == C_REPLY_ALL)? "replyall" : "replysender";
X clr_bot_line();
X iscurses = FALSE;
X if (isoff(msg[current_msg].m_flags, REPLIED))
X redo = 1;
X (void) cmd_line(sprintf(buf, "%s %d", p, current_msg+1),
X msg_list);
X if (msg_cnt)
X puts(compose_hdr(current_msg));
X iscurses = TRUE, turnon(glob_flags, CNTD_CMD);
X }
X
X /* type out a message */
X when C_DISPLAY_MSG : case C_TOP_MSG : case C_DISPLAY_NEXT :
X if (!msg_cnt ||
X c != C_DISPLAY_NEXT && ison(msg[current_msg].m_flags, DELETE)) {
X if (!msg_cnt)
X print("No messages.");
X else
X print("Message %d deleted; type 'u' to undelete.",
X current_msg+1);
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X break;
X }
X clr_bot_line();
X iscurses = FALSE;
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X if (c == C_DISPLAY_MSG)
X c = cmd_line(strcpy(buf, "type"), msg_list);
X else if (c == C_TOP_MSG)
X c = cmd_line(strcpy(buf, "top"), msg_list);
X else
X c = cmd_line(strcpy(buf, "next"), msg_list);
X if (c > -1)
X turnon(glob_flags, CNTD_CMD), redo = 1;
X iscurses = TRUE;
X puts(compose_hdr(current_msg));
X
X /* bind a key or string to a curses-mode command */
X when C_BIND : case C_UNBIND : case C_MAP : case C_BIND_MACRO :
X case C_MAP_BANG : {
X char *argv[2];
X argv[0] = (c == C_BIND) ? "bind" :
X (c == C_UNBIND) ? "unbind" :
X (c == C_MAP) ? "map" :
X (c == C_MAP_BANG) ? "map!" : "bind-macro";
X argv[1] = NULL;
X if (bind_it(1, argv) < -1)
X turnon(glob_flags, CNTD_CMD);
X else if (ison(glob_flags, CNTD_CMD)) /* if it was set anyway */
X putchar('\n');
X else
X curses_help_msg(TRUE);
X }
X
X when C_MACRO :
X turnon(glob_flags, IN_MACRO);
X /* Current macro should already be in the mac_stack, so
X * all we have to do here is look for the next character
X */
X
X /* help stuff */
X when C_HELP :
X move(LINES-1, 0), refresh();
X help(0, "curses", cmd_help);
X turnon(glob_flags, CNTD_CMD);
X if (msg_cnt)
X puts(compose_hdr(current_msg));
X
X otherwise :
X mac_flush();
X bell();
X if (ison(glob_flags, CNTD_CMD)) {
X /* use print instead of puts to overwrite hit_return msg */
X print("unknown command"), putchar('\n');
X redo = 1;
X }
X }
X
X if (ison(glob_flags, CNTD_CMD)) {
X int old_cnt = msg_cnt;
X if (!(c = hit_return()) && !redo && msg_cnt == old_cnt)
X redraw();
X clr_bot_line();
X if (old_cnt != msg_cnt)
X redo = 1;
X if (c)
X return c;
X }
X if (redo) {
X set_screen_size(); /* it may have changed */
X n = current_msg;
X clear();
X if (msg_cnt < screen || n_array[0] < n && n < n_array[screen-1])
X (void) do_hdrs(0, DUBL_NULL, NULL);
X else
X (void) cmd_line(sprintf(buf, "\\headers %d", n+1), msg_list);
X (void) curses_help_msg(TRUE);
X redo = 0;
X }
X return 0;
X}
X
Xvrfy_update(redo)
Xint *redo;
X{
X char buf[16];
X int c;
X
X /* update current folder */
X if (ison(glob_flags, DO_UPDATE)) {
X if (ison(glob_flags, READ_ONLY)) {
X mac_flush();
X print("Folder is read-only.");
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X return 0;
X }
X print("Update folder [y]? ");
X if ((c = getchar()) != 'y' && c != 'Y' && c != '\n' && !isspace(c)) {
X print("Folder unchanged.");
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X return 0;
X }
X if (cmd_line(strcpy(buf, "update"), msg_list) != -1 &&
X ison(glob_flags, CNTD_CMD))
X *redo = 1, turnoff(glob_flags, CNTD_CMD);
X }
X turnoff(glob_flags, DO_UPDATE);
X return 1; /* make sure bottom line is clear and no reverse video */
X}
X
Xscrn_line(line, buf)
Xchar *buf;
X{
X#ifndef A_CHARTEXT
X (void) strncpy(buf, stdscr->_y[line], COLS-1);
X buf[COLS-1] = 0; /* strncpy does not null terminate */
X#else
X int n;
X
X for (n = 0; n < COLS; n++)
X if ((buf[n] = (mvinch(line, n) & A_CHARTEXT)) == '\0')
X break;
X buf[n] = '\0';
X#endif /* A_CHARTEXT */
X}
X
X/*
X * Generate the help message from the variable curses_help.
X * If visible is true, the message is displayed,
X * otherwise its size (in lines) is computed and returned.
X */
Xcurses_help_msg(visible)
Xint visible;
X{
X int count, i, len, siz = 0, mxm = 0;
X static int old_siz = 0;
X register struct cmd_map *list;
X extern struct cmd_map map_func_names[];
X char *curs_help = do_set(set_options, "curses_help"), **format;
X
X if (!curs_help) {
X if (old_siz && visible) {
X int bot = min(n_array[screen-1], msg_cnt-1);
X move(max(0, bot - n_array[0]) + 2, 0), clrtobot();
X old_siz = 0;
X }
X return 0;
X } else if (!*curs_help)
X curs_help = DEF_CURSES_HELP;
X /* Split the help string into words */
X if (!(format = mk_argv(curs_help, &count, FALSE)) || count <= 0)
X return 0;
X /* Generate a help message for each word */
X for (i = 0; i < count; i++) {
X char buf[MAX_BIND_LEN*2+MAX_LONG_CMD+5], asc[MAX_BIND_LEN*2];
X
X buf[0] = '\0'; /* default to empty in case of no match */
X for (list = cmd_map; list; list = list->m_next) {
X if (!strcmp(format[i], map_func_names[list->m_cmd].m_str)) {
X len = strlen(sprintf(buf, "(%s) %s ",
X ctrl_strcpy(asc, list->m_str, FALSE),
X map_func_names[list->m_cmd].m_str));
X if (len > mxm)
X mxm = len;
X break;
X }
X }
X strdup(format[i], buf); /* replace word with its "definition" */
X }
X /* Columnate the output nicely */
X if (mxm > 0) {
X len = (COLS - 1) / mxm;
X if (len == 0) {
X if (visible)
X print("Curses help message too long!");
X return 0;
X }
X siz = count / len;
X if (count % len)
X siz++;
X if (siz > LINES / 3) {
X if (visible)
X print("Curses help message too long!");
X return 0;
X }
X if (visible) {
X int next = LINES - 1 - siz;
X if (old_siz > siz) {
X int bot = min(n_array[screen-1], msg_cnt-1);
X move(max(0, bot - n_array[0]) + 2, 0), clrtobot();
X }
X old_siz = siz;
X for (i = 0; i < count; i++) {
X if (!(i % len))
X move(next, 0), clrtoeol(), ++next;
X if (format[i][0])
X printw("%-*.*s", mxm, mxm, format[i]);
X }
X refresh();
X }
X }
X free_vec(format);
X return siz;
X}
X
Xset_screen_size()
X{
X int hlp_siz = LINES - 2 - curses_help_msg(FALSE);
X
X if (!do_set(set_options, "screen"))
X#ifdef USG
X switch (_tty.sg_ospeed & CBAUD)
X#else /* USG */
X switch (_tty.sg_ospeed)
X#endif /* USG */
X {
X case B300 : screen = min(hlp_siz, 7);
X when B1200 : screen = min(hlp_siz, 14);
X when B2400 : screen = min(hlp_siz, 22);
X otherwise : screen = hlp_siz;
X }
X else
X screen = min(screen, hlp_siz);
X}
X
X/*
X * prompt for a carriage return, but return whatever user types unless
X * it's a character which he might regret (like 'q' or 'x'). Ignore
X * interrupts (kind of) because we have nowhere to longjmp to. When we
X * return, we'll setjmp again (top of loop.c)
X */
Xhit_return()
X{
X int c;
X
X turnon(glob_flags, IGN_SIGS);
X iscurses = FALSE;
X (void) check_new_mail();
X iscurses = TRUE;
X mail_status(1), addstr("...continue... "), refresh();
X c = getcmd();
X turnoff(glob_flags, IGN_SIGS);
X
X /* don't let the user type something he might regret */
X if (c == C_QUIT || c == C_EXIT)
X return C_NULL;
X return c;
X}
X
Xcurses_msg_list(str, list, m_list)
Xregister char *str, *list;
Xchar m_list[];
X{
X register char *p = NULL;
X int c, sv_cur_msg = current_msg;
X
X print(str);
X c = Getstr(list, COLS-13, 0);
X move(LINES-1, 0), refresh();
X if (c <= 0 || !(p = do_range(list, m_list)) ||
X (p == list && *p && *p != '$' && *p != '^')) {
X if (p)
X print("Invalid message list: %s", p);
X current_msg = sv_cur_msg;
X return 0;
X }
X current_msg = sv_cur_msg;
X return 1;
X}
X
Xcurs_vars(which)
Xint which; /* really, a char */
X{
X char c, buf[128], buf2[128], *string;
X struct options **list;
X
X switch(which) {
X case C_OWN_HDR : string = "my_hdr", list = &own_hdrs;
X when C_ALIAS : string = "alias", list = &aliases;
X when C_IGNORE : string = "ignore", list = &ignore_hdr;
X when C_VAR_SET : string = "set", list = &set_options;
X otherwise : clr_bot_line(); return;
X }
X
X print("%s [? Set Unset All]: ", string);
X c = m_getchar();
X clr_bot_line();
X switch (Lower(c)) {
X /* if help, print help -- if "all", show all settings. */
X case '?' : case 'a' :
X if (c == '?') {
X if (!strcmp(string, "set")) {
X print("which variable? [all <var>]: ");
X if ((c = Getstr(buf+1, COLS-40, 0)) < 0)
X return;
X clr_bot_line();
X buf[0] = '?';
X if (c > 0) {
X char *argv[3];
X argv[0] = string;
X argv[1] = buf;
X argv[2] = NULL;
X Lower(buf[1]);
X if (!strcmp(buf+1, "a"))
X (void) strcpy(buf+1, "all");
X if (!strcmp(buf+1, "all"))
X turnon(glob_flags, CNTD_CMD);
X (void) set(2, argv);
X break;
X }
X }
X /* help returns next command (hit_return) */
X help(0, string, cmd_help);
X turnon(glob_flags, CNTD_CMD);
X return;
X }
X turnon(glob_flags, CNTD_CMD);
X (void) do_set(*list, NULL);
X
X /* if set, prompt for string and let user type */
X when 's' :
X print("set: ");
X c = Getstr(buf, COLS-18, 0);
X clr_bot_line();
X if (c > 0)
X (void) cmd_line(sprintf(buf2, "%s %s", string, buf), msg_list);
X
X /* if unset, just as easy as set! */
X when 'u' :
X print("unset: ", string);
X if (Getstr(buf, COLS-18, 0) > 0 && !un_set(list, buf))
X print("%s isn't set", buf);
X }
X if (ison(glob_flags, CNTD_CMD))
X putchar('\n');
X else
X curses_help_msg(TRUE);
X}
X#endif /* CURSES */
END_OF_FILE
if test 27579 -ne `wc -c <'curses.c'`; then
echo shar: \"'curses.c'\" unpacked with wrong size!
fi
# end of 'curses.c'
fi
echo shar: End of archive 12 \(of 19\).
cp /dev/null ark12isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 19 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
More information about the Comp.sources.unix
mailing list