From 958f3726f119bbadc13ac368b4139ac431b5ca42 Mon Sep 17 00:00:00 2001 From: Nadi Sarrar Date: Tue, 8 Aug 2006 18:13:40 +0000 Subject: * first bits of decoding facility information elements * fail on misdn_cfg_init() if elements in the config enum don't match with the config structs in misdn_config.c * implemented first bits for encoding ISDN facility information elements via ASN.1 descriptions * using unnamed semaphore for syncing in misdn_thread * advanced fax detection: configurable detect timeout and context to jump into git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@39378 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_misdn.c | 233 +++++++++++------- channels/misdn/Makefile | 4 +- channels/misdn/asn1.c | 181 ++++++++++++++ channels/misdn/asn1.h | 72 ++++++ channels/misdn/chan_misdn_config.h | 4 +- channels/misdn/fac.c | 492 +++++++++++++++++-------------------- channels/misdn/fac.h | 10 +- channels/misdn/isdn_lib.c | 37 ++- channels/misdn/isdn_lib.h | 4 + channels/misdn/isdn_msg_parser.c | 7 +- channels/misdn_config.c | 54 +++- 11 files changed, 709 insertions(+), 389 deletions(-) create mode 100644 channels/misdn/asn1.c create mode 100644 channels/misdn/asn1.h (limited to 'channels') diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c index 72a26c843..213b6481d 100644 --- a/channels/chan_misdn.c +++ b/channels/chan_misdn.c @@ -43,8 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include #include #include -#include -#include +#include #include "asterisk/channel.h" #include "asterisk/config.h" @@ -157,7 +156,9 @@ struct chan_list { char ast_rd_buf[4096]; struct ast_frame frame; - int faxdetect; + int faxdetect; /* 0:no 1:yes 2:yes+nojump */ + int faxdetect_timeout; + struct timeval faxdetect_tv; int faxhandled; int ast_dsp; @@ -258,7 +259,6 @@ static struct robin_list* get_robin_position (char *group) /* the main schedule context for stuff like l1 watcher, overlap dial, ... */ static struct sched_context *misdn_tasks = NULL; static pthread_t misdn_tasks_thread; -static int misdn_tasks_semid; static void chan_misdn_log(int level, int port, char *tmpl, ...); @@ -417,15 +417,15 @@ static void print_facility( struct misdn_bchannel *bc) { switch (bc->fac_type) { case FACILITY_CALLDEFLECT: - chan_misdn_log(2,bc->port," --> calldeflect: %s\n", + chan_misdn_log(0,bc->port," --> calldeflect: %s\n", bc->fac.calldeflect_nr); break; case FACILITY_CENTREX: - chan_misdn_log(2,bc->port," --> centrex: %s\n", + chan_misdn_log(0,bc->port," --> centrex: %s\n", bc->fac.cnip); break; default: - chan_misdn_log(2,bc->port," --> unknown\n"); + chan_misdn_log(0,bc->port," --> unknown\n"); } } @@ -453,11 +453,6 @@ static void* misdn_tasks_thread_func (void *data) { int wait; struct sigaction sa; - struct sembuf semb = { - .sem_num = 0, - .sem_op = 1, - .sem_flg = 0 - }; sa.sa_handler = sighandler; sa.sa_flags = SA_NODEFER; @@ -465,7 +460,7 @@ static void* misdn_tasks_thread_func (void *data) sigaddset(&sa.sa_mask, SIGUSR1); sigaction(SIGUSR1, &sa, NULL); - semop(misdn_tasks_semid, &semb, 1); + sem_post((sem_t *)data); while (1) { wait = ast_sched_wait(misdn_tasks); @@ -480,44 +475,21 @@ static void* misdn_tasks_thread_func (void *data) static void misdn_tasks_init (void) { - key_t key; - union { - int val; - struct semid_ds *buf; - unsigned short *array; - struct seminfo *__buf; - } semu; - struct sembuf semb = { - .sem_num = 0, - .sem_op = -1, - .sem_flg = 0 - }; - - chan_misdn_log(4, 0, "Starting misdn_tasks thread\n"); - - key = ftok("/etc/asterisk/misdn.conf", 'E'); - if (key == -1) { - perror("chan_misdn: Failed to create a semaphore key!"); - exit(1); - } + sem_t blocker; + int i = 5; - misdn_tasks_semid = semget(key, 10, 0666 | IPC_CREAT); - if (misdn_tasks_semid == -1) { - perror("chan_misdn: Failed to get a semaphore!"); - exit(1); - } - - semu.val = 0; - if (semctl(misdn_tasks_semid, 0, SETVAL, semu) == -1) { + if (sem_init(&blocker, 0, 0)) { perror("chan_misdn: Failed to initialize semaphore!"); exit(1); } + chan_misdn_log(4, 0, "Starting misdn_tasks thread\n"); + misdn_tasks = sched_context_create(); - pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, NULL); + pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, &blocker); - semop(misdn_tasks_semid, &semb, 1); - semctl(misdn_tasks_semid, 0, IPC_RMID, semu); + while (sem_wait(&blocker) && --i); + sem_destroy(&blocker); } static void misdn_tasks_destroy (void) @@ -1751,6 +1723,8 @@ static int read_config(struct chan_list *ch, int orig) { misdn_cfg_get( port, MISDN_CFG_ALLOWED_BEARERS, &ch->allowed_bearers, BUFFERSIZE); + char faxdetect[BUFFERSIZE+1]; + misdn_cfg_get( port, MISDN_CFG_FAXDETECT, faxdetect, BUFFERSIZE); int hdlc=0; misdn_cfg_get( port, MISDN_CFG_HDLC, &hdlc, sizeof(int)); @@ -1803,6 +1777,13 @@ static int read_config(struct chan_list *ch, int orig) { if ( orig == ORG_AST) { misdn_cfg_get( port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(bc->te_choose_channel), sizeof(int)); + if (strstr(faxdetect, "outgoing") || strstr(faxdetect, "both")) { + if (strstr(faxdetect, "nojump")) + ch->faxdetect=2; + else + ch->faxdetect=1; + } + { char callerid[BUFFERSIZE+1]; misdn_cfg_get( port, MISDN_CFG_CALLERID, callerid, BUFFERSIZE); @@ -1827,6 +1808,12 @@ static int read_config(struct chan_list *ch, int orig) { ch->overlap_dial = 0; } else { /** ORIGINATOR MISDN **/ + if (strstr(faxdetect, "incoming") || strstr(faxdetect, "both")) { + if (strstr(faxdetect, "nojump")) + ch->faxdetect=2; + else + ch->faxdetect=1; + } misdn_cfg_get( port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(int)); debug_numplan(port, bc->cpnnumplan,"CTON"); @@ -1897,6 +1884,18 @@ static int read_config(struct chan_list *ch, int orig) { ast_mutex_init(&ch->overlap_tv_lock); } /* ORIG MISDN END */ + ch->overlap_dial_task = -1; + + if (ch->faxdetect) { + misdn_cfg_get( port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout)); + if (!ch->dsp) + ch->dsp = ast_dsp_new(); + if (ch->dsp) + ast_dsp_set_features(ch->dsp, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_DETECT); + if (!ch->trans) + ch->trans=ast_translator_build_path(AST_FORMAT_SLINEAR, AST_FORMAT_ALAW); + } + return 0; } @@ -2468,44 +2467,65 @@ static int misdn_hangup(struct ast_channel *ast) struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame) { struct ast_frame *f,*f2; - if (tmp->trans) - f2=ast_translate(tmp->trans, frame,0); - else { + + if (tmp->trans) { + f2 = ast_translate(tmp->trans, frame, 0); + f = ast_dsp_process(tmp->ast, tmp->dsp, f2); + } else { chan_misdn_log(0, tmp->bc->port, "No T-Path found\n"); return NULL; } - - f = ast_dsp_process(tmp->ast, tmp->dsp, f2); - if (f && (f->frametype == AST_FRAME_DTMF)) { - ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c", f->subclass); - if (f->subclass == 'f' && tmp->faxdetect) { - /* Fax tone -- Handle and return NULL */ - struct ast_channel *ast = tmp->ast; - if (!tmp->faxhandled) { - tmp->faxhandled++; - if (strcmp(ast->exten, "fax")) { - if (ast_exists_extension(ast, ast_strlen_zero(ast->macrocontext)? ast->context : ast->macrocontext, "fax", 1, AST_CID_P(ast))) { - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name); - /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ - pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten); - if (ast_async_goto(ast, ast->context, "fax", 1)) - ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, ast->context); - } else - ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n",ast->context, ast->exten); - } else - ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n"); - } else - ast_log(LOG_DEBUG, "Fax already handled\n"); - - } else if ( tmp->ast_dsp) { - chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n",f->subclass); - return f; - } - } - frame->frametype = AST_FRAME_NULL; - frame->subclass = 0; + + if (!f || (f->frametype != AST_FRAME_DTMF)) + return frame; + + ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c", f->subclass); + + if (tmp->faxdetect && (f->subclass == 'f')) { + /* Fax tone -- Handle and return NULL */ + if (!tmp->faxhandled) { + struct ast_channel *ast = tmp->ast; + tmp->faxhandled++; + chan_misdn_log(0, tmp->bc->port, "Fax detected, preparing %s for fax transfer.\n", ast->name); + tmp->bc->rxgain = 0; + isdn_lib_update_rxgain(tmp->bc); + tmp->bc->txgain = 0; + isdn_lib_update_txgain(tmp->bc); + tmp->bc->ec_enable = 0; + isdn_lib_update_ec(tmp->bc); + isdn_lib_stop_dtmf(tmp->bc); + switch (tmp->faxdetect) { + case 1: + if (strcmp(ast->exten, "fax")) { + char *context; + char context_tmp[BUFFERSIZE]; + misdn_cfg_get(tmp->bc->port, MISDN_CFG_FAXDETECT_CONTEXT, &context_tmp, sizeof(context_tmp)); + context = ast_strlen_zero(context_tmp) ? (ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext) : context_tmp; + if (ast_exists_extension(ast, context, "fax", 1, AST_CID_P(ast))) { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension (context:%s)\n", ast->name, context); + /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ + pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten); + if (ast_async_goto(ast, context, "fax", 1)) + ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, context); + } else + ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n", context, ast->exten); + } else + ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n"); + break; + case 2: + ast_verbose(VERBOSE_PREFIX_3 "Not redirecting %s to fax extension, nojump is set.\n", ast->name); + break; + } + } else + ast_log(LOG_DEBUG, "Fax already handled\n"); + } + + if (tmp->ast_dsp && (f->subclass != 'f')) { + chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n", f->subclass); + } + return frame; } @@ -2519,7 +2539,7 @@ static struct ast_frame *misdn_read(struct ast_channel *ast) chan_misdn_log(1,0,"misdn_read called without ast\n"); return NULL; } - if (! (tmp=MISDN_ASTERISK_TECH_PVT(ast)) ) { + if (!(tmp=MISDN_ASTERISK_TECH_PVT(ast))) { chan_misdn_log(1,0,"misdn_read called without ast->pvt\n"); return NULL; } @@ -2539,17 +2559,40 @@ static struct ast_frame *misdn_read(struct ast_channel *ast) tmp->frame.frametype = AST_FRAME_VOICE; tmp->frame.subclass = AST_FORMAT_ALAW; tmp->frame.datalen = len; - tmp->frame.samples = len ; - tmp->frame.mallocd =0 ; - tmp->frame.offset= 0 ; + tmp->frame.samples = len; + tmp->frame.mallocd = 0; + tmp->frame.offset = 0; tmp->frame.src = NULL; - tmp->frame.data = tmp->ast_rd_buf ; - - if (tmp->faxdetect || tmp->ast_dsp ) { - return process_ast_dsp(tmp, &tmp->frame); + tmp->frame.data = tmp->ast_rd_buf; + + if (tmp->faxdetect && !tmp->faxhandled) { + if (tmp->faxdetect_timeout) { + if (ast_tvzero(tmp->faxdetect_tv)) { + tmp->faxdetect_tv = ast_tvnow(); + chan_misdn_log(2,tmp->bc->port,"faxdetect: starting detection with timeout: %ds ...\n", tmp->faxdetect_timeout); + return process_ast_dsp(tmp, &tmp->frame); + } else { + struct timeval tv_now = ast_tvnow(); + int diff = ast_tvdiff_ms(tv_now, tmp->faxdetect_tv); + if (diff <= (tmp->faxdetect_timeout * 1000)) { + chan_misdn_log(5,tmp->bc->port,"faxdetect: detecting ...\n"); + return process_ast_dsp(tmp, &tmp->frame); + } else { + chan_misdn_log(2,tmp->bc->port,"faxdetect: stopping detection (time ran out) ...\n"); + tmp->faxdetect = 0; + return &tmp->frame; + } + } + } else { + chan_misdn_log(5,tmp->bc->port,"faxdetect: detecting ... (no timeout)\n"); + return process_ast_dsp(tmp, &tmp->frame); + } + } else { + if (tmp->ast_dsp) + return process_ast_dsp(tmp, &tmp->frame); + else + return &tmp->frame; } - - return &tmp->frame; } @@ -2629,7 +2672,6 @@ static int misdn_write(struct ast_channel *ast, struct ast_frame *frame) } chan_misdn_log(9, ch->bc->port, "Sending :%d bytes 2 MISDN\n",frame->samples); - if ( !ch->bc->nojitter && misdn_cap_is_speech(ch->bc->capability) ) { /* Buffered Transmit (triggert by read from isdn side)*/ if (misdn_jb_fill(ch->jb,frame->data,frame->samples) < 0) { @@ -3586,6 +3628,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) case EVENT_PORT_ALARM: case EVENT_RETRIEVE: case EVENT_NEW_BC: + case EVENT_FACILITY: break; case EVENT_RELEASE_COMPLETE: chan_misdn_log(1, bc->port, " --> no Ch, so we've already released.\n"); @@ -4442,6 +4485,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) struct ast_channel *bridged=AST_BRIDGED_P(ch->ast); struct chan_list *ch; + misdn_lib_send_event(bc, EVENT_DISCONNECT); + if (bridged && MISDN_ASTERISK_TECH_PVT(bridged)) { ch=MISDN_ASTERISK_TECH_PVT(bridged); /*ch->state=MISDN_FACILITY_DEFLECTED;*/ @@ -4455,7 +4500,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) break; default: - chan_misdn_log(1, bc->port," --> not yet handled\n"); + chan_misdn_log(0, bc->port," --> not yet handled: facility type:%p\n", bc->fac_type); } break; @@ -4550,8 +4595,10 @@ static int load_module(void *mod) return -1; } - - misdn_cfg_init(max_ports); + if (misdn_cfg_init(max_ports)) { + ast_log(LOG_ERROR, "Unable to initialize misdn_config.\n"); + return -1; + } g_config_initialized=1; misdn_debug = (int *)malloc(sizeof(int) * (max_ports+1)); @@ -4891,6 +4938,7 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) case 'f': chan_misdn_log(1, ch->bc->port, "SETOPT: Faxdetect\n"); ch->faxdetect=1; + misdn_cfg_get(ch->bc->port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout)); break; case 'a': @@ -4921,7 +4969,6 @@ static int misdn_set_opt_exec(struct ast_channel *chan, void *data) if (ch->faxdetect || ch->ast_dsp) { - if (!ch->dsp) ch->dsp = ast_dsp_new(); if (ch->dsp) ast_dsp_set_features(ch->dsp, DSP_FEATURE_DTMF_DETECT| DSP_FEATURE_FAX_DETECT); if (!ch->trans) ch->trans=ast_translator_build_path(AST_FORMAT_SLINEAR, AST_FORMAT_ALAW); diff --git a/channels/misdn/Makefile b/channels/misdn/Makefile index ba4a12926..febca51ed 100644 --- a/channels/misdn/Makefile +++ b/channels/misdn/Makefile @@ -11,14 +11,14 @@ CFLAGS += -fPIC endif SOURCES = isdn_lib.c isdn_msg_parser.c OBJDIR = . -OBJS = isdn_lib.o isdn_msg_parser.o fac.o +OBJS = isdn_lib.o isdn_msg_parser.o fac.o asn1.o ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/lib/libbnec.so),) CFLAGS+=-DBEROEC_VERSION=1 CFLAGS+=-DWITH_BEROEC endif - +CFLAGS+=-DFACILITY_DEBUG all: chan_misdn_lib.a diff --git a/channels/misdn/asn1.c b/channels/misdn/asn1.c new file mode 100644 index 000000000..80dcacd64 --- /dev/null +++ b/channels/misdn/asn1.c @@ -0,0 +1,181 @@ + +#include "asn1.h" +#include + +/* +** ASN.1 Encoding +*/ + +int _enc_null (__u8 *dest, int tag) +{ + dest[0] = tag; + dest[1] = 0; + return 2; +} + +int _enc_bool (__u8 *dest, __u32 i, int tag) +{ + dest[0] = tag; + dest[1] = 1; + dest[2] = i ? 1:0; + return 3; +} + +int _enc_int (__u8 *dest, __u32 i, int tag) +{ + __u8 *p; + dest[0] = tag; + p = &dest[2]; + do { + *p++ = i; + i >>= 8; + } while (i); + dest[1] = p - &dest[2]; + return p - dest; +} + +int _enc_enum (__u8 *dest, __u32 i, int tag) +{ + __u8 *p; + + dest[0] = tag; + p = &dest[2]; + do { + *p++ = i; + i >>= 8; + } while (i); + dest[1] = p - &dest[2]; + return p - dest; +} + +int _enc_num_string (__u8 *dest, __u8 *nd, __u8 len, int tag) +{ + __u8 *p; + int i; + + dest[0] = tag; + p = &dest[2]; + for (i = 0; i < len; i++) + *p++ = *nd++; + dest[1] = p - &dest[2]; + return p - dest; +} + +int _enc_sequence_start (__u8 *dest, __u8 **id, int tag) +{ + dest[0] = tag; + *id = &dest[1]; + return 2; +} + +int _enc_sequence_end (__u8 *dest, __u8 *id, int tag_dummy) +{ + *id = dest - id - 1; + return 0; +} + +/* +** ASN.1 Decoding +*/ + +#define CHECK_P \ + do { \ + if (p >= end) \ + return -1; \ + } while (0) + +#define CallASN1(ret, p, end, todo) \ + do { \ + ret = todo; \ + if (ret < 0) { \ + return -1; \ + } \ + p += ret; \ + } while (0) + +#define INIT \ + int len, ret; \ + __u8 *begin = p; \ + if (tag) \ + *tag = *p; \ + p++; \ + CallASN1(ret, p, end, dec_len(p, &len)); \ + if (len >= 0) { \ + if (p + len > end) \ + return -1; \ + end = p + len; \ + } + +int _dec_null (__u8 *p, __u8 *end, int *tag) +{ + INIT; + return p - begin; +} + +int _dec_bool (__u8 *p, __u8 *end, int *i, int *tag) +{ + INIT; + *i = 0; + while (len--) { + CHECK_P; + *i = (*i >> 8) + *p; + p++; + } + return p - begin; +} + +int _dec_int (__u8 *p, __u8 *end, int *i, int *tag) +{ + INIT; + + *i = 0; + while (len--) { + CHECK_P; + *i = (*i << 8) + *p; + p++; + } + return p - begin; +} + +int _dec_enum (__u8 *p, __u8 *end, int *i, int *tag) +{ + INIT; + + *i = 0; + while (len--) { + CHECK_P; + *i = (*i << 8) + *p; + p++; + } + return p - begin; +} + +int _dec_num_string (__u8 *p, __u8 *end, char *str, int *tag) +{ + INIT; + + while (len--) { + CHECK_P; + *str++ = *p; + p++; + } + *str = 0; + return p - begin; +} + +int _dec_octet_string (__u8 *p, __u8 *end, char *str, int *tag) +{ + return _dec_num_string(p, end, str, tag); +} + +int _dec_sequence (__u8 *p, __u8 *end, int *tag) +{ + INIT; + return p - begin; +} + +int dec_len (__u8 *p, int *len) +{ + *len = *p; + return 1; +} diff --git a/channels/misdn/asn1.h b/channels/misdn/asn1.h new file mode 100644 index 000000000..d3bdae356 --- /dev/null +++ b/channels/misdn/asn1.h @@ -0,0 +1,72 @@ +#ifndef __ASN1_H__ +#define __ASN1_H__ + +#include + +/* +** ASN.1 Tags +*/ + +#define ASN1_TAG_BOOLEAN (0x01) +#define ASN1_TAG_INTEGER (0x02) +#define ASN1_TAG_BIT_STRING (0x03) +#define ASN1_TAG_OCTET_STRING (0x04) +#define ASN1_TAG_NULL (0x05) +#define ASN1_TAG_OBJECT_IDENTIFIER (0x06) +#define ASN1_TAG_ENUM (0x0a) +#define ASN1_TAG_SEQUENCE (0x30) +#define ASN1_TAG_SET (0x31) +#define ASN1_TAG_NUMERIC_STRING (0x12) +#define ASN1_TAG_PRINTABLE_STRING (0x13) +#define ASN1_TAG_IA5_STRING (0x16) +#define ASN1_TAG_UTC_TIME (0x17) +#define ASN1_TAG_CONSTRUCTED (0x20) +#define ASN1_TAG_CONTEXT_SPECIFIC (0x80) +#define ASN1_TAG_EXPLICIT (0x100) +#define ASN1_TAG_OPT (0x200) +#define ASN1_NOT_TAGGED (0x400) + +/* +** ASN.1 Encoding +*/ + +#define enc_null(dest) _enc_null(dest,ASN1_TAG_NULL) +#define enc_bool(dest,i) _enc_bool(dest,i,ASN1_TAG_BOOLEAN) +#define enc_int(dest,i) _enc_int(dest,i,ASN1_TAG_INTEGER) +#define enc_enum(dest,i) _enc_enum(dest,i,ASN1_TAG_ENUM) +#define enc_num_string(dest,num,len) _enc_num_string(dest,num,len,ASN1_TAG_NUMERIC_STRING) +#define enc_sequence_start(dest,id) _enc_sequence_start(dest,id,ASN1_TAG_SEQUENCE) +#define enc_sequence_end(dest,id) _enc_sequence_end(dest,id,ASN1_TAG_SEQUENCE) + +int _enc_null (__u8 *dest, int tag); +int _enc_bool (__u8 *dest, __u32 i, int tag); +int _enc_int (__u8 *dest, __u32 i, int tag); +int _enc_enum (__u8 *dest, __u32 i, int tag); +int _enc_num_string (__u8 *dest, __u8 *nd, __u8 len, int tag); +int _enc_sequence_start (__u8 *dest, __u8 **id, int tag); +int _enc_sequence_end (__u8 *dest, __u8 *id, int tag_dummy); + +/* +** ASN.1 Decoding +*/ + +#define dec_null(p, end) _dec_null (p, end, NULL); +#define dec_bool(p, end,i) _dec_bool (p, end, i, NULL) +#define dec_int(p, end,i) _dec_int (p, end, i, NULL) +#define dec_enum(p, end,i) _dec_enum (p, end, i, NULL) +#define dec_num_string(p, end,str) _dec_num_string (p, end, str, NULL) +#define dec_octet_string(p, end,str) _dec_octet_string (p, end, str, NULL) +#define dec_sequence(p, end) _dec_sequence (p, end, NULL) + +int _dec_null (__u8 *p, __u8 *end, int *tag); +int _dec_bool (__u8 *p, __u8 *end, int *i, int *tag); +int _dec_int (__u8 *p, __u8 *end, int *i, int *tag); +int _dec_enum (__u8 *p, __u8 *end, int *i, int *tag); +int _dec_num_string (__u8 *p, __u8 *end, char *str, int *tag); +int _dec_octet_string (__u8 *p, __u8 *end, char *str, int *tag); +int _dec_sequence (__u8 *p, __u8 *end, int *tag); + +int dec_len (__u8 *p, int *len); + +#endif + diff --git a/channels/misdn/chan_misdn_config.h b/channels/misdn/chan_misdn_config.h index 4828261cd..04376c3cd 100644 --- a/channels/misdn/chan_misdn_config.h +++ b/channels/misdn/chan_misdn_config.h @@ -75,6 +75,8 @@ enum misdn_cfg_elements { MISDN_CFG_OVERLAP_DIAL, /* int (bool)*/ MISDN_CFG_MSNS, /* char[] */ MISDN_CFG_FAXDETECT, /* char[] */ + MISDN_CFG_FAXDETECT_CONTEXT, /* char[] */ + MISDN_CFG_FAXDETECT_TIMEOUT, /* int */ MISDN_CFG_PTP, /* int (bool) */ MISDN_CFG_LAST, @@ -100,7 +102,7 @@ enum misdn_cfg_method { }; /* you must call misdn_cfg_init before any other function of this header file */ -void misdn_cfg_init(int max_ports); +int misdn_cfg_init(int max_ports); void misdn_cfg_reload(void); void misdn_cfg_destroy(void); diff --git a/channels/misdn/fac.c b/channels/misdn/fac.c index 383a60f26..19bfbf729 100644 --- a/channels/misdn/fac.c +++ b/channels/misdn/fac.c @@ -1,313 +1,267 @@ -#include "isdn_lib_intern.h" -#include "isdn_lib.h" - -#include "string.h" - - - - -#define CENTREX_ID 0xa1 -#define CALLDEFLECT_ID 0xa1 - -/** - This file covers the encoding and decoding of facility messages and - facility information elements. - - There will be 2 Functions as Interface: - - fac_enc( char **ntmsg, msg_t * msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc) - fac_dec( unsigned char *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc); - - Those will either read the union facility or fill it. - - internally, we will have deconding and encoding functions for each facility - IE. - -**/ - - -/* support stuff */ -static void strnncpy(unsigned char *dest, unsigned char *src, int len, int dst_len) +#include "fac.h" +#include "asn1.h" + +#if 0 ++------------------------------- +| IE_IDENTIFIER ++------------------------------- +| {length} ++------------------------------- +| +--------------------------- +| | SERVICE_DISCRIMINATOR +| +--------------------------- +| | COMPONENT_TYPE_TAG +| +--------------------------- +| | {length} +| +--------------------------- +| | +----------------------- +| | | INVOKE_IDENTIFIER_TAG (0x2) +| | +----------------------- +| | | {length} (0x1) +| | +----------------------- +| | | {value} (odd integer 0-127) +| | +----------------------- +| | +----------------------- +| | | OPERATION_VALUE_TAG (0x2) +| | +----------------------- +| | | {length} (0x1) +| | +----------------------- +| | | {value} +| | +----------------------- +| | +----------------------- +| | | ASN.1 data ++---+---+----------------------- +#endif + +enum { + SUPPLEMENTARY_SERVICE = 0x91, +} SERVICE_DISCRIMINATOR; + +enum { + INVOKE = 0xa1, + RETURN_RESULT = 0xa2, + RETURN_ERROR = 0xa3, + REJECT = 0xa4, +} COMPONENT_TYPE_TAG; + +enum { + INVOKE_IDENTIFIER = 0x02, + LINKED_IDENTIFIER = 0x80, + NULL_IDENTIFIER = 0x05, +} INVOKE_IDENTIFIER_TAG; + +enum { + OPERATION_VALUE = 0x02, +} OPERATION_VALUE_TAG; + +enum { + VALUE_QUERY = 0x8c, + SET_VALUE = 0x8d, + REQUEST_FEATURE = 0x8f, + ABORT = 0xbe, + REDIRECT_CALL = 0xce, + CALLING_PARTY_TO_HOLD = 0xcf, + CALLING_PARTY_FROM_HOLD = 0x50, + DROP_TARGET_PARTY = 0xd1, + USER_DATA_TRANSFER = 0xd3, + APP_SPECIFIC_STATUS = 0xd2, + + /* not from document */ + CALL_DEFLECT = 0x0d, + AOC = 0x22, +} OPERATION_CODE; + +enum { + Q931_IE_TAG = 0x40, +} ARGUMENT_TAG; + +#ifdef FACILITY_DEBUG +#define FAC_DUMP(fac,len,bc) fac_dump(fac,len,bc) +#include +static void fac_dump (__u8 *facility, unsigned int fac_len, struct misdn_bchannel *bc) { - if (len > dst_len-1) - len = dst_len-1; - strncpy((char *)dest, (char *)src, len); - dest[len] = '\0'; + int i; + cb_log(0, bc->port, " --- facility dump start. length:%d\n", fac_len); + for (i = 0; i < fac_len; ++i) + if (isprint(facility[i])) + cb_log(0, bc->port, " --- %d: %04p (char:%c)\n", i, facility[i], facility[i]); + else + cb_log(0, bc->port, " --- %d: %04p\n", i, facility[i]); + cb_log(0, bc->port, " --- facility dump end\n"); } +#else +#define FAC_DUMP(fac,len,bc) +#endif +/* +** Facility Encoding +*/ - - -/**********************/ -/*** FACILITY STUFF ***/ -/**********************/ - - -/* IE_FACILITY */ -void enc_ie_facility(unsigned char **ntmode, msg_t *msg, unsigned char *facility, int facility_len, int nt, struct misdn_bchannel *bc) +static int enc_fac_calldeflect (__u8 *dest, char *number, int pres) { - unsigned char *p; - Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN); - int l; - - - if (!facility || facility_len<=0) - { - return; - } - + __u8 *body_len, + *p = dest, + *seq1, *seq2; + + *p++ = SUPPLEMENTARY_SERVICE; + *p++ = INVOKE; + + body_len = p++; + + p += _enc_int(p, 0x1 /* some odd integer in (0..127) */, INVOKE_IDENTIFIER); + p += _enc_int(p, CALL_DEFLECT, OPERATION_VALUE); + p += enc_sequence_start(p, &seq1); + p += enc_sequence_start(p, &seq2); + p += _enc_num_string(p, number, strlen(number), ASN1_TAG_CONTEXT_SPECIFIC); + p += enc_sequence_end(p, seq2); + p += enc_bool(p, pres); + p += enc_sequence_end(p, seq1); - l = facility_len; - p = msg_put(msg, l+2); - if (nt) - *ntmode = p+1; - else - qi->QI_ELEMENT(facility) = p - (unsigned char *)qi - sizeof(Q931_info_t); - p[0] = IE_FACILITY; - p[1] = l; - memcpy(p+2, facility, facility_len); + *body_len = p - &body_len[1]; + + return p - dest; } - -/* facility for siemens CENTEX (known parts implemented only) */ -void enc_ie_facility_centrex(unsigned char **ntmode, msg_t *msg, unsigned char *cnip, int setup, int nt, struct misdn_bchannel *bc) +static void enc_ie_facility (__u8 **ntmode, msg_t *msg, __u8 *facility, int facility_len, struct misdn_bchannel *bc) { - unsigned char centrex[256]; - int i = 0; - - if (!cnip) - return; - - /* centrex facility */ - centrex[i++] = FACILITY_CENTREX; - centrex[i++] = CENTREX_ID; + __u8 *ie_fac; + + Q931_info_t *qi; - /* cnip */ - if (strlen((char *)cnip) > 15) - { -/* if (options.deb & DEBUG_PORT) */ - cb_log(1,0,"%s: CNIP/CONP text too long (max 13 chars), cutting.\n", __FUNCTION__); - cnip[15] = '\0'; - } - /* dunno what the 8 bytes mean */ - if (setup) - { - centrex[i++] = 0x17; - centrex[i++] = 0x02; - centrex[i++] = 0x02; - centrex[i++] = 0x44; - centrex[i++] = 0x18; - centrex[i++] = 0x02; - centrex[i++] = 0x01; - centrex[i++] = 0x09; - } else - { - centrex[i++] = 0x18; - centrex[i++] = 0x02; - centrex[i++] = 0x02; - centrex[i++] = 0x81; - centrex[i++] = 0x09; - centrex[i++] = 0x02; - centrex[i++] = 0x01; - centrex[i++] = 0x0a; + ie_fac = msg_put(msg, facility_len + 2); + if (bc->nt) { + *ntmode = ie_fac + 1; + } else { + qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN); + qi->QI_ELEMENT(facility) = ie_fac - (__u8 *)qi - sizeof(Q931_info_t); } - centrex[i++] = 0x80; - centrex[i++] = strlen((char *)cnip); - strcpy((char *)(¢rex[i]), (char *)cnip); - i += strlen((char *)cnip); - cb_log(4,0," cnip='%s'\n", cnip); + ie_fac[0] = IE_FACILITY; + ie_fac[1] = facility_len; + memcpy(ie_fac + 2, facility, facility_len); - /* encode facility */ - enc_ie_facility(ntmode, msg, centrex, i, nt , bc); + FAC_DUMP(ie_fac, facility_len + 2, bc); } -void dec_ie_facility_centrex(unsigned char *p, Q931_info_t *qi, unsigned char *centrex, int facility_len, unsigned char *cnip, int cnip_len, int nt, struct misdn_bchannel *bc) +void fac_enc (__u8 **ntmsg, msg_t *msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc) { + __u8 facility[256]; + int len; - int i = 0; - *cnip = '\0'; - - if (facility_len >= 2) - { - if (centrex[i++] != FACILITY_CENTREX) - return; - if (centrex[i++] != CENTREX_ID) - return; - } - - /* loop sub IEs of facility */ - while(facility_len > i+1) - { - if (centrex[i+1]+i+1 > facility_len) - { - printf("%s: ERROR: short read of centrex facility.\n", __FUNCTION__); - return; - } - switch(centrex[i]) - { - case 0x80: - strnncpy(cnip, ¢rex[i+2], centrex[i+1], cnip_len); - cb_log(4,0," CENTREX cnip='%s'\n", cnip); - break; - } - i += 1+centrex[i+1]; + switch (type) { + case FACILITY_CALLDEFLECT: + len = enc_fac_calldeflect(facility, fac.calldeflect_nr, 1); + enc_ie_facility(ntmsg, msg, facility, len, bc); + break; + case FACILITY_CENTREX: + case FACILITY_NONE: + break; } } +/* +** Facility Decoding +*/ +static int dec_fac_calldeflect (__u8 *p, int len, struct misdn_bchannel *bc) +{ + __u8 *end = p + len; + int offset, + pres; + if ((offset = dec_sequence(p, end)) < 0) + return -1; + p += offset; -/* facility for CALL Deflect (known parts implemented only) */ -void enc_ie_facility_calldeflect(unsigned char **ntmode, msg_t *msg, unsigned char *nr, int nt, struct misdn_bchannel *bc) -{ - unsigned char fac[256]; + if ((offset = dec_sequence(p, end)) < 0) + return -1; + p += offset; - if (!nr) - return; + if ((offset = dec_num_string(p, end, bc->fac.calldeflect_nr)) < 0) + return -1; + p += offset; - int len = strlen(nr); - /* calldeflect facility */ - - /* cnip */ - if (strlen((char *)nr) > 15) - { -/* if (options.deb & DEBUG_PORT) */ - cb_log(1,0,"%s: NR text too long (max 13 chars), cutting.\n", __FUNCTION__); - nr[15] = '\0'; - } - - fac[0]=FACILITY_CALLDEFLECT; // .. - fac[1]=CALLDEFLECT_ID; - fac[2]=0x0f + len; // strlen destination + 15 = 26 - fac[3]=0x02; - fac[4]=0x01; - //fac[5]=0x70; - fac[5]=0x09; - fac[6]=0x02; - fac[7]=0x01; - fac[8]=0x0d; - fac[9]=0x30; - fac[10]=0x07 + len; // strlen destination + 7 = 18 - fac[11]=0x30; // ...hm 0x30 - fac[12]=0x02+ len; // strlen destination + 2 - fac[13]=0x80; // CLIP - fac[14]= len; // strlen destination - - memcpy((unsigned char *)fac+15,nr,len); - fac[15+len]=0x01; //sending complete - fac[16+len]=0x01; - fac[17+len]=0x80; - - enc_ie_facility(ntmode, msg, fac, 17+len +1 , nt , bc); -} + if ((offset = dec_bool(p, end, &pres)) < 0) + return -1; + + cb_log(0, 0, "CALLDEFLECT: dest:%s pres:%s (not implemented yet)\n", bc->fac.calldeflect_nr, pres ? "yes" : "no"); + bc->fac_type = FACILITY_CALLDEFLECT; + return 0; +} -void dec_ie_facility_calldeflect(unsigned char *p, Q931_info_t *qi, unsigned char *fac, int fac_len, unsigned char *cd_nr, int nt, struct misdn_bchannel *bc) +void fac_dec (__u8 *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc) { - *cd_nr = '\0'; - - if (fac_len >= 15) - { - if (fac[0] != FACILITY_CALLDEFLECT) - return; - if (fac[1] != CALLDEFLECT_ID) - return; - } else { - cb_log(1,bc->port, "IE too short: FAC_CALLDEFLECT\n"); - return ; - } - - - - { - int dest_len=fac[2]-0x0f; - - if (dest_len <0 || dest_len > 15) { - cb_log(1,bc->port, "IE is garbage: FAC_CALLDEFLECT\n"); - return ; - } - - if (fac_len < 15+dest_len) { - cb_log(1,bc->port, "IE too short: FAC_CALLDEFLECT\n"); - return ; - } - - memcpy(cd_nr, &fac[15],dest_len); - cd_nr[dest_len]=0; - - cb_log(5,bc->port, "--> IE CALLDEFLECT NR: %s\n",cd_nr); + int len, + offset, + inner_len, + invoke_id, + op_tag, + op_val; + __u8 *end, + *begin = p; + + if (!bc->nt) { + if (qi->QI_ELEMENT(facility)) + p = (__u8 *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(facility) + 1; + else + p = NULL; } -} + if (!p) + return; + offset = dec_len (p, &len); + if (offset < 0) { + cb_log(0, bc->port, "Could not decode FACILITY: dec_len failed!\n"); + return; + } + p += offset; + end = p + len; + FAC_DUMP(p, len, bc); -void fac_enc( unsigned char **ntmsg, msg_t * msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc) -{ - switch (type) { - case FACILITY_CENTREX: - { - int setup=0; - enc_ie_facility_centrex(ntmsg, msg, fac.cnip, setup, bc->nt, bc); - } - break; - case FACILITY_CALLDEFLECT: - enc_ie_facility_calldeflect(ntmsg, msg, fac.calldeflect_nr, bc->nt, bc); - break; - default: - cb_log(1,0,"Don't know how handle this facility: %d\n", type); + if (len < 3 || p[0] != SUPPLEMENTARY_SERVICE || p[1] != INVOKE) { + cb_log(0, bc->port, "Could not decode FACILITY: invalid or not supported!\n"); + return; } -} + p += 2; -void fac_dec( unsigned char *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc) -{ - int i, fac_len=0; - unsigned char facility[256]; + offset = dec_len (p, &inner_len); + if (offset < 0) { + cb_log(0, bc->port, "Could not decode FACILITY: failed parsing inner length!\n"); + return; + } + p += offset; - if (!bc->nt) - { - p = NULL; - if (qi->QI_ELEMENT(facility)) - p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->QI_ELEMENT(facility) + 1; + offset = dec_int (p, end, &invoke_id); + if (offset < 0) { + cb_log(0, bc->port, "Could not decode FACILITY: failed parsing invoke identifier!\n"); + return; } - if (!p) + p += offset; + + offset = _dec_int (p, end, &op_val, &op_tag); + if (offset < 0) { + cb_log(0, bc->port, "Could not decode FACILITY: failed parsing operation value!\n"); return; - - fac_len = p[0] & 0xff; + } + p += offset; - memcpy(facility, p+1, fac_len); - - switch(facility[0]) { - case FACILITY_CENTREX: - { - int cnip_len=15; - - dec_ie_facility_centrex(p, qi,facility, fac_len, fac->cnip, cnip_len, bc->nt, bc); - - *type=FACILITY_CENTREX; + if (op_tag != OPERATION_VALUE || offset != 3) { + cb_log(0, bc->port, "Could not decode FACILITY: operation value tag 0x%x unknown!\n", op_tag); + return; } - break; - case FACILITY_CALLDEFLECT: - dec_ie_facility_calldeflect(p, qi,facility, fac_len, fac->calldeflect_nr, bc->nt, bc); - - *type=FACILITY_CALLDEFLECT; + + switch (op_val) { + case CALL_DEFLECT: + cb_log(0, bc->port, "FACILITY: Call Deflect\n"); + dec_fac_calldeflect(p, len - (p - begin) + 1, bc); + break; + case AOC: + cb_log(0, bc->port, "FACILITY: AOC\n"); break; default: - cb_log(3, bc->port, "Unknown Facility received: "); - i = 0; - while(i < fac_len) - { - cb_log(3, bc->port, " %02x", facility[i]); - i++; - } - cb_log(3, bc->port, " facility\n"); - - *type=FACILITY_NONE; + cb_log(0, bc->port, "FACILITY unknown: operation value 0x%x, ignoring ...\n", op_val); } - - } - -/*** FACILITY END **/ - diff --git a/channels/misdn/fac.h b/channels/misdn/fac.h index acc41f17f..da6329967 100644 --- a/channels/misdn/fac.h +++ b/channels/misdn/fac.h @@ -1,8 +1,10 @@ -#ifndef FAC_H -#define FAC_H +#ifndef __FAC_H__ +#define __FAC_H__ -void fac_enc( unsigned char **ntmsg, msg_t * msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc); +#include "isdn_lib_intern.h" -void fac_dec( unsigned char *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc); +void fac_enc (__u8 **ntmsg, msg_t *msg, enum facility_type type, union facility fac, struct misdn_bchannel *bc); +void fac_dec (__u8 *p, Q931_info_t *qi, enum facility_type *type, union facility *fac, struct misdn_bchannel *bc); #endif + diff --git a/channels/misdn/isdn_lib.c b/channels/misdn/isdn_lib.c index 8209df926..8b6e08f5c 100644 --- a/channels/misdn/isdn_lib.c +++ b/channels/misdn/isdn_lib.c @@ -2589,6 +2589,7 @@ int handle_frm(msg_t *msg) bc=find_bc_by_l3id(stack, frm->dinfo); +handle_frm_bc: if (bc ) { enum event_e event = isdn_msg_get_event(msgs_g, msg, 0); enum event_response_e response=RESPONSE_OK; @@ -2602,7 +2603,7 @@ int handle_frm(msg_t *msg) if(!isdn_get_info(msgs_g,event,0)) cb_log(0, stack->port, "Unknown Event Ind: Addr:%x prim %x dinfo %x\n",frm->addr, frm->prim, frm->dinfo); - else + else response=cb_event(event, bc, glob_mgr->user_data); #if 1 if (event == EVENT_SETUP) { @@ -2644,7 +2645,13 @@ int handle_frm(msg_t *msg) #endif } else { - cb_log(0, stack->port, "NO BC FOR STACK\n"); + cb_log(0, stack->port, " --> Didn't find BC so temporarly creating dummy BC (l3id:%x) on this port.\n", frm->dinfo); + struct misdn_bchannel dummybc; + memset (&dummybc,0,sizeof(dummybc)); + dummybc.port=stack->port; + dummybc.l3_id=frm->dinfo; + bc=&dummybc; + goto handle_frm_bc; } } @@ -4023,6 +4030,32 @@ void manager_ph_control(struct misdn_bchannel *bc, int c1, int c2) mISDN_write(glob_mgr->midev, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC); } +/* + * allow live control of channel parameters + */ +void isdn_lib_update_rxgain (struct misdn_bchannel *bc) +{ + manager_ph_control(bc, VOL_CHANGE_RX, bc->rxgain); +} + +void isdn_lib_update_txgain (struct misdn_bchannel *bc) +{ + manager_ph_control(bc, VOL_CHANGE_TX, bc->txgain); +} + +void isdn_lib_update_ec (struct misdn_bchannel *bc) +{ + if (bc->ec_enable) + manager_ec_enable(bc); + else + manager_ec_disable(bc); +} + +void isdn_lib_stop_dtmf (struct misdn_bchannel *bc) +{ + manager_ph_control(bc, DTMF_TONE_STOP, 0); +} + /* * send control information to the channel (dsp-module) */ diff --git a/channels/misdn/isdn_lib.h b/channels/misdn/isdn_lib.h index 3673baf7d..5bb82d4d5 100644 --- a/channels/misdn/isdn_lib.h +++ b/channels/misdn/isdn_lib.h @@ -406,6 +406,10 @@ int misdn_lib_tx2misdn_frm(struct misdn_bchannel *bc, void *data, int len); void manager_ph_control(struct misdn_bchannel *bc, int c1, int c2); +void isdn_lib_update_rxgain (struct misdn_bchannel *bc); +void isdn_lib_update_txgain (struct misdn_bchannel *bc); +void isdn_lib_update_ec (struct misdn_bchannel *bc); +void isdn_lib_stop_dtmf (struct misdn_bchannel *bc); int misdn_lib_port_restart(int port); int misdn_lib_get_port_info(int port); diff --git a/channels/misdn/isdn_msg_parser.c b/channels/misdn/isdn_msg_parser.c index ae8aa76bf..5ee7f6f49 100644 --- a/channels/misdn/isdn_msg_parser.c +++ b/channels/misdn/isdn_msg_parser.c @@ -879,8 +879,7 @@ msg_t *build_release_complete (struct isdn_msg msgs[], struct misdn_bchannel *bc void parse_facility (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel *bc, int nt) { -//#define FACILITY_DECODE -#ifdef FACILITY_DECODE +#ifdef FACILITY_DEBUG int HEADER_LEN = nt?mISDNUSER_HEAD_SIZE:mISDN_HEADER_LEN; FACILITY_t *facility=(FACILITY_t*)((unsigned long)(msg->data+HEADER_LEN)); Q931_info_t *qi=(Q931_info_t*)(msg->data+HEADER_LEN); @@ -889,9 +888,7 @@ void parse_facility (struct isdn_msg msgs[], msg_t *msg, struct misdn_bchannel * printf("Parsing FACILITY Msg\n"); #endif - { - fac_dec(facility->FACILITY, qi, &bc->fac_type, &bc->fac, bc); - } + fac_dec(facility->FACILITY, qi, &bc->fac_type, &bc->fac, bc); #endif } diff --git a/channels/misdn_config.c b/channels/misdn_config.c index 48be30675..5bca76e93 100644 --- a/channels/misdn_config.c +++ b/channels/misdn_config.c @@ -113,7 +113,7 @@ static const struct misdn_cfg_spec port_spec[] = { "\tas well, since chan_misdn has no chance to distinguish if the L1 is down\n" "\tbecause of a lost Link or because the Provider shut it down..." }, { "block_on_alarm", MISDN_CFG_ALARM_BLOCK, MISDN_CTYPE_BOOL, "yes", NONE , - "Block this port if we have an alarm on it.\n" + "Block this port if we have an alarm on it." "default: yes\n" }, { "hdlc", MISDN_CFG_HDLC, MISDN_CTYPE_BOOL, "no", NONE, "Set this to yes, if you want to bridge a mISDN data channel to\n" @@ -212,7 +212,7 @@ static const struct misdn_cfg_spec port_spec[] = { { "nodialtone", MISDN_CFG_NODIALTONE, MISDN_CTYPE_BOOL, "no", NONE, "Enable this to prevent chan_misdn to generate the dialtone\n" "\tThis makes only sense together with the always_immediate=yes option\n" - "\tto generate your own dialtone with Playtones or so.\n"}, + "\tto generate your own dialtone with Playtones or so."}, { "immediate", MISDN_CFG_IMMEDIATE, MISDN_CTYPE_BOOL, "no", NONE, "Enable this if you want callers which called exactly the base\n" "\tnumber (so no extension is set) to jump into the s extension.\n" @@ -221,7 +221,7 @@ static const struct misdn_cfg_spec port_spec[] = { { "senddtmf", MISDN_CFG_SENDDTMF, MISDN_CTYPE_BOOL, "no", NONE, "Enable this if we should produce DTMF Tones ourselves." }, { "hold_allowed", MISDN_CFG_HOLD_ALLOWED, MISDN_CTYPE_BOOL, "no", NONE, - "Enable this to have support for hold and retrieve.\n" }, + "Enable this to have support for hold and retrieve." }, { "early_bconnect", MISDN_CFG_EARLY_BCONNECT, MISDN_CTYPE_BOOL, "yes", NONE, "Disable this if you don't mind correct handling of Progress Indicators." }, { "incoming_early_audio", MISDN_CFG_INCOMING_EARLY_AUDIO, MISDN_CTYPE_BOOL, "no", NONE, @@ -272,7 +272,19 @@ static const struct misdn_cfg_spec port_spec[] = { "Defines the maximum amount of outgoing calls per port for this group\n" "\texceeding calls will be rejected" }, { "faxdetect", MISDN_CFG_FAXDETECT, MISDN_CTYPE_STR, "no", NONE, - "Context to jump into if we detect an incoming fax." }, + "Setup fax detection:\n" + "\t no - no fax detection\n" + "\t incoming - fax detection for incoming calls\n" + "\t outgoing - fax detection for outgoing calls\n" + "\t both - fax detection for incoming and outgoing calls\n" + "\tAdd +nojump to your value (i.e. faxdetect=both+nojump) if you don't want to jump into the\n" + "\tfax-extension but still want to detect the fax and prepare the channel for fax transfer." }, + { "faxdetect_timeout", MISDN_CFG_FAXDETECT_TIMEOUT, MISDN_CTYPE_INT, "5", NONE, + "Number of seconds the fax detection should do its job. After the given period of time,\n" + "\twe assume that it's not a fax call and save some CPU time by turning off fax detection.\n" + "\tSet this to 0 if you don't want a timeout (never stop detecting)." }, + { "faxdetect_context", MISDN_CFG_FAXDETECT_CONTEXT, MISDN_CTYPE_STR, NO_DEFAULT, NONE, + "Context to jump into if we detect a fax. Don't set this if you want to stay in the current context." }, { "l1watcher_timeout", MISDN_CFG_L1_TIMEOUT, MISDN_CTYPE_BOOLINT, "0", 4, "Watches the layer 1. If the layer 1 is down, it tries to\n" "\tget it up. The timeout is given in seconds. with 0 as value it\n" @@ -342,28 +354,41 @@ static ast_mutex_t config_mutex; "Please edit your misdn.conf and then do a \"misdn reload\".\n", name, value, section); \ }) -static void _enum_array_map (void) +static int _enum_array_map (void) { - int i, j; + int i, j, ok; for (i = MISDN_CFG_FIRST + 1; i < MISDN_CFG_LAST; ++i) { if (i == MISDN_CFG_PTP) continue; + ok = 0; for (j = 0; j < NUM_PORT_ELEMENTS; ++j) { if (port_spec[j].elem == i) { map[i] = j; + ok = 1; break; } } + if (!ok) { + ast_log(LOG_WARNING, "Enum element %d in misdn_cfg_elements (port section) has no corresponding element in the config struct!\n", i); + return -1; + } } for (i = MISDN_GEN_FIRST + 1; i < MISDN_GEN_LAST; ++i) { + ok = 0; for (j = 0; j < NUM_GEN_ELEMENTS; ++j) { if (gen_spec[j].elem == i) { map[i] = j; + ok = 1; break; } } + if (!ok) { + ast_log(LOG_WARNING, "Enum element %d in misdn_cfg_elements (general section) has no corresponding element in the config struct!\n", i); + return -1; + } } + return 0; } static int get_cfg_position (char *name, int type) @@ -998,7 +1023,7 @@ void misdn_cfg_destroy (void) ast_mutex_destroy(&config_mutex); } -void misdn_cfg_init (int this_max_ports) +int misdn_cfg_init (int this_max_ports) { char config[] = "misdn.conf"; char *cat, *p; @@ -1007,8 +1032,8 @@ void misdn_cfg_init (int this_max_ports) struct ast_variable *v; if (!(cfg = AST_LOAD_CFG(config))) { - ast_log(LOG_WARNING,"no misdn.conf ?\n"); - return; + ast_log(LOG_WARNING, "missing file: misdn.conf\n"); + return -1; } ast_mutex_init(&config_mutex); @@ -1018,6 +1043,9 @@ void misdn_cfg_init (int this_max_ports) if (this_max_ports) { /* this is the first run */ max_ports = this_max_ports; + map = (int *)calloc(MISDN_GEN_LAST + 1, sizeof(int)); + if (_enum_array_map()) + return -1; p = (char *)calloc(1, (max_ports + 1) * sizeof(union misdn_cfg_pt *) + (max_ports + 1) * NUM_PORT_ELEMENTS * sizeof(union misdn_cfg_pt)); port_cfg = (union misdn_cfg_pt **)p; @@ -1028,8 +1056,6 @@ void misdn_cfg_init (int this_max_ports) } general_cfg = (union misdn_cfg_pt *)calloc(1, sizeof(union misdn_cfg_pt *) * NUM_GEN_ELEMENTS); ptp = (int *)calloc(max_ports + 1, sizeof(int)); - map = (int *)calloc(MISDN_GEN_LAST + 1, sizeof(int)); - _enum_array_map(); } else { /* misdn reload */ @@ -1044,18 +1070,20 @@ void misdn_cfg_init (int this_max_ports) while(cat) { v = ast_variable_browse(cfg, cat); - if (!strcasecmp(cat,"general")) { + if (!strcasecmp(cat, "general")) { _build_general_config(v); } else { _build_port_config(v, cat); } - cat = ast_category_browse(cfg,cat); + cat = ast_category_browse(cfg, cat); } _fill_defaults(); misdn_cfg_unlock(); AST_DESTROY_CFG(cfg); + + return 0; } -- cgit v1.2.3