/* * $Id: divertctrl.c,v 1.5 2002/07/04 10:36:54 paul Exp $ * * Control program for the dss1 diversion supplementary services. (User side) * * Copyright 1999 by Werner Cornelius (werner@ikt.de) * * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: divertctrl.c,v $ * Revision 1.5 2002/07/04 10:36:54 paul * Include stdlib.h for prototypes; * Make some things depend on NETWORK_DIAL define. * * Revision 1.4 2001/06/10 17:38:25 werner * * Updated tool and manpage with new remote dial feature * * Revision 1.3 2001/01/09 19:27:55 werner * * Added Output for interrogate and description for services. * Thanks for help from Wolfram Joost. * * Revision 1.2 1999/09/02 13:24:14 paul * fixed some compile warnings * * Revision 1.1 1999/05/07 21:33:01 werner * Initial release of divertctrl * * */ #include #include #include #include #include #include #include #include #include "isdn_divert.h" static char number_types[7] = { 'U', 'I', 'N', 'S', 'M', '?', 'A' }; static char cf_types[4][5] = { "CFU", "CFB", "CFNR", "?" }; static struct { unsigned type; char *name; } service_types[18] = { { 0, "all services" }, { 1, "speech" }, { 2, "unrestricted digital information" }, { 3, "audio 3.1 kHz" }, { 4, "unrestricted digital information wtaa" }, { 5, "multirate" }, { 32, "telephony 3.1 kHz" }, { 33, "teletex" }, { 34, "telefax group 4 class 1" }, { 35, "videotex syntax based" }, { 36, "videotelephony" }, { 37, "telefax group 2/3" }, { 38, "telephony 7 kHz" }, { 39, "eurofiletransfer" }, { 40, "filetransfer and access management" }, { 41, "videoconference" }, { 42, "audio graphic conference" } }; char *progname; /* name of program */ ulong drvid; /* ids of driver */ int fd; /* file descriptor for read and ioctl */ divert_ioctl dioctl; /* structure exchanging ioctl data */ char **argp; /* pointer to actual parameter */ int argrest; /* remaining args */ int waitreq; /* wait requested */ int exitcode;/* exitcode for program */ /****************************/ /* print a short usage help */ /****************************/ void usage(void) { close(fd); fprintf(stderr,"usage: %s [wait] [parms]\n\n",progname); fprintf(stderr,"[wait] : wait optional keyword until -> wait until command executed \n"); fprintf(stderr," : desired command to execute\n"); fprintf(stderr," activate \n"); fprintf(stderr," deactivate \n"); fprintf(stderr," interrogate \n"); fprintf(stderr," listrules -> list all rules for drivers\n"); fprintf(stderr," ignore [uus1_string] -> ignore call with callid/send uus1\n"); fprintf(stderr," alert [uus1_string] -> alert call with callid/send uus1\n"); fprintf(stderr," deflect [to_nr] -> deflect call with callid to to_nr \n"); fprintf(stderr," appendrule -> append a rule at list end\n"); fprintf(stderr," insertrule -> insert a rule at list start\n"); fprintf(stderr," flushrules [drivers] -> flush all rules for specified drivers\n"); fprintf(stderr," append- and insertrule take the following arguments:\n"); #ifdef NETWORK_DIAL fprintf(stderr," [msn] [si1] [si2] [caller] [screen] [delay] [callopt] [destnr/if]\n"); #else fprintf(stderr," [msn] [si1] [si2] [caller] [screen] [delay] [callopt] [destnr]\n"); #endif fprintf(stderr," drivers -> driver names for D-chans, %% separated, - = all D-chan\n"); fprintf(stderr," action -> 0/ignore 1/report 2/proceed 3/alert 4/reject\n"); fprintf(stderr," msn -> - = wildcard or explicit selected msn.subaddress\n"); fprintf(stderr," when action = 5 then if specifies a network interface to dial\n"); fprintf(stderr," si1 -> 0 = all services, else bitmask for services 1..7\n"); fprintf(stderr," si2 -> 0 = ignore, else specified value\n"); fprintf(stderr," caller -> - = wildcard, 0 = unknown, else number.subaddress\n"); fprintf(stderr," a - trailing number digits is handled as wildcard\n"); fprintf(stderr," screen -> 0 = noscreen 1 = divertonly 2 = divertto\n"); fprintf(stderr," delay -> time in seconds until hangup or divert in auto mode\n"); fprintf(stderr," callopt -> 0 = all calls, 1 = only non waiting, 2 = only waiting\n"); fprintf(stderr," destnr -> destination number and subaddress\n"); fprintf(stderr," defaults: allmsn, si1=0, si2=0, all callers, noscreen, delay=10\n"); fprintf(stderr,"\n"); exit(-1); } /* usage */ /******************************************/ /* get the driver parameter and set drvid */ /******************************************/ void getdrvid(void) { char *p,*p1; argp++; argrest--; if (argrest < 1) { drvid = DEFLECT_ALL_IDS; return; } if ((*argp)[0] == '-') drvid = DEFLECT_ALL_IDS; else { drvid = 0; /* first no device */ p = *argp; while (p) { p1 = p; p = strchr(p1,'%'); if (p) *p++ = '\0'; strcpy(dioctl.getid.drvnam,p1); /* set string to query */ if (ioctl(fd,IIOCGETDRV,&dioctl)) { fprintf(stderr,"driver %s not found \n",p1); close(fd); exit(-1); } drvid |= (1L << dioctl.getid.drvid); } } argp++; argrest--; } /* getdrvid */ /***********************************/ /* set the rule pars from cmd line */ /***********************************/ void setrulepar(void) { divert_rule *dr = &dioctl.getsetrule.rule; unsigned u; /* first set the defaults */ dr->drvid = 0; /* no driver */ dr->action= DEFLECT_IGNORE; strcpy(dr->my_msn,"0"); dr->si1 = 0; dr->si2 = 0; strcpy(dr->caller,"-"); dr->screen= 0; /* no screening */ dr->waittime = 0; dr->callopt = 0; dr->to_nr[0] = '\0'; if (!argrest) return; /* action */ if ((sscanf(*(argp),"%u",&u) <= 0) || (u > 5)) { fprintf(stderr,"invalid action value %s\n",*argp); usage(); } dr->action = u & 0xFF; #ifdef NETWORK_DIAL if (((dr->action == DEFLECT_ALERT) || (dr->action == NETWORK_DIAL)) && (argrest != 9)) #else if ((dr->action == DEFLECT_ALERT) && (argrest != 9)) #endif { fprintf(stderr,"alerting/dialing action must be supplied with all parms\n"); usage(); } if (!--argrest) return; /* copy msn */ strcpy(dr->my_msn, *(++argp)); if (!--argrest) return; /* si1 */ if (sscanf(*(++argp),"%u",&u) <= 0) { fprintf(stderr,"invalid si1 value %s\n",*argp); usage(); } dr->si1 = u & 0xFF; if (!--argrest) return; /* si2 */ if (sscanf(*(++argp),"%u",&u) <= 0) { fprintf(stderr,"invalid si2 value %s\n",*argp); usage(); } dr->si2 = u & 0xFF; if (!--argrest) return; /* caller */ strcpy(dr->caller,*(++argp)); if (!--argrest) return; /* screen */ if ((sscanf(*(++argp),"%u",&u) <= 0) || (u > 2)) { fprintf(stderr,"invalid screen value %s\n",*argp); usage(); } dr->screen = u & 0xFF; if (!--argrest) return; /* delay */ if ((sscanf(*(++argp),"%u",&u) <= 0) || (u > 99)) { fprintf(stderr,"invalid delay value %s\n",*argp); usage(); } dr->waittime = u & 0xFF; if (!--argrest) return; /* callopt */ if ((sscanf(*(++argp),"%u",&u) <= 0) || (u > 2)) { fprintf(stderr,"invalid callopt value %s\n",*argp); usage(); } dr->callopt = u & 0xFF; if (!--argrest) return; /* to_nr */ strcpy(dr->to_nr,*(++argp)); if (!--argrest) return; fprintf(stderr,"to many cmd line parms\n"); usage(); } /* setrulepar */ /************************************************/ /* getcallid fetches the callid for id commands */ /************************************************/ void getcallid(void) { argp++; argrest--; if (argrest < 1) { fprintf(stderr,"callid missing\n"); usage(); } if (sscanf(*argp,"%lu",&dioctl.fwd_ctrl.callid) != 1) { fprintf(stderr,"invalid callid value %s\n",*argp); usage(); } argp++; argrest--; } /* getcallid */ /***************************************************************************/ /* getcfpar fetches the parms for de/activating and interrogating services */ /***************************************************************************/ #define CFP dioctl.cf_ctrl void getcfpar(void) { unsigned u; /* first set the defaults */ CFP.service = 0; /* all services */ CFP.msn[0] = '\0'; /* all msns */ CFP.fwd_nr[0] = '\0'; if (!argrest) { fprintf(stderr,"no procedure specified \n"); usage(); } if (!strcmp(*argp,"cfu")) CFP.cfproc = 0; else if (!strcmp(*argp,"cfb")) CFP.cfproc = 1; else if (!strcmp(*argp,"cfnr")) CFP.cfproc = 2; else { fprintf(stderr,"invalid procedure %s\n",*argp); usage(); } if (waitreq) CFP.cfproc |= 0x80; argp++; argrest--; strcpy(CFP.msn,*(argp++)); if (!(--argrest)) return; if ((sscanf(*argp,"%u",&u) != 1) || (u > 255)) { fprintf(stderr,"invalid service [0-255] %s\n",*argp); usage(); } CFP.service = u & 0xFF; argrest--; argp++; } /* getcfpar */ #undef CFP /********************/ /* execute commands */ /********************/ static void do_command(void) { divert_rule *dr = &dioctl.getsetrule.rule; divert_ioctl ioc; int i; ulong u,cmd; fd_set rdfs; struct timeval tv; char read_buf[512]; ssize_t read_len; char *read_ptr; ulong read_procid; ulong read_counter; char read_driver[30]; u_long read_msn_type; char read_msn[35]; u_long read_cfproc; u_long read_service; u_long read_tonr_type; char read_tonr[35]; int read_char_count; char read_end; char read_found; if (!strcmp(*argp,"listrules")) { getdrvid(); dioctl.getsetrule.ruleidx = 0; /* get first rule */ while (1) { /* fetch all rules */ if (ioctl(fd,IIOCGETRULE,&dioctl)) return; /* no more rules */ i = 0; /* first interface */ dr->drvid = drvid & dr->drvid; /* only requested bits */ while (dr->drvid) { if (!(dr->drvid & 1)) { dr->drvid >>= 1; /* next entry */ i++; continue; } if (dr->drvid == DEFLECT_ALL_IDS) { printf("%10s","-"); /* all if */ dr->drvid = 0; /* no further output */ } else { ioc.getid.drvid = i++; /* set para */ dr->drvid >>= 1; if (ioctl(fd,IIOCGETNAM,&ioc)) continue; /* invalid driver */ if (!ioc.getid.drvnam[0]) continue; /* no name */ printf("%10s ",ioc.getid.drvnam); } printf("%15s %20s %2d %3d %d %2d %d %s\n", dr->my_msn, /* msn */ dr->caller, /* caller id */ dr->si1, /* si1 0 = all */ dr->si2, /* si2 0 = all */ dr->action, /* desired action */ dr->waittime,/* wait until action */ dr->callopt, /* option for waiting calls */ dr->to_nr); /* deflect to */ } /* interface match */ dioctl.getsetrule.ruleidx++; /* next rule */ } /* fetch all rules */ } /* listrules */ else if (!strcmp(*argp,"deflect")) { getcallid(); dioctl.fwd_ctrl.subcmd = 2; if (argrest) { strcpy(dioctl.fwd_ctrl.to_nr,*argp); argp++; argrest--; } else dioctl.fwd_ctrl.to_nr[0] = '\0'; exitcode = ioctl(fd,IIOCDODFACT,&dioctl); } /* deflect */ else if (!strcmp(*argp,"alert")) { getcallid(); dioctl.fwd_ctrl.subcmd = 1; if (argrest) { strcpy(dioctl.fwd_ctrl.to_nr,*argp); argp++; argrest--; } else dioctl.fwd_ctrl.to_nr[0] = '\0'; exitcode = ioctl(fd,IIOCDODFACT,&dioctl); } /* alert */ else if (!strcmp(*argp,"ignore")) { getcallid(); dioctl.fwd_ctrl.subcmd = 0; if (argrest) { strcpy(dioctl.fwd_ctrl.to_nr,*argp); argp++; argrest--; } else dioctl.fwd_ctrl.to_nr[0] = '\0'; exitcode = ioctl(fd,IIOCDODFACT,&dioctl); } /* ignore */ else if (!strcmp(*argp,"insertrule")) { getdrvid(); setrulepar(); dioctl.getsetrule.ruleidx = 0; /* start of list */ dr->drvid = drvid; /* driver id */ ioctl(fd,IIOCINSRULE,&dioctl); } /* insertrule */ else if (!strcmp(*argp,"appendrule")) { getdrvid(); setrulepar(); dioctl.getsetrule.ruleidx = -1; /* end of list */ dr->drvid = drvid; /* driver id */ ioctl(fd,IIOCINSRULE,&dioctl); } /* appendrule */ else if (!strcmp(*argp,"flushrules")) { getdrvid(); dioctl.getsetrule.ruleidx = 0; /* start of list */ while (1) { /* fetch all rules */ if (ioctl(fd,IIOCGETRULE,&dioctl)) return; /* no more rules */ if (drvid & dr->drvid) { dr->drvid &= ~drvid; /* delete drivers */ if (dr->drvid) { ioctl(fd,IIOCMODRULE,&dioctl); dioctl.getsetrule.ruleidx++; } else ioctl(fd,IIOCDELRULE,&dioctl); } else dioctl.getsetrule.ruleidx++; } /* fetch all rules */ } /* flushrules */ else if ((!strcmp(*argp,"activate")) || (!strcmp(*argp,"deactivate")) || (!strcmp(*argp,"interrogate"))) { if (*argp[0] == 'a') cmd = IIOCDOCFACT; else if (*argp[0] == 'i') cmd = IIOCDOCFINT; else cmd = IIOCDOCFDIS; getdrvid(); getcfpar(); dioctl.cf_ctrl.fwd_nr[0] = '\0'; if (cmd == IIOCDOCFACT) { if (!argrest) { fprintf(stderr,"missing diverted to number \n"); usage(); } strcpy(dioctl.cf_ctrl.fwd_nr,*(argp++)); argrest--; } /* only activate */ dioctl.cf_ctrl.drvid = 0; u = drvid; /* list of drivers */ while (u) { if (u & 1) { if ((exitcode = ioctl(fd,cmd,&dioctl)) > 0) return; /* error executing diversion */ else if ((exitcode < 0) && (drvid != DEFLECT_ALL_IDS)) return; read_end = 0; read_found = 0; while ( !read_end && (cmd == IIOCDOCFINT) ) { FD_ZERO(&rdfs); FD_SET(fd,&rdfs); tv.tv_sec = 4; tv.tv_usec = 0; if (select(fd+1,&rdfs,NULL,NULL,&tv) != 1) { break; } read_len = read(fd,read_buf,sizeof(read_buf)-1); if (read_len) { read_buf[read_len] = 0; read_ptr = read_buf; while (*read_ptr) { if ( ((*read_ptr != (DIVERT_REPORT | 0x30)) || (read_ptr[1] != ' ')) && strncmp(read_ptr,"128 ",4) ) { while (*read_ptr && (*read_ptr != '\r')) read_ptr++; if (*read_ptr) read_ptr++; continue; } if ( !strncmp(read_ptr,"128 ",4)) { sscanf(read_ptr + 4,"%lx",&read_procid); if (read_procid == dioctl.cf_ctrl.procid) { puts("Error. :-("); read_end = 1; break; } } else { read_ptr += 2; sscanf(read_ptr,"%lx %lu %s %lu %s %lx %lu %n", &read_procid,&read_counter,read_driver, &read_msn_type,read_msn,&read_service,&read_cfproc, &read_char_count); read_ptr += read_char_count; read_end = (read_procid == dioctl.cf_ctrl.procid) && !read_counter; if (read_end) { if (!read_found) puts("Nothing active."); break; } if ( read_procid == dioctl.cf_ctrl.procid ) { sscanf(read_ptr,"%lu %s",&read_tonr_type,read_tonr); if (read_msn_type > 6) read_msn_type = 5; if (read_tonr_type > 6) read_tonr_type = 5; if (read_cfproc > 3) read_cfproc = 3; read_found = 1; printf("%-8s %c %-8s %-4s %c %-10s ",read_driver, number_types[read_msn_type],read_msn, cf_types[read_cfproc], number_types[read_tonr_type],read_tonr); for (read_char_count = 0; read_char_count < 18; read_char_count++) { if (service_types[read_char_count].type == read_service) { puts(service_types[read_char_count].name); break; } } if (read_char_count == 18) puts("unknown"); } } while (*read_ptr && (*read_ptr != '\r')) read_ptr++; if (*read_ptr) read_ptr++; } } } exitcode = 0; } u >>= 1; /* next driver */ dioctl.cf_ctrl.drvid++; } /* for all drivers */ } /* activate */ else { fprintf(stderr,"unknown command: %s\n",*argp); usage(); } } /* do_command */ int main(int argc, char *argv[]) { exitcode = 0; /* default no error */ /* first get our own program name */ if ((progname = strrchr(argv[0], '/'))) progname++; else progname = argv[0]; /* now open the interface */ if ((fd = open("/proc/net/isdn/divert", O_RDWR)) < 0) { if ((fd = open("/dev/isdndivert", O_RDWR)) < 0) { fprintf(stderr,"error opening device (dss1_divert module not loaded ?)\n"); exit(-1); } } /* check the interface version */ dioctl.drv_version = -1; /* invalidate */ if (ioctl(fd,IIOCGETVER,&dioctl)) { fprintf(stderr,"could not execute ioctl call \n"); close(fd); exit(-1); } if ( dioctl.drv_version != DIVERT_IIOC_VERSION) { fprintf(stderr,"versions of %s and driver incompatible\n",progname); close(fd); exit(-1); } argrest = argc - 1; /* remaining number of parameters */ argp = argv + 1; /* pointer to next parameter/command */ waitreq = 0; /* if no wait desired */ if (argrest >= 1) if (!strcmp(*argp,"wait")) { waitreq = 1; argp++; argrest--; } /* a minimum of 1 additional cmd line parameters is needed */ if (argrest < 1) usage(); do_command(); close(fd); exit(exitcode); } /* main */