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 / commands.c < prev    next >
C/C++ Source or Header  |  1992-10-30  |  23KB  |  801 lines

  1. /* @(#)commands.c    (c) copyright 10/18/86 (Dan Heller) */
  2.  
  3. #include "mush.h"
  4.  
  5. /*
  6.  * Note that all of the routines in here act upon and return 0 or -1.
  7.  * if -1, then the main loop will clear message lists.
  8.  */
  9.  
  10. struct cmd cmds[] = {
  11. #ifdef SIGSTOP
  12.     { "stop", stop },
  13. #endif /* SIGSTOP */
  14.     { "?",       question_mark },{ "sh", sh },
  15.     { "alias",       do_alias    },  { "unalias",    do_alias   },
  16.     { "expand",      do_alias    },  { "cmd",     do_alias   },
  17.     { "uncmd",       do_alias    },  { "from",    do_from    },
  18.     { "un_hdr",      do_alias    },  { "my_hdr",      do_alias   },
  19.     { "fkey",       do_alias    },  { "unfkey",     do_alias   },
  20.     { "set",       set         },  { "unset",     set        },
  21.     { "ignore",      set         },  { "unignore", set        },
  22.     { "version",  do_version  },  { "help",    print_help },
  23.     { "pick",       do_pick     },  { "sort",     sort        },
  24.     { "next",      readmsg     },  { "previous", readmsg    },
  25.     { "type",     readmsg     },  { "print",    readmsg    },
  26.     { "history",  disp_hist   },  { "top",    readmsg       },
  27.     { "saveopts", save_opts   },  { "source",   source        },
  28.     { "headers",  do_hdrs     },  { "ls",    ls       },
  29.     { "folder",   folder      },  { "update",   folder     },
  30.     { "cd",       cd          },  { "pwd",    cd        },
  31.     { "exit",      mush_quit   },  { "quit",     mush_quit  },
  32.     { "write",       save_msg    },  { "save",     save_msg   },
  33.     { "copy",       save_msg    },  { "folders",  folders    },
  34.     { "merge",      merge_folders },
  35.     { "mark",      mark_msg    },  { "unmark",    mark_msg   },
  36. #ifdef CURSES
  37.     { "curses",   curses_init },  { "bind",    bind_it    },
  38.     { "unbind",   bind_it     },  { "bind-macro", bind_it  },
  39.     { "unbind-macro", bind_it  },
  40. #endif /* CURSES */
  41.     { "map",      bind_it     },  { "unmap",       bind_it    },
  42.     { "map!",     bind_it     },  { "unmap!",      bind_it    },
  43.     { "preserve", preserve    },  { "unpreserve",  preserve   },
  44.     { "replyall", respond     },  { "replysender", respond    },
  45.     { "delete",      delete      },  { "undelete",    delete     },
  46.     { "mail",       do_mail     },  { "echo",       do_echo    },
  47.     { "lpr",      lpr          },  { "alternates",  alts       },
  48.     { "edit",      edit_msg    },  { "flags",       msg_flags  },
  49.     { "pipe",     pipe_msg    },  { "eval",       eval_cmd   },
  50.     { "undigest", do_undigest },  { "await",       await      },
  51.     { NULL, mush_quit }
  52. };
  53.  
  54. struct cmd ucb_cmds[] = {
  55.     { "t",   readmsg   }, { "n",  readmsg  }, { "p", readmsg  },
  56.     { "+",   readmsg   }, { "-",  readmsg  }, { "P", readmsg  },
  57.     { "Print", readmsg }, { "T",  readmsg  }, { "Type", readmsg },
  58.     { "x",   mush_quit }, { "q", mush_quit }, { "xit", mush_quit },
  59.     { ":a",  do_hdrs   }, { ":d", do_hdrs  }, { ":r", do_hdrs },
  60.     { ":o",  do_hdrs   }, { ":u", do_hdrs  }, { ":n", do_hdrs },
  61.     { ":s",  do_hdrs   }, { ":p", do_hdrs  }, { ":m", do_hdrs },
  62.     { "z",   do_hdrs   }, { "z-", do_hdrs  }, { "z+", do_hdrs },
  63.     { "h",   do_hdrs   }, { "H",  do_hdrs  },
  64.     { "f",   do_from   }, { "m",  do_mail  }, { "alts", alts  },
  65.     { "d",   delete    }, { "dt", delete   }, { "dp", delete  },
  66.     { "u",   delete    }, { "fo", folder   },
  67.     { "s",   save_msg  }, { "co", save_msg }, { "w", save_msg },
  68.     { "pre", preserve  }, { "unpre", preserve },
  69.     { "R",   respond   }, { "r",   respond },
  70.     { "reply", respond }, { "respond", respond },
  71.     { "v",   edit_msg  }, { "e",   edit_msg },
  72.     { NULL, mush_quit }
  73. };
  74.  
  75. struct cmd hidden_cmds[] = {
  76.     { "about",    print_help  },
  77.     { "debug", toggle_debug }, { "open",     nopenfiles },
  78.     { "stty",    my_stty     },
  79.     { "setenv",    Setenv      }, { "unsetenv",     Unsetenv   },
  80.     { "printenv", Printenv  }, { "Pipe",    pipe_msg   },
  81.     { NULL, mush_quit }
  82. };
  83.  
  84. toggle_debug(argc, argv)
  85. int argc;
  86. char **argv;
  87. {
  88.     if (argc < 2) /* no value -- toggle "debug" (off/on) */
  89.     debug = !debug;
  90.     else
  91.     debug = atoi(*++argv);
  92.     print("debugging value: %d\n", debug);
  93.     return 0;
  94. }
  95.  
  96. /* if + was specified, then print messages without headers.
  97.  * n or \n (which will be NULL) will print next unread or undeleted message.
  98.  */
  99. readmsg(x, argv, list)
  100. int x;
  101. char **argv, list[];
  102. {
  103.     register char *p = x? *argv : NULL;
  104.     register long flg = 0;
  105.     extern FILE *ed_fp;
  106. #ifdef SUNTOOL
  107.     SIGRET (*oldint)(), (*oldquit)();
  108. #endif /* SUNTOOL */
  109.  
  110.     if (x && *++argv && !strcmp(*argv, "-?"))
  111.     return help(0, "readmsg", cmd_help);
  112.     /* View a message as long as user isn't in the editor.
  113.      * If ed_fp is not null, then we've got the
  114.      * file open for typing.  If it's NULL, then an editor is going.
  115.      */
  116.     if (ison(glob_flags, IS_GETTING) && !ed_fp) {
  117.     print("Not while you're in the editor, you don't.\n");
  118.     return -1;
  119.     }
  120.     if (!msg_cnt) {
  121.     print("No messages.\n");
  122.     return -1;
  123.     }
  124.     if (x)
  125.     if (!strcmp(p, "top"))
  126.         turnon(flg, M_TOP);
  127.     else if (*p == '+') {
  128.         turnon(flg, NO_PAGE);
  129.         turnon(flg, NO_HEADER);
  130.     } else if (isupper(*p))
  131.         turnon(flg, NO_IGNORE);
  132.  
  133.     if (x && (x = get_msg_list(argv, list)) == -1)
  134.     return -1;
  135.     else if (x == 0) {  /* no arguments were parsed (or given) */
  136.     /* get_msg_list sets current msg on */
  137.     if (isoff(glob_flags, IS_PIPE))
  138.         unset_msg_bit(list, current_msg);
  139.     /* most commands move to the "next" message. type and print don't */
  140.     if ((!p || !*p || *p == 'n' || *p == '+') && current_msg < msg_cnt &&
  141.                     isoff(msg[current_msg].m_flags, UNREAD))
  142.         current_msg++;
  143.     if (p && (*p == '-' || !strcmp(p, "previous"))) {
  144.         while (--current_msg >= 0 &&
  145.         (ison(msg[current_msg].m_flags, DELETE) ||
  146.          ison(msg[current_msg].m_flags, SAVED)))
  147.         ;
  148.         if (current_msg < 0) {
  149.         print("No previous message.\n");
  150.         current_msg = 0;
  151.         return -1;
  152.         }
  153.     } else {
  154.         /*
  155.          * To be compatible with ucb-mail, find the next available unread
  156.          * message.  If at the end, only wrap around if "wrap" is set.
  157.          */
  158.         if (current_msg == msg_cnt && do_set(set_options, "wrap"))
  159.         current_msg = 0;
  160.         /* "type" or "print" prints the current only -- "next" goes on.. */
  161.         if (!p || !*p || *p == 'n')
  162.         while (current_msg < msg_cnt &&
  163.             (ison(msg[current_msg].m_flags, DELETE) ||
  164.              ison(msg[current_msg].m_flags, SAVED)))
  165.             current_msg++;
  166.         if (current_msg >= msg_cnt) {
  167.         print("No more messages.\n");
  168.         current_msg = msg_cnt - 1;
  169.         return -1;
  170.         }
  171.     }
  172.     if (isoff(glob_flags, IS_PIPE))
  173.         set_msg_bit(list, current_msg);
  174.     }
  175. #ifdef SUNTOOL
  176.     if (istool > 1)
  177.     on_intr();
  178. #endif /* SUNTOOL */
  179.     current_msg = 0;
  180.     for (x = 0; x < msg_cnt && isoff(glob_flags, WAS_INTR); x++)
  181.     if (msg_bit(list, x)) {
  182.         if (current_msg > 0 && istool > 1 && isoff(flg, NO_PAGE) &&
  183.             c_more("Type RETURN for next message, q to quit:") == 'q')
  184.         break;
  185.         current_msg = x;
  186. #ifdef SUNTOOL
  187.         if (istool > 1) {
  188.         read_mail(NO_ITEM, 0, NO_EVENT);
  189.         break;
  190.         }
  191. #endif /* SUNTOOL */
  192.         display_msg(x, flg);
  193.     }
  194. #ifdef SUNTOOL
  195.     if (istool > 1)
  196.     off_intr();
  197. #endif /* SUNTOOL */
  198.     return 0;
  199. }
  200.  
  201. preserve(n, argv, list)
  202. int n;        /* no use for argc, so use space for a local variable */
  203. char **argv, list[];
  204. {
  205.     register int unpre;
  206.  
  207.     unpre = !strncmp(*argv, "un", 2);
  208.     if (*++argv && !strcmp(*argv, "-?"))
  209.     return help(0, "preserve", cmd_help);
  210.     if (get_msg_list(argv, list) == -1)
  211.     return -1;
  212.     for (n = 0; n < msg_cnt; n++)
  213.     if (msg_bit(list, n))
  214.         if (unpre) {
  215.         if (ison(msg[n].m_flags, PRESERVE)) {
  216.             turnoff(msg[n].m_flags, PRESERVE);
  217.             turnon(glob_flags, DO_UPDATE);
  218.         }
  219.         } else {
  220.         if (isoff(msg[n].m_flags, PRESERVE)) {
  221.             turnon(msg[n].m_flags, PRESERVE);
  222.             turnon(glob_flags, DO_UPDATE);
  223.         }
  224.         }
  225.     if (istool)
  226.     (void) do_hdrs(0, DUBL_NULL, NULL);
  227.     return 0;
  228. }
  229.  
  230. lpr(n, argv, list)
  231. int n;  /* no use for argc, so use its address space for a variable */
  232. char **argv, list[];
  233. {
  234.     register FILE    *pp;
  235.     register long     flags = 0;
  236.     char        print_cmd[128], *printer, c, *cmd;
  237.     int            total = 0;
  238.     SIGRET        (*oldint)(), (*oldquit)();
  239.  
  240. #ifdef PRINTER_OPT
  241.     char *opt = PRINTER_OPT;
  242. #else
  243.     char opt[2];
  244. #ifdef SYSV
  245.     opt[0] = 'd';
  246. #else
  247.     opt[0] = 'P';
  248. #endif /* SYSV */
  249.     opt[1] = 0;
  250. #endif /* PRINTER_OPT */
  251.  
  252.     if (!chk_option("alwaysignore", "printer"))
  253.     turnon(flags, NO_IGNORE);
  254. #ifdef MSG_SEPARATOR
  255.     turnon(flags, NO_SEPARATOR);
  256. #endif /* MMDF */
  257.     if (!(printer = do_set(set_options, "printer")) || !*printer)
  258.     printer = DEF_PRINTER;
  259.     while (argv && *++argv && **argv == '-') {
  260.     n = 1;
  261.     while (c = argv[0][n++])
  262.         switch(c) {
  263.         case 'n': turnon(flags, NO_HEADER);
  264.         when 'h': turnoff(flags, NO_IGNORE);
  265.         when 'P': case 'd':
  266. #ifndef PRINTER_OPT
  267.             opt[0] = argv[0][n-1];
  268. #endif /* PRINTER_OPT */
  269.             if (!argv[0][n] && !(n = 0, *++argv)) {
  270.                 print("specify printer!\n");
  271.                 return -1;
  272.             }
  273.             printer = argv[0] + n;
  274.             n += strlen(printer);
  275.         otherwise: return help(0, "lpr", cmd_help);
  276.         }
  277.     }
  278.     if (get_msg_list(argv, list) == -1)
  279.     return -1;
  280.  
  281.     if (cmd = do_set(set_options, "print_cmd"))
  282.     (void) strcpy(print_cmd, cmd);
  283.     else
  284.     (void) sprintf(print_cmd, "%s %s%s", LPR, opt, printer);
  285.     Debug("print command: %s\n", print_cmd);
  286.     if (!(pp = popen(print_cmd, "w"))) {
  287.     error("cannot print");
  288.     return -1;
  289.     }
  290.     on_intr();
  291.     for (n = 0; isoff(glob_flags, WAS_INTR) && n < msg_cnt; n++) {
  292.     if (msg_bit(list, n)) {
  293.         if (total++)
  294.         (void) fputc('\f', pp); /* send a formfeed for multiple copies */
  295.         print("printing message %d...", n+1);
  296.         print_more("(%d lines)\n", copy_msg(n, pp, (u_long) flags, NULL));
  297.         turnon(msg[n].m_flags, PRINTED|DO_UPDATE);
  298.         turnon(glob_flags, DO_UPDATE);
  299.     }
  300.     }
  301.     off_intr();
  302.     (void) pclose(pp);
  303.     print_more("%d message%s printed ", total, (total==1)? "": "s");
  304.     if (cmd)
  305.     print_more("through \"%s\".\n", cmd);
  306.     else
  307.     print_more("at \"%s\".\n", printer);
  308.     return 0;
  309. }
  310.  
  311. /* save [msg_list] [file] */
  312. save_msg(n, argv, list)   /* argc isn't used, so use space for variable 'n' */
  313. int n;
  314. char **argv, list[];
  315. {
  316.     register FILE    *mail_fp = NULL_FILE;
  317.     register char     *file = NULL, *mode, firstchar = **argv, *tmp = ".";
  318.     int         msg_number, force = 0, by_subj = 0, by_author = 0;
  319.     char        buf[MAXPATHLEN], fbuf[MAXPATHLEN];
  320.     long         flg = 0;
  321.  
  322.     while (*++argv)
  323.     if (*argv[0] != '-')
  324.         break;
  325.     else
  326.         switch (argv[0][1]) {
  327.         case 'S' :
  328.             by_subj = 2;
  329.         when 's' :
  330.             by_subj = 1;
  331.         when 'A' :
  332.             by_author = 2;
  333.         when 'a' :
  334.             by_author = 1;
  335.         when 'f' :
  336.             force = 1;
  337.         otherwise :
  338.             return help(0, "save", cmd_help);
  339.         }
  340.     if (!force && (force = (*argv && !strcmp(*argv, "!"))))
  341.     argv++;
  342.     if ((n = get_msg_list(argv, list)) == -1)
  343.     return -1;
  344.     argv += n;
  345.     if (*argv && *(file = *argv) == '\\')
  346.     file++;
  347.     else if (!file && !by_subj && !by_author) {
  348.     /* if no filename specified, save in ~/mbox */
  349.     if (firstchar == 'w') {
  350.         /* mbox should have headers. If he really wants it, specify it */
  351.         print("Must specify file name for 'w'\n");
  352.         return -1;
  353.     }
  354.     if (!(file = do_set(set_options, "mbox")) || !*file)
  355.         file = DEF_MBOX;
  356.     }
  357.     n = 1; /* tell getpath to ignore no such file or directory */
  358.     if (file)
  359.     tmp = getpath(file, &n);
  360.     if (n < 0) {
  361.     print("%s: %s\n", file, tmp);
  362.     return -1;
  363.     } else if (n && !by_subj && !by_author) {
  364.     print("%s is a directory\n", file);
  365.     return -1;
  366.     }
  367.     file = strcpy(fbuf, tmp); /* getpath() called again later, save result */
  368.     if (force || Access(file, F_OK))
  369.     mode = "w", force = 0;
  370.     else
  371.     mode = "a";
  372.     if (firstchar != 'w' && *mode == 'a' && !by_author && !by_subj &&
  373.         !test_folder(file, "not a folder, save anyway?"))
  374.     return 0;
  375.     /*
  376.      * open the file for writing (appending) unless we're saving by subject
  377.      * or author name in which case we'll determine the filename later
  378.      */
  379.     if (!by_author && !by_subj && !(mail_fp = lock_fopen(file, mode))) {
  380.     error("cannot save in \"%s\"", file);
  381.     return -1;
  382.     }
  383.  
  384. #ifdef SUNTOOL
  385.     if (istool)
  386.     timeout_cursors(TRUE);
  387. #endif /* SUNTOOL */
  388.     if (!chk_option("alwaysignore", "save"))
  389.     turnon(flg, NO_IGNORE);    /* presently overridden by UPDATE_STATUS */
  390.     if (firstchar == 'w') {
  391.     turnon(flg, NO_HEADER);
  392. #ifdef MMDF
  393.     turnon(flg, NO_SEPARATOR);
  394. #endif /* MMDF */
  395.     } else
  396.     turnon(flg, UPDATE_STATUS);
  397.  
  398.     for (n = msg_number = 0; msg_number < msg_cnt; msg_number++)
  399.     if (msg_bit(list, msg_number)) {
  400.         if ((by_author || by_subj) && !mail_fp) {
  401.         char buf2[256], addr[256];
  402.         register char *p, *p2;
  403.         if (by_subj) {
  404.             if (p = header_field(msg_number, "subject")) {
  405.             /* convert spaces and non-alpha-numerics to '_' */
  406.             if (!lcase_strncmp(p, "re:", 3)) {
  407.                 p += 3;
  408.                 skipspaces(0);
  409.             }
  410.             for (p2 = p; *p2; p2++)
  411.                 if (!isalnum(*p2) && !index(".,@#$%-+=", *p2))
  412.                 *p2 = '_';
  413.             } else
  414.             p = "mbox";
  415.         } else {
  416.             (void) reply_to(msg_number, FALSE, buf2);
  417.             (void) get_name_n_addr(buf2, NULL, addr);
  418.             if (p = rindex(addr, '!'))
  419.             p++;
  420.             else
  421.             p = addr;
  422.             if (p2 = any(p, "@%"))
  423.             *p2 = 0;
  424.         }
  425.         if (!p || !*p)
  426.             p = "tmp";
  427.         (void) sprintf(buf, "%s/%s", file, p);
  428.         if (force || Access(buf, F_OK))
  429.             mode = "w";
  430.         else
  431.             mode = "a";
  432.         if (firstchar != 'w' && *mode == 'a' &&
  433.             !test_folder(buf, "not a folder, save anyway?")) {
  434.             if (by_author == 2 || by_subj == 2)
  435.             break;
  436.             continue;
  437.         }
  438.         if (!(mail_fp = lock_fopen(buf, mode))) {
  439.             error("cannot save in \"%s\"", buf);
  440.             if (by_author == 2 || by_subj == 2)
  441.             break;
  442.             continue;
  443.         }
  444.         }
  445.         print("%sing msg %d ... ",
  446.         (firstchar == 's')? "Sav" : "Writ", msg_number+1);
  447.         print_more("(%d lines)",
  448.         copy_msg(msg_number, mail_fp, (u_long) flg, NULL));
  449.         if (by_author == 1 || by_subj == 1) {
  450.         print_more(" in \"%s\"", buf);
  451.         (void) close_lock(buf, mail_fp), mail_fp = NULL_FILE;
  452.         }
  453.         print_more("\n");
  454.         n++;
  455.         if (isoff(msg[msg_number].m_flags, SAVED) && firstchar != 'c') {
  456.         turnon(glob_flags, DO_UPDATE);
  457.         turnon(msg[msg_number].m_flags, SAVED|DO_UPDATE);
  458.         }
  459.     }
  460.     if (mail_fp) {
  461.     (void) close_lock(file, mail_fp);
  462.     if (!file)
  463.         file = buf;
  464.     print_more("%s %d msg%s to %s\n",
  465.         (*mode == 'a')? "Appended" : "Saved", n, (n != 1)? "s": "", file);
  466.     }
  467. #ifdef SUNTOOL
  468.     if (istool) {
  469.     extern Panel_item folder_item, save_item;
  470.     timeout_cursors(FALSE);
  471.     if (firstchar != 'c' && n > 0)
  472.         (void) do_hdrs(0, DUBL_NULL, NULL);
  473.     if (*mode == 'w' && n > 0) {
  474. #ifndef NO_WALK_MENUS
  475.         create_folder_menus();
  476. #else /* NO_WALK_MENUS */
  477.         add_folder_to_menu(folder_item, 3);
  478.         add_folder_to_menu(save_item, 1);
  479. #endif /* NO_WALK_MENUS */
  480.     }
  481.     }
  482. #endif /* SUNTOOL */
  483.     return 0;
  484. }
  485.  
  486. respond(n, argv, list)
  487. int n;  /* no use for argc, so use its address space for a variable */
  488. char **argv, *list;
  489. {
  490.     register char *cmd = *argv;
  491.     char list1[MAXMSGS_BITS];
  492.     int cur_msg = current_msg, save_cnt = msg_cnt;
  493.  
  494.     if (*++argv && !strcmp(*argv, "-?"))
  495.     return help(0, "respond", cmd_help);
  496.     if ((n = get_msg_list(argv, list)) == -1)
  497.     return -1;
  498.  
  499.     /* make into our own list so ~: commands don't overwrite this list */
  500.     bitput(list, list1, MAXMSGS, =);
  501.  
  502.     /* back up one arg to replace "cmd" in the new argv[0] */
  503.     argv += (n-1);
  504.     if (!strcmp(cmd, "replyall"))
  505.     Upper(*cmd);
  506.     if (n > 0)
  507.     strdup(argv[0], cmd);
  508.  
  509.     /* make sure the *current* message is the one being replied to */
  510.     for (current_msg = -1, n = 0; n < msg_cnt && current_msg == -1; n++)
  511.     if (msg_bit(list1, n) && current_msg == -1)
  512.         current_msg = n;
  513.     if (current_msg == -1) { /* "reply -" can cause this to happen */
  514.     current_msg = cur_msg;
  515.     return -1;
  516.     }
  517.     if (do_mail(1 /* ignored */, argv, list) == -1)
  518.     return -1;
  519.     /* New mail may have arrived during do_mail(), which will change
  520.      * the msg_cnt.  Use the old count when examining the list of bits
  521.      * to set the replied flag, or the wrong messages can be marked.
  522.      */
  523.     for (n = 0; n < save_cnt; n++)
  524.     if (msg_bit(list1, n)) {
  525.         /* set_isread(n); */
  526.         set_replied(n); /* only if mail got delivered */
  527.     }
  528.     if (istool)
  529.     (void) do_hdrs(0, DUBL_NULL, NULL);
  530.     /* copy the specified list back into msg_list */
  531.     bitput(list1, list, MAXMSGS, =);
  532.     return 0;
  533. }
  534.  
  535. /* cd to a particular directory specified by "p" */
  536. cd(x, argv) /* argc, unused -- use space for a non-register variable */
  537. int x;
  538. char **argv;
  539. {
  540.     char *cwd, buf[MAXPATHLEN];
  541.     register char *path, *p = argv[1], *cdpath = NULL, *p2;
  542.     int err = 0;
  543.  
  544.     if (argv && argv[1] && !strcmp(argv[1], "-?"))
  545.     return help(0, argv[0], cmd_help);
  546.  
  547.     if (!strcmp(*argv, "pwd")) {
  548.     set_cwd(); /* reset in case some dummy changed $cwd */
  549.         if ((p = do_set(set_options, "cwd")) && *p) {
  550.         print("%s\n", p);
  551.         return 0;
  552.     }
  553.     return -1;
  554.     }
  555.     if (!p || !*p) /* if no args, pwd = ".", cd = ~ */
  556.     p = (**argv == 'p')? "." : "~";
  557.     /* if a full path was not specified, loop through cdpath */
  558.     if (**argv != 'p' && *p != '/' && *p != '~' && *p != '+')
  559.     cdpath = do_set(set_options, "cdpath");
  560.     (void) strcpy(buf, p);
  561.     do  {
  562.     err = x = 0;
  563.     path = getpath(buf, &x);
  564.     if (x != 1 || chdir(path) == -1) {
  565.         err = errno;
  566.         if (cdpath && *cdpath) {
  567.         char c;
  568.         if (p2 = any(cdpath, " \t:"))
  569.             c = *p2, *p2 = 0;
  570.         (void) sprintf(buf, "%s/%s", cdpath, p);
  571.         if (cdpath = p2) /* assign and compare to NULL */
  572.             *p2 = c;
  573.         while (cdpath && (isspace(*cdpath) || *cdpath == ':'))
  574.             cdpath++;
  575.         } else
  576.         break;
  577.     }
  578.     } while (err);
  579.     if (err)
  580.     error(p);
  581.     set_cwd();
  582.     if ((istool || iscurses || err) && (cwd = do_set(set_options, "cwd"))) {
  583.     if (err)
  584.         turnon(glob_flags, CONT_PRNT);
  585.     if (iscurses || istool || ison(glob_flags, WARNING))
  586.         print("Working dir: %s\n", cwd);
  587.     }
  588.     return 0;
  589. }
  590.  
  591. mush_quit(argc, argv)
  592. int argc;
  593. char **argv;
  594. {
  595.     u_long updated = ison(glob_flags, DO_UPDATE);
  596.  
  597.     if (argc > 1) {
  598.     if (!strcmp(argv[1], "-?"))
  599.         return help(0, "quit", cmd_help);
  600.     else {
  601.         print("%s: too many arguments\n", argv[0]);
  602.         return -1;
  603.     }
  604.     }
  605.     if ((!argc || (*argv && **argv == 'q')) && !copyback("Really Quit? ",TRUE))
  606.     return -1;
  607. #ifdef CURSES
  608.     if (iscurses) {
  609.     /* we may already be on the bottom line; some cases won't be */
  610.     move(LINES-1, 0), refresh();
  611.     if (updated)
  612.         putchar('\n');
  613.     }
  614. #endif /* CURSES */
  615.     cleanup(0);
  616. #ifdef lint
  617.     return 0;
  618. #endif /* lint */
  619. }
  620.  
  621. delete(argc, argv, list)
  622. int argc;
  623. char **argv, list[];
  624. {
  625.     register int prnt_next, undel = argc && **argv == 'u';
  626.     int old_msg = current_msg;
  627.  
  628.     prnt_next = (argv && (!strcmp(*argv, "dt") || !strcmp(*argv, "dp")));
  629.  
  630.     if (argc && *++argv && !strcmp(*argv, "-?"))
  631.     return help(0, "delete", cmd_help);
  632.  
  633.     if (ison(glob_flags, READ_ONLY)) {
  634.     print("Folder is read-only\n");
  635.     return -1;
  636.     }
  637.  
  638.     if (get_msg_list(argv, list) == -1)
  639.     return -1;
  640.     for (argc = 0; argc < msg_cnt; argc++)
  641.     if (msg_bit(list, argc))
  642.         if (undel)
  643.         turnoff(msg[argc].m_flags, DELETE);
  644.         else
  645.         turnon(msg[argc].m_flags, DELETE|DO_UPDATE);
  646.  
  647.     /* only if current_msg has been affected && not in curses mode */
  648.     if (prnt_next == 0 && !iscurses && msg_bit(list, current_msg))
  649.     prnt_next = !!do_set(set_options, "autoprint"); /* change to boolean */
  650.  
  651.     turnon(glob_flags, DO_UPDATE);
  652.  
  653.     /* goto next available message if current was just deleted.
  654.      * If there are no more messages, turnoff prnt_next.
  655.      */
  656.     if (!iscurses && !undel && msg_bit(list, current_msg))
  657.     (void) next_msg();
  658.     else
  659.     prnt_next = 0;
  660.  
  661.     if (prnt_next && !undel && !iscurses && isoff(glob_flags, DO_PIPE))
  662.     if (old_msg != current_msg && isoff(msg[current_msg].m_flags, DELETE))
  663.         display_msg(current_msg, (long)0);
  664.     else {
  665.         if (ison(msg[current_msg].m_flags, DELETE))
  666.         print("No more messages.\n");
  667.         current_msg = old_msg;
  668.     }
  669. #ifdef SUNTOOL
  670.     if (istool && isoff(glob_flags, IS_PIPE)) {
  671.     /* If deleted messages are to be shown and the current message
  672.      * has moved off the screen, or if all messages are deleted,
  673.      * redraw the whole display.
  674.      * Otherwise, redraw the display starting at the current
  675.      * topmost message, to bring the new current message on.
  676.      */
  677.     if (current_msg != old_msg && do_set(set_options, "show_deleted") ||
  678.         n_array[0] > msg_cnt)
  679.         (void) do_hdrs(0, DUBL_NULL, NULL);
  680.     else {
  681.         char *av[3], buf[8];
  682.         /* do_hdrs(0, ...) repositions the display, so pass an arg */
  683.         av[0] = "h";
  684.         av[1] = sprintf(buf, "%d", n_array[0] + 1);
  685.         av[2] = NULL;
  686.         (void) do_hdrs(2, av, NULL);
  687.     }
  688.     }
  689. #endif /* SUNTOOL */
  690.     return 0;
  691. }
  692.  
  693. /*
  694.  * historically from the "from" command in ucb-mail, this just prints
  695.  * the composed header of the messages set in list or in pipe.
  696.  */
  697. do_from(n, argv, list)
  698. int n;
  699. char **argv, list[];
  700. {
  701.     int inc_cur_msg = 0;
  702.  
  703.     if (argv && *++argv && !strcmp(*argv, "-?"))
  704.     return help(0, "from", cmd_help);
  705.     if (argv && *argv && (!strcmp(*argv, "+") || !strcmp(*argv, "-")))
  706.     if (!strcmp(*argv, "+")) {
  707.         if (!*++argv && current_msg < msg_cnt-1)
  708.         current_msg++;
  709.         inc_cur_msg = 1;
  710.     } else if (!strcmp(*argv, "-")) {
  711.         if (!*++argv && current_msg > 0)
  712.         current_msg--;
  713.         inc_cur_msg = -1;
  714.     }
  715.     if ((n = get_msg_list(argv, list)) == -1)
  716.     return -1;
  717.     else if (argv && argv[n]) {
  718.     u_long save_flags = glob_flags;
  719.     char *newargv[6], buf[BUFSIZ];
  720.     (void) argv_to_string(buf, &argv[n]);
  721.     newargv[0] = "pick";
  722.     if (n == 0) {
  723.         newargv[++n] = "-r";
  724.         newargv[++n] = "*";
  725.         turnoff(glob_flags, IS_PIPE);
  726.     } else {
  727.         n = 0;
  728.         turnon(glob_flags, IS_PIPE);
  729.     }
  730.     newargv[++n] = "-f";
  731.     newargv[++n] = buf;
  732.     newargv[++n] = NULL;
  733.     Debug("calling: "), print_argv(newargv);
  734.     turnon(glob_flags, DO_PIPE);
  735.     (void) do_pick(n, newargv, list);
  736.     glob_flags = save_flags;
  737.     }
  738.     for (n = 0; n < msg_cnt; n++)
  739.     if (msg_bit(list, n)) {
  740.         wprint("%s\n", compose_hdr(n));
  741.         /* if -/+ given, set current message pointer to this message */
  742.         if (inc_cur_msg) {
  743.         current_msg = n;
  744.         /* if - was given, then set to first listed message.
  745.          * otherwise, + means last listed message -- let it go...
  746.          */
  747.         if (inc_cur_msg < 0)
  748.             inc_cur_msg = 0;
  749.         }
  750.     }
  751.     return 0;
  752. }
  753.  
  754. static
  755. sorter(cmd1, cmd2)
  756. register struct cmd *cmd1, *cmd2;
  757. {
  758.     return strcmp(cmd1->command, cmd2->command);
  759. }
  760.  
  761. question_mark(x, argv)
  762. int x;
  763. char **argv;
  764. {
  765.     int n = 0, N = sizeof cmds / sizeof (struct cmd);
  766.     char *Cmds[sizeof cmds/sizeof(struct cmd)], *p, buf[30];
  767.  
  768.     if (!*++argv) {
  769.     if (N % 5)
  770.         N = N / 5 + 1;
  771.     else
  772.         N = N / 5;
  773.  
  774.     qsort((char *)cmds, sizeof(cmds)/sizeof(struct cmd)-1,
  775.                 sizeof(struct cmd), sorter);
  776.  
  777.     for (x = 0; x < N * 5; x++) {
  778.         if (!(x % 5))
  779.         if (!(p = Cmds[n++] = malloc(80))) {
  780.             error("malloc in question_mark()");
  781.             free_vec(Cmds);
  782.             return -1;
  783.         }
  784.         if (x%5*N+n < sizeof cmds / sizeof (struct cmd))
  785.         p += strlen(sprintf(p, "%-14.14s ", cmds[x%5*N+n-1].command));
  786.     }
  787.     Cmds[n++] = savestr("Type: `command -?' for help with most commands.");
  788.     Cmds[n] = NULL;
  789.     (void) help(0, (char *) Cmds, NULL);
  790.     free_vec(Cmds);
  791.     } else if (!strcmp(*argv, "-?"))
  792.     return help(0, "?", cmd_help);
  793.     else {
  794.     for (x = 0; cmds[x].command; x++)
  795.         if (!strcmp(*argv, cmds[x].command))
  796.         return cmd_line(sprintf(buf, "\\%s -?", *argv), msg_list);
  797.     print("Unknown command: %s\n", *argv);
  798.     }
  799.     return 0 - in_pipe();
  800. }
  801.