/*
* (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
* Copyright (c) 1996-2005 Michael T Pins. All rights reserved.
*
* .nn/init file handling
*/
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
#include <ctype.h>
#include "config.h"
#include "global.h"
#include "articles.h"
#include "admin.h"
#include "answer.h"
#include "db.h"
#include "execute.h"
#include "folder.h"
#include "group.h"
#include "hostname.h"
#include "init.h"
#include "keymap.h"
#include "kill.h"
#include "macro.h"
#include "menu.h"
#include "newsrc.h"
#include "nn.h"
#include "printconf.h"
#include "save.h"
#include "sequence.h"
#include "sort.h"
#include "nn_term.h"
#include "variable.h"
#ifdef USE_MALLOC_H
#include <malloc.h>
#endif
/* init.c */
static char *strip_str(register char *cmd);
static int split_command(register char *cmd);
static char *argv(int i);
static int is_sequence(char *cmd);
static void load_init_file(char *name, FILE ** seq_hook_ptr, int only_seq);
static void print_debug_info(void);
static void print_command(char *str);
static int do_show(char *table, int mode_arg);
static int do_map(FILE * initf);
static void parse_on_to_end(FILE * f);
extern char *help_directory, *lib_directory;
int in_init = 0; /* true when parsing init file */
int alt_cmd_key; /* K_ when parse_command returns AC_KEYCMD */
long initial_memory_break; /* for :debug statistics */
int first_time_user = 0;
static int init_err = 0; /* errors in init file */
extern char *term_name;
extern FILE *loc_seq_hook, *glob_seq_hook;
extern int list_offset;
extern int in_menu_mode;
extern char *dflt_enter_macro;
/* extern char *dflt_exit_macro; */
extern int terminal_speed, slow_speed;
extern char *pname;
extern char *start_up_macro;
extern char *newsrc_file;
extern int in_menu_mode;
extern int do_kill_handling;
extern char printer[];
extern char *mail_box;
void
init_message(char *fmt,...)
{
va_list ap;
va_start(ap, fmt);
if (in_init) {
visual_off();
printf("init error: ");
vprintf(fmt, ap);
putchar(NL);
init_err++;
} else
vmsg(fmt, ap);
va_end(ap);
}
#define MAXARG 10
static char *argvec[MAXARG + 2];
static int argc;
static char *
strip_str(register char *cmd)
{
if (cmd == NULL)
return cmd;
while (*cmd && isascii(*cmd) && isspace(*cmd))
cmd++;
if (*cmd == NUL || *cmd == NL)
return NULL;
return cmd;
}
static int
split_command(register char *cmd)
{
/* split command string */
for (argc = 0; argc < MAXARG + 2; argc++)
argvec[argc] = NULL;
strip_more:
if ((cmd = strip_str(cmd)) == NULL || *cmd == '#')
return 0;
if (*cmd == ':') {
cmd++;
goto strip_more;
}
argc = 0;
argvec[0] = cmd;
return 1;
}
static char *
argv(int i)
{
register char *cmd;
if (i > MAXARG)
return NULL;
if (argc <= i) {
if (argvec[argc]) {
cmd = argvec[argc];
while (argc <= i) {
while (*cmd && (!isascii(*cmd) || !isspace(*cmd)))
cmd++;
if (*cmd == NUL) {
argc = MAXARG;
break;
}
*cmd++ = NUL;
if ((cmd = strip_str(cmd)) == NULL) {
argc = MAXARG;
break;
}
argvec[++argc] = cmd;
}
} else {
argc = MAXARG;
}
}
return argvec[i];
}
static int
is_sequence(char *cmd)
{
if (!split_command(cmd))
return 0;
if ((cmd = argv(0)) == NULL)
return 0;
return strcmp(cmd, "sequence") == 0;
}
#define START_SEQUENCE 555
#define CHAIN_FILE 556 /* chain file */
#define STOP_FILE 557 /* stop */
static void
load_init_file(char *name, FILE ** seq_hook_ptr, int only_seq)
{
FILE *init;
char cmdbuf[1024], *cmd, *term;
/* use cmdbuf temporarily (to handle @ expansion) */
for (cmd = cmdbuf; *name; name++)
if (*name == '@') {
term = term_name;
while (term && *term)
*cmd++ = *term++;
} else
*cmd++ = *name;
*cmd = NUL;
name = cmdbuf;
chain_file:
if (strchr(name, '/') == NULL)
name = relative(nn_directory, name);
init = open_file(name, OPEN_READ);
if (init == NULL)
return;
while (fgets_multi(cmdbuf, 1024, init)) {
if (only_seq) {
if (!is_sequence(cmdbuf))
continue;
*seq_hook_ptr = init;
return;
}
/* we use AC_REDRAW to avoid !-commands clear the screen */
switch (parse_command(cmdbuf, AC_REDRAW, init)) {
case CHAIN_FILE:
fclose(init);
name = argvec[argc]; /* ARGTAIL */
if (name == NULL)
return;
goto chain_file;
case STOP_FILE:
fclose(init);
return;
case START_SEQUENCE:
if (seq_hook_ptr) {
*seq_hook_ptr = init;
return; /* no close !! */
} else {
init_message("load file contains 'sequence'");
fclose(init);
return;
}
}
}
fclose(init);
}
static char dflt_init_files[] = ",init";
void
visit_init_file(int only_seq, char *first_arg)
{
char *next_arg;
in_init = 1;
load_init_file(relative(lib_directory, "setup"), (FILE **) NULL, 0);
in_init = 0;
if (first_arg && strncmp(first_arg, "-I", 2) == 0) {
if (first_arg[2] == NUL)
return;
first_arg += 2;
} else
first_arg = dflt_init_files;
in_init = 1;
while (first_arg) {
next_arg = strchr(first_arg, ',');
if (next_arg)
*next_arg++ = NUL;
if (*first_arg == NUL) {
if (glob_seq_hook == NULL)
load_init_file(relative(lib_directory, "init"), &glob_seq_hook, only_seq);
} else {
if (loc_seq_hook != NULL) {
fclose(loc_seq_hook);
loc_seq_hook = NULL;
}
load_init_file(first_arg, &loc_seq_hook, only_seq);
}
first_arg = next_arg;
}
if (init_err)
nn_exit(1);
in_init = 0;
}
/*
* parse a command (also :-commands)
*/
static char *sw_string;
static int sw_loop_once;
#define SWITCH(str) \
for (sw_string = str, sw_loop_once = 1; --sw_loop_once == 0; )
#define CASE(str) \
if (strcmp(sw_string, str) == 0)
#define ARG(i, str) (argv(i) && strcmp(argv(i), str) == 0)
#define ARGVAL(i) atol(argv(i))
#define ARGTAIL argvec[argc]
static struct alt_commands {
char *alt_name;
int alt_len;
int alt_type;
} alt_commands[] = {
"admin", 5, 0,
"bug", 3, 0,
"cd", 2, 1,
"compile", 7, 0,
"coredump", 8, 0,
"cost", 4, 0,
"decode", 6, 0,
"define", 6, 0,
"help", 4, 2,
"load", 4, 0,
"local", 5, 3,
"lock", 4, 3,
"make", 4, -1,
"make map ", 9, -2,
"man", 3, 0,
"map", 3, 4,
"mkdir", 5, 1,
"motd", 4, 0,
"patch", 5, 0, /* QUICK HACK */
"post", 4, 0, /* QUICK HACK */
"print", 5, -3, /* QUICK HACK */
"print-variables", 15, 0,
"pwd", 3, 0,
"rmail", 5, 0,
"set", 3, 3,
"show", 4, -1,
"show config", 11, 0,
"show groups", 11, -1,
"show groups all", 15, 0,
"show groups subscr", 18, 0,
"show groups total", 17, 0,
"show groups unsub", 17, 0,
"show kill", 9, 0,
"show map", 8, -1,
"show map #", 10, 0,
"show map key", 12, 0,
"show map menu", 13, 0,
"show map show", 13, 0,
"show rc ", 8, 0,
"sort", 4, -1,
"sort arrival", 12, 0,
"sort date", 9, 0,
"sort lexical", 12, 0,
"sort sender", 11, 0,
"sort subject", 12, 0,
"toggle", 6, 3,
"unread", 6, 0,
"unset", 5, 3,
"unshar", 6, 0, /* QUICK HACK */
NULL, 0, 0
};
int
alt_completion(char *buf, int index)
{
static char *head, *tail = NULL, buffer[FILENAME];
static int len;
static struct alt_commands *alt, *help_alt;
static fct_type other_compl;
int temp;
register char *p, *q;
if (other_compl) {
temp = CALL(other_compl) (buf, index);
if (index == 0 && temp == 1 && tail)
strcpy(tail, head);
if (index < 0 || (index == 0 && temp == 0)) {
other_compl = NULL;
list_offset = 0;
}
return temp;
}
if (index < 0)
return 0;
if (buf) {
if (index >= 1 && buf[0] == '!')
return -1; /* :! is special */
head = buf;
tail = buf + index;
alt = help_alt = alt_commands;
len = tail - head;
other_compl = NULL;
for (; alt->alt_name; alt++) {
if (len <= alt->alt_len)
continue;
if (head[alt->alt_len] != SP) {
if (alt->alt_type != -2)
continue;
if (strncmp(alt->alt_name, head, alt->alt_len))
continue;
return -1;
}
index = strncmp(alt->alt_name, head, alt->alt_len);
if (index < 0)
continue;
if (index > 0)
break;
if (alt->alt_type < 0) {
if (len > alt->alt_len)
continue;
break;
}
if (alt->alt_type == 0)
return -1; /* cannot be further compl */
head += alt->alt_len;
while (*head && *head == SP)
head++;
len = tail - head;
temp = -1;
switch (alt->alt_type) {
case 1:
other_compl = file_completion;
tail = NULL;
temp = file_completion(head, len);
break;
case 2:
other_compl = file_completion;
sprintf(buffer, "%s.%s",
relative(help_directory, "help"), head);
len = strlen(buffer);
head = buffer + len;
list_offset = 5;
temp = file_completion(buffer, len);
break;
case 3:
/* [set ]variable[ value] */
for (p = head; *p;)
if (*p++ == SP)
return -1;
other_compl = var_completion;
var_compl_opts((int) (tail - buf));
tail = NULL;
temp = var_completion(head, len);
break;
case 4:
/* [map XXX ]Y command[ N] */
if (*head == '#')
return -1;
for (p = head, temp = 0; *p;)
if (*p++ == SP) {
while (*p && *p == SP)
p++;
head = p;
temp++;
}
if (temp == 0)
other_compl = keymap_completion;
else if (temp == 2)
other_compl = cmd_completion;
else
return -1;
tail = NULL;
len = p - head;
temp = CALL(other_compl) (head, len);
break;
}
if (temp <= 0)
other_compl = NULL;
return temp;
}
alt = alt_commands;
return 1;
}
if (index) {
list_completion((char *) NULL);
if (help_alt->alt_name == NULL)
help_alt = alt_commands;
list_offset = 0;
if ((p = strrchr(head, ' ')))
list_offset = p - head;
while (help_alt->alt_name) {
if (len > help_alt->alt_len ||
(index = strncmp(help_alt->alt_name, head, len)) < 0) {
help_alt++;
continue;
}
if (index > 0) {
help_alt = alt_commands;
break;
}
p = help_alt->alt_name;
if (list_completion(p) == 0)
break;
temp = help_alt->alt_len;
if (help_alt->alt_type == -3) {
help_alt++;
continue;
}
do
help_alt++;
while (((q = help_alt->alt_name)) && help_alt->alt_len > temp &&
strncmp(p, q, temp) == 0);
}
fl;
list_offset = 0;
return 1;
}
for (; alt->alt_name; alt++) {
if (len == 0)
index = 0;
else
index = strncmp(alt->alt_name, head, len);
if (index < 0)
continue;
if (index > 0)
break;
p = alt->alt_name;
sprintf(tail, "%s%s", p + len, alt->alt_type <= -2 ? "" : " ");
temp = alt->alt_len;
if (alt->alt_type == -3) {
alt++;
return 1;
}
do
alt++;
while (((q = alt->alt_name)) && alt->alt_len > temp &&
strncmp(p, q, temp) == 0);
return 1;
}
cmd_completion(head, len);
if ((temp = cmd_completion((char *) NULL, 0))) {
other_compl = cmd_completion;
tail = NULL;
}
return temp;
}
static void
print_debug_info(void)
{
#ifdef USE_MALLOC_H
struct mallinfo mallinfo(), mi;
#endif
static long prev_mem = 0;
long cur_mem;
clrdisp();
tprintf("group=%s, nart=%ld\n\r", current_group->group_name, n_articles);
cur_mem = (((long) sbrk(0)) - initial_memory_break) / 1024;
tprintf("\nMemory usage: %ldk, previous: %ldk, change: %ldk\n\r",
cur_mem, prev_mem, cur_mem - prev_mem);
prev_mem = cur_mem;
#ifdef USE_MALLOC_H
mi = mallinfo();
tprintf("\nMalloc info. Total allocation: %d\n\r", mi.arena);
tprintf("Ordinary blocks: %d, space in use: %d, space free: %d\n\r",
mi.ordblks, mi.uordblks, mi.fordblks);
tprintf("Small blocks: %d, space in use: %d, space free: %d\n\r",
mi.smblks, mi.usmblks, mi.fsmblks);
tprintf("Holding blocks: %d, space in headers: %d\n\r",
mi.hblks, mi.hblkhd);
#endif
any_key(0);
}
static void
print_command(char *str)
{
char **av;
char buf[1024];
if (!in_init) {
msg(str);
return;
}
buf[0] = NUL;
for (av = argvec; *av; av++) {
strcat(buf, " ");
strcat(buf, *av);
}
init_message("%s: %s", str, buf);
}
static int
do_show(char *table, int mode_arg)
{
register group_header *gh;
int ret = 1;
if (in_init || table == NULL)
return 0;
no_raw();
SWITCH(table) {
CASE("config") {
clrdisp();
print_config(stdout);
any_key(0);
break;
}
CASE("kill") {
clrdisp();
dump_kill_list();
break;
}
CASE("groups") {
clrdisp();
if ARG
(mode_arg, "all")
group_overview(1);
else if ARG
(mode_arg, "total")
group_overview(2);
else if ARG
(mode_arg, "unsub")
group_overview(3);
else if ARG
(mode_arg, "subscr")
group_overview(4);
else if ARG
(mode_arg, "sequence")
group_overview(-1);
else
group_overview(0);
break;
}
CASE("map") {
char *name;
if ((name = argv(mode_arg)) == NULL)
name = in_menu_mode ? "menu" : "show";
if (name[0] == '#') {
clrdisp();
dump_multi_keys();
break;
}
SWITCH(name) {
CASE("key") {
clrdisp();
dump_global_map();
break;
}
if (dump_key_map(name) >= 0)
break;
init_message("unknown map '%s'", argv(mode_arg));
ret = 0;
/* break; goto err */
}
break;
}
CASE("rc") {
if (argv(2)) {
gh = lookup(argv(2));
if (gh == NULL) {
msg("Unknown: %s", argv(2));
break;
}
} else
gh = current_group;
if (gh->group_flag & G_FAKED)
break;
clrdisp();
tprintf("Available: %ld - %ld (unread %ld)\n\n\r",
(long) (gh->first_db_article), (long) (gh->last_db_article),
(long) (gh->unread_count));
tprintf(".newsrc:\n\r>%s\r<%s\n\rselect:\n\r>%s\r<%s\n\r",
gh->newsrc_line ? gh->newsrc_line : "(null)\n",
gh->newsrc_orig == gh->newsrc_line ? "(same)\n" :
gh->newsrc_orig ? gh->newsrc_orig : "(null)\n",
gh->select_line ? gh->select_line : "(null)\n",
gh->select_orig == gh->select_line ? "(same)\n" :
gh->select_orig ? gh->select_orig : "(null)\n");
any_key(0);
break;
}
init_message("unknown table '%s'", table);
ret = 0;
/* break; */
/* goto err; */
/* NOTREACHED */
}
nn_raw();
return ret;
/*
err:
nn_raw();
return 0;
*/
}
static int
do_map(FILE * initf)
{
int code, map_menu, map_show, must_redraw = 0;
key_type bind_to;
register struct key_map_def *map_def;
register int *map;
code = lookup_keymap(argv(1));
if (code < 0) {
print_command("unknown map");
goto out;
}
map_def = &keymaps[code];
if (map_def->km_flag & K_GLOBAL_KEY_MAP) {
if (argv(3) == NULL)
goto mac_err;
if (argv(2) == NULL) {
dump_global_map();
return 1;
}
global_key_map[parse_key(argv(2))] = parse_key(argv(3));
return 0;
}
if (map_def->km_flag & K_MULTI_KEY_MAP) {
key_type multi_buffer[16], *mb;
int i;
if (argv(1)[1] == NUL) {
dump_multi_keys();
return 1;
}
if (isdigit(argv(1)[1]))
bind_to = K_function(argv(1)[1] - '0');
else {
bind_to = parse_key(argv(1) + 1);
if (bind_to < K_up_arrow || bind_to > K_right_arrow)
goto mac_err;
}
for (i = 2, mb = multi_buffer; argv(i); i++)
*mb++ = parse_key(argv(i));
*mb = NUL;
enter_multi_key(bind_to, (key_type *) copy_str((char *) multi_buffer));
return 0;
}
code = K_UNBOUND;
map = map_def->km_map;
map_show = map_def->km_flag & K_BOTH_MAPS;
map_menu = map_def->km_flag & K_BIND_ORIG;
if (ARG(3, "(")) {
code = (int) m_define("-2", initf);
must_redraw = 1;
if (code == K_UNBOUND)
goto mac_err;
}
if (code == K_UNBOUND && argv(3))
code = lookup_command(argv(3), map_def->km_flag & (K_ONLY_MENU | K_ONLY_MORE));
switch (code) {
case K_INVALID - 1:
init_message("Cannot bind '%s' in '%s' map", argv(3), argv(1));
goto out;
case K_EQUAL_KEY:
if (argv(4) == NULL)
goto mac_err;
code = map[parse_key(argv(4))];
break;
case K_MACRO:
case K_ARTICLE_ID:
if (argv(4) == NULL)
goto mac_err;
code |= atoi(argv(4));
break;
case K_PREFIX_KEY:
if (argv(4) == NULL)
goto mac_err;
code = lookup_keymap(argv(4));
if (code < 0) {
print_command("unknown prefix map");
goto out;
}
code |= K_PREFIX_KEY;
break;
}
if (code == K_INVALID) {
init_message("unknown key command: %s", argv(3));
goto out;
}
bind_to = parse_key(argv(2));
if (map_menu) {
if (code & K_MACRO && orig_menu_map[bind_to] == 0)
orig_menu_map[bind_to] = map[bind_to];
}
map[bind_to] = code;
if (map_show)
more_key_map[bind_to] = code;
goto out;
mac_err:
print_command("map argument missing");
out:
return must_redraw;
}
static void
parse_on_to_end(FILE * f)
{
register char *cp;
char buf[1024];
static char *last_cmd_res = NULL;
int i;
int err_flag = 0;
if (ARGTAIL == NULL || *ARGTAIL == NUL)
goto on_err;
cp = NULL;
switch (*ARGTAIL) {
case '#': /* on #... end: skipped (+hack for else) */
goto skip_to_end;
case '`': /* on `shell command` str1 str2 ... */
{
FILE *p;
char *cmd = ARGTAIL + 1, *t;
if ((cp = strrchr(cmd, '`')) == NULL)
goto syntax_err;
if ((t = strip_str(cp + 1)) == NULL)
goto syntax_err;
*cp = NUL;
ARGTAIL = t;
if (cmd[0]) {
buf[0] = NUL;
if ((p = popen(cmd, "r"))) {
if (fgets(buf, 1024, p))
buf[strlen(buf) - 1] = NUL;
pclose(p);
}
if (last_cmd_res != NULL && strcmp(last_cmd_res, buf)) {
free(last_cmd_res);
last_cmd_res = NULL;
}
if (buf[0] == NUL)
goto skip_to_end;
last_cmd_res = copy_str(buf);
}
for (i = 1; argv(i) != NULL; i++)
if (strcmp(argv(i), last_cmd_res) == 0)
return;
}
goto skip_to_end;
case '$': /* on $VAR [ a b c ... ] */
cp = argv(1);
if ((cp = getenv(cp + 1)) == NULL)
goto skip_to_end;
if (ARGTAIL == NULL)
return;
for (i = 2; argv(i) != NULL; i++)
if (strcmp(argv(i), cp) == 0)
return;
goto skip_to_end;
case '!': /* on !shell-command */
cp = ARGTAIL + 1;
break;
case '[': /* on [ test ] */
cp = ARGTAIL + strlen(ARGTAIL) - 1;
if (*cp != ']')
goto syntax_err;
cp = ARGTAIL;
break;
default:
break;
}
if (cp) {
if (run_shell(cp, -2, 1) == 0)
return;
goto skip_to_end;
}
if (argv(1) == NULL)
goto on_err;
SWITCH(argv(1)) {
CASE("entry") {
group_header *gh;
char *macro;
int ii;
macro = parse_enter_macro(f, NL);
if (ARGTAIL) {
for (ii = 2; argv(ii); ii++) {
start_group_search(argv(ii));
while ((gh = get_group_search()))
gh->enter_macro = macro;
}
} else
dflt_enter_macro = macro;
return;
}
/* CASE( "exit" ) {
dflt_exit_macro = parse_enter_macro(f, NL);
return;
}
*/
CASE("slow") {
if (terminal_speed <= (slow_speed / 10))
return;
break;
}
CASE("fast") {
if (terminal_speed > (slow_speed / 10))
return;
break;
}
CASE("term") {
int ii;
for (ii = 2; argv(ii) != NULL; ii++)
if (strcmp(argv(ii), term_name) == 0)
return;
break;
}
CASE("host") {
char local_host[100];
int ii;
nn_gethostname(local_host, 100);
for (ii = 2; argv(ii) != NULL; ii++)
if (strcmp(argv(ii), local_host) == 0)
return;
break;
}
CASE("program") {
char *pname1;
int ii;
for (pname1 = pname; *pname1 == 'n'; pname1++);
for (ii = 2; argv(ii) != NULL; ii++) {
if (strcmp(argv(ii), pname) == 0)
return;
if (pname1[0] && strcmp(argv(ii), pname1) == 0)
return;
}
break;
}
CASE("start-up") {
start_up_macro = parse_enter_macro(f, NL);
return;
}
CASE("first-use") {
if (!first_time_user)
break;
if (argv(2) == NULL || ARG(2, "all"))
return;
if (newsrc_file == NULL) /* == code from visit_rc_file == */
newsrc_file = home_relative(".newsrc");
if (ARG(2, "old") && file_exist(newsrc_file, (char *) NULL))
return;
if (ARG(2, "new") && !file_exist(newsrc_file, (char *) NULL))
return;
break;
}
err_flag = 1;
/* goto on_err; */
}
if (err_flag == 1)
goto on_err;
skip_to_end:
while (fgets_multi(buf, 1024, f)) {
for (cp = buf; *cp && isascii(*cp) && isspace(*cp); cp++);
if (*cp != 'e')
continue;
if (strncmp(cp, "end", 3) == 0)
return;
if (strncmp(cp, "else", 4) == 0)
return;
}
init_message("end missing (on %s)", argv(1));
return;
on_err:
init_message("on `what'?");
return;
syntax_err:
init_message("syntax error: on %s", ARGTAIL);
}
int
parse_command(char *cmd, int ok_val, FILE * initf)
{
if (!split_command(cmd))
return ok_val;
if (*ARGTAIL == '!') {
if (ok_val == AC_UNCHANGED) { /* in macro */
if (ARGTAIL[1] == '!') /* !!cmd => guarantee no output! */
run_shell(ARGTAIL + 2, -2, 1);
else
run_shell(ARGTAIL + 1, -1, 1);
return ok_val;
}
if (run_shell(ARGTAIL + 1, ok_val == AC_PROMPT ? 1 : 0, in_init) >= 0) {
any_key(0);
return AC_REDRAW;
}
return ok_val;
}
SWITCH(argv(0)) {
CASE("unset") {
if (argv(1) == NULL)
goto stx_err;
if (set_variable(argv(1), 0, (char *) NULL))
return AC_REDRAW;
else
return ok_val;
}
CASE("local") {
if (ARGTAIL == NULL)
goto stx_err;
cmd = argv(1);
if (!push_variable(cmd))
return ok_val;
if (ARGTAIL && set_variable(cmd, 1, ARGTAIL))
return AC_REDRAW;
else
return ok_val;
}
CASE("set") {
if (ARGTAIL == NULL || ARGTAIL[0] == '/') {
disp_variables(0, ARGTAIL);
return AC_REDRAW;
}
cmd = argv(1); /* get ARGTAIL right */
if (cmd != NULL && strcmp(cmd, "all") == 0) {
disp_variables(1, (char *) NULL);
return AC_REDRAW;
}
if (set_variable(cmd, 1, ARGTAIL))
return AC_REDRAW;
else
return ok_val;
}
CASE("toggle") {
if (argv(1) == NULL)
goto stx_err;
toggle_variable(argv(1));
break;
}
CASE("lock") {
if (argv(1) == NULL)
goto stx_err;
lock_variable(argv(1));
break;
}
CASE("define") {
if (in_init) {
if (argv(1) == NULL) {
init_message("macro number missing");
break;
}
m_define(argv(1), initf);
} else if (m_define(argv(1), (FILE *) NULL))
return AC_REDRAW;
break;
}
CASE("map") {
if (argv(2) == NULL) {
if (do_show("map", 1))
return AC_REDRAW;
break;
}
if (do_map(initf))
return AC_REDRAW;
break;
}
CASE("make") {
if (ARG(1, "map") && argv(2)) {
switch (make_keymap(argv(2))) {
case -1:
init_message("map %s already exists", argv(2));
break;
case -2:
init_message("cannot make %s: too many maps", argv(2));
break;
}
break;
}
print_command("invalid make command");
break;
}
CASE("cd") {
if (change_dir(argv(1), in_init))
init_message("chdir %s FAILED", argv(1));
break;
}
CASE("clear") {
clrdisp();
break;
}
if (in_init) {
CASE("load") {
if (argv(1))
load_init_file(argv(1), (FILE **) NULL, 0);
break;
}
CASE("on") {
parse_on_to_end(initf);
break;
}
CASE("else") {
ARGTAIL = "#"; /* skip to end */
parse_on_to_end(initf);
break;
}
CASE("end") {
break;
}
CASE("echo") {
tprintf("\r%s\n\r", ARGTAIL);
break;
}
CASE("error") {
nn_exitmsg(1, "%s\n", ARGTAIL);
}
CASE("exit") {
nn_exit(ARGTAIL != NULL ? atoi(ARGTAIL) : 0);
}
CASE("chain") {
return CHAIN_FILE;
}
CASE("stop") {
return STOP_FILE;
}
CASE("sequence") {
return START_SEQUENCE;
}
CASE("save-files") {
parse_save_files(initf);
break;
}
print_command("unknown command");
break;
}
/*
* commands only available from : command line
*/
if (ok_val != AC_REDRAW) {
alt_cmd_key = lookup_command(sw_string,
in_menu_mode ? K_ONLY_MENU : K_ONLY_MORE);
if (alt_cmd_key > K_INVALID && alt_cmd_key != K_HELP) {
if (alt_cmd_key == K_MACRO) {
if (ARGTAIL == NULL)
break;
alt_cmd_key |= atoi(ARGTAIL);
}
return AC_KEYCMD;
}
}
CASE("load") {
clrdisp();
in_init = 1;
init_err = 0;
load_init_file(argv(1) ? argv(1) : "init", (FILE **) NULL, 0);
in_init = 0;
if (init_err)
any_key(0);
return AC_REDRAW;
}
CASE("q") {
break;
}
CASE("Q") {
return AC_QUIT;
}
CASE("q!") {
if (restore_bak())
return AC_QUIT;
break;
}
CASE("x") {
update_rc_all(current_group, 0);
return AC_QUIT;
}
CASE("help") {
if (argv(1) == NULL)
display_help("help");
else
display_help(argv(1));
return AC_REDRAW;
}
CASE("man") {
char *manual;
group_header *orig_group;
manual = relative(help_directory, "Manual");
if (!file_exist(manual, "fr")) {
manual = relative(lib_directory, "Manual");
if (!file_exist(manual, "fr")) {
msg("Online manual is not available");
break;
}
}
orig_group = current_group;
folder_menu(manual, 1);
init_group(orig_group);
return AC_REDRAW;
}
CASE("motd") {
if (display_motd(0))
return AC_REDRAW;
msg("no motd file");
break;
}
CASE("sort") {
if (argv(1) == NULL)
sort_articles(-1);
else if (ARG(1, "no") || ARG(1, "arrival"))
sort_articles(0);
else if ARG
(1, "subject")
sort_articles(1);
else if ARG
(1, "lexical")
sort_articles(2);
else if (ARG(1, "date") || ARG(1, "age"))
sort_articles(3);
else if (ARG(1, "sender") || ARG(1, "from"))
sort_articles(4);
else {
msg("Unknown sort mode '%s'", argv(1));
break;
}
return AC_REORDER;
}
CASE("unread") {
group_header *gh;
int ix;
if (argv(1) && (gh = lookup(argv(1))) != NULL)
ix = 2;
else {
ix = 1;
gh = current_group;
}
if (gh == current_group)
return AC_REENTER_GROUP;
if (argv(ix)) {
if (!restore_rc(gh, gh->last_db_article - (article_number) ARGVAL(ix)))
break;
} else if (!restore_unread(gh))
break;
break;
}
CASE("dump") {
if (do_show(argv(1), 2))
return AC_REDRAW;
break;
}
CASE("show") {
if (do_show(argv(1), 2))
return AC_REDRAW;
break;
}
CASE("compile") {
clrdisp();
rm_kill_file();
free_kill_entries();
do_kill_handling = init_kill() && do_kill_handling;
return AC_REDRAW;
}
CASE("print-variables") {
FILE *p;
if ((p = popen(ARGTAIL ? ARGTAIL : printer, "w"))) {
print_variable_config(p, 1);
pclose(p);
msg("Variables printed");
}
break;
}
CASE("pwd") {
FILE *p = popen("exec pwd", "r");
char dir[FILENAME];
if (p) {
if (fgets(dir, FILENAME, p)) {
dir[strlen(dir) - 1] = NUL;
msg("%s", dir);
}
pclose(p);
}
break;
}
CASE("rmail") {
group_header *orig_group;
int rv;
if (mail_box == NULL) {
msg("'mail' path not defined");
break;
}
orig_group = current_group;
rv = folder_menu(mail_box, 2);
init_group(orig_group);
return rv == ME_NO_REDRAW ? ok_val : AC_REDRAW;
}
CASE("mkdir") {
char *dir;
char name_buf[FILENAME];
if ((dir = run_mkdir(argv(1), name_buf))) {
prompt("Change to %s", dir);
if (yes(0))
change_dir(dir, 0);
}
break;
}
CASE("sh") {
suspend_nn();
s_redraw = 0;
return AC_REDRAW;
}
CASE("admin") {
group_header *cur_group;
cur_group = current_group;
no_raw();
clrdisp();
tprintf("\n\n\n\rADMINISTRATION MODE\r\n\n\n");
admin_mode((char *) NULL);
clrdisp();
nn_raw();
init_group(cur_group);
return AC_REDRAW;
}
CASE("cost") {
#ifdef ACCOUNTING
gotoxy(0, Lines - 1);
clrline();
account('C', 1);
#else
msg("No accounting");
#endif
break;
}
CASE("bug") {
if (answer((article_header *) NULL, K_BUG_REPORT, 0))
return AC_REDRAW;
break;
}
CASE("debug") {
print_debug_info();
return AC_REDRAW;
}
CASE("coredump") {
unset_raw();
abort();
}
msg("unknown command: \"%s\"", argv(0));
}
return ok_val;
stx_err:
print_command("syntax error");
return ok_val;
}
void
display_help(char *subject)
{
char file[FILENAME];
strcpy(file, "help.");
strcpy(file + 5, subject);
display_file(file, CLEAR_DISPLAY | CONFIRMATION);
}
syntax highlighted by Code2HTML, v. 0.9.1