diff --git a/CREDITS b/CREDITS index cef7cfc1a..b971259ef 100755 --- a/CREDITS +++ b/CREDITS @@ -6,6 +6,13 @@ and TSU 120e to the project. (http://www.adtran.com) * Thanks to QuickNet Technologies for their donation of an Internet PhoneJack card to the project. (http://www.quicknet.net) +=== DEVELOPMENT SUPPORT === +I'd like to thank the following companies for helping fund development of +Asterisk: + +* Celera Networks - US Digital +* Adtran, Inc. + === OTHER SOURCE CODE IN ASTERISK === I did not implement the codecs in asterisk. Here is the copyright on the diff --git a/README b/README index 0656a8985..704e31d67 100755 --- a/README +++ b/README @@ -1,7 +1,11 @@ The Asterisk Open Source PBX by Mark Spencer -Copyright (C) 1999, Mark Spencer +Copyright (C) 2001, Linux Support Services, Inc. ================================================================ +* SECURITY + It is imperative that you read and fully understand the contents of + the SECURITY file before you attempt to configure an Asterisk server. + * WHAT IS ASTERISK Asterisk is an Open Source PBX and telephony toolkit. It is, in a sense, middleware between Internet and telephony channels on the bottom, @@ -10,7 +14,27 @@ on the project itself, please visit the Asterisk home page at: http://www.asteriskpbx.com +* LICENSING + Asterisk is distributed under GNU General Public License. The GPL also +must apply to all loadable modules as well, except as defined below. + Linux Support Services, Inc. retains copyright to all of the core +Asterisk system, and therefore can grant, at its sole discression, the +ability for companies, individuals, or organizations to create proprietary +or Open Source (but non-GPL'd) modules which may be dynamically linked at +runtime with the portions of Asterisk which fall under our copyright +umbrella, or are distributed under more flexible licenses than GPL. At +this time (5/21/2001) the only component of Asterisk which is covered +under GPL and not under our Copyright is the Xing MP3 decoder. + + If you wish to use our code in other GPL programs, don't worry -- there +is no requirement that you provide the same exemption in your GPL'd +products (although if you've written a module for Asterisk we would +strongly encourage you to make the same excemption that we do). + + If you have any questions, whatsoever, regarding our licensing policy, +please contact us. + * REQUIRED COMPONENTS == Linux == diff --git a/SECURITY b/SECURITY new file mode 100755 index 000000000..fd9873958 --- /dev/null +++ b/SECURITY @@ -0,0 +1,38 @@ +==== Security Notes with Asterisk ==== + +PLEASE READ THE FOLLOWING IMPORTANT SECURITY RELATED INFORMATION. +IMPROPER CONFIGURATION OF ASTERISK COULD ALLOW UNAUTHORIZED USE OF YOUR +FACILITIES, POTENTIALLY INCURRING SUBSTANTIAL CHARGES. + +First and foremost remember this: + +USE THE EXTENSION CONTEXTS TO ISOLATE OUTGOING OR TOLL SERVICES FROM ANY +INCOMING CONNECTIONS. + +You should consider that if any channel, incoming line, etc can enter an +extension context that it has the capability of accessing any extension +within that context. + +Therefore, you should NOT allow access to outgoing or toll services in +contexts that are accessible (especially without a password) from incoming +channels, be they IAX channels, FX or other trunks, or even untrusted +stations within you network. In particular, never ever put outgoing toll +services in the "default" context. To make things easier, you can include +the "default" context within other private contexts by using: + + include => default + +in the appropriate section. A well designed PBX might look like this: + +[longdistance] +exten => _91NXXNXXXXXX,1,Dial,Tor/g2/BYEXTENSION +include => local + +[local] +exten => _9NXXNXXX,1,Dial,Tor/g2/BYEXTENSION +include => default + +[default] +exten => 6123,Dial,Tor/1 + + diff --git a/apps/app_image.c b/apps/app_image.c new file mode 100755 index 000000000..cc677ff5c --- /dev/null +++ b/apps/app_image.c @@ -0,0 +1,89 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * + * App to transmit an image + * + * Copyright (C) 1999, Mark Spencer + * + * Mark Spencer + * + * This program is free software, distributed under the terms of + * the GNU General Public License + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *tdesc = "Image Transmission Application"; + +static char *app = "SendImage"; + +static char *synopsis = "Send an image file"; + +static char *descrip = +" SendImage(filename): Sends an image on a channel. If the channel\n" +"does not support image transport, and there exists a step with\n" +"priority n + 101, then execution will continue at that step.\n" +"Otherwise, execution will continue at the next priority level.\n" +"SendImage only returns 0 if the image was sent correctly or if\n" +"the channel does not support image transport, and -1 otherwise.\n"; + +STANDARD_LOCAL_USER; + +LOCAL_USER_DECL; + +static int sendimage_exec(struct ast_channel *chan, void *data) +{ + int res = 0; + struct localuser *u; + if (!data || !strlen((char *)data)) { + ast_log(LOG_WARNING, "SendImage requires an argument (filename)\n"); + return -1; + } + LOCAL_USER_ADD(u); + if (!ast_supports_images(chan)) { + /* Does not support transport */ + if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) + chan->priority += 100; + return 0; + } + res = ast_send_image(chan, data); + LOCAL_USER_REMOVE(u); + return res; +} + +int unload_module(void) +{ + STANDARD_HANGUP_LOCALUSERS; + return ast_unregister_application(app); +} + +int load_module(void) +{ + return ast_register_application(app, sendimage_exec, synopsis, descrip); +} + +char *description(void) +{ + return tdesc; +} + +int usecount(void) +{ + int res; + STANDARD_USECOUNT(res); + return res; +} + +char *key() +{ + return ASTERISK_GPL_KEY; +} diff --git a/apps/app_system.c b/apps/app_system.c index bb10543e2..a4369125f 100755 --- a/apps/app_system.c +++ b/apps/app_system.c @@ -31,10 +31,11 @@ static char *app = "System"; static char *synopsis = "Execute a system command"; static char *descrip = -" System(command): Executes a command by using system(). Returns -1 on failure to execute\n" -" the specified command. If the command itself executes but is in error, and if there exists\n" -" a priority n + 101, where 'n' is the priority of the current instance, then the channel will\n" -" will be setup to continue at that priority level. Otherwise, System returns 0.\n"; +" System(command): Executes a command by using system(). Returns -1 on\n" +"failure to execute the specified command. If the command itself executes\n" +"but is in error, and if there exists a priority n + 101, where 'n' is the\n" +"priority of the current instance, then the channel will be setup to\n" +"continue at that priority level. Otherwise, System returns 0.\n"; STANDARD_LOCAL_USER; @@ -58,7 +59,7 @@ static int skel_exec(struct ast_channel *chan, void *data) ast_log(LOG_WARNING, "Unable to execute '%s'\n", data); res = -1; } else { - if (res && ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101)) + if (res && ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) chan->priority+=100; res = 0; } diff --git a/apps/app_url.c b/apps/app_url.c new file mode 100755 index 000000000..542c490a7 --- /dev/null +++ b/apps/app_url.c @@ -0,0 +1,137 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * + * App to transmit a URL + * + * Copyright (C) 1999, Mark Spencer + * + * Mark Spencer + * + * This program is free software, distributed under the terms of + * the GNU General Public License + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *tdesc = "Send URL Applications"; + +static char *app = "SendURL"; + +static char *synopsis = "Send a URL"; + +static char *descrip = +" SendURL(URL[|option]): Requests client go to URL. If the client\n" +"does not support html transport, and there exists a step with\n" +"priority n + 101, then execution will continue at that step.\n" +"Otherwise, execution will continue at the next priority level.\n" +"SendURL only returns 0 if the URL was sent correctly or if\n" +"the channel does not support HTML transport, and -1 otherwise.\n" +"If the option 'wait' is specified, execution will wait for an\n" +"acknowledgement that the URL has been loaded before continuing\n" +"and will return -1 if the peer is unable to load the URL\n"; + +STANDARD_LOCAL_USER; + +LOCAL_USER_DECL; + +static int sendurl_exec(struct ast_channel *chan, void *data) +{ + int res = 0; + struct localuser *u; + char tmp[256]; + char *options; + int option_wait=0; + struct ast_frame *f; + if (!data || !strlen((char *)data)) { + ast_log(LOG_WARNING, "SendURL requires an argument (URL)\n"); + return -1; + } + strncpy(tmp, (char *)data, sizeof(tmp)); + strtok(tmp, "|"); + options = strtok(NULL, "|"); + if (options && !strcasecmp(options, "wait")) + option_wait = 1; + LOCAL_USER_ADD(u); + if (!ast_channel_supports_html(chan)) { + /* Does not support transport */ + if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) + chan->priority += 100; + LOCAL_USER_REMOVE(u); + return 0; + } + res = ast_channel_sendurl(chan, tmp); + if (res > -1) { + if (option_wait) { + for(;;) { + /* Wait for an event */ + res = ast_waitfor(chan, -1); + if (res < 0) + break; + f = ast_read(chan); + if (!f) { + res = -1; + break; + } + if (f->frametype == AST_FRAME_HTML) { + switch(f->subclass) { + case AST_HTML_LDCOMPLETE: + res = 0; + ast_frfree(f); + goto out; + break; + case AST_HTML_NOSUPPORT: + /* Does not support transport */ + if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) + chan->priority += 100; + res = 0; + goto out; + break; + default: + ast_log(LOG_WARNING, "Don't know what to do with HTML subclass %d\n", f->subclass); + }; + } + ast_frfree(f); + } + } + } +out: + LOCAL_USER_REMOVE(u); + return res; +} + +int unload_module(void) +{ + STANDARD_HANGUP_LOCALUSERS; + return ast_unregister_application(app); +} + +int load_module(void) +{ + return ast_register_application(app, sendurl_exec, synopsis, descrip); +} + +char *description(void) +{ + return tdesc; +} + +int usecount(void) +{ + int res; + STANDARD_USECOUNT(res); + return res; +} + +char *key() +{ + return ASTERISK_GPL_KEY; +} diff --git a/callerid.c b/callerid.c index f78714fbf..438d2b38b 100755 --- a/callerid.c +++ b/callerid.c @@ -62,7 +62,7 @@ struct callerid_state *callerid_new(void) { struct callerid_state *cid; cid = malloc(sizeof(struct callerid_state)); - memset(cid, 0, sizeof(*cid)); + memset(cid, 0, sizeof(struct callerid_state)); if (cid) { cid->fskd.spb = 7; /* 1200 baud */ cid->fskd.hdlc = 0; /* Async */ @@ -146,6 +146,10 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len) while(mylen >= 80) { olen = mylen; res = fsk_serie(&cid->fskd, buf, &mylen, &b); + if (mylen < 0) { + ast_log(LOG_ERROR, "fsk_serie made mylen < 0 (%d)\n", mylen); + return -1; + } buf += (olen - mylen); if (res < 0) { ast_log(LOG_NOTICE, "fsk_serie failed\n"); @@ -263,7 +267,8 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len) if (mylen) { memcpy(cid->oldstuff, buf, mylen * 2); cid->oldlen = mylen * 2; - } + } else + cid->oldlen = 0; free(obuf); return 0; } @@ -444,7 +449,7 @@ void ast_shrink_phone_number(char *n) int ast_isphonenumber(char *n) { int x; - if (!n) + if (!n || !strlen(n)) return 0; for (x=0;n[x];x++) if (!strchr("0123456789", n[x])) @@ -483,7 +488,7 @@ int ast_callerid_parse(char *instr, char **name, char **location) } else { strncpy(tmp, instr, sizeof(tmp)); ast_shrink_phone_number(tmp); - if (!ast_isphonenumber(tmp)) { + if (ast_isphonenumber(tmp)) { /* Assume it's just a location */ *name = NULL; *location = instr; diff --git a/channels/chan_oss.c b/channels/chan_oss.c index 784067a97..fab41ed14 100755 --- a/channels/chan_oss.c +++ b/channels/chan_oss.c @@ -56,6 +56,7 @@ static struct timeval lasttime; static int usecnt; static int needanswer = 0; +static int needringing = 0; static int needhangup = 0; static int silencesuppression = 0; static int silencethreshold = 1000; @@ -438,6 +439,7 @@ static int oss_call(struct ast_channel *c, char *dest, int timeout) needanswer = 1; } else { ast_verbose( " << Type 'answer' to answer, or use 'autoanswer' for future calls >> \n"); + needringing = 1; write(sndcmd[1], &res, sizeof(res)); } return 0; @@ -591,7 +593,15 @@ static struct ast_frame *oss_read(struct ast_channel *chan) f.src = type; f.mallocd = 0; + if (needringing) { + f.frametype = AST_FRAME_CONTROL; + f.subclass = AST_CONTROL_RINGING; + needringing = 0; + return &f; + } + if (needhangup) { + needhangup = 0; return NULL; } if (strlen(text2send)) { @@ -632,8 +642,10 @@ static struct ast_frame *oss_read(struct ast_channel *chan) } res = read(sounddev, buf + AST_FRIENDLY_OFFSET + readpos, FRAME_SIZE * 2 - readpos); if (res < 0) { - ast_log(LOG_WARNING, "Error reading from sound device: %s\n", strerror(errno)); + ast_log(LOG_WARNING, "Error reading from sound device (If you're running 'artsd' then kill it): %s\n", strerror(errno)); +#if 0 CRASH; +#endif return NULL; } readpos += res; @@ -641,6 +653,10 @@ static struct ast_frame *oss_read(struct ast_channel *chan) if (readpos >= FRAME_SIZE * 2) { /* A real frame */ readpos = 0; + if (chan->state != AST_STATE_UP) { + /* Don't transmit unless it's up */ + return &f; + } f.frametype = AST_FRAME_VOICE; f.subclass = AST_FORMAT_SLINEAR; f.timelen = FRAME_SIZE / 8; @@ -887,7 +903,7 @@ static int console_dial(int fd, int argc, char *argv[]) if (tmp2 && strlen(tmp2)) myc = tmp2; } - if (ast_exists_extension(NULL, myc, mye, 1)) { + if (ast_exists_extension(NULL, myc, mye, 1, NULL)) { strncpy(oss.exten, mye, sizeof(oss.exten)); strncpy(oss.context, myc, sizeof(oss.context)); hookstate = 1; diff --git a/channels/chan_phone.c b/channels/chan_phone.c index d0ff80843..27de1daac 100755 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -35,6 +35,7 @@ #include "DialTone.h" #define PHONE_MAX_BUF 480 +#define DEFAULT_GAIN 0x100 static char *desc = "Linux Telephony API Support"; static char *type = "Phone"; @@ -52,7 +53,7 @@ static int echocancel = AEC_OFF; static int silencesupression = 0; -static int prefformat = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR; +static int prefformat = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW; static pthread_mutex_t usecnt_lock = PTHREAD_MUTEX_INITIALIZER; @@ -90,13 +91,19 @@ static struct phone_pvt { char buf[PHONE_MAX_BUF]; /* Static buffer for reading frames */ int obuflen; int dialtone; + int txgain, rxgain; /* gain control for playing, recording */ + /* 0x100 - 1.0, 0x200 - 2.0, 0x80 - 0.5 */ + int cpt; /* Call Progress Tone playing? */ int silencesupression; char context[AST_MAX_EXTENSION]; char obuf[PHONE_MAX_BUF * 2]; char ext[AST_MAX_EXTENSION]; char language[MAX_LANGUAGE]; + char callerid[AST_MAX_EXTENSION]; } *iflist = NULL; +static char callerid[AST_MAX_EXTENSION]; + static int phone_digit(struct ast_channel *ast, char digit) { struct phone_pvt *p; @@ -179,6 +186,7 @@ static int phone_hangup(struct ast_channel *ast) if (option_debug) ast_log(LOG_DEBUG, "Got hunghup, giving busy signal\n"); ioctl(p->fd, PHONE_BUSY); + p->cpt = 1; } p->lastformat = -1; p->lastinput = -1; @@ -226,6 +234,15 @@ static int phone_setup(struct ast_channel *ast) return -1; } } + } else if (ast->pvt->rawreadformat == AST_FORMAT_ULAW) { + ioctl(p->fd, PHONE_REC_STOP); + if (p->lastinput != AST_FORMAT_ULAW) { + p->lastinput = AST_FORMAT_ULAW; + if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) { + ast_log(LOG_WARNING, "Failed to set codec to signed linear 16\n"); + return -1; + } + } } else { ast_log(LOG_WARNING, "Can't do format %d\n", ast->pvt->rawreadformat); return -1; @@ -397,8 +414,16 @@ static int phone_write_buf(struct phone_pvt *p, char *buf, int len, int frlen) #endif if (res != frlen) { if (res < 1) { +/* + * Card is in non-blocking mode now and it works well now, but there are + * lot of messages like this. So, this message is temporarily disabled. + */ +#if 0 ast_log(LOG_WARNING, "Write failed: %s\n", strerror(errno)); return -1; +#else + return 0; +#endif } else { ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frlen); } @@ -427,7 +452,8 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) ast_frfree(frame); return -1; } - if (!(frame->subclass & (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR))) { + if (!(frame->subclass & + (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW))) { ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass); ast_frfree(frame); return -1; @@ -479,6 +505,25 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) p->obuflen = 0; } maxfr = 480; + } else if (frame->subclass == AST_FORMAT_ULAW) { + if (p->lastformat != AST_FORMAT_ULAW) { + ioctl(p->fd, PHONE_PLAY_STOP); + ioctl(p->fd, PHONE_REC_STOP); + if (ioctl(p->fd, PHONE_PLAY_CODEC, ULAW)) { + ast_log(LOG_WARNING, "Unable to set uLaw mode\n"); + return -1; + } + if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) { + ast_log(LOG_WARNING, "Unable to set uLaw mode\n"); + return -1; + } + p->lastformat = AST_FORMAT_ULAW; + p->lastinput = AST_FORMAT_ULAW; + codecset = 1; + /* Reset output buffer */ + p->obuflen = 0; + } + maxfr = 240; } if (codecset) { ioctl(p->fd, PHONE_REC_DEPTH, 3); @@ -517,8 +562,14 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) if (res != expected) { if (res < 0) ast_log(LOG_WARNING, "Write returned error (%s)\n", strerror(errno)); +/* + * Card is in non-blocking mode now and it works well now, but there are + * lot of messages like this. So, this message is temporarily disabled. + */ +#if 0 else ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frame->datalen); +#endif return -1; } sofar += res; @@ -553,6 +604,8 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *conte strncpy(tmp->exten, i->ext, sizeof(tmp->exten)); if (strlen(i->language)) strncpy(tmp->language, i->language, sizeof(tmp->language)); + if (strlen(i->callerid)) + tmp->callerid = strdup(i->callerid); i->owner = tmp; ast_pthread_mutex_lock(&usecnt_lock); usecnt++; @@ -561,6 +614,7 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *conte if (state != AST_STATE_DOWN) { if (state == AST_STATE_RING) { ioctl(tmp->fds[0], PHONE_RINGBACK); + i->cpt = 1; } if (ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); @@ -603,7 +657,7 @@ static void phone_check_exception(struct phone_pvt *i) i->dialtone = 0; if (strlen(i->ext) < AST_MAX_EXTENSION - 1) strcat(i->ext, digit); - if (ast_exists_extension(NULL, i->context, i->ext, 1)) { + if (ast_exists_extension(NULL, i->context, i->ext, 1, i->callerid)) { /* It's a valid extension in its context, get moving! */ phone_new(i, AST_STATE_RING, i->context); /* No need to restart monitor, we are the monitor */ @@ -613,10 +667,10 @@ static void phone_check_exception(struct phone_pvt *i) ast_pthread_mutex_unlock(&usecnt_lock); ast_update_use_count(); } - } else if (!ast_canmatch_extension(NULL, i->context, i->ext, 1)) { + } else if (!ast_canmatch_extension(NULL, i->context, i->ext, 1, i->callerid)) { /* There is nothing in the specified extension that can match anymore. Try the default */ - if (ast_exists_extension(NULL, "default", i->ext, 1)) { + if (ast_exists_extension(NULL, "default", i->ext, 1, i->callerid)) { /* Check the default, too... */ phone_new(i, AST_STATE_RING, "default"); if (i->owner) { @@ -626,11 +680,12 @@ static void phone_check_exception(struct phone_pvt *i) ast_update_use_count(); } /* XXX This should probably be justified better XXX */ - } else if (!ast_canmatch_extension(NULL, "default", i->ext, 1)) { + } else if (!ast_canmatch_extension(NULL, "default", i->ext, 1, i->callerid)) { /* It's not a valid extension, give a busy signal */ if (option_debug) ast_log(LOG_DEBUG, "%s can't match anything in %s or default\n", i->ext, i->context); ioctl(i->fd, PHONE_BUSY); + i->cpt = 1; } } #if 0 @@ -665,7 +720,11 @@ static void phone_check_exception(struct phone_pvt *i) ast_update_use_count(); } memset(i->ext, 0, sizeof(i->ext)); - ioctl(i->fd, PHONE_CPT_STOP); + if (i->cpt) + { + ioctl(i->fd, PHONE_CPT_STOP); + i->cpt = 0; + } ioctl(i->fd, PHONE_PLAY_STOP); ioctl(i->fd, PHONE_REC_STOP); i->dialtone = 0; @@ -833,13 +892,11 @@ static int restart_monitor() return 0; } -static struct phone_pvt *mkif(char *iface, int mode) +static struct phone_pvt *mkif(char *iface, int mode, int txgain, int rxgain) { /* Make a phone_pvt structure for this interface */ struct phone_pvt *tmp; -#if 0 int flags; -#endif tmp = malloc(sizeof(struct phone_pvt)); if (tmp) { @@ -852,6 +909,9 @@ static struct phone_pvt *mkif(char *iface, int mode) if (mode == MODE_FXO) { if (ioctl(tmp->fd, IXJCTL_PORT, PORT_PSTN)) ast_log(LOG_DEBUG, "Unable to set port to PSTN\n"); + } else { + if (ioctl(tmp->fd, IXJCTL_PORT, PORT_POTS)) + ast_log(LOG_DEBUG, "Unable to set port to PSTN\n"); } ioctl(tmp->fd, PHONE_PLAY_STOP); ioctl(tmp->fd, PHONE_REC_STOP); @@ -867,10 +927,8 @@ static struct phone_pvt *mkif(char *iface, int mode) ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression); #endif tmp->mode = mode; -#if 0 flags = fcntl(tmp->fd, F_GETFL); fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK); -#endif tmp->owner = NULL; tmp->lastformat = -1; tmp->lastinput = -1; @@ -882,6 +940,12 @@ static struct phone_pvt *mkif(char *iface, int mode) tmp->next = NULL; tmp->obuflen = 0; tmp->dialtone = 0; + tmp->cpt = 0; + strncpy(tmp->callerid, callerid, sizeof(tmp->callerid)); + tmp->txgain = txgain; + ioctl(tmp->fd, PHONE_PLAY_VOLUME, tmp->txgain); + tmp->rxgain = rxgain; + ioctl(tmp->fd, PHONE_REC_VOLUME, tmp->rxgain); } return tmp; } @@ -894,7 +958,7 @@ static struct ast_channel *phone_request(char *type, int format, void *data) char *name = data; oldformat = format; - format &= (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR); + format &= (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW); if (!format) { ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat); return NULL; @@ -919,12 +983,36 @@ static struct ast_channel *phone_request(char *type, int format, void *data) return tmp; } +/* parse gain value from config file */ +static int parse_gain_value(char *gain_type, char *value) +{ + float gain; + + /* try to scan number */ + if (sscanf(value, "%f", &gain) != 1) + { + ast_log(LOG_ERROR, "Invalid %s value '%s' in '%s' config\n", + value, gain_type, config); + return DEFAULT_GAIN; + } + + /* multiplicate gain by 1.0 gain value */ + gain = gain * (float)DEFAULT_GAIN; + + /* percentage? */ + if (value[strlen(value) - 1] == '%') + return (int)(gain / (float)100); + + return (int)gain; +} + int load_module() { struct ast_config *cfg; struct ast_variable *v; struct phone_pvt *tmp; int mode = MODE_IMMEDIATE; + int txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; /* default gain 1.0 */ cfg = ast_load(config); /* We *must* have a config file otherwise stop immediately */ @@ -941,7 +1029,7 @@ int load_module() while(v) { /* Create the interface list */ if (!strcasecmp(v->name, "device")) { - tmp = mkif(v->value, mode); + tmp = mkif(v->value, mode, txgain, rxgain); if (tmp) { tmp->next = iflist; iflist = tmp; @@ -957,6 +1045,8 @@ int load_module() silencesupression = ast_true(v->value); } else if (!strcasecmp(v->name, "language")) { strncpy(language, v->value, sizeof(language)); + } else if (!strcasecmp(v->name, "callerid")) { + strncpy(callerid, v->value, sizeof(callerid)); } else if (!strcasecmp(v->name, "mode")) { if (!strncasecmp(v->value, "di", 2)) mode = MODE_DIALTONE; @@ -988,12 +1078,17 @@ int load_module() echocancel = AEC_HIGH; } else ast_log(LOG_WARNING, "Unknown echo cancellation '%s'\n", v->value); - } + } else if (!strcasecmp(v->name, "txgain")) { + txgain = parse_gain_value(v->name, v->value); + } else if (!strcasecmp(v->name, "rxgain")) { + rxgain = parse_gain_value(v->name, v->value); + } v = v->next; } ast_pthread_mutex_unlock(&iflock); /* Make sure we can register our Adtranphone channel type */ - if (ast_channel_register(type, tdesc, AST_FORMAT_G723_1, phone_request)) { + if (ast_channel_register(type, tdesc, + AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW, phone_request)) { ast_log(LOG_ERROR, "Unable to register channel class %s\n", type); ast_destroy(cfg); unload_module();