home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / mush6.4 / part13 / commands.c
C/C++ Source or Header  |  1989-03-12  |  29KB  |  1,080 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",      quit        },  { "quit",     quit        },
  32.     { "write",       save_msg    },  { "save",     save_msg   },
  33.     { "copy",       save_msg    },  { "folders",  folders    },
  34.     { "merge",      merge_folders },
  35. #ifdef CURSES
  36.     { "curses",   curses_init },  { "bind",    bind_it    },
  37.     { "unbind",   bind_it     },  { "bind-macro", bind_it  },
  38.     { "unbind-macro", bind_it  },
  39. #endif /* CURSES */
  40.     { "map",      bind_it     },  { "unmap",       bind_it    },
  41.     { "map!",     bind_it     },  { "unmap!",      bind_it    },
  42.     { "preserve", preserve    },  { "unpreserve",  preserve   },
  43.     { "replyall", respond     },  { "replysender", respond    },
  44.     { "delete",      delete      },  { "undelete",    delete     },
  45.     { "mail",       do_mail     },  { "echo",       do_echo    },
  46.     { "lpr",      lpr          },  { "alternates",  alts       },
  47.     { "edit",      edit_msg    },  { "flags",       msg_flags  },
  48.     { "pipe",     pipe_msg    },  { "eval",       eval_cmd   },
  49.     { "undigest", do_undigest    },
  50.     { NULL, quit }
  51. };
  52.  
  53. struct cmd ucb_cmds[] = {
  54.     { "t",   readmsg   }, { "n",  readmsg  }, { "p", readmsg  },
  55.     { "+",   readmsg   }, { "-",  readmsg  }, { "P", readmsg  },
  56.     { "Print", readmsg }, { "T",  readmsg  }, { "Type", readmsg },
  57.     { "x",   quit      }, { "xit", quit    }, { "q",  quit    },
  58.     { ":a",  do_hdrs   }, { ":d", do_hdrs  }, { ":r", do_hdrs },
  59.     { ":o",  do_hdrs   }, { ":u", do_hdrs  }, { ":n", do_hdrs },
  60.     { ":s",  do_hdrs   }, { ":p", do_hdrs  },
  61.     { "z",   do_hdrs   }, { "z-", do_hdrs  }, { "z+", do_hdrs },
  62.     { "h",   do_hdrs   }, { "H",  do_hdrs  },
  63.     { "f",   do_from   }, { "m",  do_mail  }, { "alts", alts  },
  64.     { "d",   delete    }, { "dt", delete   }, { "dp", delete  },
  65.     { "u",   delete    }, { "fo", folder   },
  66.     { "s",   save_msg  }, { "co", save_msg }, { "w", save_msg },
  67.     { "pre", preserve  }, { "unpre", preserve },
  68.     { "R",   respond   }, { "r",   respond },
  69.     { "reply", respond }, { "respond", respond },
  70.     { "v",   edit_msg  }, { "e",   edit_msg },
  71.     { NULL, quit }
  72. };
  73.  
  74. struct cmd hidden_cmds[] = {
  75.     { "debug", toggle_debug }, { "open",     nopenfiles },
  76.     { "stty",    my_stty     },
  77.     { "setenv",    Setenv      }, { "unsetenv",     Unsetenv   },
  78.     { "printenv", Printenv  }, { "Pipe",    pipe_msg   },
  79.     { NULL, quit }
  80. };
  81.  
  82. toggle_debug(argc, argv)
  83. char **argv;
  84. {
  85.     if (argc < 2) /* no value -- toggle "debug" (off/on) */
  86.     debug = !debug;
  87.     else
  88.     debug = atoi(*++argv);
  89.     print("debugging value: %d\n", debug);
  90.     return 0;
  91. }
  92.  
  93. /* if + was specified, then print messages without headers.
  94.  * n or \n (which will be NULL) will print next unread or undeleted message.
  95.  */
  96. readmsg(x, argv, list)
  97. register char **argv, list[];
  98. {
  99.     register char *p = x? *argv : NULL;
  100.     register long flg = 0;
  101.     extern FILE *ed_fp;
  102.  
  103.     if (x && *++argv && !strcmp(*argv, "-?"))
  104.     return help(0, "readmsg", cmd_help);
  105.     /* View a message as long as user isn't in the editor.  If is_getting
  106.      * is set, then the user is typing in a letter (or something else not
  107.      * threatening in tool mode).  If ed_fp is not null, then we've got the
  108.      * file open for typing.  If it's NULL, then an editor is going.
  109.      */
  110.     if (ison(glob_flags, IS_GETTING) && !ed_fp) {
  111.     print("Not while you're in the editor, you don't.\n");
  112.     return -1;
  113.     }
  114.     if (!msg_cnt) {
  115.     print("No messages.\n");
  116.     return -1;
  117.     }
  118.     if (x)
  119.     if (!strcmp(p, "top"))
  120.         turnon(flg, M_TOP);
  121.     else if (*p == '+') {
  122.         turnon(flg, NO_PAGE);
  123.         turnon(flg, NO_HEADER);
  124.     } else if (isupper(*p))
  125.         turnon(flg, NO_IGNORE);
  126.  
  127.     if (x && (x = get_msg_list(argv, list)) == -1)
  128.     return -1;
  129.     else if (x == 0) {  /* no arguments were parsed (or given) */
  130.     /* get_msg_list sets current msg on */
  131.     if (isoff(glob_flags, IS_PIPE))
  132.         unset_msg_bit(list, current_msg);
  133.     /* most commands move to the "next" message. type and print don't */
  134.     if ((!p || !*p || *p == 'n' || *p == '+') && current_msg < msg_cnt &&
  135.                     isoff(msg[current_msg].m_flags, UNREAD))
  136.         current_msg++;
  137.     if (p && (*p == '-' || !strcmp(p, "previous"))) {
  138.         while (--current_msg >= 0 &&
  139.         (ison(msg[current_msg].m_flags, DELETE) ||
  140.          ison(msg[current_msg].m_flags, SAVED)))
  141.         ;
  142.         if (current_msg < 0) {
  143.         print("No previous message.\n");
  144.         current_msg = 0;
  145.         return -1;
  146.         }
  147.     } else {
  148.         /*
  149.          * To be compatible with ucb-mail, find the next available unread
  150.          * message.  If at the end, only wrap around if "wrap" is set.
  151.          */
  152.         if (current_msg == msg_cnt && do_set(set_options, "wrap"))
  153.         current_msg = 0;
  154.         /* "type" or "print" prints the current only -- "next" goes on.. */
  155.         if (!p || !*p || *p == 'n')
  156.         while (current_msg < msg_cnt &&
  157.             (ison(msg[current_msg].m_flags, DELETE) ||
  158.              ison(msg[current_msg].m_flags, SAVED)))
  159.             current_msg++;
  160.         if (current_msg >= msg_cnt) {
  161.         print("No more messages.\n");
  162.         current_msg = msg_cnt - 1;
  163.         return -1;
  164.         }
  165.     }
  166.     if (isoff(glob_flags, IS_PIPE))
  167.         set_msg_bit(list, current_msg);
  168.     }
  169.     current_msg = 0;
  170.     for (x = 0; x < msg_cnt; x++)
  171.     if (msg_bit(list, x)) {
  172.         current_msg = x;
  173. #ifdef SUNTOOL
  174.         if (istool > 1) {
  175.         read_mail(NO_ITEM, 0, NO_EVENT);
  176.         return 0;
  177.         }
  178. #endif /* SUNTOOL */
  179.         display_msg(x, flg);
  180.     }
  181.     return 0;
  182. }
  183.  
  184. preserve(n, argv, list)
  185. register int n;        /* no use for argc, so use space for a local variable */
  186. register char **argv, list[];
  187. {
  188.     register int unpre;
  189.  
  190.     unpre = !strncmp(*argv, "un", 2);
  191.     if (*++argv && !strcmp(*argv, "-?"))
  192.     return help(0, "preserve", cmd_help);
  193.     if (get_msg_list(argv, list) == -1)
  194.     return -1;
  195.     for (n = 0; n < msg_cnt; n++)
  196.     if (msg_bit(list, n))
  197.         if (unpre) {
  198.         if (ison(msg[n].m_flags, PRESERVE)) {
  199.             turnoff(msg[n].m_flags, PRESERVE);
  200.             turnon(glob_flags, DO_UPDATE);
  201.         }
  202.         } else {
  203.         if (isoff(msg[n].m_flags, PRESERVE)) {
  204.             /* || ison(msg[n].m_flags, DELETE)) */
  205.             /* turnoff(msg[n].m_flags, DELETE); */
  206.             turnon(msg[n].m_flags, PRESERVE);
  207.             turnon(glob_flags, DO_UPDATE);
  208.         }
  209.         }
  210.     if (istool)
  211.     (void) do_hdrs(0, DUBL_NULL, NULL);
  212.     return 0;
  213. }
  214.  
  215. lpr(n, argv, list)
  216. register int n;  /* no use for argc, so use its address space for a variable */
  217. register char **argv, list[];
  218. {
  219.     register FILE    *pp;
  220.     register long     flags = 0;
  221.     char        print_cmd[128], *printer, c, *cmd;
  222.     int            total = 0;
  223.     SIGRET        (*oldint)(), (*oldquit)();
  224.  
  225.     turnon(flags, NO_IGNORE);
  226. #ifdef MMDF
  227.     turnon(flags, NO_SEPARATOR);
  228. #endif /* MMDF */
  229.     if (!(printer = do_set(set_options, "printer")) || !*printer)
  230.     printer = DEF_PRINTER;
  231.     while (argv && *++argv && **argv == '-') {
  232.     n = 1;
  233.     while (c = argv[0][n++])
  234.         switch(c) {
  235.         case 'n': turnon(flags, NO_HEADER);
  236.         when 'h': turnoff(flags, NO_IGNORE);
  237.         when 'P': case 'd':
  238.             if (!argv[0][n]) {
  239.                 print("specify printer!\n");
  240.                 return -1;
  241.             }
  242.             printer = argv[0] + n;
  243.             n += strlen(printer);
  244.         otherwise: return help(0, "lpr", cmd_help);
  245.         }
  246.     }
  247.     if (get_msg_list(argv, list) == -1)
  248.     return -1;
  249.  
  250.     if (cmd = do_set(set_options, "print_cmd"))
  251.     (void) strcpy(print_cmd, cmd);
  252.     else
  253. #ifdef SYSV
  254.     (void) sprintf(print_cmd, "%s -d%s", LPR, printer);
  255. #else
  256.     (void) sprintf(print_cmd, "%s -P%s", LPR, printer);
  257. #endif /* SYSV */
  258.     Debug("print command: %s\n", print_cmd);
  259.     if (!(pp = popen(print_cmd, "w"))) {
  260.     error("cannot print");
  261.     return -1;
  262.     }
  263.     on_intr();
  264.     for (n = 0; isoff(glob_flags, WAS_INTR) && n < msg_cnt; n++) {
  265.     if (msg_bit(list, n)) {
  266.         if (total++)
  267.         fputc('\f', pp); /* send a formfeed for multiple copies */
  268.         print("printing message %d...", n+1);
  269.         print_more("(%d lines)\n", copy_msg(n, pp, flags));
  270.     }
  271.     }
  272.     off_intr();
  273.     (void) pclose(pp);
  274.     print_more("%d message%s printed ", total, (total==1)? "": "s");
  275.     if (cmd)
  276.     print_more("through \"%s\".\n", cmd);
  277.     else
  278.     print_more("at \"%s\".\n", printer);
  279.     return 0;
  280. }
  281.  
  282. /* save [msg_list] [file] */
  283. save_msg(n, argv, list)   /* argc isn't used, so use space for variable 'n' */
  284. register char **argv, list[];
  285. {
  286.     register FILE    *mail_fp = NULL_FILE;
  287.     register char     *file = NULL, *mode, firstchar = **argv, *tmp = ".";
  288.     int         msg_number, force, by_subj = 0, by_author = 0;
  289.     char        buf[MAXPATHLEN];
  290.     long         flg = 0;
  291.  
  292.     while (*++argv)
  293.     if (*argv[0] != '-')
  294.         break;
  295.     else
  296.         switch (argv[0][1]) {
  297.         case 'S' :
  298.             by_subj = 2;
  299.         when 's' :
  300.             by_subj = 1;
  301.         when 'A' :
  302.             by_author = 2;
  303.         when 'a' :
  304.             by_author = 1;
  305.         otherwise :
  306.             return help(0, "save", cmd_help);
  307.         }
  308.     if (force = (*argv && !strcmp(*argv, "!")))
  309.     argv++;
  310.     if ((n = get_msg_list(argv, list)) == -1)
  311.     return -1;
  312.     argv += n;
  313.     if (*argv && *(file = *argv) == '\\')
  314.     file++;
  315.     else if (!file && !by_subj && !by_author) {
  316.     /* if no filename specified, save in ~/mbox */
  317.     if (firstchar == 'w') {
  318.         /* mbox should have headers. If he really wants it, specify it */
  319.         print("Must specify file name for 'w'\n");
  320.         return -1;
  321.     }
  322.     if (!(file = do_set(set_options, "mbox")) || !*file)
  323.         file = DEF_MBOX;
  324.     }
  325.     n = 1; /* tell getpath to ignore no such file or directory */
  326.     if (file)
  327.     tmp = getpath(file, &n);
  328.     if (n < 0) {
  329.     print("%s: %s\n", file, tmp);
  330.     return -1;
  331.     } else if (n && !by_subj && !by_author) {
  332.     print("%s is a directory\n", file);
  333.     return -1;
  334.     }
  335.     file = tmp;
  336.     if (force || Access(file, F_OK))
  337.     mode = "w", force = 0;
  338.     else
  339.     mode = "a";
  340.     /*
  341.      * open the file for writing (appending) unless we're saving by subject
  342.      * or author name in which case we'll determine the filename later
  343.      */
  344.     if (!by_author && !by_subj && !(mail_fp = mask_fopen(file, mode))) {
  345.     error("cannot save in \"%s\"", file);
  346.     return -1;
  347.     }
  348.  
  349. #ifdef SUNTOOL
  350.     if (istool)
  351.     lock_cursors();
  352. #endif /* SUNTOOL */
  353.     turnon(flg, NO_IGNORE);
  354.     if (firstchar == 'w') {
  355.     turnon(flg, NO_HEADER);
  356. #ifdef MMDF
  357.     turnon(flg, NO_SEPARATOR);
  358. #endif /* MMDF */
  359.     } else
  360.     turnon(flg, UPDATE_STATUS);
  361.  
  362.     for (n = msg_number = 0; msg_number < msg_cnt; msg_number++)
  363.     if (msg_bit(list, msg_number)) {
  364.         if ((by_author || by_subj) && !mail_fp) {
  365.         char buf2[256], addr[256];
  366.         register char *p, *p2;
  367.         if (by_subj) {
  368.             if (p = header_field(msg_number, "subject")) {
  369.             /* convert spaces and non-alpha-numerics to '_' */
  370.             if (!lcase_strncmp(p, "re: ", 4))
  371.                 p += 4;
  372.             for (p2 = p; *p2; p2++)
  373.                 if (!isalnum(*p2) && !index(".,@#$%-+=", *p2))
  374.                 *p2 = '_';
  375.             } else
  376.             p = "mbox";
  377.         } else {
  378.             (void) reply_to(msg_number, FALSE, buf2);
  379.             (void) get_name_n_addr(buf2, NULL, addr);
  380.             if (p = rindex(addr, '!'))
  381.             p++;
  382.             else
  383.             p = addr;
  384.             if (p2 = any(p, "@%"))
  385.             *p2 = 0;
  386.         }
  387.         if (!p || !*p)
  388.             p = "tmp";
  389.         (void) sprintf(buf, "%s/%s", file, p);
  390.         if (force || Access(buf, F_OK))
  391.             mode = "w";
  392.         else
  393.             mode = "a";
  394.         if (!(mail_fp = fopen(buf, mode))) {
  395.             error("cannot save in \"%s\"", buf);
  396.             if (by_author == 2 || by_subj == 2)
  397.             break;
  398.             continue;
  399.         }
  400.         }
  401.             print("%sing msg %d ... ",
  402.         (firstchar == 's')? "Sav" : "Writ", msg_number+1);
  403.         print_more("(%d lines)", copy_msg(msg_number, mail_fp, flg));
  404.         if (by_author == 1 || by_subj == 1) {
  405.         print_more(" in \"%s\"", buf);
  406.         fclose(mail_fp), mail_fp = NULL_FILE;
  407.         }
  408.         print_more("\n");
  409.         n++;
  410.         if (isoff(msg[msg_number].m_flags, SAVED) && firstchar != 'c') {
  411.         turnon(glob_flags, DO_UPDATE);
  412.         turnon(msg[msg_number].m_flags, SAVED);
  413.         }
  414.     }
  415.     if (mail_fp) {
  416.     fclose(mail_fp);
  417.     if (!file)
  418.         file = buf;
  419.     print_more("%s %d msg%s to %s\n",
  420.         (*mode == 'a')? "Appended" : "Saved", n, (n != 1)? "s": "", file);
  421.     }
  422. #ifdef SUNTOOL
  423.     if (istool) {
  424.     unlock_cursors();
  425.     (void) do_hdrs(0, DUBL_NULL, NULL);
  426.     add_folder_to_menu(folder_item, 3);
  427.     add_folder_to_menu(save_item, 1);
  428.     }
  429. #endif /* SUNTOOL */
  430.     return 0;
  431. }
  432.  
  433. respond(n, argv, list)
  434. register int n;  /* no use for argc, so use its address space for a variable */
  435. register char **argv, *list;
  436. {
  437.     register char *cmd = *argv;
  438.     char list1[MAXMSGS_BITS];
  439.     int cur_msg = current_msg;
  440.  
  441.     if (*++argv && !strcmp(*argv, "-?"))
  442.     return help(0, "respond", cmd_help);
  443.     if ((n = get_msg_list(argv, list)) == -1)
  444.     return -1;
  445.  
  446.     /* make into our own list so ~: commands don't overwrite this list */
  447.     bitput(list, list1, MAXMSGS, =);
  448.  
  449.     /* back up one arg to replace "cmd" in the new argv[0] */
  450.     argv += (n-1);
  451.     if (!strcmp(cmd, "replyall"))
  452.     Upper(*cmd);
  453.     strdup(argv[0], cmd);
  454.  
  455.     /* make sure the *current* message is the one being replied to */
  456.     for (current_msg = -1, n = 0; n < msg_cnt && current_msg == -1; n++)
  457.     if (msg_bit(list1, n) && current_msg == -1)
  458.         current_msg = n;
  459.     if (current_msg == -1) { /* "reply -" can cause this to happen */
  460.     current_msg = cur_msg;
  461.     return -1;
  462.     }
  463.     if (do_mail(1 /* ignored */, argv, list) == -1)
  464.     return -1;
  465.     for (n = 0; n < msg_cnt; n++)
  466.     if (msg_bit(list1, n)) {
  467.         /* set_isread(n); */
  468.         set_replied(n); /* only if mail got delivered */
  469.     }
  470.     if (istool)
  471.     do_hdrs(0, DUBL_NULL, NULL);
  472.     /* copy the specified list back into msg_list */
  473.     bitput(list1, list, MAXMSGS, =);
  474.     return 0;
  475. }
  476.  
  477. /* cd to a particular directory specified by "p" */
  478. cd(x, argv) /* argc, unused -- use space for a non-register variable */
  479. register char **argv;
  480. {
  481.     char cwd[MAXPATHLEN], buf[MAXPATHLEN];
  482.     register char *path, *p = argv[1], *cdpath = NULL, *p2;
  483. #ifdef SYSV
  484.     char *getcwd();
  485. #else
  486.     char *getwd();
  487. #endif /* SYSV */
  488.     int err = 0;
  489.  
  490.     if (!strcmp(*argv, "pwd") && (p = do_set(set_options, "cwd")) && *p) {
  491.     print("%s\n", p);
  492.     return -1;
  493.     }
  494.     if (!p || !*p) /* if no args, pwd = ".", cd = ~ */
  495.     p = (**argv == 'p')? "." : "~";
  496.     /* if a full path was not specified, loop through cdpath */
  497.     if (**argv != 'p' && *p != '/' && *p != '~' && *p != '+')
  498.     cdpath = do_set(set_options, "cdpath");
  499.     do  {
  500.     if (cdpath) {
  501.         char c;
  502.         if (p2 = any(cdpath, " \t:"))
  503.         c = *p2, *p2 = 0;
  504.         (void) sprintf(buf, "%s/%s", cdpath, p);
  505.         if (cdpath = p2) /* assign and compare to NULL */
  506.         *p2 = c;
  507.         while (cdpath && isspace(*cdpath))
  508.         cdpath++;
  509.     } else
  510.         (void) strcpy(buf, p);
  511.     x = 0;
  512.     path = getpath(buf, &x);
  513.     if (x != 1 || chdir(path) == -1)
  514.         err = errno;
  515.     else
  516.         err = 0;
  517.     } while (err && cdpath && *cdpath);
  518.     if (err)
  519.     error(p);
  520. #ifdef SYSV
  521.     if (getcwd(cwd, sizeof cwd) == NULL)
  522. #else
  523.     if (getwd(cwd) == NULL)
  524. #endif /* SYSV */
  525.     print("can't get cwd: %s.\n", cwd), err++;
  526.     else {
  527.     char *new_argv[4];
  528.     new_argv[0] = "cwd";
  529.     new_argv[1] = "=";
  530.     new_argv[2] = cwd;
  531.     new_argv[3] = NULL;
  532.     (void) add_option(&set_options, new_argv);
  533.     }
  534.     if (istool || iscurses || err) {
  535.     if (err)
  536.         turnon(glob_flags, CONT_PRNT);
  537.     if (iscurses || istool || ison(glob_flags, WARNING))
  538.         print("Working dir: %s\n", cwd);
  539.     }
  540.     return 0;
  541. }
  542.  
  543. quit(argc, argv)
  544. char **argv;
  545. {
  546.     u_long updated = ison(glob_flags, DO_UPDATE);
  547.  
  548.     if (argc > 1 && !strcmp(argv[1], "-?"))
  549.     return help(0, "quit", cmd_help);
  550.     if ((!argc || (*argv && **argv == 'q')) && !copyback("Really Quit? "))
  551.     return -1;
  552. #ifdef CURSES
  553.     if (iscurses) {
  554.     /* we may already be on the bottom line; some cases won't be */
  555.     move(LINES-1, 0), refresh();
  556.     if (updated)
  557.         putchar('\n');
  558.     }
  559. #endif /* CURSES */
  560.     cleanup(0);
  561. #ifdef lint
  562.     return 0;
  563. #endif /* lint */
  564. }
  565.  
  566. delete(argc, argv, list)
  567. register int argc;
  568. register char **argv, list[];
  569. {
  570.     register int prnt_next, undel = argc && **argv == 'u';
  571.     int old_msg = current_msg;
  572.  
  573.     prnt_next = (argv && (!strcmp(*argv, "dt") || !strcmp(*argv, "dp")));
  574.  
  575.     if (argc && *++argv && !strcmp(*argv, "-?")) {
  576.     print("usage: delete/undelete [msg_list]\n");
  577.     return -1;
  578.     }
  579.  
  580.     if (ison(glob_flags, READ_ONLY)) {
  581.     print("Folder is read-only\n");
  582.     return -1;
  583.     }
  584.  
  585.     if (get_msg_list(argv, list) == -1)
  586.     return -1;
  587.     for (argc = 0; argc < msg_cnt; argc++)
  588.     if (msg_bit(list, argc))
  589.         if (undel)
  590.         turnoff(msg[argc].m_flags, DELETE);
  591.         else
  592.         turnon(msg[argc].m_flags, DELETE);
  593.  
  594.     /* only if current_msg has been affected && not in curses mode */
  595.     if (prnt_next == 0 && !iscurses && msg_bit(list, current_msg))
  596.     prnt_next = !!do_set(set_options, "autoprint"); /* change to boolean */
  597.  
  598.     turnon(glob_flags, DO_UPDATE);
  599.  
  600.     /* goto next available message if current was just deleted.
  601.      * If there are no more messages, turnoff prnt_next.
  602.      */
  603.     if (!iscurses && !undel && msg_bit(list, current_msg) &&
  604.     (ison(msg[current_msg].m_flags, DELETE) ||
  605.     ison(msg[current_msg].m_flags, SAVED)))
  606.     next_msg();
  607.  
  608.     if (prnt_next && !undel && !iscurses)
  609.     if (old_msg != current_msg && isoff(msg[current_msg].m_flags, DELETE))
  610.         display_msg(current_msg, (long)0);
  611.     else
  612.         print("No more messages.\n"), current_msg = old_msg;
  613. #ifdef SUNTOOL
  614.     if (istool)
  615.     (void) do_hdrs(0, DUBL_NULL, NULL);
  616. #endif /* SUNTOOL */
  617.     return 0;
  618. }
  619.  
  620. /*
  621.  * historically from the "from" command in ucb-mail, this just prints
  622.  * the composed header of the messages set in list or in pipe.
  623.  */
  624. do_from(n, argv, list)
  625. char **argv, list[];
  626. {
  627.     int inc_cur_msg = 0;
  628.  
  629.     if (argv && *++argv && !strcmp(*argv, "-?"))
  630.     return help(0, "from", cmd_help);
  631.     if (argv && *argv && (!strcmp(*argv, "+") || !strcmp(*argv, "-")))
  632.     if (!strcmp(*argv, "+")) {
  633.         if (!*++argv && current_msg < msg_cnt-1)
  634.         current_msg++;
  635.         inc_cur_msg = 1;
  636.     } else if (!strcmp(*argv, "-")) {
  637.         if (!*++argv && current_msg > 0)
  638.         current_msg--;
  639.         inc_cur_msg = -1;
  640.     }
  641.     if (get_msg_list(argv, list) == -1)
  642.     return -1;
  643.     for (n = 0; n < msg_cnt; n++)
  644.     if (msg_bit(list, n)) {
  645.         wprint("%s\n", compose_hdr(n));
  646.         /* if -/+ given, set current message pointer to this message */
  647.         if (inc_cur_msg) {
  648.         current_msg = n;
  649.         /* if - was given, then set to first listed message.
  650.          * otherwise, + means last listed message -- let it go...
  651.          */
  652.         if (inc_cur_msg < 0)
  653.             inc_cur_msg = 0;
  654.         }
  655.     }
  656.     return 0;
  657. }
  658.  
  659. /*
  660.  * Do an ls from the system.
  661.  * Read from a popen and use wprint in case the tool does this command.
  662.  * The folders command uses this command.
  663.  */
  664. ls(x, argv)
  665. char **argv;
  666. {
  667.     register char  *p, *tmp;
  668.     char       buf[128];
  669.     register FILE  *pp;
  670.  
  671.     if (*++argv && !strcmp(*argv, "-?"))
  672.     return help(0, "ls", cmd_help);
  673.     if (!(p = do_set(set_options, "lister")))
  674.     p = "";
  675.     (void) sprintf(buf, "%s -C%s ", LS_COMMAND, p);
  676.     p = buf+strlen(buf);
  677.     for ( ; *argv; ++argv) {
  678.     x = 0;
  679.     if (**argv != '-')
  680.         tmp = getpath(*argv, &x);
  681.     else
  682.         tmp = *argv;
  683.     if (x == -1) {
  684.         wprint("%s: %s\n", *argv, tmp);
  685.         return -1;
  686.     }
  687.     p += strlen(sprintf(p, " %s", tmp));
  688.     }
  689.     if (!(pp = popen(buf, "r"))) {
  690.     error(buf);
  691.     return -1;
  692.     }
  693.     (void) do_pager(NULL, TRUE);
  694.     while (fgets(buf, 127, pp) && do_pager(buf, FALSE) != EOF)
  695.     ;
  696.     (void) pclose(pp);
  697.     (void) do_pager(NULL, FALSE);
  698.     return 0;
  699. }
  700.  
  701. sh(un_used, argv)
  702. char **argv;
  703. {
  704.     register char *p;
  705.     char buf[128];
  706.  
  707.     if (istool > 1 || *++argv && !strcmp(*argv, "-?"))
  708.     return help(0, "shell", cmd_help);
  709.     if (!(p = do_set(set_options, "shell"))
  710.     && !(p = do_set(set_options, "SHELL")))
  711.     p = DEF_SHELL;
  712.     if (!*argv)
  713.     (void) strcpy(buf, p);
  714.     else
  715.     (void) argv_to_string(buf, argv);
  716.     echo_on();
  717.     (void) system(buf);
  718.     echo_off();
  719.     return 0;
  720. }
  721.  
  722. static
  723. sorter(cmd1, cmd2)
  724. register struct cmd *cmd1, *cmd2;
  725. {
  726.     return strcmp(cmd1->command, cmd2->command);
  727. }
  728.  
  729. question_mark(x, argv)
  730. char **argv;
  731. {
  732.     int n = 0;
  733.     char *Cmds[sizeof cmds/sizeof(struct cmd)], *p, *malloc(), buf[30];
  734.  
  735.     qsort((char *)cmds, sizeof(cmds)/sizeof(struct cmd)-1,
  736.             sizeof(struct cmd), sorter);
  737.  
  738.     if (!*++argv) {
  739.     for (x = 0; cmds[x].command; x++) {
  740.         if (!(x % 5))
  741.         if (!(p = Cmds[n++] = malloc(80))) {
  742.             error("malloc in question_mark()");
  743.             free_vec(Cmds);
  744.             return -1;
  745.         }
  746.         p += strlen(sprintf(p, "%-14.14s ", cmds[x].command));
  747.     }
  748.     Cmds[n++] = savestr("Type: `command -?' for help with most commands.");
  749.     Cmds[n] = NULL;
  750.     (void) help(0, Cmds, NULL);
  751.     free_vec(Cmds);
  752.     } else {
  753.     for (x = 0; cmds[x].command; x++)
  754.         if (!strcmp(*argv, cmds[x].command))
  755.         return cmd_line(sprintf(buf, "\\%s -?", *argv), msg_list);
  756.     print("Unknown command: %s\n", *argv);
  757.     }
  758.     return 0 - in_pipe();
  759. }
  760.  
  761. #ifdef SIGSTOP
  762. stop(argc, argv)
  763. char **argv;
  764. {
  765.     if (istool)
  766.     print("Not a tool-based option.");
  767.     if (argc && *++argv && !strcmp(*argv, "-?"))
  768.     return help(0, "stop", cmd_help);
  769.     if (kill(getpid(), SIGTSTP) == -1)
  770.     error("couldn't stop myself");
  771.     return 0;
  772. }
  773. #endif /* SIGSTOP */
  774.  
  775. extern char **environ;
  776. static int spaces = 0;
  777.  
  778. Setenv(i, argv)
  779. char **argv;
  780. {
  781.     char *newstr;
  782.  
  783.     if (i < 2 || i > 3 || !strcmp(argv[1], "-?"))
  784.     return help(0, "setenv", cmd_help);
  785.  
  786.     if (i == 3) {
  787.     newstr = malloc(strlen(argv[1]) + strlen(argv[2]) + 2);
  788.     (void) sprintf(newstr, "%s=%s", argv[1], argv[2]);
  789.     } else {
  790.     newstr = malloc(strlen(argv[1]) + 2);
  791.     (void) sprintf(newstr, "%s=", argv[1]);
  792.     }
  793.  
  794.     (void) Unsetenv(2, argv);
  795.  
  796.     for (i = 0; environ[i]; i++);
  797.     if (!spaces) {
  798.     char **new_environ = (char **)malloc((i+2) * sizeof(char *));
  799.     /* add 1 for the new item, and 1 for null-termination */
  800.     if (!new_environ) {
  801.         free(newstr);
  802.         return -1;
  803.     }
  804.     spaces = 1;
  805.     for (i = 0; new_environ[i] = environ[i]; i++);
  806.     xfree(environ);
  807.     environ = new_environ;
  808.     }
  809.     environ[i] = newstr;
  810.     environ[i+1] = NULL;
  811.     spaces--;
  812.     return 0;
  813. }
  814.  
  815. Unsetenv(n, argv)
  816. char **argv;
  817. {
  818.     char **envp, **last;
  819.  
  820.     if (n != 2 || !strcmp(argv[1], "-?"))
  821.     return help(0, "unsetenv", cmd_help);
  822.  
  823.     n = strlen(argv[1]);
  824.     for (last = environ; *last; last++);
  825.     last--;
  826.  
  827.     for (envp = environ; envp <= last; envp++) {
  828.     if (strncmp(argv[1], *envp, n) == 0 && (*envp)[n] == '=') {
  829.         xfree(*envp);
  830.         *envp = *last;
  831.         *last-- = NULL;
  832.         spaces++;
  833.     }
  834.     }
  835.     return 0;
  836. }
  837.  
  838. Printenv(argc, argv)
  839. char **argv;
  840. {
  841.     char **e;
  842.     for (e = environ; *e; e++)
  843.     if (argc < 2 || !strncmp(*e, argv[1], strlen(argv[1])))
  844.         wprint("%s\n", *e);
  845.     return 0;
  846. }
  847.  
  848. /*
  849.  * internal stty call to allow the user to change his tty character
  850.  * settings.  sorry, no way to change cbreak/echo modes.  Save echo_flg
  851.  * so that execute() won't reset it.
  852.  */
  853. my_stty(un_used, argv)
  854. char **argv;
  855. {
  856.     u_long save_echo = ison(glob_flags, ECHO_FLAG);
  857.  
  858.     turnon(glob_flags, ECHO_FLAG);
  859.     execute(argv);
  860.     if (save_echo)
  861.     turnon(glob_flags, ECHO_FLAG);
  862.     else
  863.     turnoff(glob_flags, ECHO_FLAG);
  864.  
  865.     savetty();
  866. #ifdef TIOCGLTC
  867.     if (ioctl(0, TIOCGLTC, <chars))
  868.     error("TIOCGLTC");
  869. #endif /* TIOCGLTC */
  870.     echo_off();
  871.     return 0;
  872. }
  873.  
  874. /*
  875.  * Edit a message...
  876.  */
  877. edit_msg(i, argv, list)
  878. char *argv[], list[];
  879. {
  880.     int edited = 0;
  881.     char buf[MAXPATHLEN], *dir, *edit_cmd[3];
  882.     u_long flags = 0L;
  883.     FILE *fp;
  884.  
  885.     if (istool)
  886.     return 0;
  887.  
  888.     if (*++argv && !strcmp(*argv, "-?"))
  889.     return help(0, "edit_msg", cmd_help);
  890.  
  891.     if (ison(glob_flags, READ_ONLY)) {
  892.     print("\"%s\" is read-only.\n", mailfile);
  893.     return -1;
  894.     }
  895.  
  896.     if (get_msg_list(argv, list) == -1)
  897.     return -1;
  898.  
  899.     for (i = 0; i < msg_cnt; i++) {
  900.     if (!msg_bit(list, i))
  901.         continue;
  902.  
  903.     if (edited) {
  904.         print("Edit message %d [y/n/q]? ", i+1);
  905.         if (Getstr(buf, sizeof (buf), 0) < 0 || lower(buf[0]) == 'q')
  906.         return 0;
  907.         if (buf[0] && buf[0] != 'y')
  908.         continue;
  909.     }
  910.  
  911.     if (!(dir = do_set(set_options, "tmpdir")) &&
  912.         !(dir = do_set(set_options, "home")))
  913. alted:
  914.         dir = ALTERNATE_HOME;
  915.     (void) mktemp(sprintf(buf, "%s/.msgXXXXXXX", dir));
  916.     if (!(fp = mask_fopen(buf, "w+"))) {
  917.         if (strcmp(dir, ALTERNATE_HOME))
  918.         goto alted;
  919.         error("can't create %s", buf);
  920.         return -1;
  921.     }
  922.     wprint("editing message %d ...", i+1);
  923.     /* copy message into file making sure all headers exist. */
  924.     turnon(flags, UPDATE_STATUS);
  925. #ifdef MMDF
  926.     turnon(flags, NO_SEPARATOR);
  927. #endif /* MMDF */
  928.     wprint("(%d lines)\n", copy_msg(i, fp, flags));
  929.  
  930.     if (!(edit_cmd[0] = do_set(set_options, "visual")) || !*edit_cmd[0])
  931.         edit_cmd[0] = DEF_EDITOR;
  932.     edit_cmd[1] = buf;
  933.     edit_cmd[2] = NULL;
  934.     print("Starting \"%s %s\"...\n", edit_cmd[0], buf);
  935.     fclose(fp);
  936.     turnon(glob_flags, IS_GETTING);
  937.     execute(edit_cmd);
  938.     turnoff(glob_flags, IS_GETTING);
  939.     if (load_folder(buf, FALSE, (char *)i) > 0) {
  940.         (void) unlink(buf);
  941.         edited++;
  942.     }
  943.     set_isread(i); /* if you edit it, you read it, right? */
  944.     }
  945.     return 0;
  946. }
  947.  
  948. /*
  949.  * Pipe a message list to a unix command.  This function is hacked together
  950.  * from bits of readmsg, above, and other bits of display_msg (misc.c).
  951.  */
  952. pipe_msg(x, argv, list)
  953. register char **argv, list[];
  954. {
  955.     char *p = x ? *argv : NULL;
  956.     char buf[256];
  957.     u_long flg = 0L;
  958.     extern FILE *ed_fp;
  959.  
  960.     /* Increment argv only if argv[0] is the mush command "pipe" */
  961.     if (x && p && (!strcmp(p, "pipe") || !strcmp(p, "Pipe"))) {
  962.     if (*++argv && !strcmp(*argv, "-?"))
  963.         return help(0, "pipe_msg", cmd_help);
  964.     else if (p && *p == 'P')
  965.         turnon(flg, NO_HEADER);
  966.     }
  967.     /* Pipe a message as long as user isn't in the editor.  If is_getting
  968.      * is set, then the user is typing in a letter (or something else not
  969.      * threatening in tool mode).  If ed_fp is not null, then we've got the
  970.      * file open for typing.  If it's NULL, then an editor is going.
  971.      */
  972.     if (ison(glob_flags, IS_GETTING) && !ed_fp) {
  973.     print("Not while you're in the editor, you don't.\n");
  974.     return -1;
  975.     }
  976.     if (!msg_cnt) {
  977.     print("No messages.\n");
  978.     return -1;
  979.     }
  980.  
  981.     if (x && (x = get_msg_list(argv, list)) == -1)
  982.     return -1;
  983.     else {
  984.     argv += x;
  985.     if (!*argv) {
  986.         print("No unix command for pipe!\n");
  987.         return -1;
  988.     }
  989.     (void) argv_to_string(buf, argv);
  990.     }
  991.     current_msg = 0;
  992. #ifdef MMDF
  993.     turnon(flg, NO_SEPARATOR);
  994. #endif /* MMDF */
  995.     (void) do_pager(buf, TRUE); /* start pager */
  996.     for (x = 0; x < msg_cnt; x++)
  997.     if (msg_bit(list, x)) {
  998.         current_msg = x;
  999.         if (ison(msg[x].m_flags, DELETE)) {
  1000.         print("Message %d deleted; ", x+1);
  1001.         if (iscurses)
  1002.             print_more("skipping it.");
  1003.         else
  1004.             print("skipping it.\n");
  1005.         continue;
  1006.         }
  1007.         set_isread(x);
  1008.         (void) copy_msg(x, NULL_FILE, flg);
  1009.     }
  1010.     (void) do_pager(NULL, FALSE); /* end pager */
  1011.     return 0;
  1012. }
  1013.  
  1014. /* echo the arguments.  return 0 or -1 if -h given and there are no msgs. */
  1015. do_echo(n, argv)
  1016. register char **argv;
  1017. {
  1018.     char buf[BUFSIZ], c;
  1019.     int no_return = 0, comp_hdr = 0, as_prompt = 0;
  1020.  
  1021.     while (argv && *++argv && **argv == '-') {
  1022.     n = 1;
  1023.     while (c = argv[0][n++])
  1024.         switch(c) {
  1025.         case 'n': no_return++;
  1026.         when 'h': comp_hdr++;
  1027.         when 'p': as_prompt++;
  1028.         otherwise: return help(0, "echo", cmd_help);
  1029.         }
  1030.     }
  1031.     if (comp_hdr && as_prompt) {
  1032.     print("-h and -n cannot be used together.\n");
  1033.     return -1;
  1034.     }
  1035.  
  1036.     (void) argv_to_string(buf, argv);
  1037.     if (comp_hdr) {
  1038.     char *save_hdr_fmt = hdr_format;
  1039.     if (!msg_cnt) {
  1040.         print("No messages.\n");
  1041.         return -1;
  1042.     }
  1043.     hdr_format = buf;
  1044.     print("%s", compose_hdr(current_msg)+9); /* there may be a %-sign */
  1045.     hdr_format = save_hdr_fmt;
  1046.     } else if (as_prompt) {
  1047.     char *save_prompt = prompt;
  1048.     prompt = buf;
  1049.     mail_status(1);
  1050.     prompt = save_prompt;
  1051.     } else
  1052.     print("%s", buf); /* there may be a %-sign in "buf" */
  1053.     if (!no_return)
  1054.     print_more("\n");
  1055.     return 0;
  1056. }
  1057.  
  1058. eval_cmd (argc, argv, list)
  1059. char *argv[], list[];
  1060. {
  1061.     int status = -1;
  1062.     u_long save_is_pipe;
  1063.     char **newav, buf[BUFSIZ];
  1064.  
  1065.     if (*++argv && !strcmp(*argv, "-?"))
  1066.     return help(0, "eval", cmd_help);
  1067.  
  1068.     (void) argv_to_string(buf,argv);
  1069.     /* Can't use cmd_line() because we want DO_PIPE and IS_PIPE
  1070.      * to remain on -- cmd_line() turns both of them off
  1071.      */
  1072.     if (newav = make_command(buf, TRPL_NULL, &argc)) {
  1073.     save_is_pipe = ison(glob_flags, IS_PIPE);
  1074.     status = do_command(argc, newav, list);
  1075.     if (save_is_pipe)
  1076.         turnon(glob_flags, IS_PIPE);
  1077.     }
  1078.     return status;
  1079. }
  1080.