/* ARISA - Admin Interface - Global Menu * Copyright (C) 2003 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 */ /** Global Menu Commands **/ MENU_CMD(cmd_quit) { return RET_QIT; } MENU_CMD(cmd_exit) { if(ins->prev == NULL) return CHAIN_CMD(cmd_quit); else return RET_UP; } MENU_CMD(cmd_log) { if(strcmp(args[1],"on") == 0) log_subscribe(ac->msgqueue); else if(strcmp(args[1],"off") == 0) log_unsubscribe(ac->msgqueue); else { LOCK(ac->user); LOG("<%s>: %s",ac->user->username,args[1]); UNLOCK(ac->user); } return 0; } MENU_CMD(cmd_prompt) { admin_output_prompt(ac); return 0; } MENU_CMD(cmd_gotoroot) { return RET_RTN; } MENU_CMD(cmd_date) { char buffer[32]; admin_msg(ac,"%s",timestr(xtime(),buffer,sizeof(buffer))); return 0; } MENU_CMD(cmd_colour) { if(strcasecmp(args[1],"none") == 0) ac->colour = COLOUR_NONE; else if(strcasecmp(args[1],"irc") == 0) ac->colour = COLOUR_IRC; else if(strcasecmp(args[1],"int") == 0) ac->colour = COLOUR_INT; else { admin_msg(ac,"Invalid colour type: %s",args[1]); RET_VAL(RET_INV_ARG); } return 0; } MENU_CMD(cmd_pljp) { int i,found; LOCKR(&(global->party_line.lock)); for(i = 0, found = 0; i < global->party_line.no_subs && !found; ++i) { if(global->party_line.subs[i] == ac->msgqueue) found = 1; } UNLOCKR(&(global->party_line.lock)); if(found) admin_party_line_unsubscribe(ac); else admin_party_line_subscribe(ac); return 0; } MENU_CMD(cmd_plmsg) { char buffer[510]; LOCK(ac->user); snprintf(buffer,sizeof(buffer),"<%s> %s",ac->user->username,args[1]); UNLOCK(ac->user); admin_party_line_msg(buffer,ac->msgqueue); return 0; } MENU_CMD(cmd_msg) { char buffer[510]; user_t *u; int i,j; u = user_find(args[1]); if(u != NULL) { LOCK(ac->user); snprintf(buffer,sizeof(buffer),"%sPM%s <%s> %s", COLOUR_BOLD,COLOUR_BOLD, ac->user->username,args[2]); UNLOCK(ac->user); LOCK(global); for(i = 0, j = 0; i < global->no_admins; ++i) { LOCK(global->admins[i]); if(global->admins[i]->admin.user == u) { pqueue_push_back(&global->admins[i]->msgqueue,xstrdup(buffer)); j++; } UNLOCK(global->admins[i]); } UNLOCK(global); if(j == 0) { admin_msg(ac,"User %s, not logged on.",args[1]); RET_VAL(RET_EXE_ERR); } } else { admin_msg(ac,"Invalid User: %s",args[1]); RET_VAL(RET_INV_ARG); } return 0; } static const char *send_state_text(state_t s); // pre-declaration MENU_CMD(cmd_whoison) { char username[64],buffer[32]; int i,j; user_t *u; LOCK(global); for(i = 0; i < global->no_admins; ++i) { LOCK(global->admins[i]); if(global->admins[i]->state == STATE_COMPLETE) { UNLOCK(global->admins[i]); continue; } if(global->admins[i]->admin.user != NULL) { /* This lock bounce is okay since we have the * global lock. */ u = global->admins[i]->admin.user; UNLOCK(global->admins[i]); LOCK(u); xstrncpy(username,u->username,sizeof(username)); UNLOCK(u); LOCK(global->admins[i]); } else strcpy(username,"-"); LOCKR(&(global->party_line.lock)); for(j = 0; j < global->party_line.no_subs && j >= 0; ++j) { if(global->party_line.subs[j] == &(global->admins[i]->msgqueue)) j = -2; } UNLOCKR(&(global->party_line.lock)); admin_cmsg(ac,"%s (%s), State: %s, Since: %s%s%s", username, global->admins[i]->host == NULL ? "Via Socket" : global->admins[i]->host, send_state_text(global->admins[i]->state), timestr(global->admins[i]->connected,buffer, sizeof(buffer)), j >= 0 ? "" : ", ", j >= 0 ? "" : "%9PL%9"); UNLOCK(global->admins[i]); } UNLOCK(global); return 0; } MENU_CMD(cmd_netmsg) { network_t *n; char buffer[512]; n = irc_network_find(args[1]); if(n != NULL) { colourise(COLOUR_IRC,buffer,sizeof(buffer),args[3]); irc_send_msg(n,args[2],buffer); } else { admin_msg(ac,"Invalid Network: %s",args[1]); RET_VAL(RET_INV_ARG); } return 0; } static int qsort_cmdcmp(const void *a, const void *b); // pre-declaration MENU_CMD(cmd_help) { unsigned long privs; int i,len,no_cmds = 0; menu_t *cmd,**cmds = NULL; char *cmd_str; if(no_args == 1) cmd_str = "help"; else cmd_str = args[1]; LOCK(ac->user); privs = ac->user->uprivs; UNLOCK(ac->user); for(i = 0; cmd_str[i] != '\0'; ++i) { if(cmd_str[i] == '?') break; } len = i; if(cmd_str[len] == '?') { cmds = find_cmds(ins,cmd_str,len,privs,&no_cmds,0,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); } } else { cmds = find_cmds(ins,cmd_str,len,privs,&no_cmds,0,1); cmd = NULL; 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,cmd_str) == 0) cmd = cmds[i]; } } if(cmd != NULL) { if(cmd->help != NULL) { admin_cmsg(ac,"Help for %s (%s).", cmd_str,cmd->name); admin_cmsg(ac,""); for(i = 0; i < cmd->no_help; ++i) admin_cmsg(ac,cmd->help[i],cmd->name); } else { admin_msg(ac,"No help available for %s (%s).", cmd_str,cmd->name); } } else { admin_msg(ac,"Command %s not found.",cmd_str); } } if(cmds != NULL) { for(i = 0; i < no_cmds; ++i) menu_deref(cmds[i]); xfree(cmds); } return 0; } MENU_CMD(cmd_verbose) { if(strcasecmp(args[1],"on") == 0) ac->verbose = 1; else ac->verbose = 0; return 0; } static double d_avgspeed(uint32_t *ags) { double ret = 0.0; int i; for(i = 0; i < AVGSPEED; ++i) ret += (double) ags[i]; return ret / (double)AVGSPEED; } static void gstat_line(acontext_t *ac) { char shared_buf[8], ul_buf[8], dl_buf[8]; double ul_rate = 0.0, dl_rate = 0.0; off_t shared = 0, ul = 0, dl = 0; int no_chats = 0, no_sends = 0, no_queues = 0, no_uploads = 0; int no_admins = 0, no_packs = 0, no_sent = 0; int max_chats = 0, max_sends = 0, max_queues = 0, max_uploads = 0; int i,j; LOCK(global); no_admins = global->no_admins; for(i = 0; i < global->no_interfaces; ++i) { interface_t *intf = global->interfaces[i]; LOCK(intf); if(intf->type == INTERFACE_SEND) { ul += intf->stat_mib * (1024.0 * 1024.0) + intf->stat_carry; ul_rate += d_avgspeed(intf->avgspeed); for(j = 0; j < intf->send.no_pools; ++j) { pool_t *p = intf->send.pools[j]; LOCK(p); no_sends += p->no_csends; max_sends += p->sends; UNLOCK(p); } } else if(intf->type == INTERFACE_RECV) { dl += intf->stat_mib * (1024.0 * 1024.0) + intf->stat_carry; dl_rate += d_avgspeed(intf->avgspeed); no_uploads += intf->recv.no_uploads; max_uploads += intf->recv.max_no_uploads; } else if(intf->type == INTERFACE_CHAT) { ul += intf->stat_mib * (1024.0 * 1024.0) + intf->stat_carry; ul_rate += d_avgspeed(intf->avgspeed); no_chats += intf->chat.no_chats; max_chats += intf->chat.max_no; } UNLOCK(intf); } for(i = 0; i < global->no_queues; ++i) { queue_t *q = global->queues[i]; LOCK(q); no_queues += q->no_qsends; max_queues += q->length; UNLOCK(q); } for(i = 0; i < global->no_packlists; ++i) { packlist_t *p = global->packlists[i]; LOCK(p); no_packs += p->no_packs; for(j = 0; j < p->no_packs; ++j) { RLOCK(p->packs[j]); shared += p->packs[j]->size; no_sent += p->packs[j]->no_gets; RUNLOCK(p->packs[j]); } UNLOCK(p); } UNLOCK(global); admin_msg(ac,"GStat: U:%.1fKiB/s D:%.1fKiB/s S:%d/%d Q:%d/%d R:%d/%d C:%d/%d A:%d P:%d/%d Sh:%s Ul:%s Dl:%s", ul_rate / 1024.0,dl_rate / 1024.0, no_sends,max_sends,no_queues,max_queues, no_uploads,max_uploads,no_chats,max_chats, no_admins, no_sent,no_packs,three_digit_size(shared_buf,shared), three_digit_size(ul_buf,ul), three_digit_size(dl_buf,dl)); } MENU_CHECK(gstat_line_checker) { gstat_line(ac); return 0; } MENU_CMD(cmd_stats) { if(no_args < 2) { gstat_line(ac); } else { while(ins->prev != NULL) ins = ins->prev; if(strcasecmp(args[1],"on") == 0) { if(ins->check == NULL) { ins->check = gstat_line_checker; admin_msg(ac,"Global stat line: on."); } else if(ins->check == gstat_line_checker) { admin_msg(ac,"Global stat line: on."); } else { admin_msg(ac,"Global stat line can not be set."); } } else if(strcasecmp(args[1],"off") == 0) { if(ins->check == gstat_line_checker) { ins->check = NULL; admin_msg(ac,"Global stat line: off."); } else { admin_msg(ac,"Global stat line is not on."); } } else { admin_msg(ac,"%s [on|off]",args[0]); } } return 0; } /** Global Menu Structure **/ MENU_HELPER(cmd_net_channels_helper); // pre-declaration static const cmd_t global_menu[] = { {"/", cmd_gotoroot, 0,0,0,1, PRIVS_EMPTY,NULL}, {"toroot", cmd_gotoroot, 0,0,0,1, PRIVS_EMPTY,NULL}, {"'", cmd_plmsg, 1,-2,0,1, PRIV_TO_MASK(PRIV_PARTY_LINE), NULL}, {"plmsg", cmd_plmsg, 1,-2,0,1, PRIV_TO_MASK(PRIV_PARTY_LINE), NULL}, {";", cmd_pljp, 0,0,0,1, PRIV_TO_MASK(PRIV_PARTY_LINE), NULL}, {"pljp", cmd_pljp, 0,0,0,1, PRIV_TO_MASK(PRIV_PARTY_LINE), NULL}, {":", cmd_msg, 2,-2,0,1, PRIV_TO_MASK(PRIV_PARTY_LINE), NULL}, {"pmsg", cmd_msg, 2,-2,0,1, PRIV_TO_MASK(PRIV_PARTY_LINE), NULL}, {".", cmd_prompt, 0,0,0,1, PRIVS_EMPTY,NULL}, {"prompt", cmd_prompt, 0,0,0,1, PRIVS_EMPTY,NULL}, {"..", cmd_exit, 0,0,0,1, PRIVS_EMPTY,NULL}, {"|", cmd_whoison, 0,0,0,1, PRIV_TO_MASK(PRIV_PARTY_LINE), NULL}, {"whoison", cmd_whoison, 0,0,0,1, PRIV_TO_MASK(PRIV_PARTY_LINE), NULL}, {"=", cmd_netmsg, 3,-2,0,1, PRIV_TO_MASK(PRIV_MESSAGE), cmd_net_channels_helper}, {"netmsg", cmd_netmsg, 3,-2,0,1, PRIV_TO_MASK(PRIV_MESSAGE), cmd_net_channels_helper}, {"colour", cmd_colour, 1,1,0,1, PRIVS_EMPTY,NULL}, {"date", cmd_date, 0,0,0,1, PRIVS_EMPTY,NULL}, {"exit", cmd_exit, 0,0,0,1, PRIVS_EMPTY,NULL}, {"log", cmd_log, 1,-2,0,1, PRIV_TO_MASK(PRIV_LOG), NULL}, {"help", cmd_help, 0,1,0,0, PRIVS_EMPTY,NULL}, {"quit", cmd_quit, 0,0,1,1, PRIVS_EMPTY,NULL}, {"stats", cmd_stats, 0,1,0,0, PRIVS_EMPTY,NULL}, {"verbose", cmd_verbose, 1,1,0,1, PRIVS_EMPTY,NULL}, {NULL} };