From 5ad4c41dc406a15beaa0a7b73d9dada1df74f939 Mon Sep 17 00:00:00 2001 From: Super User Date: Sun, 3 Feb 2008 13:47:33 +0100 Subject: now gives warning if mISDN branch is wrong. also some work on chan_lcr. modified: Makefile modified: apppbx.cpp modified: bchannel.c modified: chan_lcr.c modified: chan_lcr.h modified: dss1.cpp modified: dss1.h modified: extension.c modified: extension.h modified: genrc.c modified: ie.cpp renamed: admin_client.c -> lcradmin.c renamed: admin.h -> lcrsocket.h modified: mISDN.cpp modified: main.h renamed: admin_server.c -> socket_server.c renamed: admin_server.h -> socket_server.h modified: todo.txt --- lcradmin.c | 1757 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1757 insertions(+) create mode 100644 lcradmin.c (limited to 'lcradmin.c') diff --git a/lcradmin.c b/lcradmin.c new file mode 100644 index 0000000..cf97f69 --- /dev/null +++ b/lcradmin.c @@ -0,0 +1,1757 @@ +/*****************************************************************************\ +** ** +** Linux Call Router ** +** ** +**---------------------------------------------------------------------------** +** Copyright: Andreas Eversberg ** +** ** +** Administration tool ** +** ** +\*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "macro.h" +#include "join.h" +#include "joinpbx.h" +#include "extension.h" +#include "message.h" +#include "lcrsocket.h" +#include "cause.h" + +#define LTEE {addch(ACS_LTEE);addch(ACS_HLINE);addch(ACS_HLINE);} +#define LLCORNER {addch(ACS_LLCORNER);addch(ACS_HLINE);addch(ACS_HLINE);} +#define VLINE {addch(ACS_VLINE);addstr(" ");} +#define EMPTY {addstr(" ");} +//char rotator[] = {'-', '\\', '|', '/'}; +int lastlines, lastcols; +int show_interfaces = 2, + show_calls = 1, + show_log = 1; + +enum { + MODE_STATE, + MODE_INTERFACE, + MODE_ROUTE, + MODE_DIAL, + MODE_RELEASE, + MODE_UNBLOCK, + MODE_BLOCK, + MODE_UNLOAD, + MODE_TESTCALL, + MODE_TRACE, +}; + +char *text_interfaces[] = { + "off", + "brief", + "active channels", + "all channels", +}; + +char *text_calls[] = { + "off", + "brief", + "structured", +}; + +char red = 1, + green = 2, + yellow = 3, + blue = 4, + mangenta = 5, + cyan = 6, + white = 7; + +#define LOGLINES 128 +char logline[LOGLINES][512]; +unsigned long logcur = 0; +int logfh = -1; +char logfile[128]; + +/* + * curses + */ +void init_curses(void) +{ + /* init curses */ + initscr(); cbreak(); noecho(); + start_color(); + nodelay(stdscr, TRUE); + if (COLOR_PAIRS>=8 && COLORS>=8) + { + init_pair(1,1,0); + init_pair(2,2,0); + init_pair(3,3,0); + init_pair(4,4,0); + init_pair(5,5,0); + init_pair(6,6,0); + init_pair(7,7,0); + } + lastlines = LINES; + lastcols = COLS; +} + +void cleanup_curses(void) +{ + endwin(); +} + +void color(int color) +{ + if (COLOR_PAIRS>=8 && COLORS>=8) + attrset(COLOR_PAIR(color)); +} + +/* + * permanently show current state using ncurses + */ +int debug_port(struct admin_message *msg, struct admin_message *m, int line, int i, int vline) +{ + char buffer[256]; + + color(white); + addstr("PORT:"); + color(yellow); + SPRINT(buffer,"%s(%d)", m[i].u.p.name,m[i].u.p.serial); + addstr(buffer); + color(cyan); + addstr(" state="); + switch (m[i].u.p.state) + { + case ADMIN_STATE_IDLE: + color(red); + addstr("'idle'"); + break; + case ADMIN_STATE_IN_SETUP: + color(red); + addstr("'in << setup'"); + break; + case ADMIN_STATE_OUT_SETUP: + color(red); + addstr("'out >> setup'"); + break; + case ADMIN_STATE_IN_OVERLAP: + color(yellow); + addstr("'in << overlap'"); + break; + case ADMIN_STATE_OUT_OVERLAP: + color(yellow); + addstr("'out >> overlap'"); + break; + case ADMIN_STATE_IN_PROCEEDING: + color(mangenta); + addstr("'in << proc'"); + break; + case ADMIN_STATE_OUT_PROCEEDING: + color(mangenta); + addstr("'out >> proc'"); + break; + case ADMIN_STATE_IN_ALERTING: + color(cyan); + addstr("'in << alert'"); + break; + case ADMIN_STATE_OUT_ALERTING: + color(cyan); + addstr("'out >> alert'"); + break; + case ADMIN_STATE_CONNECT: + color(white); + addstr("'connect'"); + break; + case ADMIN_STATE_IN_DISCONNECT: + color(blue); + addstr("'in << disc'"); + break; + case ADMIN_STATE_OUT_DISCONNECT: + color(blue); + addstr("'out >> disc'"); + break; + default: + color(blue); + addstr("'--NONE--'"); + } + + if (m[i].u.p.isdn) + { + color(cyan); + addstr(" bchannel="); + color(white); + SPRINT(buffer,"%d", m[i].u.p.isdn_chan); + addstr(buffer); + if (m[i].u.p.isdn_ces >= 0) + { + color(cyan); + addstr(" ces="); + color(yellow); + SPRINT(buffer, "%d", m[i].u.p.isdn_ces); + addstr(buffer); + } + if (m[i].u.p.isdn_hold) + { + color(red); + addstr(" hold"); + } + } + + return(line); +} +int debug_epoint(struct admin_message *msg, struct admin_message *m, int line, int i, int vline) +{ + unsigned long epoint = m[i].u.e.serial; + char buffer[256]; + unsigned char c; + int j, jj; + int ltee; + + color(white); + SPRINT(buffer,"EPOINT(%d)", epoint); + addstr(buffer); + color(cyan); + addstr(" state="); + switch (m[i].u.e.state) + { + case ADMIN_STATE_IDLE: + color(red); + addstr("'idle'"); + break; + case ADMIN_STATE_IN_SETUP: + color(red); + addstr("'in << setup'"); + break; + case ADMIN_STATE_OUT_SETUP: + color(red); + addstr("'out >> setup'"); + break; + case ADMIN_STATE_IN_OVERLAP: + color(yellow); + addstr("'in << overlap'"); + break; + case ADMIN_STATE_OUT_OVERLAP: + color(yellow); + addstr("'out >> overlap'"); + break; + case ADMIN_STATE_IN_PROCEEDING: + color(mangenta); + addstr("'in << proc'"); + break; + case ADMIN_STATE_OUT_PROCEEDING: + color(mangenta); + addstr("'out >> proc'"); + break; + case ADMIN_STATE_IN_ALERTING: + color(cyan); + addstr("'in << alert'"); + break; + case ADMIN_STATE_OUT_ALERTING: + color(cyan); + addstr("'out >> alert'"); + break; + case ADMIN_STATE_CONNECT: + color(white); + addstr("'connect'"); + break; + case ADMIN_STATE_IN_DISCONNECT: + color(blue); + addstr("'in << disc'"); + break; + case ADMIN_STATE_OUT_DISCONNECT: + color(blue); + addstr("'out >> disc'"); + break; + default: + color(blue); + addstr("'--NONE--'"); + } + if (m[i].u.e.terminal[0]) + { + color(cyan); + addstr(" terminal="); + color(green); + addstr(m[i].u.e.terminal); + } + color(white); + SPRINT(buffer, " %s", m[i].u.e.callerid); + addstr(buffer); + color(cyan); + addstr("->"); + color(white); + addstr(m[i].u.e.dialing); + if (m[i].u.e.action[0]) + { + color(cyan); + addstr(" action="); + color(yellow); + addstr(m[i].u.e.action); + } + if (m[i].u.e.park) + { + color(cyan); + addstr(" park="); /* 9 digits */ + color(green); + UCPY(buffer, "\""); /* 9 digits */ + j = 0; + jj = m[i].u.e.park_len; + while(j < jj) + { + c = m[i].u.e.park_callid[j]; + if (c >= 32 && c < 127 && c != '[') + { + SCCAT(buffer, c); + } else + UPRINT(buffer+strlen(buffer), "[%02x]", c); + j++; + } + SCAT(buffer, "\""); + addstr(buffer); + } else + { + color(red); + switch(m[i].u.e.rx_state) + { + case NOTIFY_STATE_SUSPEND: + addstr(" in=suspend"); + break; + case NOTIFY_STATE_HOLD: + addstr(" in=hold"); + break; + case NOTIFY_STATE_CONFERENCE: + addstr(" in=conference"); + break; + } + switch(m[i].u.e.tx_state) + { + case NOTIFY_STATE_SUSPEND: + addstr(" out=suspend"); + break; + case NOTIFY_STATE_HOLD: + addstr(" out=hold"); + break; + case NOTIFY_STATE_CONFERENCE: + addstr(" out=conference"); + break; + } + } + if (m[i].u.e.crypt) + { + color(cyan); + addstr(" crypt="); + if (m[i].u.e.crypt) /* crypt on */ + { + color(green); + addstr("active"); + } else + { + color(yellow); + addstr("pending"); + } + } + /* loop all related ports */ + ltee = 0; + j = msg->u.s.interfaces+msg->u.s.joins+msg->u.s.epoints; + jj = j + msg->u.s.ports; + while(j < jj) + { + if (m[j].u.p.epoint == epoint) + { + color(cyan); + move(++line>1?line:1, 1); + if (vline) + VLINE + else + EMPTY + move(line>1?line:1, 5); + LTEE + ltee = line; + move(line>1?line:1, 8); + if (line+2 >= LINES) break; + line = debug_port(msg, m, line, j, vline); + if (line+2 >= LINES) break; + } + j++; + } + if (ltee) + { + color(cyan); + move(ltee>1?line:1, 5); + LLCORNER + } + + return(line); +} +int debug_join(struct admin_message *msg, struct admin_message *m, int line, int i) +{ + unsigned long join = m[i].u.j.serial; + char buffer[256]; + int j, jj; + + color(white); + SPRINT(buffer,"JOIN(%d)", join); + addstr(buffer); + if (m[i].u.j.partyline) + { + color(cyan); + addstr(" partyline="); + color(white); + SPRINT(buffer, "%d\n", m[i].u.j.partyline); + addstr(buffer); + } + if (m[i].u.j.remote[0]) + { + color(cyan); + addstr(" remote="); + color(white); + SPRINT(buffer, "%s\n", m[i].u.j.remote); + addstr(buffer); + } + /* find number of epoints */ + j = msg->u.s.interfaces+msg->u.s.joins; + jj = j + msg->u.s.epoints; + i = 0; + while(j < jj) + { + if (m[j].u.e.join == join) + i++; + j++; + } + /* loop all related endpoints */ + j = msg->u.s.interfaces+msg->u.s.joins; + jj = j + msg->u.s.epoints; + while(j < jj) + { + if (m[j].u.e.join == join) + { + i--; + move(++line>1?line:1, 1); + color(cyan); + if (i) + LTEE + else + LLCORNER + move(line>1?line:1, 4); + if (line+2 >= LINES) break; + line = debug_epoint(msg, m, line, j, i?1:0); + if (line+2 >= LINES) break; + } + j++; + } + + return(line); +} +char *admin_state(int sock, char *argv[]) +{ + struct admin_message msg, + *m; + char buffer[512], + *p; + int line, offset = 0, hoffset = 0; + int i, ii, j, jj, k; + unsigned long l, ll; + int num; + int len; + int off; + int ltee; + int anything; + int enter = 0; + char enter_string[128] = "", ch; + fd_set select_rfds; + struct timeval select_tv; + + /* flush logfile name */ + logfile[0] = '\0'; + + /* init curses */ + init_curses(); + + again: + /* send reload command */ + memset(&msg, 0, sizeof(msg)); + msg.message = ADMIN_REQUEST_STATE; +// printf("sizeof=%d\n",sizeof(msg));fflush(stdout); + if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) + { + cleanup_curses(); + return("Broken pipe while sending command."); + } + + /* receive response */ + if (read(sock, &msg, sizeof(msg)) != sizeof(msg)) + { + cleanup_curses(); + return("Broken pipe while receiving response."); + } + + if (msg.message != ADMIN_RESPONSE_STATE) + { + cleanup_curses(); + return("Response not valid. Expecting state response."); + } + num = msg.u.s.interfaces + msg.u.s.remotes + msg.u.s.joins + msg.u.s.epoints + msg.u.s.ports; + m = (struct admin_message *)MALLOC(num*sizeof(struct admin_message)); + off=0; + if (num) + { + readagain: + if ((len = read(sock, ((unsigned char *)(m))+off, num*sizeof(struct admin_message)-off)) != num*(int)sizeof(struct admin_message)-off) + { + if (len <= 0) { + FREE(m, 0); + // fprintf(stderr, "got=%d expected=%d\n", i, num*sizeof(struct admin_message)); + cleanup_curses(); + return("Broken pipe while receiving state infos."); + } + if (len < num*(int)sizeof(struct admin_message)) + { + off+=len; + goto readagain; + } + } + } + j = 0; + i = 0; +// fprintf("getting =%d interfaces\n", msg.u.s.interfaces); + while(i < msg.u.s.interfaces) + { +// fprintf(stderr, "j=%d message=%d\n", j, m[j].message); + if (m[j].message != ADMIN_RESPONSE_S_INTERFACE) + { + FREE(m, 0); + cleanup_curses(); + return("Response not valid. Expecting interface information."); + } + i++; + j++; + } + i = 0; + while(i < msg.u.s.remotes) + { + if (m[j].message != ADMIN_RESPONSE_S_REMOTE) + { + FREE(m, 0); + cleanup_curses(); + return("Response not valid. Expecting remote application information."); + } + i++; + j++; + } + i = 0; + while(i < msg.u.s.joins) + { + if (m[j].message != ADMIN_RESPONSE_S_JOIN) + { + FREE(m, 0); + cleanup_curses(); + return("Response not valid. Expecting join information."); + } + i++; + j++; + } + i = 0; + while(i < msg.u.s.epoints) + { + if (m[j].message != ADMIN_RESPONSE_S_EPOINT) + { + FREE(m, 0); + cleanup_curses(); + return("Response not valid. Expecting endpoint information."); + } + i++; + j++; + } + i = 0; + while(i < msg.u.s.ports) + { + if (m[j].message != ADMIN_RESPONSE_S_PORT) + { + FREE(m, 0); + cleanup_curses(); + return("Response not valid. Expecting port information."); + } + i++; + j++; + } + // now j is the number of message blocks + + /* display start */ + erase(); + + line = 1-offset; + + /* change log */ + if (!!strcmp(logfile, msg.u.s.logfile)) + { + SCPY(logfile, msg.u.s.logfile); + if (logfh >= 0) + close(logfh); + i = 0; + ii = LOGLINES; + while(i < ii) + { + logline[i][0] = '~'; + logline[i][1] = '\0'; + i++; + } + logcur = 0; + logfh = open(logfile, O_RDONLY|O_NONBLOCK); + if (logfh >= 0) + { + /* seek at the end -8000 chars */ + lseek(logfh, -8000, SEEK_END); + /* if not at the beginning, read until endofline */ + logline[logcur % LOGLINES][0] = '\0'; + l = read(logfh, logline[logcur % LOGLINES], sizeof(logline[logcur % LOGLINES])-1); + if (l > 0) + { + /* read first line and skip junk */ + logline[logcur % LOGLINES][l] = '\0'; + if ((p = strchr(logline[logcur % LOGLINES],'\n'))) + { + logcur++; + SCPY(logline[logcur % LOGLINES], p+1); + SCPY(logline[(logcur-1) % LOGLINES], "..."); + } + goto finish_line; + } + } + } + + /* read log */ + if (logfh >= 0) + { + while(42) + { + ll = strlen(logline[logcur % LOGLINES]); + l = read(logfh, logline[logcur % LOGLINES]+ll, sizeof(logline[logcur % LOGLINES])-ll-1); + if (l<=0) + break; + logline[logcur % LOGLINES][ll+l] = '\0'; + finish_line: + /* put data to lines */ + while ((p = strchr(logline[logcur % LOGLINES],'\n'))) + { + *p = '\0'; + logcur++; + SCPY(logline[logcur % LOGLINES], p+1); + } + /* if line is full without return, go next line */ + if (strlen(logline[logcur % LOGLINES]) == sizeof(logline[logcur % LOGLINES])-1) + { + logcur++; + logline[logcur % LOGLINES][0] = '\0'; + } + } + } + + /* display interfaces */ + if (show_interfaces > 0) + { + anything = 0; + i = 0; + ii = i + msg.u.s.interfaces; + while(i < ii) + { + /* show interface summary */ + move(++line>1?line:1, 0); + color(white); + if (m[i].u.i.block >= 2) + { + SPRINT(buffer, "%s (%d)%s", m[i].u.i.interface_name, m[i].u.i.portnum, (m[i].u.i.extension)?" (extension)":""); + addstr(buffer); + color(red); + addstr(" not loaded"); + } else + { + SPRINT(buffer, "%s (%d) %s %s%s use:%d", m[i].u.i.interface_name, m[i].u.i.portnum, (m[i].u.i.ntmode)?"NT-mode":"TE-mode", (m[i].u.i.ptp)?"ptp ":"ptmp", (m[i].u.i.extension)?" extension":"", m[i].u.i.use); + addstr(buffer); + if (m[i].u.i.ptp || !m[i].u.i.ntmode) + { + color((m[i].u.i.l2link)?green:red); + addstr((m[i].u.i.l2link)?" L2 UP":" L2 down"); + } + color((m[i].u.i.l1link)?green:blue); + addstr((m[i].u.i.l1link)?" L1 ACTIVE":" L1 inactive"); + if (m[i].u.i.block) + { + color(red); + addstr(" blocked"); + } + if (line+2 >= LINES) goto end; + /* show channels */ + if (show_interfaces > 1) + { + ltee = 0; + j = k =0; + jj = m[i].u.i.channels; + while(j < jj) + { + /* show all channels */ + if (show_interfaces>2 || m[i].u.i.busy[j]>0) + { + color(cyan); + /* show left side / right side */ + if ((k & 1) && (COLS > 70)) + { + move(line>1?line:1,4+((COLS-4)/2)); + } else + { + move(++line>1?line:1, 1); + LTEE + ltee = 1; + } + k++; + color(white); + if (m[i].u.i.pri) + SPRINT(buffer,"S%2d: ", j+1+(j>=15)); + else + SPRINT(buffer,"B%2d: ", j+1); + addstr(buffer); + switch(m[i].u.i.busy[j]) + { + case B_STATE_IDLE: + if ((!m[i].u.i.l2link && m[i].u.i.ptp) || m[i].u.i.block) + { + color(red); + addstr("blocked "); + } else + { + color(blue); + addstr("idle "); + } + break; + case B_STATE_ACTIVATING: + color(yellow); + addstr("act'ing "); + break; + case B_STATE_ACTIVE: + color(green); + addstr("busy "); + break; + case B_STATE_DEACTIVATING: + color(yellow); + addstr("dact'ing"); + break; + case B_STATE_EXPORTING: + color(yellow); + addstr("exp'ing "); + break; + case B_STATE_REMOTE: + color(green); + addstr("remote "); + break; + case B_STATE_IMPORTING: + color(yellow); + addstr("imp'ing "); + break; + } + if (m[i].u.i.port[j]) + { + /* search for port */ + l = msg.u.s.interfaces+msg.u.s.joins+msg.u.s.epoints; + ll = l+msg.u.s.ports; + while(l < ll) + { + if (m[l].u.p.serial == m[i].u.i.port[j]) + { + SPRINT(buffer, " %s(%ld)", m[l].u.p.name, m[l].u.p.serial); + addstr(buffer); + } + l++; + } + } + if (line+2 >= LINES) + { + if (ltee) + { + color(cyan); + move(line>1?line:1, 1); + LLCORNER + } + goto end; + } + } + j++; + } + if (ltee) + { + color(cyan); + move(line>1?line:1, 1); + LLCORNER + } + if (line+2 >= LINES) goto end; + /* show summary if no channels were shown */ + if (show_interfaces<2 && ltee==0) + { + color(cyan); + move(++line>1?line:1, 1); + LLCORNER + + if (m[i].u.i.l2link && m[i].u.i.block==0) + { + color(green); + SPRINT(buffer,"all %d channels free", m[i].u.i.channels); + } else + { + color(red); + SPRINT(buffer,"all %d channels blocked", m[i].u.i.channels); + } + addstr(buffer); + } + if (line+2 >= LINES) goto end; + } + } + i++; + anything = 1; + } + i = 0; + ii = i + msg.u.s.remotes; + while(i < ii) + { + /* show remote summary */ + move(++line>1?line:1, 0); + color(white); + SPRINT(buffer, "Remote: %s", m[i].u.r.name); + addstr(buffer); + i++; + } + if (anything) + line++; + if (line+2 >= LINES) goto end; + } + /* display calls (brief) */ + if (show_calls == 1) + { + anything = 0; + i = msg.u.s.interfaces+msg.u.s.joins; + ii = i+msg.u.s.epoints; + while(i < ii) + { + /* for each endpoint... */ + if (!m[i].u.e.join) + { + move(++line>1?line:1, 0); + color(white); + SPRINT(buffer, "(%d): ", m[i].u.e.serial); + addstr(buffer); + color(cyan); + if (m[i].u.e.terminal[0]) + { + addstr("intern="); + color(green); + addstr(m[i].u.e.terminal); + } else + addstr("extern"); + color(white); + SPRINT(buffer, " %s", m[i].u.e.callerid); + addstr(buffer); + color(cyan); + addstr("->"); + color(white); + SPRINT(buffer, "%s", m[i].u.e.dialing); + addstr(buffer); + if (m[i].u.e.action[0]) + { + color(cyan); + addstr(" action="); + color(yellow); + addstr(m[i].u.e.action); + } + if (line+2 >= LINES) goto end; + } + i++; + anything = 1; + } + j = msg.u.s.interfaces; + jj = j+msg.u.s.joins; + while(j < jj) + { + /* for each call... */ + move(++line>1?line:1, 0); + color(white); + SPRINT(buffer, "(%d):", m[j].u.j.serial); + addstr(buffer); + i = msg.u.s.interfaces+msg.u.s.joins; + ii = i+msg.u.s.epoints; + while(i < ii) + { + /* for each endpoint... */ + if (m[i].u.e.join == m[j].u.j.serial) + { + color(white); + SPRINT(buffer, " (%d)", m[i].u.e.serial); + addstr(buffer); + color(cyan); + if (m[i].u.e.terminal[0]) + { + addstr("int="); + color(green); + addstr(m[i].u.e.terminal); + } else + addstr("ext"); + color(white); + SPRINT(buffer, "-%s", m[i].u.e.callerid); + addstr(buffer); + color(cyan); + addstr(">"); + color(white); + SPRINT(buffer, "%s", m[i].u.e.dialing); + addstr(buffer); + } + i++; + anything = 1; + } + if (line+2 >= LINES) goto end; + j++; + } + if (anything) + line++; + if (line+2 >= LINES) goto end; + } + /* display calls (structurd) */ + if (show_calls == 2) + { + /* show all ports with no epoint */ + anything = 0; + i = msg.u.s.interfaces+msg.u.s.joins+msg.u.s.epoints; + ii = i+msg.u.s.ports; + while(i < ii) + { + if (!m[i].u.p.epoint) + { + move(++line>1?line:1, 8); + if (line+2 >= LINES) goto end; + line = debug_port(&msg, m, line, i, 0); + if (line+2 >= LINES) goto end; + anything = 1; + } + i++; + } + if (anything) + line++; + if (line+2 >= LINES) goto end; + + /* show all epoints with no call */ + anything = 0; + i = msg.u.s.interfaces+msg.u.s.joins; + ii = i+msg.u.s.epoints; + while(i < ii) + { + if (!m[i].u.e.join) + { + move(++line>1?line:1, 4); + if (line+2 >= LINES) goto end; + line = debug_epoint(&msg, m, line, i, 0); + if (line+2 >= LINES) goto end; + anything = 1; + } + i++; + } + if (anything) + line++; + if (line+2 >= LINES) goto end; + + /* show all joins */ + anything = 0; + i = msg.u.s.interfaces; + ii = i+msg.u.s.joins; + while(i < ii) + { + move(++line>1?line:1, 0); + if (line+2 >= LINES) goto end; + line = debug_join(&msg, m, line, i); + if (line+2 >= LINES) goto end; + i++; + anything = 1; + } + if (anything) + line++; + if (line+2 >= LINES) goto end; + + } + + /* show log */ + if (show_log) + { + if (line+2 < LINES) + { + move(line++>1?line-1:1, 0); + color(blue); + hline(ACS_HLINE, COLS); + color(white); + + l = logcur-(LINES-line-2); + ll = logcur; + if (ll-l >= LOGLINES) + l = ll-LOGLINES+1; + while(l!=ll) + { + move(line++>1?line-1:1, 0); + if ((int)strlen(logline[l % LOGLINES]) > hoffset) + SCPY(buffer, logline[l % LOGLINES] + hoffset); + else + buffer[0] = '\0'; + if (COLS < (int)strlen(buffer)) + { + buffer[COLS-1] = '\0'; + addstr(buffer); + color(mangenta); + addch('*'); + color(white); + } else + addstr(buffer); + l++; + } + } + } + + end: + /* free memory */ + FREE(m, 0); + /* display name/time */ +// move(0, 0); +// hline(' ', COLS); + move(0, 0); + color(cyan); + msg.u.s.version_string[sizeof(msg.u.s.version_string)-1] = '\0'; + SPRINT(buffer, "LCR %s", msg.u.s.version_string); + addstr(buffer); + if (COLS>50) + { + move(0, COLS-19); + SPRINT(buffer, "%04d-%02d-%02d %02d:%02d:%02d", + msg.u.s.tm.tm_year+1900, msg.u.s.tm.tm_mon+1, msg.u.s.tm.tm_mday, + msg.u.s.tm.tm_hour, msg.u.s.tm.tm_min, msg.u.s.tm.tm_sec); + addstr(buffer); + } + /* displeay head line */ + move(1, 0); + color(blue); + hline(ACS_HLINE, COLS); + if (offset) + { + move(1, 1); + SPRINT(buffer, "Offset +%d", offset); + color(red); + addstr(buffer); + } + if (hoffset) + { + move(1, 13); + SPRINT(buffer, "H-Offset +%d", hoffset); + color(red); + addstr(buffer); + } + /* display end */ + move(LINES-2, 0); + color(blue); + hline(ACS_HLINE, COLS); + move(LINES-1, 0); + if (enter) + { + color(white); + SPRINT(buffer, "-> %s", enter_string); + } else + { + color(cyan); + SPRINT(buffer, "i=interfaces '%s' c=calls '%s' l=log q=quit +-*/=scroll enter", text_interfaces[show_interfaces], text_calls[show_calls]); + } + addstr(buffer); + refresh(); + + /* resize */ + if (lastlines!=LINES || lastcols!=COLS) + { + cleanup_curses(); + init_curses(); + goto again; + } + + if (enter) + { + /* user input in enter mode */ + ch = getch(); + enter_again: + if (ch == 10) + { + FILE *fp; + + enter = 0; + if (!enter_string[0]) + goto again; + + SPRINT(logline[logcur++ % LOGLINES], "> %s", enter_string); + if (!!strncmp(enter_string, "interface", 10) && + !!strncmp(enter_string, "route", 6) && + !!strncmp(enter_string, "release ", 8) && + !!strncmp(enter_string, "block ", 6) && + !!strncmp(enter_string, "unblock ", 8) && + !!strncmp(enter_string, "unload ", 7)) + { + SPRINT(logline[logcur++ % LOGLINES], "usage:"); + SPRINT(logline[logcur++ % LOGLINES], "interface (reload interface.conf)"); + SPRINT(logline[logcur++ % LOGLINES], "route (reload routing.conf)"); + SPRINT(logline[logcur++ % LOGLINES], "release (release endpoint with given ID)"); + SPRINT(logline[logcur++ % LOGLINES], "block (block port for further calls)"); + SPRINT(logline[logcur++ % LOGLINES], "unblock (unblock port for further calls, load if not loaded)"); + SPRINT(logline[logcur++ % LOGLINES], "unload (unload mISDN stack, release call calls)"); + } else + { + /* applend output to log window */ + SPRINT(buffer, "%s %s", argv[0], enter_string); + fp = popen(buffer, "r"); + if (fp) + { + while(fgets(logline[logcur % LOGLINES], sizeof(logline[0]), fp)) + logline[logcur++ % LOGLINES][sizeof(logline[0])-1] = '\0'; + pclose(fp); + } else + { + SPRINT(logline[logcur++ % LOGLINES], "failed to execute '%s'", buffer); + } + } + logline[logcur % LOGLINES][0] = '\0'; + enter_string[0] = '\0'; + goto again; + } + if (ch>=32 && ch<=126) + { + SCCAT(enter_string, ch); + ch = getch(); + if (ch > 0) + goto enter_again; + goto again; + } else + if (ch==8 || ch==127) + { + if (enter_string[0]) + enter_string[strlen(enter_string)-1] = '\0'; + ch = getch(); + if (ch > 0) + goto enter_again; + goto again; + } else + if (ch != 3) + { + ch = getch(); + if (ch > 0) + goto enter_again; + FD_ZERO(&select_rfds); + FD_SET(0, &select_rfds); + select_tv.tv_sec = 0; + select_tv.tv_usec = 250000; + select(1, &select_rfds, NULL, NULL, &select_tv); + goto again; + } + } else + { + /* user input in normal mode */ + switch(getch()) + { + case 12: /* refresh */ + cleanup_curses(); + init_curses(); + goto again; + break; + + case 3: /* abort */ + case 'q': + case 'Q': + break; + + case 'i': /* toggle interface */ + show_interfaces++; + if (show_interfaces > 3) show_interfaces = 0; + goto again; + + case 'c': /* toggle calls */ + show_calls++; + if (show_calls > 2) show_calls = 0; + goto again; + + case 'l': /* toggle log */ + show_log++; + if (show_log > 1) show_log = 0; + goto again; + + case '+': /* scroll down */ + offset++; + goto again; + + case '-': /* scroll up */ + if (offset) + offset--; + goto again; + + case '*': /* scroll right */ + hoffset += 2; + goto again; + + case '/': /* scroll left */ + if (hoffset) + hoffset -= 2; + goto again; + + case 10: /* entermode */ + enter = 1; + goto again; + + default: + FD_ZERO(&select_rfds); + FD_SET(0, &select_rfds); + select_tv.tv_sec = 0; + select_tv.tv_usec = 250000; + select(1, &select_rfds, NULL, NULL, &select_tv); + goto again; + } + } + + /* check for logfh */ + if (logfh >= 0) + close(logfh); + logfh = -1; + + /* cleanup curses and exit */ + cleanup_curses(); + + return(NULL); +} + + +/* + * Send command and show error message. + */ +char *admin_cmd(int sock, int mode, char *extension, char *number) +{ + static struct admin_message msg; + + /* send reload command */ + memset(&msg, 0, sizeof(msg)); + switch(mode) + { + case MODE_INTERFACE: + msg.message = ADMIN_REQUEST_CMD_INTERFACE; + break; + case MODE_ROUTE: + msg.message = ADMIN_REQUEST_CMD_ROUTE; + break; + case MODE_DIAL: + msg.message = ADMIN_REQUEST_CMD_DIAL; + SPRINT(msg.u.x.message, "%s:%s", extension?:"", number?:""); + break; + case MODE_RELEASE: + msg.message = ADMIN_REQUEST_CMD_RELEASE; + SCPY(msg.u.x.message, number); + break; + case MODE_UNBLOCK: + msg.message = ADMIN_REQUEST_CMD_BLOCK; + msg.u.x.portnum = atoi(number); + msg.u.x.block = 0; + break; + case MODE_BLOCK: + msg.message = ADMIN_REQUEST_CMD_BLOCK; + msg.u.x.portnum = atoi(number); + msg.u.x.block = 1; + break; + case MODE_UNLOAD: + msg.message = ADMIN_REQUEST_CMD_BLOCK; + msg.u.x.portnum = atoi(number); + msg.u.x.block = 2; + break; + } + + if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) + return("Broken pipe while sending command."); + + /* receive response */ + if (read(sock, &msg, sizeof(msg)) != sizeof(msg)) + return("Broken pipe while receiving response."); + switch(mode) + { + case MODE_INTERFACE: + if (msg.message != ADMIN_RESPONSE_CMD_INTERFACE) + return("Response not valid."); + break; + case MODE_ROUTE: + if (msg.message != ADMIN_RESPONSE_CMD_ROUTE) + return("Response not valid."); + break; + case MODE_DIAL: + if (msg.message != ADMIN_RESPONSE_CMD_DIAL) + return("Response not valid."); + break; + case MODE_RELEASE: + if (msg.message != ADMIN_RESPONSE_CMD_RELEASE) + return("Response not valid."); + break; + case MODE_UNBLOCK: + case MODE_BLOCK: + case MODE_UNLOAD: + if (msg.message != ADMIN_RESPONSE_CMD_BLOCK) + return("Response not valid."); + break; + } + + /* process response */ + if (msg.u.x.error) + { + return(msg.u.x.message); + } + printf("Command successfull.\n"); + return(NULL); +} + + +/* + * makes a testcall + */ +#define GET_NOW() { \ + gettimeofday(&now_tv, &now_tz); \ + now_d = ((double)(now_tv.tv_usec))/1000000 + now_tv.tv_sec; \ + } +char *admin_testcall(int sock, int argc, char *argv[]) +{ + static struct admin_message msg; + int ar = 2; + int stimeout = 0, ptimeout = 0, atimeout = 0, ctimeout = 0; + int l; + double timer = 0, now_d; + unsigned long on = 1; + struct timeval now_tv; + struct timezone now_tz; + + printf("pid=%d\n", getpid()); fflush(stdout); + + while (argc > ar) + { + if (!strcmp(argv[ar], "--setup-timeout")) + { + ar++; + if (argc == ar) + return("Missing setup timeout value.\n"); + stimeout = atoi(argv[ar]); + ar++; + } else + if (!strcmp(argv[ar], "--proceeding-timeout")) + { + ar++; + if (argc == ar) + return("Missing proceeding timeout value.\n"); + ptimeout = atoi(argv[ar]); + ar++; + } else + if (!strcmp(argv[ar], "--alerting-timeout")) + { + ar++; + if (argc == ar) + return("Missing alerting timeout value.\n"); + atimeout = atoi(argv[ar]); + ar++; + } else + if (!strcmp(argv[ar], "--connect-timeout")) + { + ar++; + if (argc == ar) + return("Missing connect timeout value.\n"); + ctimeout = atoi(argv[ar]); + ar++; + } else + { + break; + } + } + + /* send reload command */ + memset(&msg, 0, sizeof(msg)); + msg.message = ADMIN_CALL_SETUP; + msg.u.call.present = 1; + + if (argc > ar) + { + SCPY(msg.u.call.interface, argv[ar]); + } + ar++; + if (argc > ar) + { + SCPY(msg.u.call.callerid, argv[ar]); + } + ar++; + if (argc > ar) + { + SCPY(msg.u.call.dialing, argv[ar]); + } + ar++; + if (argc > ar) + { + if (argv[ar][0] == 'r') + msg.u.call.present = 0; + } + ar++; + msg.u.call.bc_capa = 0x00; /*INFO_BC_SPEECH*/ + msg.u.call.bc_mode = 0x00; /*INFO_BMODE_CIRCUIT*/ + msg.u.call.bc_info1 = 0; + msg.u.call.hlc = 0; + msg.u.call.exthlc = 0; + if (argc > ar) + msg.u.call.bc_capa = strtol(argv[ar],NULL,0); + else + msg.u.call.bc_info1 = 3 | 0x80; /* alaw, if no capability is given at all */ + ar++; + if (argc > ar) { + msg.u.call.bc_mode = strtol(argv[ar],NULL,0); + if (msg.u.call.bc_mode) msg.u.call.bc_mode = 2; + } + ar++; + if (argc > ar) { + msg.u.call.bc_info1 = strtol(argv[ar],NULL,0); + if (msg.u.call.bc_info1 < 0) + msg.u.call.bc_info1 = 0; + else + msg.u.call.bc_info1 |= 0x80; + } + ar++; + if (argc > ar) { + msg.u.call.hlc = strtol(argv[ar],NULL,0); + if (msg.u.call.hlc < 0) + msg.u.call.hlc = 0; + else + msg.u.call.hlc |= 0x80; + } + ar++; + if (argc > ar) { + msg.u.call.exthlc = strtol(argv[ar],NULL,0); + if (msg.u.call.exthlc < 0) + msg.u.call.exthlc = 0; + else + msg.u.call.exthlc |= 0x80; + } + ar++; + + if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) + return("Broken pipe while sending command."); + + if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0) + return("Failed to set socket into non-blocking IO."); + + if (stimeout) + { + GET_NOW(); + timer = now_d + (double)stimeout; + } + + /* receive response */ +next: + l = read(sock, &msg, sizeof(msg)); + if (l < 0) + { + if (errno == EWOULDBLOCK) + { + if (timer) + { + GET_NOW(); + if (timer <= now_d) + { + printf("Timeout\n"); fflush(stdout); + return(NULL); + } + } + usleep(30000); + goto next; + } + return("Broken pipe while receiving response."); + } + if (l != sizeof(msg)) + return("Response has unexpected message size."); + switch(msg.message) + { + case ADMIN_CALL_SETUP_ACK: + printf("SETUP ACKNOWLEDGE\n"); fflush(stdout); + goto next; + + case ADMIN_CALL_PROCEEDING: + printf("PROCEEDING\n"); fflush(stdout); + if (ptimeout) + { + GET_NOW(); + timer = now_d + (double)ptimeout; + } + goto next; + + case ADMIN_CALL_ALERTING: + printf("ALERTING\n"); fflush(stdout); + if (atimeout) + { + GET_NOW(); + timer = now_d + (double)atimeout; + } + goto next; + + case ADMIN_CALL_CONNECT: + printf("CONNECT\n number=%s\n", msg.u.call.callerid); fflush(stdout); + if (ctimeout) + { + GET_NOW(); + timer = now_d + (double)ctimeout; + } + goto next; + + case ADMIN_CALL_NOTIFY: + printf("NOTIFY\n notify=%d\n number=%s\n", msg.u.call.notify, msg.u.call.callerid); fflush(stdout); + goto next; + + case ADMIN_CALL_DISCONNECT: + printf("DISCONNECT\n cause=%d %s\n location=%d %s\n", msg.u.call.cause, (msg.u.call.cause>0 && msg.u.call.cause<128)?isdn_cause[msg.u.call.cause].german:"", msg.u.call.location, (msg.u.call.location>=0 && msg.u.call.location<128)?isdn_location[msg.u.call.location].german:""); fflush(stdout); + break; + + case ADMIN_CALL_RELEASE: + printf("RELEASE\n cause=%d %s\n location=%d %s\n", msg.u.call.cause, (msg.u.call.cause>0 && msg.u.call.cause<128)?isdn_cause[msg.u.call.cause].german:"", msg.u.call.location, (msg.u.call.location>=0 && msg.u.call.location<128)?isdn_location[msg.u.call.location].german:""); fflush(stdout); + break; + + default: + return("Response not valid."); + } + + printf("Call released.\n"); fflush(stdout); + return(NULL); +} + + +/* + * makes a trace + */ +char *admin_trace(int sock, int argc, char *argv[]) +{ + static struct admin_message msg; + int i; + + /* show help */ + if (argc > 2) if (!strcasecmp(argv[2], "help")) + { + printf("Trace Help\n----------\n"); + printf("%s trace [brief|short] [= [...]]\n\n", argv[0]); + printf("By default a complete trace is shown in detailed format.\n"); + printf("To show a more compact format, use 'brief' or 'short' keyword.\n"); + printf("Use filter values to select specific trace messages.\n"); + printf("All given filter values must match. If no filter is given, anything matches.\n\n"); + printf("Filters:\n"); + printf(" category=\n"); + printf(" 0x01 = CH: channel object trace\n"); + printf(" 0x02 = EP: endpoint object trace\n"); + printf(" port= select only given port for trace\n"); + printf(" interface= select only given interface for trace\n"); + printf(" caller= select only given caller id for trace\n"); + printf(" dialing= select only given dialed number for trace\n"); + return(NULL); + } + + /* init trace request */ + memset(&msg, 0, sizeof(msg)); + msg.message = ADMIN_TRACE_REQUEST; + msg.u.trace_req.detail = 3; + + /* parse args */ + i = 2; + while(i < argc) + { + if (!strcasecmp(argv[i], "brief")) + msg.u.trace_req.detail = 1; + else if (!strcasecmp(argv[i], "short")) + msg.u.trace_req.detail = 2; + else if (!strncasecmp(argv[i], "category=", 9)) + msg.u.trace_req.category = atoi(argv[i]+9); + else if (!strncasecmp(argv[i], "port=", 5)) + msg.u.trace_req.port = atoi(argv[i]+5); + else if (!strncasecmp(argv[i], "interface=", 10)) + SCPY(msg.u.trace_req.interface, argv[i]+10); + else if (!strncasecmp(argv[i], "caller=", 7)) + SCPY(msg.u.trace_req.caller, argv[i]+7); + else if (!strncasecmp(argv[i], "dialing=", 8)) + SCPY(msg.u.trace_req.dialing, argv[i]+8); + else return("Invalid trace option, try 'trace help'."); + + i++; + } + + /* send trace request */ + if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) + return("Broken pipe while sending trace request."); + + /* receive response */ +next: + if (read(sock, &msg, sizeof(msg)) != sizeof(msg)) + return("Broken pipe while receiving response."); + + if (msg.message != ADMIN_TRACE_RESPONSE) + return("Response not valid."); + + printf("%s", msg.u.trace_rsp.text); + goto next; +} + + +/* + * main function + */ +int main(int argc, char *argv[]) +{ + int mode; + char *socket_name = SOCKET_NAME; + int sock, conn; + struct sockaddr_un sock_address; + char *ret; + + + /* show options */ + if (argc <= 1) + { + usage: + printf("\n"); + printf("Usage: %s state | interface | route | dial ...\n", argv[0]); + printf("state - View current states using graphical console output.\n"); + printf("interface - Tell LCR to reload \"interface.conf\".\n"); + printf("route - Tell LCR to reload \"route.conf\".\n"); + printf("dial - Tell LCR the next number to dial for extension.\n"); + printf("release - Tell LCR to release endpoint with given number.\n"); + printf("block - Block given port.\n"); + printf("unblock - Unblock given port.\n"); + printf("unload - Unload port. To load port use 'block' or 'unblock'.\n"); + printf("testcall [options] [present|restrict []] - Testcall\n"); + printf(" -> options = --setup-timeout --proceeding-timeout \n"); + printf(" --alerting-timeout --connect-timeout \n"); + printf(" -> capability = (Values must be numbers, -1 to omit.)\n"); + printf("trace [brief|short] [ [...]] - Shows call trace. Use filter to reduce output.\n"); + printf(" -> Use 'trace help' to see filter description.\n"); + printf("\n"); + return(0); + } + + /* check mode */ + if (!(strcasecmp(argv[1],"state"))) + { + mode = MODE_STATE; + } else + if (!(strcasecmp(argv[1],"interface"))) + { + mode = MODE_INTERFACE; + } else + if (!(strcasecmp(argv[1],"route"))) + { + mode = MODE_ROUTE; + } else + if (!(strcasecmp(argv[1],"dial"))) + { + if (argc <= 3) + goto usage; + mode = MODE_DIAL; + } else + if (!(strcasecmp(argv[1],"release"))) + { + if (argc <= 2) + goto usage; + mode = MODE_RELEASE; + } else + if (!(strcasecmp(argv[1],"unblock"))) + { + if (argc <= 2) + goto usage; + mode = MODE_UNBLOCK; + } else + if (!(strcasecmp(argv[1],"block"))) + { + if (argc <= 2) + goto usage; + mode = MODE_BLOCK; + } else + if (!(strcasecmp(argv[1],"unload"))) + { + if (argc <= 2) + goto usage; + mode = MODE_UNLOAD; + } else + if (!(strcasecmp(argv[1],"testcall"))) + { + if (argc <= 4) + goto usage; + mode = MODE_TESTCALL; + } else + if (!(strcasecmp(argv[1],"trace"))) + { + mode = MODE_TRACE; + } else + { + goto usage; + } + +//pipeagain: + /* open socket */ + if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) + { + fprintf(stderr, "Failed to create socket.\n"); + exit(EXIT_FAILURE); + } + memset(&sock_address, 0, sizeof(sock_address)); + sock_address.sun_family = PF_UNIX; + UCPY(sock_address.sun_path, socket_name); + if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0) + { + close(sock); + fprintf(stderr, "Failed to connect to socket \"%s\".\nIs LCR running?\n", sock_address.sun_path); + exit(EXIT_FAILURE); + } + + /* process mode */ + switch(mode) + { + case MODE_STATE: + ret = admin_state(sock, argv); + break; + + case MODE_INTERFACE: + case MODE_ROUTE: + ret = admin_cmd(sock, mode, NULL, NULL); + break; + + case MODE_DIAL: + ret = admin_cmd(sock, mode, argv[2], argv[3]); + break; + + case MODE_RELEASE: + case MODE_UNBLOCK: + case MODE_BLOCK: + case MODE_UNLOAD: + ret = admin_cmd(sock, mode, NULL, argv[2]); + break; + + case MODE_TESTCALL: + ret = admin_testcall(sock, argc, argv); + break; + + case MODE_TRACE: + ret = admin_trace(sock, argc, argv); + break; + } + + close(sock); + /* now we say good bye */ + if (ret) + { +// if (!strncasecmp(ret, "Broken Pipe", 11)) +// goto pipeagain; + printf("%s\n", ret); + exit(EXIT_FAILURE); + } +} + + + + + -- cgit v1.2.3-55-g7522