2003-09-11 19:44:48 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
2003-09-11 19:44:48 +00:00
*
2005-09-14 20:46:50 +00:00
* Copyright ( C ) 1999 - 2005 , Digium , Inc .
2003-09-11 19:44:48 +00:00
*
* chan_skinny was developed by Jeremy McNamara & Florian Overkamp
2006-06-18 22:36:39 +00:00
* chan_skinny was heavily modified / fixed by North Antara
2003-09-11 19:44:48 +00:00
*
2005-09-14 20:46:50 +00:00
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
2003-09-11 19:44:48 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2005-10-24 20:12:06 +00:00
/*! \file
2003-09-12 23:47:02 +00:00
*
2005-10-24 20:12:06 +00:00
* \ brief Implementation of the Skinny protocol
2006-03-22 20:45:00 +00:00
*
2006-06-18 22:36:39 +00:00
* \ author Jeremy McNamara & Florian Overkamp & North Antara
2005-11-06 15:09:47 +00:00
* \ ingroup channel_drivers
2003-09-11 19:44:48 +00:00
*/
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2003-09-11 19:44:48 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2005-06-07 17:06:33 +00:00
# include <unistd.h>
2005-06-06 21:09:59 +00:00
# include <sys/socket.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <sys/ioctl.h>
# include <net/if.h>
# include <errno.h>
# include <fcntl.h>
# include <netdb.h>
# include <arpa/inet.h>
# include <sys/signal.h>
# include <signal.h>
# include <ctype.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/lock.h"
# include "asterisk/sched.h"
# include "asterisk/io.h"
# include "asterisk/rtp.h"
# include "asterisk/acl.h"
# include "asterisk/callerid.h"
# include "asterisk/cli.h"
# include "asterisk/say.h"
# include "asterisk/cdr.h"
# include "asterisk/astdb.h"
# include "asterisk/features.h"
# include "asterisk/app.h"
# include "asterisk/musiconhold.h"
# include "asterisk/utils.h"
# include "asterisk/dsp.h"
2006-02-01 23:05:28 +00:00
# include "asterisk/stringfields.h"
2006-06-18 22:36:39 +00:00
# include "asterisk/astobj.h"
2006-06-01 04:35:00 +00:00
# include "asterisk/abstract_jb.h"
2006-08-20 04:39:57 +00:00
# include "asterisk/threadstorage.h"
2007-02-24 02:06:44 +00:00
# include "asterisk/devicestate.h"
2003-09-11 19:44:48 +00:00
2006-03-21 15:12:41 +00:00
/*************************************
* Skinny / Asterisk Protocol Settings *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-03-04 06:47:24 +00:00
static const char tdesc [ ] = " Skinny Client Control Protocol (Skinny) " ;
static const char config [ ] = " skinny.conf " ;
2003-09-11 19:44:48 +00:00
Merged revisions 43650 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r43650 | qwell | 2006-09-26 08:33:47 -0700 (Tue, 26 Sep 2006) | 11 lines
Add proper codec support to chan_skinny. Works with at least ulaw, alaw, and g729a.
This is technically a "new feature", but there are justifications for it.
I found a bug with the recent rtp packetization changes, which caused the media setup to
fail under certain circumstances, particularly when using allow=all, or having no allow=
statements (globally or on the device).
I could have either removed the rtp packetization features, or I could add proper codec
support (which, without, I think most people would consider to be a bug anyways).
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43651 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-09-26 15:35:37 +00:00
static int default_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW ;
2006-09-18 23:32:57 +00:00
static struct ast_codec_pref default_prefs ;
2003-09-11 19:44:48 +00:00
Merged revisions 43650 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r43650 | qwell | 2006-09-26 08:33:47 -0700 (Tue, 26 Sep 2006) | 11 lines
Add proper codec support to chan_skinny. Works with at least ulaw, alaw, and g729a.
This is technically a "new feature", but there are justifications for it.
I found a bug with the recent rtp packetization changes, which caused the media setup to
fail under certain circumstances, particularly when using allow=all, or having no allow=
statements (globally or on the device).
I could have either removed the rtp packetization features, or I could add proper codec
support (which, without, I think most people would consider to be a bug anyways).
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43651 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-09-26 15:35:37 +00:00
enum skinny_codecs {
SKINNY_CODEC_ALAW = 2 ,
SKINNY_CODEC_ULAW = 4 ,
SKINNY_CODEC_G723_1 = 9 ,
SKINNY_CODEC_G729A = 12 ,
SKINNY_CODEC_G726_32 = 82 , /* XXX Which packing order does this translate to? */
SKINNY_CODEC_H261 = 100 ,
SKINNY_CODEC_H263 = 101
} ;
2004-01-09 21:12:21 +00:00
# define DEFAULT_SKINNY_PORT 2000
2006-03-21 15:12:41 +00:00
# define DEFAULT_SKINNY_BACKLOG 2
2004-01-09 21:12:21 +00:00
# define SKINNY_MAX_PACKET 1000
2003-09-11 19:44:48 +00:00
2006-03-21 15:12:41 +00:00
static int keep_alive = 120 ;
2007-05-11 22:52:36 +00:00
static char vmexten [ AST_MAX_EXTENSION ] ; /* Voicemail pilot number */
2003-09-11 19:44:48 +00:00
static char date_format [ 6 ] = " D-M-Y " ;
static char version_id [ 16 ] = " P002F202 " ;
2005-06-02 09:11:46 +00:00
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define letohl(x) (x)
# define letohs(x) (x)
# define htolel(x) (x)
# define htoles(x) (x)
# else
2005-07-30 19:12:30 +00:00
# if defined(SOLARIS) || defined(__Darwin__) || defined(__NetBSD__)
2005-06-02 09:11:46 +00:00
# define __bswap_16(x) \
2006-03-21 15:12:41 +00:00
( ( ( ( x ) & 0xff00 ) > > 8 ) | \
( ( ( x ) & 0x00ff ) < < 8 ) )
2005-06-02 09:11:46 +00:00
# define __bswap_32(x) \
2006-03-21 15:12:41 +00:00
( ( ( ( x ) & 0xff000000 ) > > 24 ) | \
( ( ( x ) & 0x00ff0000 ) > > 8 ) | \
( ( ( x ) & 0x0000ff00 ) < < 8 ) | \
( ( ( x ) & 0x000000ff ) < < 24 ) )
2005-06-02 09:11:46 +00:00
# else
# include <bits/byteswap.h>
# endif
# define letohl(x) __bswap_32(x)
# define letohs(x) __bswap_16(x)
# define htolel(x) __bswap_32(x)
# define htoles(x) __bswap_16(x)
# endif
2006-06-01 04:35:00 +00:00
/*! Global jitterbuffer configuration - by default, jb is disabled */
static struct ast_jb_conf default_jbconf =
{
. flags = 0 ,
. max_size = - 1 ,
. resync_threshold = - 1 ,
. impl = " "
} ;
static struct ast_jb_conf global_jbconf ;
2005-06-02 09:11:46 +00:00
2006-10-19 01:00:57 +00:00
AST_THREADSTORAGE ( device2str_threadbuf ) ;
2006-08-20 04:39:57 +00:00
# define DEVICE2STR_BUFSIZE 15
2006-10-19 01:00:57 +00:00
AST_THREADSTORAGE ( control2str_threadbuf ) ;
2006-08-20 04:39:57 +00:00
# define CONTROL2STR_BUFSIZE 100
2006-03-21 15:12:41 +00:00
/*********************
* Protocol Messages *
* * * * * * * * * * * * * * * * * * * * */
2003-09-11 19:44:48 +00:00
/* message types */
2006-04-17 01:17:03 +00:00
# define KEEP_ALIVE_MESSAGE 0x0000
2003-09-11 19:44:48 +00:00
/* no additional struct */
2006-04-17 01:17:03 +00:00
# define REGISTER_MESSAGE 0x0001
2006-09-17 21:58:04 +00:00
struct register_message {
2003-09-11 19:44:48 +00:00
char name [ 16 ] ;
2006-06-18 22:36:39 +00:00
uint32_t userId ;
uint32_t instance ;
uint32_t ip ;
uint32_t type ;
uint32_t maxStreams ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
# define IP_PORT_MESSAGE 0x0002
# define KEYPAD_BUTTON_MESSAGE 0x0003
2006-09-17 21:58:04 +00:00
struct keypad_button_message {
2006-06-18 22:36:39 +00:00
uint32_t button ;
uint32_t lineInstance ;
uint32_t callReference ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
# define STIMULUS_MESSAGE 0x0005
2006-09-17 21:58:04 +00:00
struct stimulus_message {
2006-06-18 22:36:39 +00:00
uint32_t stimulus ;
uint32_t stimulusInstance ;
uint32_t unknown1 ;
2006-09-17 21:58:04 +00:00
} ;
2006-03-22 20:45:00 +00:00
2003-09-11 19:44:48 +00:00
# define OFFHOOK_MESSAGE 0x0006
2006-09-17 21:58:04 +00:00
struct offhook_message {
2006-06-18 22:36:39 +00:00
uint32_t unknown1 ;
uint32_t unknown2 ;
2006-09-17 21:58:04 +00:00
} ;
2006-06-18 22:36:39 +00:00
2003-09-11 19:44:48 +00:00
# define ONHOOK_MESSAGE 0x0007
2006-09-17 21:58:04 +00:00
struct onhook_message {
2006-06-18 22:36:39 +00:00
uint32_t unknown1 ;
uint32_t unknown2 ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define CAPABILITIES_RES_MESSAGE 0x0010
2006-09-17 21:58:04 +00:00
struct station_capabilities {
2006-06-18 22:36:39 +00:00
uint32_t codec ;
uint32_t frames ;
2003-09-11 19:44:48 +00:00
union {
char res [ 8 ] ;
Merged revisions 43650 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r43650 | qwell | 2006-09-26 08:33:47 -0700 (Tue, 26 Sep 2006) | 11 lines
Add proper codec support to chan_skinny. Works with at least ulaw, alaw, and g729a.
This is technically a "new feature", but there are justifications for it.
I found a bug with the recent rtp packetization changes, which caused the media setup to
fail under certain circumstances, particularly when using allow=all, or having no allow=
statements (globally or on the device).
I could have either removed the rtp packetization features, or I could add proper codec
support (which, without, I think most people would consider to be a bug anyways).
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43651 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-09-26 15:35:37 +00:00
uint32_t rate ;
2006-03-22 20:45:00 +00:00
} payloads ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-09-17 21:58:04 +00:00
struct capabilities_res_message {
2006-06-18 22:36:39 +00:00
uint32_t count ;
2003-09-11 19:44:48 +00:00
struct station_capabilities caps [ 18 ] ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
# define SPEED_DIAL_STAT_REQ_MESSAGE 0x000A
2006-09-17 21:58:04 +00:00
struct speed_dial_stat_req_message {
2006-06-18 22:36:39 +00:00
uint32_t speedDialNumber ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define LINE_STATE_REQ_MESSAGE 0x000B
2006-09-17 21:58:04 +00:00
struct line_state_req_message {
2006-06-18 22:36:39 +00:00
uint32_t lineNumber ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define TIME_DATE_REQ_MESSAGE 0x000D
2003-09-11 19:44:48 +00:00
# define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
2006-04-17 01:17:03 +00:00
# define VERSION_REQ_MESSAGE 0x000F
2003-09-11 19:44:48 +00:00
# define SERVER_REQUEST_MESSAGE 0x0012
2006-06-18 22:36:39 +00:00
2003-09-11 19:44:48 +00:00
# define ALARM_MESSAGE 0x0020
2006-09-17 21:58:04 +00:00
struct alarm_message {
2006-06-18 22:36:39 +00:00
uint32_t alarmSeverity ;
char displayMessage [ 80 ] ;
uint32_t alarmParam1 ;
uint32_t alarmParam2 ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define OPEN_RECEIVE_CHANNEL_ACK_MESSAGE 0x0022
2006-09-17 21:58:04 +00:00
struct open_receive_channel_ack_message {
2006-06-18 22:36:39 +00:00
uint32_t status ;
uint32_t ipAddr ;
uint32_t port ;
uint32_t passThruId ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define SOFT_KEY_SET_REQ_MESSAGE 0x0025
2006-06-18 22:36:39 +00:00
# define SOFT_KEY_EVENT_MESSAGE 0x0026
2006-09-17 21:58:04 +00:00
struct soft_key_event_message {
2006-06-18 22:36:39 +00:00
uint32_t softKeyEvent ;
uint32_t instance ;
uint32_t reference ;
2006-09-17 21:58:04 +00:00
} ;
2006-06-18 22:36:39 +00:00
2003-09-11 19:44:48 +00:00
# define UNREGISTER_MESSAGE 0x0027
2006-04-17 01:17:03 +00:00
# define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028
2006-06-18 22:36:39 +00:00
# define HEADSET_STATUS_MESSAGE 0x002B
# define REGISTER_AVAILABLE_LINES_MESSAGE 0x002D
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define REGISTER_ACK_MESSAGE 0x0081
2006-09-17 21:58:04 +00:00
struct register_ack_message {
2006-06-18 22:36:39 +00:00
uint32_t keepAlive ;
2003-09-11 19:44:48 +00:00
char dateTemplate [ 6 ] ;
char res [ 2 ] ;
2006-06-18 22:36:39 +00:00
uint32_t secondaryKeepAlive ;
2003-09-11 19:44:48 +00:00
char res2 [ 4 ] ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define START_TONE_MESSAGE 0x0082
2006-09-17 21:58:04 +00:00
struct start_tone_message {
2006-06-18 22:36:39 +00:00
uint32_t tone ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
# define STOP_TONE_MESSAGE 0x0083
# define SET_RINGER_MESSAGE 0x0085
2006-09-17 21:58:04 +00:00
struct set_ringer_message {
2006-06-18 22:36:39 +00:00
uint32_t ringerMode ;
uint32_t unknown1 ; /* See notes in transmit_ringer_mode */
uint32_t unknown2 ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
# define SET_LAMP_MESSAGE 0x0086
2006-09-17 21:58:04 +00:00
struct set_lamp_message {
2006-06-18 22:36:39 +00:00
uint32_t stimulus ;
uint32_t stimulusInstance ;
uint32_t deviceStimulus ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-03-22 20:45:00 +00:00
# define SET_SPEAKER_MESSAGE 0x0088
2006-09-17 21:58:04 +00:00
struct set_speaker_message {
2006-06-18 22:36:39 +00:00
uint32_t mode ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
/* XXX When do we need to use this? */
# define SET_MICROPHONE_MESSAGE 0x0089
2006-09-17 21:58:04 +00:00
struct set_microphone_message {
2006-06-18 22:36:39 +00:00
uint32_t mode ;
2006-09-17 21:58:04 +00:00
} ;
2006-06-18 22:36:39 +00:00
2003-09-11 19:44:48 +00:00
# define START_MEDIA_TRANSMISSION_MESSAGE 0x008A
2006-09-17 21:58:04 +00:00
struct media_qualifier {
2006-06-18 22:36:39 +00:00
uint32_t precedence ;
uint32_t vad ;
uint32_t packets ;
uint32_t bitRate ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-09-17 21:58:04 +00:00
struct start_media_transmission_message {
2006-06-18 22:36:39 +00:00
uint32_t conferenceId ;
uint32_t passThruPartyId ;
uint32_t remoteIp ;
uint32_t remotePort ;
uint32_t packetSize ;
uint32_t payloadType ;
2006-09-17 21:58:04 +00:00
struct media_qualifier qualifier ;
} ;
2003-09-11 19:44:48 +00:00
2003-11-22 19:15:34 +00:00
# define STOP_MEDIA_TRANSMISSION_MESSAGE 0x008B
2006-09-17 21:58:04 +00:00
struct stop_media_transmission_message {
2006-06-18 22:36:39 +00:00
uint32_t conferenceId ;
uint32_t passThruPartyId ;
2006-09-17 21:58:04 +00:00
} ;
2003-11-22 19:15:34 +00:00
2003-09-11 19:44:48 +00:00
# define CALL_INFO_MESSAGE 0x008F
2006-09-17 21:58:04 +00:00
struct call_info_message {
2003-09-11 19:44:48 +00:00
char callingPartyName [ 40 ] ;
char callingParty [ 24 ] ;
char calledPartyName [ 40 ] ;
char calledParty [ 24 ] ;
2006-06-18 22:36:39 +00:00
uint32_t instance ;
uint32_t reference ;
uint32_t type ;
2003-09-11 19:44:48 +00:00
char originalCalledPartyName [ 40 ] ;
char originalCalledParty [ 24 ] ;
2007-02-17 17:11:07 +00:00
char lastRedirectingPartyName [ 40 ] ;
char lastRedirectingParty [ 24 ] ;
uint32_t originalCalledPartyRedirectReason ;
uint32_t lastRedirectingReason ;
char callingPartyVoiceMailbox [ 24 ] ;
char calledPartyVoiceMailbox [ 24 ] ;
char originalCalledPartyVoiceMailbox [ 24 ] ;
char lastRedirectingVoiceMailbox [ 24 ] ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
# define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
2006-09-17 21:58:04 +00:00
struct speed_dial_stat_res_message {
2006-06-18 22:36:39 +00:00
uint32_t speedDialNumber ;
2003-09-11 19:44:48 +00:00
char speedDialDirNumber [ 24 ] ;
char speedDialDisplayName [ 40 ] ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
# define LINE_STAT_RES_MESSAGE 0x0092
2006-09-17 21:58:04 +00:00
struct line_stat_res_message {
2006-06-18 22:36:39 +00:00
uint32_t lineNumber ;
2003-09-11 19:44:48 +00:00
char lineDirNumber [ 24 ] ;
char lineDisplayName [ 42 ] ;
2006-06-18 22:36:39 +00:00
uint32_t space ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
# define DEFINETIMEDATE_MESSAGE 0x0094
2006-09-17 21:58:04 +00:00
struct definetimedate_message {
2006-06-18 22:36:39 +00:00
uint32_t year ; /* since 1900 */
uint32_t month ;
uint32_t dayofweek ; /* monday = 1 */
uint32_t day ;
uint32_t hour ;
uint32_t minute ;
uint32_t seconds ;
uint32_t milliseconds ;
uint32_t timestamp ;
2006-09-17 21:58:04 +00:00
} ;
2006-03-22 20:45:00 +00:00
2003-09-11 19:44:48 +00:00
# define BUTTON_TEMPLATE_RES_MESSAGE 0x0097
2006-09-17 21:58:04 +00:00
struct button_definition {
2006-06-18 22:36:39 +00:00
uint8_t instanceNumber ;
uint8_t buttonDefinition ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-09-17 21:58:04 +00:00
struct button_definition_template {
2006-06-18 22:36:39 +00:00
uint8_t buttonDefinition ;
/* for now, anything between 0xB0 and 0xCF is custom */
/*int custom;*/
2006-09-17 21:58:04 +00:00
} ;
2006-06-18 22:36:39 +00:00
# define STIMULUS_REDIAL 0x01
# define STIMULUS_SPEEDDIAL 0x02
# define STIMULUS_HOLD 0x03
# define STIMULUS_TRANSFER 0x04
# define STIMULUS_FORWARDALL 0x05
# define STIMULUS_FORWARDBUSY 0x06
# define STIMULUS_FORWARDNOANSWER 0x07
# define STIMULUS_DISPLAY 0x08
# define STIMULUS_LINE 0x09
# define STIMULUS_VOICEMAIL 0x0F
# define STIMULUS_AUTOANSWER 0x11
# define STIMULUS_CONFERENCE 0x7D
# define STIMULUS_CALLPARK 0x7E
# define STIMULUS_CALLPICKUP 0x7F
# define STIMULUS_NONE 0xFF
/* Button types */
# define BT_REDIAL STIMULUS_REDIAL
# define BT_SPEEDDIAL STIMULUS_SPEEDDIAL
# define BT_HOLD STIMULUS_HOLD
# define BT_TRANSFER STIMULUS_TRANSFER
# define BT_FORWARDALL STIMULUS_FORWARDALL
# define BT_FORWARDBUSY STIMULUS_FORWARDBUSY
# define BT_FORWARDNOANSWER STIMULUS_FORWARDNOANSWER
# define BT_DISPLAY STIMULUS_DISPLAY
# define BT_LINE STIMULUS_LINE
# define BT_VOICEMAIL STIMULUS_VOICEMAIL
# define BT_AUTOANSWER STIMULUS_AUTOANSWER
# define BT_CONFERENCE STIMULUS_CONFERENCE
# define BT_CALLPARK STIMULUS_CALLPARK
# define BT_CALLPICKUP STIMULUS_CALLPICKUP
# define BT_NONE 0x00
/* Custom button types - add our own between 0xB0 and 0xCF.
This may need to be revised in the future ,
if stimuluses are ever added in this range . */
2007-02-24 02:23:43 +00:00
# define BT_CUST_LINESPEEDDIAL 0xB0 /* line or speeddial with/without hint */
# define BT_CUST_LINE 0xB1 /* line or speeddial with hint only */
2005-05-24 22:24:04 +00:00
2006-09-17 21:58:04 +00:00
struct button_template_res_message {
2006-06-18 22:36:39 +00:00
uint32_t buttonOffset ;
uint32_t buttonCount ;
uint32_t totalButtonCount ;
2006-09-17 21:58:04 +00:00
struct button_definition definition [ 42 ] ;
} ;
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define VERSION_RES_MESSAGE 0x0098
2006-09-17 21:58:04 +00:00
struct version_res_message {
2003-09-11 19:44:48 +00:00
char version [ 16 ] ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define DISPLAYTEXT_MESSAGE 0x0099
2006-09-17 21:58:04 +00:00
struct displaytext_message {
2006-04-17 01:17:03 +00:00
char text [ 40 ] ;
2006-09-17 21:58:04 +00:00
} ;
2006-04-17 01:17:03 +00:00
2006-11-08 22:52:01 +00:00
# define CLEAR_NOTIFY_MESSAGE 0x0115
# define CLEAR_PROMPT_MESSAGE 0x0113
2006-04-17 01:17:03 +00:00
# define CLEAR_DISPLAY_MESSAGE 0x009A
2006-11-08 22:52:01 +00:00
2006-04-17 01:17:03 +00:00
# define CAPABILITIES_REQ_MESSAGE 0x009B
# define REGISTER_REJ_MESSAGE 0x009D
2006-09-17 21:58:04 +00:00
struct register_rej_message {
2006-04-17 01:17:03 +00:00
char errMsg [ 33 ] ;
2006-09-17 21:58:04 +00:00
} ;
2006-04-17 01:17:03 +00:00
# define SERVER_RES_MESSAGE 0x009E
2006-09-17 21:58:04 +00:00
struct server_identifier {
2006-04-17 01:17:03 +00:00
char serverName [ 48 ] ;
2006-09-17 21:58:04 +00:00
} ;
2006-04-17 01:17:03 +00:00
2006-09-17 21:58:04 +00:00
struct server_res_message {
struct server_identifier server [ 5 ] ;
2006-06-18 22:36:39 +00:00
uint32_t serverListenPort [ 5 ] ;
uint32_t serverIpAddr [ 5 ] ;
2006-09-17 21:58:04 +00:00
} ;
2006-04-17 01:17:03 +00:00
2006-06-18 22:36:39 +00:00
# define RESET_MESSAGE 0x009F
2006-09-17 21:58:04 +00:00
struct reset_message {
2006-06-18 22:36:39 +00:00
uint32_t resetType ;
2006-09-17 21:58:04 +00:00
} ;
2006-06-18 22:36:39 +00:00
2006-04-17 01:17:03 +00:00
# define KEEP_ALIVE_ACK_MESSAGE 0x0100
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define OPEN_RECEIVE_CHANNEL_MESSAGE 0x0105
2006-09-17 21:58:04 +00:00
struct open_receive_channel_message {
2006-06-18 22:36:39 +00:00
uint32_t conferenceId ;
uint32_t partyId ;
uint32_t packets ;
uint32_t capability ;
uint32_t echo ;
uint32_t bitrate ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define CLOSE_RECEIVE_CHANNEL_MESSAGE 0x0106
2006-09-17 21:58:04 +00:00
struct close_receive_channel_message {
2006-06-18 22:36:39 +00:00
uint32_t conferenceId ;
uint32_t partyId ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108
2003-09-11 19:44:48 +00:00
2006-09-17 21:58:04 +00:00
struct soft_key_template_definition {
2003-09-11 19:44:48 +00:00
char softKeyLabel [ 16 ] ;
2006-06-18 22:36:39 +00:00
uint32_t softKeyEvent ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
# define KEYDEF_ONHOOK 0
# define KEYDEF_CONNECTED 1
# define KEYDEF_ONHOLD 2
# define KEYDEF_RINGIN 3
# define KEYDEF_OFFHOOK 4
# define KEYDEF_CONNWITHTRANS 5
# define KEYDEF_DADFD 6 /* Digits After Dialing First Digit */
# define KEYDEF_CONNWITHCONF 7
# define KEYDEF_RINGOUT 8
# define KEYDEF_OFFHOOKWITHFEAT 9
# define KEYDEF_UNKNOWN 10
# define SOFTKEY_NONE 0x00
# define SOFTKEY_REDIAL 0x01
# define SOFTKEY_NEWCALL 0x02
# define SOFTKEY_HOLD 0x03
# define SOFTKEY_TRNSFER 0x04
# define SOFTKEY_CFWDALL 0x05
# define SOFTKEY_CFWDBUSY 0x06
# define SOFTKEY_CFWDNOANSWER 0x07
# define SOFTKEY_BKSPC 0x08
# define SOFTKEY_ENDCALL 0x09
# define SOFTKEY_RESUME 0x0A
# define SOFTKEY_ANSWER 0x0B
# define SOFTKEY_INFO 0x0C
# define SOFTKEY_CONFRN 0x0D
# define SOFTKEY_PARK 0x0E
# define SOFTKEY_JOIN 0x0F
# define SOFTKEY_MEETME 0x10
# define SOFTKEY_PICKUP 0x11
# define SOFTKEY_GPICKUP 0x12
2006-09-17 21:58:04 +00:00
struct soft_key_template_definition soft_key_template_default [ ] = {
2006-06-18 22:36:39 +00:00
{ " Redial " , 0x01 } ,
{ " NewCall " , 0x02 } ,
{ " Hold " , 0x03 } ,
{ " Trnsfer " , 0x04 } ,
{ " CFwdAll " , 0x05 } ,
{ " CFwdBusy " , 0x06 } ,
{ " CFwdNoAnswer " , 0x07 } ,
{ " << " , 0x08 } ,
{ " EndCall " , 0x09 } ,
{ " Resume " , 0x0A } ,
{ " Answer " , 0x0B } ,
{ " Info " , 0x0C } ,
{ " Confrn " , 0x0D } ,
{ " Park " , 0x0E } ,
{ " Join " , 0x0F } ,
{ " MeetMe " , 0x10 } ,
{ " PickUp " , 0x11 } ,
{ " GPickUp " , 0x12 } ,
} ;
2006-09-17 21:58:04 +00:00
struct soft_key_definitions {
2006-06-18 22:36:39 +00:00
const uint8_t mode ;
const uint8_t * defaults ;
const int count ;
2006-09-17 21:58:04 +00:00
} ;
2006-06-18 22:36:39 +00:00
static const uint8_t soft_key_default_onhook [ ] = {
SOFTKEY_REDIAL ,
SOFTKEY_CFWDALL ,
SOFTKEY_CFWDBUSY ,
SOFTKEY_GPICKUP ,
SOFTKEY_CONFRN ,
} ;
static const uint8_t soft_key_default_connected [ ] = {
SOFTKEY_HOLD ,
SOFTKEY_ENDCALL ,
SOFTKEY_TRNSFER ,
SOFTKEY_PARK ,
SOFTKEY_CFWDALL ,
SOFTKEY_CFWDBUSY ,
} ;
static const uint8_t soft_key_default_onhold [ ] = {
SOFTKEY_RESUME ,
SOFTKEY_NEWCALL ,
SOFTKEY_ENDCALL ,
SOFTKEY_TRNSFER ,
} ;
static const uint8_t soft_key_default_ringin [ ] = {
SOFTKEY_ANSWER ,
SOFTKEY_ENDCALL ,
SOFTKEY_TRNSFER ,
} ;
static const uint8_t soft_key_default_offhook [ ] = {
SOFTKEY_REDIAL ,
SOFTKEY_ENDCALL ,
SOFTKEY_CFWDALL ,
SOFTKEY_CFWDBUSY ,
SOFTKEY_GPICKUP ,
} ;
static const uint8_t soft_key_default_connwithtrans [ ] = {
SOFTKEY_HOLD ,
SOFTKEY_ENDCALL ,
SOFTKEY_TRNSFER ,
SOFTKEY_PARK ,
SOFTKEY_CFWDALL ,
SOFTKEY_CFWDBUSY ,
2005-05-24 22:24:04 +00:00
} ;
2006-06-18 22:36:39 +00:00
static const uint8_t soft_key_default_dadfd [ ] = {
SOFTKEY_BKSPC ,
SOFTKEY_ENDCALL ,
} ;
static const uint8_t soft_key_default_connwithconf [ ] = {
SOFTKEY_NONE ,
} ;
static const uint8_t soft_key_default_ringout [ ] = {
SOFTKEY_ENDCALL ,
SOFTKEY_TRNSFER ,
SOFTKEY_CFWDALL ,
SOFTKEY_CFWDBUSY ,
} ;
static const uint8_t soft_key_default_offhookwithfeat [ ] = {
SOFTKEY_REDIAL ,
SOFTKEY_ENDCALL ,
} ;
static const uint8_t soft_key_default_unknown [ ] = {
SOFTKEY_NONE ,
} ;
2006-09-17 21:58:04 +00:00
static const struct soft_key_definitions soft_key_default_definitions [ ] = {
2006-06-18 22:36:39 +00:00
{ KEYDEF_ONHOOK , soft_key_default_onhook , sizeof ( soft_key_default_onhook ) / sizeof ( uint8_t ) } ,
{ KEYDEF_CONNECTED , soft_key_default_connected , sizeof ( soft_key_default_connected ) / sizeof ( uint8_t ) } ,
{ KEYDEF_ONHOLD , soft_key_default_onhold , sizeof ( soft_key_default_onhold ) / sizeof ( uint8_t ) } ,
{ KEYDEF_RINGIN , soft_key_default_ringin , sizeof ( soft_key_default_ringin ) / sizeof ( uint8_t ) } ,
{ KEYDEF_OFFHOOK , soft_key_default_offhook , sizeof ( soft_key_default_offhook ) / sizeof ( uint8_t ) } ,
{ KEYDEF_CONNWITHTRANS , soft_key_default_connwithtrans , sizeof ( soft_key_default_connwithtrans ) / sizeof ( uint8_t ) } ,
{ KEYDEF_DADFD , soft_key_default_dadfd , sizeof ( soft_key_default_dadfd ) / sizeof ( uint8_t ) } ,
{ KEYDEF_CONNWITHCONF , soft_key_default_connwithconf , sizeof ( soft_key_default_connwithconf ) / sizeof ( uint8_t ) } ,
{ KEYDEF_RINGOUT , soft_key_default_ringout , sizeof ( soft_key_default_ringout ) / sizeof ( uint8_t ) } ,
{ KEYDEF_OFFHOOKWITHFEAT , soft_key_default_offhookwithfeat , sizeof ( soft_key_default_offhookwithfeat ) / sizeof ( uint8_t ) } ,
{ KEYDEF_UNKNOWN , soft_key_default_unknown , sizeof ( soft_key_default_unknown ) / sizeof ( uint8_t ) }
} ;
2006-09-17 21:58:04 +00:00
struct soft_key_template_res_message {
2006-06-18 22:36:39 +00:00
uint32_t softKeyOffset ;
uint32_t softKeyCount ;
uint32_t totalSoftKeyCount ;
2006-09-17 21:58:04 +00:00
struct soft_key_template_definition softKeyTemplateDefinition [ 32 ] ;
} ;
2003-09-11 19:44:48 +00:00
2006-04-17 01:17:03 +00:00
# define SOFT_KEY_SET_RES_MESSAGE 0x0109
2003-09-11 19:44:48 +00:00
2006-09-17 21:58:04 +00:00
struct soft_key_set_definition {
2006-06-18 22:36:39 +00:00
uint8_t softKeyTemplateIndex [ 16 ] ;
uint16_t softKeyInfoIndex [ 16 ] ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-09-17 21:58:04 +00:00
struct soft_key_set_res_message {
2006-06-18 22:36:39 +00:00
uint32_t softKeySetOffset ;
uint32_t softKeySetCount ;
uint32_t totalSoftKeySetCount ;
2006-09-17 21:58:04 +00:00
struct soft_key_set_definition softKeySetDefinition [ 16 ] ;
2006-06-18 22:36:39 +00:00
uint32_t res ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
# define SELECT_SOFT_KEYS_MESSAGE 0x0110
2006-09-17 21:58:04 +00:00
struct select_soft_keys_message {
2006-06-18 22:36:39 +00:00
uint32_t instance ;
uint32_t reference ;
uint32_t softKeySetIndex ;
uint32_t validKeyMask ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
# define CALL_STATE_MESSAGE 0x0111
2006-09-17 21:58:04 +00:00
struct call_state_message {
2006-06-18 22:36:39 +00:00
uint32_t callState ;
uint32_t lineInstance ;
uint32_t callReference ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2005-06-02 09:11:46 +00:00
# define DISPLAY_PROMPT_STATUS_MESSAGE 0x0112
2006-09-17 21:58:04 +00:00
struct display_prompt_status_message {
2006-06-18 22:36:39 +00:00
uint32_t messageTimeout ;
2005-06-02 09:11:46 +00:00
char promptMessage [ 32 ] ;
2006-06-18 22:36:39 +00:00
uint32_t lineInstance ;
uint32_t callReference ;
2006-09-17 21:58:04 +00:00
} ;
2005-06-02 09:11:46 +00:00
# define DISPLAY_NOTIFY_MESSAGE 0x0114
2006-09-17 21:58:04 +00:00
struct display_notify_message {
2006-06-18 22:36:39 +00:00
uint32_t displayTimeout ;
2005-06-02 09:11:46 +00:00
char displayMessage [ 100 ] ;
2006-09-17 21:58:04 +00:00
} ;
2005-06-02 09:11:46 +00:00
2003-09-11 19:44:48 +00:00
# define ACTIVATE_CALL_PLANE_MESSAGE 0x0116
2006-09-17 21:58:04 +00:00
struct activate_call_plane_message {
2006-06-18 22:36:39 +00:00
uint32_t lineInstance ;
2006-09-17 21:58:04 +00:00
} ;
2003-09-11 19:44:48 +00:00
2006-03-21 15:12:41 +00:00
# define DIALED_NUMBER_MESSAGE 0x011D
2006-09-17 21:58:04 +00:00
struct dialed_number_message {
2006-03-21 15:12:41 +00:00
char dialedNumber [ 24 ] ;
2006-06-18 22:36:39 +00:00
uint32_t lineInstance ;
uint32_t callReference ;
2006-09-17 21:58:04 +00:00
} ;
union skinny_data {
struct alarm_message alarm ;
struct speed_dial_stat_req_message speeddialreq ;
struct register_message reg ;
struct register_ack_message regack ;
struct register_rej_message regrej ;
struct capabilities_res_message caps ;
struct version_res_message version ;
struct button_template_res_message buttontemplate ;
struct displaytext_message displaytext ;
struct display_prompt_status_message displaypromptstatus ;
struct definetimedate_message definetimedate ;
struct start_tone_message starttone ;
struct speed_dial_stat_res_message speeddial ;
struct line_state_req_message line ;
struct line_stat_res_message linestat ;
struct soft_key_set_res_message softkeysets ;
struct soft_key_template_res_message softkeytemplate ;
struct server_res_message serverres ;
struct reset_message reset ;
struct set_lamp_message setlamp ;
struct set_ringer_message setringer ;
struct call_state_message callstate ;
struct keypad_button_message keypad ;
struct select_soft_keys_message selectsoftkey ;
struct activate_call_plane_message activatecallplane ;
struct stimulus_message stimulus ;
struct offhook_message offhook ;
struct onhook_message onhook ;
struct set_speaker_message setspeaker ;
struct set_microphone_message setmicrophone ;
struct call_info_message callinfo ;
struct start_media_transmission_message startmedia ;
struct stop_media_transmission_message stopmedia ;
struct open_receive_channel_message openreceivechannel ;
struct open_receive_channel_ack_message openreceivechannelack ;
struct close_receive_channel_message closereceivechannel ;
struct display_notify_message displaynotify ;
struct dialed_number_message dialednumber ;
struct soft_key_event_message softkeyeventmessage ;
} ;
2006-06-18 22:36:39 +00:00
2003-09-11 19:44:48 +00:00
/* packet composition */
2006-09-17 21:58:04 +00:00
struct skinny_req {
2003-09-11 19:44:48 +00:00
int len ;
int res ;
int e ;
2006-09-17 21:58:04 +00:00
union skinny_data data ;
} ;
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
/* XXX This is the combined size of the variables above. (len, res, e)
If more are added , this MUST change .
( sizeof ( skinny_req ) - sizeof ( skinny_data ) ) DOES NOT WORK on all systems ( amd64 ? ) . */
int skinny_header_size = 12 ;
2006-03-21 15:12:41 +00:00
/*****************************
* Asterisk specific globals *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-09-11 19:44:48 +00:00
2006-06-18 23:18:34 +00:00
static int skinnydebug = 0 ;
2003-09-11 19:44:48 +00:00
/* a hostname, portnumber, socket and such is usefull for VoIP protocols */
static struct sockaddr_in bindaddr ;
static char ourhost [ 256 ] ;
static int ourport ;
static struct in_addr __ourip ;
2006-06-18 22:36:39 +00:00
struct ast_hostent ahp ;
struct hostent * hp ;
2006-03-21 15:12:41 +00:00
static int skinnysock = - 1 ;
2003-09-11 19:44:48 +00:00
static pthread_t accept_t ;
2005-07-10 23:49:57 +00:00
static char context [ AST_MAX_CONTEXT ] = " default " ;
2003-09-11 19:44:48 +00:00
static char language [ MAX_LANGUAGE ] = " " ;
2006-07-19 20:44:39 +00:00
static char mohinterpret [ MAX_MUSICCLASS ] = " default " ;
2006-09-17 22:24:27 +00:00
static char mohsuggest [ MAX_MUSICCLASS ] = " " ;
2004-10-02 00:58:31 +00:00
static char cid_num [ AST_MAX_EXTENSION ] = " " ;
static char cid_name [ AST_MAX_EXTENSION ] = " " ;
2003-09-11 19:44:48 +00:00
static char linelabel [ AST_MAX_EXTENSION ] = " " ;
static int nat = 0 ;
2005-01-15 21:51:38 +00:00
static ast_group_t cur_callergroup = 0 ;
static ast_group_t cur_pickupgroup = 0 ;
2003-09-11 19:44:48 +00:00
static int immediate = 0 ;
static int callwaiting = 0 ;
static int callreturn = 0 ;
static int threewaycalling = 0 ;
2005-06-02 09:11:46 +00:00
static int mwiblink = 0 ;
2003-09-11 19:44:48 +00:00
/* This is for flashhook transfers */
static int transfer = 0 ;
static int cancallforward = 0 ;
2004-05-12 21:30:23 +00:00
/* static int busycount = 3;*/
2005-05-25 17:18:05 +00:00
static char accountcode [ AST_MAX_ACCOUNT_CODE ] = " " ;
2003-09-11 19:44:48 +00:00
static char mailbox [ AST_MAX_EXTENSION ] ;
static int amaflags = 0 ;
static int callnums = 1 ;
2006-06-18 22:36:39 +00:00
# define SKINNY_DEVICE_UNKNOWN -1
# define SKINNY_DEVICE_NONE 0
# define SKINNY_DEVICE_30SPPLUS 1
# define SKINNY_DEVICE_12SPPLUS 2
# define SKINNY_DEVICE_12SP 3
# define SKINNY_DEVICE_12 4
# define SKINNY_DEVICE_30VIP 5
# define SKINNY_DEVICE_7910 6
# define SKINNY_DEVICE_7960 7
# define SKINNY_DEVICE_7940 8
# define SKINNY_DEVICE_7935 9
# define SKINNY_DEVICE_ATA186 12 /* Cisco ATA-186 */
# define SKINNY_DEVICE_7941 115
# define SKINNY_DEVICE_7971 119
# define SKINNY_DEVICE_7985 302
# define SKINNY_DEVICE_7911 307
# define SKINNY_DEVICE_7961GE 308
# define SKINNY_DEVICE_7941GE 309
# define SKINNY_DEVICE_7905 20000
# define SKINNY_DEVICE_7920 30002
# define SKINNY_DEVICE_7970 30006
# define SKINNY_DEVICE_7912 30007
# define SKINNY_DEVICE_7902 30008
# define SKINNY_DEVICE_CIPC 30016 /* Cisco IP Communicator */
# define SKINNY_DEVICE_7961 30018
# define SKINNY_DEVICE_7936 30019
# define SKINNY_DEVICE_SCCPGATEWAY_AN 30027 /* ??? */
# define SKINNY_DEVICE_SCCPGATEWAY_BRI 30028 /* ??? */
2003-09-11 19:44:48 +00:00
# define SKINNY_SPEAKERON 1
# define SKINNY_SPEAKEROFF 2
2006-06-18 22:36:39 +00:00
# define SKINNY_MICON 1
# define SKINNY_MICOFF 2
2003-09-11 19:44:48 +00:00
# define SKINNY_OFFHOOK 1
# define SKINNY_ONHOOK 2
# define SKINNY_RINGOUT 3
# define SKINNY_RINGIN 4
# define SKINNY_CONNECTED 5
# define SKINNY_BUSY 6
# define SKINNY_CONGESTION 7
# define SKINNY_HOLD 8
# define SKINNY_CALLWAIT 9
# define SKINNY_TRANSFER 10
# define SKINNY_PARK 11
# define SKINNY_PROGRESS 12
2007-02-24 02:23:43 +00:00
# define SKINNY_CALLREMOTEMULTILINE 13
2003-09-11 19:44:48 +00:00
# define SKINNY_INVALID 14
2005-06-02 09:11:46 +00:00
# define SKINNY_SILENCE 0x00
# define SKINNY_DIALTONE 0x21
# define SKINNY_BUSYTONE 0x23
# define SKINNY_ALERT 0x24
# define SKINNY_REORDER 0x25
# define SKINNY_CALLWAITTONE 0x2D
# define SKINNY_NOTONE 0x7F
2003-09-11 19:44:48 +00:00
2003-09-13 23:30:30 +00:00
# define SKINNY_LAMP_OFF 1
2006-03-21 15:12:41 +00:00
# define SKINNY_LAMP_ON 2
2003-09-13 23:30:30 +00:00
# define SKINNY_LAMP_WINK 3
# define SKINNY_LAMP_FLASH 4
# define SKINNY_LAMP_BLINK 5
# define SKINNY_RING_OFF 1
# define SKINNY_RING_INSIDE 2
# define SKINNY_RING_OUTSIDE 3
# define SKINNY_RING_FEATURE 4
2004-05-12 21:30:23 +00:00
# define TYPE_TRUNK 1
# define TYPE_LINE 2
2003-09-11 19:44:48 +00:00
2004-05-12 21:30:23 +00:00
/* Skinny rtp stream modes. Do we really need this? */
2006-03-21 15:12:41 +00:00
# define SKINNY_CX_SENDONLY 0
# define SKINNY_CX_RECVONLY 1
# define SKINNY_CX_SENDRECV 2
# define SKINNY_CX_CONF 3
# define SKINNY_CX_CONFERENCE 3
# define SKINNY_CX_MUTE 4
# define SKINNY_CX_INACTIVE 4
2003-09-11 19:44:48 +00:00
2003-09-12 23:47:02 +00:00
#if 0
2003-09-11 19:44:48 +00:00
static char * skinny_cxmodes [ ] = {
2006-03-21 15:12:41 +00:00
" sendonly " ,
" recvonly " ,
" sendrecv " ,
" confrnce " ,
" inactive "
2003-09-11 19:44:48 +00:00
} ;
2003-09-12 23:47:02 +00:00
# endif
2003-09-11 19:44:48 +00:00
/* driver scheduler */
static struct sched_context * sched ;
static struct io_context * io ;
/* 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 ) ;
2003-09-13 23:30:30 +00:00
/* Protect the network socket */
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( netlock ) ;
2003-09-13 23:30:30 +00:00
/* Protect the session list */
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( sessionlock ) ;
2003-09-13 23:30:30 +00:00
/* Protect the device list */
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( devicelock ) ;
2005-06-21 23:06:44 +00:00
#if 0
2005-06-02 09:11:46 +00:00
/* Protect the paging device list */
AST_MUTEX_DEFINE_STATIC ( pagingdevicelock ) ;
2005-06-21 23:06:44 +00:00
# endif
2003-09-11 19:44:48 +00:00
/* This is the thread for the monitor which checks for input on the channels
2006-03-21 15:12:41 +00:00
which are not currently in use . */
2004-03-15 07:51:22 +00:00
static pthread_t monitor_thread = AST_PTHREADT_NULL ;
2003-09-11 19:44:48 +00:00
/* Wait up to 16 seconds for first digit */
static int firstdigittimeout = 16000 ;
/* How long to wait for following digits */
static int gendigittimeout = 8000 ;
/* How long to wait for an extra digit, if there is an ambiguous match */
static int matchdigittimeout = 3000 ;
struct skinny_subchannel {
ast_mutex_t lock ;
struct ast_channel * owner ;
struct ast_rtp * rtp ;
2006-06-18 22:36:39 +00:00
struct ast_rtp * vrtp ;
unsigned int callid ;
/* time_t lastouttime; */ /* Unused */
2004-05-31 02:49:53 +00:00
int progress ;
int ringing ;
2006-09-17 22:24:27 +00:00
int onhold ;
2006-06-18 22:36:39 +00:00
/* int lastout; */ /* Unused */
2003-09-11 19:44:48 +00:00
int cxmode ;
int nat ;
int outgoing ;
int alreadygone ;
2006-06-18 22:36:39 +00:00
2006-03-22 20:45:00 +00:00
struct skinny_subchannel * next ;
2006-06-18 22:36:39 +00:00
struct skinny_line * parent ;
2003-09-11 19:44:48 +00:00
} ;
struct skinny_line {
ast_mutex_t lock ;
char name [ 80 ] ;
2004-03-04 06:25:27 +00:00
char label [ 42 ] ; /* Label that shows next to the line buttons */
2005-05-25 17:18:05 +00:00
char accountcode [ AST_MAX_ACCOUNT_CODE ] ;
2006-03-22 20:45:00 +00:00
char exten [ AST_MAX_EXTENSION ] ; /* Extension where to start */
2005-07-10 23:49:57 +00:00
char context [ AST_MAX_CONTEXT ] ;
2003-09-11 19:44:48 +00:00
char language [ MAX_LANGUAGE ] ;
2004-10-02 00:58:31 +00:00
char cid_num [ AST_MAX_EXTENSION ] ; /* Caller*ID */
char cid_name [ AST_MAX_EXTENSION ] ; /* Caller*ID */
2004-03-04 06:25:27 +00:00
char lastcallerid [ AST_MAX_EXTENSION ] ; /* Last Caller*ID */
2006-03-22 20:45:00 +00:00
char call_forward [ AST_MAX_EXTENSION ] ;
2003-09-11 19:44:48 +00:00
char mailbox [ AST_MAX_EXTENSION ] ;
2007-05-11 22:52:36 +00:00
char vmexten [ AST_MAX_EXTENSION ] ;
2006-07-19 20:44:39 +00:00
char mohinterpret [ MAX_MUSICCLASS ] ;
2006-09-17 22:24:27 +00:00
char mohsuggest [ MAX_MUSICCLASS ] ;
2006-06-18 22:36:39 +00:00
char lastnumberdialed [ AST_MAX_EXTENSION ] ; /* Last number that was dialed - used for redial */
2004-05-12 21:30:23 +00:00
int curtone ; /* Current tone being played */
2005-01-15 21:51:38 +00:00
ast_group_t callgroup ;
ast_group_t pickupgroup ;
2003-09-11 19:44:48 +00:00
int callwaiting ;
int transfer ;
int threewaycalling ;
2005-06-02 09:11:46 +00:00
int mwiblink ;
2003-09-11 19:44:48 +00:00
int cancallforward ;
int callreturn ;
int dnd ; /* How does this affect callwait? Do we just deny a skinny_request if we're dnd? */
int hascallerid ;
int hidecallerid ;
int amaflags ;
int type ;
int instance ;
int group ;
int needdestroy ;
int capability ;
int nonCodecCapability ;
int onhooktime ;
2006-06-18 22:36:39 +00:00
int msgstate ; /* voicemail message state */
2003-09-11 19:44:48 +00:00
int immediate ;
int hookstate ;
2006-06-18 22:36:39 +00:00
int nat ;
2006-09-18 23:32:57 +00:00
struct ast_codec_pref prefs ;
2006-06-18 22:36:39 +00:00
struct skinny_subchannel * sub ;
2003-09-11 19:44:48 +00:00
struct skinny_line * next ;
struct skinny_device * parent ;
} ;
2006-06-18 22:36:39 +00:00
struct skinny_speeddial {
ast_mutex_t lock ;
char label [ 42 ] ;
2007-02-24 02:23:43 +00:00
char context [ AST_MAX_CONTEXT ] ;
2006-06-18 22:36:39 +00:00
char exten [ AST_MAX_EXTENSION ] ;
int instance ;
2007-02-24 02:23:43 +00:00
int stateid ;
int laststate ;
int isHint ;
2006-06-18 22:36:39 +00:00
struct skinny_speeddial * next ;
struct skinny_device * parent ;
} ;
struct skinny_addon {
ast_mutex_t lock ;
char type [ 10 ] ;
struct skinny_addon * next ;
struct skinny_device * parent ;
} ;
2003-09-11 19:44:48 +00:00
static struct skinny_device {
/* A device containing one or more lines */
char name [ 80 ] ;
char id [ 16 ] ;
2006-03-22 20:45:00 +00:00
char version_id [ 16 ] ;
2007-06-01 19:42:27 +00:00
char exten [ AST_MAX_EXTENSION ] ; /* Cruddy variable name, pick a better one */
2003-09-11 19:44:48 +00:00
int type ;
int registered ;
2006-06-18 22:36:39 +00:00
int lastlineinstance ;
int lastcallreference ;
2006-09-18 23:32:57 +00:00
int capability ;
2003-09-11 19:44:48 +00:00
struct sockaddr_in addr ;
struct in_addr ourip ;
struct skinny_line * lines ;
2006-06-18 22:36:39 +00:00
struct skinny_speeddial * speeddials ;
struct skinny_addon * addons ;
2006-09-18 23:32:57 +00:00
struct ast_codec_pref prefs ;
2003-09-11 19:44:48 +00:00
struct ast_ha * ha ;
struct skinnysession * session ;
struct skinny_device * next ;
} * devices = NULL ;
2005-06-07 16:59:20 +00:00
struct skinny_paging_device {
2005-06-02 09:11:46 +00:00
char name [ 80 ] ;
char id [ 16 ] ;
struct skinny_device * * devices ;
struct skinny_paging_device * next ;
2005-06-07 16:59:20 +00:00
} ;
2005-06-02 09:11:46 +00:00
2004-03-04 06:25:27 +00:00
static struct skinnysession {
2003-09-11 19:44:48 +00:00
pthread_t t ;
ast_mutex_t lock ;
struct sockaddr_in sin ;
int fd ;
char inbuf [ SKINNY_MAX_PACKET ] ;
2006-06-18 22:36:39 +00:00
char outbuf [ SKINNY_MAX_PACKET ] ;
2003-09-11 19:44:48 +00:00
struct skinny_device * device ;
struct skinnysession * next ;
} * sessions = NULL ;
2005-03-04 06:47:24 +00:00
static struct ast_channel * skinny_request ( const char * type , int format , void * data , int * cause ) ;
2007-02-24 02:06:44 +00:00
static int skinny_devicestate ( void * data ) ;
2005-03-04 06:47:24 +00:00
static int skinny_call ( struct ast_channel * ast , char * dest , int timeout ) ;
static int skinny_hangup ( struct ast_channel * ast ) ;
static int skinny_answer ( struct ast_channel * ast ) ;
static struct ast_frame * skinny_read ( struct ast_channel * ast ) ;
static int skinny_write ( struct ast_channel * ast , struct ast_frame * frame ) ;
2006-05-10 12:24:11 +00:00
static int skinny_indicate ( struct ast_channel * ast , int ind , const void * data , size_t datalen ) ;
2005-03-04 06:47:24 +00:00
static int skinny_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan ) ;
2006-08-31 01:59:02 +00:00
static int skinny_senddigit_begin ( struct ast_channel * ast , char digit ) ;
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
static int skinny_senddigit_end ( struct ast_channel * ast , char digit , unsigned int duration ) ;
2005-03-04 06:47:24 +00:00
static const struct ast_channel_tech skinny_tech = {
2006-02-01 23:05:28 +00:00
. type = " Skinny " ,
2005-03-04 06:47:24 +00:00
. description = tdesc ,
2006-09-18 23:32:57 +00:00
. capabilities = ( ( AST_FORMAT_MAX_AUDIO < < 1 ) - 1 ) ,
2006-05-31 17:21:21 +00:00
. properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER ,
2005-03-04 06:47:24 +00:00
. requester = skinny_request ,
2007-02-24 02:06:44 +00:00
. devicestate = skinny_devicestate ,
2005-03-04 06:47:24 +00:00
. call = skinny_call ,
. hangup = skinny_hangup ,
. answer = skinny_answer ,
. read = skinny_read ,
. write = skinny_write ,
. indicate = skinny_indicate ,
. fixup = skinny_fixup ,
2006-08-31 01:59:02 +00:00
. send_digit_begin = skinny_senddigit_begin ,
. send_digit_end = skinny_senddigit_end ,
2005-03-04 06:47:24 +00:00
/* .bridge = ast_rtp_bridge, */
} ;
2007-02-24 02:23:43 +00:00
static int skinny_extensionstate_cb ( char * context , char * exten , int state , void * data ) ;
2006-09-17 21:58:04 +00:00
static void * get_button_template ( struct skinnysession * s , struct button_definition_template * btn )
2006-06-18 22:36:39 +00:00
{
struct skinny_device * d = s - > device ;
struct skinny_addon * a = d - > addons ;
int i ;
switch ( d - > type ) {
case SKINNY_DEVICE_30SPPLUS :
case SKINNY_DEVICE_30VIP :
/* 13 rows, 2 columns */
for ( i = 0 ; i < 4 ; i + + )
2007-02-24 02:23:43 +00:00
( btn + + ) - > buttonDefinition = BT_CUST_LINE ;
2006-06-18 22:36:39 +00:00
( btn + + ) - > buttonDefinition = BT_REDIAL ;
( btn + + ) - > buttonDefinition = BT_VOICEMAIL ;
( btn + + ) - > buttonDefinition = BT_CALLPARK ;
( btn + + ) - > buttonDefinition = BT_FORWARDALL ;
( btn + + ) - > buttonDefinition = BT_CONFERENCE ;
for ( i = 0 ; i < 4 ; i + + )
( btn + + ) - > buttonDefinition = BT_NONE ;
for ( i = 0 ; i < 13 ; i + + )
( btn + + ) - > buttonDefinition = BT_SPEEDDIAL ;
break ;
case SKINNY_DEVICE_12SPPLUS :
case SKINNY_DEVICE_12SP :
case SKINNY_DEVICE_12 :
/* 6 rows, 2 columns */
for ( i = 0 ; i < 2 ; i + + )
2007-02-24 02:23:43 +00:00
( btn + + ) - > buttonDefinition = BT_CUST_LINE ;
for ( i = 0 ; i < 4 ; i + + )
2006-06-18 22:36:39 +00:00
( btn + + ) - > buttonDefinition = BT_SPEEDDIAL ;
( btn + + ) - > buttonDefinition = BT_HOLD ;
2007-02-24 02:23:43 +00:00
( btn + + ) - > buttonDefinition = BT_REDIAL ;
2006-06-18 22:36:39 +00:00
( btn + + ) - > buttonDefinition = BT_TRANSFER ;
( btn + + ) - > buttonDefinition = BT_FORWARDALL ;
( btn + + ) - > buttonDefinition = BT_CALLPARK ;
( btn + + ) - > buttonDefinition = BT_VOICEMAIL ;
break ;
case SKINNY_DEVICE_7910 :
( btn + + ) - > buttonDefinition = BT_LINE ;
( btn + + ) - > buttonDefinition = BT_HOLD ;
( btn + + ) - > buttonDefinition = BT_TRANSFER ;
( btn + + ) - > buttonDefinition = BT_DISPLAY ;
( btn + + ) - > buttonDefinition = BT_VOICEMAIL ;
( btn + + ) - > buttonDefinition = BT_CONFERENCE ;
( btn + + ) - > buttonDefinition = BT_FORWARDALL ;
for ( i = 0 ; i < 2 ; i + + )
( btn + + ) - > buttonDefinition = BT_SPEEDDIAL ;
( btn + + ) - > buttonDefinition = BT_REDIAL ;
break ;
case SKINNY_DEVICE_7960 :
case SKINNY_DEVICE_7961 :
case SKINNY_DEVICE_7961GE :
for ( i = 0 ; i < 6 ; i + + )
( btn + + ) - > buttonDefinition = BT_CUST_LINESPEEDDIAL ;
break ;
case SKINNY_DEVICE_7940 :
case SKINNY_DEVICE_7941 :
case SKINNY_DEVICE_7941GE :
for ( i = 0 ; i < 2 ; i + + )
( btn + + ) - > buttonDefinition = BT_CUST_LINESPEEDDIAL ;
break ;
case SKINNY_DEVICE_7935 :
case SKINNY_DEVICE_7936 :
for ( i = 0 ; i < 2 ; i + + )
( btn + + ) - > buttonDefinition = BT_LINE ;
break ;
case SKINNY_DEVICE_ATA186 :
( btn + + ) - > buttonDefinition = BT_LINE ;
break ;
case SKINNY_DEVICE_7970 :
case SKINNY_DEVICE_7971 :
case SKINNY_DEVICE_CIPC :
for ( i = 0 ; i < 8 ; i + + )
( btn + + ) - > buttonDefinition = BT_CUST_LINESPEEDDIAL ;
break ;
case SKINNY_DEVICE_7985 :
/* XXX I have no idea what the buttons look like on these. */
ast_log ( LOG_WARNING , " Unsupported device type '%d (7985)' found. \n " , d - > type ) ;
break ;
case SKINNY_DEVICE_7912 :
case SKINNY_DEVICE_7911 :
case SKINNY_DEVICE_7905 :
( btn + + ) - > buttonDefinition = BT_LINE ;
( btn + + ) - > buttonDefinition = BT_HOLD ;
break ;
case SKINNY_DEVICE_7920 :
/* XXX I don't know if this is right. */
for ( i = 0 ; i < 4 ; i + + )
( btn + + ) - > buttonDefinition = BT_CUST_LINESPEEDDIAL ;
break ;
case SKINNY_DEVICE_7902 :
ast_log ( LOG_WARNING , " Unsupported device type '%d (7902)' found. \n " , d - > type ) ;
break ;
case SKINNY_DEVICE_SCCPGATEWAY_AN :
case SKINNY_DEVICE_SCCPGATEWAY_BRI :
ast_log ( LOG_WARNING , " Unsupported device type '%d (SCCP gateway)' found. \n " , d - > type ) ;
break ;
default :
ast_log ( LOG_WARNING , " Unknown device type '%d' found. \n " , d - > type ) ;
break ;
}
for ( a = d - > addons ; a ; a = a - > next ) {
if ( ! strcasecmp ( a - > type , " 7914 " ) ) {
for ( i = 0 ; i < 14 ; i + + )
( btn + + ) - > buttonDefinition = BT_CUST_LINESPEEDDIAL ;
} else {
ast_log ( LOG_WARNING , " Unknown addon type '%s' found. Skipping. \n " , a - > type ) ;
}
}
return btn ;
}
2006-09-17 21:58:04 +00:00
static struct skinny_req * req_alloc ( size_t size , int response_message )
2003-09-11 19:44:48 +00:00
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2006-06-18 22:36:39 +00:00
if ( ! ( req = ast_calloc ( 1 , skinny_header_size + size + 4 ) ) )
2003-09-11 19:44:48 +00:00
return NULL ;
2006-06-18 22:36:39 +00:00
req - > len = htolel ( size + 4 ) ;
req - > e = htolel ( response_message ) ;
2003-09-11 19:44:48 +00:00
return req ;
}
2006-06-18 22:36:39 +00:00
static struct skinny_line * find_line_by_instance ( struct skinny_device * d , int instance )
2003-09-11 19:44:48 +00:00
{
2006-06-18 22:36:39 +00:00
struct skinny_line * l ;
2007-06-01 19:42:27 +00:00
/*Dialing from on hook or on a 7920 uses instance 0 in requests
but we need to start looking at instance 1 */
if ( ! instance )
instance = 1 ;
2006-06-18 22:36:39 +00:00
for ( l = d - > lines ; l ; l = l - > next ) {
if ( l - > instance = = instance )
break ;
}
if ( ! l ) {
ast_log ( LOG_WARNING , " Could not find line with instance '%d' on device '%s' \n " , instance , d - > name ) ;
}
return l ;
2003-09-11 19:44:48 +00:00
}
2006-06-18 22:36:39 +00:00
static struct skinny_line * find_line_by_name ( const char * dest )
2003-09-13 23:30:30 +00:00
{
struct skinny_line * l ;
struct skinny_device * d ;
char line [ 256 ] ;
char * at ;
char * device ;
2006-03-22 20:45:00 +00:00
2006-04-21 18:08:57 +00:00
ast_copy_string ( line , dest , sizeof ( line ) ) ;
2003-09-13 23:30:30 +00:00
at = strchr ( line , ' @ ' ) ;
if ( ! at ) {
ast_log ( LOG_NOTICE , " Device '%s' has no @ (at) sign! \n " , dest ) ;
return NULL ;
}
2006-04-21 18:08:57 +00:00
* at + + = ' \0 ' ;
2003-09-13 23:30:30 +00:00
device = at ;
ast_mutex_lock ( & devicelock ) ;
2006-04-21 18:08:57 +00:00
for ( d = devices ; d ; d = d - > next ) {
2003-09-13 23:30:30 +00:00
if ( ! strcasecmp ( d - > name , device ) ) {
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
2004-04-06 03:43:43 +00:00
ast_verbose ( " Found device: %s \n " , d - > name ) ;
2003-09-13 23:30:30 +00:00
/* Found the device */
2006-04-21 18:08:57 +00:00
for ( l = d - > lines ; l ; l = l - > next ) {
2003-09-13 23:30:30 +00:00
/* Search for the right line */
if ( ! strcasecmp ( l - > name , line ) ) {
ast_mutex_unlock ( & devicelock ) ;
2006-06-18 22:36:39 +00:00
return l ;
2003-09-13 23:30:30 +00:00
}
}
}
}
2006-03-22 20:45:00 +00:00
/* Device not found */
2003-09-13 23:30:30 +00:00
ast_mutex_unlock ( & devicelock ) ;
return NULL ;
}
2006-06-18 22:36:39 +00:00
/* It's quicker/easier to find the subchannel when we know the instance number too */
static struct skinny_subchannel * find_subchannel_by_instance_reference ( struct skinny_device * d , int instance , int reference )
{
struct skinny_line * l = find_line_by_instance ( d , instance ) ;
struct skinny_subchannel * sub ;
if ( ! l ) {
return NULL ;
}
2007-06-01 19:42:27 +00:00
/* 7920 phones set call reference to 0, so use the first
sub - channel on the list .
This MIGHT need more love to be right */
if ( ! reference )
sub = l - > sub ;
else {
for ( sub = l - > sub ; sub ; sub = sub - > next ) {
if ( sub - > callid = = reference )
break ;
}
2006-06-18 22:36:39 +00:00
}
if ( ! sub ) {
ast_log ( LOG_WARNING , " Could not find subchannel with reference '%d' on '%s' \n " , reference , d - > name ) ;
}
return sub ;
}
/* Find the subchannel when we only have the callid - this shouldn't happen often */
static struct skinny_subchannel * find_subchannel_by_reference ( struct skinny_device * d , int reference )
{
struct skinny_line * l ;
struct skinny_subchannel * sub = NULL ;
for ( l = d - > lines ; l ; l = l - > next ) {
for ( sub = l - > sub ; sub ; sub = sub - > next ) {
if ( sub - > callid = = reference )
break ;
}
if ( sub )
break ;
}
if ( ! l ) {
ast_log ( LOG_WARNING , " Could not find any lines that contained a subchannel with reference '%d' on device '%s' \n " , reference , d - > name ) ;
} else {
if ( ! sub ) {
ast_log ( LOG_WARNING , " Could not find subchannel with reference '%d' on '%s@%s' \n " , reference , l - > name , d - > name ) ;
}
}
return sub ;
}
2007-02-24 02:23:43 +00:00
static struct skinny_speeddial * find_speeddial_by_instance ( struct skinny_device * d , int instance , int isHint )
2006-06-18 22:36:39 +00:00
{
struct skinny_speeddial * sd ;
for ( sd = d - > speeddials ; sd ; sd = sd - > next ) {
2007-02-24 02:23:43 +00:00
if ( sd - > isHint = = isHint & & sd - > instance = = instance )
2006-06-18 22:36:39 +00:00
break ;
}
if ( ! sd ) {
ast_log ( LOG_WARNING , " Could not find speeddial with instance '%d' on device '%s' \n " , instance , d - > name ) ;
}
return sd ;
}
Merged revisions 43650 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r43650 | qwell | 2006-09-26 08:33:47 -0700 (Tue, 26 Sep 2006) | 11 lines
Add proper codec support to chan_skinny. Works with at least ulaw, alaw, and g729a.
This is technically a "new feature", but there are justifications for it.
I found a bug with the recent rtp packetization changes, which caused the media setup to
fail under certain circumstances, particularly when using allow=all, or having no allow=
statements (globally or on the device).
I could have either removed the rtp packetization features, or I could add proper codec
support (which, without, I think most people would consider to be a bug anyways).
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43651 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-09-26 15:35:37 +00:00
static int codec_skinny2ast ( enum skinny_codecs skinnycodec )
{
switch ( skinnycodec ) {
case SKINNY_CODEC_ALAW :
return AST_FORMAT_ALAW ;
case SKINNY_CODEC_ULAW :
return AST_FORMAT_ULAW ;
case SKINNY_CODEC_G723_1 :
return AST_FORMAT_G723_1 ;
case SKINNY_CODEC_G729A :
return AST_FORMAT_G729A ;
case SKINNY_CODEC_G726_32 :
return AST_FORMAT_G726_AAL2 ; /* XXX Is this right? */
case SKINNY_CODEC_H261 :
return AST_FORMAT_H261 ;
case SKINNY_CODEC_H263 :
return AST_FORMAT_H263 ;
default :
return 0 ;
}
}
static int codec_ast2skinny ( int astcodec )
{
switch ( astcodec ) {
case AST_FORMAT_ALAW :
return SKINNY_CODEC_ALAW ;
case AST_FORMAT_ULAW :
return SKINNY_CODEC_ULAW ;
case AST_FORMAT_G723_1 :
return SKINNY_CODEC_G723_1 ;
case AST_FORMAT_G729A :
return SKINNY_CODEC_G729A ;
case AST_FORMAT_G726_AAL2 : /* XXX Is this right? */
return SKINNY_CODEC_G726_32 ;
case AST_FORMAT_H261 :
return SKINNY_CODEC_H261 ;
case AST_FORMAT_H263 :
return SKINNY_CODEC_H263 ;
default :
return 0 ;
}
}
2006-10-09 16:15:16 +00:00
static int skinny_register ( struct skinny_req * req , struct skinnysession * s )
{
struct skinny_device * d ;
2007-02-24 02:23:43 +00:00
struct skinny_line * l ;
struct skinny_speeddial * sd ;
2006-10-09 16:15:16 +00:00
struct sockaddr_in sin ;
socklen_t slen ;
ast_mutex_lock ( & devicelock ) ;
for ( d = devices ; d ; d = d - > next ) {
if ( ! strcasecmp ( req - > data . reg . name , d - > id )
& & ast_apply_ha ( d - > ha , & ( s - > sin ) ) ) {
s - > device = d ;
d - > type = letohl ( req - > data . reg . type ) ;
if ( ast_strlen_zero ( d - > version_id ) ) {
ast_copy_string ( d - > version_id , version_id , sizeof ( d - > version_id ) ) ;
}
d - > registered = 1 ;
d - > session = s ;
slen = sizeof ( sin ) ;
if ( getsockname ( s - > fd , ( struct sockaddr * ) & sin , & slen ) ) {
ast_log ( LOG_WARNING , " Cannot get socket name \n " ) ;
sin . sin_addr = __ourip ;
}
d - > ourip = sin . sin_addr ;
2007-02-24 02:23:43 +00:00
for ( sd = d - > speeddials ; sd ; sd = sd - > next ) {
sd - > stateid = ast_extension_state_add ( sd - > context , sd - > exten , skinny_extensionstate_cb , sd ) ;
}
for ( l = d - > lines ; l ; l = l - > next ) {
ast_device_state_changed ( " Skinny/%s@%s " , l - > name , d - > name ) ;
}
2006-10-09 16:15:16 +00:00
break ;
}
}
ast_mutex_unlock ( & devicelock ) ;
if ( ! d ) {
return 0 ;
}
return 1 ;
}
static int skinny_unregister ( struct skinny_req * req , struct skinnysession * s )
{
struct skinny_device * d ;
2007-02-24 02:23:43 +00:00
struct skinny_line * l ;
struct skinny_speeddial * sd ;
2006-10-09 16:15:16 +00:00
d = s - > device ;
if ( d ) {
d - > session = NULL ;
d - > registered = 0 ;
2007-02-24 02:23:43 +00:00
for ( sd = d - > speeddials ; sd ; sd = sd - > next ) {
if ( sd - > stateid > - 1 )
ast_extension_state_del ( sd - > stateid , NULL ) ;
}
for ( l = d - > lines ; l ; l = l - > next ) {
ast_device_state_changed ( " Skinny/%s@%s " , l - > name , d - > name ) ;
}
2006-10-09 16:15:16 +00:00
}
return - 1 ; /* main loop will destroy the session */
}
2006-09-17 21:58:04 +00:00
static int transmit_response ( struct skinnysession * s , struct skinny_req * req )
2003-09-11 19:44:48 +00:00
{
int res = 0 ;
2007-03-06 18:02:35 +00:00
if ( ! s ) {
ast_log ( LOG_WARNING , " Asked to transmit to a non-existant session! \n " ) ;
return - 1 ;
}
2003-09-11 19:44:48 +00:00
ast_mutex_lock ( & s - > lock ) ;
2006-03-22 20:45:00 +00:00
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
2006-12-22 20:43:38 +00:00
ast_log ( LOG_VERBOSE , " writing packet type %04X (%d bytes) to socket %d \n " , letohl ( req - > e ) , letohl ( req - > len ) + 8 , s - > fd ) ;
2006-12-22 21:40:56 +00:00
if ( letohl ( req - > len > SKINNY_MAX_PACKET ) | | letohl ( req - > len < 0 ) ) {
2006-12-22 20:43:38 +00:00
ast_log ( LOG_WARNING , " transmit_response: the length of the request is out of bounds \n " ) ;
return - 1 ;
}
2005-06-02 09:11:46 +00:00
2006-06-18 22:36:39 +00:00
memset ( s - > outbuf , 0 , sizeof ( s - > outbuf ) ) ;
memcpy ( s - > outbuf , req , skinny_header_size ) ;
2006-12-22 20:43:38 +00:00
memcpy ( s - > outbuf + skinny_header_size , & req - > data , letohl ( req - > len ) ) ;
2006-06-18 22:36:39 +00:00
res = write ( s - > fd , s - > outbuf , letohl ( req - > len ) + 8 ) ;
2006-10-09 16:15:16 +00:00
2005-06-02 09:11:46 +00:00
if ( res ! = letohl ( req - > len ) + 8 ) {
ast_log ( LOG_WARNING , " Transmit: write only sent %d out of %d bytes: %s \n " , res , letohl ( req - > len ) + 8 , strerror ( errno ) ) ;
2006-10-09 16:15:16 +00:00
if ( res = = - 1 ) {
if ( skinnydebug )
ast_log ( LOG_WARNING , " Transmit: Skinny Client was lost, unregistering \n " ) ;
skinny_unregister ( NULL , s ) ;
}
2003-09-11 19:44:48 +00:00
}
2006-10-09 16:15:16 +00:00
2003-09-11 19:44:48 +00:00
ast_mutex_unlock ( & s - > lock ) ;
return 1 ;
}
static void transmit_speaker_mode ( struct skinnysession * s , int mode )
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct set_speaker_message ) , SET_SPEAKER_MESSAGE ) ) )
2003-09-11 19:44:48 +00:00
return ;
2006-06-18 22:36:39 +00:00
2006-03-22 20:45:00 +00:00
req - > data . setspeaker . mode = htolel ( mode ) ;
2003-09-11 19:44:48 +00:00
transmit_response ( s , req ) ;
}
2006-06-18 22:36:39 +00:00
/*
static void transmit_microphone_mode ( struct skinnysession * s , int mode )
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct set_microphone_message ) , SET_MICROPHONE_MESSAGE ) ) )
return ;
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
req - > data . setmicrophone . mode = htolel ( mode ) ;
transmit_response ( s , req ) ;
}
*/
2003-09-11 19:44:48 +00:00
static void transmit_callstate ( struct skinnysession * s , int instance , int state , unsigned callid )
2006-03-22 20:45:00 +00:00
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct call_state_message ) , CALL_STATE_MESSAGE ) ) )
2003-09-11 19:44:48 +00:00
return ;
2006-06-18 22:36:39 +00:00
2003-09-11 19:44:48 +00:00
if ( state = = SKINNY_ONHOOK ) {
transmit_speaker_mode ( s , SKINNY_SPEAKEROFF ) ;
}
2005-06-02 09:11:46 +00:00
req - > data . callstate . callState = htolel ( state ) ;
req - > data . callstate . lineInstance = htolel ( instance ) ;
req - > data . callstate . callReference = htolel ( callid ) ;
2003-09-11 19:44:48 +00:00
transmit_response ( s , req ) ;
if ( state = = SKINNY_OFFHOOK ) {
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct activate_call_plane_message ) , ACTIVATE_CALL_PLANE_MESSAGE ) ) )
return ;
2005-06-02 09:11:46 +00:00
req - > data . activatecallplane . lineInstance = htolel ( instance ) ;
2003-09-11 19:44:48 +00:00
transmit_response ( s , req ) ;
} else if ( state = = SKINNY_ONHOOK ) {
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct activate_call_plane_message ) , ACTIVATE_CALL_PLANE_MESSAGE ) ) )
return ;
req - > data . activatecallplane . lineInstance = htolel ( instance ) ;
2003-09-11 19:44:48 +00:00
transmit_response ( s , req ) ;
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct close_receive_channel_message ) , CLOSE_RECEIVE_CHANNEL_MESSAGE ) ) )
return ;
2006-04-17 01:17:03 +00:00
req - > data . closereceivechannel . conferenceId = 0 ;
2006-06-18 22:36:39 +00:00
req - > data . closereceivechannel . partyId = htolel ( callid ) ;
2003-09-11 19:44:48 +00:00
transmit_response ( s , req ) ;
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct stop_media_transmission_message ) , STOP_MEDIA_TRANSMISSION_MESSAGE ) ) )
return ;
2006-03-21 15:12:41 +00:00
req - > data . stopmedia . conferenceId = 0 ;
2006-06-18 22:36:39 +00:00
req - > data . stopmedia . passThruPartyId = htolel ( callid ) ;
2006-03-22 20:45:00 +00:00
transmit_response ( s , req ) ;
2003-09-11 19:44:48 +00:00
}
2006-03-22 20:45:00 +00:00
}
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
static void transmit_callinfo ( struct skinnysession * s , const char * fromname , const char * fromnum , const char * toname , const char * tonum , int instance , int callid , int calltype )
2005-06-02 09:11:46 +00:00
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2005-06-02 09:11:46 +00:00
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct call_info_message ) , CALL_INFO_MESSAGE ) ) )
2005-06-02 09:11:46 +00:00
return ;
2007-02-17 17:11:07 +00:00
if ( skinnydebug )
ast_verbose ( " Setting Callinfo to %s(%s) from %s(%s) on %s(%d) \n " , fromname , fromnum , toname , tonum , s - > device - > name , instance ) ;
2005-11-16 21:07:52 +00:00
if ( fromname ) {
2005-06-21 23:06:44 +00:00
ast_copy_string ( req - > data . callinfo . callingPartyName , fromname , sizeof ( req - > data . callinfo . callingPartyName ) ) ;
2005-11-16 21:07:52 +00:00
}
if ( fromnum ) {
2005-06-21 23:06:44 +00:00
ast_copy_string ( req - > data . callinfo . callingParty , fromnum , sizeof ( req - > data . callinfo . callingParty ) ) ;
2005-11-16 21:07:52 +00:00
}
if ( toname ) {
2005-06-21 23:06:44 +00:00
ast_copy_string ( req - > data . callinfo . calledPartyName , toname , sizeof ( req - > data . callinfo . calledPartyName ) ) ;
2005-11-16 21:07:52 +00:00
}
if ( tonum ) {
2005-06-21 23:06:44 +00:00
ast_copy_string ( req - > data . callinfo . calledParty , tonum , sizeof ( req - > data . callinfo . calledParty ) ) ;
2005-11-16 21:07:52 +00:00
}
2005-06-02 09:11:46 +00:00
req - > data . callinfo . instance = htolel ( instance ) ;
req - > data . callinfo . reference = htolel ( callid ) ;
req - > data . callinfo . type = htolel ( calltype ) ;
transmit_response ( s , req ) ;
}
2006-06-18 22:36:39 +00:00
static void transmit_connect ( struct skinnysession * s , struct skinny_subchannel * sub )
2003-09-11 19:44:48 +00:00
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2006-06-18 22:36:39 +00:00
struct skinny_line * l = sub - > parent ;
Merged revisions 43650 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r43650 | qwell | 2006-09-26 08:33:47 -0700 (Tue, 26 Sep 2006) | 11 lines
Add proper codec support to chan_skinny. Works with at least ulaw, alaw, and g729a.
This is technically a "new feature", but there are justifications for it.
I found a bug with the recent rtp packetization changes, which caused the media setup to
fail under certain circumstances, particularly when using allow=all, or having no allow=
statements (globally or on the device).
I could have either removed the rtp packetization features, or I could add proper codec
support (which, without, I think most people would consider to be a bug anyways).
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43651 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-09-26 15:35:37 +00:00
struct ast_format_list fmt ;
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct open_receive_channel_message ) , OPEN_RECEIVE_CHANNEL_MESSAGE ) ) )
2003-09-11 19:44:48 +00:00
return ;
2006-06-18 22:36:39 +00:00
Merged revisions 43650 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r43650 | qwell | 2006-09-26 08:33:47 -0700 (Tue, 26 Sep 2006) | 11 lines
Add proper codec support to chan_skinny. Works with at least ulaw, alaw, and g729a.
This is technically a "new feature", but there are justifications for it.
I found a bug with the recent rtp packetization changes, which caused the media setup to
fail under certain circumstances, particularly when using allow=all, or having no allow=
statements (globally or on the device).
I could have either removed the rtp packetization features, or I could add proper codec
support (which, without, I think most people would consider to be a bug anyways).
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43651 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-09-26 15:35:37 +00:00
fmt = ast_codec_pref_getsize ( & l - > prefs , ast_best_codec ( l - > capability ) ) ;
2006-09-17 23:04:48 +00:00
req - > data . openreceivechannel . conferenceId = htolel ( 0 ) ;
2006-06-18 22:36:39 +00:00
req - > data . openreceivechannel . partyId = htolel ( sub - > callid ) ;
Merged revisions 43650 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r43650 | qwell | 2006-09-26 08:33:47 -0700 (Tue, 26 Sep 2006) | 11 lines
Add proper codec support to chan_skinny. Works with at least ulaw, alaw, and g729a.
This is technically a "new feature", but there are justifications for it.
I found a bug with the recent rtp packetization changes, which caused the media setup to
fail under certain circumstances, particularly when using allow=all, or having no allow=
statements (globally or on the device).
I could have either removed the rtp packetization features, or I could add proper codec
support (which, without, I think most people would consider to be a bug anyways).
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43651 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-09-26 15:35:37 +00:00
req - > data . openreceivechannel . packets = htolel ( fmt . cur_ms ) ;
req - > data . openreceivechannel . capability = htolel ( codec_ast2skinny ( fmt . bits ) ) ;
2006-09-17 23:04:48 +00:00
req - > data . openreceivechannel . echo = htolel ( 0 ) ;
req - > data . openreceivechannel . bitrate = htolel ( 0 ) ;
2003-09-11 19:44:48 +00:00
transmit_response ( s , req ) ;
2006-03-22 20:45:00 +00:00
}
2003-09-11 19:44:48 +00:00
static void transmit_tone ( struct skinnysession * s , int tone )
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
if ( tone = = SKINNY_NOTONE ) {
/* This is bad, mmm'kay? */
return ;
}
2005-11-16 21:07:52 +00:00
if ( tone > 0 ) {
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct start_tone_message ) , START_TONE_MESSAGE ) ) )
return ;
2005-11-16 21:07:52 +00:00
} else {
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( 0 , STOP_TONE_MESSAGE ) ) )
return ;
2006-03-22 20:45:00 +00:00
}
2006-06-18 22:36:39 +00:00
2003-09-11 19:44:48 +00:00
if ( tone > 0 ) {
2006-03-22 20:45:00 +00:00
req - > data . starttone . tone = htolel ( tone ) ;
2003-09-11 19:44:48 +00:00
}
transmit_response ( s , req ) ;
}
static void transmit_selectsoftkeys ( struct skinnysession * s , int instance , int callid , int softkey )
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct select_soft_keys_message ) , SELECT_SOFT_KEYS_MESSAGE ) ) )
2003-09-11 19:44:48 +00:00
return ;
2006-06-18 22:36:39 +00:00
2005-06-02 09:11:46 +00:00
req - > data . selectsoftkey . instance = htolel ( instance ) ;
req - > data . selectsoftkey . reference = htolel ( callid ) ;
req - > data . selectsoftkey . softKeySetIndex = htolel ( softkey ) ;
2006-06-18 22:36:39 +00:00
req - > data . selectsoftkey . validKeyMask = htolel ( 0xFFFFFFFF ) ;
2003-09-11 19:44:48 +00:00
transmit_response ( s , req ) ;
}
2005-02-25 17:43:10 +00:00
static void transmit_lamp_indication ( struct skinnysession * s , int stimulus , int instance , int indication )
2003-09-11 19:44:48 +00:00
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct set_lamp_message ) , SET_LAMP_MESSAGE ) ) )
2003-09-11 19:44:48 +00:00
return ;
2006-06-18 22:36:39 +00:00
2005-06-02 09:11:46 +00:00
req - > data . setlamp . stimulus = htolel ( stimulus ) ;
req - > data . setlamp . stimulusInstance = htolel ( instance ) ;
req - > data . setlamp . deviceStimulus = htolel ( indication ) ;
2003-09-11 19:44:48 +00:00
transmit_response ( s , req ) ;
}
static void transmit_ringer_mode ( struct skinnysession * s , int mode )
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
ast_verbose ( " Setting ringer mode to '%d'. \n " , mode ) ;
if ( ! ( req = req_alloc ( sizeof ( struct set_ringer_message ) , SET_RINGER_MESSAGE ) ) )
2003-09-11 19:44:48 +00:00
return ;
2006-06-18 22:36:39 +00:00
2006-03-22 20:45:00 +00:00
req - > data . setringer . ringerMode = htolel ( mode ) ;
2006-06-18 22:36:39 +00:00
/* XXX okay, I don't quite know what this is, but here's what happens (on a 7960).
Note : The phone will always show as ringing on the display .
1 : phone will audibly ring over and over
2 : phone will audibly ring only once
any other value , will NOT cause the phone to audibly ring
*/
req - > data . setringer . unknown1 = htolel ( 1 ) ;
/* XXX the value here doesn't seem to change anything. Must be higher than 0.
Perhaps a packet capture can shed some light on this . */
req - > data . setringer . unknown2 = htolel ( 1 ) ;
2003-09-11 19:44:48 +00:00
transmit_response ( s , req ) ;
}
2006-06-18 22:36:39 +00:00
static void transmit_displaymessage ( struct skinnysession * s , const char * text )
2005-01-25 03:41:05 +00:00
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2005-01-25 03:41:05 +00:00
if ( text = = 0 ) {
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( 0 , CLEAR_DISPLAY_MESSAGE ) ) )
return ;
if ( skinnydebug )
ast_verbose ( " Clearing Display \n " ) ;
2005-01-25 03:41:05 +00:00
} else {
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct displaytext_message ) , DISPLAYTEXT_MESSAGE ) ) )
return ;
2005-01-25 03:41:05 +00:00
2006-06-18 22:36:39 +00:00
ast_copy_string ( req - > data . displaytext . text , text , sizeof ( req - > data . displaytext . text ) ) ;
if ( skinnydebug )
ast_verbose ( " Displaying message '%s' \n " , req - > data . displaytext . text ) ;
2005-01-25 03:41:05 +00:00
}
2006-06-18 22:36:39 +00:00
2005-01-25 03:41:05 +00:00
transmit_response ( s , req ) ;
}
2006-06-18 22:36:39 +00:00
static void transmit_displaynotify ( struct skinnysession * s , const char * text , int t )
2005-06-02 09:11:46 +00:00
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2005-06-02 09:11:46 +00:00
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct display_notify_message ) , DISPLAY_NOTIFY_MESSAGE ) ) )
2006-03-21 15:12:41 +00:00
return ;
2005-06-02 09:11:46 +00:00
2006-04-21 18:08:57 +00:00
ast_copy_string ( req - > data . displaynotify . displayMessage , text , sizeof ( req - > data . displaynotify . displayMessage ) ) ;
2005-06-02 09:11:46 +00:00
req - > data . displaynotify . displayTimeout = htolel ( t ) ;
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
2005-06-02 09:11:46 +00:00
ast_verbose ( " Displaying notify '%s' \n " , text ) ;
2006-03-22 20:45:00 +00:00
2005-06-02 09:11:46 +00:00
transmit_response ( s , req ) ;
}
2006-06-18 22:36:39 +00:00
static void transmit_displaypromptstatus ( struct skinnysession * s , const char * text , int t , int instance , int callid )
2005-06-02 09:11:46 +00:00
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2005-06-02 09:11:46 +00:00
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct display_prompt_status_message ) , DISPLAY_PROMPT_STATUS_MESSAGE ) ) )
2006-03-21 15:12:41 +00:00
return ;
2005-06-02 09:11:46 +00:00
2006-04-21 18:08:57 +00:00
ast_copy_string ( req - > data . displaypromptstatus . promptMessage , text , sizeof ( req - > data . displaypromptstatus . promptMessage ) ) ;
2005-06-02 09:11:46 +00:00
req - > data . displaypromptstatus . messageTimeout = htolel ( t ) ;
req - > data . displaypromptstatus . lineInstance = htolel ( instance ) ;
req - > data . displaypromptstatus . callReference = htolel ( callid ) ;
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
2005-06-02 09:11:46 +00:00
ast_verbose ( " Displaying Prompt Status '%s' \n " , text ) ;
transmit_response ( s , req ) ;
}
2006-06-18 22:36:39 +00:00
static void transmit_dialednumber ( struct skinnysession * s , const char * text , int instance , int callid )
2005-06-02 09:11:46 +00:00
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2005-06-02 09:11:46 +00:00
2006-06-18 22:36:39 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct dialed_number_message ) , DIALED_NUMBER_MESSAGE ) ) )
2006-03-21 15:12:41 +00:00
return ;
2005-06-02 09:11:46 +00:00
2006-04-21 18:08:57 +00:00
ast_copy_string ( req - > data . dialednumber . dialedNumber , text , sizeof ( req - > data . dialednumber . dialedNumber ) ) ;
2006-03-21 15:12:41 +00:00
req - > data . dialednumber . lineInstance = htolel ( instance ) ;
req - > data . dialednumber . callReference = htolel ( callid ) ;
2005-06-02 09:11:46 +00:00
transmit_response ( s , req ) ;
}
2007-02-24 02:23:43 +00:00
static int skinny_extensionstate_cb ( char * context , char * exten , int state , void * data )
{
struct skinny_speeddial * sd = data ;
struct skinny_device * d = sd - > parent ;
struct skinnysession * s = d - > session ;
char hint [ AST_MAX_EXTENSION ] ;
int callstate = SKINNY_CALLREMOTEMULTILINE ;
int lamp = SKINNY_LAMP_OFF ;
switch ( state ) {
case AST_EXTENSION_DEACTIVATED : /* Retry after a while */
case AST_EXTENSION_REMOVED : /* Extension is gone */
ast_verbose ( VERBOSE_PREFIX_2 " Extension state: Watcher for hint %s %s. Notify Device %s \n " , exten , state = = AST_EXTENSION_DEACTIVATED ? " deactivated " : " removed " , d - > name ) ;
sd - > stateid = - 1 ;
callstate = SKINNY_ONHOOK ;
lamp = SKINNY_LAMP_OFF ;
break ;
case AST_EXTENSION_RINGING :
case AST_EXTENSION_UNAVAILABLE :
callstate = SKINNY_RINGIN ;
lamp = SKINNY_LAMP_BLINK ;
break ;
case AST_EXTENSION_BUSY : /* callstate = SKINNY_BUSY wasn't wanting to work - I'll settle for this */
case AST_EXTENSION_INUSE :
callstate = SKINNY_CALLREMOTEMULTILINE ;
lamp = SKINNY_LAMP_ON ;
break ;
case AST_EXTENSION_ONHOLD :
callstate = SKINNY_HOLD ;
lamp = SKINNY_LAMP_WINK ;
break ;
case AST_EXTENSION_NOT_INUSE :
default :
callstate = SKINNY_ONHOOK ;
lamp = SKINNY_LAMP_OFF ;
break ;
}
if ( ast_get_hint ( hint , sizeof ( hint ) , NULL , 0 , NULL , sd - > context , sd - > exten ) ) {
/* If they are not registered, we will override notification and show no availability */
if ( ast_device_state ( hint ) = = AST_DEVICE_UNAVAILABLE ) {
callstate = SKINNY_ONHOOK ;
lamp = SKINNY_LAMP_FLASH ;
}
}
transmit_lamp_indication ( s , STIMULUS_LINE , sd - > instance , lamp ) ;
transmit_callstate ( s , sd - > instance , callstate , 0 ) ;
sd - > laststate = state ;
return 0 ;
}
2005-02-25 17:43:10 +00:00
static int has_voicemail ( struct skinny_line * l )
{
return ast_app_has_voicemail ( l - > mailbox , NULL ) ;
}
static void do_housekeeping ( struct skinnysession * s )
{
2005-11-16 21:07:52 +00:00
int new ;
int old ;
2007-05-11 22:52:36 +00:00
int device_lamp = 0 ;
2006-06-18 22:36:39 +00:00
struct skinny_device * d = s - > device ;
struct skinny_line * l ;
2005-02-25 17:43:10 +00:00
2005-06-02 09:11:46 +00:00
transmit_displaymessage ( s , NULL ) ;
2005-02-25 17:43:10 +00:00
2007-05-11 22:52:36 +00:00
/* Set MWI on individual lines */
2006-06-18 22:36:39 +00:00
for ( l = d - > lines ; l ; l = l - > next ) {
if ( has_voicemail ( l ) ) {
if ( skinnydebug )
ast_verbose ( " Checking for voicemail Skinny %s@%s \n " , l - > name , d - > name ) ;
ast_app_inboxcount ( l - > mailbox , & new , & old ) ;
if ( skinnydebug )
ast_verbose ( " Skinny %s@%s has voicemail! \n " , l - > name , d - > name ) ;
transmit_lamp_indication ( s , STIMULUS_VOICEMAIL , l - > instance , l - > mwiblink ? SKINNY_LAMP_BLINK : SKINNY_LAMP_ON ) ;
2007-05-11 22:52:36 +00:00
device_lamp + + ;
2006-06-18 22:36:39 +00:00
} else {
transmit_lamp_indication ( s , STIMULUS_VOICEMAIL , l - > instance , SKINNY_LAMP_OFF ) ;
2005-02-25 17:43:10 +00:00
}
}
2007-05-11 22:52:36 +00:00
/* If at least one line has VM, turn the device level lamp on */
if ( device_lamp )
transmit_lamp_indication ( s , STIMULUS_VOICEMAIL , 0 , SKINNY_LAMP_ON ) ;
else
transmit_lamp_indication ( s , STIMULUS_VOICEMAIL , 0 , SKINNY_LAMP_OFF ) ;
2005-02-25 17:43:10 +00:00
}
2006-03-22 20:45:00 +00:00
/* I do not believe skinny can deal with video.
2003-09-11 19:44:48 +00:00
Anyone know differently ? */
2006-06-18 22:36:39 +00:00
/* Yes, it can. Currently 7985 and Cisco VT Advantage do video. */
2006-08-28 17:37:56 +00:00
static enum ast_rtp_get_result skinny_get_vrtp_peer ( struct ast_channel * c , struct ast_rtp * * rtp )
2003-09-11 19:44:48 +00:00
{
2006-08-28 17:37:56 +00:00
struct skinny_subchannel * sub = NULL ;
if ( ! ( sub = c - > tech_pvt ) | | ! ( sub - > vrtp ) )
return AST_RTP_GET_FAILED ;
* rtp = sub - > vrtp ;
return AST_RTP_TRY_NATIVE ;
2003-09-11 19:44:48 +00:00
}
2006-08-28 17:37:56 +00:00
static enum ast_rtp_get_result skinny_get_rtp_peer ( struct ast_channel * c , struct ast_rtp * * rtp )
2003-09-11 19:44:48 +00:00
{
2006-08-28 17:37:56 +00:00
struct skinny_subchannel * sub = NULL ;
if ( ! ( sub = c - > tech_pvt ) | | ! ( sub - > rtp ) )
return AST_RTP_GET_FAILED ;
* rtp = sub - > rtp ;
return AST_RTP_TRY_NATIVE ;
2003-09-11 19:44:48 +00:00
}
2007-02-16 13:35:44 +00:00
static int skinny_set_rtp_peer ( struct ast_channel * c , struct ast_rtp * rtp , struct ast_rtp * vrtp , struct ast_rtp * trtp , int codecs , int nat_active )
2003-09-11 19:44:48 +00:00
{
struct skinny_subchannel * sub ;
2006-07-14 20:14:38 +00:00
sub = c - > tech_pvt ;
2003-09-11 19:44:48 +00:00
if ( sub ) {
/* transmit_modify_with_sdp(sub, rtp); @@FIXME@@ if needed */
return 0 ;
}
return - 1 ;
}
static struct ast_rtp_protocol skinny_rtp = {
2006-02-01 23:05:28 +00:00
. type = " Skinny " ,
2005-03-04 06:47:24 +00:00
. get_rtp_info = skinny_get_rtp_peer ,
2006-03-21 15:12:41 +00:00
. get_vrtp_info = skinny_get_vrtp_peer ,
2005-03-04 06:47:24 +00:00
. set_rtp_peer = skinny_set_rtp_peer ,
2003-09-11 19:44:48 +00:00
} ;
static int skinny_do_debug ( int fd , int argc , char * argv [ ] )
{
2006-11-02 23:16:09 +00:00
if ( argc ! = 3 ) {
2003-09-11 19:44:48 +00:00
return RESULT_SHOWUSAGE ;
2005-11-16 21:07:52 +00:00
}
2003-09-11 19:44:48 +00:00
skinnydebug = 1 ;
ast_cli ( fd , " Skinny Debugging Enabled \n " ) ;
return RESULT_SUCCESS ;
}
2006-09-18 19:54:18 +00:00
static int skinny_no_debug ( int fd , int argc , char * argv [ ] )
{
2006-11-10 17:01:06 +00:00
if ( argc ! = 4 ) {
2006-09-18 19:54:18 +00:00
return RESULT_SHOWUSAGE ;
}
skinnydebug = 0 ;
ast_cli ( fd , " Skinny Debugging Disabled \n " ) ;
return RESULT_SUCCESS ;
}
2006-06-18 22:36:39 +00:00
static char * complete_skinny_reset ( const char * line , const char * word , int pos , int state )
2003-09-11 19:44:48 +00:00
{
2006-03-21 15:12:41 +00:00
struct skinny_device * d ;
2005-06-02 09:11:46 +00:00
2006-06-18 22:36:39 +00:00
char * result = NULL ;
int wordlen = strlen ( word ) ;
int which = 0 ;
if ( pos = = 2 ) {
for ( d = devices ; d & & ! result ; d = d - > next ) {
if ( ! strncasecmp ( word , d - > id , wordlen ) & & + + which > state )
result = ast_strdup ( d - > id ) ;
}
}
return result ;
}
static int skinny_reset_device ( int fd , int argc , char * argv [ ] )
{
struct skinny_device * d ;
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2006-06-18 22:36:39 +00:00
if ( argc < 3 | | argc > 4 ) {
2005-06-02 09:11:46 +00:00
return RESULT_SHOWUSAGE ;
2005-11-16 21:07:52 +00:00
}
2005-06-02 09:11:46 +00:00
ast_mutex_lock ( & devicelock ) ;
2006-06-18 22:36:39 +00:00
for ( d = devices ; d ; d = d - > next ) {
int fullrestart = 0 ;
if ( ! strcasecmp ( argv [ 2 ] , d - > id ) | | ! strcasecmp ( argv [ 2 ] , " all " ) ) {
if ( ! ( d - > session ) )
continue ;
if ( ! ( req = req_alloc ( sizeof ( struct reset_message ) , RESET_MESSAGE ) ) )
continue ;
if ( argc = = 4 & & ! strcasecmp ( argv [ 3 ] , " restart " ) )
fullrestart = 1 ;
if ( fullrestart )
req - > data . reset . resetType = 2 ;
else
req - > data . reset . resetType = 1 ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " %s device %s. \n " , ( fullrestart ) ? " Restarting " : " Resetting " , d - > id ) ;
transmit_response ( d - > session , req ) ;
}
}
ast_mutex_unlock ( & devicelock ) ;
return RESULT_SUCCESS ;
}
2006-08-20 01:25:02 +00:00
static char * device2str ( int type )
{
2006-08-20 18:03:24 +00:00
char * tmp ;
2006-08-20 01:25:02 +00:00
switch ( type ) {
case SKINNY_DEVICE_NONE :
return " No Device " ;
case SKINNY_DEVICE_30SPPLUS :
return " 30SP Plus " ;
case SKINNY_DEVICE_12SPPLUS :
return " 12SP Plus " ;
case SKINNY_DEVICE_12SP :
return " 12SP " ;
case SKINNY_DEVICE_12 :
return " 12 " ;
case SKINNY_DEVICE_30VIP :
return " 30VIP " ;
case SKINNY_DEVICE_7910 :
return " 7910 " ;
case SKINNY_DEVICE_7960 :
return " 7960 " ;
case SKINNY_DEVICE_7940 :
return " 7940 " ;
case SKINNY_DEVICE_7935 :
return " 7935 " ;
case SKINNY_DEVICE_ATA186 :
return " ATA186 " ;
case SKINNY_DEVICE_7941 :
return " 7941 " ;
case SKINNY_DEVICE_7971 :
return " 7971 " ;
case SKINNY_DEVICE_7985 :
return " 7985 " ;
case SKINNY_DEVICE_7911 :
return " 7911 " ;
case SKINNY_DEVICE_7961GE :
return " 7961GE " ;
case SKINNY_DEVICE_7941GE :
return " 7941GE " ;
case SKINNY_DEVICE_7905 :
return " 7905 " ;
case SKINNY_DEVICE_7920 :
return " 7920 " ;
case SKINNY_DEVICE_7970 :
return " 7970 " ;
case SKINNY_DEVICE_7912 :
return " 7912 " ;
case SKINNY_DEVICE_7902 :
return " 7902 " ;
case SKINNY_DEVICE_CIPC :
2006-08-20 01:27:24 +00:00
return " IP Communicator " ;
2006-08-20 01:25:02 +00:00
case SKINNY_DEVICE_7961 :
return " 7961 " ;
case SKINNY_DEVICE_7936 :
return " 7936 " ;
case SKINNY_DEVICE_SCCPGATEWAY_AN :
return " SCCPGATEWAY_AN " ;
case SKINNY_DEVICE_SCCPGATEWAY_BRI :
return " SCCPGATEWAY_BRI " ;
case SKINNY_DEVICE_UNKNOWN :
return " Unknown " ;
default :
2006-08-20 04:39:57 +00:00
if ( ! ( tmp = ast_threadstorage_get ( & device2str_threadbuf , DEVICE2STR_BUFSIZE ) ) )
return " Unknown " ;
snprintf ( tmp , DEVICE2STR_BUFSIZE , " UNKNOWN-%d " , type ) ;
2006-08-20 01:25:02 +00:00
return tmp ;
}
}
2006-06-18 22:36:39 +00:00
static int skinny_show_devices ( int fd , int argc , char * argv [ ] )
{
struct skinny_device * d ;
struct skinny_line * l ;
int numlines = 0 ;
if ( argc ! = 3 ) {
return RESULT_SHOWUSAGE ;
}
ast_mutex_lock ( & devicelock ) ;
2006-08-20 01:25:02 +00:00
ast_cli ( fd , " Name DeviceId IP Type R NL \n " ) ;
ast_cli ( fd , " -------------------- ---------------- --------------- --------------- - -- \n " ) ;
2006-06-18 22:36:39 +00:00
for ( d = devices ; d ; d = d - > next ) {
2005-06-02 09:11:46 +00:00
numlines = 0 ;
2006-06-18 22:36:39 +00:00
for ( l = d - > lines ; l ; l = l - > next ) {
numlines + + ;
}
2005-06-02 09:11:46 +00:00
2006-08-20 01:25:02 +00:00
ast_cli ( fd , " %-20s %-16s %-15s %-15s %c %2d \n " ,
2006-03-22 20:45:00 +00:00
d - > name ,
d - > id ,
2006-08-20 01:25:02 +00:00
d - > session ? ast_inet_ntoa ( d - > session - > sin . sin_addr ) : " " ,
device2str ( d - > type ) ,
2006-03-22 20:45:00 +00:00
d - > registered ? ' Y ' : ' N ' ,
2005-06-02 09:11:46 +00:00
numlines ) ;
}
ast_mutex_unlock ( & devicelock ) ;
return RESULT_SUCCESS ;
}
static int skinny_show_lines ( int fd , int argc , char * argv [ ] )
{
2006-03-21 15:12:41 +00:00
struct skinny_device * d ;
2005-06-02 09:11:46 +00:00
struct skinny_line * l ;
2005-11-16 21:07:52 +00:00
if ( argc ! = 3 ) {
2003-09-11 19:44:48 +00:00
return RESULT_SHOWUSAGE ;
2005-11-16 21:07:52 +00:00
}
2003-09-11 19:44:48 +00:00
ast_mutex_lock ( & devicelock ) ;
2006-06-18 22:36:39 +00:00
ast_cli ( fd , " Device Name Instance Name Label \n " ) ;
ast_cli ( fd , " -------------------- -------- -------------------- -------------------- \n " ) ;
for ( d = devices ; d ; d = d - > next ) {
for ( l = d - > lines ; l ; l = l - > next ) {
ast_cli ( fd , " %-20s %8d %-20s %-20s \n " ,
d - > name ,
2005-06-02 09:11:46 +00:00
l - > instance ,
l - > name ,
2006-06-18 22:36:39 +00:00
l - > label ) ;
2003-09-11 19:44:48 +00:00
}
}
2006-06-18 22:36:39 +00:00
2003-09-11 19:44:48 +00:00
ast_mutex_unlock ( & devicelock ) ;
return RESULT_SUCCESS ;
}
2006-12-06 07:35:31 +00:00
static const char show_devices_usage [ ] =
2006-11-02 23:16:09 +00:00
" Usage: skinny show devices \n "
2005-06-02 09:11:46 +00:00
" Lists all devices known to the Skinny subsystem. \n " ;
2006-12-06 07:35:31 +00:00
static const char show_lines_usage [ ] =
2006-11-02 23:16:09 +00:00
" Usage: skinny show lines \n "
2003-09-11 19:44:48 +00:00
" Lists all lines known to the Skinny subsystem. \n " ;
2006-12-06 07:35:31 +00:00
static const char debug_usage [ ] =
2006-11-10 17:01:06 +00:00
" Usage: skinny set debug \n "
2003-09-11 19:44:48 +00:00
" Enables dumping of Skinny packets for debugging purposes \n " ;
2006-12-06 07:35:31 +00:00
static const char no_debug_usage [ ] =
2006-11-10 17:01:06 +00:00
" Usage: skinny set debug off \n "
2003-09-11 19:44:48 +00:00
" Disables dumping of Skinny packets for debugging purposes \n " ;
2006-12-06 07:35:31 +00:00
static const char reset_usage [ ] =
2006-06-18 22:36:39 +00:00
" Usage: skinny reset <DeviceId|all> [restart] \n "
" Causes a Skinny device to reset itself, optionally with a full restart \n " ;
2006-09-18 19:54:18 +00:00
static struct ast_cli_entry cli_skinny [ ] = {
2006-11-02 23:16:09 +00:00
{ { " skinny " , " show " , " devices " , NULL } ,
2006-09-18 19:54:18 +00:00
skinny_show_devices , " List defined Skinny devices " ,
2006-09-21 21:59:12 +00:00
show_devices_usage } ,
2006-09-18 19:54:18 +00:00
2006-11-02 23:16:09 +00:00
{ { " skinny " , " show " , " lines " , NULL } ,
2006-09-18 19:54:18 +00:00
skinny_show_lines , " List defined Skinny lines per device " ,
2006-09-21 21:59:12 +00:00
show_lines_usage } ,
2006-09-18 19:54:18 +00:00
2006-11-10 17:01:06 +00:00
{ { " skinny " , " set " , " debug " , NULL } ,
2006-09-18 19:54:18 +00:00
skinny_do_debug , " Enable Skinny debugging " ,
debug_usage } ,
2006-11-10 17:01:06 +00:00
{ { " skinny " , " set " , " debug " , " off " , NULL } ,
2006-09-18 19:54:18 +00:00
skinny_no_debug , " Disable Skinny debugging " ,
2006-09-21 21:59:12 +00:00
no_debug_usage } ,
2006-09-18 19:54:18 +00:00
{ { " skinny " , " reset " , NULL } ,
skinny_reset_device , " Reset Skinny device(s) " ,
reset_usage , complete_skinny_reset } ,
} ;
2006-06-18 22:36:39 +00:00
2005-06-21 23:06:44 +00:00
#if 0
2006-06-18 22:36:39 +00:00
static struct skinny_paging_device * build_paging_device ( const char * cat , struct ast_variable * v )
2005-06-02 09:11:46 +00:00
{
return NULL ;
}
2005-06-21 23:06:44 +00:00
# endif
2005-06-02 09:11:46 +00:00
2006-06-18 22:36:39 +00:00
static struct skinny_device * build_device ( const char * cat , struct ast_variable * v )
2003-09-11 19:44:48 +00:00
{
struct skinny_device * d ;
struct skinny_line * l ;
2006-06-18 22:36:39 +00:00
struct skinny_speeddial * sd ;
struct skinny_addon * a ;
2007-05-11 22:52:36 +00:00
char device_vmexten [ AST_MAX_EXTENSION ] ;
2006-06-18 22:36:39 +00:00
int lineInstance = 1 ;
int speeddialInstance = 1 ;
int y = 0 ;
2006-03-22 20:45:00 +00:00
2006-06-18 22:36:39 +00:00
if ( ! ( d = ast_calloc ( 1 , sizeof ( struct skinny_device ) ) ) ) {
return NULL ;
} else {
2006-04-21 18:08:57 +00:00
ast_copy_string ( d - > name , cat , sizeof ( d - > name ) ) ;
2006-06-18 22:36:39 +00:00
d - > lastlineinstance = 1 ;
2006-09-18 23:32:57 +00:00
d - > capability = default_capability ;
d - > prefs = default_prefs ;
2007-05-11 22:52:36 +00:00
if ( ! ast_strlen_zero ( vmexten ) )
ast_copy_string ( device_vmexten , vmexten , sizeof ( device_vmexten ) ) ;
2003-09-11 19:44:48 +00:00
while ( v ) {
if ( ! strcasecmp ( v - > name , " host " ) ) {
2005-11-16 21:07:52 +00:00
if ( ast_get_ip ( & d - > addr , v - > value ) ) {
free ( d ) ;
return NULL ;
2006-03-22 20:45:00 +00:00
}
2003-09-11 19:44:48 +00:00
} else if ( ! strcasecmp ( v - > name , " port " ) ) {
d - > addr . sin_port = htons ( atoi ( v - > value ) ) ;
} else if ( ! strcasecmp ( v - > name , " device " ) ) {
2006-06-18 22:36:39 +00:00
ast_copy_string ( d - > id , v - > value , sizeof ( d - > id ) ) ;
2004-01-09 21:12:21 +00:00
} else if ( ! strcasecmp ( v - > name , " permit " ) | | ! strcasecmp ( v - > name , " deny " ) ) {
2007-01-01 19:20:46 +00:00
d - > ha = ast_append_ha ( v - > name , v - > value , d - > ha , NULL ) ;
2007-05-11 22:52:36 +00:00
} else if ( ! strcasecmp ( v - > name , " vmexten " ) ) {
ast_copy_string ( device_vmexten , v - > value , sizeof ( device_vmexten ) ) ;
2003-09-11 19:44:48 +00:00
} else if ( ! strcasecmp ( v - > name , " context " ) ) {
2006-06-18 22:36:39 +00:00
ast_copy_string ( context , v - > value , sizeof ( context ) ) ;
2006-09-18 23:32:57 +00:00
} else if ( ! strcasecmp ( v - > name , " allow " ) ) {
ast_parse_allow_disallow ( & d - > prefs , & d - > capability , v - > value , 1 ) ;
} else if ( ! strcasecmp ( v - > name , " disallow " ) ) {
ast_parse_allow_disallow ( & d - > prefs , & d - > capability , v - > value , 0 ) ;
2004-01-09 21:12:21 +00:00
} else if ( ! strcasecmp ( v - > name , " version " ) ) {
2006-06-18 22:36:39 +00:00
ast_copy_string ( d - > version_id , v - > value , sizeof ( d - > version_id ) ) ;
2003-09-11 19:44:48 +00:00
} else if ( ! strcasecmp ( v - > name , " nat " ) ) {
nat = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " callerid " ) ) {
2004-01-09 21:12:21 +00:00
if ( ! strcasecmp ( v - > value , " asreceived " ) ) {
2004-10-02 00:58:31 +00:00
cid_num [ 0 ] = ' \0 ' ;
cid_name [ 0 ] = ' \0 ' ;
2004-01-09 21:12:21 +00:00
} else {
2004-10-02 00:58:31 +00:00
ast_callerid_split ( v - > value , cid_name , sizeof ( cid_name ) , cid_num , sizeof ( cid_num ) ) ;
2004-01-09 21:12:21 +00:00
}
2003-09-11 19:44:48 +00:00
} else if ( ! strcasecmp ( v - > name , " language " ) ) {
2006-06-18 22:36:39 +00:00
ast_copy_string ( language , v - > value , sizeof ( language ) ) ;
2006-03-21 15:12:41 +00:00
} else if ( ! strcasecmp ( v - > name , " accountcode " ) ) {
2006-06-18 22:36:39 +00:00
ast_copy_string ( accountcode , v - > value , sizeof ( accountcode ) ) ;
2006-03-21 15:12:41 +00:00
} else if ( ! strcasecmp ( v - > name , " amaflags " ) ) {
y = ast_cdr_amaflags2int ( v - > value ) ;
if ( y < 0 ) {
ast_log ( LOG_WARNING , " Invalid AMA flags: %s at line %d \n " , v - > value , v - > lineno ) ;
} else {
amaflags = y ;
}
2006-07-19 20:44:39 +00:00
} else if ( ! strcasecmp ( v - > name , " mohinterpret " ) | | ! strcasecmp ( v - > name , " musiconhold " ) ) {
ast_copy_string ( mohinterpret , v - > value , sizeof ( mohinterpret ) ) ;
2006-09-17 22:24:27 +00:00
} else if ( ! strcasecmp ( v - > name , " mohsuggest " ) ) {
ast_copy_string ( mohsuggest , v - > value , sizeof ( mohsuggest ) ) ;
2006-03-21 15:12:41 +00:00
} else if ( ! strcasecmp ( v - > name , " callgroup " ) ) {
cur_callergroup = ast_get_group ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " pickupgroup " ) ) {
cur_pickupgroup = ast_get_group ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " immediate " ) ) {
immediate = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " cancallforward " ) ) {
cancallforward = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " mailbox " ) ) {
2006-06-18 22:36:39 +00:00
ast_copy_string ( mailbox , v - > value , sizeof ( mailbox ) ) ;
2006-03-21 15:12:41 +00:00
} else if ( ! strcasecmp ( v - > name , " callreturn " ) ) {
2003-09-11 19:44:48 +00:00
callreturn = ast_true ( v - > value ) ;
2006-03-21 15:12:41 +00:00
} else if ( ! strcasecmp ( v - > name , " callwaiting " ) ) {
callwaiting = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " transfer " ) ) {
transfer = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " threewaycalling " ) ) {
threewaycalling = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " mwiblink " ) ) {
mwiblink = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " linelabel " ) ) {
2006-06-18 22:36:39 +00:00
ast_copy_string ( linelabel , v - > value , sizeof ( linelabel ) ) ;
} else if ( ! strcasecmp ( v - > name , " speeddial " ) ) {
if ( ! ( sd = ast_calloc ( 1 , sizeof ( struct skinny_speeddial ) ) ) ) {
return NULL ;
} else {
2007-02-24 02:23:43 +00:00
char * stringp , * exten , * context , * label ;
2006-06-18 22:36:39 +00:00
stringp = v - > value ;
exten = strsep ( & stringp , " , " ) ;
2007-02-24 02:23:43 +00:00
if ( ( context = strchr ( exten , ' @ ' ) ) ) {
* context + + = ' \0 ' ;
}
label = stringp ;
2006-06-18 22:36:39 +00:00
ast_mutex_init ( & sd - > lock ) ;
ast_copy_string ( sd - > exten , exten , sizeof ( sd - > exten ) ) ;
2007-02-24 02:23:43 +00:00
if ( ! ast_strlen_zero ( context ) ) {
sd - > isHint = 1 ;
sd - > instance = lineInstance + + ;
ast_copy_string ( sd - > context , context , sizeof ( sd - > context ) ) ;
} else {
sd - > isHint = 0 ;
sd - > instance = speeddialInstance + + ;
sd - > context [ 0 ] = ' \0 ' ;
}
ast_copy_string ( sd - > label , S_OR ( label , exten ) , sizeof ( sd - > label ) ) ;
2006-06-18 22:36:39 +00:00
2007-02-24 02:04:34 +00:00
sd - > parent = d ;
2006-06-18 22:36:39 +00:00
sd - > next = d - > speeddials ;
d - > speeddials = sd ;
}
} else if ( ! strcasecmp ( v - > name , " addon " ) ) {
if ( ! ( a = ast_calloc ( 1 , sizeof ( struct skinny_addon ) ) ) ) {
return NULL ;
} else {
ast_mutex_init ( & a - > lock ) ;
ast_copy_string ( a - > type , v - > value , sizeof ( a - > type ) ) ;
a - > next = d - > addons ;
d - > addons = a ;
}
2006-03-21 15:12:41 +00:00
} else if ( ! strcasecmp ( v - > name , " trunk " ) | | ! strcasecmp ( v - > name , " line " ) ) {
2006-06-18 22:36:39 +00:00
if ( ! ( l = ast_calloc ( 1 , sizeof ( struct skinny_line ) ) ) ) {
return NULL ;
} else {
2006-03-21 15:12:41 +00:00
ast_mutex_init ( & l - > lock ) ;
2006-06-18 22:36:39 +00:00
ast_copy_string ( l - > name , v - > value , sizeof ( l - > name ) ) ;
2006-03-22 20:45:00 +00:00
2003-09-11 19:44:48 +00:00
/* XXX Should we check for uniqueness?? XXX */
2006-06-18 22:36:39 +00:00
ast_copy_string ( l - > context , context , sizeof ( l - > context ) ) ;
ast_copy_string ( l - > cid_num , cid_num , sizeof ( l - > cid_num ) ) ;
ast_copy_string ( l - > cid_name , cid_name , sizeof ( l - > cid_name ) ) ;
ast_copy_string ( l - > label , linelabel , sizeof ( l - > label ) ) ;
ast_copy_string ( l - > language , language , sizeof ( l - > language ) ) ;
2006-07-19 20:44:39 +00:00
ast_copy_string ( l - > mohinterpret , mohinterpret , sizeof ( l - > mohinterpret ) ) ;
2006-09-17 22:24:27 +00:00
ast_copy_string ( l - > mohsuggest , mohsuggest , sizeof ( l - > mohsuggest ) ) ;
2006-06-18 22:36:39 +00:00
ast_copy_string ( l - > mailbox , mailbox , sizeof ( l - > mailbox ) ) ;
ast_copy_string ( l - > mailbox , mailbox , sizeof ( l - > mailbox ) ) ;
2004-05-05 05:03:48 +00:00
if ( ! ast_strlen_zero ( mailbox ) ) {
2006-04-06 16:50:33 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Setting mailbox '%s' on %s@%s \n " , mailbox , d - > name , l - > name ) ;
2003-09-11 19:44:48 +00:00
}
2007-05-11 22:52:36 +00:00
if ( ! ast_strlen_zero ( device_vmexten ) )
ast_copy_string ( l - > vmexten , device_vmexten , sizeof ( vmexten ) ) ;
2003-09-11 19:44:48 +00:00
l - > msgstate = - 1 ;
2006-09-18 23:32:57 +00:00
l - > capability = d - > capability ;
l - > prefs = d - > prefs ;
2003-09-11 19:44:48 +00:00
l - > parent = d ;
2004-01-09 21:12:21 +00:00
if ( ! strcasecmp ( v - > name , " trunk " ) ) {
2003-09-11 19:44:48 +00:00
l - > type = TYPE_TRUNK ;
2004-01-09 21:12:21 +00:00
} else {
2003-09-11 19:44:48 +00:00
l - > type = TYPE_LINE ;
2004-01-09 21:12:21 +00:00
}
2003-09-11 19:44:48 +00:00
l - > immediate = immediate ;
l - > callgroup = cur_callergroup ;
l - > pickupgroup = cur_pickupgroup ;
l - > callreturn = callreturn ;
2006-03-21 15:12:41 +00:00
l - > cancallforward = cancallforward ;
l - > callwaiting = callwaiting ;
2006-03-22 20:45:00 +00:00
l - > transfer = transfer ;
2006-03-21 15:12:41 +00:00
l - > threewaycalling = threewaycalling ;
l - > mwiblink = mwiblink ;
l - > onhooktime = time ( NULL ) ;
2006-06-18 22:36:39 +00:00
l - > instance = lineInstance + + ;
2006-03-22 20:45:00 +00:00
/* ASSUME we're onhook at this point */
2006-03-21 15:12:41 +00:00
l - > hookstate = SKINNY_ONHOOK ;
2006-06-18 22:36:39 +00:00
l - > nat = nat ;
2006-03-21 15:12:41 +00:00
l - > next = d - > lines ;
2006-03-22 20:45:00 +00:00
d - > lines = l ;
2003-09-11 19:44:48 +00:00
}
2004-01-09 21:12:21 +00:00
} else {
2003-09-11 19:44:48 +00:00
ast_log ( LOG_WARNING , " Don't know keyword '%s' at line %d \n " , v - > name , v - > lineno ) ;
2004-01-09 21:12:21 +00:00
}
2003-09-11 19:44:48 +00:00
v = v - > next ;
2004-01-09 21:12:21 +00:00
}
2006-03-22 20:45:00 +00:00
2004-01-09 21:12:21 +00:00
if ( ! d - > lines ) {
2003-09-11 19:44:48 +00:00
ast_log ( LOG_ERROR , " A Skinny device must have at least one line! \n " ) ;
return NULL ;
}
2006-06-18 22:36:39 +00:00
if ( /*d->addr.sin_addr.s_addr && */ ! ntohs ( d - > addr . sin_port ) ) {
2003-09-11 19:44:48 +00:00
d - > addr . sin_port = htons ( DEFAULT_SKINNY_PORT ) ;
2005-11-16 21:07:52 +00:00
}
2006-06-18 22:36:39 +00:00
#if 0
/* I don't think we need this anymore at all, since d->ourip is set in skinny_register now */
2003-09-11 19:44:48 +00:00
if ( d - > addr . sin_addr . s_addr ) {
2006-06-18 22:36:39 +00:00
/* XXX See note above, in 'host' option. */
2003-09-11 19:44:48 +00:00
if ( ast_ouraddrfor ( & d - > addr . sin_addr , & d - > ourip ) ) {
2006-06-18 22:36:39 +00:00
d - > ourip = __ourip ;
2003-09-11 19:44:48 +00:00
}
} else {
2006-06-18 22:36:39 +00:00
d - > ourip = __ourip ;
2003-09-11 19:44:48 +00:00
}
2006-06-18 22:36:39 +00:00
# endif
2003-09-11 19:44:48 +00:00
}
return d ;
}
static void start_rtp ( struct skinny_subchannel * sub )
{
2006-06-18 22:36:39 +00:00
struct skinny_line * l = sub - > parent ;
struct skinny_device * d = l - > parent ;
2006-07-14 20:14:38 +00:00
int hasvideo = 0 ;
2005-11-16 21:07:52 +00:00
ast_mutex_lock ( & sub - > lock ) ;
/* Allocate the RTP */
2006-07-14 20:14:38 +00:00
sub - > rtp = ast_rtp_new_with_bindaddr ( sched , io , 1 , 0 , bindaddr . sin_addr ) ;
if ( hasvideo )
sub - > vrtp = ast_rtp_new_with_bindaddr ( sched , io , 1 , 0 , bindaddr . sin_addr ) ;
2005-11-16 21:07:52 +00:00
if ( sub - > rtp & & sub - > owner ) {
sub - > owner - > fds [ 0 ] = ast_rtp_fd ( sub - > rtp ) ;
2006-07-14 20:14:38 +00:00
sub - > owner - > fds [ 1 ] = ast_rtcp_fd ( sub - > rtp ) ;
}
if ( hasvideo & & sub - > vrtp & & sub - > owner ) {
sub - > owner - > fds [ 2 ] = ast_rtp_fd ( sub - > vrtp ) ;
sub - > owner - > fds [ 3 ] = ast_rtcp_fd ( sub - > vrtp ) ;
2005-11-16 21:07:52 +00:00
}
if ( sub - > rtp ) {
2006-06-18 22:36:39 +00:00
ast_rtp_setnat ( sub - > rtp , l - > nat ) ;
2005-11-16 21:07:52 +00:00
}
2006-07-14 20:14:38 +00:00
if ( sub - > vrtp ) {
ast_rtp_setnat ( sub - > vrtp , l - > nat ) ;
}
2006-09-18 23:32:57 +00:00
/* Set Frame packetization */
if ( sub - > rtp )
ast_rtp_codec_setpref ( sub - > rtp , & l - > prefs ) ;
2005-11-16 21:07:52 +00:00
/* Create the RTP connection */
2006-06-18 22:36:39 +00:00
transmit_connect ( d - > session , sub ) ;
2005-11-16 21:07:52 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
2003-09-11 19:44:48 +00:00
}
2006-07-14 20:14:38 +00:00
static void * skinny_newcall ( void * data )
{
struct ast_channel * c = data ;
struct skinny_subchannel * sub = c - > tech_pvt ;
struct skinny_line * l = sub - > parent ;
struct skinny_device * d = l - > parent ;
struct skinnysession * s = d - > session ;
int res = 0 ;
ast_copy_string ( l - > lastnumberdialed , c - > exten , sizeof ( l - > lastnumberdialed ) ) ;
ast_set_callerid ( c ,
l - > hidecallerid ? " " : l - > cid_num ,
l - > hidecallerid ? " " : l - > cid_name ,
c - > cid . cid_ani ? NULL : l - > cid_num ) ;
ast_setstate ( c , AST_STATE_RING ) ;
res = ast_pbx_run ( c ) ;
if ( res ) {
ast_log ( LOG_WARNING , " PBX exited non-zero \n " ) ;
transmit_tone ( s , SKINNY_REORDER ) ;
}
return NULL ;
}
2003-09-11 19:44:48 +00:00
static void * skinny_ss ( void * data )
{
2006-07-14 20:14:38 +00:00
struct ast_channel * c = data ;
struct skinny_subchannel * sub = c - > tech_pvt ;
2003-09-11 19:44:48 +00:00
struct skinny_line * l = sub - > parent ;
2006-06-18 22:36:39 +00:00
struct skinny_device * d = l - > parent ;
struct skinnysession * s = d - > session ;
2003-09-11 19:44:48 +00:00
int len = 0 ;
int timeout = firstdigittimeout ;
2007-06-01 19:42:27 +00:00
int res = 0 ;
2003-09-11 19:44:48 +00:00
int getforward = 0 ;
2007-06-01 19:42:27 +00:00
int loop_pause = 100 ;
2006-03-21 15:12:41 +00:00
2006-04-06 16:50:33 +00:00
if ( option_verbose > 2 )
2006-06-18 22:36:39 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Starting simple switch on '%s@%s' \n " , l - > name , d - > name ) ;
2006-09-02 01:39:15 +00:00
2007-06-01 19:42:27 +00:00
len = strlen ( d - > exten ) ;
2006-04-06 16:50:33 +00:00
while ( len < AST_MAX_EXTENSION - 1 ) {
2007-06-01 19:42:27 +00:00
res = 1 ; /* Assume that we will get a digit */
while ( strlen ( d - > exten ) = = len ) {
ast_safe_sleep ( c , loop_pause ) ;
timeout - = loop_pause ;
if ( ( timeout - = loop_pause ) < = 0 ) {
res = 0 ;
break ;
2007-05-11 22:52:36 +00:00
}
2007-06-01 19:42:27 +00:00
res = 1 ;
2006-03-21 15:12:41 +00:00
}
2007-06-01 19:42:27 +00:00
timeout = 0 ;
len = strlen ( d - > exten ) ;
if ( ! ast_ignore_pattern ( c - > context , d - > exten ) ) {
2003-09-11 19:44:48 +00:00
transmit_tone ( s , SKINNY_SILENCE ) ;
2006-03-22 20:45:00 +00:00
}
2007-06-01 19:42:27 +00:00
if ( ast_exists_extension ( c , c - > context , d - > exten , 1 , l - > cid_num ) ) {
if ( ! res | | ! ast_matchmore_extension ( c , c - > context , d - > exten , 1 , l - > cid_num ) ) {
2006-03-21 15:12:41 +00:00
if ( getforward ) {
/* Record this as the forwarding extension */
2007-06-01 19:42:27 +00:00
ast_copy_string ( l - > call_forward , d - > exten , sizeof ( l - > call_forward ) ) ;
2006-04-06 16:50:33 +00:00
if ( option_verbose > 2 )
2006-03-22 20:45:00 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Setting call forward to '%s' on channel %s \n " ,
2006-07-14 20:14:38 +00:00
l - > call_forward , c - > name ) ;
2006-03-22 20:45:00 +00:00
transmit_tone ( s , SKINNY_DIALTONE ) ;
2006-03-21 15:12:41 +00:00
if ( res ) {
break ;
}
2006-07-14 20:14:38 +00:00
ast_safe_sleep ( c , 500 ) ;
ast_indicate ( c , - 1 ) ;
ast_safe_sleep ( c , 1000 ) ;
2007-06-01 19:42:27 +00:00
memset ( d - > exten , 0 , sizeof ( d - > exten ) ) ;
2006-03-22 20:45:00 +00:00
transmit_tone ( s , SKINNY_DIALTONE ) ;
2006-03-21 15:12:41 +00:00
len = 0 ;
getforward = 0 ;
} else {
2007-06-01 19:42:27 +00:00
ast_copy_string ( c - > exten , d - > exten , sizeof ( c - > exten ) ) ;
ast_copy_string ( l - > lastnumberdialed , d - > exten , sizeof ( l - > lastnumberdialed ) ) ;
memset ( d - > exten , 0 , sizeof ( d - > exten ) ) ;
2006-07-14 20:14:38 +00:00
skinny_newcall ( c ) ;
2006-06-18 22:36:39 +00:00
return NULL ;
2005-11-16 21:07:52 +00:00
}
2006-03-21 15:12:41 +00:00
} else {
/* It's a match, but they just typed a digit, and there is an ambiguous match,
so just set the timeout to matchdigittimeout and wait some more */
timeout = matchdigittimeout ;
}
2005-11-16 21:07:52 +00:00
} else if ( res = = 0 ) {
2006-10-03 15:53:07 +00:00
if ( option_debug )
2007-06-01 19:42:27 +00:00
ast_log ( LOG_DEBUG , " Not enough digits (%s) (and no ambiguous match)... \n " , d - > exten ) ;
2006-03-22 20:45:00 +00:00
transmit_tone ( s , SKINNY_REORDER ) ;
2007-05-11 22:52:36 +00:00
if ( sub - > owner & & sub - > owner - > _state ! = AST_STATE_UP ) {
ast_indicate ( c , - 1 ) ;
ast_hangup ( c ) ;
}
2006-03-21 15:12:41 +00:00
return NULL ;
2007-06-01 19:42:27 +00:00
} else if ( ! ast_canmatch_extension ( c , c - > context , d - > exten , 1 , c - > cid . cid_num ) & &
( ( d - > exten [ 0 ] ! = ' * ' ) | | ( ! ast_strlen_zero ( d - > exten ) > 2 ) ) ) {
ast_log ( LOG_WARNING , " Can't match [%s] from '%s' in context %s \n " , d - > exten , c - > cid . cid_num ? c - > cid . cid_num : " <Unknown Caller> " , c - > context ) ;
2006-03-22 20:45:00 +00:00
transmit_tone ( s , SKINNY_REORDER ) ;
2005-11-16 21:07:52 +00:00
/* hang out for 3 seconds to let congestion play */
2006-07-14 20:14:38 +00:00
ast_safe_sleep ( c , 3000 ) ;
2006-03-21 15:12:41 +00:00
break ;
}
if ( ! timeout ) {
timeout = gendigittimeout ;
2005-11-16 21:07:52 +00:00
}
2007-06-01 19:42:27 +00:00
if ( len & & ! ast_ignore_pattern ( c - > context , d - > exten ) ) {
2006-07-14 20:14:38 +00:00
ast_indicate ( c , - 1 ) ;
2005-11-16 21:07:52 +00:00
}
2006-03-22 20:45:00 +00:00
}
2007-05-11 22:52:36 +00:00
if ( c )
ast_hangup ( c ) ;
2003-09-11 19:44:48 +00:00
return NULL ;
}
static int skinny_call ( struct ast_channel * ast , char * dest , int timeout )
{
2003-09-13 23:30:30 +00:00
int res = 0 ;
int tone = 0 ;
2006-06-18 22:36:39 +00:00
struct skinny_subchannel * sub = ast - > tech_pvt ;
struct skinny_line * l = sub - > parent ;
struct skinny_device * d = l - > parent ;
2006-07-14 20:14:38 +00:00
struct skinnysession * s = d - > session ;
2003-09-14 02:17:32 +00:00
2006-06-18 22:36:39 +00:00
if ( ! d - > registered ) {
2003-09-14 02:17:32 +00:00
ast_log ( LOG_ERROR , " Device not registered, cannot call %s \n " , dest ) ;
return - 1 ;
}
2006-03-22 20:45:00 +00:00
2003-09-13 23:30:30 +00:00
if ( ( ast - > _state ! = AST_STATE_DOWN ) & & ( ast - > _state ! = AST_STATE_RESERVED ) ) {
ast_log ( LOG_WARNING , " skinny_call called on %s, neither down nor reserved \n " , ast - > name ) ;
return - 1 ;
}
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
2006-03-21 15:12:41 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " skinny_call(%s) \n " , ast - > name ) ;
2003-09-11 19:44:48 +00:00
2003-09-13 23:30:30 +00:00
if ( l - > dnd ) {
2004-04-06 22:17:32 +00:00
ast_queue_control ( ast , AST_CONTROL_BUSY ) ;
2003-09-14 02:17:32 +00:00
return - 1 ;
2003-09-13 23:30:30 +00:00
}
2006-03-21 15:12:41 +00:00
2003-09-13 23:30:30 +00:00
switch ( l - > hookstate ) {
2006-03-21 15:12:41 +00:00
case SKINNY_OFFHOOK :
tone = SKINNY_CALLWAITTONE ;
break ;
case SKINNY_ONHOOK :
2005-11-16 21:07:52 +00:00
tone = SKINNY_ALERT ;
break ;
2006-03-21 15:12:41 +00:00
default :
ast_log ( LOG_ERROR , " Don't know how to deal with hookstate %d \n " , l - > hookstate ) ;
break ;
}
2003-09-11 19:44:48 +00:00
2006-07-14 20:14:38 +00:00
transmit_callstate ( s , l - > instance , SKINNY_RINGIN , sub - > callid ) ;
transmit_selectsoftkeys ( s , l - > instance , sub - > callid , KEYDEF_RINGIN ) ;
2007-02-17 17:11:07 +00:00
transmit_displaypromptstatus ( s , " Ring-In " , 0 , l - > instance , sub - > callid ) ;
transmit_callinfo ( s , ast - > cid . cid_name , ast - > cid . cid_num , l - > cid_name , l - > cid_num , l - > instance , sub - > callid , 1 ) ;
transmit_lamp_indication ( s , STIMULUS_LINE , l - > instance , SKINNY_LAMP_BLINK ) ;
transmit_ringer_mode ( s , SKINNY_RING_INSIDE ) ;
2003-09-13 23:30:30 +00:00
ast_setstate ( ast , AST_STATE_RINGING ) ;
2004-04-06 22:17:32 +00:00
ast_queue_control ( ast , AST_CONTROL_RINGING ) ;
2003-09-11 19:44:48 +00:00
sub - > outgoing = 1 ;
return res ;
}
static int skinny_hangup ( struct ast_channel * ast )
{
2006-03-21 15:12:41 +00:00
struct skinny_subchannel * sub = ast - > tech_pvt ;
2006-06-18 22:36:39 +00:00
struct skinny_line * l ;
struct skinny_device * d ;
struct skinnysession * s ;
2006-03-21 15:12:41 +00:00
2006-06-18 22:36:39 +00:00
if ( ! sub ) {
2006-10-03 15:53:07 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Asked to hangup channel not connected \n " ) ;
2006-03-21 15:12:41 +00:00
return 0 ;
}
2006-06-18 22:36:39 +00:00
l = sub - > parent ;
d = l - > parent ;
s = d - > session ;
if ( skinnydebug )
ast_verbose ( " skinny_hangup(%s) on %s@%s \n " , ast - > name , l - > name , d - > name ) ;
if ( d - > registered ) {
if ( ( l - > type = TYPE_LINE ) & & ( l - > hookstate = = SKINNY_OFFHOOK ) ) {
l - > hookstate = SKINNY_ONHOOK ;
2003-09-14 02:17:32 +00:00
transmit_callstate ( s , l - > instance , SKINNY_ONHOOK , sub - > callid ) ;
2005-02-25 17:43:10 +00:00
transmit_lamp_indication ( s , STIMULUS_LINE , l - > instance , SKINNY_LAMP_OFF ) ;
2006-03-22 20:45:00 +00:00
transmit_speaker_mode ( s , SKINNY_SPEAKEROFF ) ;
2006-06-18 22:36:39 +00:00
} else if ( ( l - > type = TYPE_LINE ) & & ( l - > hookstate = = SKINNY_ONHOOK ) ) {
2003-09-14 02:17:32 +00:00
transmit_callstate ( s , l - > instance , SKINNY_ONHOOK , sub - > callid ) ;
2006-03-22 20:45:00 +00:00
transmit_speaker_mode ( s , SKINNY_SPEAKEROFF ) ;
2003-09-14 02:17:32 +00:00
transmit_ringer_mode ( s , SKINNY_RING_OFF ) ;
transmit_tone ( s , SKINNY_SILENCE ) ;
2005-02-25 17:43:10 +00:00
transmit_lamp_indication ( s , STIMULUS_LINE , l - > instance , SKINNY_LAMP_OFF ) ;
do_housekeeping ( s ) ;
2006-03-22 20:45:00 +00:00
}
2006-03-21 15:12:41 +00:00
}
ast_mutex_lock ( & sub - > lock ) ;
sub - > owner = NULL ;
ast - > tech_pvt = NULL ;
sub - > alreadygone = 0 ;
sub - > outgoing = 0 ;
if ( sub - > rtp ) {
ast_rtp_destroy ( sub - > rtp ) ;
sub - > rtp = NULL ;
}
ast_mutex_unlock ( & sub - > lock ) ;
return 0 ;
2003-09-11 19:44:48 +00:00
}
static int skinny_answer ( struct ast_channel * ast )
{
2006-03-21 15:12:41 +00:00
int res = 0 ;
struct skinny_subchannel * sub = ast - > tech_pvt ;
struct skinny_line * l = sub - > parent ;
2006-06-18 22:36:39 +00:00
struct skinny_device * d = l - > parent ;
struct skinnysession * s = d - > session ;
2005-06-02 09:11:46 +00:00
2006-03-21 15:12:41 +00:00
sub - > cxmode = SKINNY_CX_SENDRECV ;
if ( ! sub - > rtp ) {
2003-09-11 19:44:48 +00:00
start_rtp ( sub ) ;
2006-03-22 20:45:00 +00:00
}
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
ast_verbose ( " skinny_answer(%s) on %s@%s-%d \n " , ast - > name , l - > name , d - > name , sub - > callid ) ;
2006-03-21 15:12:41 +00:00
if ( ast - > _state ! = AST_STATE_UP ) {
ast_setstate ( ast , AST_STATE_UP ) ;
}
2006-06-20 08:09:30 +00:00
2006-06-18 22:36:39 +00:00
transmit_tone ( s , SKINNY_SILENCE ) ;
2006-06-20 08:09:30 +00:00
/* order matters here...
for some reason , transmit_callinfo must be before transmit_callstate ,
or you won ' t get keypad messages in some situations . */
transmit_callinfo ( s , ast - > cid . cid_name , ast - > cid . cid_num , ast - > exten , ast - > exten , l - > instance , sub - > callid , 2 ) ;
2006-03-21 15:12:41 +00:00
transmit_callstate ( s , l - > instance , SKINNY_CONNECTED , sub - > callid ) ;
2007-02-24 02:04:34 +00:00
transmit_selectsoftkeys ( s , l - > instance , sub - > callid , KEYDEF_CONNECTED ) ;
2006-03-21 15:12:41 +00:00
transmit_displaypromptstatus ( s , " Connected " , 0 , l - > instance , sub - > callid ) ;
return res ;
2003-09-11 19:44:48 +00:00
}
2006-06-18 22:36:39 +00:00
/* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
2003-09-11 19:44:48 +00:00
static struct ast_frame * skinny_rtp_read ( struct skinny_subchannel * sub )
{
2006-06-18 22:36:39 +00:00
struct ast_channel * ast = sub - > owner ;
2003-09-11 19:44:48 +00:00
struct ast_frame * f ;
2006-06-18 22:36:39 +00:00
2006-07-14 20:14:38 +00:00
if ( ! sub - > rtp ) {
/* We have no RTP allocated for this channel */
return & ast_null_frame ;
}
switch ( ast - > fdno ) {
case 0 :
f = ast_rtp_read ( sub - > rtp ) ; /* RTP Audio */
break ;
case 1 :
f = ast_rtcp_read ( sub - > rtp ) ; /* RTCP Control Channel */
break ;
case 2 :
f = ast_rtp_read ( sub - > vrtp ) ; /* RTP Video */
break ;
case 3 :
f = ast_rtcp_read ( sub - > vrtp ) ; /* RTCP Control Channel for video */
break ;
#if 0
case 5 :
/* Not yet supported */
f = ast_udptl_read ( sub - > udptl ) ; /* UDPTL for T.38 */
break ;
# endif
default :
f = & ast_null_frame ;
}
2006-06-18 22:36:39 +00:00
if ( ast ) {
2003-09-11 19:44:48 +00:00
/* We already hold the channel lock */
if ( f - > frametype = = AST_FRAME_VOICE ) {
2006-06-18 22:36:39 +00:00
if ( f - > subclass ! = ast - > nativeformats ) {
2006-10-03 15:53:07 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Oooh, format changed to %d \n " , f - > subclass ) ;
2006-06-18 22:36:39 +00:00
ast - > nativeformats = f - > subclass ;
ast_set_read_format ( ast , ast - > readformat ) ;
ast_set_write_format ( ast , ast - > writeformat ) ;
2003-09-11 19:44:48 +00:00
}
}
}
return f ;
}
2006-03-21 15:12:41 +00:00
static struct ast_frame * skinny_read ( struct ast_channel * ast )
2003-09-11 19:44:48 +00:00
{
struct ast_frame * fr ;
2005-03-04 06:47:24 +00:00
struct skinny_subchannel * sub = ast - > tech_pvt ;
2003-09-11 19:44:48 +00:00
ast_mutex_lock ( & sub - > lock ) ;
fr = skinny_rtp_read ( sub ) ;
ast_mutex_unlock ( & sub - > lock ) ;
return fr ;
}
static int skinny_write ( struct ast_channel * ast , struct ast_frame * frame )
{
2005-03-04 06:47:24 +00:00
struct skinny_subchannel * sub = ast - > tech_pvt ;
2003-09-11 19:44:48 +00:00
int res = 0 ;
if ( frame - > frametype ! = AST_FRAME_VOICE ) {
2005-11-16 21:07:52 +00:00
if ( frame - > frametype = = AST_FRAME_IMAGE ) {
2003-09-11 19:44:48 +00:00
return 0 ;
2005-11-16 21:07:52 +00:00
} else {
2004-05-12 21:30:23 +00:00
ast_log ( LOG_WARNING , " Can't send %d type frames with skinny_write \n " , frame - > frametype ) ;
2003-09-11 19:44:48 +00:00
return 0 ;
}
} else {
if ( ! ( frame - > subclass & ast - > nativeformats ) ) {
ast_log ( LOG_WARNING , " Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d) \n " ,
frame - > subclass , ast - > nativeformats , ast - > readformat , ast - > writeformat ) ;
return - 1 ;
}
}
if ( sub ) {
ast_mutex_lock ( & sub - > lock ) ;
if ( sub - > rtp ) {
2006-03-21 15:12:41 +00:00
res = ast_rtp_write ( sub - > rtp , frame ) ;
2003-09-11 19:44:48 +00:00
}
ast_mutex_unlock ( & sub - > lock ) ;
}
return res ;
}
2004-04-06 22:17:32 +00:00
static int skinny_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan )
2003-09-11 19:44:48 +00:00
{
2005-03-04 06:47:24 +00:00
struct skinny_subchannel * sub = newchan - > tech_pvt ;
2006-03-21 15:12:41 +00:00
ast_log ( LOG_NOTICE , " skinny_fixup(%s, %s) \n " , oldchan - > name , newchan - > name ) ;
2003-09-11 19:44:48 +00:00
if ( sub - > owner ! = oldchan ) {
ast_log ( LOG_WARNING , " old channel wasn't %p but was %p \n " , oldchan , sub - > owner ) ;
return - 1 ;
}
sub - > owner = newchan ;
return 0 ;
}
2006-08-31 01:59:02 +00:00
static int skinny_senddigit_begin ( struct ast_channel * ast , char digit )
{
return - 1 ; /* Start inband indications */
}
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
static int skinny_senddigit_end ( struct ast_channel * ast , char digit , unsigned int duration )
2003-09-11 19:44:48 +00:00
{
2004-05-12 21:30:23 +00:00
#if 0
2005-03-04 06:47:24 +00:00
struct skinny_subchannel * sub = ast - > tech_pvt ;
2006-06-18 22:36:39 +00:00
struct skinny_line * l = sub - > parent ;
struct skinny_device * d = l - > parent ;
2004-05-12 21:30:23 +00:00
int tmp ;
/* not right */
2006-03-21 15:12:41 +00:00
sprintf ( tmp , " %d " , digit ) ;
2006-06-18 22:36:39 +00:00
transmit_tone ( d - > session , digit ) ;
2004-05-12 21:30:23 +00:00
# endif
2006-08-31 01:59:02 +00:00
return - 1 ; /* Stop inband indications */
2003-09-11 19:44:48 +00:00
}
static char * control2str ( int ind ) {
2006-08-20 18:03:24 +00:00
char * tmp ;
2006-03-21 15:12:41 +00:00
switch ( ind ) {
case AST_CONTROL_HANGUP :
return " Other end has hungup " ;
case AST_CONTROL_RING :
return " Local ring " ;
case AST_CONTROL_RINGING :
return " Remote end is ringing " ;
case AST_CONTROL_ANSWER :
return " Remote end has answered " ;
case AST_CONTROL_BUSY :
return " Remote end is busy " ;
case AST_CONTROL_TAKEOFFHOOK :
return " Make it go off hook " ;
case AST_CONTROL_OFFHOOK :
return " Line is off hook " ;
case AST_CONTROL_CONGESTION :
return " Congestion (circuits busy) " ;
case AST_CONTROL_FLASH :
return " Flash hook " ;
case AST_CONTROL_WINK :
return " Wink " ;
case AST_CONTROL_OPTION :
return " Set a low-level option " ;
case AST_CONTROL_RADIO_KEY :
return " Key Radio " ;
case AST_CONTROL_RADIO_UNKEY :
return " Un-Key Radio " ;
case AST_CONTROL_PROGRESS :
return " Remote end is making Progress " ;
case AST_CONTROL_PROCEEDING :
return " Remote end is proceeding " ;
case AST_CONTROL_HOLD :
return " Hold " ;
case AST_CONTROL_UNHOLD :
return " Unhold " ;
2005-06-02 09:11:46 +00:00
case - 1 :
2006-03-21 15:12:41 +00:00
return " Stop tone " ;
2006-08-20 01:25:02 +00:00
default :
2006-08-20 04:39:57 +00:00
if ( ! ( tmp = ast_threadstorage_get ( & control2str_threadbuf , CONTROL2STR_BUFSIZE ) ) )
return " Unknown " ;
snprintf ( tmp , CONTROL2STR_BUFSIZE , " UNKNOWN-%d " , ind ) ;
2006-08-20 01:25:02 +00:00
return tmp ;
2006-03-21 15:12:41 +00:00
}
2003-09-11 19:44:48 +00:00
}
2006-05-10 12:24:11 +00:00
static int skinny_indicate ( struct ast_channel * ast , int ind , const void * data , size_t datalen )
2003-09-11 19:44:48 +00:00
{
2005-03-04 06:47:24 +00:00
struct skinny_subchannel * sub = ast - > tech_pvt ;
2003-09-11 19:44:48 +00:00
struct skinny_line * l = sub - > parent ;
2006-06-18 22:36:39 +00:00
struct skinny_device * d = l - > parent ;
struct skinnysession * s = d - > session ;
2003-09-11 19:44:48 +00:00
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
2006-03-21 15:12:41 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Asked to indicate '%s' condition on channel %s \n " , control2str ( ind ) , ast - > name ) ;
2003-09-11 19:44:48 +00:00
switch ( ind ) {
case AST_CONTROL_RINGING :
2005-01-16 08:16:07 +00:00
if ( ast - > _state ! = AST_STATE_UP ) {
2006-03-22 20:45:00 +00:00
if ( ! sub - > progress ) {
2004-05-31 02:49:53 +00:00
transmit_tone ( s , SKINNY_ALERT ) ;
transmit_callstate ( s , l - > instance , SKINNY_RINGOUT , sub - > callid ) ;
2006-03-21 15:12:41 +00:00
transmit_dialednumber ( s , ast - > exten , l - > instance , sub - > callid ) ;
2005-06-02 09:11:46 +00:00
transmit_displaypromptstatus ( s , " Ring Out " , 0 , l - > instance , sub - > callid ) ;
transmit_callinfo ( s , ast - > cid . cid_name , ast - > cid . cid_num , ast - > exten , ast - > exten , l - > instance , sub - > callid , 2 ) ; /* 2 = outgoing from phone */
2004-05-31 02:49:53 +00:00
sub - > ringing = 1 ;
break ;
}
}
return - 1 ;
2003-09-11 19:44:48 +00:00
case AST_CONTROL_BUSY :
2006-03-22 20:45:00 +00:00
if ( ast - > _state ! = AST_STATE_UP ) {
2004-05-31 02:49:53 +00:00
transmit_tone ( s , SKINNY_BUSYTONE ) ;
transmit_callstate ( s , l - > instance , SKINNY_BUSY , sub - > callid ) ;
sub - > alreadygone = 1 ;
ast_softhangup_nolock ( ast , AST_SOFTHANGUP_DEV ) ;
2006-03-21 15:12:41 +00:00
break ;
}
return - 1 ;
2003-09-11 19:44:48 +00:00
case AST_CONTROL_CONGESTION :
2006-03-22 20:45:00 +00:00
if ( ast - > _state ! = AST_STATE_UP ) {
2004-05-31 02:49:53 +00:00
transmit_tone ( s , SKINNY_REORDER ) ;
transmit_callstate ( s , l - > instance , SKINNY_CONGESTION , sub - > callid ) ;
sub - > alreadygone = 1 ;
2006-03-21 15:12:41 +00:00
ast_softhangup_nolock ( ast , AST_SOFTHANGUP_DEV ) ;
break ;
}
return - 1 ;
2004-05-31 02:49:53 +00:00
case AST_CONTROL_PROGRESS :
2006-03-21 15:12:41 +00:00
if ( ( ast - > _state ! = AST_STATE_UP ) & & ! sub - > progress & & ! sub - > outgoing ) {
2005-06-02 09:11:46 +00:00
transmit_tone ( s , SKINNY_ALERT ) ;
2004-05-31 02:49:53 +00:00
transmit_callstate ( s , l - > instance , SKINNY_PROGRESS , sub - > callid ) ;
2005-06-02 09:11:46 +00:00
transmit_displaypromptstatus ( s , " Call Progress " , 0 , l - > instance , sub - > callid ) ;
transmit_callinfo ( s , ast - > cid . cid_name , ast - > cid . cid_num , ast - > exten , ast - > exten , l - > instance , sub - > callid , 2 ) ; /* 2 = outgoing from phone */
2006-03-21 15:12:41 +00:00
sub - > progress = 1 ;
break ;
}
return - 1 ;
2003-09-11 19:44:48 +00:00
case - 1 :
transmit_tone ( s , SKINNY_SILENCE ) ;
2006-03-22 20:45:00 +00:00
break ;
2006-07-19 20:44:39 +00:00
case AST_CONTROL_HOLD :
ast_moh_start ( ast , data , l - > mohinterpret ) ;
break ;
case AST_CONTROL_UNHOLD :
ast_moh_stop ( ast ) ;
break ;
2004-06-14 21:18:52 +00:00
case AST_CONTROL_PROCEEDING :
break ;
2003-09-11 19:44:48 +00:00
default :
ast_log ( LOG_WARNING , " Don't know how to indicate condition %d \n " , ind ) ;
return - 1 ;
}
return 0 ;
}
2006-03-22 20:45:00 +00:00
2006-06-18 22:36:39 +00:00
static struct ast_channel * skinny_new ( struct skinny_line * l , int state )
2003-09-11 19:44:48 +00:00
{
struct ast_channel * tmp ;
2006-06-18 22:36:39 +00:00
struct skinny_subchannel * sub ;
struct skinny_device * d = l - > parent ;
2003-09-11 19:44:48 +00:00
int fmt ;
2006-06-18 22:36:39 +00:00
2007-04-10 05:41:34 +00:00
tmp = ast_channel_alloc ( 1 , state , l - > cid_num , l - > cid_name , l - > accountcode , l - > exten , l - > context , l - > amaflags , " Skinny/%s@%s-%d " , l - > name , d - > name , callnums ) ;
2006-06-18 22:36:39 +00:00
if ( ! tmp ) {
ast_log ( LOG_WARNING , " Unable to allocate channel structure \n " ) ;
return NULL ;
} else {
sub = ast_calloc ( 1 , sizeof ( struct skinny_subchannel ) ) ;
if ( ! sub ) {
ast_log ( LOG_WARNING , " Unable to allocate Skinny subchannel \n " ) ;
return NULL ;
} else {
ast_mutex_init ( & sub - > lock ) ;
sub - > owner = tmp ;
sub - > callid = callnums + + ;
d - > lastlineinstance = l - > instance ;
d - > lastcallreference = sub - > callid ;
sub - > cxmode = SKINNY_CX_INACTIVE ;
sub - > nat = l - > nat ;
sub - > parent = l ;
2006-09-17 22:24:27 +00:00
sub - > onhold = 0 ;
2006-06-18 22:36:39 +00:00
sub - > next = l - > sub ;
l - > sub = sub ;
}
2005-03-04 06:47:24 +00:00
tmp - > tech = & skinny_tech ;
2006-06-18 22:36:39 +00:00
tmp - > tech_pvt = sub ;
2003-09-11 19:44:48 +00:00
tmp - > nativeformats = l - > capability ;
if ( ! tmp - > nativeformats )
2006-09-18 23:32:57 +00:00
tmp - > nativeformats = default_capability ;
2003-09-11 19:44:48 +00:00
fmt = ast_best_codec ( tmp - > nativeformats ) ;
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
2006-04-06 16:50:33 +00:00
ast_verbose ( " skinny_new: tmp->nativeformats=%d fmt=%d \n " , tmp - > nativeformats , fmt ) ;
2005-11-16 21:07:52 +00:00
if ( sub - > rtp ) {
2003-09-11 19:44:48 +00:00
tmp - > fds [ 0 ] = ast_rtp_fd ( sub - > rtp ) ;
2005-11-16 21:07:52 +00:00
}
if ( state = = AST_STATE_RING ) {
2003-09-11 19:44:48 +00:00
tmp - > rings = 1 ;
2005-11-16 21:07:52 +00:00
}
2003-09-11 19:44:48 +00:00
tmp - > writeformat = fmt ;
2005-03-04 06:47:24 +00:00
tmp - > rawwriteformat = fmt ;
2003-09-11 19:44:48 +00:00
tmp - > readformat = fmt ;
2005-03-04 06:47:24 +00:00
tmp - > rawreadformat = fmt ;
2006-02-01 23:05:28 +00:00
if ( ! ast_strlen_zero ( l - > language ) )
ast_string_field_set ( tmp , language , l - > language ) ;
if ( ! ast_strlen_zero ( l - > accountcode ) )
ast_string_field_set ( tmp , accountcode , l - > accountcode ) ;
if ( l - > amaflags )
2003-09-11 19:44:48 +00:00
tmp - > amaflags = l - > amaflags ;
2006-06-18 22:36:39 +00:00
2007-01-23 22:59:55 +00:00
ast_module_ref ( ast_module_info - > self ) ;
2003-09-11 19:44:48 +00:00
tmp - > callgroup = l - > callgroup ;
tmp - > pickupgroup = l - > pickupgroup ;
2006-02-01 23:05:28 +00:00
ast_string_field_set ( tmp , call_forward , l - > call_forward ) ;
2006-04-21 18:08:57 +00:00
ast_copy_string ( tmp - > context , l - > context , sizeof ( tmp - > context ) ) ;
ast_copy_string ( tmp - > exten , l - > exten , sizeof ( tmp - > exten ) ) ;
2006-08-05 05:26:29 +00:00
/* Don't use ast_set_callerid() here because it will
2006-11-07 21:47:49 +00:00
* generate a needless NewCallerID event */
2006-08-05 05:26:29 +00:00
tmp - > cid . cid_num = ast_strdup ( l - > cid_num ) ;
tmp - > cid . cid_ani = ast_strdup ( l - > cid_num ) ;
tmp - > cid . cid_name = ast_strdup ( l - > cid_name ) ;
2003-09-11 19:44:48 +00:00
tmp - > priority = 1 ;
2005-06-02 09:11:46 +00:00
tmp - > adsicpe = AST_ADSI_UNAVAILABLE ;
2006-08-16 03:43:47 +00:00
if ( sub - > rtp )
ast_jb_configure ( tmp , & global_jbconf ) ;
2003-09-11 19:44:48 +00:00
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 ) ;
2006-06-23 16:49:12 +00:00
tmp = NULL ;
2003-09-11 19:44:48 +00:00
}
}
2006-06-23 16:49:12 +00:00
}
2006-03-21 15:12:41 +00:00
return tmp ;
2003-09-11 19:44:48 +00:00
}
2006-09-17 22:24:27 +00:00
static int skinny_hold ( struct skinny_subchannel * sub )
{
struct skinny_line * l = sub - > parent ;
struct skinny_device * d = l - > parent ;
struct skinnysession * s = d - > session ;
struct skinny_req * req ;
/* Channel needs to be put on hold */
if ( skinnydebug )
ast_verbose ( " Putting on Hold(%d) \n " , l - > instance ) ;
ast_queue_control_data ( sub - > owner , AST_CONTROL_HOLD ,
S_OR ( l - > mohsuggest , NULL ) ,
! ast_strlen_zero ( l - > mohsuggest ) ? strlen ( l - > mohsuggest ) + 1 : 0 ) ;
if ( ! ( req = req_alloc ( sizeof ( struct activate_call_plane_message ) , ACTIVATE_CALL_PLANE_MESSAGE ) ) )
return 0 ;
2006-09-17 23:04:48 +00:00
2006-09-17 22:24:27 +00:00
req - > data . activatecallplane . lineInstance = htolel ( l - > instance ) ;
transmit_response ( s , req ) ;
2006-09-17 23:04:48 +00:00
2006-09-17 22:24:27 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct close_receive_channel_message ) , CLOSE_RECEIVE_CHANNEL_MESSAGE ) ) )
return 0 ;
2006-09-17 23:04:48 +00:00
2006-09-17 22:24:27 +00:00
req - > data . closereceivechannel . conferenceId = htolel ( 0 ) ;
req - > data . closereceivechannel . partyId = htolel ( sub - > callid ) ;
transmit_response ( s , req ) ;
2006-09-17 23:04:48 +00:00
2006-09-17 22:24:27 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct stop_media_transmission_message ) , STOP_MEDIA_TRANSMISSION_MESSAGE ) ) )
return 0 ;
2006-09-17 23:04:48 +00:00
2006-09-17 22:24:27 +00:00
req - > data . stopmedia . conferenceId = htolel ( 0 ) ;
req - > data . stopmedia . passThruPartyId = htolel ( sub - > callid ) ;
transmit_response ( s , req ) ;
2006-09-17 23:04:48 +00:00
2007-02-24 02:23:43 +00:00
transmit_lamp_indication ( s , STIMULUS_LINE , l - > instance , SKINNY_LAMP_WINK ) ;
2006-09-17 22:24:27 +00:00
sub - > onhold = 1 ;
return 1 ;
}
static int skinny_unhold ( struct skinny_subchannel * sub )
{
struct skinny_line * l = sub - > parent ;
struct skinny_device * d = l - > parent ;
struct skinnysession * s = d - > session ;
struct skinny_req * req ;
/* Channel is on hold, so we will unhold */
if ( skinnydebug )
ast_verbose ( " Taking off Hold(%d) \n " , l - > instance ) ;
ast_queue_control ( sub - > owner , AST_CONTROL_UNHOLD ) ;
if ( ! ( req = req_alloc ( sizeof ( struct activate_call_plane_message ) , ACTIVATE_CALL_PLANE_MESSAGE ) ) )
return 0 ;
2006-09-17 23:04:48 +00:00
2006-09-17 22:24:27 +00:00
req - > data . activatecallplane . lineInstance = htolel ( l - > instance ) ;
transmit_response ( s , req ) ;
2006-09-17 23:04:48 +00:00
transmit_connect ( s , sub ) ;
2006-09-17 22:24:27 +00:00
transmit_lamp_indication ( s , STIMULUS_LINE , l - > instance , SKINNY_LAMP_ON ) ;
sub - > onhold = 0 ;
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_keep_alive_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
if ( ! ( req = req_alloc ( 0 , KEEP_ALIVE_ACK_MESSAGE ) ) )
return - 1 ;
transmit_response ( s , req ) ;
do_housekeeping ( s ) ;
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_register_message ( struct skinny_req * req , struct skinnysession * s )
2003-09-11 19:44:48 +00:00
{
char name [ 16 ] ;
2006-06-18 22:36:39 +00:00
int res ;
memcpy ( & name , req - > data . reg . name , sizeof ( name ) ) ;
res = skinny_register ( req , s ) ;
if ( ! res ) {
ast_log ( LOG_ERROR , " Rejecting Device %s: Device not found \n " , name ) ;
2006-09-17 21:58:04 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct register_rej_message ) , REGISTER_REJ_MESSAGE ) ) )
2006-06-18 22:36:39 +00:00
return - 1 ;
snprintf ( req - > data . regrej . errMsg , sizeof ( req - > data . regrej . errMsg ) , " No Authority: %s " , name ) ;
transmit_response ( s , req ) ;
return 0 ;
}
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Device '%s' successfully registered \n " , name ) ;
2006-09-17 21:58:04 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct register_ack_message ) , REGISTER_ACK_MESSAGE ) ) )
2006-06-18 22:36:39 +00:00
return - 1 ;
req - > data . regack . res [ 0 ] = ' 0 ' ;
req - > data . regack . res [ 1 ] = ' \0 ' ;
req - > data . regack . keepAlive = htolel ( keep_alive ) ;
ast_copy_string ( req - > data . regack . dateTemplate , date_format , sizeof ( req - > data . regack . dateTemplate ) ) ;
req - > data . regack . res2 [ 0 ] = ' 0 ' ;
req - > data . regack . res2 [ 1 ] = ' \0 ' ;
req - > data . regack . secondaryKeepAlive = htolel ( keep_alive ) ;
transmit_response ( s , req ) ;
if ( skinnydebug )
ast_verbose ( " Requesting capabilities \n " ) ;
if ( ! ( req = req_alloc ( 0 , CAPABILITIES_REQ_MESSAGE ) ) )
return - 1 ;
transmit_response ( s , req ) ;
return res ;
}
2006-09-17 21:58:04 +00:00
static int handle_ip_port_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
/* no response necessary */
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_keypad_button_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
struct skinny_subchannel * sub = NULL ;
struct skinny_line * l ;
2006-06-20 08:09:30 +00:00
struct skinny_device * d = s - > device ;
2006-09-02 01:44:50 +00:00
struct ast_frame f = { 0 , } ;
2006-06-20 08:09:30 +00:00
char dgt ;
2003-09-11 19:44:48 +00:00
int digit ;
2006-06-18 22:36:39 +00:00
int lineInstance ;
int callReference ;
2006-03-22 20:45:00 +00:00
2006-06-18 22:36:39 +00:00
digit = letohl ( req - > data . keypad . button ) ;
lineInstance = letohl ( req - > data . keypad . lineInstance ) ;
callReference = letohl ( req - > data . keypad . callReference ) ;
2006-07-14 20:14:38 +00:00
2006-06-18 22:36:39 +00:00
if ( digit = = 14 ) {
2006-06-20 08:09:30 +00:00
dgt = ' * ' ;
2006-06-18 22:36:39 +00:00
} else if ( digit = = 15 ) {
2006-06-20 08:09:30 +00:00
dgt = ' # ' ;
2006-09-02 01:39:15 +00:00
} else if ( digit > = 0 & & digit < = 9 ) {
2006-06-20 08:09:30 +00:00
dgt = ' 0 ' + digit ;
2006-06-18 22:36:39 +00:00
} else {
/* digit=10-13 (A,B,C,D ?), or
* digit is bad value
*
* probably should not end up here , but set
* value for backward compatibility , and log
* a warning .
*/
2006-06-20 08:09:30 +00:00
dgt = ' 0 ' + digit ;
2006-06-18 22:36:39 +00:00
ast_log ( LOG_WARNING , " Unsupported digit %d \n " , digit ) ;
2003-09-13 23:30:30 +00:00
}
2006-09-02 01:39:15 +00:00
2006-09-02 01:44:50 +00:00
f . subclass = dgt ;
2006-09-02 01:39:15 +00:00
2006-09-02 01:44:50 +00:00
f . src = " skinny " ;
2005-02-25 17:43:10 +00:00
2006-06-18 22:36:39 +00:00
if ( lineInstance & & callReference )
2006-06-20 08:09:30 +00:00
sub = find_subchannel_by_instance_reference ( d , lineInstance , callReference ) ;
else
sub = find_subchannel_by_instance_reference ( d , d - > lastlineinstance , d - > lastcallreference ) ;
2006-06-18 22:36:39 +00:00
if ( ! sub )
return 0 ;
l = sub - > parent ;
if ( sub - > owner ) {
2006-09-02 01:39:15 +00:00
if ( sub - > owner - > _state = = 0 ) {
2006-09-02 01:44:50 +00:00
f . frametype = AST_FRAME_DTMF_BEGIN ;
ast_queue_frame ( sub - > owner , & f ) ;
2006-09-02 01:39:15 +00:00
}
2006-06-18 22:36:39 +00:00
/* XXX MUST queue this frame to all lines in threeway call if threeway call is active */
2006-09-02 01:44:50 +00:00
f . frametype = AST_FRAME_DTMF_END ;
ast_queue_frame ( sub - > owner , & f ) ;
2006-06-18 22:36:39 +00:00
/* XXX This seriously needs to be fixed */
if ( sub - > next & & sub - > next - > owner ) {
2006-09-02 01:39:15 +00:00
if ( sub - > owner - > _state = = 0 ) {
2006-09-02 01:44:50 +00:00
f . frametype = AST_FRAME_DTMF_BEGIN ;
ast_queue_frame ( sub - > next - > owner , & f ) ;
2006-09-02 01:39:15 +00:00
}
2006-09-02 01:44:50 +00:00
f . frametype = AST_FRAME_DTMF_END ;
ast_queue_frame ( sub - > next - > owner , & f ) ;
2003-09-11 19:44:48 +00:00
}
2006-06-18 22:36:39 +00:00
} else {
if ( skinnydebug )
ast_verbose ( " No owner: %s \n " , l - > name ) ;
}
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_stimulus_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
struct skinny_device * d = s - > device ;
struct skinny_line * l ;
struct skinny_subchannel * sub ;
/*struct skinny_speeddial *sd;*/
struct ast_channel * c ;
pthread_t t ;
int event ;
int instance ;
int unknown1 ;
/*int res = 0;*/
event = letohl ( req - > data . stimulus . stimulus ) ;
instance = letohl ( req - > data . stimulus . stimulusInstance ) ;
unknown1 = letohl ( req - > data . stimulus . unknown1 ) ; /* No clue.. */
if ( skinnydebug )
ast_verbose ( " unknown1 in handle_stimulus_message is '%d' \n " , unknown1 ) ;
sub = find_subchannel_by_instance_reference ( d , d - > lastlineinstance , d - > lastcallreference ) ;
if ( ! sub ) {
l = find_line_by_instance ( d , d - > lastlineinstance ) ;
if ( ! l ) {
return 0 ;
2004-05-12 21:30:23 +00:00
}
2006-06-18 22:36:39 +00:00
} else {
l = sub - > parent ;
}
switch ( event ) {
case STIMULUS_REDIAL :
if ( skinnydebug )
ast_verbose ( " Received Stimulus: Redial(%d) \n " , instance ) ;
c = skinny_new ( l , AST_STATE_DOWN ) ;
2007-05-11 22:52:36 +00:00
if ( ! c ) {
2006-07-14 20:14:38 +00:00
ast_log ( LOG_WARNING , " Unable to create channel for %s@%s \n " , l - > name , d - > name ) ;
} else {
2006-06-18 22:36:39 +00:00
sub = c - > tech_pvt ;
2007-05-11 22:52:36 +00:00
l = sub - > parent ;
if ( l - > hookstate = = SKINNY_ONHOOK ) {
l - > hookstate = SKINNY_OFFHOOK ;
transmit_callstate ( s , l - > instance , SKINNY_OFFHOOK , sub - > callid ) ;
}
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
ast_verbose ( " Attempting to Clear display on Skinny %s@%s \n " , l - > name , d - > name ) ;
transmit_displaymessage ( s , NULL ) ; /* clear display */
transmit_tone ( s , SKINNY_DIALTONE ) ;
if ( ast_strlen_zero ( l - > lastnumberdialed ) ) {
ast_log ( LOG_WARNING , " Attempted redial, but no previously dialed number found. \n " ) ;
return 0 ;
2004-01-12 02:19:25 +00:00
}
2006-06-18 22:36:39 +00:00
if ( ! ast_ignore_pattern ( c - > context , l - > lastnumberdialed ) ) {
transmit_tone ( s , SKINNY_SILENCE ) ;
2004-01-12 02:19:25 +00:00
}
2006-07-14 20:14:38 +00:00
ast_copy_string ( c - > exten , l - > lastnumberdialed , sizeof ( c - > exten ) ) ;
if ( ast_pthread_create ( & t , NULL , skinny_newcall , c ) ) {
ast_log ( LOG_WARNING , " Unable to create new call thread: %s \n " , strerror ( errno ) ) ;
ast_hangup ( c ) ;
2005-02-25 17:43:10 +00:00
}
2006-06-18 22:36:39 +00:00
}
break ;
case STIMULUS_SPEEDDIAL :
if ( skinnydebug )
ast_verbose ( " Received Stimulus: SpeedDial(%d) \n " , instance ) ;
2007-05-11 22:52:36 +00:00
struct skinny_speeddial * sd ;
2007-02-24 02:23:43 +00:00
if ( ! ( sd = find_speeddial_by_instance ( d , instance , 0 ) ) ) {
2006-06-18 22:36:39 +00:00
return 0 ;
}
2007-05-11 22:52:36 +00:00
if ( ! sub | | ! sub - > owner )
c = skinny_new ( l , AST_STATE_DOWN ) ;
else
c = sub - > owner ;
if ( ! c ) {
ast_log ( LOG_WARNING , " Unable to create channel for %s@%s \n " , l - > name , d - > name ) ;
} else {
2006-06-18 22:36:39 +00:00
sub = c - > tech_pvt ;
l = sub - > parent ;
2007-05-11 22:52:36 +00:00
if ( l - > hookstate = = SKINNY_ONHOOK ) {
l - > hookstate = SKINNY_OFFHOOK ;
transmit_speaker_mode ( s , SKINNY_SPEAKERON ) ;
transmit_callstate ( s , l - > instance , SKINNY_OFFHOOK , sub - > callid ) ;
}
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
ast_verbose ( " Attempting to Clear display on Skinny %s@%s \n " , l - > name , d - > name ) ;
transmit_displaymessage ( s , NULL ) ; /* clear display */
2005-02-25 17:43:10 +00:00
transmit_tone ( s , SKINNY_DIALTONE ) ;
2006-06-18 22:36:39 +00:00
if ( ! ast_ignore_pattern ( c - > context , sd - > exten ) ) {
transmit_tone ( s , SKINNY_SILENCE ) ;
2005-02-25 17:43:10 +00:00
}
2006-06-18 22:36:39 +00:00
if ( ast_exists_extension ( c , c - > context , sd - > exten , 1 , l - > cid_num ) ) {
2007-05-11 22:52:36 +00:00
ast_copy_string ( c - > exten , sd - > exten , sizeof ( c - > exten ) ) ;
ast_copy_string ( l - > lastnumberdialed , sd - > exten , sizeof ( l - > lastnumberdialed ) ) ;
if ( ast_pthread_create ( & t , NULL , skinny_newcall , c ) ) {
ast_log ( LOG_WARNING , " Unable to create new call thread: %s \n " , strerror ( errno ) ) ;
ast_hangup ( c ) ;
2006-06-18 22:36:39 +00:00
}
2007-05-11 22:52:36 +00:00
break ;
2005-02-25 17:43:10 +00:00
}
2006-06-18 22:36:39 +00:00
}
break ;
case STIMULUS_HOLD :
if ( skinnydebug )
ast_verbose ( " Received Stimulus: Hold(%d) \n " , instance ) ;
2006-09-17 22:24:27 +00:00
2007-02-24 02:04:34 +00:00
if ( ! sub )
break ;
2006-09-17 22:24:27 +00:00
if ( sub - > onhold ) {
skinny_unhold ( sub ) ;
} else {
skinny_hold ( sub ) ;
}
2006-06-18 22:36:39 +00:00
break ;
case STIMULUS_TRANSFER :
if ( skinnydebug )
ast_verbose ( " Received Stimulus: Transfer(%d) \n " , instance ) ;
transmit_tone ( s , SKINNY_DIALTONE ) ;
/* XXX figure out how to transfer */
break ;
case STIMULUS_CONFERENCE :
if ( skinnydebug )
2006-07-01 17:59:37 +00:00
ast_verbose ( " Received Stimulus: Conference(%d) \n " , instance ) ;
2006-06-18 22:36:39 +00:00
transmit_tone ( s , SKINNY_DIALTONE ) ;
/* XXX determine the best way to pull off a conference. Meetme? */
break ;
case STIMULUS_VOICEMAIL :
if ( skinnydebug )
ast_verbose ( " Received Stimulus: Voicemail(%d) \n " , instance ) ;
2007-05-11 22:52:36 +00:00
if ( ! sub | | ! sub - > owner ) {
c = skinny_new ( l , AST_STATE_DOWN ) ;
} else {
c = sub - > owner ;
}
if ( ! c ) {
ast_log ( LOG_WARNING , " Unable to create channel for %s@%s \n " , l - > name , d - > name ) ;
} else {
sub = c - > tech_pvt ;
l = sub - > parent ;
if ( ast_strlen_zero ( l - > vmexten ) ) /* Exit the call if no VM pilot */
break ;
if ( l - > hookstate = = SKINNY_ONHOOK ) {
l - > hookstate = SKINNY_OFFHOOK ;
transmit_speaker_mode ( s , SKINNY_SPEAKERON ) ;
transmit_callstate ( s , l - > instance , SKINNY_OFFHOOK , sub - > callid ) ;
}
if ( skinnydebug )
ast_verbose ( " Attempting to Clear display on Skinny %s@%s \n " , l - > name , d - > name ) ;
transmit_displaymessage ( s , NULL ) ; /* clear display */
transmit_tone ( s , SKINNY_DIALTONE ) ;
if ( ! ast_ignore_pattern ( c - > context , vmexten ) ) {
transmit_tone ( s , SKINNY_SILENCE ) ;
}
if ( ast_exists_extension ( c , c - > context , l - > vmexten , 1 , l - > cid_num ) ) {
ast_copy_string ( c - > exten , l - > vmexten , sizeof ( c - > exten ) ) ;
ast_copy_string ( l - > lastnumberdialed , l - > vmexten , sizeof ( l - > lastnumberdialed ) ) ;
if ( ast_pthread_create ( & t , NULL , skinny_newcall , c ) ) {
ast_log ( LOG_WARNING , " Unable to create new call thread: %s \n " , strerror ( errno ) ) ;
ast_hangup ( c ) ;
}
break ;
}
}
2006-06-18 22:36:39 +00:00
break ;
case STIMULUS_CALLPARK :
if ( skinnydebug )
ast_verbose ( " Received Stimulus: Park Call(%d) \n " , instance ) ;
/* XXX Park the call */
break ;
case STIMULUS_FORWARDALL :
if ( skinnydebug )
ast_verbose ( " Received Stimulus: Forward All(%d) \n " , instance ) ;
/* Why is DND under FORWARDALL? */
/* Because it's the same thing. */
/* Do not disturb */
transmit_tone ( s , SKINNY_DIALTONE ) ;
if ( l - > dnd ! = 0 ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Disabling DND on %s@%s \n " , l - > name , d - > name ) ;
l - > dnd = 0 ;
transmit_lamp_indication ( s , STIMULUS_FORWARDALL , 1 , SKINNY_LAMP_ON ) ;
transmit_displaynotify ( s , " DnD disabled " , 10 ) ;
} else {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Enabling DND on %s@%s \n " , l - > name , d - > name ) ;
l - > dnd = 1 ;
transmit_lamp_indication ( s , STIMULUS_FORWARDALL , 1 , SKINNY_LAMP_OFF ) ;
transmit_displaynotify ( s , " DnD enabled " , 10 ) ;
}
break ;
case STIMULUS_FORWARDBUSY :
if ( skinnydebug )
ast_verbose ( " Received Stimulus: Forward Busy (%d) \n " , instance ) ;
break ;
case STIMULUS_FORWARDNOANSWER :
if ( skinnydebug )
ast_verbose ( " Received Stimulus: Forward No Answer (%d) \n " , instance ) ;
break ;
case STIMULUS_DISPLAY :
/* Not sure what this is */
if ( skinnydebug )
ast_verbose ( " Received Stimulus: Display(%d) \n " , instance ) ;
break ;
case STIMULUS_LINE :
if ( skinnydebug )
ast_verbose ( " Received Stimulus: Line(%d) \n " , instance ) ;
2007-02-24 02:23:43 +00:00
l = find_line_by_instance ( d , instance ) ;
2006-06-18 22:36:39 +00:00
if ( ! l ) {
return 0 ;
}
/* turn the speaker on */
transmit_speaker_mode ( s , SKINNY_SPEAKERON ) ;
transmit_ringer_mode ( s , SKINNY_RING_OFF ) ;
transmit_lamp_indication ( s , STIMULUS_LINE , l - > instance , SKINNY_LAMP_ON ) ;
l - > hookstate = SKINNY_OFFHOOK ;
2007-02-24 02:23:43 +00:00
ast_device_state_changed ( " Skinny/%s@%s " , l - > name , d - > name ) ;
2006-06-18 22:36:39 +00:00
if ( sub & & sub - > outgoing ) {
/* We're answering a ringing call */
ast_queue_control ( sub - > owner , AST_CONTROL_ANSWER ) ;
transmit_callstate ( s , l - > instance , SKINNY_OFFHOOK , sub - > callid ) ;
transmit_tone ( s , SKINNY_SILENCE ) ;
transmit_callstate ( s , l - > instance , SKINNY_CONNECTED , sub - > callid ) ;
transmit_displaypromptstatus ( s , " Connected " , 0 , l - > instance , sub - > callid ) ;
transmit_selectsoftkeys ( s , l - > instance , sub - > callid , KEYDEF_CONNECTED ) ;
start_rtp ( sub ) ;
ast_setstate ( sub - > owner , AST_STATE_UP ) ;
} else {
if ( sub & & sub - > owner ) {
2006-10-03 15:53:07 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Current subchannel [%s] already has owner \n " , sub - > owner - > name ) ;
2006-06-18 22:36:39 +00:00
} else {
c = skinny_new ( l , AST_STATE_DOWN ) ;
2007-05-11 22:52:36 +00:00
if ( c ) {
2006-06-18 22:36:39 +00:00
sub = c - > tech_pvt ;
transmit_callstate ( s , l - > instance , SKINNY_OFFHOOK , sub - > callid ) ;
if ( skinnydebug )
ast_verbose ( " Attempting to Clear display on Skinny %s@%s \n " , l - > name , d - > name ) ;
transmit_displaymessage ( s , NULL ) ; /* clear display */
transmit_tone ( s , SKINNY_DIALTONE ) ;
transmit_selectsoftkeys ( s , l - > instance , sub - > callid , KEYDEF_OFFHOOK ) ;
/* start the switch thread */
if ( ast_pthread_create ( & t , NULL , skinny_ss , c ) ) {
ast_log ( LOG_WARNING , " Unable to create switch thread: %s \n " , strerror ( errno ) ) ;
ast_hangup ( c ) ;
}
} else {
ast_log ( LOG_WARNING , " Unable to create channel for %s@%s \n " , l - > name , d - > name ) ;
}
}
}
break ;
default :
if ( skinnydebug )
ast_verbose ( " RECEIVED UNKNOWN STIMULUS: %d(%d) \n " , event , instance ) ;
break ;
}
2007-02-24 02:23:43 +00:00
ast_device_state_changed ( " Skinny/%s@%s " , l - > name , d - > name ) ;
2006-06-18 22:36:39 +00:00
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_offhook_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
struct skinny_device * d = s - > device ;
struct skinny_line * l ;
struct skinny_subchannel * sub ;
struct ast_channel * c ;
pthread_t t ;
int unknown1 ;
int unknown2 ;
unknown1 = letohl ( req - > data . offhook . unknown1 ) ;
unknown2 = letohl ( req - > data . offhook . unknown2 ) ;
sub = find_subchannel_by_instance_reference ( d , d - > lastlineinstance , d - > lastcallreference ) ;
if ( ! sub ) {
l = find_line_by_instance ( d , d - > lastlineinstance ) ;
if ( ! l ) {
return 0 ;
}
} else {
l = sub - > parent ;
}
2007-02-24 02:23:43 +00:00
transmit_ringer_mode ( s , SKINNY_RING_OFF ) ;
l - > hookstate = SKINNY_OFFHOOK ;
ast_device_state_changed ( " Skinny/%s@%s " , l - > name , d - > name ) ;
2006-09-17 22:24:27 +00:00
if ( sub & & sub - > onhold ) {
return 1 ;
}
2006-06-18 22:36:39 +00:00
transmit_lamp_indication ( s , STIMULUS_LINE , l - > instance , SKINNY_LAMP_ON ) ;
if ( sub & & sub - > outgoing ) {
/* We're answering a ringing call */
ast_queue_control ( sub - > owner , AST_CONTROL_ANSWER ) ;
transmit_callstate ( s , l - > instance , SKINNY_OFFHOOK , sub - > callid ) ;
transmit_tone ( s , SKINNY_SILENCE ) ;
transmit_callstate ( s , l - > instance , SKINNY_CONNECTED , sub - > callid ) ;
transmit_selectsoftkeys ( s , l - > instance , sub - > callid , KEYDEF_CONNECTED ) ;
start_rtp ( sub ) ;
ast_setstate ( sub - > owner , AST_STATE_UP ) ;
} else {
if ( sub & & sub - > owner ) {
2006-10-03 15:53:07 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Current sub [%s] already has owner \n " , sub - > owner - > name ) ;
2006-06-18 22:36:39 +00:00
} else {
c = skinny_new ( l , AST_STATE_DOWN ) ;
2007-05-11 22:52:36 +00:00
if ( c ) {
2006-06-18 22:36:39 +00:00
sub = c - > tech_pvt ;
transmit_callstate ( s , l - > instance , SKINNY_OFFHOOK , sub - > callid ) ;
if ( skinnydebug )
ast_verbose ( " Attempting to Clear display on Skinny %s@%s \n " , l - > name , d - > name ) ;
transmit_displaymessage ( s , NULL ) ; /* clear display */
transmit_tone ( s , SKINNY_DIALTONE ) ;
transmit_selectsoftkeys ( s , l - > instance , sub - > callid , KEYDEF_OFFHOOK ) ;
/* start the switch thread */
if ( ast_pthread_create ( & t , NULL , skinny_ss , c ) ) {
ast_log ( LOG_WARNING , " Unable to create switch thread: %s \n " , strerror ( errno ) ) ;
ast_hangup ( c ) ;
}
} else {
ast_log ( LOG_WARNING , " Unable to create channel for %s@%s \n " , l - > name , d - > name ) ;
}
}
}
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_onhook_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
struct skinny_device * d = s - > device ;
struct skinny_line * l ;
struct skinny_subchannel * sub ;
int unknown1 ;
int unknown2 ;
unknown1 = letohl ( req - > data . onhook . unknown1 ) ;
unknown2 = letohl ( req - > data . onhook . unknown2 ) ;
sub = find_subchannel_by_instance_reference ( d , d - > lastlineinstance , d - > lastcallreference ) ;
if ( ! sub ) {
return 0 ;
2006-09-17 22:24:27 +00:00
}
l = sub - > parent ;
2007-02-24 02:23:43 +00:00
if ( l - > hookstate = = SKINNY_ONHOOK ) {
/* Something else already put us back on hook */
2006-09-17 22:24:27 +00:00
return 0 ;
2006-06-18 22:36:39 +00:00
}
2007-02-24 02:23:43 +00:00
l - > hookstate = SKINNY_ONHOOK ;
2006-06-18 22:36:39 +00:00
2007-02-24 02:23:43 +00:00
ast_device_state_changed ( " Skinny/%s@%s " , l - > name , d - > name ) ;
if ( sub - > onhold ) {
2006-06-18 22:36:39 +00:00
return 0 ;
}
2007-02-24 02:23:43 +00:00
2006-06-18 22:36:39 +00:00
sub - > cxmode = SKINNY_CX_RECVONLY ;
transmit_callstate ( s , l - > instance , l - > hookstate , sub - > callid ) ;
if ( skinnydebug )
ast_verbose ( " Skinny %s@%s went on hook \n " , l - > name , d - > name ) ;
if ( l - > transfer & & ( sub - > owner & & sub - > next & & sub - > next - > owner ) & & ( ( ! sub - > outgoing ) | | ( sub - > next & & ! sub - > next - > outgoing ) ) ) {
/* We're allowed to transfer, we have two active calls and
we made at least one of the calls . Let ' s try and transfer */
#if 0
if ( ( res = attempt_transfer ( p ) ) < 0 ) {
if ( sub - > next & & sub - > next - > owner ) {
sub - > next - > alreadygone = 1 ;
ast_queue_hangup ( sub - > next - > owner , 1 ) ;
}
} else if ( res ) {
ast_log ( LOG_WARNING , " Transfer attempt failed \n " ) ;
return 0 ;
}
# endif
} else {
/* Hangup the current call */
/* If there is another active call, skinny_hangup will ring the phone with the other call */
if ( sub - > owner ) {
sub - > alreadygone = 1 ;
ast_queue_hangup ( sub - > owner ) ;
} else {
ast_log ( LOG_WARNING , " Skinny(%s@%s-%d) channel already destroyed \n " ,
l - > name , d - > name , sub - > callid ) ;
}
}
if ( ( l - > hookstate = = SKINNY_ONHOOK ) & & ( sub - > next & & ! sub - > next - > rtp ) ) {
do_housekeeping ( s ) ;
}
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_capabilities_res_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
Merged revisions 43650 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r43650 | qwell | 2006-09-26 08:33:47 -0700 (Tue, 26 Sep 2006) | 11 lines
Add proper codec support to chan_skinny. Works with at least ulaw, alaw, and g729a.
This is technically a "new feature", but there are justifications for it.
I found a bug with the recent rtp packetization changes, which caused the media setup to
fail under certain circumstances, particularly when using allow=all, or having no allow=
statements (globally or on the device).
I could have either removed the rtp packetization features, or I could add proper codec
support (which, without, I think most people would consider to be a bug anyways).
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43651 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-09-26 15:35:37 +00:00
struct skinny_device * d = s - > device ;
struct skinny_line * l ;
int count = 0 ;
int codecs = 0 ;
int i ;
count = letohl ( req - > data . caps . count ) ;
for ( i = 0 ; i < count ; i + + ) {
int acodec = 0 ;
int scodec = 0 ;
scodec = letohl ( req - > data . caps . caps [ i ] . codec ) ;
acodec = codec_skinny2ast ( scodec ) ;
if ( skinnydebug )
ast_verbose ( " Adding codec capability '%d (%d)' \n " , acodec , scodec ) ;
codecs | = acodec ;
}
d - > capability & = codecs ;
ast_verbose ( " Device capability set to '%d' \n " , d - > capability ) ;
for ( l = d - > lines ; l ; l = l - > next ) {
ast_mutex_lock ( & l - > lock ) ;
l - > capability = d - > capability ;
ast_mutex_unlock ( & l - > lock ) ;
}
2006-06-18 22:36:39 +00:00
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_speed_dial_stat_req_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
struct skinny_device * d = s - > device ;
struct skinny_speeddial * sd ;
int instance ;
instance = letohl ( req - > data . speeddialreq . speedDialNumber ) ;
2007-02-24 02:23:43 +00:00
sd = find_speeddial_by_instance ( d , instance , 0 ) ;
2006-06-18 22:36:39 +00:00
if ( ! sd ) {
return 0 ;
}
2006-09-17 21:58:04 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct speed_dial_stat_res_message ) , SPEED_DIAL_STAT_RES_MESSAGE ) ) )
2006-06-18 22:36:39 +00:00
return - 1 ;
req - > data . speeddialreq . speedDialNumber = htolel ( instance ) ;
snprintf ( req - > data . speeddial . speedDialDirNumber , sizeof ( req - > data . speeddial . speedDialDirNumber ) , sd - > exten ) ;
snprintf ( req - > data . speeddial . speedDialDisplayName , sizeof ( req - > data . speeddial . speedDialDisplayName ) , sd - > label ) ;
transmit_response ( s , req ) ;
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_line_state_req_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
struct skinny_device * d = s - > device ;
struct skinny_line * l ;
2007-02-24 02:23:43 +00:00
struct skinny_speeddial * sd = NULL ;
2006-06-18 22:36:39 +00:00
int instance ;
instance = letohl ( req - > data . line . lineNumber ) ;
ast_mutex_lock ( & devicelock ) ;
l = find_line_by_instance ( d , instance ) ;
if ( ! l ) {
2007-02-24 02:23:43 +00:00
sd = find_speeddial_by_instance ( d , instance , 1 ) ;
}
if ( ! l & & ! sd ) {
2006-06-18 22:36:39 +00:00
return 0 ;
}
ast_mutex_unlock ( & devicelock ) ;
2006-09-17 21:58:04 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct line_stat_res_message ) , LINE_STAT_RES_MESSAGE ) ) )
2006-06-18 22:36:39 +00:00
return - 1 ;
req - > data . linestat . lineNumber = letohl ( instance ) ;
2007-02-24 02:23:43 +00:00
if ( ! l ) {
memcpy ( req - > data . linestat . lineDirNumber , sd - > label , sizeof ( req - > data . linestat . lineDirNumber ) ) ;
memcpy ( req - > data . linestat . lineDisplayName , sd - > label , sizeof ( req - > data . linestat . lineDisplayName ) ) ;
} else {
memcpy ( req - > data . linestat . lineDirNumber , l - > name , sizeof ( req - > data . linestat . lineDirNumber ) ) ;
memcpy ( req - > data . linestat . lineDisplayName , l - > label , sizeof ( req - > data . linestat . lineDisplayName ) ) ;
}
2006-06-18 22:36:39 +00:00
transmit_response ( s , req ) ;
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_time_date_req_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
time_t timer ;
struct tm * cmtime ;
2006-09-17 21:58:04 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct definetimedate_message ) , DEFINETIMEDATE_MESSAGE ) ) )
2006-06-18 22:36:39 +00:00
return - 1 ;
timer = time ( NULL ) ;
cmtime = localtime ( & timer ) ;
req - > data . definetimedate . year = htolel ( cmtime - > tm_year + 1900 ) ;
req - > data . definetimedate . month = htolel ( cmtime - > tm_mon + 1 ) ;
req - > data . definetimedate . dayofweek = htolel ( cmtime - > tm_wday ) ;
req - > data . definetimedate . day = htolel ( cmtime - > tm_mday ) ;
req - > data . definetimedate . hour = htolel ( cmtime - > tm_hour ) ;
req - > data . definetimedate . minute = htolel ( cmtime - > tm_min ) ;
req - > data . definetimedate . seconds = htolel ( cmtime - > tm_sec ) ;
transmit_response ( s , req ) ;
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_button_template_req_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
struct skinny_device * d = s - > device ;
struct skinny_line * l ;
int i ;
struct skinny_speeddial * sd ;
2006-09-17 21:58:04 +00:00
struct button_definition_template btn [ 42 ] ;
2006-06-18 22:36:39 +00:00
int lineInstance = 1 ;
int speeddialInstance = 1 ;
int buttonCount = 0 ;
2006-09-17 21:58:04 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct button_template_res_message ) , BUTTON_TEMPLATE_RES_MESSAGE ) ) )
2006-07-18 21:19:59 +00:00
return - 1 ;
2006-06-18 22:36:39 +00:00
memset ( & btn , 0 , sizeof ( btn ) ) ;
get_button_template ( s , btn ) ;
for ( i = 0 ; i < 42 ; i + + ) {
int btnSet = 0 ;
switch ( btn [ i ] . buttonDefinition ) {
2007-02-24 02:23:43 +00:00
case BT_CUST_LINE :
/* assume failure */
req - > data . buttontemplate . definition [ i ] . buttonDefinition = BT_NONE ;
req - > data . buttontemplate . definition [ i ] . instanceNumber = htolel ( 0 ) ;
for ( l = d - > lines ; l ; l = l - > next ) {
if ( l - > instance = = lineInstance ) {
ast_verbose ( " Adding button: %d, %d \n " , BT_LINE , lineInstance ) ;
req - > data . buttontemplate . definition [ i ] . buttonDefinition = BT_LINE ;
req - > data . buttontemplate . definition [ i ] . instanceNumber = htolel ( lineInstance ) ;
lineInstance + + ;
buttonCount + + ;
btnSet = 1 ;
break ;
}
}
if ( ! btnSet ) {
for ( sd = d - > speeddials ; sd ; sd = sd - > next ) {
if ( sd - > isHint & & sd - > instance = = lineInstance ) {
ast_verbose ( " Adding button: %d, %d \n " , BT_LINE , lineInstance ) ;
req - > data . buttontemplate . definition [ i ] . buttonDefinition = BT_LINE ;
req - > data . buttontemplate . definition [ i ] . instanceNumber = htolel ( lineInstance ) ;
lineInstance + + ;
buttonCount + + ;
btnSet = 1 ;
break ;
}
}
}
break ;
2006-06-18 22:36:39 +00:00
case BT_CUST_LINESPEEDDIAL :
/* assume failure */
2006-06-23 23:22:57 +00:00
req - > data . buttontemplate . definition [ i ] . buttonDefinition = BT_NONE ;
2006-06-18 22:36:39 +00:00
req - > data . buttontemplate . definition [ i ] . instanceNumber = htolel ( 0 ) ;
for ( l = d - > lines ; l ; l = l - > next ) {
if ( l - > instance = = lineInstance ) {
ast_verbose ( " Adding button: %d, %d \n " , BT_LINE , lineInstance ) ;
2006-06-23 23:22:57 +00:00
req - > data . buttontemplate . definition [ i ] . buttonDefinition = BT_LINE ;
req - > data . buttontemplate . definition [ i ] . instanceNumber = htolel ( lineInstance ) ;
lineInstance + + ;
2006-06-18 22:36:39 +00:00
buttonCount + + ;
btnSet = 1 ;
break ;
}
}
if ( ! btnSet ) {
for ( sd = d - > speeddials ; sd ; sd = sd - > next ) {
2007-02-24 02:23:43 +00:00
if ( sd - > isHint & & sd - > instance = = lineInstance ) {
ast_verbose ( " Adding button: %d, %d \n " , BT_LINE , lineInstance ) ;
req - > data . buttontemplate . definition [ i ] . buttonDefinition = BT_LINE ;
req - > data . buttontemplate . definition [ i ] . instanceNumber = htolel ( lineInstance ) ;
lineInstance + + ;
buttonCount + + ;
btnSet = 1 ;
break ;
} else if ( ! sd - > isHint & & sd - > instance = = speeddialInstance ) {
2006-06-18 22:36:39 +00:00
ast_verbose ( " Adding button: %d, %d \n " , BT_SPEEDDIAL , speeddialInstance ) ;
2006-06-23 23:22:57 +00:00
req - > data . buttontemplate . definition [ i ] . buttonDefinition = BT_SPEEDDIAL ;
req - > data . buttontemplate . definition [ i ] . instanceNumber = htolel ( speeddialInstance ) ;
speeddialInstance + + ;
2006-06-18 22:36:39 +00:00
buttonCount + + ;
btnSet = 1 ;
break ;
}
}
}
break ;
case BT_LINE :
req - > data . buttontemplate . definition [ i ] . buttonDefinition = htolel ( BT_NONE ) ;
req - > data . buttontemplate . definition [ i ] . instanceNumber = htolel ( 0 ) ;
for ( l = d - > lines ; l ; l = l - > next ) {
if ( l - > instance = = lineInstance ) {
ast_verbose ( " Adding button: %d, %d \n " , BT_LINE , lineInstance ) ;
2006-06-23 23:22:57 +00:00
req - > data . buttontemplate . definition [ i ] . buttonDefinition = BT_LINE ;
req - > data . buttontemplate . definition [ i ] . instanceNumber = htolel ( lineInstance ) ;
lineInstance + + ;
2006-06-18 22:36:39 +00:00
buttonCount + + ;
btnSet = 1 ;
break ;
}
}
break ;
case BT_SPEEDDIAL :
req - > data . buttontemplate . definition [ i ] . buttonDefinition = BT_NONE ;
req - > data . buttontemplate . definition [ i ] . instanceNumber = 0 ;
for ( sd = d - > speeddials ; sd ; sd = sd - > next ) {
2007-02-24 02:23:43 +00:00
if ( ! sd - > isHint & & sd - > instance = = speeddialInstance ) {
2006-06-18 22:36:39 +00:00
ast_verbose ( " Adding button: %d, %d \n " , BT_SPEEDDIAL , speeddialInstance ) ;
2006-06-23 23:22:57 +00:00
req - > data . buttontemplate . definition [ i ] . buttonDefinition = BT_SPEEDDIAL ;
2007-02-24 02:23:43 +00:00
req - > data . buttontemplate . definition [ i ] . instanceNumber = htolel ( speeddialInstance - 1 ) ;
2006-06-23 23:22:57 +00:00
speeddialInstance + + ;
2006-06-18 22:36:39 +00:00
buttonCount + + ;
btnSet = 1 ;
break ;
}
}
break ;
case BT_NONE :
break ;
default :
ast_verbose ( " Adding button: %d, %d \n " , btn [ i ] . buttonDefinition , 0 ) ;
req - > data . buttontemplate . definition [ i ] . buttonDefinition = htolel ( btn [ i ] . buttonDefinition ) ;
req - > data . buttontemplate . definition [ i ] . instanceNumber = htolel ( 0 ) ;
buttonCount + + ;
btnSet = 1 ;
break ;
}
}
req - > data . buttontemplate . buttonOffset = htolel ( 0 ) ;
req - > data . buttontemplate . buttonCount = htolel ( buttonCount ) ;
req - > data . buttontemplate . totalButtonCount = htolel ( buttonCount ) ;
if ( skinnydebug )
ast_verbose ( " Sending %d template to %s \n " ,
d - > type ,
d - > name ) ;
transmit_response ( s , req ) ;
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_version_req_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
struct skinny_device * d = s - > device ;
2006-09-17 21:58:04 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct version_res_message ) , VERSION_RES_MESSAGE ) ) )
2006-06-18 22:36:39 +00:00
return - 1 ;
snprintf ( req - > data . version . version , sizeof ( req - > data . version . version ) , d - > version_id ) ;
transmit_response ( s , req ) ;
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_server_request_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
struct skinny_device * d = s - > device ;
2006-09-17 21:58:04 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct server_res_message ) , SERVER_RES_MESSAGE ) ) )
2006-06-18 22:36:39 +00:00
return - 1 ;
memcpy ( req - > data . serverres . server [ 0 ] . serverName , ourhost ,
sizeof ( req - > data . serverres . server [ 0 ] . serverName ) ) ;
req - > data . serverres . serverListenPort [ 0 ] = htolel ( ourport ) ;
req - > data . serverres . serverIpAddr [ 0 ] = htolel ( d - > ourip . s_addr ) ;
transmit_response ( s , req ) ;
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_alarm_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
/* no response necessary */
if ( skinnydebug )
ast_verbose ( " Received Alarm Message: %s \n " , req - > data . alarm . displayMessage ) ;
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_open_receive_channel_ack_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
struct skinny_device * d = s - > device ;
struct skinny_line * l ;
struct skinny_subchannel * sub ;
Merged revisions 43650 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r43650 | qwell | 2006-09-26 08:33:47 -0700 (Tue, 26 Sep 2006) | 11 lines
Add proper codec support to chan_skinny. Works with at least ulaw, alaw, and g729a.
This is technically a "new feature", but there are justifications for it.
I found a bug with the recent rtp packetization changes, which caused the media setup to
fail under certain circumstances, particularly when using allow=all, or having no allow=
statements (globally or on the device).
I could have either removed the rtp packetization features, or I could add proper codec
support (which, without, I think most people would consider to be a bug anyways).
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43651 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-09-26 15:35:37 +00:00
struct ast_format_list fmt ;
2006-06-18 22:36:39 +00:00
struct sockaddr_in sin ;
struct sockaddr_in us ;
uint32_t addr ;
int port ;
int status ;
int passthruid ;
status = letohl ( req - > data . openreceivechannelack . status ) ;
if ( status ) {
ast_log ( LOG_ERROR , " Open Receive Channel Failure \n " ) ;
return 0 ;
}
addr = letohl ( req - > data . openreceivechannelack . ipAddr ) ;
port = letohl ( req - > data . openreceivechannelack . port ) ;
passthruid = letohl ( req - > data . openreceivechannelack . passThruId ) ;
sin . sin_family = AF_INET ;
sin . sin_addr . s_addr = addr ;
sin . sin_port = htons ( port ) ;
sub = find_subchannel_by_reference ( d , passthruid ) ;
if ( ! sub )
return 0 ;
l = sub - > parent ;
if ( sub - > rtp ) {
ast_rtp_set_peer ( sub - > rtp , & sin ) ;
ast_rtp_get_us ( sub - > rtp , & us ) ;
} else {
ast_log ( LOG_ERROR , " No RTP structure, this is very bad \n " ) ;
return 0 ;
}
if ( skinnydebug ) {
2006-07-21 17:31:28 +00:00
ast_verbose ( " ipaddr = %s:%d \n " , ast_inet_ntoa ( sin . sin_addr ) , ntohs ( sin . sin_port ) ) ;
ast_verbose ( " ourip = %s:%d \n " , ast_inet_ntoa ( d - > ourip ) , ntohs ( us . sin_port ) ) ;
2006-06-18 22:36:39 +00:00
}
2006-09-17 21:58:04 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct start_media_transmission_message ) , START_MEDIA_TRANSMISSION_MESSAGE ) ) )
2006-06-18 22:36:39 +00:00
return - 1 ;
Merged revisions 43650 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r43650 | qwell | 2006-09-26 08:33:47 -0700 (Tue, 26 Sep 2006) | 11 lines
Add proper codec support to chan_skinny. Works with at least ulaw, alaw, and g729a.
This is technically a "new feature", but there are justifications for it.
I found a bug with the recent rtp packetization changes, which caused the media setup to
fail under certain circumstances, particularly when using allow=all, or having no allow=
statements (globally or on the device).
I could have either removed the rtp packetization features, or I could add proper codec
support (which, without, I think most people would consider to be a bug anyways).
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43651 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-09-26 15:35:37 +00:00
fmt = ast_codec_pref_getsize ( & l - > prefs , ast_best_codec ( l - > capability ) ) ;
if ( skinnydebug )
ast_verbose ( " Setting payloadType to '%d' (%d ms) \n " , fmt . bits , fmt . cur_ms ) ;
2006-09-17 23:04:48 +00:00
req - > data . startmedia . conferenceId = htolel ( 0 ) ;
2006-06-18 22:36:39 +00:00
req - > data . startmedia . passThruPartyId = htolel ( sub - > callid ) ;
req - > data . startmedia . remoteIp = htolel ( d - > ourip . s_addr ) ;
req - > data . startmedia . remotePort = htolel ( ntohs ( us . sin_port ) ) ;
Merged revisions 43650 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r43650 | qwell | 2006-09-26 08:33:47 -0700 (Tue, 26 Sep 2006) | 11 lines
Add proper codec support to chan_skinny. Works with at least ulaw, alaw, and g729a.
This is technically a "new feature", but there are justifications for it.
I found a bug with the recent rtp packetization changes, which caused the media setup to
fail under certain circumstances, particularly when using allow=all, or having no allow=
statements (globally or on the device).
I could have either removed the rtp packetization features, or I could add proper codec
support (which, without, I think most people would consider to be a bug anyways).
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43651 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-09-26 15:35:37 +00:00
req - > data . startmedia . packetSize = htolel ( fmt . cur_ms ) ;
req - > data . startmedia . payloadType = htolel ( codec_ast2skinny ( fmt . bits ) ) ;
2006-06-18 22:36:39 +00:00
req - > data . startmedia . qualifier . precedence = htolel ( 127 ) ;
2006-09-17 23:04:48 +00:00
req - > data . startmedia . qualifier . vad = htolel ( 0 ) ;
req - > data . startmedia . qualifier . packets = htolel ( 0 ) ;
req - > data . startmedia . qualifier . bitRate = htolel ( 0 ) ;
2006-06-18 22:36:39 +00:00
transmit_response ( s , req ) ;
2006-09-17 23:04:48 +00:00
2006-06-18 22:36:39 +00:00
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_soft_key_set_req_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
int i ;
int x ;
int y ;
2006-09-17 21:58:04 +00:00
const struct soft_key_definitions * softkeymode = soft_key_default_definitions ;
2006-06-18 22:36:39 +00:00
2006-09-17 21:58:04 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct soft_key_set_res_message ) , SOFT_KEY_SET_RES_MESSAGE ) ) )
2006-06-18 22:36:39 +00:00
return - 1 ;
req - > data . softkeysets . softKeySetOffset = htolel ( 0 ) ;
req - > data . softkeysets . softKeySetCount = htolel ( 11 ) ;
req - > data . softkeysets . totalSoftKeySetCount = htolel ( 11 ) ;
2006-09-17 21:58:04 +00:00
for ( x = 0 ; x < sizeof ( soft_key_default_definitions ) / sizeof ( struct soft_key_definitions ) ; x + + ) {
2006-06-18 22:36:39 +00:00
const uint8_t * defaults = softkeymode - > defaults ;
/* XXX I wanted to get the size of the array dynamically, but that wasn't wanting to work.
This will have to do for now . */
for ( y = 0 ; y < softkeymode - > count ; y + + ) {
2006-09-17 21:58:04 +00:00
for ( i = 0 ; i < ( sizeof ( soft_key_template_default ) / sizeof ( struct soft_key_template_definition ) ) ; i + + ) {
2006-06-18 22:36:39 +00:00
if ( defaults [ y ] = = i + 1 ) {
req - > data . softkeysets . softKeySetDefinition [ softkeymode - > mode ] . softKeyTemplateIndex [ y ] = htolel ( i + 1 ) ;
}
}
}
softkeymode + + ;
}
transmit_response ( s , req ) ;
transmit_selectsoftkeys ( s , 0 , 0 , KEYDEF_ONHOOK ) ;
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_soft_key_event_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
struct skinny_device * d = s - > device ;
struct skinny_line * l ;
struct skinny_subchannel * sub = NULL ;
struct ast_channel * c ;
pthread_t t ;
int event ;
int instance ;
int reference ;
event = letohl ( req - > data . softkeyeventmessage . softKeyEvent ) ;
instance = letohl ( req - > data . softkeyeventmessage . instance ) ;
reference = letohl ( req - > data . softkeyeventmessage . reference ) ;
if ( instance ) {
l = find_line_by_instance ( d , instance ) ;
if ( reference ) {
sub = find_subchannel_by_instance_reference ( d , instance , reference ) ;
} else {
sub = find_subchannel_by_instance_reference ( d , instance , d - > lastcallreference ) ;
}
} else {
l = find_line_by_instance ( d , d - > lastlineinstance ) ;
}
if ( ! l ) {
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: %d(%d) \n " , event , instance ) ;
return 0 ;
}
2007-02-24 02:23:43 +00:00
ast_device_state_changed ( " Skinny/%s@%s " , l - > name , d - > name ) ;
2006-06-18 22:36:39 +00:00
switch ( event ) {
case SOFTKEY_NONE :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: None(%d) \n " , instance ) ;
break ;
case SOFTKEY_REDIAL :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Redial(%d) \n " , instance ) ;
2006-07-14 20:14:38 +00:00
if ( ! sub | | ! sub - > owner ) {
2006-06-18 22:36:39 +00:00
c = skinny_new ( l , AST_STATE_DOWN ) ;
} else {
c = sub - > owner ;
}
2007-05-11 22:52:36 +00:00
if ( ! c ) {
2006-07-14 20:14:38 +00:00
ast_log ( LOG_WARNING , " Unable to create channel for %s@%s \n " , l - > name , d - > name ) ;
} else {
2006-06-18 22:36:39 +00:00
sub = c - > tech_pvt ;
2007-05-11 22:52:36 +00:00
if ( l - > hookstate = = SKINNY_ONHOOK ) {
l - > hookstate = SKINNY_OFFHOOK ;
transmit_speaker_mode ( s , SKINNY_SPEAKERON ) ;
transmit_callstate ( s , l - > instance , SKINNY_OFFHOOK , sub - > callid ) ;
}
2006-07-14 20:14:38 +00:00
if ( skinnydebug )
ast_verbose ( " Attempting to Clear display on Skinny %s@%s \n " , l - > name , d - > name ) ;
transmit_displaymessage ( s , NULL ) ; /* clear display */
transmit_tone ( s , SKINNY_DIALTONE ) ;
2006-06-18 22:36:39 +00:00
if ( ast_strlen_zero ( l - > lastnumberdialed ) ) {
ast_log ( LOG_WARNING , " Attempted redial, but no previously dialed number found. \n " ) ;
2007-02-24 02:04:34 +00:00
break ;
2006-06-18 22:36:39 +00:00
}
if ( ! ast_ignore_pattern ( c - > context , l - > lastnumberdialed ) ) {
transmit_tone ( s , SKINNY_SILENCE ) ;
}
2006-07-14 20:14:38 +00:00
ast_copy_string ( c - > exten , l - > lastnumberdialed , sizeof ( c - > exten ) ) ;
if ( ast_pthread_create ( & t , NULL , skinny_newcall , c ) ) {
ast_log ( LOG_WARNING , " Unable to create new call thread: %s \n " , strerror ( errno ) ) ;
ast_hangup ( c ) ;
2006-06-18 22:36:39 +00:00
}
}
break ;
2007-05-11 22:52:36 +00:00
case SOFTKEY_NEWCALL : /* Actually the DIAL softkey */
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: New Call(%d) \n " , instance ) ;
2007-05-11 22:52:36 +00:00
if ( ! sub | | ! sub - > owner ) {
c = skinny_new ( l , AST_STATE_DOWN ) ;
} else {
c = sub - > owner ;
}
2005-11-16 21:07:52 +00:00
2007-05-11 22:52:36 +00:00
/* transmit_ringer_mode(s,SKINNY_RING_OFF);
transmit_lamp_indication ( s , STIMULUS_LINE , l - > instance , SKINNY_LAMP_ON ) ; */
/* l->hookstate = SKINNY_OFFHOOK; */
if ( ! c ) {
ast_log ( LOG_WARNING , " Unable to create channel for %s@%s \n " , l - > name , d - > name ) ;
} else {
sub = c - > tech_pvt ;
if ( l - > hookstate = = SKINNY_ONHOOK ) {
l - > hookstate = SKINNY_OFFHOOK ;
transmit_speaker_mode ( s , SKINNY_SPEAKERON ) ;
transmit_callstate ( s , l - > instance , SKINNY_OFFHOOK , sub - > callid ) ;
}
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
ast_verbose ( " Attempting to Clear display on Skinny %s@%s \n " , l - > name , d - > name ) ;
transmit_displaymessage ( s , NULL ) ; /* clear display */
2005-02-25 17:43:10 +00:00
transmit_tone ( s , SKINNY_DIALTONE ) ;
2006-06-18 22:36:39 +00:00
transmit_selectsoftkeys ( s , l - > instance , sub - > callid , KEYDEF_OFFHOOK ) ;
2007-05-11 22:52:36 +00:00
/* start the switch thread */
if ( ast_pthread_create ( & t , NULL , skinny_ss , c ) ) {
ast_log ( LOG_WARNING , " Unable to create switch thread: %s \n " , strerror ( errno ) ) ;
ast_hangup ( c ) ;
2004-01-12 02:19:25 +00:00
}
2003-09-11 19:44:48 +00:00
}
break ;
2006-06-18 22:36:39 +00:00
case SOFTKEY_HOLD :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Hold(%d) \n " , instance ) ;
2006-09-17 22:24:27 +00:00
if ( sub ) {
if ( sub - > onhold ) {
skinny_unhold ( sub ) ;
} else {
skinny_hold ( sub ) ;
}
}
2003-09-11 19:44:48 +00:00
break ;
2006-06-18 22:36:39 +00:00
case SOFTKEY_TRNSFER :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Transfer(%d) \n " , instance ) ;
transmit_tone ( s , SKINNY_DIALTONE ) ;
/* XXX figure out how to transfer */
2003-09-11 19:44:48 +00:00
break ;
2006-06-18 22:36:39 +00:00
case SOFTKEY_CFWDALL :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Forward All(%d) \n " , instance ) ;
2005-02-25 17:43:10 +00:00
2006-06-18 22:36:39 +00:00
/* Do not disturb */
transmit_tone ( s , SKINNY_DIALTONE ) ;
if ( l - > dnd ! = 0 ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Disabling DND on %s@%s \n " , l - > name , d - > name ) ;
l - > dnd = 0 ;
transmit_lamp_indication ( s , STIMULUS_FORWARDALL , 1 , SKINNY_LAMP_ON ) ;
transmit_displaynotify ( s , " DnD disabled " , 10 ) ;
} else {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Enabling DND on %s@%s \n " , l - > name , d - > name ) ;
l - > dnd = 1 ;
transmit_lamp_indication ( s , STIMULUS_FORWARDALL , 1 , SKINNY_LAMP_OFF ) ;
transmit_displaynotify ( s , " DnD enabled " , 10 ) ;
2005-02-25 17:43:10 +00:00
}
2003-09-11 19:44:48 +00:00
break ;
2006-06-18 22:36:39 +00:00
case SOFTKEY_CFWDBUSY :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Forward Busy (%d) \n " , instance ) ;
2003-09-11 19:44:48 +00:00
break ;
2006-06-18 22:36:39 +00:00
case SOFTKEY_CFWDNOANSWER :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Forward No Answer (%d) \n " , instance ) ;
2003-09-11 19:44:48 +00:00
break ;
2006-06-18 22:36:39 +00:00
case SOFTKEY_BKSPC :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Backspace(%d) \n " , instance ) ;
2003-09-11 19:44:48 +00:00
break ;
2006-06-18 22:36:39 +00:00
case SOFTKEY_ENDCALL :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: End Call(%d) \n " , instance ) ;
if ( l - > hookstate = = SKINNY_ONHOOK ) {
/* Something else already put us back on hook */
break ;
}
if ( sub ) {
sub - > cxmode = SKINNY_CX_RECVONLY ;
l - > hookstate = SKINNY_ONHOOK ;
transmit_callstate ( s , l - > instance , l - > hookstate , sub - > callid ) ;
if ( skinnydebug )
ast_verbose ( " Skinny %s@%s went on hook \n " , l - > name , d - > name ) ;
if ( l - > transfer & & ( sub - > owner & & sub - > next & & sub - > next - > owner ) & & ( ( ! sub - > outgoing ) | | ( sub - > next & & ! sub - > next - > outgoing ) ) ) {
/* We're allowed to transfer, we have two active calls and
we made at least one of the calls . Let ' s try and transfer */
2005-02-25 17:43:10 +00:00
#if 0
2006-06-18 22:36:39 +00:00
if ( ( res = attempt_transfer ( p ) ) < 0 ) {
if ( sub - > next & & sub - > next - > owner ) {
sub - > next - > alreadygone = 1 ;
ast_queue_hangup ( sub - > next - > owner , 1 ) ;
}
} else if ( res ) {
ast_log ( LOG_WARNING , " Transfer attempt failed \n " ) ;
2007-02-24 02:04:34 +00:00
break ;
2006-06-18 22:36:39 +00:00
}
2006-03-22 20:45:00 +00:00
# endif
2006-06-18 22:36:39 +00:00
} else {
/* Hangup the current call */
/* If there is another active call, skinny_hangup will ring the phone with the other call */
if ( sub - > owner ) {
sub - > alreadygone = 1 ;
ast_queue_hangup ( sub - > owner ) ;
} else {
ast_log ( LOG_WARNING , " Skinny(%s@%s-%d) channel already destroyed \n " ,
l - > name , d - > name , sub - > callid ) ;
}
}
if ( ( l - > hookstate = = SKINNY_ONHOOK ) & & ( sub - > next & & ! sub - > next - > rtp ) ) {
do_housekeeping ( s ) ;
}
2004-05-12 21:30:23 +00:00
}
2003-09-11 19:44:48 +00:00
break ;
2006-06-18 22:36:39 +00:00
case SOFTKEY_RESUME :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Resume(%d) \n " , instance ) ;
2003-09-11 19:44:48 +00:00
break ;
2006-06-18 22:36:39 +00:00
case SOFTKEY_ANSWER :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Answer(%d) \n " , instance ) ;
2003-09-13 23:30:30 +00:00
transmit_ringer_mode ( s , SKINNY_RING_OFF ) ;
2006-06-18 22:36:39 +00:00
transmit_lamp_indication ( s , STIMULUS_LINE , l - > instance , SKINNY_LAMP_ON ) ;
2006-03-22 20:45:00 +00:00
2006-06-18 22:36:39 +00:00
l - > hookstate = SKINNY_OFFHOOK ;
if ( sub & & sub - > outgoing ) {
2005-06-02 09:11:46 +00:00
/* We're answering a ringing call */
ast_queue_control ( sub - > owner , AST_CONTROL_ANSWER ) ;
2006-06-18 22:36:39 +00:00
transmit_callstate ( s , l - > instance , SKINNY_OFFHOOK , sub - > callid ) ;
2004-05-12 21:30:23 +00:00
transmit_tone ( s , SKINNY_SILENCE ) ;
2006-06-18 22:36:39 +00:00
transmit_callstate ( s , l - > instance , SKINNY_CONNECTED , sub - > callid ) ;
transmit_selectsoftkeys ( s , l - > instance , sub - > callid , KEYDEF_CONNECTED ) ;
2005-06-02 09:11:46 +00:00
start_rtp ( sub ) ;
2004-05-12 21:30:23 +00:00
ast_setstate ( sub - > owner , AST_STATE_UP ) ;
}
2003-09-11 19:44:48 +00:00
break ;
2006-06-18 22:36:39 +00:00
case SOFTKEY_INFO :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Info(%d) \n " , instance ) ;
break ;
case SOFTKEY_CONFRN :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Transfer(%d) \n " , instance ) ;
transmit_tone ( s , SKINNY_DIALTONE ) ;
/* XXX determine the best way to pull off a conference. Meetme? */
break ;
case SOFTKEY_PARK :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Park Call(%d) \n " , instance ) ;
/* XXX Park the call */
break ;
case SOFTKEY_JOIN :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Join(%d) \n " , instance ) ;
break ;
case SOFTKEY_MEETME :
/* XXX How is this different from CONFRN? */
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Meetme(%d) \n " , instance ) ;
break ;
case SOFTKEY_PICKUP :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: None(%d) \n " , instance ) ;
break ;
case SOFTKEY_GPICKUP :
if ( skinnydebug )
ast_verbose ( " Received Softkey Event: Group Pickup (%d) \n " , instance ) ;
break ;
default :
if ( skinnydebug )
ast_verbose ( " Received unknown Softkey Event: %d(%d) \n " , event , instance ) ;
break ;
}
2007-02-24 02:23:43 +00:00
ast_device_state_changed ( " Skinny/%s@%s " , l - > name , d - > name ) ;
2006-06-18 22:36:39 +00:00
return 1 ;
}
2005-06-02 09:11:46 +00:00
2006-09-17 21:58:04 +00:00
static int handle_unregister_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
return skinny_unregister ( req , s ) ;
}
2006-09-17 21:58:04 +00:00
static int handle_soft_key_template_req_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
2006-09-17 21:58:04 +00:00
if ( ! ( req = req_alloc ( sizeof ( struct soft_key_template_res_message ) , SOFT_KEY_TEMPLATE_RES_MESSAGE ) ) )
2006-06-18 22:36:39 +00:00
return - 1 ;
req - > data . softkeytemplate . softKeyOffset = htolel ( 0 ) ;
2006-09-17 21:58:04 +00:00
req - > data . softkeytemplate . softKeyCount = htolel ( sizeof ( soft_key_template_default ) / sizeof ( struct soft_key_template_definition ) ) ;
req - > data . softkeytemplate . totalSoftKeyCount = htolel ( sizeof ( soft_key_template_default ) / sizeof ( struct soft_key_template_definition ) ) ;
2006-06-18 22:36:39 +00:00
memcpy ( req - > data . softkeytemplate . softKeyTemplateDefinition ,
soft_key_template_default ,
sizeof ( soft_key_template_default ) ) ;
transmit_response ( s , req ) ;
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_headset_status_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
/* XXX umm...okay? Why do I care? */
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_register_available_lines_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
/* XXX I have no clue what this is for, but my phone was sending it, so... */
return 1 ;
}
2006-09-17 21:58:04 +00:00
static int handle_message ( struct skinny_req * req , struct skinnysession * s )
2006-06-18 22:36:39 +00:00
{
int res = 0 ;
if ( ( ! s - > device ) & & ( letohl ( req - > e ) ! = REGISTER_MESSAGE & & letohl ( req - > e ) ! = ALARM_MESSAGE ) ) {
ast_log ( LOG_WARNING , " Client sent message #%d without first registering. \n " , req - > e ) ;
free ( req ) ;
return 0 ;
}
switch ( letohl ( req - > e ) ) {
case KEEP_ALIVE_MESSAGE :
res = handle_keep_alive_message ( req , s ) ;
break ;
case REGISTER_MESSAGE :
if ( skinnydebug )
ast_verbose ( " Device %s is attempting to register \n " , req - > data . reg . name ) ;
res = handle_register_message ( req , s ) ;
break ;
case IP_PORT_MESSAGE :
res = handle_ip_port_message ( req , s ) ;
2005-06-02 09:11:46 +00:00
break ;
2003-09-11 19:44:48 +00:00
case KEYPAD_BUTTON_MESSAGE :
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
ast_verbose ( " Collected digit: [%d] \n " , letohl ( req - > data . keypad . button ) ) ;
2007-06-01 19:42:27 +00:00
struct skinny_device * d = s - > device ;
struct skinny_subchannel * sub ;
int lineInstance ;
int callReference ;
lineInstance = letohl ( req - > data . keypad . lineInstance ) ;
callReference = letohl ( req - > data . keypad . callReference ) ;
sub = find_subchannel_by_instance_reference ( d , lineInstance , callReference ) ;
if ( sub & & ( sub - > owner - > _state < AST_STATE_UP ) ) {
char dgt ;
int digit = letohl ( req - > data . keypad . button ) ;
if ( digit = = 14 ) {
dgt = ' * ' ;
} else if ( digit = = 15 ) {
dgt = ' # ' ;
} else if ( digit > = 0 & & digit < = 9 ) {
dgt = ' 0 ' + digit ;
} else {
/* digit=10-13 (A,B,C,D ?), or
* digit is bad value
*
* probably should not end up here , but set
* value for backward compatibility , and log
* a warning .
*/
dgt = ' 0 ' + digit ;
ast_log ( LOG_WARNING , " Unsupported digit %d \n " , digit ) ;
}
d - > exten [ strlen ( d - > exten ) ] = dgt ;
d - > exten [ strlen ( d - > exten ) + 1 ] = ' \0 ' ;
} else
res = handle_keypad_button_message ( req , s ) ;
2006-06-18 22:36:39 +00:00
break ;
case STIMULUS_MESSAGE :
res = handle_stimulus_message ( req , s ) ;
break ;
case OFFHOOK_MESSAGE :
res = handle_offhook_message ( req , s ) ;
break ;
case ONHOOK_MESSAGE :
res = handle_onhook_message ( req , s ) ;
break ;
case CAPABILITIES_RES_MESSAGE :
if ( skinnydebug )
ast_verbose ( " Received CapabilitiesRes \n " ) ;
res = handle_capabilities_res_message ( req , s ) ;
break ;
case SPEED_DIAL_STAT_REQ_MESSAGE :
if ( skinnydebug )
ast_verbose ( " Received SpeedDialStatRequest \n " ) ;
res = handle_speed_dial_stat_req_message ( req , s ) ;
break ;
case LINE_STATE_REQ_MESSAGE :
res = handle_line_state_req_message ( req , s ) ;
break ;
case TIME_DATE_REQ_MESSAGE :
if ( skinnydebug )
ast_verbose ( " Received Time/Date Request \n " ) ;
res = handle_time_date_req_message ( req , s ) ;
break ;
case BUTTON_TEMPLATE_REQ_MESSAGE :
if ( skinnydebug )
ast_verbose ( " Buttontemplate requested \n " ) ;
res = handle_button_template_req_message ( req , s ) ;
break ;
case VERSION_REQ_MESSAGE :
if ( skinnydebug )
ast_verbose ( " Version Request \n " ) ;
res = handle_version_req_message ( req , s ) ;
break ;
case SERVER_REQUEST_MESSAGE :
if ( skinnydebug )
ast_verbose ( " Received Server Request \n " ) ;
res = handle_server_request_message ( req , s ) ;
break ;
case ALARM_MESSAGE :
res = handle_alarm_message ( req , s ) ;
2003-09-11 19:44:48 +00:00
break ;
2006-04-17 01:17:03 +00:00
case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE :
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
2006-04-17 01:17:03 +00:00
ast_verbose ( " Received Open Receive Channel Ack \n " ) ;
2006-06-18 22:36:39 +00:00
res = handle_open_receive_channel_ack_message ( req , s ) ;
break ;
case SOFT_KEY_SET_REQ_MESSAGE :
if ( skinnydebug )
ast_verbose ( " Received SoftKeySetReq \n " ) ;
res = handle_soft_key_set_req_message ( req , s ) ;
break ;
case SOFT_KEY_EVENT_MESSAGE :
res = handle_soft_key_event_message ( req , s ) ;
break ;
case UNREGISTER_MESSAGE :
if ( skinnydebug )
ast_verbose ( " Received Unregister Request \n " ) ;
res = handle_unregister_message ( req , s ) ;
break ;
case SOFT_KEY_TEMPLATE_REQ_MESSAGE :
if ( skinnydebug )
ast_verbose ( " Received SoftKey Template Request \n " ) ;
res = handle_soft_key_template_req_message ( req , s ) ;
break ;
case HEADSET_STATUS_MESSAGE :
res = handle_headset_status_message ( req , s ) ;
break ;
case REGISTER_AVAILABLE_LINES_MESSAGE :
res = handle_register_available_lines_message ( req , s ) ;
2006-03-22 20:45:00 +00:00
break ;
2003-09-11 19:44:48 +00:00
default :
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
2006-04-06 16:50:33 +00:00
ast_verbose ( " RECEIVED UNKNOWN MESSAGE TYPE: %x \n " , letohl ( req - > e ) ) ;
2003-09-11 19:44:48 +00:00
break ;
}
2006-06-18 22:36:39 +00:00
if ( res > = 0 & & req )
free ( req ) ;
return res ;
2003-09-11 19:44:48 +00:00
}
static void destroy_session ( struct skinnysession * s )
{
struct skinnysession * cur , * prev = NULL ;
ast_mutex_lock ( & sessionlock ) ;
cur = sessions ;
while ( cur ) {
2005-11-16 21:07:52 +00:00
if ( cur = = s ) {
2003-09-11 19:44:48 +00:00
break ;
2005-11-16 21:07:52 +00:00
}
2003-09-11 19:44:48 +00:00
prev = cur ;
cur = cur - > next ;
}
if ( cur ) {
2005-11-16 21:07:52 +00:00
if ( prev ) {
2003-09-11 19:44:48 +00:00
prev - > next = cur - > next ;
2005-11-16 21:07:52 +00:00
} else {
2003-09-11 19:44:48 +00:00
sessions = cur - > next ;
2005-11-16 21:07:52 +00:00
}
if ( s - > fd > - 1 ) {
2003-09-11 19:44:48 +00:00
close ( s - > fd ) ;
2005-11-16 21:07:52 +00:00
}
2004-06-22 17:42:14 +00:00
ast_mutex_destroy ( & s - > lock ) ;
2003-09-11 19:44:48 +00:00
free ( s ) ;
2005-11-16 21:07:52 +00:00
} else {
2005-04-13 23:33:47 +00:00
ast_log ( LOG_WARNING , " Trying to delete nonexistent session %p? \n " , s ) ;
2005-11-16 21:07:52 +00:00
}
2003-09-11 19:44:48 +00:00
ast_mutex_unlock ( & sessionlock ) ;
}
2006-03-21 15:12:41 +00:00
static int get_input ( struct skinnysession * s )
{
int res ;
2004-04-26 12:51:49 +00:00
int dlen = 0 ;
2006-03-21 15:12:41 +00:00
struct pollfd fds [ 1 ] ;
2006-03-22 20:45:00 +00:00
2004-04-26 12:51:49 +00:00
fds [ 0 ] . fd = s - > fd ;
fds [ 0 ] . events = POLLIN ;
2006-06-18 22:36:39 +00:00
fds [ 0 ] . revents = 0 ;
2007-06-04 23:29:22 +00:00
res = poll ( fds , 1 , ( keep_alive * 1100 ) ) ; /* If nothing has happen, client is dead */
/* we add 10% to the keep_alive to deal */
/* with network delays, etc */
2003-09-13 23:30:30 +00:00
if ( res < 0 ) {
2007-06-04 23:29:22 +00:00
if ( errno ! = EINTR ) {
2006-06-18 22:36:39 +00:00
ast_log ( LOG_WARNING , " Select returned error: %s \n " , strerror ( errno ) ) ;
return res ;
}
2007-06-04 23:29:22 +00:00
} else if ( res = = 0 ) {
if ( skinnydebug )
ast_verbose ( " Skinny Client was lost, unregistering \n " ) ;
skinny_unregister ( NULL , s ) ;
return - 1 ;
}
2006-06-18 22:36:39 +00:00
if ( fds [ 0 ] . revents ) {
ast_mutex_lock ( & s - > lock ) ;
2003-09-11 19:44:48 +00:00
memset ( s - > inbuf , 0 , sizeof ( s - > inbuf ) ) ;
2003-09-13 23:30:30 +00:00
res = read ( s - > fd , s - > inbuf , 4 ) ;
2006-06-18 22:36:39 +00:00
if ( res < 0 ) {
ast_log ( LOG_WARNING , " read() returned error: %s \n " , strerror ( errno ) ) ;
2006-10-09 16:15:16 +00:00
if ( skinnydebug )
ast_verbose ( " Skinny Client was lost, unregistering \n " ) ;
skinny_unregister ( NULL , s ) ;
2006-08-21 07:34:59 +00:00
ast_mutex_unlock ( & s - > lock ) ;
2006-06-18 22:36:39 +00:00
return res ;
} else if ( res ! = 4 ) {
ast_log ( LOG_WARNING , " Skinny Client sent less data than expected. Expected 4 but got %d. \n " , res ) ;
2006-08-21 07:34:59 +00:00
ast_mutex_unlock ( & s - > lock ) ;
2006-10-09 16:15:16 +00:00
if ( res = = 0 ) {
if ( skinnydebug )
ast_verbose ( " Skinny Client was lost, unregistering \n " ) ;
skinny_unregister ( NULL , s ) ;
}
2003-09-13 23:30:30 +00:00
return - 1 ;
}
2006-10-09 16:15:16 +00:00
2005-06-02 09:11:46 +00:00
dlen = letohl ( * ( int * ) s - > inbuf ) ;
2006-08-21 07:34:59 +00:00
if ( dlen < 0 ) {
ast_log ( LOG_WARNING , " Skinny Client sent invalid data. \n " ) ;
ast_mutex_unlock ( & s - > lock ) ;
return - 1 ;
}
2005-11-16 21:07:52 +00:00
if ( dlen + 8 > sizeof ( s - > inbuf ) ) {
2004-05-26 23:15:23 +00:00
dlen = sizeof ( s - > inbuf ) - 8 ;
2005-11-16 21:07:52 +00:00
}
2005-06-02 09:11:46 +00:00
* ( int * ) s - > inbuf = htolel ( dlen ) ;
2006-06-18 22:36:39 +00:00
2003-09-13 23:30:30 +00:00
res = read ( s - > fd , s - > inbuf + 4 , dlen + 4 ) ;
ast_mutex_unlock ( & s - > lock ) ;
2006-06-18 22:36:39 +00:00
if ( res < 0 ) {
ast_log ( LOG_WARNING , " read() returned error: %s \n " , strerror ( errno ) ) ;
return res ;
} else if ( res ! = ( dlen + 4 ) ) {
2003-09-13 23:30:30 +00:00
ast_log ( LOG_WARNING , " Skinny Client sent less data than expected. \n " ) ;
return - 1 ;
2006-03-21 15:12:41 +00:00
}
2006-06-18 22:36:39 +00:00
return res ;
2006-03-21 15:12:41 +00:00
}
2006-06-18 22:36:39 +00:00
return 0 ;
2006-03-21 15:12:41 +00:00
}
2003-09-11 19:44:48 +00:00
2006-09-17 21:58:04 +00:00
static struct skinny_req * skinny_req_parse ( struct skinnysession * s )
2003-09-11 19:44:48 +00:00
{
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2006-03-22 20:45:00 +00:00
2006-06-18 22:36:39 +00:00
if ( ! ( req = ast_calloc ( 1 , SKINNY_MAX_PACKET ) ) )
2003-09-11 19:44:48 +00:00
return NULL ;
2006-06-18 22:36:39 +00:00
ast_mutex_lock ( & s - > lock ) ;
memcpy ( req , s - > inbuf , skinny_header_size ) ;
memcpy ( & req - > data , s - > inbuf + skinny_header_size , letohl ( * ( int * ) ( s - > inbuf ) ) - 4 ) ;
ast_mutex_unlock ( & s - > lock ) ;
2005-06-02 09:11:46 +00:00
if ( letohl ( req - > e ) < 0 ) {
2003-09-11 19:44:48 +00:00
ast_log ( LOG_ERROR , " Event Message is NULL from socket %d, This is bad \n " , s - > fd ) ;
2003-09-13 23:30:30 +00:00
free ( req ) ;
2003-09-11 19:44:48 +00:00
return NULL ;
}
2006-06-18 22:36:39 +00:00
2003-09-11 19:44:48 +00:00
return req ;
}
static void * skinny_session ( void * data )
{
int res ;
2006-09-17 21:58:04 +00:00
struct skinny_req * req ;
2003-09-11 19:44:48 +00:00
struct skinnysession * s = data ;
2006-03-22 20:45:00 +00:00
2006-04-06 16:50:33 +00:00
if ( option_verbose > 2 )
2006-07-21 17:31:28 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Starting Skinny session from %s \n " , ast_inet_ntoa ( s - > sin . sin_addr ) ) ;
2006-06-18 22:36:39 +00:00
2003-09-11 19:44:48 +00:00
for ( ; ; ) {
res = get_input ( s ) ;
2005-11-16 21:07:52 +00:00
if ( res < 0 ) {
2003-09-11 19:44:48 +00:00
break ;
2005-11-16 21:07:52 +00:00
}
2006-06-18 22:36:39 +00:00
if ( res > 0 )
{
if ( ! ( req = skinny_req_parse ( s ) ) ) {
destroy_session ( s ) ;
return NULL ;
}
res = handle_message ( req , s ) ;
if ( res < 0 ) {
destroy_session ( s ) ;
return NULL ;
}
2006-03-22 20:45:00 +00:00
}
2003-09-11 19:44:48 +00:00
}
ast_log ( LOG_NOTICE , " Skinny Session returned: %s \n " , strerror ( errno ) ) ;
2006-11-08 22:52:01 +00:00
if ( s )
destroy_session ( s ) ;
2003-09-11 19:44:48 +00:00
return 0 ;
}
static void * accept_thread ( void * ignore )
{
int as ;
struct sockaddr_in sin ;
2005-05-15 03:21:51 +00:00
socklen_t sinlen ;
2003-09-11 19:44:48 +00:00
struct skinnysession * s ;
struct protoent * p ;
int arg = 1 ;
2007-01-05 17:10:59 +00:00
pthread_t tcp_thread ;
2003-09-11 19:44:48 +00:00
for ( ; ; ) {
sinlen = sizeof ( sin ) ;
2003-10-21 02:57:29 +00:00
as = accept ( skinnysock , ( struct sockaddr * ) & sin , & sinlen ) ;
2003-09-11 19:44:48 +00:00
if ( as < 0 ) {
ast_log ( LOG_NOTICE , " Accept returned -1: %s \n " , strerror ( errno ) ) ;
continue ;
}
p = getprotobyname ( " tcp " ) ;
if ( p ) {
if ( setsockopt ( as , p - > p_proto , TCP_NODELAY , ( char * ) & arg , sizeof ( arg ) ) < 0 ) {
ast_log ( LOG_WARNING , " Failed to set Skinny tcp connection to TCP_NODELAY mode: %s \n " , strerror ( errno ) ) ;
}
}
2006-06-18 22:36:39 +00:00
if ( ! ( s = ast_calloc ( 1 , sizeof ( struct skinnysession ) ) ) )
2003-09-11 19:44:48 +00:00
continue ;
2006-06-18 22:36:39 +00:00
2003-09-11 19:44:48 +00:00
memcpy ( & s - > sin , & sin , sizeof ( sin ) ) ;
ast_mutex_init ( & s - > lock ) ;
s - > fd = as ;
ast_mutex_lock ( & sessionlock ) ;
s - > next = sessions ;
sessions = s ;
ast_mutex_unlock ( & sessionlock ) ;
2006-03-22 20:45:00 +00:00
2007-05-24 18:30:19 +00:00
if ( ast_pthread_create_detached ( & tcp_thread , NULL , skinny_session , s ) ) {
2003-09-11 19:44:48 +00:00
destroy_session ( s ) ;
2004-05-12 21:30:23 +00:00
}
2003-09-11 19:44:48 +00:00
}
2006-06-18 22:36:39 +00:00
if ( skinnydebug )
2004-04-06 03:43:43 +00:00
ast_verbose ( " killing accept thread \n " ) ;
2003-09-11 19:44:48 +00:00
close ( as ) ;
return 0 ;
}
static void * do_monitor ( void * data )
{
int res ;
/* This thread monitors all the interfaces which are not yet in use
( and thus do not have a separate thread ) indefinitely */
/* From here on out, we die whenever asked */
for ( ; ; ) {
pthread_testcancel ( ) ;
/* Wait for sched or io */
res = ast_sched_wait ( sched ) ;
2004-05-12 21:30:23 +00:00
if ( ( res < 0 ) | | ( res > 1000 ) ) {
2003-09-11 19:44:48 +00:00
res = 1000 ;
2004-05-12 21:30:23 +00:00
}
2003-09-11 19:44:48 +00:00
res = ast_io_wait ( io , res ) ;
ast_mutex_lock ( & monlock ) ;
2004-05-12 21:30:23 +00:00
if ( res > = 0 ) {
2003-09-11 19:44:48 +00:00
ast_sched_runq ( sched ) ;
2004-05-12 21:30:23 +00:00
}
2003-09-11 19:44:48 +00:00
ast_mutex_unlock ( & monlock ) ;
}
/* Never reached */
return NULL ;
2006-03-22 20:45:00 +00:00
2003-09-11 19:44:48 +00:00
}
static int restart_monitor ( void )
{
/* If we're supposed to be stopped -- stay stopped */
2004-03-15 07:51:22 +00:00
if ( monitor_thread = = AST_PTHREADT_STOP )
2003-09-11 19:44:48 +00:00
return 0 ;
2006-09-22 22:13:47 +00:00
ast_mutex_lock ( & monlock ) ;
2003-09-11 19:44:48 +00:00
if ( monitor_thread = = pthread_self ( ) ) {
ast_mutex_unlock ( & monlock ) ;
ast_log ( LOG_WARNING , " Cannot kill myself \n " ) ;
return - 1 ;
}
2004-03-15 09:14:16 +00:00
if ( monitor_thread ! = AST_PTHREADT_NULL ) {
2003-09-11 19:44:48 +00:00
/* Wake up the thread */
pthread_kill ( monitor_thread , SIGURG ) ;
} else {
/* Start a new monitor */
2006-10-04 19:51:38 +00:00
if ( ast_pthread_create_background ( & monitor_thread , NULL , do_monitor , NULL ) < 0 ) {
2003-09-11 19:44:48 +00:00
ast_mutex_unlock ( & monlock ) ;
ast_log ( LOG_ERROR , " Unable to start monitor thread. \n " ) ;
return - 1 ;
}
}
ast_mutex_unlock ( & monlock ) ;
return 0 ;
}
2004-10-26 22:25:43 +00:00
static struct ast_channel * skinny_request ( const char * type , int format , void * data , int * cause )
2003-09-11 19:44:48 +00:00
{
int oldformat ;
2006-11-08 22:52:01 +00:00
2006-06-18 22:36:39 +00:00
struct skinny_line * l ;
2003-09-11 19:44:48 +00:00
struct ast_channel * tmpc = NULL ;
char tmp [ 256 ] ;
char * dest = data ;
oldformat = format ;
2006-11-08 22:52:01 +00:00
if ( ! ( format & = ( ( AST_FORMAT_MAX_AUDIO < < 1 ) - 1 ) ) ) {
2003-09-11 19:44:48 +00:00
ast_log ( LOG_NOTICE , " Asked to get a channel of unsupported format '%d' \n " , format ) ;
2006-11-08 22:52:01 +00:00
return NULL ;
}
2006-04-21 18:08:57 +00:00
ast_copy_string ( tmp , dest , sizeof ( tmp ) ) ;
2004-05-05 05:03:48 +00:00
if ( ast_strlen_zero ( tmp ) ) {
2003-09-13 23:30:30 +00:00
ast_log ( LOG_NOTICE , " Skinny channels require a device \n " ) ;
2003-09-11 19:44:48 +00:00
return NULL ;
}
2006-06-18 22:36:39 +00:00
l = find_line_by_name ( tmp ) ;
if ( ! l ) {
2003-09-13 23:30:30 +00:00
ast_log ( LOG_NOTICE , " No available lines on: %s \n " , dest ) ;
2003-09-11 19:44:48 +00:00
return NULL ;
}
2006-03-21 15:12:41 +00:00
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " skinny_request(%s) \n " , tmp ) ;
}
2006-06-18 22:36:39 +00:00
tmpc = skinny_new ( l , AST_STATE_DOWN ) ;
2004-05-12 21:30:23 +00:00
if ( ! tmpc ) {
2003-09-11 19:44:48 +00:00
ast_log ( LOG_WARNING , " Unable to make channel for '%s' \n " , tmp ) ;
2004-05-12 21:30:23 +00:00
}
2003-09-11 19:44:48 +00:00
restart_monitor ( ) ;
return tmpc ;
}
2007-02-24 02:06:44 +00:00
static int skinny_devicestate ( void * data )
{
struct skinny_line * l ;
struct skinny_subchannel * sub ;
char * tmp ;
int res = AST_DEVICE_UNKNOWN ;
tmp = ast_strdupa ( data ) ;
l = find_line_by_name ( tmp ) ;
if ( ! l )
res = AST_DEVICE_INVALID ;
else if ( ! l - > parent )
res = AST_DEVICE_UNAVAILABLE ;
else if ( l - > dnd )
res = AST_DEVICE_BUSY ;
else {
if ( l - > hookstate = = SKINNY_ONHOOK ) {
res = AST_DEVICE_NOT_INUSE ;
} else {
res = AST_DEVICE_INUSE ;
}
for ( sub = l - > sub ; sub ; sub = sub - > next ) {
if ( sub - > onhold ) {
res = AST_DEVICE_ONHOLD ;
break ;
}
}
}
return res ;
}
2003-09-12 23:47:02 +00:00
static int reload_config ( void )
2003-09-11 19:44:48 +00:00
{
2005-11-16 21:07:52 +00:00
int on = 1 ;
2003-09-11 19:44:48 +00:00
struct ast_config * cfg ;
struct ast_variable * v ;
char * cat ;
struct skinny_device * d ;
int oldport = ntohs ( bindaddr . sin_port ) ;
2004-05-12 21:30:23 +00:00
2005-06-24 02:56:15 +00:00
if ( gethostname ( ourhost , sizeof ( ourhost ) ) ) {
2003-09-11 19:44:48 +00:00
ast_log ( LOG_WARNING , " Unable to get hostname, Skinny disabled \n " ) ;
2003-09-14 15:42:27 +00:00
return 0 ;
2003-09-11 19:44:48 +00:00
}
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( config ) ;
2003-09-11 19:44:48 +00:00
/* We *must* have a config file otherwise stop immediately */
if ( ! cfg ) {
ast_log ( LOG_NOTICE , " Unable to load config %s, Skinny disabled \n " , config ) ;
2006-09-02 01:39:42 +00:00
return - 1 ;
2003-09-11 19:44:48 +00:00
}
memset ( & bindaddr , 0 , sizeof ( bindaddr ) ) ;
Merged revisions 43650 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r43650 | qwell | 2006-09-26 08:33:47 -0700 (Tue, 26 Sep 2006) | 11 lines
Add proper codec support to chan_skinny. Works with at least ulaw, alaw, and g729a.
This is technically a "new feature", but there are justifications for it.
I found a bug with the recent rtp packetization changes, which caused the media setup to
fail under certain circumstances, particularly when using allow=all, or having no allow=
statements (globally or on the device).
I could have either removed the rtp packetization features, or I could add proper codec
support (which, without, I think most people would consider to be a bug anyways).
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43651 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-09-26 15:35:37 +00:00
memset ( & default_prefs , 0 , sizeof ( default_prefs ) ) ;
2006-06-01 04:35:00 +00:00
/* Copy the default jb config over global_jbconf */
memcpy ( & global_jbconf , & default_jbconf , sizeof ( struct ast_jb_conf ) ) ;
/* load the general section */
2003-09-11 19:44:48 +00:00
v = ast_variable_browse ( cfg , " general " ) ;
2006-06-01 16:47:28 +00:00
while ( v ) {
2006-06-01 04:35:00 +00:00
/* handle jb conf */
2006-06-01 15:44:35 +00:00
if ( ! ast_jb_read_conf ( & global_jbconf , v - > name , v - > value ) ) {
2006-06-01 04:35:00 +00:00
v = v - > next ;
continue ;
}
2003-09-11 19:44:48 +00:00
/* Create the interface list */
if ( ! strcasecmp ( v - > name , " bindaddr " ) ) {
2004-04-22 00:20:34 +00:00
if ( ! ( hp = ast_gethostbyname ( v - > value , & ahp ) ) ) {
2003-09-11 19:44:48 +00:00
ast_log ( LOG_WARNING , " Invalid address: %s \n " , v - > value ) ;
} else {
memcpy ( & bindaddr . sin_addr , hp - > h_addr , sizeof ( bindaddr . sin_addr ) ) ;
}
2006-06-18 22:36:39 +00:00
} else if ( ! strcasecmp ( v - > name , " keepalive " ) ) {
2006-03-22 20:45:00 +00:00
keep_alive = atoi ( v - > value ) ;
2007-05-11 22:52:36 +00:00
} else if ( ! strcasecmp ( v - > name , " vmexten " ) ) {
ast_copy_string ( vmexten , v - > value , sizeof ( vmexten ) ) ;
2006-06-18 22:36:39 +00:00
} else if ( ! strcasecmp ( v - > name , " dateformat " ) ) {
ast_copy_string ( date_format , v - > value , sizeof ( date_format ) ) ;
2003-09-11 19:44:48 +00:00
} else if ( ! strcasecmp ( v - > name , " allow " ) ) {
2006-09-18 23:32:57 +00:00
ast_parse_allow_disallow ( & default_prefs , & default_capability , v - > value , 1 ) ;
2003-09-11 19:44:48 +00:00
} else if ( ! strcasecmp ( v - > name , " disallow " ) ) {
2006-09-18 23:32:57 +00:00
ast_parse_allow_disallow ( & default_prefs , & default_capability , v - > value , 0 ) ;
2006-09-21 21:59:12 +00:00
} else if ( ! strcasecmp ( v - > name , " bindport " ) ) {
2005-04-29 17:00:33 +00:00
if ( sscanf ( v - > value , " %d " , & ourport ) = = 1 ) {
2003-09-11 19:44:48 +00:00
bindaddr . sin_port = htons ( ourport ) ;
} else {
2006-06-18 22:36:39 +00:00
ast_log ( LOG_WARNING , " Invalid bindport '%s' at line %d of %s \n " , v - > value , v - > lineno , config ) ;
}
2003-09-11 19:44:48 +00:00
}
v = v - > next ;
}
2006-06-18 22:36:39 +00:00
2003-09-11 19:44:48 +00:00
if ( ntohl ( bindaddr . sin_addr . s_addr ) ) {
2006-06-18 22:36:39 +00:00
__ourip = bindaddr . sin_addr ;
2003-09-11 19:44:48 +00:00
} else {
2004-04-22 00:20:34 +00:00
hp = ast_gethostbyname ( ourhost , & ahp ) ;
2003-09-11 19:44:48 +00:00
if ( ! hp ) {
ast_log ( LOG_WARNING , " Unable to get our IP address, Skinny disabled \n " ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2003-09-11 19:44:48 +00:00
return 0 ;
}
memcpy ( & __ourip , hp - > h_addr , sizeof ( __ourip ) ) ;
}
2004-05-12 21:30:23 +00:00
if ( ! ntohs ( bindaddr . sin_port ) ) {
2003-09-11 19:44:48 +00:00
bindaddr . sin_port = ntohs ( DEFAULT_SKINNY_PORT ) ;
2004-05-12 21:30:23 +00:00
}
2003-09-11 19:44:48 +00:00
bindaddr . sin_family = AF_INET ;
2006-03-22 20:45:00 +00:00
2003-09-11 19:44:48 +00:00
/* load the device sections */
cat = ast_category_browse ( cfg , NULL ) ;
while ( cat ) {
2005-06-02 09:11:46 +00:00
if ( ! strcasecmp ( cat , " general " ) ) {
2006-03-21 15:12:41 +00:00
/* Nothing to do */
2005-06-02 09:11:46 +00:00
#if 0
} else if ( ! strncasecmp ( cat , " paging- " , 7 ) ) {
p = build_paging_device ( cat , ast_variable_browse ( cfg , cat ) ) ;
if ( p ) {
}
# endif
} else {
2003-09-11 19:44:48 +00:00
d = build_device ( cat , ast_variable_browse ( cfg , cat ) ) ;
if ( d ) {
2006-04-06 16:50:33 +00:00
if ( option_verbose > 2 )
2003-09-11 19:44:48 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Added device '%s' \n " , d - > name ) ;
ast_mutex_lock ( & devicelock ) ;
d - > next = devices ;
devices = d ;
ast_mutex_unlock ( & devicelock ) ;
}
}
cat = ast_category_browse ( cfg , cat ) ;
}
ast_mutex_lock ( & netlock ) ;
if ( ( skinnysock > - 1 ) & & ( ntohs ( bindaddr . sin_port ) ! = oldport ) ) {
close ( skinnysock ) ;
skinnysock = - 1 ;
}
if ( skinnysock < 0 ) {
skinnysock = socket ( AF_INET , SOCK_STREAM , 0 ) ;
2003-09-14 00:29:01 +00:00
if ( setsockopt ( skinnysock , SOL_SOCKET , SO_REUSEADDR , & on , sizeof ( on ) ) = = - 1 ) {
2006-09-28 18:09:01 +00:00
ast_log ( LOG_ERROR , " Set Socket Options failed: errno %d, %s \n " , errno , strerror ( errno ) ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2003-09-11 19:44:48 +00:00
return 0 ;
}
if ( skinnysock < 0 ) {
ast_log ( LOG_WARNING , " Unable to create Skinny socket: %s \n " , strerror ( errno ) ) ;
} else {
if ( bind ( skinnysock , ( struct sockaddr * ) & bindaddr , sizeof ( bindaddr ) ) < 0 ) {
ast_log ( LOG_WARNING , " Failed to bind to %s:%d: %s \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( bindaddr . sin_addr ) , ntohs ( bindaddr . sin_port ) ,
2003-09-11 19:44:48 +00:00
strerror ( errno ) ) ;
close ( skinnysock ) ;
skinnysock = - 1 ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2003-09-11 19:44:48 +00:00
return 0 ;
2006-03-22 20:45:00 +00:00
}
2003-09-11 19:44:48 +00:00
if ( listen ( skinnysock , DEFAULT_SKINNY_BACKLOG ) ) {
ast_log ( LOG_WARNING , " Failed to start listening to %s:%d: %s \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( bindaddr . sin_addr ) , ntohs ( bindaddr . sin_port ) ,
2003-09-11 19:44:48 +00:00
strerror ( errno ) ) ;
close ( skinnysock ) ;
skinnysock = - 1 ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2003-09-11 19:44:48 +00:00
return 0 ;
}
2006-04-06 16:50:33 +00:00
if ( option_verbose > 1 )
2006-03-22 20:45:00 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Skinny listening on %s:%d \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( bindaddr . sin_addr ) , ntohs ( bindaddr . sin_port ) ) ;
2006-10-04 19:51:38 +00:00
ast_pthread_create_background ( & accept_t , NULL , accept_thread , NULL ) ;
2003-09-11 19:44:48 +00:00
}
}
ast_mutex_unlock ( & netlock ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2006-09-02 01:39:42 +00:00
return 1 ;
2003-09-11 19:44:48 +00:00
}
2006-04-11 10:00:24 +00:00
static void delete_devices ( void )
2003-09-14 00:05:37 +00:00
{
struct skinny_device * d , * dlast ;
struct skinny_line * l , * llast ;
2006-06-18 22:36:39 +00:00
struct skinny_speeddial * sd , * sdlast ;
struct skinny_addon * a , * alast ;
2006-03-22 20:45:00 +00:00
2003-09-14 00:05:37 +00:00
ast_mutex_lock ( & devicelock ) ;
2006-03-22 20:45:00 +00:00
2003-09-14 00:05:37 +00:00
/* Delete all devices */
2006-03-22 20:45:00 +00:00
for ( d = devices ; d ; ) {
2003-09-14 00:05:37 +00:00
/* Delete all lines for this device */
for ( l = d - > lines ; l ; ) {
llast = l ;
l = l - > next ;
2004-06-22 17:42:14 +00:00
ast_mutex_destroy ( & llast - > lock ) ;
2003-09-14 00:05:37 +00:00
free ( llast ) ;
}
2006-06-18 22:36:39 +00:00
/* Delete all speeddials for this device */
for ( sd = d - > speeddials ; sd ; ) {
sdlast = sd ;
sd = sd - > next ;
ast_mutex_destroy ( & sdlast - > lock ) ;
free ( sdlast ) ;
}
/* Delete all addons for this device */
for ( a = d - > addons ; a ; ) {
alast = a ;
a = a - > next ;
ast_mutex_destroy ( & alast - > lock ) ;
free ( alast ) ;
}
2003-09-14 00:05:37 +00:00
dlast = d ;
d = d - > next ;
free ( dlast ) ;
}
devices = NULL ;
ast_mutex_unlock ( & devicelock ) ;
}
2006-09-22 22:13:47 +00:00
#if 0
/*
* XXX This never worked properly anyways .
* Let ' s get rid of it , until we can fix it .
*/
2006-08-21 02:11:39 +00:00
static int reload ( void )
2003-09-14 00:05:37 +00:00
{
delete_devices ( ) ;
reload_config ( ) ;
restart_monitor ( ) ;
return 0 ;
}
2006-09-22 22:13:47 +00:00
# endif
2003-09-14 00:05:37 +00:00
2006-08-21 02:11:39 +00:00
static int load_module ( void )
2003-09-11 19:44:48 +00:00
{
int res = 0 ;
2005-11-16 21:07:52 +00:00
for ( ; res < ( sizeof ( soft_key_template_default ) / sizeof ( soft_key_template_default [ 0 ] ) ) ; res + + ) {
2005-07-13 19:21:04 +00:00
soft_key_template_default [ res ] . softKeyEvent = htolel ( soft_key_template_default [ res ] . softKeyEvent ) ;
2005-11-16 21:07:52 +00:00
}
2003-09-11 19:44:48 +00:00
/* load and parse config */
res = reload_config ( ) ;
2006-09-02 01:39:42 +00:00
if ( res = = - 1 ) {
2006-08-31 21:00:20 +00:00
return AST_MODULE_LOAD_DECLINE ;
}
2006-09-02 01:39:42 +00:00
/* Make sure we can register our skinny channel type */
if ( ast_channel_register ( & skinny_tech ) ) {
ast_log ( LOG_ERROR , " Unable to register channel class 'Skinny' \n " ) ;
return - 1 ;
}
2003-09-11 19:44:48 +00:00
ast_rtp_proto_register ( & skinny_rtp ) ;
2006-09-18 19:54:18 +00:00
ast_cli_register_multiple ( cli_skinny , sizeof ( cli_skinny ) / sizeof ( struct ast_cli_entry ) ) ;
2003-09-11 19:44:48 +00:00
sched = sched_context_create ( ) ;
if ( ! sched ) {
ast_log ( LOG_WARNING , " Unable to create schedule context \n " ) ;
}
io = io_context_create ( ) ;
if ( ! io ) {
ast_log ( LOG_WARNING , " Unable to create I/O context \n " ) ;
}
/* And start the monitor for the first time */
restart_monitor ( ) ;
2005-11-16 21:07:52 +00:00
2003-09-11 19:44:48 +00:00
return res ;
}
2006-08-21 02:11:39 +00:00
static int unload_module ( void )
2003-09-11 19:44:48 +00:00
{
2006-09-22 22:13:47 +00:00
struct skinnysession * s , * slast ;
struct skinny_device * d ;
struct skinny_line * l ;
struct skinny_subchannel * sub ;
ast_mutex_lock ( & sessionlock ) ;
/* Destroy all the interfaces and free their memory */
s = sessions ;
while ( s ) {
slast = s ;
s = s - > next ;
for ( d = slast - > device ; d ; d = d - > next ) {
for ( l = d - > lines ; l ; l = l - > next ) {
ast_mutex_lock ( & l - > lock ) ;
for ( sub = l - > sub ; sub ; sub = sub - > next ) {
ast_mutex_lock ( & sub - > lock ) ;
if ( sub - > owner ) {
sub - > alreadygone = 1 ;
ast_softhangup ( sub - > owner , AST_SOFTHANGUP_APPUNLOAD ) ;
}
ast_mutex_unlock ( & sub - > lock ) ;
}
ast_mutex_unlock ( & l - > lock ) ;
}
}
if ( slast - > fd > - 1 )
close ( slast - > fd ) ;
ast_mutex_destroy ( & slast - > lock ) ;
free ( slast ) ;
}
sessions = NULL ;
ast_mutex_unlock ( & sessionlock ) ;
2006-09-22 03:09:22 +00:00
delete_devices ( ) ;
2003-09-11 19:44:48 +00:00
2006-09-22 03:09:22 +00:00
ast_mutex_lock ( & monlock ) ;
if ( monitor_thread & & ( monitor_thread ! = AST_PTHREADT_STOP ) ) {
pthread_cancel ( monitor_thread ) ;
pthread_kill ( monitor_thread , SIGURG ) ;
pthread_join ( monitor_thread , NULL ) ;
2003-09-11 19:44:48 +00:00
}
2006-09-22 03:09:22 +00:00
monitor_thread = AST_PTHREADT_STOP ;
ast_mutex_unlock ( & monlock ) ;
2006-09-22 22:13:47 +00:00
ast_mutex_lock ( & netlock ) ;
if ( accept_t & & ( accept_t ! = AST_PTHREADT_STOP ) ) {
pthread_cancel ( accept_t ) ;
pthread_kill ( accept_t , SIGURG ) ;
pthread_join ( accept_t , NULL ) ;
}
accept_t = AST_PTHREADT_STOP ;
ast_mutex_unlock ( & netlock ) ;
2004-03-04 06:25:27 +00:00
2006-03-27 21:13:54 +00:00
ast_rtp_proto_unregister ( & skinny_rtp ) ;
2005-03-04 06:47:24 +00:00
ast_channel_unregister ( & skinny_tech ) ;
2006-09-18 19:54:18 +00:00
ast_cli_unregister_multiple ( cli_skinny , sizeof ( cli_skinny ) / sizeof ( struct ast_cli_entry ) ) ;
2004-03-04 06:25:27 +00:00
2006-09-22 03:09:22 +00:00
close ( skinnysock ) ;
sched_context_destroy ( sched ) ;
2004-03-04 06:25:27 +00:00
return 0 ;
2003-09-11 19:44:48 +00:00
}
2006-08-21 02:11:39 +00:00
AST_MODULE_INFO ( ASTERISK_GPL_KEY , AST_MODFLAG_DEFAULT , " Skinny Client Control Protocol (Skinny) " ,
. load = load_module ,
. unload = unload_module ,
) ;