1999-12-16 22:47:49 +00:00
/*
* Asterisk - - A telephony toolkit for Linux .
*
* A / Open ITU - 56 / 2 Voice Modem Driver ( Rockwell , IS - 101 , and others )
*
2005-01-21 07:06:25 +00:00
* Copyright ( C ) 1999 - 2005 , Digium , Inc .
1999-12-16 22:47:49 +00:00
*
2004-10-02 00:58:31 +00:00
* Mark Spencer < markster @ digium . com >
1999-12-16 22:47:49 +00:00
*
* This program is free software , distributed under the terms of
* the GNU General Public License
*/
# include <stdio.h>
# include <string.h>
2005-04-21 06:02:45 +00:00
# include "asterisk/lock.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/vmodem.h"
# include "asterisk/utils.h"
1999-12-16 22:47:49 +00:00
# include <sys/socket.h>
# include <sys/time.h>
# include <errno.h>
# include <unistd.h>
# include <stdlib.h>
2003-09-08 16:48:07 +00:00
# include <netinet/in.h>
1999-12-16 22:47:49 +00:00
# include <arpa/inet.h>
# include <fcntl.h>
# include <sys/ioctl.h>
# include <sys/termios.h>
# include <sys/signal.h>
# include <ctype.h>
/* Up to 10 seconds for an echo to arrive */
# define ECHO_TIMEOUT 10
2005-03-04 06:47:24 +00:00
static const char desc [ ] = " Generic Voice Modem Driver " ;
static const char tdesc [ ] = " Generic Voice Modem Channel Driver " ;
static const char type [ ] = " Modem " ;
static const char config [ ] = " modem.conf " ;
1999-12-16 22:47:49 +00:00
static char dialtype = ' T ' ;
static int gmode = MODEM_MODE_IMMEDIATE ;
/* Default modem type */
static char mtype [ 80 ] = " autodetect " ;
/* Default context for incoming calls */
static char context [ AST_MAX_EXTENSION ] = " default " ;
2000-01-10 17:43:38 +00:00
/* Default language */
static char language [ MAX_LANGUAGE ] = " " ;
1999-12-16 22:47:49 +00:00
/* Initialization String */
2001-06-19 16:17:52 +00:00
static char initstr [ AST_MAX_INIT_STR ] = " ATE0Q0 " ;
1999-12-16 22:47:49 +00:00
2000-12-29 14:05:23 +00:00
/* Default MSN */
static char msn [ AST_MAX_EXTENSION ] = " " ;
2002-11-11 18:21:17 +00:00
/* Default Listen */
static char incomingmsn [ AST_MAX_EXTENSION ] = " " ;
2004-06-22 14:17:07 +00:00
/* Default DTMF-detection mode (i4l/asterisk) */
static int dtmfmode = MODEM_DTMF_AST ;
/* Default DTMF-generation mode (i4l (outband) / asterisk (inband) */
static int dtmfmodegen = MODEM_DTMF_AST ;
struct ast_dsp * dsp = NULL ;
2004-06-21 04:29:50 +00:00
/* Default valid outgoing MSN */
static char outgoingmsn [ AST_MAX_EXTENSION ] = " " ;
2002-11-11 18:21:17 +00:00
/* Default group */
2005-01-15 21:51:38 +00:00
static ast_group_t cur_group = 0 ;
2002-11-11 18:21:17 +00:00
1999-12-16 22:47:49 +00:00
static int usecnt = 0 ;
static int baudrate = 115200 ;
static int stripmsd = 0 ;
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( usecnt_lock ) ;
1999-12-16 22:47:49 +00:00
/* Protect the interface list (of ast_modem_pvt's) */
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( iflock ) ;
1999-12-16 22:47:49 +00:00
/* Protect the monitoring thread, so only one process can kill or start it, and not
when it ' s doing something critical . */
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( monlock ) ;
1999-12-16 22:47:49 +00:00
/* This is the thread for the monitor which checks for input on the channels
which are not currently in use . */
2004-03-15 07:51:22 +00:00
static pthread_t monitor_thread = AST_PTHREADT_NULL ;
1999-12-16 22:47:49 +00:00
static int restart_monitor ( void ) ;
2005-03-04 06:47:24 +00:00
static struct ast_channel * modem_request ( const char * type , int format , void * data , int * cause ) ;
static int modem_digit ( struct ast_channel * ast , char digit ) ;
static int modem_call ( struct ast_channel * ast , char * idest , int timeout ) ;
static int modem_hangup ( struct ast_channel * ast ) ;
static int modem_answer ( struct ast_channel * ast ) ;
static struct ast_frame * modem_read ( struct ast_channel * ) ;
static int modem_write ( struct ast_channel * ast , struct ast_frame * frame ) ;
static int modem_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan ) ;
static const struct ast_channel_tech modem_tech = {
. type = type ,
. description = tdesc ,
. capabilities = AST_FORMAT_SLINEAR ,
. requester = modem_request ,
. send_digit = modem_digit ,
. call = modem_call ,
. hangup = modem_hangup ,
. answer = modem_answer ,
. read = modem_read ,
. write = modem_write ,
. fixup = modem_fixup ,
} ;
1999-12-16 22:47:49 +00:00
/* The private structures of the Phone Jack channels are linked for
selecting outgoing channels */
static struct ast_modem_pvt * iflist = NULL ;
static int modem_digit ( struct ast_channel * ast , char digit )
{
struct ast_modem_pvt * p ;
2005-03-04 06:47:24 +00:00
p = ast - > tech_pvt ;
1999-12-16 22:47:49 +00:00
if ( p - > mc - > dialdigit )
return p - > mc - > dialdigit ( p , digit ) ;
2002-11-11 18:21:17 +00:00
ast_log ( LOG_DEBUG , " Channel %s lacks digit dialing \n " , ast - > name ) ;
return - 1 ;
1999-12-16 22:47:49 +00:00
}
static struct ast_modem_driver * drivers = NULL ;
static struct ast_modem_driver * find_capability ( char * ident )
{
struct ast_modem_driver * mc ;
int x ;
mc = drivers ;
while ( mc ) {
for ( x = 0 ; mc - > idents [ x ] ; x + + ) {
if ( ! strcmp ( ident , mc - > idents [ x ] ) )
break ;
}
if ( mc - > idents [ x ] )
break ;
mc = mc - > next ;
}
if ( mc ) {
if ( mc - > incusecnt )
mc - > incusecnt ( ) ;
}
return mc ;
}
static struct ast_modem_driver * find_driver ( char * drv )
{
struct ast_modem_driver * mc ;
mc = drivers ;
while ( mc ) {
if ( ! strcasecmp ( mc - > name , drv ) )
break ;
mc = mc - > next ;
}
if ( mc ) {
if ( mc - > incusecnt )
mc - > incusecnt ( ) ;
}
return mc ;
}
int ast_register_modem_driver ( struct ast_modem_driver * mc )
{
mc - > next = drivers ;
drivers = mc ;
return 0 ;
}
int ast_unregister_modem_driver ( struct ast_modem_driver * mc )
{
struct ast_modem_driver * last = NULL , * cur ;
cur = drivers ;
while ( cur ) {
if ( cur = = mc ) {
if ( last )
last - > next = mc - > next ;
else
drivers = mc - > next ;
return 0 ;
}
cur = cur - > next ;
}
return - 1 ;
}
static int modem_call ( struct ast_channel * ast , char * idest , int timeout )
{
struct ast_modem_pvt * p ;
int ms = timeout ;
2004-07-16 04:40:54 +00:00
char rdest [ 80 ] , * where , dstr [ 100 ] = " " ;
2002-11-11 18:21:17 +00:00
char * stringp = NULL ;
2001-10-18 16:47:57 +00:00
strncpy ( rdest , idest , sizeof ( rdest ) - 1 ) ;
2002-11-11 18:21:17 +00:00
stringp = rdest ;
strsep ( & stringp , " : " ) ;
where = strsep ( & stringp , " : " ) ;
1999-12-16 22:47:49 +00:00
if ( ! where ) {
ast_log ( LOG_WARNING , " Destination %s requres a real destination (device:destination) \n " , idest ) ;
return - 1 ;
}
2005-03-04 06:47:24 +00:00
p = ast - > tech_pvt ;
2004-07-16 04:40:54 +00:00
strncpy ( dstr , where + p - > stripmsd , sizeof ( dstr ) - 1 ) ;
2001-06-19 16:17:52 +00:00
/* if not a transfer or just sending tones, must be in correct state */
if ( strcasecmp ( rdest , " transfer " ) & & strcasecmp ( rdest , " sendtones " ) ) {
2002-07-12 09:03:50 +00:00
if ( ( ast - > _state ! = AST_STATE_DOWN ) & & ( ast - > _state ! = AST_STATE_RESERVED ) ) {
2001-06-19 16:17:52 +00:00
ast_log ( LOG_WARNING , " modem_call called on %s, neither down nor reserved \n " , ast - > name ) ;
return - 1 ;
}
}
if ( ! strcasecmp ( rdest , " transfer " ) ) /* if a transfer, put in transfer stuff */
{
2004-07-16 04:40:54 +00:00
snprintf ( dstr , sizeof ( dstr ) , " !,%s " , where + p - > stripmsd ) ;
1999-12-16 22:47:49 +00:00
}
if ( ! strcasecmp ( where , " handset " ) ) {
if ( p - > mc - > setdev )
if ( p - > mc - > setdev ( p , MODEM_DEV_HANDSET ) )
return - 1 ;
/* Should be immediately up */
2002-07-12 09:03:50 +00:00
ast_setstate ( ast , AST_STATE_UP ) ;
1999-12-16 22:47:49 +00:00
} else {
if ( p - > mc - > setdev )
if ( p - > mc - > setdev ( p , MODEM_DEV_TELCO_SPK ) )
return - 1 ;
if ( p - > mc - > dial )
2001-06-19 16:17:52 +00:00
p - > mc - > dial ( p , dstr ) ;
2002-07-12 09:03:50 +00:00
ast_setstate ( ast , AST_STATE_DIALING ) ;
while ( ( ast - > _state ! = AST_STATE_UP ) & & ( ms > 0 ) ) {
1999-12-16 22:47:49 +00:00
ms = ast_waitfor ( ast , ms ) ;
/* Just read packets and watch what happens */
if ( ms > 0 ) {
if ( ! modem_read ( ast ) )
return - 1 ;
}
}
if ( ms < 0 )
return - 1 ;
}
return 0 ;
}
int ast_modem_send ( struct ast_modem_pvt * p , char * cmd , int len )
{
2001-06-19 16:17:52 +00:00
int i ;
usleep ( 5000 ) ;
1999-12-16 22:47:49 +00:00
if ( ! len ) {
2001-06-19 16:17:52 +00:00
for ( i = 0 ; cmd [ i ] ; )
{
if ( fwrite ( cmd + i , 1 , 1 , p - > f ) ! = 1 )
{
if ( errno = = EWOULDBLOCK ) continue ;
return - 1 ;
}
i + + ;
}
tcdrain ( fileno ( p - > f ) ) ;
fprintf ( p - > f , " \r \n " ) ;
1999-12-16 22:47:49 +00:00
return 0 ;
} else {
if ( fwrite ( cmd , 1 , len , p - > f ) < len )
return - 1 ;
return 0 ;
}
}
int ast_modem_read_response ( struct ast_modem_pvt * p , int timeout )
{
2001-06-19 16:17:52 +00:00
int res = - 1 , c , i ;
1999-12-16 22:47:49 +00:00
timeout * = 1000 ;
2001-06-19 16:17:52 +00:00
p - > response [ 0 ] = 0 ;
c = i = 0 ;
1999-12-16 22:47:49 +00:00
do {
2001-03-10 19:12:11 +00:00
res = ast_waitfor_n_fd ( & p - > fd , 1 , & timeout , NULL ) ;
1999-12-16 22:47:49 +00:00
if ( res < 0 ) {
2001-10-18 16:47:57 +00:00
strncpy ( p - > response , " (No Response) " , sizeof ( p - > response ) - 1 ) ;
1999-12-16 22:47:49 +00:00
return - 1 ;
}
2001-06-19 16:17:52 +00:00
/* get no more then buffer length */
while ( i < sizeof ( p - > response ) - 1 )
{
c = fgetc ( p - > f ) ; /* get a char */
if ( c < 1 ) /* if error */
{
/* if nothing in buffer, go back into timeout stuff */
if ( errno = = EWOULDBLOCK ) break ;
/* return as error */
2001-10-18 16:47:57 +00:00
strncpy ( p - > response , " (No Response) " , sizeof ( p - > response ) - 1 ) ;
2001-06-19 16:17:52 +00:00
return - 1 ;
}
/* save char */
p - > response [ i + + ] = c ;
p - > response [ i ] = 0 ;
/* if end of input */
if ( c = = ' \n ' ) break ;
}
if ( c > = 0 ) /* if input terminated normally */
{
/* ignore just CR/LF */
if ( ! strcmp ( p - > response , " \r \n " ) )
{
/* reset input buffer stuff */
i = 0 ;
p - > response [ 0 ] = 0 ;
}
else /* otherwise return with info in buffer */
{
return 0 ;
}
}
1999-12-16 22:47:49 +00:00
} while ( timeout > 0 ) ;
2001-10-18 16:47:57 +00:00
strncpy ( p - > response , " (No Response) " , sizeof ( p - > response ) - 1 ) ;
1999-12-16 22:47:49 +00:00
return - 1 ;
}
int ast_modem_expect ( struct ast_modem_pvt * p , char * result , int timeout )
{
int res = - 1 ;
timeout * = 1000 ;
2001-10-18 16:47:57 +00:00
strncpy ( p - > response , " (No Response) " , sizeof ( p - > response ) - 1 ) ;
1999-12-16 22:47:49 +00:00
do {
2001-03-10 19:12:11 +00:00
res = ast_waitfor_n_fd ( & p - > fd , 1 , & timeout , NULL ) ;
1999-12-16 22:47:49 +00:00
if ( res < 0 ) {
return - 1 ;
}
/* Read a response */
fgets ( p - > response , sizeof ( p - > response ) , p - > f ) ;
2001-06-19 16:17:52 +00:00
#if 0
1999-12-16 22:47:49 +00:00
fprintf ( stderr , " Modem said: %s " , p - > response ) ;
# endif
if ( ! strncasecmp ( p - > response , result , strlen ( result ) ) )
return 0 ;
} while ( timeout > 0 ) ;
return - 1 ;
}
void ast_modem_trim ( char * s )
{
int x ;
x = strlen ( s ) - 1 ;
while ( x > = 0 ) {
if ( ( s [ x ] ! = ' \r ' ) & & ( s [ x ] ! = ' \n ' ) & & ( s [ x ] ! = ' ' ) )
break ;
s [ x ] = ' \0 ' ;
x - - ;
}
}
static int modem_setup ( struct ast_modem_pvt * p , int baudrate )
{
2001-06-19 16:17:52 +00:00
1999-12-16 22:47:49 +00:00
/* Make sure there's a modem there and that it's in a reasonable
mode . Set the baud rate , etc . */
char identity [ 256 ] ;
char * ident = NULL ;
2001-06-19 16:17:52 +00:00
char etx [ 2 ] = { 0x10 , ' ! ' } ;
1999-12-16 22:47:49 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Setting up modem %s \n " , p - > dev ) ;
2000-01-10 17:43:38 +00:00
if ( ast_modem_send ( p , etx , 2 ) ) {
ast_log ( LOG_WARNING , " Failed to send ETX? \n " ) ;
return - 1 ;
}
1999-12-16 22:47:49 +00:00
if ( ast_modem_send ( p , " \r \n " , 2 ) ) {
ast_log ( LOG_WARNING , " Failed to send enter? \n " ) ;
return - 1 ;
}
2001-06-19 16:17:52 +00:00
usleep ( 10000 ) ;
1999-12-16 22:47:49 +00:00
/* Read any outstanding stuff */
while ( ! ast_modem_read_response ( p , 0 ) ) ;
if ( ast_modem_send ( p , " ATZ " , 0 ) ) {
ast_log ( LOG_WARNING , " Modem not responding on %s \n " , p - > dev ) ;
return - 1 ;
}
if ( ast_modem_expect ( p , " OK " , ECHO_TIMEOUT ) ) {
ast_log ( LOG_WARNING , " Modem reset failed: %s \n " , p - > response ) ;
return - 1 ;
}
if ( ast_modem_send ( p , p - > initstr , 0 ) ) {
ast_log ( LOG_WARNING , " Modem not responding on %s \n " , p - > dev ) ;
return - 1 ;
}
if ( ast_modem_expect ( p , " OK " , ECHO_TIMEOUT ) ) {
ast_log ( LOG_WARNING , " Modem initialization failed: %s \n " , p - > response ) ;
return - 1 ;
}
if ( ast_modem_send ( p , " ATI3 " , 0 ) ) {
ast_log ( LOG_WARNING , " Modem not responding on %s \n " , p - > dev ) ;
return - 1 ;
}
if ( ast_modem_read_response ( p , ECHO_TIMEOUT ) ) {
ast_log ( LOG_WARNING , " Modem did not provide identification \n " ) ;
return - 1 ;
}
2001-10-18 16:47:57 +00:00
strncpy ( identity , p - > response , sizeof ( identity ) - 1 ) ;
1999-12-16 22:47:49 +00:00
ast_modem_trim ( identity ) ;
if ( ast_modem_expect ( p , " OK " , ECHO_TIMEOUT ) ) {
ast_log ( LOG_WARNING , " Modem did not provide identification \n " ) ;
return - 1 ;
}
if ( ! strcasecmp ( mtype , " autodetect " ) ) {
p - > mc = find_capability ( identity ) ;
if ( ! p - > mc ) {
ast_log ( LOG_WARNING , " Unable to autodetect modem. You'll need to specify a driver in modem.conf. Please report modem identification (%s) and which driver works to markster@linux-support.net. \n " , identity ) ;
return - 1 ;
}
} else {
p - > mc = find_driver ( mtype ) ;
if ( ! p - > mc ) {
ast_log ( LOG_WARNING , " No driver for modem type '%s' \n " , mtype ) ;
return - 1 ;
}
}
if ( p - > mc - > init ) {
if ( p - > mc - > init ( p ) ) {
ast_log ( LOG_WARNING , " Modem Initialization Failed on '%s', driver %s. \n " , p - > dev , p - > mc - > name ) ;
p - > mc - > decusecnt ( ) ;
return - 1 ;
}
}
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Configured modem %s with driver %s (%s) \n " , p - > dev , p - > mc - > name , p - > mc - > identify ? ( ident = p - > mc - > identify ( p ) ) : " No identification " ) ;
}
if ( ident )
free ( ident ) ;
return 0 ;
}
static int modem_hangup ( struct ast_channel * ast )
{
struct ast_modem_pvt * p ;
2000-12-29 14:05:23 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " modem_hangup(%s) \n " , ast - > name ) ;
2005-03-04 06:47:24 +00:00
p = ast - > tech_pvt ;
1999-12-16 22:47:49 +00:00
/* Hang up */
if ( p - > mc - > hangup )
p - > mc - > hangup ( p ) ;
/* Re-initialize */
if ( p - > mc - > init )
p - > mc - > init ( p ) ;
2002-07-12 09:03:50 +00:00
ast_setstate ( ast , AST_STATE_DOWN ) ;
2004-10-02 00:58:31 +00:00
memset ( p - > cid_num , 0 , sizeof ( p - > cid_num ) ) ;
memset ( p - > cid_name , 0 , sizeof ( p - > cid_name ) ) ;
2002-06-28 02:08:32 +00:00
memset ( p - > dnid , 0 , sizeof ( p - > dnid ) ) ;
2005-03-04 06:47:24 +00:00
( ( struct ast_modem_pvt * ) ( ast - > tech_pvt ) ) - > owner = NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
1999-12-16 22:47:49 +00:00
usecnt - - ;
if ( usecnt < 0 )
ast_log ( LOG_WARNING , " Usecnt < 0??? \n " ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & usecnt_lock ) ;
1999-12-16 22:47:49 +00:00
ast_update_use_count ( ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Hungup '%s' \n " , ast - > name ) ;
2005-03-04 06:47:24 +00:00
ast - > tech_pvt = NULL ;
2002-07-12 09:03:50 +00:00
ast_setstate ( ast , AST_STATE_DOWN ) ;
1999-12-16 22:47:49 +00:00
restart_monitor ( ) ;
return 0 ;
}
static int modem_answer ( struct ast_channel * ast )
{
struct ast_modem_pvt * p ;
int res = 0 ;
2000-12-29 14:05:23 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " modem_answer(%s) \n " , ast - > name ) ;
2005-03-04 06:47:24 +00:00
p = ast - > tech_pvt ;
1999-12-16 22:47:49 +00:00
if ( p - > mc - > answer ) {
res = p - > mc - > answer ( p ) ;
}
if ( ! res ) {
ast - > rings = 0 ;
2002-07-12 09:03:50 +00:00
ast_setstate ( ast , AST_STATE_UP ) ;
1999-12-16 22:47:49 +00:00
}
return res ;
}
2001-06-19 16:17:52 +00:00
#if 0
1999-12-16 22:47:49 +00:00
static char modem_2digit ( char c )
{
if ( c = = 12 )
return ' # ' ;
else if ( c = = 11 )
return ' * ' ;
else if ( ( c < 10 ) & & ( c > = 0 ) )
return ' 0 ' + c - 1 ;
else
return ' ? ' ;
}
2001-06-19 16:17:52 +00:00
# endif
1999-12-16 22:47:49 +00:00
static struct ast_frame * modem_read ( struct ast_channel * ast )
{
2005-03-04 06:47:24 +00:00
struct ast_modem_pvt * p = ast - > tech_pvt ;
1999-12-16 22:47:49 +00:00
struct ast_frame * fr = NULL ;
if ( p - > mc - > read )
fr = p - > mc - > read ( p ) ;
return fr ;
}
static int modem_write ( struct ast_channel * ast , struct ast_frame * frame )
{
int res = 0 ;
2002-06-28 02:08:32 +00:00
long flags ;
2005-03-04 06:47:24 +00:00
struct ast_modem_pvt * p = ast - > tech_pvt ;
2002-06-28 02:08:32 +00:00
2002-11-11 18:21:17 +00:00
/* Modems tend to get upset when they receive data whilst in
* command mode . This makes esp . dial commands short lived .
* Pauline Middelink - 2002 - 09 - 24 */
if ( ast - > _state ! = AST_STATE_UP )
return 0 ;
2002-06-28 02:08:32 +00:00
/* Temporarily make non-blocking */
flags = fcntl ( ast - > fds [ 0 ] , F_GETFL ) ;
fcntl ( ast - > fds [ 0 ] , F_SETFL , flags | O_NONBLOCK ) ;
1999-12-16 22:47:49 +00:00
if ( p - > mc - > write )
res = p - > mc - > write ( p , frame ) ;
2002-06-28 02:08:32 +00:00
/* Block again */
fcntl ( ast - > fds [ 0 ] , F_SETFL , flags ) ;
2004-08-27 16:17:16 +00:00
return res ;
1999-12-16 22:47:49 +00:00
}
2004-10-23 11:50:04 +00:00
static int modem_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan )
{
2005-03-04 06:47:24 +00:00
struct ast_modem_pvt * p = newchan - > tech_pvt ;
2004-10-23 11:50:04 +00:00
ast_log ( LOG_WARNING , " fixup called \n " ) ;
if ( p - > owner ! = oldchan ) {
ast_log ( LOG_WARNING , " old channel wasn't %p but was %p \n " , oldchan , p - > owner ) ;
return - 1 ;
}
p - > owner = newchan ;
return 0 ;
}
1999-12-16 22:47:49 +00:00
struct ast_channel * ast_modem_new ( struct ast_modem_pvt * i , int state )
{
struct ast_channel * tmp ;
2002-06-28 02:08:32 +00:00
tmp = ast_channel_alloc ( 1 ) ;
1999-12-16 22:47:49 +00:00
if ( tmp ) {
2005-03-04 06:47:24 +00:00
tmp - > tech = & modem_tech ;
1999-12-16 22:47:49 +00:00
snprintf ( tmp - > name , sizeof ( tmp - > name ) , " Modem[%s]/%s " , i - > mc - > name , i - > dev + 5 ) ;
tmp - > type = type ;
2001-04-10 20:52:03 +00:00
tmp - > fds [ 0 ] = i - > fd ;
2001-03-10 19:12:11 +00:00
tmp - > nativeformats = i - > mc - > formats ;
2002-07-12 09:03:50 +00:00
ast_setstate ( tmp , state ) ;
1999-12-16 22:47:49 +00:00
if ( state = = AST_STATE_RING )
tmp - > rings = 1 ;
2005-03-04 06:47:24 +00:00
tmp - > tech_pvt = i ;
2001-10-18 16:47:57 +00:00
strncpy ( tmp - > context , i - > context , sizeof ( tmp - > context ) - 1 ) ;
2004-10-02 00:58:31 +00:00
if ( ! ast_strlen_zero ( i - > cid_num ) )
tmp - > cid . cid_num = strdup ( i - > cid_num ) ;
if ( ! ast_strlen_zero ( i - > cid_name ) )
tmp - > cid . cid_name = strdup ( i - > cid_name ) ;
2000-01-10 17:43:38 +00:00
if ( strlen ( i - > language ) )
2001-10-18 16:47:57 +00:00
strncpy ( tmp - > language , i - > language , sizeof ( tmp - > language ) - 1 ) ;
2002-06-28 02:08:32 +00:00
if ( strlen ( i - > dnid ) )
strncpy ( tmp - > exten , i - > dnid , sizeof ( tmp - > exten ) - 1 ) ;
1999-12-16 22:47:49 +00:00
i - > owner = tmp ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
1999-12-16 22:47:49 +00:00
usecnt + + ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & usecnt_lock ) ;
1999-12-16 22:47:49 +00:00
ast_update_use_count ( ) ;
if ( state ! = AST_STATE_DOWN ) {
if ( ast_pbx_start ( tmp ) ) {
ast_log ( LOG_WARNING , " Unable to start PBX on %s \n " , tmp - > name ) ;
ast_hangup ( tmp ) ;
2000-01-05 17:22:42 +00:00
tmp = NULL ;
1999-12-16 22:47:49 +00:00
}
}
} else
ast_log ( LOG_WARNING , " Unable to allocate channel structure \n " ) ;
return tmp ;
}
static void modem_mini_packet ( struct ast_modem_pvt * i )
{
struct ast_frame * fr ;
fr = i - > mc - > read ( i ) ;
2001-06-19 16:17:52 +00:00
if ( ! fr ) return ;
2000-01-05 17:22:42 +00:00
if ( fr - > frametype = = AST_FRAME_CONTROL ) {
if ( fr - > subclass = = AST_CONTROL_RING ) {
ast_modem_new ( i , AST_STATE_RING ) ;
}
}
1999-12-16 22:47:49 +00:00
}
static void * do_monitor ( void * data )
{
fd_set rfds , efds ;
int n , res ;
struct ast_modem_pvt * i ;
/* This thread monitors all the frame relay interfaces which are not yet in use
( and thus do not have a separate thread ) indefinitely */
/* From here on out, we die whenever asked */
#if 0
if ( pthread_setcanceltype ( PTHREAD_CANCEL_ASYNCHRONOUS , NULL ) ) {
ast_log ( LOG_WARNING , " Unable to set cancel type to asynchronous \n " ) ;
return NULL ;
}
# endif
for ( ; ; ) {
/* Don't let anybody kill us right away. Nobody should lock the interface list
and wait for the monitor list , but the other way around is okay . */
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & monlock ) ) {
1999-12-16 22:47:49 +00:00
ast_log ( LOG_ERROR , " Unable to grab monitor lock \n " ) ;
return NULL ;
}
/* Lock the interface list */
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & iflock ) ) {
1999-12-16 22:47:49 +00:00
ast_log ( LOG_ERROR , " Unable to grab interface lock \n " ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
1999-12-16 22:47:49 +00:00
return NULL ;
}
/* Build the stuff we're going to select on, that is the socket of every
ast_modem_pvt that does not have an associated owner channel */
n = - 1 ;
FD_ZERO ( & rfds ) ;
FD_ZERO ( & efds ) ;
i = iflist ;
while ( i ) {
if ( FD_ISSET ( i - > fd , & rfds ) )
ast_log ( LOG_WARNING , " Descriptor %d appears twice (%s)? \n " , i - > fd , i - > dev ) ;
if ( ! i - > owner ) {
/* This needs to be watched, as it lacks an owner */
FD_SET ( i - > fd , & rfds ) ;
FD_SET ( i - > fd , & efds ) ;
if ( i - > fd > n )
n = i - > fd ;
}
i = i - > next ;
}
/* Okay, now that we know what to do, release the interface lock */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
1999-12-16 22:47:49 +00:00
/* And from now on, we're okay to be killed, so release the monitor lock as well */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
1999-12-16 22:47:49 +00:00
#if 0
ast_log ( LOG_DEBUG , " In monitor, n=%d, pid=%d \n " , n , getpid ( ) ) ;
# endif
/* Wait indefinitely for something to happen */
pthread_testcancel ( ) ;
2003-04-27 18:13:11 +00:00
res = ast_select ( n + 1 , & rfds , NULL , & efds , NULL ) ;
1999-12-16 22:47:49 +00:00
pthread_testcancel ( ) ;
/* Okay, select has finished. Let's see what happened. */
if ( res < 1 ) {
2003-12-27 23:46:19 +00:00
if ( ( errno ! = EINTR ) & & ( errno ! = EAGAIN ) )
ast_log ( LOG_WARNING , " select return %d: %s \n " , res , strerror ( errno ) ) ;
1999-12-16 22:47:49 +00:00
continue ;
}
/* Alright, lock the interface list again, and let's look and see what has
happened */
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & iflock ) ) {
1999-12-16 22:47:49 +00:00
ast_log ( LOG_WARNING , " Unable to lock the interface list \n " ) ;
continue ;
}
i = iflist ;
while ( i ) {
if ( FD_ISSET ( i - > fd , & rfds ) | | FD_ISSET ( i - > fd , & efds ) ) {
if ( i - > owner ) {
ast_log ( LOG_WARNING , " Whoa.... I'm owned but found (%d, %s)... \n " , i - > fd , i - > dev ) ;
i = i - > next ;
continue ;
}
modem_mini_packet ( i ) ;
}
i = i - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
1999-12-16 22:47:49 +00:00
}
/* Never reached */
return NULL ;
}
static int restart_monitor ( )
{
/* If we're supposed to be stopped -- stay stopped */
2004-03-15 07:51:22 +00:00
if ( monitor_thread = = AST_PTHREADT_STOP )
1999-12-16 22:47:49 +00:00
return 0 ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & monlock ) ) {
1999-12-16 22:47:49 +00:00
ast_log ( LOG_WARNING , " Unable to lock monitor \n " ) ;
return - 1 ;
}
if ( monitor_thread = = pthread_self ( ) ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
1999-12-16 22:47:49 +00:00
ast_log ( LOG_WARNING , " Cannot kill myself \n " ) ;
return - 1 ;
}
2004-03-15 07:51:22 +00:00
if ( monitor_thread ! = AST_PTHREADT_NULL ) {
1999-12-16 22:47:49 +00:00
pthread_cancel ( monitor_thread ) ;
/* Nudge it a little, as it's probably stuck in select */
pthread_kill ( monitor_thread , SIGURG ) ;
pthread_join ( monitor_thread , NULL ) ;
}
/* Start a new monitor */
2004-08-08 17:15:02 +00:00
if ( ast_pthread_create ( & monitor_thread , NULL , do_monitor , NULL ) < 0 ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
1999-12-16 22:47:49 +00:00
ast_log ( LOG_ERROR , " Unable to start monitor thread. \n " ) ;
return - 1 ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
1999-12-16 22:47:49 +00:00
return 0 ;
}
2000-12-29 14:05:23 +00:00
static void stty ( struct ast_modem_pvt * p )
{
struct termios mode ;
memset ( & mode , 0 , sizeof ( mode ) ) ;
if ( tcgetattr ( p - > fd , & mode ) ) {
ast_log ( LOG_WARNING , " Unable to get serial parameters on %s: %s \n " , p - > dev , strerror ( errno ) ) ;
return ;
}
2004-12-14 23:36:30 +00:00
# ifndef SOLARIS
2000-12-29 14:05:23 +00:00
cfmakeraw ( & mode ) ;
2004-12-14 23:36:30 +00:00
# else
mode . c_iflag & = ~ ( IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON ) ;
mode . c_oflag & = ~ OPOST ;
mode . c_lflag & = ~ ( ECHO | ECHONL | ICANON | ISIG | IEXTEN ) ;
mode . c_cflag & = ~ ( CSIZE | PARENB ) ;
mode . c_cflag | = CS8 ;
# endif
cfsetispeed ( & mode , B115200 ) ;
cfsetospeed ( & mode , B115200 ) ;
2000-12-29 14:05:23 +00:00
if ( tcsetattr ( p - > fd , TCSANOW , & mode ) )
ast_log ( LOG_WARNING , " Unable to set serial parameters on %s: %s \n " , p - > dev , strerror ( errno ) ) ;
}
1999-12-16 22:47:49 +00:00
static struct ast_modem_pvt * mkif ( char * iface )
{
/* Make a ast_modem_pvt structure for this interface */
struct ast_modem_pvt * tmp ;
#if 0
int flags ;
# endif
tmp = malloc ( sizeof ( struct ast_modem_pvt ) ) ;
if ( tmp ) {
2004-10-23 06:03:29 +00:00
memset ( tmp , 0 , sizeof ( struct ast_modem_pvt ) ) ;
1999-12-16 22:47:49 +00:00
tmp - > fd = open ( iface , O_RDWR | O_NONBLOCK ) ;
if ( tmp - > fd < 0 ) {
ast_log ( LOG_WARNING , " Unable to open '%s' \n " , iface ) ;
free ( tmp ) ;
return NULL ;
}
2001-10-18 16:47:57 +00:00
strncpy ( tmp - > language , language , sizeof ( tmp - > language ) - 1 ) ;
strncpy ( tmp - > msn , msn , sizeof ( tmp - > msn ) - 1 ) ;
2002-11-11 18:21:17 +00:00
strncpy ( tmp - > incomingmsn , incomingmsn , sizeof ( tmp - > incomingmsn ) - 1 ) ;
2004-06-22 14:17:07 +00:00
tmp - > dtmfmode = dtmfmode ;
tmp - > dtmfmodegen = dtmfmodegen ;
2004-06-21 04:29:50 +00:00
snprintf ( tmp - > outgoingmsn , sizeof ( tmp - > outgoingmsn ) , " ,%s, " , outgoingmsn ) ;
2001-10-18 16:47:57 +00:00
strncpy ( tmp - > dev , iface , sizeof ( tmp - > dev ) - 1 ) ;
2000-12-29 14:05:23 +00:00
/* Maybe in the future we want to allow variable
serial settings */
stty ( tmp ) ;
1999-12-16 22:47:49 +00:00
tmp - > f = fdopen ( tmp - > fd , " w+ " ) ;
/* Disable buffering */
setvbuf ( tmp - > f , NULL , _IONBF , 0 ) ;
if ( tmp - > f < 0 ) {
ast_log ( LOG_WARNING , " Unable to fdopen '%s' \n " , iface ) ;
free ( tmp ) ;
return NULL ;
}
tmp - > owner = NULL ;
tmp - > ministate = 0 ;
tmp - > stripmsd = stripmsd ;
tmp - > dialtype = dialtype ;
tmp - > mode = gmode ;
2002-11-11 18:21:17 +00:00
tmp - > group = cur_group ;
2004-10-02 00:58:31 +00:00
memset ( tmp - > cid_num , 0 , sizeof ( tmp - > cid_num ) ) ;
memset ( tmp - > cid_name , 0 , sizeof ( tmp - > cid_name ) ) ;
2001-10-18 16:47:57 +00:00
strncpy ( tmp - > context , context , sizeof ( tmp - > context ) - 1 ) ;
strncpy ( tmp - > initstr , initstr , sizeof ( tmp - > initstr ) - 1 ) ;
1999-12-16 22:47:49 +00:00
tmp - > next = NULL ;
tmp - > obuflen = 0 ;
if ( modem_setup ( tmp , baudrate ) < 0 ) {
ast_log ( LOG_WARNING , " Unable to configure modem '%s' \n " , iface ) ;
free ( tmp ) ;
return NULL ;
}
}
return tmp ;
}
2004-10-26 22:25:43 +00:00
static struct ast_channel * modem_request ( const char * type , int format , void * data , int * cause )
1999-12-16 22:47:49 +00:00
{
int oldformat ;
struct ast_modem_pvt * p ;
struct ast_channel * tmp = NULL ;
char dev [ 80 ] ;
2005-01-15 21:51:38 +00:00
ast_group_t group = 0 ;
2005-01-18 11:40:44 +00:00
int groupint ;
2002-11-11 18:21:17 +00:00
char * stringp = NULL ;
2001-10-18 16:47:57 +00:00
strncpy ( dev , ( char * ) data , sizeof ( dev ) - 1 ) ;
2002-11-11 18:21:17 +00:00
stringp = dev ;
strsep ( & stringp , " : " ) ;
1999-12-16 22:47:49 +00:00
oldformat = format ;
2002-11-11 18:21:17 +00:00
if ( dev [ 0 ] = = ' g ' & & isdigit ( dev [ 1 ] ) ) {
/* Retrieve the group number */
2005-01-18 11:40:44 +00:00
if ( sscanf ( dev + 1 , " %u " , & groupint ) < 1 ) {
2002-11-11 18:21:17 +00:00
ast_log ( LOG_WARNING , " Unable to determine group from [%s] \n " , ( char * ) data ) ;
return NULL ;
}
2005-01-18 11:40:44 +00:00
group = 1 < < groupint ;
2002-11-11 18:21:17 +00:00
}
1999-12-16 22:47:49 +00:00
/* Search for an unowned channel */
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & iflock ) ) {
1999-12-16 22:47:49 +00:00
ast_log ( LOG_ERROR , " Unable to lock interface list??? \n " ) ;
return NULL ;
}
p = iflist ;
while ( p ) {
2002-11-11 18:21:17 +00:00
if ( group ) {
/* if it belongs to the proper group, and the format matches
* and it is not in use , we found a candidate ! */
if ( p - > group & group & &
p - > mc - > formats & format & &
! p - > owner ) {
/* XXX Not quite sure that not having an owner is
* sufficient evidence of beeing a free device XXX */
tmp = ast_modem_new ( p , AST_STATE_DOWN ) ;
restart_monitor ( ) ;
break ;
}
} else {
if ( ! strcmp ( dev , p - > dev + 5 ) ) {
if ( p - > mc - > formats & format ) {
if ( ! p - > owner ) {
tmp = ast_modem_new ( p , AST_STATE_DOWN ) ;
restart_monitor ( ) ;
break ;
} else
ast_log ( LOG_WARNING , " Device '%s' is busy \n " , p - > dev ) ;
} else
2003-08-16 05:10:35 +00:00
ast_log ( LOG_WARNING , " Asked for a format %s line on %s \n " , ast_getformatname ( format ) , p - > dev ) ;
2002-11-11 18:21:17 +00:00
break ;
}
1999-12-16 22:47:49 +00:00
}
p = p - > next ;
}
if ( ! p )
2002-01-17 21:39:57 +00:00
ast_log ( LOG_WARNING , " Requested device '%s' does not exist \n " , dev ) ;
1999-12-16 22:47:49 +00:00
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
1999-12-16 22:47:49 +00:00
return tmp ;
}
2005-01-15 21:51:38 +00:00
static ast_group_t get_group ( char * s )
2002-11-11 18:21:17 +00:00
{
char * piece ;
int start , finish , x ;
2005-01-15 21:51:38 +00:00
ast_group_t group = 0 ;
2003-04-27 21:34:27 +00:00
char * copy = ast_strdupa ( s ) ;
2002-11-11 18:21:17 +00:00
char * stringp = NULL ;
if ( ! copy ) {
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
return 0 ;
}
stringp = copy ;
piece = strsep ( & stringp , " , " ) ;
while ( piece ) {
if ( sscanf ( piece , " %d-%d " , & start , & finish ) = = 2 ) {
/* Range */
} else if ( sscanf ( piece , " %d " , & start ) ) {
/* Just one */
finish = start ;
} else {
ast_log ( LOG_ERROR , " Syntax error parsing '%s' at '%s'. Using '0' \n " , s , piece ) ;
return 0 ;
}
piece = strsep ( & stringp , " , " ) ;
for ( x = start ; x < = finish ; x + + ) {
2005-01-15 21:51:38 +00:00
if ( ( x > 63 ) | | ( x < 0 ) ) {
2002-11-11 18:21:17 +00:00
ast_log ( LOG_WARNING , " Ignoring invalid group %d \n " , x ) ;
break ;
}
group | = ( 1 < < x ) ;
}
}
return group ;
}
2003-12-09 23:55:17 +00:00
static int __unload_module ( void )
{
struct ast_modem_pvt * p , * pl ;
/* First, take us out of the channel loop */
2005-03-04 06:47:24 +00:00
ast_channel_unregister ( & modem_tech ) ;
2003-12-09 23:55:17 +00:00
if ( ! ast_mutex_lock ( & iflock ) ) {
/* Hangup all interfaces if they have an owner */
p = iflist ;
while ( p ) {
if ( p - > owner )
ast_softhangup ( p - > owner , AST_SOFTHANGUP_APPUNLOAD ) ;
p = p - > next ;
}
iflist = NULL ;
ast_mutex_unlock ( & iflock ) ;
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
if ( ! ast_mutex_lock ( & monlock ) ) {
2004-03-15 07:51:22 +00:00
if ( monitor_thread ! = AST_PTHREADT_NULL & & monitor_thread ! = AST_PTHREADT_STOP ) {
2003-12-09 23:55:17 +00:00
pthread_cancel ( monitor_thread ) ;
pthread_join ( monitor_thread , NULL ) ;
}
2004-03-15 07:51:22 +00:00
monitor_thread = AST_PTHREADT_STOP ;
2003-12-09 23:55:17 +00:00
ast_mutex_unlock ( & monlock ) ;
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
if ( ! ast_mutex_lock ( & iflock ) ) {
/* Destroy all the interfaces and free their memory */
p = iflist ;
while ( p ) {
/* Close the socket, assuming it's real */
if ( p - > fd > - 1 )
close ( p - > fd ) ;
pl = p ;
p = p - > next ;
/* Free associated memory */
free ( pl ) ;
}
iflist = NULL ;
ast_mutex_unlock ( & iflock ) ;
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
return 0 ;
}
int unload_module ( )
{
return __unload_module ( ) ;
}
1999-12-16 22:47:49 +00:00
int load_module ( )
{
struct ast_config * cfg ;
struct ast_variable * v ;
struct ast_modem_pvt * tmp ;
char driver [ 80 ] ;
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( config ) ;
1999-12-16 22:47:49 +00:00
/* We *must* have a config file otherwise stop immediately */
if ( ! cfg ) {
ast_log ( LOG_ERROR , " Unable to load config %s \n " , config ) ;
return - 1 ;
}
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & iflock ) ) {
1999-12-16 22:47:49 +00:00
/* It's a little silly to lock it, but we mind as well just to be sure */
ast_log ( LOG_ERROR , " Unable to lock interface list??? \n " ) ;
return - 1 ;
}
v = ast_variable_browse ( cfg , " interfaces " ) ;
while ( v ) {
/* Create the interface list */
if ( ! strcasecmp ( v - > name , " device " ) ) {
tmp = mkif ( v - > value ) ;
if ( tmp ) {
tmp - > next = iflist ;
iflist = tmp ;
} else {
ast_log ( LOG_ERROR , " Unable to register channel '%s' \n " , v - > value ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2003-12-09 23:55:17 +00:00
__unload_module ( ) ;
1999-12-16 22:47:49 +00:00
return - 1 ;
}
} else if ( ! strcasecmp ( v - > name , " driver " ) ) {
snprintf ( driver , sizeof ( driver ) , " chan_modem_%s.so " , v - > value ) ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Loading modem driver %s " , driver ) ;
if ( ast_load_resource ( driver ) ) {
2000-01-05 17:22:42 +00:00
ast_log ( LOG_ERROR , " Failed to load driver %s \n " , driver ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2003-12-09 23:55:17 +00:00
__unload_module ( ) ;
1999-12-16 22:47:49 +00:00
return - 1 ;
}
} else if ( ! strcasecmp ( v - > name , " mode " ) ) {
if ( ! strncasecmp ( v - > value , " ri " , 2 ) )
gmode = MODEM_MODE_WAIT_RING ;
else if ( ! strncasecmp ( v - > value , " im " , 2 ) )
gmode = MODEM_MODE_IMMEDIATE ;
else if ( ! strncasecmp ( v - > value , " an " , 2 ) )
gmode = MODEM_MODE_WAIT_ANSWER ;
else
ast_log ( LOG_WARNING , " Unknown mode: %s \n " , v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " stripmsd " ) ) {
stripmsd = atoi ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " type " ) ) {
2001-10-18 16:47:57 +00:00
strncpy ( mtype , v - > value , sizeof ( mtype ) - 1 ) ;
1999-12-16 22:47:49 +00:00
} else if ( ! strcasecmp ( v - > name , " initstr " ) ) {
2001-10-18 16:47:57 +00:00
strncpy ( initstr , v - > value , sizeof ( initstr ) - 1 ) ;
1999-12-16 22:47:49 +00:00
} else if ( ! strcasecmp ( v - > name , " dialtype " ) ) {
dialtype = toupper ( v - > value [ 0 ] ) ;
} else if ( ! strcasecmp ( v - > name , " context " ) ) {
2001-10-18 16:47:57 +00:00
strncpy ( context , v - > value , sizeof ( context ) - 1 ) ;
2000-12-29 14:05:23 +00:00
} else if ( ! strcasecmp ( v - > name , " msn " ) ) {
2001-10-18 16:47:57 +00:00
strncpy ( msn , v - > value , sizeof ( msn ) - 1 ) ;
2002-11-11 18:21:17 +00:00
} else if ( ! strcasecmp ( v - > name , " incomingmsn " ) ) {
strncpy ( incomingmsn , v - > value , sizeof ( incomingmsn ) - 1 ) ;
2004-06-22 14:17:07 +00:00
} else if ( ! strcasecmp ( v - > name , " dtmfmode " ) ) {
char tmp [ 80 ] ;
char * alt ;
strncpy ( tmp , v - > value , sizeof ( tmp ) - 1 ) ;
alt = strchr ( tmp , ' / ' ) ;
if ( ! strcasecmp ( tmp , " none " ) )
dtmfmode = MODEM_DTMF_NONE ;
else if ( ! strcasecmp ( tmp , " asterisk " ) )
dtmfmode = MODEM_DTMF_AST ;
else if ( ! strcasecmp ( tmp , " i4l " ) )
dtmfmode = MODEM_DTMF_I4L ;
else {
ast_log ( LOG_WARNING , " Unknown dtmf detection mode '%s', using 'asterisk' \n " , v - > value ) ;
dtmfmode = MODEM_DTMF_AST ;
}
if ( alt ) {
if ( ! strcasecmp ( alt , " none " ) )
dtmfmodegen = MODEM_DTMF_NONE ;
else if ( ! strcasecmp ( alt , " asterisk " ) )
dtmfmodegen = MODEM_DTMF_AST ;
else if ( ! strcasecmp ( alt , " i4l " ) )
dtmfmodegen = MODEM_DTMF_I4L ;
else if ( ! strcasecmp ( alt , " both " ) )
dtmfmodegen = MODEM_DTMF_I4L | MODEM_DTMF_AST ;
else {
ast_log ( LOG_WARNING , " Unknown dtmf generation mode '%s', using 'asterisk' \n " , v - > value ) ;
dtmfmodegen = MODEM_DTMF_AST ;
}
} else
dtmfmodegen = dtmfmode ;
2004-06-21 04:29:50 +00:00
} else if ( ! strcasecmp ( v - > name , " outgoingmsn " ) ) {
strncpy ( outgoingmsn , v - > value , sizeof ( outgoingmsn ) - 1 ) ;
2000-01-10 17:43:38 +00:00
} else if ( ! strcasecmp ( v - > name , " language " ) ) {
2001-10-18 16:47:57 +00:00
strncpy ( language , v - > value , sizeof ( language ) - 1 ) ;
2002-11-11 18:21:17 +00:00
} else if ( ! strcasecmp ( v - > name , " group " ) ) {
cur_group = get_group ( v - > value ) ;
1999-12-16 22:47:49 +00:00
}
v = v - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2005-03-04 06:47:24 +00:00
if ( ast_channel_register ( & modem_tech ) ) {
1999-12-16 22:47:49 +00:00
ast_log ( LOG_ERROR , " Unable to register channel class %s \n " , type ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2003-12-09 23:55:17 +00:00
__unload_module ( ) ;
1999-12-16 22:47:49 +00:00
return - 1 ;
}
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
1999-12-16 22:47:49 +00:00
/* And start the monitor for the first time */
restart_monitor ( ) ;
return 0 ;
}
int usecount ( void )
{
int res ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
1999-12-16 22:47:49 +00:00
res = usecnt ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & usecnt_lock ) ;
1999-12-16 22:47:49 +00:00
return res ;
}
char * description ( )
{
2005-03-04 06:47:24 +00:00
return ( char * ) desc ;
1999-12-16 22:47:49 +00:00
}
2001-03-10 19:12:11 +00:00
char * key ( )
{
return ASTERISK_GPL_KEY ;
}