/* ARISA - Admin Interface - Interface 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 */ static int is_int_new(interface_t *i) { int j; LOCK(global); for(j = 0; j < global->no_interfaces; ++j) { if(global->interfaces[j] == i) { UNLOCK(global); return 0; } } UNLOCK(global); return 1; } static const char *send_state_text(state_t s) { switch(s) { case STATE_UNKNOWN: return "%rUNKNOWN%n"; case STATE_QUEUED: return "%cQUEUED%n"; case STATE_RESOLVING: return "%cRESOLVING%n"; case STATE_CONNECTING: return "%rCONNECTING%n"; case STATE_NEGOTIATING: return "%cNEGOTIATING%n"; case STATE_LISTENING: return "%cLISTENING%n"; case STATE_ACTIVE: return "%gACTIVE%n"; case STATE_COMPLETING: return "%GCOMPLETING%n"; case STATE_COMPLETE: return "%GCOMPLETE%n"; case STATE_SLOW: return "%ySLOW%n"; case STATE_TIMEOUT: return "%yTIMEOUT%n"; case STATE_DELETED: return "%rDELETED%n"; case STATE_PURGING: return "%rPURGING%n"; case STATE_PURGEREQUEUE: return "%rREQUEUE%n"; case STATE_ERROR: return "%rERROR%n"; case STATE_RETRY: return "%yRETRY%n"; case STATE_RESUME: return "%cRESUME%n"; case STATE_RESUMED: return "%cRESUMED%n"; default: return "UNKNOWN"; } } /** Interface Menu Commands **/ MENU_HELPER(cmd_interfaces_helper) { int i,j; LOCK(global); if(no_args == 2) { for(j = 0; args[1][j] != '\0'; ++j) { if(args[1][j] == '?') break; } for(i = 0; i < global->no_interfaces; ++i) { LOCK(global->interfaces[i]); if(global->interfaces[i]->deleted == 0 && (j == 0 || strncmp(global->interfaces[i]->name,args[1],j) == 0)) admin_msg(ac,"%s",global->interfaces[i]->name); UNLOCK(global->interfaces[i]); } } else if(no_args > 2) { admin_msg(ac,"SEND"); admin_msg(ac,"RECV"); admin_msg(ac,"CHAT"); } UNLOCK(global); } MENU_CMD(cmd_interface_makedefault) { interface_t *intf = (interface_t *)ins->data; interfacetype_t type; int i; LOCK(intf); type = intf->type; if(intf->def != 0) { UNLOCK(intf); admin_msg(ac,"Already Default Set as Default %s Interface", interfacetype_to_str(type)); return 0; } else if(intf->deleted != 0) { UNLOCK(intf); return 0; } UNLOCK(intf); LOCK(global); for(i = 0; i < global->no_interfaces; ++i) { if(global->interfaces[i] != intf) { LOCK(global->interfaces[i]); if(global->interfaces[i]->type == type && global->interfaces[i]->def != 0 && global->interfaces[i]->deleted != 0) global->interfaces[i]->def = 0; UNLOCK(global->interfaces[i]); } } LOCK(intf); intf->def = 1; UNLOCK(intf); UNLOCK(global); admin_msg(ac,"Set as Default %s Interface",interfacetype_to_str(type)); return 0; } MENU_CMD(cmd_interface_rename) { interface_t *intf = (interface_t *)ins->data; char buffer[96]; if(interface_rename(intf,args[1]) == 0) { LOCK(intf); snprintf(buffer,sizeof(buffer),"interface: %s (%s)", intf->name,interfacetype_to_str(intf->type)); UNLOCK(intf); if(ins->prompt != NULL && ins->free_prompt != 0) xfree(ins->prompt); ins->prompt = xstrdup(buffer); ins->free_prompt = 1; admin_msg(ac,"Renamed Interface to %s",args[1]); admin_output_prompt(ac); } else admin_msg(ac,"Failed Renamed to %s",args[1]); return 0; } MENU_CMD(cmd_interface_settings) { interface_t *intf = (interface_t *)ins->data; if(no_args == 1) { char buffer[256]; pqueue_t settings; pqueue_init(&settings,0); interface_read_settings(intf,&settings); LOCK(intf); snprintf(buffer,sizeof(buffer), "-- Interface Settings for %s (%s) --", intf->name,interfacetype_to_str(intf->type)); UNLOCK(intf); output_settings(ac,buffer,NULL,&settings); } else if(no_args >= 3) { if(interface_apply_setting(intf,args[1],args[2]) == -1) admin_msg(ac,"Invalid setting: %s",args[1]); } else admin_msg(ac,"%s [ ]",args[0]); return 0; } MENU_CMD(cmd_interface_save) { interface_t *intf = (interface_t *)ins->data; int ret; if(is_int_new(intf)) { ret = interface_add(intf); if(ret != -1) { admin_msg(ac,"Successfully Saved."); ins->free = NULL; } else admin_msg(ac,"Save Failed."); } else admin_msg(ac,"Interface is already saved"); return 0; } MENU_CMD(cmd_interface_delete) { interface_t *intf = (interface_t *)ins->data; int done = 1; if(!is_int_new(intf)) { interface_del(intf); LOCK(intf); if(intf->deleted != 0) admin_msg(ac,"Interface %s Deleted",intf->name); else { done = 0; admin_msg(ac,"Interface %s Deletion not possible",intf->name); } UNLOCK(intf); } if(done) return RET_UP; else return 0; } MENU_CMD(cmd_interface_info) { interface_t *intf = (interface_t *)ins->data; char tmp[16]; float f; int i,j,k; LOCK(intf); admin_msg(ac,"-- Interface %s --",intf->name); admin_msg(ac,"Type: %s (%s)",interfacetype_to_str(intf->type), intf->def ? "Default" : "Not Default"); admin_msg(ac,"State: %s", thread_is_running(&(intf->thread)) ? "Running" : "Offline"); for(i = 0, f = 0.0; i < AVGSPEED; ++i) f += (float)intf->avgspeed[i]; f /= ((float)AVGSPEED) * 1024.0; if(intf->bandwidth != 0) admin_msg(ac,"Current Rate: %.2f KiB/sec (Limit: %ld, Samples: %d)", f,intf->bandwidth,AVGSPEED); else admin_msg(ac,"Current Rate: %.2f KiB/sec (Samples: %d)", f,AVGSPEED); admin_msg(ac,"Record Rate: %.2f KiB/sec", ((float)intf->record_rate)/1024.0); admin_msg(ac,"Total Transferred: %s", format_bytes(tmp,sizeof(tmp), ((unsigned long long)intf->stat_mib)*1024*1024 + (unsigned long long)intf->stat_carry,1)); if(intf->type == INTERFACE_SEND) { for(i = 0,j = 0,k = 0; i < intf->send.no_pools; ++i) { LOCK(intf->send.pools[i]); if(intf->send.pools[i]->deleted == 0) { j++; k += intf->send.pools[i]->no_csends; } UNLOCK(intf->send.pools[i]); } admin_msg(ac,"Number of Pools: %d",j); admin_msg(ac,"Current Sends: %d",k); } else if(intf->type == INTERFACE_RECV) { admin_msg(ac,"Current Uploads: %d",intf->recv.no_uploads); } else if(intf->type == INTERFACE_CHAT) { admin_msg(ac,"Current Chats: %d",intf->chat.no_chats); } UNLOCK(intf); return 0; } static void cmd_interface_display_upload(acontext_t *ac, send_t *u, time_t now) { char buffer2[16],buffer3[16]; float f; int i; LOCK(u); RLOCK(u->pack); for(i = 0, f = 0.0; i < AVGSPEED; ++i) f += (float)u->avgspeed[i]; f /= ((float)AVGSPEED) * 1024.0; if(u->network != NULL) LOCK(u->network); // NOTE: Special case admin_cmsg(ac,"%%r-%%n From: [%%9%s:%s%%n] (%s)", u->network != NULL ? u->network->name : "Unknown", u->nick != NULL ? u->nick : "Unknown",u->host); if(u->network != NULL) UNLOCK(u->network); admin_cmsg(ac," Rate: %%9%.2f KiB/sec%%n, State %s, Elp:%s Rem:%s (%ds)", f,send_state_text(u->state), u->connected == 0 ? "-" : etimestr((now - u->connected),buffer2,sizeof(buffer2)), f > 0.0 && u->pos != u->pack->size ? etimestr( (u->pack->size - u->pos) / (off_t)((f*1024.0) >= 1.0 ? (f*1024.0) : 1.0), buffer3,sizeof(buffer3)) : "-", u->last_contact != 0 ? now - u->last_contact : 0); admin_cmsg(ac," File: %%9%s%%n (%ld/%ldKiB)", u->pack->file, (long)u->pos/1024,(long)u->pack->size/1024); RUNLOCK(u->pack); UNLOCK(u); } MENU_CMD(cmd_interface_access) { interface_t *i = (interface_t *)ins->data; char title[128]; access_t *acc; LOCK(i); if(i->type != INTERFACE_RECV) { UNLOCK(i); admin_msg(ac,"Only available on %s type interfaces.", interfacetype_to_str(INTERFACE_RECV)); return RET_INV_CMD; } snprintf(title,sizeof(title),"Interface %s",i->name); if(i->recv.access == NULL && no_args > 1) { i->recv.access = alloc_access(); LOCK(i->recv.access); i->recv.access->flags = ACCESS_DENY; UNLOCK(i->recv.access); } acc = i->recv.access; UNLOCK(i); return cmd_access_list(ac,acc,title,args,no_args); } MENU_CMD(cmd_interface_uploads) { interface_t *intf = (interface_t *)ins->data; int i; LOCK(intf); if(intf->type != INTERFACE_RECV) { UNLOCK(intf); admin_msg(ac,"Only available on %s type interfaces.", interfacetype_to_str(INTERFACE_RECV)); return -1; } else UNLOCK(intf); if(no_args == 1) { time_t now = xtime(); LOCK(intf); admin_msg(ac,"-- Uploads on Interface %s --",intf->name); for(i = 0; i < intf->recv.no_uploads; ++i) cmd_interface_display_upload(ac, intf->recv.uploads[i],now); if(i == 0) admin_msg(ac,"None"); UNLOCK(intf); } else if(tolower(args[1][0]) == 'c' && no_args >= 3) { if(no_args >= 4) { i = interface_upload_close(intf,args[2],NULL, args[3],NULL,NULL,NULL); i += interface_upload_close(intf,args[2],NULL, NULL,args[3],NULL,NULL); } else i = interface_upload_close(intf,args[2],NULL,NULL, NULL,NULL,NULL); admin_msg(ac,"Closed %d Matching Uploads",i); } else admin_msg(ac,"%s [close [|]]",args[0]); return 0; } static void cmd_interface_display_chat(acontext_t *ac, chat_t *c, time_t now) { char buffer1[32]; LOCK(c); if(c->network != NULL) LOCK(c->network); admin_cmsg(ac,"%%r-%%n To: [%%9%s:%s%%n] Type: %s, State: %s", c->network != NULL ? c->network->name : "Unknown", c->nick != NULL ? c->nick : "Unknown", c->type == CHAT_LIST ? "LIST" : "ADMIN", send_state_text(c->state)); if(c->network != NULL) UNLOCK(c->network); admin_msg(ac," Started: %s, Last Contact: %d Seconds", timestr(c->started,buffer1,sizeof(buffer1)), c->last_contact != 0 ? now - c->last_contact : 0); UNLOCK(c); } MENU_CMD(cmd_interface_chats) { interface_t *intf = (interface_t *)ins->data; int i; LOCK(intf); if(intf->type != INTERFACE_CHAT) { UNLOCK(intf); admin_msg(ac,"Only available on %s type interfaces.", interfacetype_to_str(INTERFACE_CHAT)); return -1; } else UNLOCK(intf); if(no_args == 1) { time_t now = xtime(); LOCK(intf); admin_msg(ac,"-- Chats on Interface %s --",intf->name); for(i = 0; i < intf->chat.no_chats; ++i) cmd_interface_display_chat(ac,intf->chat.chats[i],now); if(i == 0) admin_msg(ac,"None"); UNLOCK(intf); } else if(tolower(args[1][0]) == 'c' && no_args >= 3) { i = interface_chat_close(intf,args[2],NULL, no_args >= 4 ? args[3] : NULL,NULL,NULL); admin_msg(ac,"Closed %d Matching Chats",i); } else admin_msg(ac,"%s [close []]",args[0]); return 0; } /** Interface Menu Structures **/ static const cmd_t interface_menu[] = { {"access", cmd_interface_access, 0,-1,1,0,PRIVS_EMPTY,NULL}, {"chats", cmd_interface_chats, 0,3,1,0,PRIVS_EMPTY,NULL}, {"delete", cmd_interface_delete, 0,0,1,0,PRIVS_EMPTY,NULL}, {"info", cmd_interface_info, 0,0,0,0,PRIVS_EMPTY,NULL}, {"rename", cmd_interface_rename, 1,1,1,0,PRIVS_EMPTY,NULL}, {"save", cmd_interface_save, 0,0,1,0,PRIVS_EMPTY,NULL}, {"makedefault", cmd_interface_makedefault,0,0,1,0,PRIVS_EMPTY,NULL}, {"settings", cmd_interface_settings, 0,2,1,0,PRIVS_EMPTY,NULL}, {"uploads", cmd_interface_uploads, 0,3,1,0,PRIVS_EMPTY,NULL}, {NULL} }; /** Network Menu Entry **/ MENU_CHECK(cmd_interface_check) { interface_t *i = (interface_t *)ins->data; int ret = 0; LOCK(i); if(i->deleted != 0) { admin_msg(ac,"Interface %s, Deleted.",i->name); ret = -1; } UNLOCK(i); return ret; } MENU_CMD(cmd_interface_entry) { char buffer[96]; interface_t *intf; int new = 0; intf = interface_find(args[1]); if(intf == NULL) { if(no_args >= 3) { if(strcasecmp(args[2],"send") == 0) intf = alloc_interface(INTERFACE_SEND); else if(strcasecmp(args[2],"recv") == 0) intf = alloc_interface(INTERFACE_RECV); else if(strcasecmp(args[2],"chat") == 0) intf = alloc_interface(INTERFACE_CHAT); if(intf != NULL) { new = 1; intf->name = xstrdup(args[1]); admin_msg(ac,"New Interface: %s",args[1]); } else admin_msg(ac,"%s [SEND|RECV|CHAT]",args[0]); } else admin_msg(ac,"%s [SEND|RECV|CHAT]",args[0]); } if(intf != NULL) { LOCK(intf); if(intf->type == INTERFACE_SEND) { snprintf(buffer,sizeof(buffer), "interface: %s (SEND)",intf->name); } else if(intf->type == INTERFACE_RECV) { snprintf(buffer,sizeof(buffer), "interface: %s (RECV)",intf->name); } else /*if(intf->type == INTERFACE_CHAT)*/ { snprintf(buffer,sizeof(buffer), "interface: %s (CHAT)",intf->name); } UNLOCK(intf); if(ins->prompt != NULL && ins->free_prompt) xfree(ins->prompt); ins->prompt = xstrdup(buffer); ins->free_prompt = 1; ins->check = cmd_interface_check; ins->data = intf; if(new) ins->free = (void (*)(void *))free_interface; return 0; } else return -1; } static void register_interface_menu(void) { menu_t *intf_menu = menu_from_cmds( "interface", // name 1, // min_args 2, // max_args 1, // log 0, // hide PRIV_TO_MASK(PRIV_INTERFACES), // privs cmd_interface_entry, // func cmd_interfaces_helper, // helper (cmd_t *)interface_menu); register_pool_menu(intf_menu); menu_add(main_menu_root,intf_menu); menu_deref(intf_menu); }