home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume22 / nn6.4 / part11 / init.c next >
Encoding:
C/C++ Source or Header  |  1990-06-07  |  20.9 KB  |  1,140 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    .nn/init file handling
  5.  */
  6.  
  7.  
  8. #include "config.h"
  9. #include "articles.h"
  10. #include "term.h"
  11. #include "keymap.h"
  12. #include "menu.h"
  13.  
  14. import char *help_directory, *db_directory;
  15.  
  16. export int in_init = 0;        /* true when parsing init file */
  17. export int alt_cmd_key;        /* K_ when parse_command returns AC_KEYCMD */
  18.  
  19. static int init_err = 0;    /* errors in init file */
  20.  
  21.  
  22. /*VARARGS*/
  23. init_message(va_alist)
  24. va_dcl
  25. {
  26.     char *fmt;
  27.     use_vararg;
  28.  
  29.     start_vararg;
  30.  
  31.     if (in_init) {
  32.     fmt = va_arg1(char *);
  33.  
  34.     printf("init error: ");
  35.     vprintf(fmt, va_args2toN);
  36.     putchar(NL);
  37.     init_err++;
  38.     } else
  39.     vmsg(va_args1toN);
  40.  
  41.     end_vararg;
  42. }
  43.  
  44.  
  45. #define MAXARG 10
  46.  
  47. static char *argvec[MAXARG + 2];
  48. static int argc;
  49.  
  50. static char *strip_str(cmd)
  51. register char *cmd;
  52. {
  53.     if (cmd == NULL) return cmd;
  54.  
  55.     while (*cmd && isspace(*cmd)) cmd++;
  56.     if (*cmd == NUL || *cmd == NL) return NULL;
  57.  
  58.     return cmd;
  59. }
  60.  
  61.  
  62. static split_command(cmd)
  63. register char *cmd;
  64. {
  65.     /* split command string */
  66.  
  67.     for (argc = 0; argc < MAXARG + 2; argc++) argvec[argc] = NULL;
  68. strip_more:
  69.     if ((cmd = strip_str(cmd)) == NULL || *cmd == '#') return 0;
  70.     if (*cmd == ':') {
  71.     cmd++;
  72.     goto strip_more;
  73.     }
  74.  
  75.     argc = 0;
  76.     argvec[0] = cmd;
  77.  
  78.     if (in_init)
  79.     while (*cmd) {
  80.         if (*cmd == NL) {
  81.         *cmd = NUL;
  82.         break;
  83.         }
  84.         cmd++;
  85.     }
  86.  
  87.     return 1;
  88. }
  89.  
  90. static char *argv(i)
  91. int i;
  92. {
  93.     register char *cmd;
  94.  
  95.     if (i > MAXARG) return NULL;
  96.  
  97.     if (argc <= i)
  98.     if (cmd = argvec[argc])
  99.         while (argc <= i) {
  100.         while (*cmd && !isspace(*cmd)) cmd++;
  101.         if (*cmd == NUL) {
  102.             argc = MAXARG;
  103.             break;
  104.         }
  105.  
  106.         *cmd++ = NUL;
  107.         if ((cmd = strip_str(cmd)) == NULL) {
  108.             argc = MAXARG;
  109.             break;
  110.         }
  111.         argvec[++argc] = cmd;
  112.         }
  113.     else
  114.         argc = MAXARG;
  115.  
  116.     return argvec[i];
  117. }
  118.  
  119. static is_sequence(cmd)
  120. char *cmd;
  121. {
  122.     if (!split_command(cmd)) return 0;
  123.     if ((cmd = argv(0)) == NULL) return 0;
  124.     return strcmp(cmd, "sequence") == 0;
  125. }
  126.  
  127. #define START_SEQUENCE 555
  128.  
  129. static load_init_file(name, seq_hook_ptr, only_seq)
  130. char *name;
  131. FILE **seq_hook_ptr;
  132. {
  133.     FILE *init;
  134.     char cmdbuf[512], *cmd, *term;
  135.     extern char *term_name;
  136.  
  137.     /* use cmdbuf temporarily (to handle @ expansion) */
  138.     for (cmd = cmdbuf; *name; name++)
  139.     if (*name == '@') {
  140.         term = term_name;
  141.         while (term && *term) *cmd++ = *term++;
  142.     } else
  143.         *cmd++ = *name;
  144.     *cmd = NUL;
  145.     name = cmdbuf;
  146.  
  147.     if (strchr(name, '/') == NULL)
  148.     name = relative(nn_directory, name);
  149.  
  150.     init = open_file(name, OPEN_READ);
  151.     if (init == NULL) return;
  152.  
  153.     while (fgets(cmdbuf, 512, init)) {
  154.     if (only_seq) {
  155.         if (!is_sequence(cmdbuf)) continue;
  156.         *seq_hook_ptr = init;
  157.         return;
  158.     }
  159.     /* we use AC_REDRAW to avoid !-commands clear the screen */
  160.     if (parse_command(cmdbuf, AC_REDRAW, init) == START_SEQUENCE) {
  161.         if (seq_hook_ptr) {
  162.         *seq_hook_ptr = init;
  163.         return;    /* no close !! */
  164.         } else {
  165.         init_message("load file contains 'sequence'");
  166.         fclose(init);
  167.         return;
  168.         }
  169.     }
  170.     }
  171.  
  172.     fclose(init);
  173. }
  174.  
  175. visit_init_file(only_seq, first_arg)
  176. int only_seq;
  177. char *first_arg;
  178. {
  179.     extern FILE *loc_seq_hook, *glob_seq_hook;
  180.     char *next_arg;
  181.  
  182.     if (first_arg && strncmp(first_arg, "-I", 2) == 0) {
  183.     if (first_arg[2] == NUL) return;
  184.     first_arg += 2;
  185.     } else
  186.     first_arg = ",init";
  187.  
  188.     in_init = 1;
  189.     while (first_arg) {
  190.     next_arg = strchr(first_arg, ',');
  191.     if (next_arg) *next_arg++ = NUL;
  192.  
  193.     if (*first_arg == NUL) {
  194.         if (glob_seq_hook == NULL)
  195.         load_init_file(relative(lib_directory, "init"), &glob_seq_hook, only_seq);
  196.     } else {
  197.         if (loc_seq_hook != NULL) {
  198.         fclose(loc_seq_hook);
  199.         loc_seq_hook = NULL;
  200.         }
  201.         load_init_file(first_arg, &loc_seq_hook, only_seq);
  202.     }
  203.     first_arg = next_arg;
  204.     }
  205.  
  206.     if (init_err) nn_exit(1);
  207.     in_init = 0;
  208. }
  209.  
  210.  
  211. /*
  212.  * parse a command (also :-commands)
  213.  */
  214.  
  215. static char *sw_string;
  216.  
  217. #define    SWITCH(str)    \
  218.     for (sw_string = str; sw_string; sw_string = NULL)
  219.  
  220. #define CASE(str)    \
  221.     if (strcmp(sw_string, str) == 0)
  222.  
  223.  
  224. #define ARG(i, str)    (argv(i) && strcmp(argv(i), str) == 0)
  225. #define ARGVAL(i)    atol(argv(i))
  226. #define ARGTAIL        argvec[argc]
  227.  
  228. struct alt_commands {
  229.     char *alt_name;
  230.     int     alt_len;
  231.     int  alt_type;
  232. } alt_commands[] = {
  233.     "admin",            5,    0,
  234.     "bug",            3,    0,
  235.     "cd",            2,    1,
  236.     "compile",            7,    0,
  237.     "coredump",            8,    0,
  238.     "cost",            4,    0,
  239.     "decode",            6,    0,
  240.     "define",            6,    0,
  241.     "help",            4,    2,
  242.     "local",            5,    3,
  243.     "man",            3,    0,
  244.     "map",            3,    -1,
  245.     "map both",            8,    4,
  246.     "map key",            7,    0,
  247.     "map menu",            8,    4,
  248.     "map show",            8,    4,
  249.     "mkdir",            5,    1,
  250.     "patch",            5,    0, /* QUICK HACK */
  251.     "post",            4,    0, /* QUICK HACK */
  252.     "print",            5,    0, /* QUICK HACK */
  253.     "pwd",            3,    0,
  254.     "rmail",            5,    0,
  255.     "set",            3,    3,
  256.     "show",            4,    -1,
  257.     "show groups",        11,    -1,
  258.     "show groups all",        15,    0,
  259.     "show groups subscr",    18,    0,
  260.     "show groups total",    17,    0,
  261.     "show groups unsub",    17,    0,
  262.     "show kill",        9,    0,
  263.     "show map",            8,    -1,
  264.     "show map #",        10,    0,
  265.     "show map key",        12,    0,
  266.     "show map menu",        13,    0,
  267.     "show map show",        13,    0,
  268.     "show rc ",            8,    0,
  269.     "sort",            4,    -1,
  270.     "sort arrival",        12,    0,
  271.     "sort date",        9,    0,
  272.     "sort lexical",        12,    0,
  273.     "sort sender",        11,    0,
  274.     "sort subject",        12,    0,
  275.     "toggle",            6,    3,
  276.     "unread",            6,    0,
  277.     "unset",            5,    3,
  278.     "unshar",            6,    0, /* QUICK HACK */
  279.     NULL,            0,    0
  280. };
  281.  
  282. alt_completion(buf, index)
  283. char *buf;
  284. int index;
  285. {
  286.     static char *head, *tail = NULL, buffer[FILENAME];
  287.     static int len;
  288.     static struct alt_commands *alt, *help_alt;
  289.     static fct_type other_compl;
  290.     int temp;
  291.     register char *p, *q;
  292.     extern int file_completion(), var_completion(), cmd_completion();
  293.     extern int list_offset;
  294.  
  295.     if (other_compl) {
  296.     temp = CALL(other_compl)(buf, index);
  297.     if (index == 0 && temp == 1 && tail) strcpy(tail, head);
  298.     if (index < 0 || (index == 0 && temp == 0)) {
  299.         other_compl = NULL;
  300.         list_offset = 0;
  301.     }
  302.     return temp;
  303.     }
  304.  
  305.     if (index < 0) return 0;
  306.  
  307.     if (buf) {
  308.     head = buf;
  309.     tail = buf + index;
  310.     alt = help_alt = alt_commands;
  311.     len = tail - head;
  312.     other_compl = NULL;
  313.  
  314.     for (; alt->alt_name; alt++) {
  315.         if (len <= alt->alt_len || head[alt->alt_len] != SP) continue;
  316.         index = strncmp(alt->alt_name, head, alt->alt_len);
  317.         if (index < 0) continue;
  318.         if (index > 0) break;
  319.  
  320.         if (alt->alt_type < 0) {
  321.         if (len > alt->alt_len) continue;
  322.         break;
  323.         }
  324.  
  325.         if (alt->alt_type == 0) return -1; /* cannot be further compl */
  326.  
  327.         head += alt->alt_len;
  328.         while (*head && *head == SP) head++;
  329.         len = tail - head;
  330.         temp = -1;
  331.  
  332.         switch (alt->alt_type) {
  333.          case 1:
  334.         other_compl = file_completion;
  335.         tail = NULL;
  336.         temp = file_completion(head, len);
  337.         break;
  338.  
  339.          case 2:
  340.         other_compl = file_completion;
  341.         sprintf(buffer, "%s.%s",
  342.             relative(help_directory, "help"), head);
  343.         len = strlen(buffer);
  344.         head = buffer + len;
  345.         list_offset = 5;
  346.         temp = file_completion(buffer, len);
  347.         break;
  348.  
  349.          case 3:
  350.         /* [set ]variable[ value] */
  351.         for (p = head; *p; )
  352.             if (*p++ == SP) return -1;
  353.         other_compl = var_completion;
  354.         tail = NULL;
  355.         temp = var_completion(head, len);
  356.         break;
  357.  
  358.          case 4:
  359.         /* [map XXX ]Y command[ N] */
  360.         for (p = head, temp = 0; *p; )
  361.             if (*p++ == SP) {
  362.             while (*p && *p == SP) p++;
  363.             head = p;
  364.             temp++;
  365.             }
  366.         if (temp != 1) return -1;
  367.  
  368.         other_compl = cmd_completion;
  369.         tail = NULL;
  370.         len = p - head;
  371.         temp = cmd_completion(head, len);
  372.         break;
  373.         }
  374.         if (temp <= 0) other_compl = NULL;
  375.         return temp;
  376.     }
  377.  
  378.     alt = alt_commands;
  379.     return 1;
  380.     }
  381.  
  382.     if (index) {
  383.     list_completion((char *)NULL);
  384.     if (help_alt->alt_name == NULL) help_alt = alt_commands;
  385.     list_offset = 0;
  386.     if (p = strrchr(head, ' ')) list_offset = p - head;
  387.  
  388.     while (help_alt->alt_name) {
  389.         if (len > help_alt->alt_len ||
  390.         (index = strncmp(help_alt->alt_name, head, len)) < 0) {
  391.         help_alt++;
  392.         continue;
  393.         }
  394.         if (index > 0) {
  395.         help_alt = alt_commands;
  396.         break;
  397.         }
  398.         p = help_alt->alt_name;
  399.         if (list_completion(p) == 0) break;
  400.         temp = help_alt->alt_len;
  401.  
  402.         do help_alt++;
  403.         while ((q = help_alt->alt_name) && help_alt->alt_len > temp &&
  404.            strncmp(p, q, temp) == 0);
  405.     }
  406.     fl;
  407.     list_offset = 0;
  408.     return 1;
  409.     }
  410.  
  411.     for (; alt->alt_name; alt++) {
  412.     if (len == 0)
  413.         index = 0;
  414.     else
  415.         index = strncmp(alt->alt_name, head, len);
  416.     if (index < 0) continue;
  417.     if (index > 0) break;
  418.  
  419.     p = alt->alt_name;
  420.     sprintf(tail, "%s ", p + len);
  421.     temp = alt->alt_len;
  422.  
  423.     do alt++;
  424.     while ((q = alt->alt_name) && alt->alt_len > temp &&
  425.            strncmp(p, q, temp) == 0);
  426.  
  427.     return 1;
  428.     }
  429.     return 0;
  430. }
  431.  
  432. static print_debug_info()
  433. {
  434.     clrdisp();
  435.     printf("group=%s, nart=%ld\n\r", current_group->group_name, n_articles);
  436.     any_key(0);
  437. }
  438.  
  439. static print_command(str)
  440. char *str;
  441. {
  442.     char **av;
  443.  
  444.     if (!in_init) {
  445.     msg(str);
  446.     return;
  447.     }
  448.  
  449.     printf("\r%s:", str);
  450.     for (av = argvec; *av; av++)
  451.         printf(" %s", *av);
  452.     putchar(NL);
  453. }
  454.  
  455.  
  456. static do_show(table, mode_arg)
  457. char *table;
  458. int mode_arg;
  459. {
  460.     register group_header *gh;
  461.  
  462.     if (in_init || table == NULL) return 0;
  463.  
  464.     no_raw();
  465.  
  466.     SWITCH( table ) {
  467.  
  468.     CASE( "kill" ) {
  469.         clrdisp();
  470.         dump_kill_list();
  471.         break;
  472.     }
  473.  
  474.     CASE( "groups" ) {
  475.  
  476.         clrdisp();
  477.         if ARG(mode_arg, "all")
  478.         group_overview(1);
  479.         else
  480.         if ARG(mode_arg, "total")
  481.         group_overview(2);
  482.         else
  483.         if ARG(mode_arg, "unsub")
  484.         group_overview(3);
  485.         else
  486.         group_overview(0);
  487.  
  488.         break;
  489.     }
  490.  
  491.     CASE( "map" ) {
  492.         char *name;
  493.         extern in_menu_mode;
  494.  
  495.         if ((name = argv(mode_arg)) == NULL)
  496.         name = in_menu_mode ? "menu" : "show";
  497.  
  498.         if (name[0] == '#') {
  499.         clrdisp();
  500.         dump_multi_keys();
  501.         break;
  502.         }
  503.  
  504.         SWITCH( name ) {
  505.  
  506.         CASE( "key" ) {
  507.             clrdisp();
  508.             dump_global_map();
  509.             break;
  510.         }
  511.         CASE( "menu" ) {
  512.             clrdisp();
  513.             dump_key_map(menu_key_map, "menu", K_ONLY_MENU);
  514.             break;
  515.         }
  516.         CASE( "show" ) {
  517.             clrdisp();
  518.             dump_key_map(more_key_map, "show", K_ONLY_MORE);
  519.             break;
  520.         }
  521.  
  522.         init_message("unknown map '%s'", argv(mode_arg));
  523.         goto err;
  524.         /*NOTREACHED*/
  525.         }
  526.  
  527.         break;
  528.     }
  529.  
  530.     CASE( "rc" ) {
  531.         if (argv(2)) {
  532.         gh = lookup(argv(2));
  533.         if (gh == NULL) {
  534.             msg("Unknown: %s", argv(2));
  535.             break;
  536.         }
  537.         } else
  538.         gh = current_group;
  539.         if (gh->group_flag & G_FAKED) break;
  540.  
  541.         clrdisp();
  542.  
  543.         printf("Available: %ld - %ld  (unread %ld)\n\n",
  544.            (long)(gh->first_db_article), (long)(gh->last_db_article),
  545.            (long)(gh->unread_count));
  546.         printf(".newsrc:\n\r>%s\r<%s\n\rselect:\n\r>%s\r<%s\n\r",
  547.            gh->newsrc_line ? gh->newsrc_line : "(null)\n",
  548.            gh->newsrc_orig == gh->newsrc_line ? "(same)\n" :
  549.            gh->newsrc_orig ? gh->newsrc_orig : "(null)\n",
  550.            gh->select_line ? gh->select_line : "(null)\n",
  551.            gh->select_orig == gh->select_line ? "(same)\n" :
  552.            gh->select_orig ? gh->select_orig : "(null)\n");
  553.         any_key(0);
  554.         break;
  555.     }
  556.  
  557.     init_message("unknown table '%s'", table);
  558.     goto err;
  559.     /*NOTREACHED*/
  560.     }
  561.  
  562.     raw();
  563.     return 1;
  564. err:
  565.     raw();
  566.     return 0;
  567. }
  568.  
  569.  
  570. static do_map(initf)
  571. FILE *initf;
  572. {
  573.     int code, map_menu, map_show, must_redraw = 0;
  574.  
  575.     SWITCH( argv(1) ) {
  576.  
  577.     CASE( "key" ) {
  578.         if (argv(3) == NULL) break;
  579.         global_key_map[parse_key(argv(2))] = parse_key(argv(3));
  580.         goto out;
  581.     }
  582.  
  583.     if (argv(1)[0] == '#') {
  584.         key_type multi_buffer[16], *mb;
  585.         int i;
  586.  
  587.         if (!isdigit(argv(1)[1])) break;
  588.  
  589.         for (i = 2, mb = multi_buffer; argv(i); i++)
  590.         *mb++ = parse_key(argv(i));
  591.         *mb = NUL;
  592.  
  593.         enter_multi_key(K_function(argv(1)[1] - '0'),
  594.                 (key_type *)copy_str((char *)multi_buffer));
  595.  
  596.         goto out;
  597.     }
  598.  
  599.     code = K_UNBOUND;
  600.     map_menu = map_show = 0;
  601.  
  602.     CASE( "menu" ) {
  603.         map_menu++;
  604.     }
  605.     CASE( "show" ) {
  606.         map_show++;
  607.     }
  608.     CASE( "both" ) {
  609.         map_menu++;
  610.         map_show++;
  611.     }
  612.  
  613.     if (ARG(3, "(")) {
  614.         extern char *m_define();
  615.  
  616.         code = (int)m_define("-2", initf);
  617.         must_redraw = 1;
  618.         if (code == K_UNBOUND) goto mac_err;
  619.     }
  620.  
  621.     if (map_menu) {
  622.         if (code == K_UNBOUND && argv(3))
  623.         code = lookup_command(argv(3), K_ONLY_MENU);
  624.  
  625.         if (code == K_EQUAL_KEY) {
  626.         if (argv(4))
  627.             code = menu_key_map[parse_key(argv(4))];
  628.         else
  629.             goto mac_err;
  630.         } else
  631.         if (code == K_MACRO || code == K_ARTICLE_ID)
  632.         if (argv(4))
  633.             code |= atoi(argv(4));
  634.         else
  635.             goto mac_err;
  636.  
  637.         if (code != K_INVALID) {
  638.         menu_key_map[parse_key(argv(2))] = code;
  639.         if (!map_show) goto out;
  640.         }
  641.     }
  642.  
  643.     if (map_show) {
  644.         if (code == K_UNBOUND && argv(3))
  645.         code = lookup_command(argv(3), K_ONLY_MORE);
  646.  
  647.         if (code == K_EQUAL_KEY) {
  648.         if (argv(4))
  649.             code = menu_key_map[parse_key(argv(4))];
  650.         else
  651.             goto mac_err;
  652.         } else
  653.         if (code == K_MACRO)
  654.         if (argv(4))
  655.             code |= atoi(argv(4));
  656.         else
  657.             goto mac_err;
  658.  
  659.         if (code != K_INVALID) {
  660.         more_key_map[parse_key(argv(2))] = code;
  661.         goto out;
  662.         }
  663.     }
  664.  
  665.     if (argv(4)) break;
  666.  
  667.     if (code == K_INVALID) {
  668.         init_message("unknown key command: %s", argv(3));
  669.         goto out;
  670.     }
  671.     }
  672.  
  673.     print_command("syntax error");
  674.     goto out;
  675.  
  676.  mac_err:
  677.     print_command("map argument missing");
  678.  out:
  679.     return must_redraw;
  680. }
  681.  
  682. static parse_on_to_end(f)
  683. FILE *f;
  684. {
  685.     register char *cp;
  686.     char buf[256];
  687.  
  688.     if (argv(1) == NULL) goto on_err;
  689.  
  690.     SWITCH ( argv(1) ) {
  691.  
  692.     CASE( "entry" ) {
  693.         import char *dflt_enter_macro;
  694.         group_header *gh, *get_group_search();
  695.         char *macro, *parse_enter_macro();
  696.         int i;
  697.  
  698.         macro = parse_enter_macro(f, NL);
  699.         if (ARGTAIL) {
  700.         for (i = 2; argv(i); i++) {
  701.             start_group_search(argv(i));
  702.             while (gh = get_group_search())
  703.             gh->enter_macro = macro;
  704.         }
  705.         } else
  706.         dflt_enter_macro = macro;
  707.         return;
  708.     }
  709.  
  710. /*    CASE( "exit" ) {
  711.         import char *dflt_exit_macro;
  712.  
  713.         dflt_exit_macro = parse_enter_macro(f, NL);
  714.         return;
  715.     }
  716. */
  717.     CASE( "slow" ) {
  718.         import int terminal_speed, slow_speed;
  719.  
  720.         if (terminal_speed <= (slow_speed / 10)) return;
  721.         break;
  722.     }
  723.  
  724.     CASE( "fast" ) {
  725.         import int terminal_speed, slow_speed;
  726.  
  727.         if (terminal_speed > (slow_speed / 10)) return;
  728.         break;
  729.     }
  730.  
  731.     CASE( "term" ) {
  732.         extern char *term_name;
  733.         int i;
  734.  
  735.         for (i = 2; argv(i) != NULL; i++)
  736.         if (strcmp(argv(2), term_name) == 0) return;
  737.         break;
  738.     }
  739.  
  740.     CASE( "host" ) {
  741.         char local_host[100];
  742.         int i;
  743.  
  744.         gethostname(local_host, 100);
  745.         for (i = 2; argv(i) != NULL; i++)
  746.         if (strcmp(argv(2), local_host) == 0) return;
  747.         break;
  748.     }
  749.  
  750.     goto on_err;
  751.     }
  752.  
  753.     while (fgets(buf, 256, f) != NULL) {
  754.     for (cp = buf; *cp && isascii(*cp) && isspace(*cp); cp++);
  755.     if (strncmp(cp, "end", 3) == 0) return;
  756.     }
  757.     init_message("end missing (on %s)", argv(1));
  758.     return;
  759.     
  760. on_err:
  761.     init_message("on `what'?");
  762. }
  763.  
  764. parse_command(cmd, ok_val, initf)
  765. char *cmd;
  766. int ok_val;
  767. FILE *initf;
  768. {
  769.     extern char *m_define(), *parse_enter_macro();
  770.  
  771.     if (!split_command(cmd)) return ok_val;
  772.  
  773.     if (*ARGTAIL == '!') {
  774.     if (ok_val == AC_UNCHANGED) { /* in macro */
  775.         if (ARGTAIL[1] == '!') /* !!cmd => guarantee no output! */
  776.         run_shell(ARGTAIL+2, -2);
  777.         else
  778.         run_shell(ARGTAIL+1, -1);
  779.         return ok_val;
  780.     }
  781.     if (run_shell(ARGTAIL+1, ok_val == AC_PROMPT ? 1 : 0)) {
  782.         any_key(0);
  783.         return AC_REDRAW;
  784.     }
  785.     return ok_val;
  786.     }
  787.  
  788.     SWITCH( argv(0) ) {
  789.  
  790.     CASE( "unset" ) {
  791.         if (argv(1) == NULL) goto stx_err;
  792.  
  793.         if (set_variable(argv(1), 0, (char *)NULL))
  794.         return AC_REDRAW;
  795.         else
  796.         return ok_val;
  797.     }
  798.  
  799.     CASE( "local" ) {
  800.         if (ARGTAIL == NULL) goto stx_err;
  801.  
  802.         cmd = argv(1);
  803.         if (!push_variable(cmd)) return ok_val;
  804.  
  805.         if (ARGTAIL && set_variable(cmd, 1, ARGTAIL))
  806.         return AC_REDRAW;
  807.         else
  808.         return ok_val;
  809.     }
  810.  
  811.     CASE( "set" ) {
  812.         if (ARGTAIL == NULL) {
  813.         disp_variables(0);
  814.         return AC_REDRAW;
  815.         }
  816.  
  817.         cmd = argv(1);    /* get ARGTAIL right */
  818.         if (cmd != NULL && strcmp(cmd, "all") == 0) {
  819.         disp_variables(1);
  820.         return AC_REDRAW;
  821.         }
  822.  
  823.         if (set_variable(cmd, 1, ARGTAIL))
  824.         return AC_REDRAW;
  825.         else
  826.         return ok_val;
  827.     }
  828.  
  829.     CASE( "toggle" ) {
  830.         if (argv(1) == NULL) goto stx_err;
  831.         toggle_variable(argv(1));
  832.         break;
  833.     }
  834.  
  835.     CASE( "define" ) {
  836.         if (in_init) {
  837.         if (argv(1) == NULL) {
  838.             init_message("macro number missing");
  839.             break;
  840.         }
  841.         m_define(argv(1), initf);
  842.         } else
  843.         if (m_define(argv(1), (FILE *)NULL))
  844.             return AC_REDRAW;
  845.  
  846.         break;
  847.     }
  848.  
  849.     CASE( "map" ) {
  850.         if (argv(2) == NULL) {
  851.         if (do_show("map", 1))
  852.             return AC_REDRAW;
  853.         break;
  854.         }
  855.  
  856.         if (do_map(initf))
  857.         return AC_REDRAW;
  858.         break;
  859.     }
  860.  
  861.     CASE( "cd" ) {
  862.         if (change_dir(argv(1), in_init))
  863.         init_message("chdir %s FAILED", argv(1));
  864.  
  865.         break;
  866.     }
  867.  
  868.     if (in_init) {
  869.  
  870.         CASE( "load" ) {
  871.         if (argv(1)) load_init_file(argv(1), (FILE **)NULL, 0);
  872.         break;
  873.         }
  874.  
  875.         CASE( "on" ) {
  876.         parse_on_to_end(initf);
  877.         break;
  878.         }
  879.  
  880.         CASE( "end" ) {
  881.         break;
  882.         }
  883.  
  884.         CASE( "sequence" ) {
  885.         return START_SEQUENCE;
  886.         }
  887.  
  888.         CASE( "save-files" ) {
  889.         parse_save_files(initf);
  890.         break;
  891.         }
  892.  
  893.         print_command("unknown command");
  894.         break;
  895.     }
  896.  
  897.     /*
  898.      * commands only available from : command line
  899.      */
  900.  
  901.     if (ok_val != AC_REDRAW) {
  902.         extern in_menu_mode;
  903.  
  904.         alt_cmd_key = lookup_command(sw_string,
  905.                  in_menu_mode ? K_ONLY_MENU : K_ONLY_MORE);
  906.         if (alt_cmd_key != K_INVALID && alt_cmd_key != K_HELP)
  907.         return AC_KEYCMD;
  908.     }
  909.  
  910.     CASE( "q" ) {
  911.         break;
  912.     }
  913.  
  914.     CASE( "Q" ) {
  915.         return AC_QUIT;
  916.     }
  917.  
  918.     CASE( "q!" ) {
  919.         if (restore_bak())
  920.         return AC_QUIT;
  921.         break;
  922.     }
  923.  
  924.     CASE( "x" ) {
  925.         update_rc_all(current_group, 0);
  926.         return AC_QUIT;
  927.     }
  928.  
  929.     CASE( "help" ) {
  930.         if (argv(1) == NULL)
  931.         display_help("help");
  932.         else
  933.         display_help(argv(1));
  934.         return AC_REDRAW;
  935.     }
  936.  
  937.     CASE( "man" ) {
  938.         char *manual;
  939.         group_header *orig_group;
  940.         int orig_layout, orig_fsort;
  941.         import int fmt_linenum, dont_sort_folders;
  942.  
  943.         manual = relative(help_directory, "Manual");
  944.         if (!file_exist(manual, "fr")) {
  945.         manual = relative(db_directory, "Manual");
  946.         if (!file_exist(manual, "fr")) {
  947.             msg("Online manual is not available");
  948.             break;
  949.         }
  950.         }
  951.         orig_group = current_group;
  952.         orig_layout = fmt_linenum;
  953.         orig_fsort = dont_sort_folders;
  954.  
  955.         fmt_linenum = -1;
  956.         dont_sort_folders = 1;
  957.  
  958.         folder_menu(manual);
  959.  
  960.         fmt_linenum = orig_layout;
  961.         dont_sort_folders = orig_fsort;
  962.         init_group(orig_group);
  963.  
  964.         return AC_REDRAW;
  965.     }
  966.  
  967.     CASE( "sort" ) {
  968.         if (argv(1) == NULL)
  969.         sort_articles(-1);
  970.         else if (ARG(1, "no") || ARG(1, "arrival"))
  971.         sort_articles(0);
  972.         else if ARG(1, "subject")
  973.         sort_articles(1);
  974.         else if ARG(1, "lexical")
  975.         sort_articles(2);
  976.         else if (ARG(1, "date") || ARG(1, "age"))
  977.         sort_articles(3);
  978.         else if (ARG(1, "sender") || ARG(1, "from"))
  979.         sort_articles(4);
  980.         else {
  981.         msg("Unknown sort mode '%s'", argv(1));
  982.         break;
  983.         }
  984.  
  985.         return AC_REORDER;
  986.     }
  987.  
  988.     CASE( "unread" ) {
  989.         group_header *gh;
  990.         int ix;
  991.         int32 restore_rc();
  992.  
  993.         if (argv(1) && (gh = lookup(argv(1))) != NULL)
  994.         ix = 2;
  995.         else {
  996.         ix = 1;
  997.         gh = current_group;
  998.         }
  999.  
  1000.         if (gh == current_group) return AC_REENTER_GROUP;
  1001.  
  1002.         if (argv(ix)) {
  1003.         if (!restore_rc(gh, gh->last_db_article - ARGVAL(ix)))
  1004.             break;
  1005.         } else
  1006.         if (!restore_unread(gh))
  1007.             break;
  1008.         break;
  1009.     }
  1010.  
  1011.     CASE( "dump" ) {
  1012.         if (do_show(argv(1), 2))
  1013.         return AC_REDRAW;
  1014.         break;
  1015.     }
  1016.  
  1017.     CASE( "show" ) {
  1018.         if (do_show(argv(1), 2))
  1019.         return AC_REDRAW;
  1020.         break;
  1021.     }
  1022.  
  1023.     CASE( "compile" ) {
  1024.         import int do_kill_handling;
  1025.  
  1026.         clrdisp();
  1027.         rm_kill_file();
  1028.         free_kill_entries();
  1029.         do_kill_handling = init_kill() && do_kill_handling;
  1030.         return AC_REDRAW;
  1031.     }
  1032.  
  1033.     CASE( "pwd" ) {
  1034.         FILE *p = popen("exec pwd", "r");
  1035.         char dir[FILENAME];
  1036.         if (p) {
  1037.         if (fgets(dir, FILENAME, p)) {
  1038.             dir[strlen(dir) - 1] = NUL;
  1039.             msg("%s", dir);
  1040.         }
  1041.         pclose(p);
  1042.         }
  1043.         break;
  1044.     }
  1045.  
  1046.     CASE( "rmail" ) {
  1047.         import char *mail_box;
  1048.         group_header *orig_group;
  1049.  
  1050.         if (mail_box == NULL) {
  1051.         msg("'mail' path not defined");
  1052.         break;
  1053.         }
  1054.  
  1055.         orig_group = current_group;
  1056.         folder_menu(mail_box);
  1057.         init_group(orig_group);
  1058.  
  1059.         return AC_REDRAW;
  1060.     }
  1061.  
  1062.     CASE( "mkdir" ) {
  1063.         char *dir, *run_mkdir();
  1064.         char name_buf[FILENAME];
  1065.  
  1066.         if (dir = run_mkdir(argv(1), name_buf)) {
  1067.         prompt("Change to %s", dir);
  1068.         if (yes(0)) change_dir(dir, 0);
  1069.         }
  1070.         break;
  1071.     }
  1072.  
  1073.     CASE( "sh" ) {
  1074.         suspend_nn();
  1075.         s_redraw = 0;
  1076.         return AC_REDRAW;
  1077.     }
  1078.  
  1079.     CASE( "admin" ) {
  1080.         group_header *cur_group;
  1081.  
  1082.         cur_group = current_group;
  1083.         no_raw();
  1084.         clrdisp();
  1085.         printf("\n\n\n\rADMINISTRATION MODE\r\n\n\n");
  1086.         admin_mode((char *)NULL);
  1087.         clrdisp();
  1088.         raw();
  1089.         init_group(cur_group);
  1090.         return AC_REDRAW;
  1091.     }
  1092.  
  1093.     CASE( "cost" ) {
  1094. #ifdef ACCOUNTING
  1095.         gotoxy(0, Lines-1); clrline();
  1096.         account('C', 1);
  1097. #else
  1098.         msg("No accounting");
  1099. #endif
  1100.         break;
  1101.     }
  1102.  
  1103.     CASE( "bug" ) {
  1104.         if (answer((article_header *)NULL, K_BUG_REPORT, 0))
  1105.         return AC_REDRAW;
  1106.         break;
  1107.     }
  1108.  
  1109.     CASE( "debug" ) {
  1110.         print_debug_info();
  1111.         return AC_REDRAW;
  1112.     }
  1113.  
  1114.     CASE( "coredump" ) {
  1115.         unset_raw();
  1116.         abort();
  1117.     }
  1118.  
  1119.     msg("unknown command: \"%s\"", argv(0));
  1120.      }
  1121.  
  1122.     return ok_val;
  1123.  
  1124.  stx_err:
  1125.     print_command("syntax error");
  1126.     return ok_val;
  1127. }
  1128.  
  1129.  
  1130. display_help(subject)
  1131. char *subject;
  1132. {
  1133.     char file[FILENAME];
  1134.  
  1135.     strcpy(file, "help.");
  1136.     strcpy(file+5, subject);
  1137.  
  1138.     display_file(file, CLEAR_DISPLAY | CONFIRMATION);
  1139. }
  1140.