Newer
Older
Kevin P. Fleming
committed
* Copyright (C) 2004 - 2006, Christian Richter
*
* Christian Richter <crich@beronet.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*
*/
/*!
* \file
*
* \brief the chan_misdn channel driver for Asterisk
* \author Christian Richter <crich@beronet.com>
*
* \ingroup channel_drivers
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
*/
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <asterisk/channel.h>
#include <asterisk/config.h>
#include <asterisk/logger.h>
#include <asterisk/module.h>
#include <asterisk/pbx.h>
#include <asterisk/options.h>
#include <asterisk/io.h>
#include <asterisk/frame.h>
#include <asterisk/translate.h>
#include <asterisk/cli.h>
#include <asterisk/musiconhold.h>
#include <asterisk/dsp.h>
#include <asterisk/translate.h>
#include <asterisk/config.h>
#include <asterisk/file.h>
#include <asterisk/callerid.h>
#include <asterisk/indications.h>
#include <asterisk/app.h>
#include <asterisk/features.h>
#include <asterisk/stringfields.h>
#include <chan_misdn_config.h>
#include <isdn_lib.h>
#define release_lock ast_mutex_lock(&release_lock_mutex)
#define release_unlock ast_mutex_unlock(&release_lock_mutex)
char global_tracefile[BUFFERSIZE+1];
Christian Richter
committed
struct misdn_jb{
int size;
int upper_threshold;
char *samples, *ok;
int wp,rp;
int state_empty;
int state_full;
int state_buffer;
int bytes_wrote;
ast_mutex_t mutexjb;
};
void export_ies(struct ast_channel *chan, struct misdn_bchannel *bc);
void import_ies(struct ast_channel *chan, struct misdn_bchannel *bc);
Christian Richter
committed
/* allocates the jb-structure and initialise the elements*/
struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
/* frees the data and destroys the given jitterbuffer struct */
void misdn_jb_destroy(struct misdn_jb *jb);
/* fills the jitterbuffer with len data returns < 0 if there was an
error (bufferoverun). */
int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len);
/* gets len bytes out of the jitterbuffer if available, else only the
available data is returned and the return value indicates the number
of data. */
int misdn_jb_empty(struct misdn_jb *jb, char *data, int len);
/* BEGIN: chan_misdn.h */
enum tone_e {
TONE_NONE=0,
TONE_DIAL,
TONE_ALERTING,
TONE_BUSY,
TONE_CUSTOM,
TONE_FILE
};
enum misdn_chan_state {
MISDN_NOTHING, /*!< at beginning */
MISDN_WAITING4DIGS, /*!< when waiting for infos */
MISDN_EXTCANTMATCH, /*!< when asterisk couldnt match our ext */
MISDN_DIALING, /*!< when pbx_start */
MISDN_PROGRESS, /*!< we got a progress */
Christian Richter
committed
MISDN_PROCEEDING, /*!< we got a progress */
MISDN_CALLING, /*!< when misdn_call is called */
MISDN_CALLING_ACKNOWLEDGE, /*!< when we get SETUP_ACK */
MISDN_ALERTING, /*!< when Alerting */
MISDN_BUSY, /*!< when BUSY */
MISDN_CONNECTED, /*!< when connected */
Christian Richter
committed
MISDN_DISCONNECTED, /*!< when connected */
MISDN_BRIDGED, /*!< when bridged */
MISDN_CLEANING, /*!< when hangup from * but we were connected before */
MISDN_HUNGUP_FROM_MISDN, /*!< when DISCONNECT/RELEASE/REL_COMP cam from misdn */
MISDN_HUNGUP_FROM_AST, /*!< when DISCONNECT/RELEASE/REL_COMP came out of */
/* misdn_hangup */
MISDN_HOLDED, /*!< if this chan is holded */
MISDN_HOLD_DISCONNECT /*!< if this chan is holded */
};
#define ORG_AST 1
#define ORG_MISDN 2
struct chan_list {
enum misdn_chan_state state;
int holded;
int orginator;
int norxtone;
int notxtone;
Christian Richter
committed
int incoming_early_audio;
int pipe[2];
char ast_rd_buf[4096];
struct ast_frame frame;
int faxdetect;
int faxhandled;
int ast_dsp;
Christian Richter
committed
int jb_len;
int jb_upper_threshold;
Christian Richter
committed
struct misdn_jb *jb;
struct ast_dsp *dsp;
struct ast_trans_pvt *trans;
struct ast_channel * ast;
struct misdn_bchannel *bc;
struct misdn_bchannel *holded_bc;
unsigned int l3id;
int addr;
Christian Richter
committed
char context[BUFFERSIZE];
const struct tone_zone_sound *ts;
struct chan_list *peer;
struct chan_list *next;
struct chan_list *prev;
struct chan_list *first;
};
struct robin_list {
char *group;
int port;
int channel;
struct robin_list *next;
struct robin_list *prev;
};
static struct robin_list *robin = NULL;
static inline void free_robin_list_r (struct robin_list *r)
{
Christian Richter
committed
if (r) {
if (r->next) free_robin_list_r(r->next);
if (r->group) free(r->group);
free(r);
}
{
free_robin_list_r(robin);
Christian Richter
committed
static struct robin_list* get_robin_position (char *group)
{
struct robin_list *iter = robin;
for (; iter; iter = iter->next) {
if (!strcasecmp(iter->group, group))
return iter;
}
struct robin_list *new = (struct robin_list *)calloc(1, sizeof(struct robin_list));
new->group = strndup(group, strlen(group));
new->channel = 1;
if (robin) {
new->next = robin;
robin->prev = new;
}
robin = new;
return robin;
}
Christian Richter
committed
static void chan_misdn_log(int level, int port, char *tmpl, ...);
static struct ast_channel *misdn_new(struct chan_list *cl, int state, char *exten, char *callerid, int format, int port, int c);
static void send_digit_to_chan(struct chan_list *cl, char digit );
#define AST_CID_P(ast) ast->cid.cid_num
#define AST_BRIDGED_P(ast) ast_bridged_channel(ast)
#define AST_LOAD_CFG ast_config_load
#define AST_DESTROY_CFG ast_config_destroy
#define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt
#define MISDN_ASTERISK_PVT(ast) 1
#include <asterisk/strings.h>
/* #define MISDN_DEBUG 1 */
Christian Richter
committed
static char *desc = "Channel driver for mISDN Support (Bri/Pri)";
static const char misdn_type[] = "mISDN";
Christian Richter
committed
static int tracing = 0 ;
static int usecnt=0;
Christian Richter
committed
static char **misdn_key_vector=NULL;
static int misdn_key_vector_size=0;
/* Only alaw and mulaw is allowed for now */
static int prefformat = AST_FORMAT_ALAW ; /* AST_FORMAT_SLINEAR ; AST_FORMAT_ULAW | */
static ast_mutex_t usecnt_lock;
Christian Richter
committed
static int *misdn_debug;
static int *misdn_debug_only;
static int max_ports;
struct chan_list dummy_cl;
struct chan_list *cl_te=NULL;
Christian Richter
committed
static enum event_response_e
cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
Christian Richter
committed
static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc);
static void cl_queue_chan(struct chan_list **list, struct chan_list *chan);
static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan);
static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc);
static int tone_indicate( struct chan_list *cl, enum tone_e tone);
static int start_bc_tones(struct chan_list *cl);
static int stop_bc_tones(struct chan_list *cl);
static void release_chan(struct misdn_bchannel *bc);
static int misdn_set_opt_exec(struct ast_channel *chan, void *data);
static int misdn_facility_exec(struct ast_channel *chan, void *data);
Christian Richter
committed
int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
/*************** Helpers *****************/
static struct chan_list * get_chan_by_ast(struct ast_channel *ast)
{
struct chan_list *tmp;
for (tmp=cl_te; tmp; tmp = tmp->next) {
if ( tmp->ast == ast ) return tmp;
}
return NULL;
}
static struct chan_list * get_chan_by_ast_name(char *name)
{
struct chan_list *tmp;
for (tmp=cl_te; tmp; tmp = tmp->next) {
if ( tmp->ast && strcmp(tmp->ast->name,name) == 0) return tmp;
}
return NULL;
}
static char *bearer2str(int cap) {
static char *bearers[]={
"Speech",
"Audio 3.1k",
"Unres Digital",
"Res Digital",
"Unknown Bearer"
};
switch (cap) {
case INFO_CAPABILITY_SPEECH:
return bearers[0];
break;
case INFO_CAPABILITY_AUDIO_3_1K:
return bearers[1];
break;
case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
return bearers[2];
break;
case INFO_CAPABILITY_DIGITAL_RESTRICTED:
return bearers[3];
break;
default:
return bearers[4];
break;
}
}
Christian Richter
committed
static void print_facility( struct misdn_bchannel *bc)
{
switch (bc->fac_type) {
case FACILITY_CALLDEFLECT:
chan_misdn_log(2,bc->port," --> calldeflect: %s\n",
bc->fac.calldeflect_nr);
break;
case FACILITY_CENTREX:
chan_misdn_log(2,bc->port," --> centrex: %s\n",
bc->fac.cnip);
break;
default:
chan_misdn_log(2,bc->port," --> unknown\n");
}
}
static void print_bearer(struct misdn_bchannel *bc)
{
chan_misdn_log(2, bc->port, " --> Bearer: %s\n",bearer2str(bc->capability));
switch(bc->law) {
case INFO_CODEC_ALAW:
break;
case INFO_CODEC_ULAW:
break;
}
}
/*************** Helpers END *************/
Christian Richter
committed
static void send_digit_to_chan(struct chan_list *cl, char digit )
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
{
static const char* dtmf_tones[] = {
"!941+1336/100,!0/100", /* 0 */
"!697+1209/100,!0/100", /* 1 */
"!697+1336/100,!0/100", /* 2 */
"!697+1477/100,!0/100", /* 3 */
"!770+1209/100,!0/100", /* 4 */
"!770+1336/100,!0/100", /* 5 */
"!770+1477/100,!0/100", /* 6 */
"!852+1209/100,!0/100", /* 7 */
"!852+1336/100,!0/100", /* 8 */
"!852+1477/100,!0/100", /* 9 */
"!697+1633/100,!0/100", /* A */
"!770+1633/100,!0/100", /* B */
"!852+1633/100,!0/100", /* C */
"!941+1633/100,!0/100", /* D */
"!941+1209/100,!0/100", /* * */
"!941+1477/100,!0/100" }; /* # */
struct ast_channel *chan=cl->ast;
if (digit >= '0' && digit <='9')
ast_playtones_start(chan,0,dtmf_tones[digit-'0'], 0);
else if (digit >= 'A' && digit <= 'D')
ast_playtones_start(chan,0,dtmf_tones[digit-'A'+10], 0);
else if (digit == '*')
ast_playtones_start(chan,0,dtmf_tones[14], 0);
else if (digit == '#')
ast_playtones_start(chan,0,dtmf_tones[15], 0);
else {
/* not handled */
ast_log(LOG_DEBUG, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name);
}
}
/*** CLI HANDLING ***/
static int misdn_set_debug(int fd, int argc, char *argv[])
{
if (argc != 4 && argc != 5 && argc != 6 && argc != 7)
return RESULT_SHOWUSAGE;
int level = atoi(argv[3]);
switch (argc) {
case 4:
case 5: {
int only = 0;
if (argc == 5) {
if (strncasecmp(argv[4], "only", strlen(argv[4])))
return RESULT_SHOWUSAGE;
else
only = 1;
}
int i;
for (i=0; i<=max_ports; i++) {
misdn_debug[i] = level;
misdn_debug_only[i] = only;
}
ast_cli(fd, "changing debug level for all ports to %d%s\n",misdn_debug[0], only?" (only)":"");
}
break;
case 6:
case 7: {
if (strncasecmp(argv[4], "port", strlen(argv[4])))
return RESULT_SHOWUSAGE;
int port = atoi(argv[5]);
if (port <= 0 || port > max_ports) {
switch (max_ports) {
case 0:
ast_cli(fd, "port number not valid! no ports available so you won't get lucky with any number here...\n");
break;
case 1:
ast_cli(fd, "port number not valid! only port 1 is availble.\n");
break;
default:
ast_cli(fd, "port number not valid! only ports 1 to %d are available.\n", max_ports);
}
return 0;
}
if (argc == 7) {
if (strncasecmp(argv[6], "only", strlen(argv[6])))
return RESULT_SHOWUSAGE;
else
misdn_debug_only[port] = 1;
} else
misdn_debug_only[port] = 0;
misdn_debug[port] = level;
ast_cli(fd, "changing debug level to %d%s for port %d\n", misdn_debug[port], misdn_debug_only[port]?" (only)":"", port);
}
}
return 0;
}
static int misdn_set_crypt_debug(int fd, int argc, char *argv[])
{
Christian Richter
committed
if (argc != 5) return RESULT_SHOWUSAGE;
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
return 0;
}
static int misdn_restart_port (int fd, int argc, char *argv[])
{
int port;
if (argc != 4)
return RESULT_SHOWUSAGE;
port = atoi(argv[3]);
misdn_lib_port_restart(port);
return 0;
}
static int misdn_port_up (int fd, int argc, char *argv[])
{
int port;
if (argc != 4)
return RESULT_SHOWUSAGE;
port = atoi(argv[3]);
misdn_lib_get_port_up(port);
return 0;
}
Christian Richter
committed
static int misdn_port_down (int fd, int argc, char *argv[])
{
int port;
if (argc != 4)
return RESULT_SHOWUSAGE;
port = atoi(argv[3]);
misdn_lib_get_port_down(port);
return 0;
}
static int misdn_show_config (int fd, int argc, char *argv[])
{
char buffer[BUFFERSIZE];
enum misdn_cfg_elements elem;
int linebreak;
int onlyport = -1;
if (argc >= 4) {
if (!sscanf(argv[3], "%d", &onlyport) || onlyport < 0) {
ast_cli(fd, "Unknown option: %s\n", argv[3]);
return RESULT_SHOWUSAGE;
}
}
if (argc == 3 || onlyport == 0) {
ast_cli(fd,"Misdn General-Config: \n");
ast_cli(fd," -> Version: chan_misdn-" CHAN_MISDN_VERSION "\n");
for (elem = MISDN_GEN_FIRST + 1, linebreak = 1; elem < MISDN_GEN_LAST; elem++, linebreak++) {
misdn_cfg_get_config_string( 0, elem, buffer, BUFFERSIZE);
ast_cli(fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
}
ast_cli(fd, "\n");
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
}
if (onlyport < 0) {
int port = misdn_cfg_get_next_port(0);
for (; port > 0; port = misdn_cfg_get_next_port(port)) {
ast_cli(fd, "\n[PORT %d]\n", port);
for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
misdn_cfg_get_config_string( port, elem, buffer, BUFFERSIZE);
ast_cli(fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
}
ast_cli(fd, "\n");
}
}
if (onlyport > 0) {
if (misdn_cfg_is_port_valid(onlyport)) {
ast_cli(fd, "[PORT %d]\n", onlyport);
for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
misdn_cfg_get_config_string( onlyport, elem, buffer, BUFFERSIZE);
ast_cli(fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
}
ast_cli(fd, "\n");
} else {
ast_cli(fd, "Port %d is not active!\n", onlyport);
}
}
return 0;
}
struct state_struct {
enum misdn_chan_state state;
char txt[255] ;
} ;
Christian Richter
committed
static struct state_struct state_array[] = {
{MISDN_NOTHING,"NOTHING"}, /* at beginning */
{MISDN_WAITING4DIGS,"WAITING4DIGS"}, /* when waiting for infos */
{MISDN_EXTCANTMATCH,"EXTCANTMATCH"}, /* when asterisk couldnt match our ext */
{MISDN_DIALING,"DIALING"}, /* when pbx_start */
{MISDN_PROGRESS,"PROGRESS"}, /* when pbx_start */
{MISDN_CALLING,"CALLING"}, /* when misdn_call is called */
{MISDN_ALERTING,"ALERTING"}, /* when Alerting */
{MISDN_BUSY,"BUSY"}, /* when BUSY */
{MISDN_CONNECTED,"CONNECTED"}, /* when connected */
{MISDN_BRIDGED,"BRIDGED"}, /* when bridged */
{MISDN_CLEANING,"CLEANING"}, /* when hangup from * but we were connected before */
{MISDN_HUNGUP_FROM_MISDN,"HUNGUP_FROM_MISDN"}, /* when DISCONNECT/RELEASE/REL_COMP cam from misdn */
{MISDN_HOLDED,"HOLDED"}, /* when DISCONNECT/RELEASE/REL_COMP cam from misdn */
{MISDN_HOLD_DISCONNECT,"HOLD_DISCONNECT"}, /* when DISCONNECT/RELEASE/REL_COMP cam from misdn */
{MISDN_HUNGUP_FROM_AST,"HUNGUP_FROM_AST"} /* when DISCONNECT/RELEASE/REL_COMP came out of */
/* misdn_hangup */
};
Christian Richter
committed
static char *misdn_get_ch_state(struct chan_list *p)
{
int i;
if( !p) return NULL;
for (i=0; i< sizeof(state_array)/sizeof(struct state_struct); i++) {
if ( state_array[i].state == p->state) return state_array[i].txt;
}
return NULL;
}
void reload_config(void)
{
int i, cfg_debug;
Christian Richter
committed
chan_misdn_log(-1, 0, "Dynamic Crypting Activation is not support during reload at the moment\n");
free_robin_list();
misdn_cfg_reload();
misdn_cfg_update_ptp();
Christian Richter
committed
misdn_cfg_get( 0, MISDN_GEN_TRACEFILE, global_tracefile, BUFFERSIZE);
misdn_cfg_get( 0, MISDN_GEN_DEBUG, &cfg_debug, sizeof(int));
for (i = 0; i <= max_ports; i++) {
misdn_debug[i] = cfg_debug;
misdn_debug_only[i] = 0;
}
}
static int misdn_reload (int fd, int argc, char *argv[])
{
ast_cli(fd, "Reloading mISDN Config\n");
reload_config();
return 0;
}
static void print_bc_info (int fd, struct chan_list* help, struct misdn_bchannel* bc)
{
struct ast_channel *ast=help->ast;
ast_cli(fd,
"* Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s rad:%s ctx:%s state:%s\n",
Christian Richter
committed
help->orginator == ORG_AST?"*":"I",
ast?ast->exten:NULL,
ast?AST_CID_P(ast):NULL,
bc->rad,
ast?ast->context:NULL,
misdn_get_ch_state(help)
);
ast_cli(fd,
" --> astname: %s\n"
" --> ch_l3id: %x\n"
" --> ch_addr: %x\n"
" --> bc_addr: %x\n"
" --> bc_l3id: %x\n"
" --> display: %s\n"
" --> activated: %d\n"
" --> capability: %s\n"
" --> echo_cancel: %d\n"
" --> notone : rx %d tx:%d\n"
" --> bc_hold: %d holded_bc :%d\n",
help->ast->name,
help->l3id,
help->addr,
bc->addr,
bc?bc->l3_id:-1,
bc->display,
bc->active,
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
bearer2str(bc->capability),
bc->ec_enable,
help->norxtone,help->notxtone,
bc->holded, help->holded_bc?1:0
);
}
static int misdn_show_cls (int fd, int argc, char *argv[])
{
struct chan_list *help=cl_te;
ast_cli(fd,"Chan List: %p\n",cl_te);
for (;help; help=help->next) {
struct misdn_bchannel *bc=help->bc;
struct ast_channel *ast=help->ast;
if (misdn_debug[0] > 2) ast_cli(fd, "Bc:%p Ast:%p\n", bc, ast);
if (bc) {
print_bc_info(fd, help, bc);
} else if ( (bc=help->holded_bc) ) {
chan_misdn_log(0, 0, "ITS A HOLDED BC:\n");
print_bc_info(fd, help, bc);
} else {
ast_cli(fd,"* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n", ast->exten, AST_CID_P(ast));
}
}
return 0;
}
static int misdn_show_cl (int fd, int argc, char *argv[])
{
struct chan_list *help=cl_te;
if (argc != 4)
return RESULT_SHOWUSAGE;
for (;help; help=help->next) {
struct misdn_bchannel *bc=help->bc;
struct ast_channel *ast=help->ast;
if (bc && ast) {
if (!strcasecmp(ast->name,argv[3])) {
print_bc_info(fd, help, bc);
break;
}
}
}
return 0;
}
int MAXTICS=8;
static int misdn_set_tics (int fd, int argc, char *argv[])
{
if (argc != 4)
return RESULT_SHOWUSAGE;
MAXTICS=atoi(argv[3]);
return 0;
}
static int misdn_show_stacks (int fd, int argc, char *argv[])
{
ast_cli(fd, "BEGIN STACK_LIST:\n");
Christian Richter
committed
for (port=misdn_cfg_get_next_port(0); port > 0;
port=misdn_cfg_get_next_port(port)) {
char buf[128];
get_show_stack_details(port,buf);
ast_cli(fd," %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port]?"(only)":"");
return 0;
}
static int misdn_show_port (int fd, int argc, char *argv[])
{
int port;
if (argc != 4)
return RESULT_SHOWUSAGE;
port = atoi(argv[3]);
ast_cli(fd, "BEGIN STACK_LIST:\n");
char buf[128];
get_show_stack_details(port,buf);
ast_cli(fd," %s Debug:%d%s\n",buf, misdn_debug[port], misdn_debug_only[port]?"(only)":"");
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
return 0;
}
static int misdn_send_cd (int fd, int argc, char *argv[])
{
char *channame;
char *nr;
if (argc != 5)
return RESULT_SHOWUSAGE;
channame = argv[3];
nr = argv[4];
ast_cli(fd, "Sending Calldeflection (%s) to %s\n",nr, channame);
{
struct chan_list *tmp=get_chan_by_ast_name(channame);
if (!tmp) {
ast_cli(fd, "Sending CD with nr %s to %s failed Channel does not exist\n",nr, channame);
return 0;
} else {
misdn_lib_send_facility(tmp->bc, FACILITY_CALLDEFLECT, nr);
}
}
return 0;
}
static int misdn_send_digit (int fd, int argc, char *argv[])
{
char *channame;
char *msg;
if (argc != 5)
return RESULT_SHOWUSAGE;
channame = argv[3];
msg = argv[4];
ast_cli(fd, "Sending %s to %s\n",msg, channame);
{
struct chan_list *tmp=get_chan_by_ast_name(channame);
if (!tmp) {
ast_cli(fd, "Sending %s to %s failed Channel does not exist\n",msg, channame);
return 0;
} else {
#if 1
int i;
int msglen = strlen(msg);
for (i=0; i<msglen; i++) {
ast_cli(fd, "Sending: %c\n",msg[i]);
send_digit_to_chan(tmp, msg[i]);
/* res = ast_safe_sleep(tmp->ast, 250); */
usleep(250000);
/* res = ast_waitfor(tmp->ast,100); */
}
#else
int res;
res = ast_dtmf_stream(tmp->ast,NULL,msg,250);
#endif
}
}
return 0;
}
static int misdn_toggle_echocancel (int fd, int argc, char *argv[])
{
char *channame;
if (argc != 4)
return RESULT_SHOWUSAGE;
channame = argv[3];
ast_cli(fd, "Toggling EchoCancel on %s\n", channame);
{
struct chan_list *tmp=get_chan_by_ast_name(channame);
if (!tmp) {
ast_cli(fd, "Toggling EchoCancel %s failed Channel does not exist\n", channame);
return 0;
} else {
tmp->bc->ec_enable=tmp->bc->ec_enable?0:1;
if (tmp->bc->ec_enable) {
manager_ec_enable(tmp->bc);
} else {
manager_ec_disable(tmp->bc);
}
}
}
return 0;
}
static int misdn_send_display (int fd, int argc, char *argv[])
{
char *channame;
char *msg;
if (argc != 5)
return RESULT_SHOWUSAGE;
channame = argv[3];
msg = argv[4];
ast_cli(fd, "Sending %s to %s\n",msg, channame);
{
struct chan_list *tmp;
tmp=get_chan_by_ast_name(channame);
if (tmp && tmp->bc) {
ast_copy_string(tmp->bc->display, msg, sizeof(tmp->bc->display));
misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
} else {
ast_cli(fd,"No such channel %s\n",channame);
return RESULT_FAILURE;
}
}
return RESULT_SUCCESS ;
}
static char *complete_ch_helper(const char *line, const char *word, int pos, int state, int rpos)
{
struct ast_channel *c;
int which=0;
char *ret;
if (pos != rpos)
return NULL;
c = ast_channel_walk_locked(NULL);
while(c) {
if (!strncasecmp(word, c->name, strlen(word))) {
if (++which > state)
break;
}
ast_mutex_unlock(&c->lock);
c = ast_channel_walk_locked(c);
}
if (c) {
ret = strdup(c->name);
ast_mutex_unlock(&c->lock);
} else
ret = NULL;
return ret;
}
static char *complete_ch(const char *line, const char *word, int pos, int state)
{
return complete_ch_helper(line, word, pos, state, 3);
}
static char *complete_debug_port (const char *line, const char *word, int pos, int state)
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
{
if (state)
return NULL;
switch (pos) {
case 4: if (*word == 'p')
return strdup("port");
else if (*word == 'o')
return strdup("only");
break;
case 6: if (*word == 'o')
return strdup("only");
break;
}
return NULL;
}
static struct ast_cli_entry cli_send_cd =
{ {"misdn","send","calldeflect", NULL},
misdn_send_cd,
"Sends CallDeflection to mISDN Channel",
"Usage: misdn send calldeflect <channel> \"<nr>\" \n",
complete_ch
};
static struct ast_cli_entry cli_send_digit =
{ {"misdn","send","digit", NULL},
misdn_send_digit,
"Sends DTMF Digit to mISDN Channel",
"Usage: misdn send digit <channel> \"<msg>\" \n"
" Send <digit> to <channel> as DTMF Tone\n"
" when channel is a mISDN channel\n",
complete_ch
};
static struct ast_cli_entry cli_toggle_echocancel =
{ {"misdn","toggle","echocancel", NULL},
misdn_toggle_echocancel,
"Toggles EchoCancel on mISDN Channel",
"Usage: misdn toggle echocancel <channel>\n",
complete_ch
};
static struct ast_cli_entry cli_send_display =
{ {"misdn","send","display", NULL},
misdn_send_display,
"Sends Text to mISDN Channel",
"Usage: misdn send display <channel> \"<msg>\" \n"
" Send <msg> to <channel> as Display Message\n"
" when channel is a mISDN channel\n",
complete_ch
};
static struct ast_cli_entry cli_show_config =