/* ARISA - Admin Interface * Copyright (C) 2003, 2004 Carl Ritson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "arisa.h" #include "user.h" #include "admin.h" #include #include #include #include #include #include #include #include #include "admin-interface.h" /*** Global Variables ***/ menu_t *global_menu_root; menu_t *main_menu_root; /*** Menu Functions ***/ void free_menu(menu_t *m) { LOCK_FREE(&m->lock); if(m->name != NULL) xfree(m->name); if(m->type == ADMIN_MENU && m->ents != NULL) { int i; for(i = 0; i < m->no_ents; ++i) menu_deref(m->ents[i]); xfree(m->ents); } if(m->help != NULL) strarr_free(&m->help,&m->no_help); xfree(m); } menu_t *alloc_menu(enum menu_type_t type) { menu_t *m = xalloc(sizeof(menu_t)); LOCK_INIT(&m->lock); m->type = type; m->ref_count = 1; m->func = NULL; m->min_args = 0; m->max_args = 0; m->log = 0; m->hide = 0; m->privs = PRIVS_EMPTY; m->helper = NULL; m->help = NULL; m->no_help = 0; m->ents = NULL; m->no_ents = 0; return m; } void menu_ref(menu_t *m) { assert(m != NULL); LOCK(m); m->ref_count++; UNLOCK(m); } void menu_deref(menu_t *m) { int ref_count; assert(m != NULL); LOCK(m); m->ref_count--; ref_count = m->ref_count; UNLOCK(m); if(ref_count <= 0) free_menu(m); } void menu_add(menu_t *m, menu_t *ent) { menu_ref(ent); LOCK(m); PTRARR_ADD(&m->ents,&m->no_ents,ent); UNLOCK(m); } void menu_del(menu_t *m, menu_t *ent) { LOCK(m); PTRARR_DEL(&m->ents,&m->no_ents,ent); UNLOCK(m); menu_deref(ent); } /* some pre-declarations for menu_resolv */ static instance_t *alloc_instance(instance_t *orig, const char *prompt, menu_t *menu); static void free_instance(instance_t *instance); static menu_t **find_cmds(instance_t *ins, const char *prefix, int len, unsigned long privs, int *no_cmds, int use_hide, int fbg); menu_t *menu_resolv(const char *path) { instance_t *ins = alloc_instance(NULL,NULL,main_menu_root); int i,ppos = 0,npos = 0,no_cmds = 0; menu_t *cmd = NULL,**cmds; ins->gmenu = global_menu_root; if(path[ppos] != '\0' && path[ppos] == '/') ppos++; do { npos = ppos; while(path[npos] != '\0' && path[npos] != '/') npos++; cmd = NULL; cmds = find_cmds(ins,path+ppos,(npos-ppos), PRIVS_FULL,&no_cmds,0,1); if(no_cmds == 1) { cmd = cmds[0]; xfree(cmds); } else if(no_cmds > 1) { for(i = 0; i < no_cmds && cmd == NULL; ++i) { if(strlen(cmds[i]->name) == (npos-ppos)) cmd = cmds[i]; else menu_deref(cmds[i]); } xfree(cmds); } else break; if(path[npos] == '/' && cmd->type != ADMIN_MENU) { menu_deref(cmd); cmd = NULL; break; } else if(path[npos] == '\0') { break; } else { menu_deref(ins->lmenu); ins->lmenu = cmd; } if(path[npos] != '\0') ppos = npos+1; else ppos = npos; } while(path[ppos] != '\0'); free_instance(ins); return cmd; } menu_t *menu_from_cmds(const char *name, int min_args, int max_args, int log, int hide, uint32_t privs, int (*func)(instance_t *,acontext_t *,menu_t*,char **,int), void (*helper)(instance_t *,acontext_t *,char **,int), cmd_t *cmds) { menu_t *ent,*m = alloc_menu(ADMIN_MENU); int i; m->name = xstrdup(name); m->min_args = min_args; m->max_args = max_args; m->log = log; m->hide = hide; m->privs = privs; m->func = func; m->helper = helper; for(i = 0; cmds[i].name != NULL; ++i) { ent = alloc_menu(ADMIN_COMMAND); ent->name = xstrdup(cmds[i].name); ent->min_args = cmds[i].min_args; ent->max_args = cmds[i].max_args; ent->log = cmds[i].log; ent->hide = cmds[i].hide; ent->privs = cmds[i].privs; ent->func = cmds[i].func; ent->helper = cmds[i].helper; PTRARR_ADD(&m->ents,&m->no_ents,ent); } return m; } /*** Instance Functions ***/ /** alloc_instance * Initialises a new instance_t, orig should be the level below. */ static instance_t *alloc_instance(instance_t *orig, const char *prompt, menu_t *menu) { instance_t *i = xalloc(sizeof(instance_t)); if(prompt != NULL) { i->prompt = xstrdup(prompt); i->free_prompt = 1; } else { i->prompt = NULL; i->free_prompt = 0; } if(orig != NULL) { i->gmenu = orig->gmenu; i->prev = orig; } else { i->gmenu = NULL; i->prev = NULL; } i->lmenu = menu; if(menu != NULL) menu_ref(i->lmenu); i->data = NULL; i->check= NULL; i->free = NULL; return i; } /** free_instance * Deallocates an instance_t and associated data. */ static void free_instance(instance_t *i) { if(i->lmenu != NULL) menu_deref(i->lmenu); if(i->prompt != NULL && i->free_prompt) xfree(i->prompt); if(i->free != NULL && i->data != NULL) i->free(i->data); xfree(i); } /** free_instances * Deallocates an instance_t and all instances below it. */ static void free_instances(instance_t *i) { instance_t *p; while(i != NULL) { p = i->prev; free_instance(i); i = p; } } /*** Party Line ***/ /** admin_party_line_msg * Sends msg to the bots party line, excluding pqueue_t *ex. * The *ex argument is generally used to exclude the sender. */ void admin_party_line_msg(const char *msg, pqueue_t *ex) { char buffer[512]; int i; snprintf(buffer,sizeof(buffer),"%sPL%s %s", COLOUR_BOLD,COLOUR_BOLD,msg); LOCKR(&(global->party_line.lock)); for(i = 0; i < global->party_line.no_subs; ++i) { if(global->party_line.subs[i] != ex) pqueue_push_back(global->party_line.subs[i], xstrdup(buffer)); } UNLOCKR(&(global->party_line.lock)); } /** admin_party_line_subscribe * Attaches the message queue for an admin session to the party line, * and annouces that fact to the others on it. */ void admin_party_line_subscribe(acontext_t *ac) { char buffer[64]; LOCKR(&(global->party_line.lock)); PTRARR_ADD(&(global->party_line.subs),&(global->party_line.no_subs), ac->msgqueue); UNLOCKR(&(global->party_line.lock)); if(ac->user != NULL) { LOCK(ac->user); snprintf(buffer,sizeof(buffer),"%s joined", ac->user->username); UNLOCK(ac->user); admin_party_line_msg(buffer,NULL); } } /** admin_party_line_unsubscribe * Removes the message queue for an admin session from the party line, * and annouces the users departure to others on it. */ void admin_party_line_unsubscribe(acontext_t *ac) { char buffer[64]; if(ac->user != NULL) { LOCK(ac->user); snprintf(buffer,sizeof(buffer),"%s left", ac->user->username); UNLOCK(ac->user); admin_party_line_msg(buffer,NULL); } LOCKR(&(global->party_line.lock)); PTRARR_DEL(&(global->party_line.subs),&(global->party_line.no_subs), ac->msgqueue); UNLOCKR(&(global->party_line.lock)); } /******************* * Admin Interface * *******************/ /** _admin_msg * Internal handler for admin_msg and admin_cmsg. * Adds a formatted message to the mesage queue of an script context. */ static void _admin_msg(acontext_t *ac, int colour, const char *format, va_list va) { if(ac->msgqueue != NULL) { char buffer[512]; vsnprintf(buffer,sizeof(buffer),format,va); if(!colour) { char cbuffer[512]; quote_colours(cbuffer,sizeof(cbuffer),buffer); pqueue_push_back(ac->msgqueue,xstrdup(cbuffer)); } else pqueue_push_back(ac->msgqueue,xstrdup(buffer)); } } void admin_msg(acontext_t *ac, const char *format, ...) { va_list va; va_start(va,format); _admin_msg(ac,0,format,va); va_end(va); } void admin_cmsg(acontext_t *ac, const char *format, ...) { va_list va; va_start(va,format); _admin_msg(ac,1,format,va); va_end(va); } /** cmd_strarr * Generic command for manipulating arrays of strings, * used in many places in the menu system to reduce code duplication. */ static int cmd_strarr(acontext_t *ac, char ***strs, int *no_strs, char **args, int no_args) { char *tmp; int i,j,k; if(no_args < 2) { for(i = 0; i < *no_strs; ++i) admin_msg(ac,"%2d: %s",i+1,(*strs)[i]); return 0; } if(tolower(args[1][0]) == 'a') { if(no_args >= 3) PTRARR_ADD(strs,no_strs,xstrdup(args[2])); else { admin_msg(ac,"%s add ",args[0]); } } else if(tolower(args[1][0]) == 'd') { if(no_args >= 3) { i = atoi(args[2]); if(i >= 1 && i <= *no_strs) { xfree((*strs)[i-1]); PTRARR_DEL(strs,no_strs,(*strs)[i-1]); } else { admin_msg(ac,"Invalid Number: %d",i); return RET_INV_ARG; } } else { admin_msg(ac,"%s del ",args[0]); } } else if(tolower(args[1][0]) == 'w') { strarr_free(strs,no_strs); } else if(tolower(args[1][0]) == 'm' || strncasecmp(args[1],"sw",2) == 0) { if(no_args >= 4) { i = atoi(args[2]); j = atoi(args[3]); if(i < 1 || i > *no_strs) { admin_msg(ac,"Invalid Number: %d",i); } else if(j < 1 || j > *no_strs) { admin_msg(ac,"Invalid Number: %d",j); } else if(i != j) { if(tolower(args[1][0]) == 'm') { // move tmp = (*strs)[i-1]; if(j < i) { for(k = i-1; k > (j-1); --k) (*strs)[k] = (*strs)[k-1]; } else { for(k = i-1; k < (j-1); ++j) (*strs)[k] = (*strs)[k+1]; } (*strs)[j-1] = tmp; } else { // swap tmp = (*strs)[j-1]; (*strs)[j-1] = (*strs)[i-1]; (*strs)[i-1] = tmp; } } } else { admin_msg(ac,"%s %s ",args[0],args[1]); return RET_ISF_ARG; } } else if(strncasecmp(args[1],"se",2) == 0) { if(no_args >= 4) { i = atoi(args[2]); if(i < 1 || i > *no_strs) { admin_msg(ac,"Invalid Number: %d",i); return RET_INV_ARG; } else { if((*strs)[i-1] != NULL) xfree((*strs)[i-1]); (*strs)[i-1] = xstrdup(args[3]); } } else { admin_msg(ac,"%s set ",args[0]); return RET_ISF_ARG; } } else { admin_msg(ac,"%s [add|del|move|set|swap|wipe]",args[0]); return RET_ISF_ARG; } return 0; } static int cmd_access_list(acontext_t *ac, access_t *acc, char *title, char **args, int no_args) { int i,j,ret = 0; if(no_args == 1 && acc == NULL) { admin_msg(ac,"-- Access List for %s --",title); admin_msg(ac,"Empty"); } else if(no_args == 1) { char netname[13],channame[21],mode[6]; LOCK(acc); admin_msg(ac,"-- Access List for %s --",title); admin_msg(ac,"Mode: %s", (acc->flags & ACCESS_SMART) == ACCESS_SMART ? "Smart" : (acc->flags & ACCESS_ALLOW ? "Allow, Deny" : "Deny, Allow")); admin_msg(ac,"%-2s %-8s %-12s %-20s %-5s %s", "No","Type","Network","Channel","Mode","Host"); for(i = 0; i < acc->no_entries; ++i) { if(acc->entries[i]->network != NULL) { LOCK(acc->entries[i]->network); xstrncpy(netname,acc->entries[i]->network->name, sizeof(netname)); UNLOCK(acc->entries[i]->network); } else xstrncpy(netname,"",sizeof(netname)); if(acc->entries[i]->channel != NULL) { LOCK(acc->entries[i]->channel); xstrncpy(channame, acc->entries[i]->channel->name, sizeof(channame)); UNLOCK(acc->entries[i]->channel); } else xstrncpy(channame,"",sizeof(channame)); if(acc->entries[i]->mode != 0) { j = 0; if(acc->entries[i]->mode & MODE_OP) mode[j++] = 'o'; if(acc->entries[i]->mode & MODE_VOICE) mode[j++] = 'v'; if(acc->entries[i]->mode & MODE_HOP) mode[j++] = 'h'; mode[j] = '\0'; } else xstrncpy(mode,"",sizeof(mode)); admin_msg(ac,"% -2d %-8s %-12s %-20s %-5s %s", i+1, acc->entries[i]->flags & ACCESS_ALLOW ? "ALLOW" : "DENY", netname,channame,mode, acc->entries[i]->host != NULL ? acc->entries[i]->host : ""); } if(i == 0) admin_msg(ac,"Empty"); UNLOCK(acc); } else if(tolower(args[1][0]) == 'a' || tolower(args[1][0]) == 'd') { // allow || deny if(no_args >= 4) { network_t *net = NULL; channel_t *chan = NULL; char *host = NULL; int mode = MODE_REG; int err = 0; for(i = 2; i < no_args && !err;) { if(strncasecmp(args[i],"-n",2) == 0 && (i+1) < no_args) { // network if(chan == NULL) { net = irc_network_find( args[i+1]); if(net == NULL) err = i; } i += 2; } else if(strncasecmp(args[i],"-c",2) == 0 && (i+2) < no_args) { // channel net = irc_network_find(args[i+1]); if(net != NULL) { chan = irc_channel_find(net, args[i+2]); if(chan == NULL) err = i; } else err = i; i += 3; } else if(strncasecmp(args[i],"-h",2) == 0 && (i+1) < no_args) { host = args[i+1]; i += 2; } else if(strncasecmp(args[i],"-m",2) == 0 && (i+1) < no_args) { for(j = 0; args[i+1][j] != '\0'; ++j) { switch(tolower(args[i+1][j])) { case 'o': mode |= MODE_OP; break; case 'v': mode |= MODE_VOICE; break; case 'h': mode |= MODE_HOP; break; default: err = i; break; } } i += 2; } else { err = i; i++; } } if(err != 0) { admin_msg(ac,"Error with argument or parameters for: %s",args[err]); ret = RET_INV_ARG; } else { access_add_entry(acc, tolower(args[1][0]) == 'a' ? ACCESS_ALLOW : ACCESS_DENY, net,host,chan,mode); } } else { admin_msg(ac,"%s %s [-net ] [-channel ] [-host ] [-mode ]",args[0],args[1]); ret = RET_ISF_ARG; } } else if(tolower(args[1][0]) == 'c') { // clone if(no_args >= 3) { packlist_t *list = packlist_find(args[2]); access_t *oacc; if(list != NULL) { LOCK(list); oacc = list->access; UNLOCK(list); access_copy(acc,oacc); } else { admin_msg(ac,"Unknown packlist: %s",args[2]); ret = RET_INV_ARG; } } else { admin_msg(ac,"%s %s ",args[0],args[1]); ret = RET_ISF_ARG; } } else if(tolower(args[1][0]) == 'm') { // mode if(no_args >= 3) { LOCK(acc); switch (tolower(args[2][0])) { case 'a': acc->flags = ACCESS_ALLOW; break; case 'd': acc->flags = ACCESS_DENY; break; case 's': acc->flags = ACCESS_SMART; break; } UNLOCK(acc); } else { admin_msg(ac,"%s %s [Allow,Deny|Deny,Allow,Smart]", args[0],args[1]); ret = RET_ISF_ARG; } } else if(tolower(args[1][0]) == 'r') { // remove if(no_args >= 3) { int no = atoi(args[2]) - 1; if(access_del_entry_no(acc,no) != 0) { admin_msg(ac,"Unable to remove entry %s", args[2]); ret = RET_INV_ARG; } } else { admin_msg(ac,"%s %s ",args[0],args[1]); ret = RET_ISF_ARG; } } else { admin_msg(ac,"%s [allow|clone|deny|mode|remove]",args[0]); ret = RET_ISF_ARG; } return ret; } static void output_settings(acontext_t *ac, const char *title, const char *var, pqueue_t *settings) { char buffer[400]; value_t *v; if(title != NULL) admin_msg(ac,title,var); while((v = pqueue_pop_front(settings)) != NULL) { char *str = value_as_string(v, VALUE_ALLOW_NULL | VALUE_NICE_FLOATS, buffer,sizeof(buffer),NULL); admin_msg(ac,"%s: %s",v->name,str != NULL ? str : "Not Set"); xfree(v); } } static menu_t **find_cmds(instance_t *ins, const char *prefix, int len, unsigned long privs, int *no_cmds, int use_hide, int fbg) { menu_t *cmd,**cmds = NULL; int i; *no_cmds = 0; if(ins->lmenu != NULL) { LOCK(ins->lmenu); for(i = 0; i < ins->lmenu->no_ents; ++i) { cmd = ins->lmenu->ents[i]; if((strncmp(cmd->name,prefix,len) == 0 || len == 0) && PRIV_M_ISSET(privs,cmd->privs) && (!cmd->hide || !use_hide)) { PTRARR_ADD(&cmds,no_cmds,cmd); menu_ref(cmd); } } UNLOCK(ins->lmenu); } if((*no_cmds == 0 || !fbg) && ins->gmenu != NULL) { LOCK(ins->gmenu); for(i = 0; i < ins->gmenu->no_ents; ++i) { cmd = ins->gmenu->ents[i]; if((strncmp(cmd->name,prefix,len) == 0 || len == 0) && PRIV_M_ISSET(privs,cmd->privs) && (!cmd->hide || !use_hide)) { PTRARR_ADD(&cmds,no_cmds,cmd); menu_ref(cmd); } } UNLOCK(ins->gmenu); } return cmds; } /*** Global Menu ***/ #include "admin/global_menu.c" /*** Channel Menu ***/ #include "admin/channel_menu.c" /*** Network Menu ***/ #include "admin/network_menu.c" /*** Pool Menu ***/ #include "admin/pool_menu.c" /*** Interface Menu ***/ #include "admin/interface_menu.c" /*** Queue Menu ***/ #include "admin/queue_menu.c" /*** Packlist Menu ***/ #include "admin/packlist_menu.c" /*** Settings Menu ***/ #include "admin/settings_menu.c" /*** User(s) Menu ***/ #include "admin/user_menu.c" /*** Files Menu ***/ #include "admin/files_menu.c" /*** Scripting Menu ***/ #include "admin/scripting_menu.c" /*** Main Menu ***/ #include "admin/main_menu.c" /*** Help for all Menus ***/ #include "admin/help.c" /** qsort_strcmp * Linkage to strcmp for use with qsort. */ static int qsort_strcmp(const void *a, const void *b) { return strcmp(*((char **)a),*((char **)b)); } /** qsort_cmdcmp * For qsort to sort commands by name. */ static int qsort_cmdcmp(const void *a, const void *b) { return strcmp((*((menu_t **)a))->name,(*((menu_t **)b))->name); } /** build_prompt * Constructs a full prompt string from the prompts of all the instances. */ static void build_prompt(acontext_t *ac, char *buffer, size_t bufsize) { instance_t *i,*p; char c; int j = 0,k; /* 10 points if you figure out how it does its stuff ^_~ */ buffer[j++] = ']'; //buffer[j++] = '>'; i = (instance_t *)ac->instance; do { p = i->prev; if(i->prompt != NULL && j < (bufsize-4)) { for(k = strlen(i->prompt); j < (bufsize-5) && k > 0; --k) buffer[j++] = i->prompt[k-1]; buffer[j++] = '/'; } i = p; } while(i != NULL); if(((instance_t *)ac->instance)->prev == NULL) // i.e. root buffer[j++] = '/'; buffer[j++] = '['; buffer[j] = '\0'; for(j = 0, k = strlen(buffer)-1; k > j; ++j,--k) { c = buffer[j]; buffer[j] = buffer[k]; buffer[k] = c; } } /** admin_output_prompt * Builds prompt and places it on the message queue of a session. */ void admin_output_prompt(acontext_t *ac) { char buffer[512]; build_prompt(ac,buffer,sizeof(buffer)); admin_msg(ac,"%s",buffer); } static void run_cmd(acontext_t *ac, menu_t *cmd, char **args, int no_args, const char *logmsg) { instance_t *ins = ac->instance; int ret_val = RET_OK; if(cmd->log != 0) { LOCK(ac->user); LOGP(L_ADM,"%s %s", ac->user->username,logmsg); UNLOCK(ac->user); } if(cmd->type == ADMIN_COMMAND) { ret_val = cmd->func(ins,ac,cmd,args,no_args); if(ret_val == RET_UP && ins->prev != NULL) { // request going up a level ac->instance = ins->prev; free_instance(ins); ins = ac->instance; admin_output_prompt(ac); } else if(ret_val == RET_RTN) { // request to return to root instance_t *p; while(ins->prev != NULL) { p = ins->prev; free_instance(ins); ins = p; } ac->instance = ins; admin_output_prompt(ac); } else if(ret_val == RET_QIT) { ac->complete = 1; } } else if(cmd->type == ADMIN_MENU) { instance_t *nins = alloc_instance(ins,cmd->name,cmd); if(cmd->func != NULL) ret_val = cmd->func(nins,ac,cmd,args,no_args); if(ret_val == RET_OK) { ac->instance = nins; admin_output_prompt(ac); } else free_instance(nins); } if(ac->verbose) { if(ret_val == RET_OK) admin_msg(ac,"OK"); else admin_msg(ac,"ERR (%d)",ret_val); } } /** admin_process_cmd * Determines what command if any to execute, splits arguments, * calls function or helper and logs execution. */ void admin_process_cmd(acontext_t *ac, char *buffer, size_t bufsize) { instance_t *ins = (instance_t *)ac->instance; menu_t * cmd = NULL,**cmds = NULL; unsigned long privs; char logbuf[1024]; char **args = NULL; char c; int no_cmds,no_args; int i,len; if(buffer[0] == '\0') return; LOCK(ac->user); privs = ac->user->uprivs; UNLOCK(ac->user); for(i = 0; buffer[i] != '\0'; ++i) { if(buffer[i] == ' ' || buffer[i] == '?') break; } if(buffer[i] == '?') { /* ? character in the command itself, prompt user with * possibilities. */ len = i; cmds = find_cmds(ins,buffer,i,privs,&no_cmds,1,0); if(no_cmds > 0) { if(no_cmds > 1) qsort(cmds,no_cmds,sizeof(char *),qsort_cmdcmp); for(i = 0; i < no_cmds; ++i) admin_msg(ac,"%s",cmds[i]->name); } if(ac->verbose) // FIXME: remove me? admin_msg(ac,"OK"); } else { len = i; c = buffer[len]; buffer[len] = '\0'; cmds = find_cmds(ins,buffer,len,privs,&no_cmds,0,1); if(no_cmds == 1) cmd = cmds[0]; else if(no_cmds > 1) { for(i = 0; i < no_cmds && cmd == NULL; ++i) { if(strcmp(cmds[i]->name,buffer) == 0) cmd = cmds[i]; } } buffer[len] = c; if(cmd != NULL) { if(cmd->max_args > 1) no_args = cmd->max_args + 2; else if(cmd->max_args == 0) no_args = 2; else if(cmd->max_args == -2) no_args = cmd->min_args + 1; else no_args = 0; if(cmd->log != 0) { char pbuf[512]; build_prompt(ac,pbuf,sizeof(pbuf)); snprintf(logbuf,sizeof(logbuf),"%s \"%s\"", pbuf,buffer); } args = split_opt(buffer,buffer,&no_args); if(cmd->max_args >= 0 && no_args > cmd->max_args+1) { admin_msg(ac,"Too many parameters for command: %s",cmd->name); if(ac->verbose) // XXX admin_msg(ac,"ERR (%d)",RET_EXS_ARG); } else if(cmd->helper != NULL && (args[no_args-1][0] == '?' || args[no_args-1][strlen(args[no_args-1])-1] == '?')) { cmd->helper(ins,ac,args,no_args); if(ac->verbose) // XXX admin_msg(ac,"OK"); } else if((no_args-1) < cmd->min_args) { admin_msg(ac,"Too few parameters for command: %s",cmd->name); if(ac->verbose) // XXX admin_msg(ac,"ERR (%d)",RET_ISF_ARG); } else run_cmd(ac,cmd,args,no_args,logbuf); } else { admin_msg(ac,"Unknown Command"); if(ac->verbose) admin_msg(ac,"ERR (%d)",RET_INV_CMD); } } if(cmds != NULL) { for(i = 0; i < no_cmds; ++i) menu_deref(cmds[i]); xfree(cmds); } if(args != NULL) xfree(args); } /** admin_context_check * Executes the check functions defined in all the levels of the * instance tree of the context. If one returns -1 then the tree * above and including that instance is freed, and the user prompt * re-issued. Example: * "A -> B -> C", if B returns -1, B and C are free'd and the new * prompt is A. */ void admin_context_check(acontext_t *ac, time_t now) { instance_t *i,*p,*pp; i = (instance_t *)ac->instance; pp = i; do { p = i->prev; if(i->check != NULL) { if(i->check(i,ac,now) == -1) { i->prev = NULL; if(pp != NULL && pp != i) free_instances(pp); else free_instance(i); pp = p; } } i = p; } while(i != NULL); if(pp != (instance_t *)ac->instance) { ac->instance = pp; admin_output_prompt(ac); } } acontext_t *admin_new_context(pqueue_t *msgqueue) { acontext_t *ac = xalloc(sizeof(acontext_t)); ac->verbose = 0; ac->complete = 0; ac->last_ret = 0; ac->user = NULL; ac->msgqueue = msgqueue; ac->instance = alloc_instance(NULL,NULL,main_menu_root); ((instance_t *)(ac->instance))->gmenu = global_menu_root; ac->colour = COLOUR_NONE; return ac; } void admin_free_context(acontext_t *ac) { if(ac->instance != NULL) free_instances(ac->instance); xfree(ac); } int admin_context_complete(acontext_t *ac) { if(ac->complete != 0 || ac->instance == NULL) return 1; else return 0; } void admin_global_init(void) { global_menu_root = menu_from_cmds("global", 0,0,0,0,PRIVS_EMPTY,NULL,NULL,(cmd_t *)global_menu); main_menu_root = menu_from_cmds("", 0,0,0,0,PRIVS_EMPTY,NULL,NULL,(cmd_t *)main_menu); register_network_menu(); // includes channel register_interface_menu(); // includes pool register_files_menu(); register_packlist_menu(); register_queue_menu(); register_users_menu(); // includes self menu register_settings_menu(); register_scripting_menu(); admin_load_static_help(); } void admin_global_free(void) { menu_deref(global_menu_root); menu_deref(main_menu_root); }