Thu Apr 28 2011 17:13:51

Asterisk developer's documentation


chan_skinny.c File Reference

Implementation of the Skinny protocol. More...

#include "asterisk.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <fcntl.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include <signal.h>
#include <ctype.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
#include "asterisk/netsock.h"
#include "asterisk/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/cli.h"
#include "asterisk/manager.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"
#include "asterisk/stringfields.h"
#include "asterisk/abstract_jb.h"
#include "asterisk/threadstorage.h"
#include "asterisk/devicestate.h"
#include "asterisk/event.h"
#include "asterisk/indications.h"
#include "asterisk/linkedlists.h"
Include dependency graph for chan_skinny.c:

Go to the source code of this file.

Data Structures

struct  activate_call_plane_message
struct  alarm_message
struct  button_definition
struct  button_definition_template
struct  button_template_res_message
struct  call_info_message
struct  call_state_message
struct  capabilities_res_message
struct  clear_prompt_message
struct  close_receive_channel_message
struct  definetimedate_message
struct  devices
struct  dialed_number_message
struct  display_notify_message
struct  display_prompt_status_message
struct  displaytext_message
struct  enbloc_call_message
struct  forward_stat_message
struct  keypad_button_message
struct  line_stat_res_message
struct  line_state_req_message
struct  lines
struct  media_qualifier
struct  offhook_message
struct  onhook_message
struct  open_receive_channel_ack_message
struct  open_receive_channel_message
struct  register_ack_message
struct  register_message
struct  register_rej_message
struct  reset_message
struct  select_soft_keys_message
struct  server_identifier
struct  server_res_message
struct  sessions
struct  set_lamp_message
struct  set_microphone_message
struct  set_ringer_message
struct  set_speaker_message
struct  skinny_addon
union  skinny_data
struct  skinny_device
struct  skinny_device_options
struct  skinny_line
struct  skinny_line_options
struct  skinny_req
struct  skinny_speeddial
struct  skinny_subchannel
struct  skinnysession
struct  soft_key_definitions
struct  soft_key_event_message
struct  soft_key_set_definition
struct  soft_key_set_res_message
struct  soft_key_template_definition
struct  soft_key_template_res_message
struct  speed_dial_stat_req_message
struct  speed_dial_stat_res_message
struct  start_media_transmission_message
struct  start_tone_message
struct  station_capabilities
struct  stimulus_message
struct  stop_media_transmission_message
struct  stop_tone_message
struct  version_res_message

Defines

#define ACTIVATE_CALL_PLANE_MESSAGE   0x0116
#define ALARM_MESSAGE   0x0020
#define BT_AUTOANSWER   STIMULUS_AUTOANSWER
#define BT_CALLPARK   STIMULUS_CALLPARK
#define BT_CALLPICKUP   STIMULUS_CALLPICKUP
#define BT_CONFERENCE   STIMULUS_CONFERENCE
#define BT_CUST_LINE   0xB1
#define BT_CUST_LINESPEEDDIAL   0xB0
#define BT_DISPLAY   STIMULUS_DISPLAY
#define BT_DND   STIMULUS_DND
#define BT_FORWARDALL   STIMULUS_FORWARDALL
#define BT_FORWARDBUSY   STIMULUS_FORWARDBUSY
#define BT_FORWARDNOANSWER   STIMULUS_FORWARDNOANSWER
#define BT_HOLD   STIMULUS_HOLD
#define BT_LINE   STIMULUS_LINE
#define BT_NONE   0x00
#define BT_REDIAL   STIMULUS_REDIAL
#define BT_SPEEDDIAL   STIMULUS_SPEEDDIAL
#define BT_TRANSFER   STIMULUS_TRANSFER
#define BT_VOICEMAIL   STIMULUS_VOICEMAIL
#define BUTTON_TEMPLATE_REQ_MESSAGE   0x000E
#define BUTTON_TEMPLATE_RES_MESSAGE   0x0097
#define CALL_INFO_MESSAGE   0x008F
#define CALL_STATE_MESSAGE   0x0111
#define CAPABILITIES_REQ_MESSAGE   0x009B
#define CAPABILITIES_RES_MESSAGE   0x0010
#define CDEV   ((struct skinny_device *)item)
#define CDEV_OPTS   ((struct skinny_device_options *)item)
#define CLEAR_DISPLAY_MESSAGE   0x009A
#define CLEAR_NOTIFY_MESSAGE   0x0115
#define CLEAR_PROMPT_MESSAGE   0x0113
#define CLINE   ((struct skinny_line *)item)
#define CLINE_OPTS   ((struct skinny_line_options *)item)
#define CLOSE_RECEIVE_CHANNEL_MESSAGE   0x0106
#define CONTROL2STR_BUFSIZE   100
#define DEFAULT_AUTH_LIMIT   50
#define DEFAULT_AUTH_TIMEOUT   30
#define DEFAULT_SKINNY_BACKLOG   2
#define DEFAULT_SKINNY_PORT   2000
#define DEFINETIMEDATE_MESSAGE   0x0094
#define DEVICE2STR_BUFSIZE   15
#define DIALED_NUMBER_MESSAGE   0x011D
#define DISPLAY_NOTIFY_MESSAGE   0x0114
#define DISPLAY_PROMPT_STATUS_MESSAGE   0x0112
#define DISPLAYTEXT_MESSAGE   0x0099
#define ENBLOC_CALL_MESSAGE   0x0004
#define FORWARD_STAT_MESSAGE   0x0090
#define HEADSET_STATUS_MESSAGE   0x002B
#define htolel(x)   (x)
#define htoles(x)   (x)
#define IP_PORT_MESSAGE   0x0002
#define KEEP_ALIVE_ACK_MESSAGE   0x0100
#define KEEP_ALIVE_MESSAGE   0x0000
#define KEYDEF_CONNECTED   1
#define KEYDEF_CONNWITHCONF   7
#define KEYDEF_CONNWITHTRANS   5
#define KEYDEF_DADFD   6
#define KEYDEF_OFFHOOK   4
#define KEYDEF_OFFHOOKWITHFEAT   9
#define KEYDEF_ONHOLD   2
#define KEYDEF_ONHOOK   0
#define KEYDEF_RINGIN   3
#define KEYDEF_RINGOUT   8
#define KEYDEF_UNKNOWN   10
#define KEYPAD_BUTTON_MESSAGE   0x0003
#define letohl(x)   (x)
#define letohs(x)   (x)
#define LINE_STAT_RES_MESSAGE   0x0092
#define LINE_STATE_REQ_MESSAGE   0x000B
#define OFFHOOK_MESSAGE   0x0006
#define ONHOOK_MESSAGE   0x0007
#define OPEN_RECEIVE_CHANNEL_ACK_MESSAGE   0x0022
#define OPEN_RECEIVE_CHANNEL_MESSAGE   0x0105
#define REGISTER_ACK_MESSAGE   0x0081
#define REGISTER_AVAILABLE_LINES_MESSAGE   0x002D
#define REGISTER_MESSAGE   0x0001
#define REGISTER_REJ_MESSAGE   0x009D
#define RESET_MESSAGE   0x009F
#define SELECT_SOFT_KEYS_MESSAGE   0x0110
#define SERVER_REQUEST_MESSAGE   0x0012
#define SERVER_RES_MESSAGE   0x009E
#define SET_LAMP_MESSAGE   0x0086
#define SET_MICROPHONE_MESSAGE   0x0089
#define SET_RINGER_MESSAGE   0x0085
#define SET_SPEAKER_MESSAGE   0x0088
#define SKINNY_ALERT   0x24
#define SKINNY_BUSY   6
#define SKINNY_BUSYTONE   0x23
#define SKINNY_CALLREMOTEMULTILINE   13
#define SKINNY_CALLWAIT   9
#define SKINNY_CALLWAITTONE   0x2D
#define SKINNY_CFWD_ALL   (1 << 0)
#define SKINNY_CFWD_BUSY   (1 << 1)
#define SKINNY_CFWD_NOANSWER   (1 << 2)
#define SKINNY_CONGESTION   7
#define SKINNY_CONNECTED   5
#define SKINNY_CX_CONF   3
#define SKINNY_CX_CONFERENCE   3
#define SKINNY_CX_INACTIVE   4
#define SKINNY_CX_MUTE   4
#define SKINNY_CX_RECVONLY   1
#define SKINNY_CX_SENDONLY   0
#define SKINNY_CX_SENDRECV   2
#define SKINNY_DEVICE_12   4
#define SKINNY_DEVICE_12SP   3
#define SKINNY_DEVICE_12SPPLUS   2
#define SKINNY_DEVICE_30SPPLUS   1
#define SKINNY_DEVICE_30VIP   5
#define SKINNY_DEVICE_7902   30008
#define SKINNY_DEVICE_7905   20000
#define SKINNY_DEVICE_7906   369
#define SKINNY_DEVICE_7910   6
#define SKINNY_DEVICE_7911   307
#define SKINNY_DEVICE_7912   30007
#define SKINNY_DEVICE_7914   124
#define SKINNY_DEVICE_7920   30002
#define SKINNY_DEVICE_7921   365
#define SKINNY_DEVICE_7931   348
#define SKINNY_DEVICE_7935   9
#define SKINNY_DEVICE_7936   30019
#define SKINNY_DEVICE_7937   431
#define SKINNY_DEVICE_7940   8
#define SKINNY_DEVICE_7941   115
#define SKINNY_DEVICE_7941GE   309
#define SKINNY_DEVICE_7942   434
#define SKINNY_DEVICE_7945   435
#define SKINNY_DEVICE_7960   7
#define SKINNY_DEVICE_7961   30018
#define SKINNY_DEVICE_7961GE   308
#define SKINNY_DEVICE_7962   404
#define SKINNY_DEVICE_7965   436
#define SKINNY_DEVICE_7970   30006
#define SKINNY_DEVICE_7971   119
#define SKINNY_DEVICE_7975   437
#define SKINNY_DEVICE_7985   302
#define SKINNY_DEVICE_ATA186   12
#define SKINNY_DEVICE_CIPC   30016
#define SKINNY_DEVICE_NONE   0
#define SKINNY_DEVICE_OPTIONS
#define SKINNY_DEVICE_SCCPGATEWAY_AN   30027
#define SKINNY_DEVICE_SCCPGATEWAY_BRI   30028
#define SKINNY_DEVICE_UNKNOWN   -1
#define SKINNY_DEVONLY(code)
#define SKINNY_DIALTONE   0x21
#define SKINNY_HOLD   8
#define SKINNY_INVALID   14
#define SKINNY_LAMP_BLINK   5
#define SKINNY_LAMP_FLASH   4
#define SKINNY_LAMP_OFF   1
#define SKINNY_LAMP_ON   2
#define SKINNY_LAMP_WINK   3
#define SKINNY_LINE_OPTIONS
#define SKINNY_MAX_CAPABILITIES   18
#define SKINNY_MAX_PACKET   1000
#define SKINNY_MICOFF   2
#define SKINNY_MICON   1
#define SKINNY_NOTONE   0x7F
#define SKINNY_OFFHOOK   1
#define SKINNY_ONHOOK   2
#define SKINNY_PARK   11
#define SKINNY_PROGRESS   12
#define SKINNY_REORDER   0x25
#define SKINNY_RING_FEATURE   4
#define SKINNY_RING_INSIDE   2
#define SKINNY_RING_OFF   1
#define SKINNY_RING_OUTSIDE   3
#define SKINNY_RINGIN   4
#define SKINNY_RINGOUT   3
#define SKINNY_SILENCE   0x00
#define SKINNY_SPEAKEROFF   2
#define SKINNY_SPEAKERON   1
#define SKINNY_TRANSFER   10
#define SOFT_KEY_EVENT_MESSAGE   0x0026
#define SOFT_KEY_SET_REQ_MESSAGE   0x0025
#define SOFT_KEY_SET_RES_MESSAGE   0x0109
#define SOFT_KEY_TEMPLATE_REQ_MESSAGE   0x0028
#define SOFT_KEY_TEMPLATE_RES_MESSAGE   0x0108
#define SOFTKEY_ANSWER   0x0B
#define SOFTKEY_BKSPC   0x08
#define SOFTKEY_CFWDALL   0x05
#define SOFTKEY_CFWDBUSY   0x06
#define SOFTKEY_CFWDNOANSWER   0x07
#define SOFTKEY_CONFRN   0x0D
#define SOFTKEY_DND   0x13
#define SOFTKEY_ENDCALL   0x09
#define SOFTKEY_GPICKUP   0x12
#define SOFTKEY_HOLD   0x03
#define SOFTKEY_IDIVERT   0x14
#define SOFTKEY_INFO   0x0C
#define SOFTKEY_JOIN   0x0F
#define SOFTKEY_MEETME   0x10
#define SOFTKEY_NEWCALL   0x02
#define SOFTKEY_NONE   0x00
#define SOFTKEY_PARK   0x0E
#define SOFTKEY_PICKUP   0x11
#define SOFTKEY_REDIAL   0x01
#define SOFTKEY_RESUME   0x0A
#define SOFTKEY_TRNSFER   0x04
#define SPEED_DIAL_STAT_REQ_MESSAGE   0x000A
#define SPEED_DIAL_STAT_RES_MESSAGE   0x0091
#define START_MEDIA_TRANSMISSION_MESSAGE   0x008A
#define START_TONE_MESSAGE   0x0082
#define STIMULUS_AUTOANSWER   0x11
#define STIMULUS_CALLPARK   0x7E
#define STIMULUS_CALLPICKUP   0x7F
#define STIMULUS_CONFERENCE   0x7D
#define STIMULUS_DISPLAY   0x08
#define STIMULUS_DND   0x3F
#define STIMULUS_FORWARDALL   0x05
#define STIMULUS_FORWARDBUSY   0x06
#define STIMULUS_FORWARDNOANSWER   0x07
#define STIMULUS_HOLD   0x03
#define STIMULUS_LINE   0x09
#define STIMULUS_MESSAGE   0x0005
#define STIMULUS_NONE   0xFF
#define STIMULUS_REDIAL   0x01
#define STIMULUS_SPEEDDIAL   0x02
#define STIMULUS_TRANSFER   0x04
#define STIMULUS_VOICEMAIL   0x0F
#define STOP_MEDIA_TRANSMISSION_MESSAGE   0x008B
#define STOP_TONE_MESSAGE   0x0083
#define TIME_DATE_REQ_MESSAGE   0x000D
#define TYPE_DEF_DEVICE   2
#define TYPE_DEF_LINE   4
#define TYPE_DEVICE   8
#define TYPE_GENERAL   1
#define TYPE_LINE   16
#define UNREGISTER_MESSAGE   0x0027
#define VERSION_REQ_MESSAGE   0x000F
#define VERSION_RES_MESSAGE   0x0098

Enumerations

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, SKINNY_CODEC_H261 = 100, SKINNY_CODEC_H263 = 101
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static char * _skinny_show_device (int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
static char * _skinny_show_devices (int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[])
static char * _skinny_show_line (int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
static char * _skinny_show_lines (int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[])
static void * accept_thread (void *ignore)
static struct ast_variableadd_var (const char *buf, struct ast_variable *list)
 AST_THREADSTORAGE_CUSTOM_SCOPE (device2str_threadbuf, NULL, ast_free_ptr, static)
 AST_THREADSTORAGE_CUSTOM_SCOPE (control2str_threadbuf, NULL, ast_free_ptr, static)
static void cleanup_stale_contexts (char *new, char *old)
static int codec_ast2skinny (int astcodec)
static int codec_skinny2ast (enum skinny_codecs skinnycodec)
static char * complete_skinny_devices (const char *word, int state)
static char * complete_skinny_reset (const char *line, const char *word, int pos, int state)
static char * complete_skinny_show_device (const char *line, const char *word, int pos, int state)
static char * complete_skinny_show_line (const char *line, const char *word, int pos, int state)
static struct skinny_deviceconfig_device (const char *dname, struct ast_variable *v)
static struct skinny_lineconfig_line (const char *lname, struct ast_variable *v)
static int config_load (void)
static void config_parse_variables (int type, void *item, struct ast_variable *vptr)
static char * control2str (int ind)
static void delete_devices (void)
static void destroy_session (struct skinnysession *s)
static char * device2str (int type)
static void * do_monitor (void *data)
static struct skinny_linefind_line_by_instance (struct skinny_device *d, int instance)
static struct skinny_linefind_line_by_name (const char *dest)
static struct skinny_speeddialfind_speeddial_by_instance (struct skinny_device *d, int instance, int isHint)
static struct skinny_subchannelfind_subchannel_by_instance_reference (struct skinny_device *d, int instance, int reference)
static struct skinny_subchannelfind_subchannel_by_reference (struct skinny_device *d, int reference)
static void * get_button_template (struct skinnysession *s, struct button_definition_template *btn)
static int get_devicestate (struct skinny_line *l)
static int get_input (struct skinnysession *s)
static int handle_alarm_message (struct skinny_req *req, struct skinnysession *s)
static int handle_button_template_req_message (struct skinny_req *req, struct skinnysession *s)
static int handle_callforward_button (struct skinny_subchannel *sub, int cfwdtype)
static int handle_capabilities_res_message (struct skinny_req *req, struct skinnysession *s)
static int handle_enbloc_call_message (struct skinny_req *req, struct skinnysession *s)
static int handle_headset_status_message (struct skinny_req *req, struct skinnysession *s)
static int handle_hold_button (struct skinny_subchannel *sub)
static int handle_ip_port_message (struct skinny_req *req, struct skinnysession *s)
static int handle_keep_alive_message (struct skinny_req *req, struct skinnysession *s)
static int handle_keypad_button_message (struct skinny_req *req, struct skinnysession *s)
static int handle_line_state_req_message (struct skinny_req *req, struct skinnysession *s)
static int handle_message (struct skinny_req *req, struct skinnysession *s)
static int handle_offhook_message (struct skinny_req *req, struct skinnysession *s)
static int handle_onhook_message (struct skinny_req *req, struct skinnysession *s)
static int handle_open_receive_channel_ack_message (struct skinny_req *req, struct skinnysession *s)
static int handle_register_available_lines_message (struct skinny_req *req, struct skinnysession *s)
static int handle_register_message (struct skinny_req *req, struct skinnysession *s)
static int handle_server_request_message (struct skinny_req *req, struct skinnysession *s)
static char * handle_skinny_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_skinny_reset (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_skinny_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_skinny_show_device (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 Show device information.
static char * handle_skinny_show_devices (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_skinny_show_line (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 List line information.
static char * handle_skinny_show_lines (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_skinny_show_settings (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 List global settings for the Skinny subsystem.
static int handle_soft_key_event_message (struct skinny_req *req, struct skinnysession *s)
static int handle_soft_key_set_req_message (struct skinny_req *req, struct skinnysession *s)
static int handle_soft_key_template_req_message (struct skinny_req *req, struct skinnysession *s)
static int handle_speed_dial_stat_req_message (struct skinny_req *req, struct skinnysession *s)
static int handle_stimulus_message (struct skinny_req *req, struct skinnysession *s)
static int handle_time_date_req_message (struct skinny_req *req, struct skinnysession *s)
static int handle_transfer_button (struct skinny_subchannel *sub)
static int handle_unregister_message (struct skinny_req *req, struct skinnysession *s)
static int handle_version_req_message (struct skinny_req *req, struct skinnysession *s)
static int load_module (void)
static int manager_skinny_show_device (struct mansession *s, const struct message *m)
static int manager_skinny_show_devices (struct mansession *s, const struct message *m)
 Show SKINNY devices in the manager API.
static int manager_skinny_show_line (struct mansession *s, const struct message *m)
static int manager_skinny_show_lines (struct mansession *s, const struct message *m)
 Show Skinny lines in the manager API.
static void mwi_event_cb (const struct ast_event *event, void *userdata)
static void print_codec_to_cli (int fd, struct ast_codec_pref *pref)
 Print codec list from preference to CLI/manager.
static void register_exten (struct skinny_line *l)
static int reload (void)
static struct skinny_reqreq_alloc (size_t size, int response_message)
static int restart_monitor (void)
static int set_callforwards (struct skinny_line *l, const char *cfwd, int cfwdtype)
static int skinny_answer (struct ast_channel *ast)
static int skinny_call (struct ast_channel *ast, char *dest, int timeout)
static int skinny_devicestate (void *data)
static int skinny_extensionstate_cb (char *context, char *exten, int state, void *data)
static int skinny_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
static enum ast_rtp_get_result skinny_get_rtp_peer (struct ast_channel *c, struct ast_rtp **rtp)
static enum ast_rtp_get_result skinny_get_vrtp_peer (struct ast_channel *c, struct ast_rtp **rtp)
static int skinny_hangup (struct ast_channel *ast)
static int skinny_hold (struct skinny_subchannel *sub)
static int skinny_indicate (struct ast_channel *ast, int ind, const void *data, size_t datalen)
static struct ast_channelskinny_new (struct skinny_line *l, int state)
static void * skinny_newcall (void *data)
static struct ast_frameskinny_read (struct ast_channel *ast)
static int skinny_register (struct skinny_req *req, struct skinnysession *s)
static int skinny_reload (void)
static struct skinny_reqskinny_req_parse (struct skinnysession *s)
static struct ast_channelskinny_request (const char *type, int format, void *data, int *cause)
static struct ast_frameskinny_rtp_read (struct skinny_subchannel *sub)
static int skinny_senddigit_begin (struct ast_channel *ast, char digit)
static int skinny_senddigit_end (struct ast_channel *ast, char digit, unsigned int duration)
static void * skinny_session (void *data)
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)
static void * skinny_ss (void *data)
static int skinny_transfer (struct skinny_subchannel *sub)
static int skinny_unhold (struct skinny_subchannel *sub)
static int skinny_unregister (struct skinny_req *req, struct skinnysession *s)
static int skinny_write (struct ast_channel *ast, struct ast_frame *frame)
static void start_rtp (struct skinny_subchannel *sub)
static void transmit_activatecallplane (struct skinny_device *d, struct skinny_line *l)
static void transmit_callinfo (struct skinny_device *d, const char *fromname, const char *fromnum, const char *toname, const char *tonum, int instance, int callid, int calltype)
static void transmit_callstate (struct skinny_device *d, int instance, int state, unsigned callid)
static void transmit_callstateonly (struct skinny_device *d, struct skinny_subchannel *sub, int state)
static void transmit_cfwdstate (struct skinny_device *d, struct skinny_line *l)
static void transmit_closereceivechannel (struct skinny_device *d, struct skinny_subchannel *sub)
static void transmit_connect (struct skinny_device *d, struct skinny_subchannel *sub)
static void transmit_dialednumber (struct skinny_device *d, const char *text, int instance, int callid)
static void transmit_displaymessage (struct skinny_device *d, const char *text, int instance, int reference)
static void transmit_displaynotify (struct skinny_device *d, const char *text, int t)
static void transmit_displaypromptstatus (struct skinny_device *d, const char *text, int t, int instance, int callid)
static void transmit_lamp_indication (struct skinny_device *d, int stimulus, int instance, int indication)
static int transmit_response (struct skinny_device *d, struct skinny_req *req)
static void transmit_ringer_mode (struct skinny_device *d, int mode)
static void transmit_selectsoftkeys (struct skinny_device *d, int instance, int callid, int softkey)
static void transmit_speaker_mode (struct skinny_device *d, int mode)
static void transmit_stopmediatransmission (struct skinny_device *d, struct skinny_subchannel *sub)
static void transmit_tone (struct skinny_device *d, int tone, int instance, int reference)
static int unload_module (void)
static void unregister_exten (struct skinny_line *l)

Variables

static struct ast_module_info
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Skinny Client Control Protocol (Skinny)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static struct in_addr __ourip
static pthread_t accept_t
struct ast_hostent ahp
static struct ast_module_infoast_module_info = &__mod_info
static int auth_limit = DEFAULT_AUTH_LIMIT
static int auth_timeout = DEFAULT_AUTH_TIMEOUT
static struct sockaddr_in bindaddr
static int callnums = 1
static struct ast_cli_entry cli_skinny []
static const char config [] = "skinny.conf"
static char date_format [6] = "D-M-Y"
static int default_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW
struct skinny_device_optionsdefault_device = &default_device_struct
struct skinny_device_options default_device_struct
static struct ast_jb_conf default_jbconf
struct skinny_line_optionsdefault_line = &default_line_struct
struct skinny_line_options default_line_struct
static struct ast_codec_pref default_prefs
static struct devices devices
static int firstdigittimeout = 16000
static int gendigittimeout = 8000
static struct ast_jb_conf global_jbconf
static char global_vmexten [AST_MAX_EXTENSION]
struct hostent * hp
static struct io_contextio
static int keep_alive = 120
static struct lines lines
static char mandescr_show_device [] = " ActionID: <id> Optional action ID for this AMI transaction.\n"
static char mandescr_show_devices [] = " ActionID: <id> Action ID for this transaction. Will be returned.\n"
static char mandescr_show_line [] = " ActionID: <id> Optional action ID for this AMI transaction.\n"
static char mandescr_show_lines [] = " ActionID: <id> Action ID for this transaction. Will be returned.\n"
static int matchdigittimeout = 3000
static pthread_t monitor_thread = AST_PTHREADT_NULL
static ast_mutex_t monlock = AST_MUTEX_INIT_VALUE
static ast_mutex_t netlock = AST_MUTEX_INIT_VALUE
static char ourhost [256]
static int ourport
struct {
   unsigned int   cos
   unsigned int   cos_audio
   unsigned int   cos_video
   unsigned int   tos
   unsigned int   tos_audio
   unsigned int   tos_video
qos
static char regcontext [AST_MAX_CONTEXT]
static struct sched_contextsched = NULL
static struct sessions sessions
int skinny_header_size = 12
static struct ast_rtp_protocol skinny_rtp
static struct ast_channel_tech skinny_tech
static int skinnydebug = 0
static int skinnyreload = 0
static int skinnysock = -1
static const uint8_t soft_key_default_connected []
static const uint8_t soft_key_default_connwithconf []
static const uint8_t soft_key_default_connwithtrans []
static const uint8_t soft_key_default_dadfd []
static struct soft_key_definitions soft_key_default_definitions []
static const uint8_t soft_key_default_offhook []
static const uint8_t soft_key_default_offhookwithfeat []
static const uint8_t soft_key_default_onhold []
static const uint8_t soft_key_default_onhook []
static const uint8_t soft_key_default_ringin []
static const uint8_t soft_key_default_ringout []
static const uint8_t soft_key_default_unknown []
struct soft_key_template_definition soft_key_template_default []
static const char tdesc [] = "Skinny Client Control Protocol (Skinny)"
static int unauth_sessions = 0
static char used_context [AST_MAX_EXTENSION]
static char version_id [16] = "P002F202"

Detailed Description

Implementation of the Skinny protocol.

Author:
Jeremy McNamara & Florian Overkamp & North Antara

Definition in file chan_skinny.c.


Define Documentation

#define ACTIVATE_CALL_PLANE_MESSAGE   0x0116

Definition at line 903 of file chan_skinny.c.

Referenced by transmit_activatecallplane(), and transmit_callstate().

#define ALARM_MESSAGE   0x0020

Definition at line 270 of file chan_skinny.c.

Referenced by handle_message().

#define BT_AUTOANSWER   STIMULUS_AUTOANSWER

Definition at line 477 of file chan_skinny.c.

#define BT_CALLPARK   STIMULUS_CALLPARK

Definition at line 480 of file chan_skinny.c.

Referenced by get_button_template().

#define BT_CALLPICKUP   STIMULUS_CALLPICKUP

Definition at line 481 of file chan_skinny.c.

#define BT_CONFERENCE   STIMULUS_CONFERENCE

Definition at line 479 of file chan_skinny.c.

Referenced by get_button_template().

#define BT_CUST_LINE   0xB1

Definition at line 488 of file chan_skinny.c.

Referenced by get_button_template(), and handle_button_template_req_message().

#define BT_CUST_LINESPEEDDIAL   0xB0

Definition at line 487 of file chan_skinny.c.

Referenced by get_button_template(), and handle_button_template_req_message().

#define BT_DISPLAY   STIMULUS_DISPLAY

Definition at line 474 of file chan_skinny.c.

Referenced by get_button_template().

#define BT_DND   STIMULUS_DND

Definition at line 478 of file chan_skinny.c.

#define BT_FORWARDALL   STIMULUS_FORWARDALL

Definition at line 471 of file chan_skinny.c.

Referenced by get_button_template().

#define BT_FORWARDBUSY   STIMULUS_FORWARDBUSY

Definition at line 472 of file chan_skinny.c.

#define BT_FORWARDNOANSWER   STIMULUS_FORWARDNOANSWER

Definition at line 473 of file chan_skinny.c.

#define BT_HOLD   STIMULUS_HOLD

Definition at line 469 of file chan_skinny.c.

Referenced by get_button_template().

#define BT_LINE   STIMULUS_LINE

Definition at line 475 of file chan_skinny.c.

Referenced by get_button_template(), and handle_button_template_req_message().

#define BT_NONE   0x00

Definition at line 482 of file chan_skinny.c.

Referenced by get_button_template(), and handle_button_template_req_message().

#define BT_REDIAL   STIMULUS_REDIAL

Definition at line 467 of file chan_skinny.c.

Referenced by get_button_template().

#define BT_SPEEDDIAL   STIMULUS_SPEEDDIAL

Definition at line 468 of file chan_skinny.c.

Referenced by get_button_template(), and handle_button_template_req_message().

#define BT_TRANSFER   STIMULUS_TRANSFER

Definition at line 470 of file chan_skinny.c.

Referenced by get_button_template().

#define BT_VOICEMAIL   STIMULUS_VOICEMAIL

Definition at line 476 of file chan_skinny.c.

Referenced by get_button_template().

#define BUTTON_TEMPLATE_REQ_MESSAGE   0x000E

Definition at line 266 of file chan_skinny.c.

Referenced by handle_message().

#define BUTTON_TEMPLATE_RES_MESSAGE   0x0097

Definition at line 437 of file chan_skinny.c.

Referenced by handle_button_template_req_message().

#define CALL_INFO_MESSAGE   0x008F

Definition at line 375 of file chan_skinny.c.

Referenced by transmit_callinfo().

#define CALL_STATE_MESSAGE   0x0111

Definition at line 874 of file chan_skinny.c.

Referenced by transmit_callstate(), and transmit_callstateonly().

#define CAPABILITIES_REQ_MESSAGE   0x009B

Definition at line 510 of file chan_skinny.c.

Referenced by handle_register_message().

#define CAPABILITIES_RES_MESSAGE   0x0010

Definition at line 238 of file chan_skinny.c.

Referenced by handle_message().

#define CDEV   ((struct skinny_device *)item)

Definition at line 6596 of file chan_skinny.c.

Referenced by config_parse_variables().

#define CDEV_OPTS   ((struct skinny_device_options *)item)

Definition at line 6595 of file chan_skinny.c.

Referenced by config_parse_variables().

#define CLEAR_DISPLAY_MESSAGE   0x009A

Definition at line 508 of file chan_skinny.c.

Referenced by transmit_displaymessage().

#define CLEAR_NOTIFY_MESSAGE   0x0115

Definition at line 507 of file chan_skinny.c.

#define CLEAR_PROMPT_MESSAGE   0x0113

Definition at line 891 of file chan_skinny.c.

Referenced by transmit_displaypromptstatus().

#define CLINE   ((struct skinny_line *)item)

Definition at line 6594 of file chan_skinny.c.

Referenced by config_parse_variables().

#define CLINE_OPTS   ((struct skinny_line_options *)item)

Definition at line 6593 of file chan_skinny.c.

Referenced by config_parse_variables().

#define CLOSE_RECEIVE_CHANNEL_MESSAGE   0x0106

Definition at line 546 of file chan_skinny.c.

Referenced by transmit_callstate(), and transmit_closereceivechannel().

#define CONTROL2STR_BUFSIZE   100

Definition at line 185 of file chan_skinny.c.

Referenced by control2str().

#define DEFAULT_AUTH_LIMIT   50

Definition at line 104 of file chan_skinny.c.

Referenced by config_parse_variables().

#define DEFAULT_AUTH_TIMEOUT   30

Definition at line 103 of file chan_skinny.c.

Referenced by config_parse_variables().

#define DEFAULT_SKINNY_BACKLOG   2

Definition at line 101 of file chan_skinny.c.

Referenced by config_load().

#define DEFAULT_SKINNY_PORT   2000

Definition at line 100 of file chan_skinny.c.

Referenced by config_device(), and config_load().

#define DEFINETIMEDATE_MESSAGE   0x0094

Definition at line 424 of file chan_skinny.c.

Referenced by handle_time_date_req_message().

#define DEVICE2STR_BUFSIZE   15

Definition at line 182 of file chan_skinny.c.

Referenced by device2str().

#define DIALED_NUMBER_MESSAGE   0x011D

Definition at line 908 of file chan_skinny.c.

Referenced by transmit_dialednumber().

#define DISPLAY_NOTIFY_MESSAGE   0x0114

Definition at line 897 of file chan_skinny.c.

Referenced by transmit_displaynotify().

#define DISPLAY_PROMPT_STATUS_MESSAGE   0x0112

Definition at line 882 of file chan_skinny.c.

Referenced by transmit_displaypromptstatus().

#define DISPLAYTEXT_MESSAGE   0x0099

Definition at line 502 of file chan_skinny.c.

Referenced by transmit_displaymessage().

#define ENBLOC_CALL_MESSAGE   0x0004

Definition at line 214 of file chan_skinny.c.

Referenced by handle_message().

#define FORWARD_STAT_MESSAGE   0x0090

Definition at line 397 of file chan_skinny.c.

Referenced by transmit_cfwdstate().

#define HEADSET_STATUS_MESSAGE   0x002B

Definition at line 297 of file chan_skinny.c.

Referenced by handle_message().

#define htoles (   x)    (x)

Definition at line 129 of file chan_skinny.c.

#define IP_PORT_MESSAGE   0x0002

Definition at line 204 of file chan_skinny.c.

Referenced by handle_message().

#define KEEP_ALIVE_ACK_MESSAGE   0x0100

Definition at line 533 of file chan_skinny.c.

Referenced by handle_keep_alive_message().

#define KEEP_ALIVE_MESSAGE   0x0000

Definition at line 191 of file chan_skinny.c.

Referenced by handle_message().

#define KEYDEF_CONNECTED   1
#define KEYDEF_CONNWITHCONF   7

Definition at line 567 of file chan_skinny.c.

#define KEYDEF_CONNWITHTRANS   5

Definition at line 565 of file chan_skinny.c.

#define KEYDEF_DADFD   6

Definition at line 566 of file chan_skinny.c.

#define KEYDEF_OFFHOOK   4
#define KEYDEF_OFFHOOKWITHFEAT   9

Definition at line 569 of file chan_skinny.c.

Referenced by handle_transfer_button().

#define KEYDEF_ONHOLD   2

Definition at line 562 of file chan_skinny.c.

Referenced by handle_hold_button(), and handle_soft_key_event_message().

#define KEYDEF_ONHOOK   0

Definition at line 560 of file chan_skinny.c.

Referenced by handle_soft_key_set_req_message(), and transmit_callstate().

#define KEYDEF_RINGIN   3

Definition at line 563 of file chan_skinny.c.

Referenced by skinny_call().

#define KEYDEF_RINGOUT   8
#define KEYDEF_UNKNOWN   10

Definition at line 570 of file chan_skinny.c.

#define KEYPAD_BUTTON_MESSAGE   0x0003

Definition at line 206 of file chan_skinny.c.

Referenced by handle_message().

#define letohs (   x)    (x)

Definition at line 127 of file chan_skinny.c.

#define LINE_STAT_RES_MESSAGE   0x0092

Definition at line 416 of file chan_skinny.c.

Referenced by handle_line_state_req_message().

#define LINE_STATE_REQ_MESSAGE   0x000B

Definition at line 260 of file chan_skinny.c.

Referenced by handle_message().

#define OFFHOOK_MESSAGE   0x0006

Definition at line 226 of file chan_skinny.c.

Referenced by handle_message().

#define ONHOOK_MESSAGE   0x0007

Definition at line 232 of file chan_skinny.c.

Referenced by handle_message().

#define OPEN_RECEIVE_CHANNEL_ACK_MESSAGE   0x0022

Definition at line 278 of file chan_skinny.c.

Referenced by handle_message().

#define OPEN_RECEIVE_CHANNEL_MESSAGE   0x0105

Definition at line 535 of file chan_skinny.c.

Referenced by transmit_connect().

#define REGISTER_ACK_MESSAGE   0x0081

Definition at line 300 of file chan_skinny.c.

Referenced by handle_register_message().

#define REGISTER_AVAILABLE_LINES_MESSAGE   0x002D

Definition at line 298 of file chan_skinny.c.

Referenced by handle_message().

#define REGISTER_MESSAGE   0x0001

Definition at line 194 of file chan_skinny.c.

Referenced by handle_message().

#define REGISTER_REJ_MESSAGE   0x009D

Definition at line 512 of file chan_skinny.c.

Referenced by handle_register_message().

#define RESET_MESSAGE   0x009F

Definition at line 528 of file chan_skinny.c.

Referenced by handle_skinny_reset(), and skinny_reload().

#define SELECT_SOFT_KEYS_MESSAGE   0x0110

Definition at line 866 of file chan_skinny.c.

Referenced by transmit_selectsoftkeys().

#define SERVER_REQUEST_MESSAGE   0x0012

Definition at line 268 of file chan_skinny.c.

Referenced by handle_message().

#define SERVER_RES_MESSAGE   0x009E

Definition at line 517 of file chan_skinny.c.

Referenced by handle_server_request_message().

#define SET_LAMP_MESSAGE   0x0086

Definition at line 331 of file chan_skinny.c.

Referenced by transmit_lamp_indication().

#define SET_MICROPHONE_MESSAGE   0x0089

Definition at line 344 of file chan_skinny.c.

#define SET_RINGER_MESSAGE   0x0085

Definition at line 323 of file chan_skinny.c.

Referenced by transmit_ringer_mode().

#define SET_SPEAKER_MESSAGE   0x0088

Definition at line 338 of file chan_skinny.c.

Referenced by transmit_speaker_mode().

#define SKINNY_ALERT   0x24

Definition at line 1055 of file chan_skinny.c.

Referenced by skinny_call(), and skinny_indicate().

#define SKINNY_BUSY   6

Definition at line 1042 of file chan_skinny.c.

Referenced by skinny_indicate().

#define SKINNY_BUSYTONE   0x23

Definition at line 1054 of file chan_skinny.c.

Referenced by skinny_indicate().

#define SKINNY_CALLREMOTEMULTILINE   13

Definition at line 1049 of file chan_skinny.c.

Referenced by skinny_extensionstate_cb().

#define SKINNY_CALLWAIT   9

Definition at line 1045 of file chan_skinny.c.

#define SKINNY_CALLWAITTONE   0x2D

Definition at line 1057 of file chan_skinny.c.

Referenced by skinny_call().

#define SKINNY_CFWD_ALL   (1 << 0)
#define SKINNY_CFWD_BUSY   (1 << 1)
#define SKINNY_CFWD_NOANSWER   (1 << 2)
#define SKINNY_CONGESTION   7

Definition at line 1043 of file chan_skinny.c.

Referenced by skinny_indicate().

#define SKINNY_CONNECTED   5
#define SKINNY_CX_CONF   3

Definition at line 1079 of file chan_skinny.c.

#define SKINNY_CX_CONFERENCE   3

Definition at line 1080 of file chan_skinny.c.

#define SKINNY_CX_INACTIVE   4

Definition at line 1082 of file chan_skinny.c.

Referenced by skinny_new().

#define SKINNY_CX_MUTE   4

Definition at line 1081 of file chan_skinny.c.

#define SKINNY_CX_RECVONLY   1

Definition at line 1077 of file chan_skinny.c.

Referenced by handle_onhook_message(), and handle_soft_key_event_message().

#define SKINNY_CX_SENDONLY   0

Definition at line 1076 of file chan_skinny.c.

#define SKINNY_CX_SENDRECV   2

Definition at line 1078 of file chan_skinny.c.

Referenced by skinny_answer().

#define SKINNY_DEVICE_12   4

Definition at line 997 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_12SP   3

Definition at line 996 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_12SPPLUS   2

Definition at line 995 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_30SPPLUS   1

Definition at line 994 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_30VIP   5

Definition at line 998 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7902   30008

Definition at line 1024 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7905   20000

Definition at line 1020 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7906   369

Definition at line 1013 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7910   6

Definition at line 999 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7911   307

Definition at line 1008 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7912   30007

Definition at line 1023 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7914   124

Definition at line 1006 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7920   30002

Definition at line 1021 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7921   365

Definition at line 1012 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7931   348

Definition at line 1011 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7935   9

Definition at line 1002 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7936   30019

Definition at line 1027 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7937   431

Definition at line 1015 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7940   8

Definition at line 1001 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7941   115

Definition at line 1004 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7941GE   309

Definition at line 1010 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7942   434

Definition at line 1016 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7945   435

Definition at line 1017 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7960   7

Definition at line 1000 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7961   30018

Definition at line 1026 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7961GE   308

Definition at line 1009 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7962   404

Definition at line 1014 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7965   436

Definition at line 1018 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7970   30006

Definition at line 1022 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7971   119

Definition at line 1005 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7975   437

Definition at line 1019 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_7985   302

Definition at line 1007 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_ATA186   12

Definition at line 1003 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_CIPC   30016

Definition at line 1025 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_NONE   0

Definition at line 993 of file chan_skinny.c.

Referenced by device2str().

#define SKINNY_DEVICE_OPTIONS

Definition at line 1251 of file chan_skinny.c.

#define SKINNY_DEVICE_SCCPGATEWAY_AN   30027

Definition at line 1028 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_SCCPGATEWAY_BRI   30028

Definition at line 1029 of file chan_skinny.c.

Referenced by device2str(), and get_button_template().

#define SKINNY_DEVICE_UNKNOWN   -1

Definition at line 992 of file chan_skinny.c.

Referenced by device2str().

#define SKINNY_DEVONLY (   code)

Definition at line 78 of file chan_skinny.c.

Referenced by handle_message(), and transmit_response().

#define SKINNY_HOLD   8

Definition at line 1044 of file chan_skinny.c.

Referenced by skinny_extensionstate_cb(), and skinny_hold().

#define SKINNY_INVALID   14

Definition at line 1050 of file chan_skinny.c.

#define SKINNY_LAMP_BLINK   5

Definition at line 1064 of file chan_skinny.c.

Referenced by mwi_event_cb(), skinny_call(), skinny_extensionstate_cb(), and skinny_hangup().

#define SKINNY_LAMP_FLASH   4

Definition at line 1063 of file chan_skinny.c.

Referenced by skinny_extensionstate_cb().

#define SKINNY_LAMP_OFF   1
#define SKINNY_LAMP_WINK   3

Definition at line 1062 of file chan_skinny.c.

Referenced by skinny_extensionstate_cb(), and skinny_hold().

#define SKINNY_LINE_OPTIONS

Definition at line 1141 of file chan_skinny.c.

#define SKINNY_MAX_CAPABILITIES   18

Definition at line 248 of file chan_skinny.c.

Referenced by handle_capabilities_res_message().

#define SKINNY_MAX_PACKET   1000

Definition at line 102 of file chan_skinny.c.

Referenced by handle_register_message(), skinny_req_parse(), and transmit_response().

#define SKINNY_MICOFF   2

Definition at line 1035 of file chan_skinny.c.

#define SKINNY_MICON   1

Definition at line 1034 of file chan_skinny.c.

#define SKINNY_NOTONE   0x7F

Definition at line 1058 of file chan_skinny.c.

Referenced by transmit_tone().

#define SKINNY_PARK   11

Definition at line 1047 of file chan_skinny.c.

#define SKINNY_PROGRESS   12

Definition at line 1048 of file chan_skinny.c.

Referenced by skinny_indicate().

#define SKINNY_REORDER   0x25

Definition at line 1056 of file chan_skinny.c.

Referenced by skinny_indicate(), skinny_newcall(), and skinny_ss().

#define SKINNY_RING_FEATURE   4

Definition at line 1069 of file chan_skinny.c.

#define SKINNY_RING_INSIDE   2

Definition at line 1067 of file chan_skinny.c.

Referenced by skinny_call().

#define SKINNY_RING_OFF   1
#define SKINNY_RING_OUTSIDE   3

Definition at line 1068 of file chan_skinny.c.

#define SKINNY_RINGIN   4

Definition at line 1040 of file chan_skinny.c.

Referenced by skinny_call(), and skinny_extensionstate_cb().

#define SKINNY_RINGOUT   3

Definition at line 1039 of file chan_skinny.c.

Referenced by skinny_indicate().

#define SKINNY_SPEAKEROFF   2
#define SKINNY_SPEAKERON   1
#define SKINNY_TRANSFER   10

Definition at line 1046 of file chan_skinny.c.

#define SOFT_KEY_EVENT_MESSAGE   0x0026

Definition at line 288 of file chan_skinny.c.

Referenced by handle_message().

#define SOFT_KEY_SET_REQ_MESSAGE   0x0025

Definition at line 286 of file chan_skinny.c.

Referenced by handle_message().

#define SOFT_KEY_SET_RES_MESSAGE   0x0109

Definition at line 851 of file chan_skinny.c.

Referenced by handle_soft_key_set_req_message().

#define SOFT_KEY_TEMPLATE_REQ_MESSAGE   0x0028

Definition at line 296 of file chan_skinny.c.

Referenced by handle_message().

#define SOFT_KEY_TEMPLATE_RES_MESSAGE   0x0108

Definition at line 553 of file chan_skinny.c.

Referenced by handle_soft_key_template_req_message().

#define SOFTKEY_ANSWER   0x0B

Definition at line 583 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_BKSPC   0x08

Definition at line 580 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_CFWDALL   0x05

Definition at line 577 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_CFWDBUSY   0x06

Definition at line 578 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_CFWDNOANSWER   0x07

Definition at line 579 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_CONFRN   0x0D

Definition at line 585 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_DND   0x13

Definition at line 591 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_ENDCALL   0x09

Definition at line 581 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_GPICKUP   0x12

Definition at line 590 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_HOLD   0x03

Definition at line 575 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_IDIVERT   0x14

Definition at line 592 of file chan_skinny.c.

#define SOFTKEY_INFO   0x0C

Definition at line 584 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_JOIN   0x0F

Definition at line 587 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_MEETME   0x10

Definition at line 588 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_NEWCALL   0x02

Definition at line 574 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_NONE   0x00

Definition at line 572 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_PARK   0x0E

Definition at line 586 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_PICKUP   0x11

Definition at line 589 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_REDIAL   0x01

Definition at line 573 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_RESUME   0x0A

Definition at line 582 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SOFTKEY_TRNSFER   0x04

Definition at line 576 of file chan_skinny.c.

Referenced by handle_soft_key_event_message().

#define SPEED_DIAL_STAT_REQ_MESSAGE   0x000A

Definition at line 255 of file chan_skinny.c.

Referenced by handle_message().

#define SPEED_DIAL_STAT_RES_MESSAGE   0x0091

Definition at line 409 of file chan_skinny.c.

Referenced by handle_speed_dial_stat_req_message().

#define START_MEDIA_TRANSMISSION_MESSAGE   0x008A

Definition at line 349 of file chan_skinny.c.

Referenced by handle_open_receive_channel_ack_message(), and skinny_set_rtp_peer().

#define START_TONE_MESSAGE   0x0082

Definition at line 309 of file chan_skinny.c.

Referenced by transmit_tone().

#define STIMULUS_AUTOANSWER   0x11

Definition at line 459 of file chan_skinny.c.

#define STIMULUS_CALLPARK   0x7E

Definition at line 462 of file chan_skinny.c.

Referenced by handle_stimulus_message().

#define STIMULUS_CALLPICKUP   0x7F

Definition at line 463 of file chan_skinny.c.

#define STIMULUS_CONFERENCE   0x7D

Definition at line 461 of file chan_skinny.c.

Referenced by handle_stimulus_message().

#define STIMULUS_DISPLAY   0x08

Definition at line 456 of file chan_skinny.c.

Referenced by handle_stimulus_message().

#define STIMULUS_DND   0x3F

Definition at line 460 of file chan_skinny.c.

Referenced by handle_soft_key_event_message(), and handle_stimulus_message().

#define STIMULUS_FORWARDALL   0x05

Definition at line 453 of file chan_skinny.c.

Referenced by handle_stimulus_message(), and skinny_ss().

#define STIMULUS_FORWARDBUSY   0x06

Definition at line 454 of file chan_skinny.c.

Referenced by handle_stimulus_message().

#define STIMULUS_FORWARDNOANSWER   0x07

Definition at line 455 of file chan_skinny.c.

Referenced by handle_stimulus_message().

#define STIMULUS_HOLD   0x03

Definition at line 451 of file chan_skinny.c.

Referenced by handle_stimulus_message().

#define STIMULUS_MESSAGE   0x0005

Definition at line 219 of file chan_skinny.c.

Referenced by handle_message().

#define STIMULUS_NONE   0xFF

Definition at line 464 of file chan_skinny.c.

#define STIMULUS_REDIAL   0x01

Definition at line 449 of file chan_skinny.c.

Referenced by handle_stimulus_message().

#define STIMULUS_SPEEDDIAL   0x02

Definition at line 450 of file chan_skinny.c.

Referenced by handle_stimulus_message().

#define STIMULUS_TRANSFER   0x04

Definition at line 452 of file chan_skinny.c.

Referenced by handle_stimulus_message().

#define STIMULUS_VOICEMAIL   0x0F

Definition at line 458 of file chan_skinny.c.

Referenced by handle_stimulus_message(), and mwi_event_cb().

#define STOP_MEDIA_TRANSMISSION_MESSAGE   0x008B
#define STOP_TONE_MESSAGE   0x0083

Definition at line 317 of file chan_skinny.c.

Referenced by transmit_tone().

#define TIME_DATE_REQ_MESSAGE   0x000D

Definition at line 265 of file chan_skinny.c.

Referenced by handle_message().

#define TYPE_DEF_DEVICE   2

Definition at line 6588 of file chan_skinny.c.

Referenced by config_load(), and config_parse_variables().

#define TYPE_DEF_LINE   4

Definition at line 6589 of file chan_skinny.c.

Referenced by config_load(), and config_parse_variables().

#define TYPE_DEVICE   8

Definition at line 6590 of file chan_skinny.c.

Referenced by config_device(), and config_parse_variables().

#define TYPE_GENERAL   1

Definition at line 6587 of file chan_skinny.c.

Referenced by config_load(), and config_parse_variables().

#define TYPE_LINE   16

Definition at line 6591 of file chan_skinny.c.

Referenced by config_line(), and config_parse_variables().

#define UNREGISTER_MESSAGE   0x0027

Definition at line 295 of file chan_skinny.c.

Referenced by handle_message().

#define VERSION_REQ_MESSAGE   0x000F

Definition at line 267 of file chan_skinny.c.

Referenced by handle_message().

#define VERSION_RES_MESSAGE   0x0098

Definition at line 497 of file chan_skinny.c.

Referenced by handle_version_req_message().


Enumeration Type Documentation

Enumerator:
SKINNY_CODEC_ALAW 
SKINNY_CODEC_ULAW 
SKINNY_CODEC_G723_1 
SKINNY_CODEC_G729A 
SKINNY_CODEC_G726_32 
SKINNY_CODEC_H261 
SKINNY_CODEC_H263 

Definition at line 90 of file chan_skinny.c.

                   {
   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
};

Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 7494 of file chan_skinny.c.

static void __unreg_module ( void  ) [static]

Definition at line 7494 of file chan_skinny.c.

static char* _skinny_show_device ( int  type,
int  fd,
struct mansession s,
const struct message m,
int  argc,
const char *  argv[] 
) [static]

Definition at line 3069 of file chan_skinny.c.

References skinny_device::addons, ast_cli(), ast_getformatname_multiple(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, astman_append(), CLI_SHOWUSAGE, CLI_SUCCESS, device2str(), skinny_speeddial::exten, skinny_speeddial::isHint, skinny_speeddial::label, skinny_device::lines, S_OR, skinny_device::session, skinnysession::sin, skinny_device::speeddials, and skinny_addon::type.

Referenced by handle_skinny_show_device(), and manager_skinny_show_device().

{
   struct skinny_device *d;
   struct skinny_line *l;
   struct skinny_speeddial *sd;
   struct skinny_addon *sa;
   char codec_buf[512];

   if (argc < 4) {
      return CLI_SHOWUSAGE;
   }

   AST_LIST_LOCK(&devices);
   AST_LIST_TRAVERSE(&devices, d, list) {
      if (!strcasecmp(argv[3], d->id) || !strcasecmp(argv[3], d->name)) {
         int numlines = 0, numaddons = 0, numspeeddials = 0;

         AST_LIST_TRAVERSE(&d->lines, l, list){
            numlines++;
         }

         AST_LIST_TRAVERSE(&d->addons, sa, list) {
            numaddons++;
         }

         AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
            numspeeddials++;
         }

         if (type == 0) { /* CLI */
            ast_cli(fd, "Name:        %s\n", d->name);
            ast_cli(fd, "Id:          %s\n", d->id);
            ast_cli(fd, "version:     %s\n", S_OR(d->version_id, "Unknown"));
            ast_cli(fd, "Ip address:  %s\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown"));
            ast_cli(fd, "Port:        %d\n", (d->session ? ntohs(d->session->sin.sin_port) : 0));
            ast_cli(fd, "Device Type: %s\n", device2str(d->type));
            ast_cli(fd, "Conf Codecs:");
            ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, d->confcapability);
            ast_cli(fd, "%s\n", codec_buf);
            ast_cli(fd, "Neg Codecs: ");
            ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, d->capability);
            ast_cli(fd, "%s\n", codec_buf);
            ast_cli(fd, "Registered:  %s\n", (d->registered ? "Yes" : "No"));
            ast_cli(fd, "Lines:       %d\n", numlines);
            AST_LIST_TRAVERSE(&d->lines, l, list) {
               ast_cli(fd, "  %s (%s)\n", l->name, l->label);
            }
            AST_LIST_TRAVERSE(&d->addons, sa, list) {
               numaddons++;
            }  
            ast_cli(fd, "Addons:      %d\n", numaddons);
            AST_LIST_TRAVERSE(&d->addons, sa, list) {
               ast_cli(fd, "  %s\n", sa->type);
            }
            AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
               numspeeddials++;
            }
            ast_cli(fd, "Speeddials:  %d\n", numspeeddials);
            AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
               ast_cli(fd, "  %s (%s) ishint: %d\n", sd->exten, sd->label, sd->isHint);
            }
         } else { /* manager */
            astman_append(s, "Channeltype: SKINNY\r\n");
            astman_append(s, "ObjectName: %s\r\n", d->name);
            astman_append(s, "ChannelObjectType: device\r\n");
            astman_append(s, "Id: %s\r\n", d->id);
            astman_append(s, "version: %s\r\n", S_OR(d->version_id, "Unknown"));
            astman_append(s, "Ipaddress: %s\r\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown"));
            astman_append(s, "Port: %d\r\n", (d->session ? ntohs(d->session->sin.sin_port) : 0));
            astman_append(s, "DeviceType: %s\r\n", device2str(d->type));
            astman_append(s, "Codecs: ");
            ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, d->confcapability);
            astman_append(s, "%s\r\n", codec_buf);
            astman_append(s, "CodecOrder: ");
            ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, d->capability);
            astman_append(s, "%s\r\n", codec_buf);
            astman_append(s, "Devicestatus: %s\r\n", (d->registered?"registered":"unregistered"));
            astman_append(s, "NumberOfLines: %d\r\n", numlines);
            AST_LIST_TRAVERSE(&d->lines, l, list) {
               astman_append(s, "Line: %s (%s)\r\n", l->name, l->label);
            }
            astman_append(s, "NumberOfAddons: %d\r\n", numaddons);
            AST_LIST_TRAVERSE(&d->addons, sa, list) {
               astman_append(s, "Addon: %s\r\n", sa->type);
            }
            astman_append(s, "NumberOfSpeeddials: %d\r\n", numspeeddials);
            AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
               astman_append(s, "Speeddial: %s (%s) ishint: %d\r\n", sd->exten, sd->label, sd->isHint);
            }
         }
      }
   }
   AST_LIST_UNLOCK(&devices);
   return CLI_SUCCESS;
}
static char* _skinny_show_devices ( int  fd,
int *  total,
struct mansession s,
const struct message m,
int  argc,
const char *  argv[] 
) [static]

Definition at line 2951 of file chan_skinny.c.

References ast_cli(), ast_inet_ntoa(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), CLI_SHOWUSAGE, CLI_SUCCESS, device2str(), id, skinny_device::lines, skinny_device::session, and skinnysession::sin.

Referenced by handle_skinny_show_devices(), and manager_skinny_show_devices().

{
   struct skinny_device *d;
   struct skinny_line *l;
   const char *id;
   char idtext[256] = "";
   int total_devices = 0;

   if (s) { /* Manager - get ActionID */
      id = astman_get_header(m, "ActionID");
      if (!ast_strlen_zero(id))
         snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
   }

   switch (argc) {
   case 3:
      break;
   default:
      return CLI_SHOWUSAGE;
   }

   if (!s) {
      ast_cli(fd, "Name                 DeviceId         IP              Type            R NL\n");
      ast_cli(fd, "-------------------- ---------------- --------------- --------------- - --\n");
   }

   AST_LIST_LOCK(&devices);
   AST_LIST_TRAVERSE(&devices, d, list) {
      int numlines = 0;
      total_devices++;
      AST_LIST_TRAVERSE(&d->lines, l, list) {
         numlines++;
      }
      if (!s) {
         ast_cli(fd, "%-20s %-16s %-15s %-15s %c %2d\n",
            d->name,
            d->id,
            d->session?ast_inet_ntoa(d->session->sin.sin_addr):"",
            device2str(d->type),
            d->registered?'Y':'N',
            numlines);
      } else {
         astman_append(s,
            "Event: DeviceEntry\r\n%s"
            "Channeltype: SKINNY\r\n"
            "ObjectName: %s\r\n"
            "ChannelObjectType: device\r\n"
            "DeviceId: %s\r\n"
            "IPaddress: %s\r\n"
            "Type: %s\r\n"
            "Devicestatus: %s\r\n"
            "NumberOfLines: %d\r\n",
            idtext,
            d->name,
            d->id,
            d->session?ast_inet_ntoa(d->session->sin.sin_addr):"-none-",
            device2str(d->type),
            d->registered?"registered":"unregistered",
            numlines);
      }
   }
   AST_LIST_UNLOCK(&devices);

   if (total)
      *total = total_devices;
   
   return CLI_SUCCESS;
}
static char* _skinny_show_line ( int  type,
int  fd,
struct mansession s,
const struct message m,
int  argc,
const char *  argv[] 
) [static]

Definition at line 3343 of file chan_skinny.c.

References ast_callerid_merge(), ast_cdr_flags2str(), ast_cli(), ast_codec_pref_index(), ast_getformatname(), ast_getformatname_multiple(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_print_group(), astman_append(), CLI_SHOWUSAGE, CLI_SUCCESS, skinny_device::lines, print_codec_to_cli(), S_COR, S_OR, SKINNY_CFWD_ALL, SKINNY_CFWD_BUSY, and SKINNY_CFWD_NOANSWER.

Referenced by handle_skinny_show_line(), and manager_skinny_show_line().

{
   struct skinny_device *d;
   struct skinny_line *l;
   struct ast_codec_pref *pref;
   int x = 0, codec = 0;
   char codec_buf[512];
   char group_buf[256];
   char cbuf[256];

   switch (argc) {
   case 4:
      break;
   case 6:
      break;
   default:
      return CLI_SHOWUSAGE;
   }

   AST_LIST_LOCK(&devices);

   /* Show all lines matching the one supplied */
   AST_LIST_TRAVERSE(&devices, d, list) {
      if (argc == 6 && (strcasecmp(argv[5], d->id) && strcasecmp(argv[5], d->name))) {
         continue;
      }
      AST_LIST_TRAVERSE(&d->lines, l, list) {
         if (strcasecmp(argv[3], l->name)) {
            continue;
         }
         if (type == 0) { /* CLI */
            ast_cli(fd, "Line:             %s\n", l->name);
            ast_cli(fd, "On Device:        %s\n", d->name);
            ast_cli(fd, "Line Label:       %s\n", l->label);
            ast_cli(fd, "Extension:        %s\n", S_OR(l->exten, "<not set>"));
            ast_cli(fd, "Context:          %s\n", l->context);
            ast_cli(fd, "CallGroup:        %s\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup));
            ast_cli(fd, "PickupGroup:      %s\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup));
            ast_cli(fd, "Language:         %s\n", S_OR(l->language, "<not set>"));
            ast_cli(fd, "Accountcode:      %s\n", S_OR(l->accountcode, "<not set>"));
            ast_cli(fd, "AmaFlag:          %s\n", ast_cdr_flags2str(l->amaflags));
            ast_cli(fd, "CallerId Number:  %s\n", S_OR(l->cid_num, "<not set>"));
            ast_cli(fd, "CallerId Name:    %s\n", S_OR(l->cid_name, "<not set>"));
            ast_cli(fd, "Hide CallerId:    %s\n", (l->hidecallerid ? "Yes" : "No"));
            ast_cli(fd, "CFwdAll:          %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "<not set>"));
            ast_cli(fd, "CFwdBusy:         %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
            ast_cli(fd, "CFwdNoAnswer:     %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
            ast_cli(fd, "VoicemailBox:     %s\n", S_OR(l->mailbox, "<not set>"));
            ast_cli(fd, "VoicemailNumber:  %s\n", S_OR(l->vmexten, "<not set>"));
            ast_cli(fd, "MWIblink:         %d\n", l->mwiblink);
            ast_cli(fd, "Regextension:     %s\n", S_OR(l->regexten, "<not set>"));
            ast_cli(fd, "Regcontext:       %s\n", S_OR(l->regcontext, "<not set>"));
            ast_cli(fd, "MoHInterpret:     %s\n", S_OR(l->mohinterpret, "<not set>"));
            ast_cli(fd, "MoHSuggest:       %s\n", S_OR(l->mohsuggest, "<not set>"));
            ast_cli(fd, "Last dialed nr:   %s\n", S_OR(l->lastnumberdialed, "<no calls made yet>"));
            ast_cli(fd, "Last CallerID:    %s\n", S_OR(l->lastcallerid, "<not set>"));
            ast_cli(fd, "Transfer enabled: %s\n", (l->transfer ? "Yes" : "No"));
            ast_cli(fd, "Callwaiting:      %s\n", (l->callwaiting ? "Yes" : "No"));
            ast_cli(fd, "3Way Calling:     %s\n", (l->threewaycalling ? "Yes" : "No"));
            ast_cli(fd, "Can forward:      %s\n", (l->cancallforward ? "Yes" : "No"));
            ast_cli(fd, "Do Not Disturb:   %s\n", (l->dnd ? "Yes" : "No"));
            ast_cli(fd, "NAT:              %s\n", (l->nat ? "Yes" : "No"));
            ast_cli(fd, "immediate:        %s\n", (l->immediate ? "Yes" : "No"));
            ast_cli(fd, "Group:            %d\n", l->group);
            ast_cli(fd, "Parkinglot:       %s\n", S_OR(l->parkinglot, "<not set>"));
            ast_cli(fd, "Conf Codecs:      ");
            ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->confcapability);
            ast_cli(fd, "%s\n", codec_buf);
            ast_cli(fd, "Neg Codecs:       ");
            ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->capability);
            ast_cli(fd, "%s\n", codec_buf);
            ast_cli(fd, "Codec Order:      (");
            print_codec_to_cli(fd, &l->prefs);
            ast_cli(fd, ")\n");
            ast_cli(fd, "\n");
         } else { /* manager */
            astman_append(s, "Channeltype: SKINNY\r\n");
            astman_append(s, "ObjectName: %s\r\n", l->name);
            astman_append(s, "ChannelObjectType: line\r\n");
            astman_append(s, "Device: %s\r\n", d->name);
            astman_append(s, "LineLabel: %s\r\n", l->label);
            astman_append(s, "Extension: %s\r\n", S_OR(l->exten, "<not set>"));
            astman_append(s, "Context: %s\r\n", l->context);
            astman_append(s, "CallGroup: %s\r\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup));
            astman_append(s, "PickupGroup: %s\r\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup));
            astman_append(s, "Language: %s\r\n", S_OR(l->language, "<not set>"));
            astman_append(s, "Accountcode: %s\r\n", S_OR(l->accountcode, "<not set>"));
            astman_append(s, "AMAflags: %s\r\n", ast_cdr_flags2str(l->amaflags));
            astman_append(s, "Callerid: %s\r\n", ast_callerid_merge(cbuf, sizeof(cbuf), l->cid_name, l->cid_num, ""));
            astman_append(s, "HideCallerId: %s\r\n", (l->hidecallerid ? "Yes" : "No"));
            astman_append(s, "CFwdAll: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "<not set>"));
            astman_append(s, "CFwdBusy: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
            astman_append(s, "CFwdNoAnswer: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
            astman_append(s, "VoicemailBox: %s\r\n", S_OR(l->mailbox, "<not set>"));
            astman_append(s, "VoicemailNumber: %s\r\n", S_OR(l->vmexten, "<not set>"));
            astman_append(s, "MWIblink: %d\r\n", l->mwiblink);
            astman_append(s, "RegExtension: %s\r\n", S_OR(l->regexten, "<not set>"));
            astman_append(s, "Regcontext: %s\r\n", S_OR(l->regcontext, "<not set>"));
            astman_append(s, "MoHInterpret: %s\r\n", S_OR(l->mohinterpret, "<not set>"));
            astman_append(s, "MoHSuggest: %s\r\n", S_OR(l->mohsuggest, "<not set>"));
            astman_append(s, "LastDialedNr: %s\r\n", S_OR(l->lastnumberdialed, "<no calls made yet>"));
            astman_append(s, "LastCallerID: %s\r\n", S_OR(l->lastcallerid, "<not set>"));
            astman_append(s, "Transfer: %s\r\n", (l->transfer ? "Yes" : "No"));
            astman_append(s, "Callwaiting: %s\r\n", (l->callwaiting ? "Yes" : "No"));
            astman_append(s, "3WayCalling: %s\r\n", (l->threewaycalling ? "Yes" : "No"));
            astman_append(s, "CanForward: %s\r\n", (l->cancallforward ? "Yes" : "No"));
            astman_append(s, "DoNotDisturb: %s\r\n", (l->dnd ? "Yes" : "No"));
            astman_append(s, "NAT: %s\r\n", (l->nat ? "Yes" : "No"));
            astman_append(s, "immediate: %s\r\n", (l->immediate ? "Yes" : "No"));
            astman_append(s, "Group: %d\r\n", l->group);
            astman_append(s, "Parkinglot: %s\r\n", S_OR(l->parkinglot, "<not set>"));
            ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->confcapability);
            astman_append(s, "Codecs: %s\r\n", codec_buf);
            astman_append(s, "CodecOrder: ");
            pref = &l->prefs;
            for(x = 0; x < 32 ; x++) {
               codec = ast_codec_pref_index(pref, x);
               if (!codec)
                  break;
               astman_append(s, "%s", ast_getformatname(codec));
               if (x < 31 && ast_codec_pref_index(pref, x+1))
                  astman_append(s, ",");
            }
            astman_append(s, "\r\n");
         }
      }
   }
   
   AST_LIST_UNLOCK(&devices);
   return CLI_SUCCESS;
}
static char* _skinny_show_lines ( int  fd,
int *  total,
struct mansession s,
const struct message m,
int  argc,
const char *  argv[] 
) [static]

Definition at line 3208 of file chan_skinny.c.

References skinny_line::activesub, ast_bridged_channel(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), CLI_SHOWUSAGE, CLI_SUCCESS, skinny_line::device, id, ast_channel::name, skinny_subchannel::owner, and skinny_line::sub.

Referenced by handle_skinny_show_lines(), and manager_skinny_show_lines().

{
   struct skinny_line *l;
   struct skinny_subchannel *sub;
   int total_lines = 0;
   int verbose = 0;
   const char *id;
   char idtext[256] = "";

   if (s) { /* Manager - get ActionID */
      id = astman_get_header(m, "ActionID");
      if (!ast_strlen_zero(id))
         snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
   }

   switch (argc) {
   case 4:
      verbose = 1;
      break;
   case 3:
      verbose = 0;
      break;
   default:
      return CLI_SHOWUSAGE;
   }

   if (!s) {
      ast_cli(fd, "Name                 Device Name          Instance Label               \n");
      ast_cli(fd, "-------------------- -------------------- -------- --------------------\n");
   }
   AST_LIST_LOCK(&lines);
   AST_LIST_TRAVERSE(&lines, l, all) {
      total_lines++;
      if (!s) {
         ast_cli(fd, "%-20s %-20s %8d %-20s\n",
            l->name,
            (l->device ? l->device->name : "Not connected"),
            l->instance,
            l->label);
         if (verbose) {
            AST_LIST_TRAVERSE(&l->sub, sub, list) {
               ast_cli(fd, "  %s> %s to %s\n",
                  (sub == l->activesub?"Active  ":"Inactive"),
                  sub->owner->name,
                  (ast_bridged_channel(sub->owner)?ast_bridged_channel(sub->owner)->name:"")
               );
            }
         }
      } else {
         astman_append(s,
            "Event: LineEntry\r\n%s"
            "Channeltype: SKINNY\r\n"
            "ObjectName: %s\r\n"
            "ChannelObjectType: line\r\n"
            "Device: %s\r\n"
            "Instance: %d\r\n"
            "Label: %s\r\n",
            idtext,
            l->name,
            (l->device?l->device->name:"None"),
            l->instance,
            l->label);
      }
      AST_LIST_UNLOCK(&lines);
   }

   if (total) {
      *total = total_lines;
   }

   return CLI_SUCCESS;
}
static void* accept_thread ( void *  ignore) [static]

Definition at line 6428 of file chan_skinny.c.

References ast_atomic_fetchadd_int(), ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), ast_pthread_create, ast_verb, destroy_session(), errno, skinnysession::fd, skinnysession::lock, LOG_ERROR, LOG_NOTICE, LOG_WARNING, s, skinnysession::sin, skinny_session(), skinnysession::start, and skinnysession::t.

Referenced by config_load().

{
   int as;
   struct sockaddr_in sin;
   socklen_t sinlen;
   struct skinnysession *s;
   struct protoent *p;
   int arg = 1;

   for (;;) {
      sinlen = sizeof(sin);
      as = accept(skinnysock, (struct sockaddr *)&sin, &sinlen);
      if (as < 0) {
         ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
         continue;
      }

      if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= auth_limit) {
         close(as);
         ast_atomic_fetchadd_int(&unauth_sessions, -1);
         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));
         }
      }
      if (!(s = ast_calloc(1, sizeof(struct skinnysession)))) {
         close(as);
         ast_atomic_fetchadd_int(&unauth_sessions, -1);
         continue;
      }

      memcpy(&s->sin, &sin, sizeof(sin));
      ast_mutex_init(&s->lock);
      s->fd = as;

      if(time(&s->start) == -1) {
         ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
         destroy_session(s);
         continue;
      }

      AST_LIST_LOCK(&sessions);
      AST_LIST_INSERT_HEAD(&sessions, s, list);
      AST_LIST_UNLOCK(&sessions);

      if (ast_pthread_create(&s->t, NULL, skinny_session, s)) {
         destroy_session(s);
      }
   }
   if (skinnydebug)
      ast_verb(1, "killing accept thread\n");
   close(as);
   return 0;
}
static struct ast_variable* add_var ( const char *  buf,
struct ast_variable list 
) [static, read]

implement the setvar config line

Definition at line 1586 of file chan_skinny.c.

References ast_strdupa, ast_variable_new(), skinny_subchannel::list, and ast_variable::next.

Referenced by config_parse_variables().

{
   struct ast_variable *tmpvar = NULL;
   char *varname = ast_strdupa(buf), *varval = NULL;

   if ((varval = strchr(varname,'='))) {
      *varval++ = '\0';
      if ((tmpvar = ast_variable_new(varname, varval, ""))) {
         tmpvar->next = list;
         list = tmpvar;
      }
   }
   return list;
}
AST_THREADSTORAGE_CUSTOM_SCOPE ( device2str_threadbuf  ,
NULL  ,
ast_free_ptr  ,
static   
)
AST_THREADSTORAGE_CUSTOM_SCOPE ( control2str_threadbuf  ,
NULL  ,
ast_free_ptr  ,
static   
)
static void cleanup_stale_contexts ( char *  new,
char *  old 
) [static]

Definition at line 1747 of file chan_skinny.c.

References ast_context_destroy(), ast_context_find(), ast_copy_string(), AST_MAX_CONTEXT, and strsep().

Referenced by config_parse_variables().

{
   char *oldcontext, *newcontext, *stalecontext, *stringp, newlist[AST_MAX_CONTEXT];

   while ((oldcontext = strsep(&old, "&"))) {
      stalecontext = '\0';
      ast_copy_string(newlist, new, sizeof(newlist));
      stringp = newlist;
      while ((newcontext = strsep(&stringp, "&"))) {
         if (strcmp(newcontext, oldcontext) == 0) {
            /* This is not the context you're looking for */
            stalecontext = '\0';
            break;
         } else if (strcmp(newcontext, oldcontext)) {
            stalecontext = oldcontext;
         }
         
      }
      if (stalecontext)
         ast_context_destroy(ast_context_find(stalecontext), "Skinny");
   }
}
static char* complete_skinny_devices ( const char *  word,
int  state 
) [static]

Definition at line 2755 of file chan_skinny.c.

References AST_LIST_TRAVERSE, and ast_strdup.

Referenced by complete_skinny_reset(), and complete_skinny_show_device().

{
   struct skinny_device *d;
   char *result = NULL;
   int wordlen = strlen(word), which = 0;

   AST_LIST_TRAVERSE(&devices, d, list) {
      if (!strncasecmp(word, d->id, wordlen) && ++which > state)
         result = ast_strdup(d->id);
   }

   return result;
}
static char* complete_skinny_reset ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 2774 of file chan_skinny.c.

References ast_strdup, and complete_skinny_devices().

Referenced by handle_skinny_reset().

{
   return (pos == 2 ? ast_strdup(complete_skinny_devices(word, state)) : NULL);
}
static char* complete_skinny_show_device ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 2769 of file chan_skinny.c.

References ast_strdup, and complete_skinny_devices().

Referenced by handle_skinny_show_device().

{
   return (pos == 3 ? ast_strdup(complete_skinny_devices(word, state)) : NULL);
}
static char* complete_skinny_show_line ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 2779 of file chan_skinny.c.

References AST_LIST_TRAVERSE, ast_strdup, and skinny_device::lines.

Referenced by handle_skinny_show_line().

{
   struct skinny_device *d;
   struct skinny_line *l;
   char *result = NULL;
   int wordlen = strlen(word), which = 0;

   if (pos != 3)
      return NULL;
   
   AST_LIST_TRAVERSE(&devices, d, list) {
      AST_LIST_TRAVERSE(&d->lines, l, list) {
         if (!strncasecmp(word, l->name, wordlen) && ++which > state)
            result = ast_strdup(l->name);
      }
   }

   return result;
}
static struct skinny_device* config_device ( const char *  dname,
struct ast_variable v 
) [static, read]

Definition at line 7045 of file chan_skinny.c.

References skinny_device::addr, ast_calloc, ast_copy_string(), AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_verb, config_parse_variables(), default_device, DEFAULT_SKINNY_PORT, skinny_line::device, skinnysession::device, skinny_device::lines, skinny_line::lock, skinny_device::lock, LOG_ERROR, LOG_NOTICE, skinny_subchannel::parent, skinny_device::session, skinny_line::sub, TYPE_DEVICE, and update().

Referenced by config_load().

 {
   struct skinny_device *d, *temp;
   struct skinny_line *l, *ltemp;
   struct skinny_subchannel *sub;
   int update = 0;
 
   ast_log(LOG_NOTICE, "Configuring skinny device %s.\n", dname);

   AST_LIST_LOCK(&devices);
   AST_LIST_TRAVERSE(&devices, temp, list) {
      if (!strcasecmp(dname, temp->name) && temp->prune) {
         update = 1;
         break;
      }
   }

   if (!(d = ast_calloc(1, sizeof(*d)))) {
      ast_verb(1, "Unable to allocate memory for device %s.\n", dname);
      AST_LIST_UNLOCK(&devices);
      return NULL;
   }
   memcpy(d, default_device, sizeof(*default_device));
   ast_mutex_init(&d->lock);
   ast_copy_string(d->name, dname, sizeof(d->name));
   AST_LIST_INSERT_TAIL(&devices, d, list);

   ast_mutex_lock(&d->lock);
   AST_LIST_UNLOCK(&devices);
 
   config_parse_variables(TYPE_DEVICE, d, v);
 
   if (!AST_LIST_FIRST(&d->lines)) {
      ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n");
      ast_mutex_unlock(&d->lock);
      return NULL;
   }
   if (/*d->addr.sin_addr.s_addr && */!ntohs(d->addr.sin_port)) {
      d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
   }
 
   if (skinnyreload){
      AST_LIST_LOCK(&devices);
      AST_LIST_TRAVERSE(&devices, temp, list) {
         if (strcasecmp(d->id, temp->id) || !temp->prune || !temp->session) {
            continue;
         }
         ast_mutex_lock(&d->lock);
         d->session = temp->session;
         d->session->device = d;

         AST_LIST_LOCK(&d->lines);
         AST_LIST_TRAVERSE(&d->lines, l, list){
            l->device = d; 

            AST_LIST_LOCK(&temp->lines);
            AST_LIST_TRAVERSE(&temp->lines, ltemp, list) {
               if (strcasecmp(l->name, ltemp->name)) {
                  continue;
               }
               ast_mutex_lock(&ltemp->lock);
               l->instance = ltemp->instance;
               l->hookstate = ltemp->hookstate;
               if (!AST_LIST_EMPTY(&ltemp->sub)) {
                  ast_mutex_lock(&l->lock);
                  l->sub = ltemp->sub;
                  AST_LIST_TRAVERSE(&l->sub, sub, list) {
                     sub->parent = l;
                  }
                  ast_mutex_unlock(&l->lock);
               }
               ast_mutex_unlock(&ltemp->lock);
            }
            AST_LIST_UNLOCK(&temp->lines);
         }
         AST_LIST_UNLOCK(&d->lines);
         ast_mutex_unlock(&d->lock);
      }
      AST_LIST_UNLOCK(&devices);
   }

   ast_mutex_unlock(&d->lock);

   ast_verb(3, "%s config for device '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), d->name);
   
   return d;

 }
static struct skinny_line* config_line ( const char *  lname,
struct ast_variable v 
) [static, read]

Definition at line 6987 of file chan_skinny.c.

References skinny_line::all, ast_calloc, ast_copy_string(), AST_EVENT_IE_CONTEXT, AST_EVENT_IE_END, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_MWI, ast_event_subscribe(), AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), ast_verb, config_parse_variables(), default_line, skinny_line::lock, LOG_NOTICE, mwi_event_cb(), skinny_line::mwi_event_sub, strsep(), TYPE_LINE, and update().

Referenced by config_load().

 {
   struct skinny_line *l, *temp;
   int update = 0;
 
   ast_log(LOG_NOTICE, "Configuring skinny line %s.\n", lname);

   /* We find the old line and remove it just before the new
      line is created */
   AST_LIST_LOCK(&lines);
   AST_LIST_TRAVERSE(&lines, temp, all) {
      if (!strcasecmp(lname, temp->name) && temp->prune) {
         update = 1;
         break;
      }
   }

   if (!(l=ast_calloc(1, sizeof(*l)))) {
      ast_verb(1, "Unable to allocate memory for line %s.\n", lname);
      AST_LIST_UNLOCK(&lines);
      return NULL;
   }

   memcpy(l, default_line, sizeof(*default_line));
   ast_mutex_init(&l->lock);
   ast_copy_string(l->name, lname, sizeof(l->name));
   AST_LIST_INSERT_TAIL(&lines, l, all);

   ast_mutex_lock(&l->lock);
   AST_LIST_UNLOCK(&lines);

   config_parse_variables(TYPE_LINE, l, v);
         
   if (!ast_strlen_zero(l->mailbox)) {
      char *cfg_mailbox, *cfg_context;
      cfg_context = cfg_mailbox = ast_strdupa(l->mailbox);
      ast_verb(3, "Setting mailbox '%s' on line %s\n", cfg_mailbox, l->name);
      strsep(&cfg_context, "@");
      if (ast_strlen_zero(cfg_context))
          cfg_context = "default";
      l->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, l,
         AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, cfg_mailbox,
         AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cfg_context,
         AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
         AST_EVENT_IE_END);
   }
 
   ast_mutex_unlock(&l->lock);
   
   /* We do not want to unlink or free the line yet, it needs
      to be available to detect a device reconfig when we load the
      devices.  Old lines will be pruned after the reload completes */

   ast_verb(3, "%s config for line '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), l->name);

   return l;
 }
static int config_load ( void  ) [static]

Definition at line 7134 of file chan_skinny.c.

References __ourip, accept_thread(), ahp, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_gethostbyname(), ast_inet_ntoa(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_netsock_set_qos(), ast_pthread_create_background, ast_variable_browse(), ast_verb, bindaddr, config_device(), config_line(), config_parse_variables(), CONFIG_STATUS_FILEINVALID, default_capability, default_device, default_line, default_prefs, DEFAULT_SKINNY_BACKLOG, DEFAULT_SKINNY_PORT, errno, global_jbconf, LOG_ERROR, LOG_NOTICE, LOG_WARNING, netlock, qos, TYPE_DEF_DEVICE, TYPE_DEF_LINE, and TYPE_GENERAL.

Referenced by load_module(), and skinny_reload().

 {
   int on = 1;
   struct ast_config *cfg;
   char *cat;
   struct skinny_device *d;
   struct skinny_line *l;
   int oldport = ntohs(bindaddr.sin_port);
   struct ast_flags config_flags = { 0 };
   
   ast_log(LOG_NOTICE, "Configuring skinny from %s\n", config);
  
   if (gethostname(ourhost, sizeof(ourhost))) {
      ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled.\n");
      return 0;
   }
   cfg = ast_config_load(config, config_flags);
  
   /* We *must* have a config file otherwise stop immediately */
   if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled.\n", config);
      return -1;
   }
   memset(&bindaddr, 0, sizeof(bindaddr));
   memset(&default_prefs, 0, sizeof(default_prefs));

   /* Copy the default jb config over global_jbconf */
   memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));

   /* load the general section */
   cat = ast_category_browse(cfg, "general");
   config_parse_variables(TYPE_GENERAL, NULL, ast_variable_browse(cfg, "general"));

   if (ntohl(bindaddr.sin_addr.s_addr)) {
      __ourip = bindaddr.sin_addr;
   } else {
      hp = ast_gethostbyname(ourhost, &ahp);
      if (!hp) {
         ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
         ast_config_destroy(cfg);
         return 0;
      }
      memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
   }
   if (!ntohs(bindaddr.sin_port)) {
      bindaddr.sin_port = ntohs(DEFAULT_SKINNY_PORT);
   }
   bindaddr.sin_family = AF_INET;

   /* load the lines sections */
   default_line->confcapability = default_capability;
   default_line->confprefs = default_prefs;
   config_parse_variables(TYPE_DEF_LINE, default_line, ast_variable_browse(cfg, "lines"));
   cat = ast_category_browse(cfg, "lines");
   while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "devices")) {
      l = config_line(cat, ast_variable_browse(cfg, cat));
      cat = ast_category_browse(cfg, cat);
   }
      
   /* load the devices sections */
   default_device->confcapability = default_capability;
   default_device->confprefs = default_prefs;
   config_parse_variables(TYPE_DEF_DEVICE, default_device, ast_variable_browse(cfg, "devices"));
   cat = ast_category_browse(cfg, "devices");
   while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "lines")) {
      d = config_device(cat, ast_variable_browse(cfg, cat));
      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);
      if(setsockopt(skinnysock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
         ast_log(LOG_ERROR, "Set Socket Options failed: errno %d, %s\n", errno, strerror(errno));
         ast_config_destroy(cfg);
         ast_mutex_unlock(&netlock);
         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",
                  ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
                     strerror(errno));
            close(skinnysock);
            skinnysock = -1;
            ast_config_destroy(cfg);
            ast_mutex_unlock(&netlock);
            return 0;
         }
         if (listen(skinnysock, DEFAULT_SKINNY_BACKLOG)) {
               ast_log(LOG_WARNING, "Failed to start listening to %s:%d: %s\n",
                  ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
                     strerror(errno));
               close(skinnysock);
               skinnysock = -1;
               ast_config_destroy(cfg);
               ast_mutex_unlock(&netlock);
               return 0;
         }
         ast_verb(2, "Skinny listening on %s:%d\n",
               ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
         ast_netsock_set_qos(skinnysock, qos.tos, qos.cos, "Skinny");
         ast_pthread_create_background(&accept_t, NULL, accept_thread, NULL);
      }
   }
   ast_mutex_unlock(&netlock);
   ast_config_destroy(cfg);
   return 1;
}
static void config_parse_variables ( int  type,
void *  item,
struct ast_variable vptr 
) [static]

Definition at line 6598 of file chan_skinny.c.

References add_var(), ahp, skinny_line::all, ast_append_ha(), ast_callerid_split(), ast_calloc, ast_cdr_amaflags2int(), ast_context_find_or_create(), ast_copy_string(), ast_get_group(), ast_get_ip(), ast_gethostbyname(), ast_jb_read_conf(), AST_LIST_FIRST, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_log(), AST_MAX_CONTEXT, ast_mutex_init(), ast_parse_allow_disallow(), ast_str2cos(), ast_str2tos(), ast_strlen_zero(), ast_true(), bindaddr, buf, CDEV, CDEV_OPTS, cleanup_stale_contexts(), CLINE, CLINE_OPTS, skinny_speeddial::context, context, DEFAULT_AUTH_LIMIT, DEFAULT_AUTH_TIMEOUT, default_prefs, skinny_speeddial::exten, exten, global_jbconf, skinny_speeddial::instance, skinny_speeddial::isHint, skinny_speeddial::label, ast_variable::lineno, skinny_device::lines, skinny_addon::lock, skinny_speeddial::lock, LOG_WARNING, ast_variable::name, ast_variable::next, skinny_speeddial::parent, qos, S_OR, strsep(), skinny_addon::type, TYPE_DEF_DEVICE, TYPE_DEF_LINE, TYPE_DEVICE, TYPE_GENERAL, TYPE_LINE, and ast_variable::value.

Referenced by config_device(), config_line(), and config_load().

 {
   struct ast_variable *v;
   int lineInstance = 1;
   int speeddialInstance = 1;
   
   while(vptr) {
      v = vptr;
      vptr = vptr->next;
 
      if (type & (TYPE_GENERAL)) {
         char newcontexts[AST_MAX_CONTEXT];
         char oldcontexts[AST_MAX_CONTEXT];
         char *stringp, *context, *oldregcontext;
         if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
            v = v->next;
            continue;
         }
         if (!strcasecmp(v->name, "bindaddr")) {
            if (!(hp = ast_gethostbyname(v->value, &ahp))) {
               ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
            } else {
               memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
            }
            continue;
         } else if (!strcasecmp(v->name, "keepalive")) {
            keep_alive = atoi(v->value);
            continue;
         } else if (!strcasecmp(v->name, "authtimeout")) {
            int timeout = atoi(v->value);

            if (timeout < 1) {
               ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", v->value);
               auth_timeout = DEFAULT_AUTH_TIMEOUT;
            } else {
               auth_timeout = timeout;
            }
            continue;
         } else if (!strcasecmp(v->name, "authlimit")) {
            int limit = atoi(v->value);

            if (limit < 1) {
               ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", v->value);
               auth_limit = DEFAULT_AUTH_LIMIT;
            } else {
               auth_limit = limit;
            }
            continue;
         } else if (!strcasecmp(v->name, "regcontext")) {
            ast_copy_string(newcontexts, v->value, sizeof(newcontexts));
            stringp = newcontexts;
            /* Initialize copy of current global_regcontext for later use in removing stale contexts */
            ast_copy_string(oldcontexts, regcontext, sizeof(oldcontexts));
            oldregcontext = oldcontexts;
            /* Let's remove any contexts that are no longer defined in regcontext */
            cleanup_stale_contexts(stringp, oldregcontext);
            /* Create contexts if they don't exist already */
            while ((context = strsep(&stringp, "&"))) {
               ast_copy_string(used_context, context, sizeof(used_context));
               ast_context_find_or_create(NULL, NULL, context, "Skinny");
            }
            ast_copy_string(regcontext, v->value, sizeof(regcontext));
            continue;
         } else if (!strcasecmp(v->name, "dateformat")) {
            memcpy(date_format, v->value, sizeof(date_format));
            continue;
         } else if (!strcasecmp(v->name, "tos")) {
            if (ast_str2tos(v->value, &qos.tos))
               ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
            continue;
         } else if (!strcasecmp(v->name, "tos_audio")) {
            if (ast_str2tos(v->value, &qos.tos_audio))
               ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
            continue;
         } else if (!strcasecmp(v->name, "tos_video")) {
            if (ast_str2tos(v->value, &qos.tos_video))
               ast_log(LOG_WARNING, "Invalid tos_video value at line %d, refer to QoS documentation\n", v->lineno);
            continue;
         } else if (!strcasecmp(v->name, "cos")) {
            if (ast_str2cos(v->value, &qos.cos))
               ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
            continue;
         } else if (!strcasecmp(v->name, "cos_audio")) {
            if (ast_str2cos(v->value, &qos.cos_audio))
               ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
            continue;
         } else if (!strcasecmp(v->name, "cos_video")) {
            if (ast_str2cos(v->value, &qos.cos_video))
               ast_log(LOG_WARNING, "Invalid cos_video value at line %d, refer to QoS documentation\n", v->lineno);
            continue;
         } else if (!strcasecmp(v->name, "bindport")) {
            if (sscanf(v->value, "%5d", &ourport) == 1) {
               bindaddr.sin_port = htons(ourport);
            } else {
               ast_log(LOG_WARNING, "Invalid bindport '%s' at line %d of %s\n", v->value, v->lineno, config);
            }
            continue;
         } else if (!strcasecmp(v->name, "allow")) {
            ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 1);
            continue;
         } else if (!strcasecmp(v->name, "disallow")) {
            ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 0);
            continue;
         } 
      }
 
      if (!strcasecmp(v->name, "transfer")) {
         if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
            CDEV_OPTS->transfer = ast_true(v->value);
            continue;
         } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            CLINE_OPTS->transfer = ast_true(v->value);
            continue;
         }
      } else if (!strcasecmp(v->name, "callwaiting")) {
         if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
            CDEV_OPTS->callwaiting = ast_true(v->value);
            continue;
         } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            CLINE_OPTS->callwaiting = ast_true(v->value);
            continue;
         }
      } else if (!strcasecmp(v->name, "directmedia") || !strcasecmp(v->name, "canreinvite")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            CLINE_OPTS->directmedia = ast_true(v->value);
            continue;
         }
      } else if (!strcasecmp(v->name, "nat")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            CLINE_OPTS->nat = ast_true(v->value);
            continue;
         }
      } else if (!strcasecmp(v->name, "context")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            ast_copy_string(CLINE_OPTS->context, v->value, sizeof(CLINE_OPTS->context));
            continue;
         }
      }else if (!strcasecmp(v->name, "vmexten")) {
         if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
            ast_copy_string(CDEV_OPTS->vmexten, v->value, sizeof(CDEV_OPTS->vmexten));
            continue;
         } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            ast_copy_string(CLINE_OPTS->vmexten, v->value, sizeof(CLINE_OPTS->vmexten));
            continue;
         }
      } else if (!strcasecmp(v->name, "mwiblink")) {
         if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
            CDEV_OPTS->mwiblink = ast_true(v->value);
            continue;
         } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            CLINE_OPTS->mwiblink = ast_true(v->value);
            continue;
         }
      } else if (!strcasecmp(v->name, "linelabel")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            ast_copy_string(CLINE_OPTS->label, v->value, sizeof(CLINE_OPTS->label));
            continue;
         }
      } else if (!strcasecmp(v->name, "callerid")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            if (!strcasecmp(v->value, "asreceived")) {
               CLINE_OPTS->cid_num[0] = '\0';
               CLINE_OPTS->cid_name[0] = '\0';
            } else {
               ast_callerid_split(v->value, CLINE_OPTS->cid_name, sizeof(CLINE_OPTS->cid_name), CLINE_OPTS->cid_num, sizeof(CLINE_OPTS->cid_num));
            }
            continue;
         }
      } else if (!strcasecmp(v->name, "amaflags")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            int tempamaflags = ast_cdr_amaflags2int(v->value);
            if (tempamaflags < 0) {
               ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
            } else {
               CLINE_OPTS->amaflags = tempamaflags;
            }
            continue;
         }
      } else if (!strcasecmp(v->name, "regexten")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            ast_copy_string(CLINE_OPTS->regexten, v->value, sizeof(CLINE_OPTS->regexten));
            continue;
         }
      } else if (!strcasecmp(v->name, "language")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            ast_copy_string(CLINE_OPTS->language, v->value, sizeof(CLINE_OPTS->language));
            continue;
         }
      } else if (!strcasecmp(v->name, "accountcode")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            ast_copy_string(CLINE_OPTS->accountcode, v->value, sizeof(CLINE_OPTS->accountcode));
            continue;
         }
      } else if (!strcasecmp(v->name, "mohinterpret") || !strcasecmp(v->name, "musiconhold")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            ast_copy_string(CLINE_OPTS->mohinterpret, v->value, sizeof(CLINE_OPTS->mohinterpret));
            continue;
         }
      } else if (!strcasecmp(v->name, "mohsuggest")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            ast_copy_string(CLINE_OPTS->mohsuggest, v->value, sizeof(CLINE_OPTS->mohsuggest));
            continue;
         }
      } else if (!strcasecmp(v->name, "callgroup")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            CLINE_OPTS->callgroup = ast_get_group(v->value);
            continue;
         }
      } else if (!strcasecmp(v->name, "pickupgroup")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            CLINE_OPTS->pickupgroup = ast_get_group(v->value);
            continue;
         }
      } else if (!strcasecmp(v->name, "immediate")) {
         if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE | TYPE_DEF_LINE | TYPE_LINE)) {
            CLINE_OPTS->immediate = ast_true(v->value);
            continue;
         }
      } else if (!strcasecmp(v->name, "cancallforward")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            CLINE_OPTS->cancallforward = ast_true(v->value);
            continue;
         }
      } else if (!strcasecmp(v->name, "mailbox")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            ast_copy_string(CLINE_OPTS->mailbox, v->value, sizeof(CLINE_OPTS->mailbox));
            continue;
         }
      } else if ( !strcasecmp(v->name, "parkinglot")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            ast_copy_string(CLINE_OPTS->parkinglot, v->value, sizeof(CLINE_OPTS->parkinglot));
            continue;
         }
      } else if (!strcasecmp(v->name, "hasvoicemail")) {
         if (type & (TYPE_LINE)) {
            if (ast_true(v->value) && ast_strlen_zero(CLINE->mailbox)) {
               ast_copy_string(CLINE->mailbox, CLINE->name, sizeof(CLINE->mailbox));
            }
            continue;
         }
      } else if (!strcasecmp(v->name, "callreturn")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            CLINE_OPTS->callreturn = ast_true(v->value);
            continue;
         }
      } else if (!strcasecmp(v->name, "threewaycalling")) {
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            CLINE_OPTS->threewaycalling = ast_true(v->value);
            continue;
         }
      } else if (!strcasecmp(v->name, "setvar")) {
         if (type & (TYPE_LINE)) {
            CLINE->chanvars = add_var(v->value, CLINE->chanvars);
            continue;
         }
      } else if (!strcasecmp(v->name, "earlyrtp")) {
         if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
            CDEV_OPTS->earlyrtp = ast_true(v->value);
            continue;
         }
      } else if (!strcasecmp(v->name, "host")) {
         if (type & (TYPE_DEVICE)) {
            if (ast_get_ip(&CDEV->addr, v->value)) {
               ast_log(LOG_WARNING, "Bad IP '%s' at line %d.\n", v->value, v->lineno);
            }
            continue;
         }
      } else if (!strcasecmp(v->name, "port")) {
         if (type & (TYPE_DEF_DEVICE)) {
            CDEV->addr.sin_port = htons(atoi(v->value));
            continue;
         }
      } else if (!strcasecmp(v->name, "device")) {
         if (type & (TYPE_DEVICE)) {
            ast_copy_string(CDEV_OPTS->id, v->value, sizeof(CDEV_OPTS->id));
            continue;
         }
      } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
         if (type & (TYPE_DEVICE)) {
            CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, NULL);
            continue;
         }
      } else if (!strcasecmp(v->name, "allow")) {
         if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
            ast_parse_allow_disallow(&CDEV_OPTS->confprefs, &CDEV_OPTS->confcapability, v->value, 1);
            continue;
         }
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            ast_parse_allow_disallow(&CLINE_OPTS->confprefs, &CLINE_OPTS->confcapability, v->value, 1);
            continue;
         }
      } else if (!strcasecmp(v->name, "disallow")) {
         if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
            ast_parse_allow_disallow(&CDEV_OPTS->confprefs, &CDEV_OPTS->confcapability, v->value, 0);
            continue;
         }
         if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
            ast_parse_allow_disallow(&CLINE_OPTS->confprefs, &CLINE_OPTS->confcapability, v->value, 0);
            continue;
         }
      } else if (!strcasecmp(v->name, "version")) {
         if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
            ast_copy_string(CDEV_OPTS->version_id, v->value, sizeof(CDEV_OPTS->version_id));
            continue;
         }
      } else if (!strcasecmp(v->name, "line")) {
         if (type & (TYPE_DEVICE)) {
            struct skinny_line *l;
            AST_LIST_TRAVERSE(&lines, l, all) {
               if (!strcasecmp(v->value, l->name) && !l->prune) {

                  /* FIXME: temp solution about line conflicts */
                  struct skinny_device *d;
                  struct skinny_line *l2;
                  int lineinuse = 0;
                  AST_LIST_TRAVERSE(&devices, d, list) {
                     AST_LIST_TRAVERSE(&d->lines, l2, list) {
                        if (l2 == l && strcasecmp(d->id, CDEV->id)) {
                           ast_log(LOG_WARNING, "Line %s already used by %s. Not connecting to %s.\n", l->name, d->name, CDEV->name);
                           lineinuse++;
                        }
                     }
                  }
                  if (!lineinuse) {
                     if (!AST_LIST_FIRST(&CDEV->lines)) {
                        CDEV->activeline = l;
                     }
                     lineInstance++;
                     AST_LIST_INSERT_HEAD(&CDEV->lines, l, list);
                  }
                  break;
               }
            }
            continue;
         }
      } else if (!strcasecmp(v->name, "speeddial")) {
         if (type & (TYPE_DEVICE)) {
            struct skinny_speeddial *sd;
            if (!(sd = ast_calloc(1, sizeof(*sd)))) {
               ast_log(LOG_WARNING, "Unable to allocate memory for speeddial %s. Ignoring speeddial.\n", v->name);
               continue;
            } else {
               char buf[256];
               char *stringp = buf, *exten, *context, *label;
                  ast_copy_string(buf, v->value, sizeof(buf));
               exten = strsep(&stringp, ",");
               if ((context = strchr(exten, '@'))) {
                  *context++ = '\0';
               }
               label = stringp;
               ast_mutex_init(&sd->lock);
               ast_copy_string(sd->exten, exten, sizeof(sd->exten));
               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));
               sd->parent = CDEV;
               AST_LIST_INSERT_HEAD(&CDEV->speeddials, sd, list);
            }
            continue;
         }
      } else if (!strcasecmp(v->name, "addon")) {
         if (type & (TYPE_DEVICE)) {
            struct skinny_addon *a;
            if (!(a = ast_calloc(1, sizeof(*a)))) {
               ast_log(LOG_WARNING, "Unable to allocate memory for addon %s. Ignoring addon.\n", v->name);
               continue;
            } else {
               ast_mutex_init(&a->lock);
               ast_copy_string(a->type, v->value, sizeof(a->type));
               AST_LIST_INSERT_HEAD(&CDEV->addons, a, list);
            }
            continue;
         }

      } else {
         ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
         continue;
      }
      ast_log(LOG_WARNING, "Invalid category used: %s at line %d\n", v->name, v->lineno);
   }
 }
static char* control2str ( int  ind) [static]

Definition at line 4058 of file chan_skinny.c.

References AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_OPTION, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RADIO_KEY, AST_CONTROL_RADIO_UNKEY, AST_CONTROL_RING, AST_CONTROL_RINGING, AST_CONTROL_SRCUPDATE, AST_CONTROL_TAKEOFFHOOK, AST_CONTROL_UNHOLD, AST_CONTROL_WINK, ast_threadstorage_get(), and CONTROL2STR_BUFSIZE.

Referenced by skinny_indicate().

                                  {
   char *tmp;

   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";
   case AST_CONTROL_SRCUPDATE:
      return "Media Source Update";
   case -1:
      return "Stop tone";
   default:
      if (!(tmp = ast_threadstorage_get(&control2str_threadbuf, CONTROL2STR_BUFSIZE)))
                        return "Unknown";
      snprintf(tmp, CONTROL2STR_BUFSIZE, "UNKNOWN-%d", ind);
      return tmp;
   }
}
static void delete_devices ( void  ) [static]

Definition at line 7250 of file chan_skinny.c.

References skinny_device::addons, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, free, skinny_device::lines, and skinny_device::speeddials.

Referenced by unload_module().

{
   struct skinny_device *d;
   struct skinny_line *l;
   struct skinny_speeddial *sd;
   struct skinny_addon *a;

   AST_LIST_LOCK(&devices);
   AST_LIST_LOCK(&lines);

   /* Delete all devices */
   while ((d = AST_LIST_REMOVE_HEAD(&devices, list))) {
      /* Delete all lines for this device */
      while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) {
         AST_LIST_REMOVE(&lines, l, all);
         free(l);
      }
      /* Delete all speeddials for this device */
      while ((sd = AST_LIST_REMOVE_HEAD(&d->speeddials, list))) {
         free(sd);
      }
      /* Delete all addons for this device */
      while ((a = AST_LIST_REMOVE_HEAD(&d->addons, list))) {
         free(a);
      } 
      free(d);
   }
   AST_LIST_UNLOCK(&lines);
   AST_LIST_UNLOCK(&devices);
}
static char* device2str ( int  type) [static]

Definition at line 2844 of file chan_skinny.c.

References ast_threadstorage_get(), DEVICE2STR_BUFSIZE, SKINNY_DEVICE_12, SKINNY_DEVICE_12SP, SKINNY_DEVICE_12SPPLUS, SKINNY_DEVICE_30SPPLUS, SKINNY_DEVICE_30VIP, SKINNY_DEVICE_7902, SKINNY_DEVICE_7905, SKINNY_DEVICE_7906, SKINNY_DEVICE_7910, SKINNY_DEVICE_7911, SKINNY_DEVICE_7912, SKINNY_DEVICE_7914, SKINNY_DEVICE_7920, SKINNY_DEVICE_7921, SKINNY_DEVICE_7931, SKINNY_DEVICE_7935, SKINNY_DEVICE_7936, SKINNY_DEVICE_7937, SKINNY_DEVICE_7940, SKINNY_DEVICE_7941, SKINNY_DEVICE_7941GE, SKINNY_DEVICE_7942, SKINNY_DEVICE_7945, SKINNY_DEVICE_7960, SKINNY_DEVICE_7961, SKINNY_DEVICE_7961GE, SKINNY_DEVICE_7962, SKINNY_DEVICE_7965, SKINNY_DEVICE_7970, SKINNY_DEVICE_7971, SKINNY_DEVICE_7975, SKINNY_DEVICE_7985, SKINNY_DEVICE_ATA186, SKINNY_DEVICE_CIPC, SKINNY_DEVICE_NONE, SKINNY_DEVICE_SCCPGATEWAY_AN, SKINNY_DEVICE_SCCPGATEWAY_BRI, and SKINNY_DEVICE_UNKNOWN.

Referenced by _skinny_show_device(), and _skinny_show_devices().

{
   char *tmp;

   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_7914:
      return "7914";
   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_7931:
      return "7931";
   case SKINNY_DEVICE_7921:
      return "7921";
   case SKINNY_DEVICE_7906:
      return "7906";
   case SKINNY_DEVICE_7962:
      return "7962";
   case SKINNY_DEVICE_7937:
      return "7937";
   case SKINNY_DEVICE_7942:
      return "7942";
   case SKINNY_DEVICE_7945:
      return "7945";
   case SKINNY_DEVICE_7965:
      return "7965";
   case SKINNY_DEVICE_7975:
      return "7975";
   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:
      return "IP Communicator";
   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:
      if (!(tmp = ast_threadstorage_get(&device2str_threadbuf, DEVICE2STR_BUFSIZE)))
         return "Unknown";
      snprintf(tmp, DEVICE2STR_BUFSIZE, "UNKNOWN-%d", type);
      return tmp;
   }
}
static void* do_monitor ( void *  data) [static]

Definition at line 6487 of file chan_skinny.c.

References ast_io_wait(), ast_mutex_lock(), ast_mutex_unlock(), ast_sched_runq(), ast_sched_wait(), and monlock.

Referenced by restart_monitor().

{
   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);
      if ((res < 0) || (res > 1000)) {
         res = 1000;
      }
      res = ast_io_wait(io, res);
      ast_mutex_lock(&monlock);
      if (res >= 0) {
         ast_sched_runq(sched);
      }
      ast_mutex_unlock(&monlock);
   }
   /* Never reached */
   return NULL;

}
static struct skinny_line* find_line_by_instance ( struct skinny_device d,
int  instance 
) [static, read]

Definition at line 1514 of file chan_skinny.c.

References AST_LIST_TRAVERSE, ast_log(), skinny_device::lines, and LOG_WARNING.

Referenced by find_subchannel_by_instance_reference(), handle_enbloc_call_message(), handle_line_state_req_message(), handle_offhook_message(), handle_soft_key_event_message(), and handle_stimulus_message().

{
   struct skinny_line *l;

   /*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;

   AST_LIST_TRAVERSE(&d->lines, l, list){
      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;
}
static struct skinny_line* find_line_by_name ( const char *  dest) [static, read]

Definition at line 1535 of file chan_skinny.c.

References ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), ast_verb, and skinny_device::lines.

Referenced by skinny_devicestate(), and skinny_request().

{
   struct skinny_line *l;
   struct skinny_line *tmpl = NULL;
   struct skinny_device *d;
   char line[256];
   char *at;
   char *device;
   int checkdevice = 0;

   ast_copy_string(line, dest, sizeof(line));
   at = strchr(line, '@');
   if (at)
      *at++ = '\0';
   device = at;

   if (!ast_strlen_zero(device))
      checkdevice = 1;

   AST_LIST_LOCK(&devices);
   AST_LIST_TRAVERSE(&devices, d, list){
      if (checkdevice && tmpl)
         break;
      else if (!checkdevice) {
         /* This is a match, since we're checking for line on every device. */
      } else if (!strcasecmp(d->name, device)) {
         if (skinnydebug)
            ast_verb(2, "Found device: %s\n", d->name);
      } else
         continue;

      /* Found the device (or we don't care which device) */
      AST_LIST_TRAVERSE(&d->lines, l, list){
         /* Search for the right line */
         if (!strcasecmp(l->name, line)) {
            if (tmpl) {
               ast_verb(2, "Ambiguous line name: %s\n", line);
               AST_LIST_UNLOCK(&devices);
               return NULL;
            } else
               tmpl = l;
         }
      }
   }
   AST_LIST_UNLOCK(&devices);
   return tmpl;
}
static struct skinny_speeddial* find_speeddial_by_instance ( struct skinny_device d,
int  instance,
int  isHint 
) [static, read]

Definition at line 1653 of file chan_skinny.c.

References AST_LIST_TRAVERSE, ast_log(), skinny_speeddial::instance, skinny_speeddial::isHint, LOG_WARNING, and skinny_device::speeddials.

Referenced by handle_line_state_req_message(), handle_speed_dial_stat_req_message(), and handle_stimulus_message().

{
   struct skinny_speeddial *sd;

   AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
      if (sd->isHint == isHint && sd->instance == instance)
         break;
   }

   if (!sd) {
      ast_log(LOG_WARNING, "Could not find speeddial with instance '%d' on device '%s'\n", instance, d->name);
   }
   return sd;
}
static struct skinny_subchannel* find_subchannel_by_instance_reference ( struct skinny_device d,
int  instance,
int  reference 
) [static, read]

Definition at line 1602 of file chan_skinny.c.

References AST_LIST_FIRST, AST_LIST_TRAVERSE, ast_log(), skinny_subchannel::callid, find_line_by_instance(), LOG_WARNING, and skinny_line::sub.

Referenced by handle_enbloc_call_message(), handle_keypad_button_message(), handle_message(), handle_offhook_message(), handle_onhook_message(), handle_soft_key_event_message(), and handle_stimulus_message().

{
   struct skinny_line *l = find_line_by_instance(d, instance);
   struct skinny_subchannel *sub;

   if (!l) {
      return NULL;
   }

   /* 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 = AST_LIST_FIRST(&l->sub);
   else {
      AST_LIST_TRAVERSE(&l->sub, sub, list) {
         if (sub->callid == reference)
            break;
      }
   }
   if (!sub) {
      ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s'\n", reference, d->name);
   }
   return sub;
}
static struct skinny_subchannel* find_subchannel_by_reference ( struct skinny_device d,
int  reference 
) [static, read]

Definition at line 1629 of file chan_skinny.c.

References AST_LIST_TRAVERSE, ast_log(), skinny_subchannel::callid, skinny_device::lines, LOG_WARNING, and skinny_line::sub.

Referenced by handle_open_receive_channel_ack_message().

{
   struct skinny_line *l;
   struct skinny_subchannel *sub = NULL;

   AST_LIST_TRAVERSE(&d->lines, l, list){
      AST_LIST_TRAVERSE(&l->sub, sub, list){
         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;
}
static void* get_button_template ( struct skinnysession s,
struct button_definition_template btn 
) [static]

Definition at line 1363 of file chan_skinny.c.

References skinny_device::addons, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), BT_CALLPARK, BT_CONFERENCE, BT_CUST_LINE, BT_CUST_LINESPEEDDIAL, BT_DISPLAY, BT_FORWARDALL, BT_HOLD, BT_LINE, BT_NONE, BT_REDIAL, BT_SPEEDDIAL, BT_TRANSFER, BT_VOICEMAIL, skinnysession::device, LOG_WARNING, SKINNY_DEVICE_12, SKINNY_DEVICE_12SP, SKINNY_DEVICE_12SPPLUS, SKINNY_DEVICE_30SPPLUS, SKINNY_DEVICE_30VIP, SKINNY_DEVICE_7902, SKINNY_DEVICE_7905, SKINNY_DEVICE_7906, SKINNY_DEVICE_7910, SKINNY_DEVICE_7911, SKINNY_DEVICE_7912, SKINNY_DEVICE_7914, SKINNY_DEVICE_7920, SKINNY_DEVICE_7921, SKINNY_DEVICE_7931, SKINNY_DEVICE_7935, SKINNY_DEVICE_7936, SKINNY_DEVICE_7937, SKINNY_DEVICE_7940, SKINNY_DEVICE_7941, SKINNY_DEVICE_7941GE, SKINNY_DEVICE_7942, SKINNY_DEVICE_7945, SKINNY_DEVICE_7960, SKINNY_DEVICE_7961, SKINNY_DEVICE_7961GE, SKINNY_DEVICE_7962, SKINNY_DEVICE_7965, SKINNY_DEVICE_7970, SKINNY_DEVICE_7971, SKINNY_DEVICE_7975, SKINNY_DEVICE_7985, SKINNY_DEVICE_ATA186, SKINNY_DEVICE_CIPC, SKINNY_DEVICE_SCCPGATEWAY_AN, SKINNY_DEVICE_SCCPGATEWAY_BRI, and skinny_addon::type.

Referenced by handle_button_template_req_message().

{
   struct skinny_device *d = s->device;
   struct skinny_addon *a;
   int i;

   switch (d->type) {
      case SKINNY_DEVICE_30SPPLUS:
      case SKINNY_DEVICE_30VIP:
         /* 13 rows, 2 columns */
         for (i = 0; i < 4; i++)
            (btn++)->buttonDefinition = BT_CUST_LINE;
         (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++)
            (btn++)->buttonDefinition = BT_CUST_LINE;
         for (i = 0; i < 4; i++)
            (btn++)->buttonDefinition = BT_SPEEDDIAL;
         (btn++)->buttonDefinition = BT_HOLD;
         (btn++)->buttonDefinition = BT_REDIAL;
         (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:
      case SKINNY_DEVICE_7962:
      case SKINNY_DEVICE_7965:
         for (i = 0; i < 6; i++)
            (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
         break;
      case SKINNY_DEVICE_7940:
      case SKINNY_DEVICE_7941:
      case SKINNY_DEVICE_7941GE:
      case SKINNY_DEVICE_7942:
      case SKINNY_DEVICE_7945:
         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_7975:
      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_7921:
         for (i = 0; i < 6; 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_7906:
         ast_log(LOG_WARNING, "Unsupported device type '%d (7906)' found.\n", d->type);
         break;
      case SKINNY_DEVICE_7931:
         ast_log(LOG_WARNING, "Unsupported device type '%d (7931)' found.\n", d->type);
         break;
      case SKINNY_DEVICE_7937:
         ast_log(LOG_WARNING, "Unsupported device type '%d (7937)' found.\n", d->type);
         break;
      case SKINNY_DEVICE_7914:
         ast_log(LOG_WARNING, "Unsupported device type '%d (7914)' found.  Expansion module registered by itself?\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;
   }

   AST_LIST_LOCK(&d->addons);
   AST_LIST_TRAVERSE(&d->addons, a, list) {
      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);
      }
   }
   AST_LIST_UNLOCK(&d->addons);

   return btn;
}
static int get_devicestate ( struct skinny_line l) [static]

Definition at line 4029 of file chan_skinny.c.

References AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, AST_LIST_TRAVERSE, skinny_line::device, skinny_subchannel::onhold, SKINNY_ONHOOK, and skinny_line::sub.

Referenced by skinny_devicestate(), and skinny_new().

{
   struct skinny_subchannel *sub;
   int res = AST_DEVICE_UNKNOWN;

   if (!l)
      res = AST_DEVICE_INVALID;
   else if (!l->device)
      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;
      }

      AST_LIST_TRAVERSE(&l->sub, sub, list) {
         if (sub->onhold) {
            res = AST_DEVICE_ONHOLD;
            break;
         }
      }
   }

   return res;
}
static int get_input ( struct skinnysession s) [static]

Definition at line 6269 of file chan_skinny.c.

References ast_debug, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_poll, ast_verb, skinnysession::device, errno, skinnysession::fd, htolel, skinnysession::inbuf, letohl, skinnysession::lock, LOG_ERROR, LOG_WARNING, skinny_unregister(), and skinnysession::start.

Referenced by skinny_session().

{
   int res;
   int dlen = 0;
   int timeout = keep_alive * 1100;
   time_t now;
   int *bufaddr;
   struct pollfd fds[1];

   if (!s->device) {
      if(time(&now) == -1) {
         ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
         return -1;
      }

      timeout = (auth_timeout - (now - s->start)) * 1000;
      if (timeout < 0) {
         /* we have timed out */
         if (skinnydebug)
            ast_verb(1, "Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
         return -1;
      }
   }

   fds[0].fd = s->fd;
   fds[0].events = POLLIN;
   fds[0].revents = 0;
   res = ast_poll(fds, 1, timeout); /* If nothing has happen, client is dead */
                   /* we add 10% to the keep_alive to deal */
                   /* with network delays, etc */
   if (res < 0) {
      if (errno != EINTR) {
         ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
         return res;
      }
   } else if (res == 0) {
      if (skinnydebug) {
         if (s->device) {
            ast_verb(1, "Skinny Client was lost, unregistering\n");
         } else {
            ast_verb(1, "Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
         }
      }
      skinny_unregister(NULL, s);
      return -1;
   }
           
   if (fds[0].revents) {
      ast_mutex_lock(&s->lock);
      memset(s->inbuf, 0, sizeof(s->inbuf));
      res = read(s->fd, s->inbuf, 4);
      if (res < 0) {
         ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));

         if (skinnydebug)
            ast_verb(1, "Skinny Client was lost, unregistering\n");

         skinny_unregister(NULL, s);
         ast_mutex_unlock(&s->lock);
         return res;
      } else if (res != 4) {
         ast_log(LOG_WARNING, "Skinny Client sent less data than expected.  Expected 4 but got %d.\n", res);
         ast_mutex_unlock(&s->lock);
         
         if (res == 0) {
            if (skinnydebug)
               ast_verb(1, "Skinny Client was lost, unregistering\n");
            skinny_unregister(NULL, s);
         }

         return -1;
      }

      bufaddr = (int *)s->inbuf;
      dlen = letohl(*bufaddr);
      if (dlen < 4) {
         ast_debug(1, "Skinny Client sent invalid data.\n");
         ast_mutex_unlock(&s->lock);
         return -1;
      }
      if (dlen+8 > sizeof(s->inbuf)) {
         dlen = sizeof(s->inbuf) - 8;
      }
      *bufaddr = htolel(dlen);

      res = read(s->fd, s->inbuf+4, dlen+4);
      ast_mutex_unlock(&s->lock);
      if (res < 0) {
         ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
         return res;
      } else if (res != (dlen+4)) {
         ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
         return -1;
      }
      return res;
   }
   return 0;
}
static int handle_alarm_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 5517 of file chan_skinny.c.

References skinny_data::alarm, ast_verb, skinny_req::data, and alarm_message::displayMessage.

Referenced by handle_message().

{
   /* no response necessary */
   if (skinnydebug)
      ast_verb(1, "Received Alarm Message: %s\n", req->data.alarm.displayMessage);

   return 1;
}
static int handle_button_template_req_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 5344 of file chan_skinny.c.

References AST_LIST_TRAVERSE, ast_verb, BT_CUST_LINE, BT_CUST_LINESPEEDDIAL, BT_LINE, BT_NONE, BT_SPEEDDIAL, BUTTON_TEMPLATE_RES_MESSAGE, button_template_res_message::buttonCount, button_definition::buttonDefinition, button_definition_template::buttonDefinition, button_template_res_message::buttonOffset, skinny_data::buttontemplate, skinny_req::data, button_template_res_message::definition, skinnysession::device, get_button_template(), htolel, skinny_speeddial::instance, button_definition::instanceNumber, skinny_speeddial::isHint, skinny_device::lines, req_alloc(), skinny_device::speeddials, button_template_res_message::totalButtonCount, and transmit_response().

Referenced by handle_message().

{
   struct skinny_device *d = s->device;
   struct skinny_line *l;
   int i;

   struct skinny_speeddial *sd;
   struct button_definition_template btn[42];
   int lineInstance = 1;
   int speeddialInstance = 1;
   int buttonCount = 0;

   if (!(req = req_alloc(sizeof(struct button_template_res_message), BUTTON_TEMPLATE_RES_MESSAGE)))
      return -1;

   memset(&btn, 0, sizeof(btn));

   get_button_template(s, btn);

   for (i=0; i<42; i++) {
      int btnSet = 0;
      switch (btn[i].buttonDefinition) {
         case BT_CUST_LINE:
            /* assume failure */
            req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE;
            req->data.buttontemplate.definition[i].instanceNumber = htolel(0);

            AST_LIST_TRAVERSE(&d->lines, l, list) {
               if (l->instance == lineInstance) {
                  ast_verb(0, "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) {
               AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
                  if (sd->isHint && sd->instance == lineInstance) {
                     ast_verb(0, "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;
         case BT_CUST_LINESPEEDDIAL:
            /* assume failure */
            req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE;
            req->data.buttontemplate.definition[i].instanceNumber = htolel(0);

            AST_LIST_TRAVERSE(&d->lines, l, list) {
               if (l->instance == lineInstance) {
                  ast_verb(0, "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) {
               AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
                  if (sd->isHint && sd->instance == lineInstance) {
                     ast_verb(0, "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) {
                     ast_verb(0, "Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
                     req->data.buttontemplate.definition[i].buttonDefinition = BT_SPEEDDIAL;
                     req->data.buttontemplate.definition[i].instanceNumber = htolel(speeddialInstance);
                     speeddialInstance++;
                     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);

            AST_LIST_TRAVERSE(&d->lines, l, list) {
               if (l->instance == lineInstance) {
                  ast_verb(0, "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;
         case BT_SPEEDDIAL:
            req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE;
            req->data.buttontemplate.definition[i].instanceNumber = 0;

            AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
               if (!sd->isHint && sd->instance == speeddialInstance) {
                  ast_verb(0, "Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
                  req->data.buttontemplate.definition[i].buttonDefinition = BT_SPEEDDIAL;
                  req->data.buttontemplate.definition[i].instanceNumber = htolel(speeddialInstance - 1);
                  speeddialInstance++;
                  buttonCount++;
                  btnSet = 1;
                  break;
               }
            }
            break;
         case BT_NONE:
            break;
         default:
            ast_verb(0, "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_verb(1, "Sending %d template to %s\n",
               d->type,
               d->name);
   transmit_response(d, req);
   return 1;
}
static int handle_callforward_button ( struct skinny_subchannel sub,
int  cfwdtype 
) [static]

Definition at line 4595 of file chan_skinny.c.

References ast_channel::_state, ast_hangup(), ast_indicate(), ast_log(), ast_pthread_create, ast_safe_sleep(), AST_STATE_UP, ast_verb, skinny_subchannel::callid, skinny_line::device, errno, KEYDEF_RINGOUT, LOG_WARNING, skinny_subchannel::owner, skinny_subchannel::parent, set_callforwards(), SKINNY_DIALTONE, SKINNY_OFFHOOK, SKINNY_ONHOOK, SKINNY_SPEAKEROFF, SKINNY_SPEAKERON, skinny_ss(), transmit_callstate(), transmit_cfwdstate(), transmit_displaymessage(), transmit_displaynotify(), transmit_selectsoftkeys(), transmit_speaker_mode(), and transmit_tone().

Referenced by handle_soft_key_event_message(), and handle_stimulus_message().

{
   struct skinny_line *l = sub->parent;
   struct skinny_device *d = l->device;
   struct ast_channel *c = sub->owner;
   pthread_t t;

   if (l->hookstate == SKINNY_ONHOOK) {
      l->hookstate = SKINNY_OFFHOOK;
      transmit_speaker_mode(d, SKINNY_SPEAKERON);
      transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid);
   }
   if (skinnydebug)
      ast_verb(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
   transmit_displaymessage(d, NULL, l->instance, sub->callid); /* clear display */

   if (l->cfwdtype & cfwdtype) {
      set_callforwards(l, NULL, cfwdtype);
      ast_safe_sleep(c, 500);
      transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
      transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->callid);
      transmit_displaynotify(d, "CFwd disabled", 10);
      if (sub->owner && sub->owner->_state != AST_STATE_UP) {
         ast_indicate(c, -1);
         ast_hangup(c);
      }
      transmit_cfwdstate(d, l);
   } else {
      l->getforward = cfwdtype;
      transmit_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
      transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
      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);
      }
   }
   return 0;
}
static int handle_capabilities_res_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 5224 of file chan_skinny.c.

References AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_verb, capabilities_res_message::caps, skinny_data::caps, station_capabilities::codec, codec_skinny2ast(), capabilities_res_message::count, skinny_req::data, skinnysession::device, letohl, skinny_device::lines, skinny_line::lock, LOG_WARNING, and SKINNY_MAX_CAPABILITIES.

Referenced by handle_message().

{
   struct skinny_device *d = s->device;
   struct skinny_line *l;
   uint32_t count = 0;
   int codecs = 0;
   int i;

   count = letohl(req->data.caps.count);
   if (count > SKINNY_MAX_CAPABILITIES) {
      count = SKINNY_MAX_CAPABILITIES;
      ast_log(LOG_WARNING, "Received more capabilities than we can handle (%d).  Ignoring the rest.\n", SKINNY_MAX_CAPABILITIES);
   }

   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_verb(1, "Adding codec capability '%d (%d)'\n", acodec, scodec);
      codecs |= acodec;
   }

   d->capability = d->confcapability & codecs;
   ast_verb(0, "Device capability set to '%d'\n", d->capability);
   AST_LIST_TRAVERSE(&d->lines, l, list) {
      ast_mutex_lock(&l->lock);
      l->capability = l->confcapability & d->capability;
      ast_mutex_unlock(&l->lock);
   }

   return 1;
}
static int handle_enbloc_call_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 5593 of file chan_skinny.c.

References skinny_line::activesub, ast_copy_string(), ast_hangup(), ast_ignore_pattern(), ast_log(), ast_pthread_create, AST_STATE_DOWN, ast_verb, enbloc_call_message::calledParty, skinny_subchannel::callid, ast_channel::context, skinny_req::data, skinnysession::device, skinny_data::enbloccallmessage, errno, ast_channel::exten, find_line_by_instance(), find_subchannel_by_instance_reference(), LOG_WARNING, skinny_subchannel::parent, SKINNY_DIALTONE, skinny_new(), skinny_newcall(), SKINNY_OFFHOOK, SKINNY_SILENCE, ast_channel::tech_pvt, transmit_callstate(), transmit_displaymessage(), and transmit_tone().

Referenced by handle_message().

{
   struct skinny_device *d = s->device;
   struct skinny_line *l;
   struct skinny_subchannel *sub = NULL;
   struct ast_channel *c;
   pthread_t t;

   if (skinnydebug)
      ast_verb(1, "Received Enbloc Call: %s\n", req->data.enbloccallmessage.calledParty);

   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;
   }

   c = skinny_new(l, AST_STATE_DOWN);

   if(!c) {
      ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
   } else {
      l->hookstate = SKINNY_OFFHOOK;

      sub = c->tech_pvt;
      l->activesub = sub;
      transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid);
      if (skinnydebug)
         ast_verb(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
      transmit_displaymessage(d, NULL, l->instance, sub->callid); /* clear display */
      transmit_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);

      if (!ast_ignore_pattern(c->context, req->data.enbloccallmessage.calledParty)) {
         transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
      }
      ast_copy_string(c->exten, req->data.enbloccallmessage.calledParty, 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);
      }
   }
   
   return 1;
}
static int handle_headset_status_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 6060 of file chan_skinny.c.

Referenced by handle_message().

{
   /* XXX umm...okay?  Why do I care? */
   return 1;
}
static int handle_hold_button ( struct skinny_subchannel sub) [static]
static int handle_ip_port_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 4633 of file chan_skinny.c.

Referenced by handle_message().

{
   /* no response necessary */
   return 1;
}
static int handle_keep_alive_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 4519 of file chan_skinny.c.

References skinnysession::device, KEEP_ALIVE_ACK_MESSAGE, req_alloc(), and transmit_response().

Referenced by handle_message().

{
   if (!(req = req_alloc(0, KEEP_ALIVE_ACK_MESSAGE)))
      return -1;

   transmit_response(s->device, req);
   return 1;
}
static int handle_keypad_button_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 4639 of file chan_skinny.c.

References ast_channel::_state, skinny_device::activeline, skinny_line::activesub, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_LIST_NEXT, ast_log(), ast_queue_frame(), ast_verb, keypad_button_message::button, keypad_button_message::callReference, skinny_req::data, skinnysession::device, find_subchannel_by_instance_reference(), ast_frame::frametype, skinny_data::keypad, letohl, keypad_button_message::lineInstance, LOG_WARNING, skinny_subchannel::owner, skinny_subchannel::parent, ast_frame::src, and ast_frame::subclass.

Referenced by handle_message().

{
   struct skinny_subchannel *sub = NULL;
   struct skinny_line *l;
   struct skinny_device *d = s->device;
   struct ast_frame f = { 0, };
   char dgt;
   int digit;
   int lineInstance;
   int callReference;

   digit = letohl(req->data.keypad.button);
   lineInstance = letohl(req->data.keypad.lineInstance);
   callReference = letohl(req->data.keypad.callReference);

   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);
   }

   f.subclass = dgt;

   f.src = "skinny";

   if (lineInstance && callReference)
      sub = find_subchannel_by_instance_reference(d, lineInstance, callReference);
   else
      sub = d->activeline->activesub;
      //sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);

   if (!sub)
      return 0;

   l = sub->parent;
   if (sub->owner) {
      if (sub->owner->_state == 0) {
         f.frametype = AST_FRAME_DTMF_BEGIN;
         ast_queue_frame(sub->owner, &f);
      }
      /* XXX MUST queue this frame to all lines in threeway call if threeway call is active */
      f.frametype = AST_FRAME_DTMF_END;
      ast_queue_frame(sub->owner, &f);
      /* XXX This seriously needs to be fixed */
      if (AST_LIST_NEXT(sub, list) && AST_LIST_NEXT(sub, list)->owner) {
         if (sub->owner->_state == 0) {
            f.frametype = AST_FRAME_DTMF_BEGIN;
            ast_queue_frame(AST_LIST_NEXT(sub, list)->owner, &f);
         }
         f.frametype = AST_FRAME_DTMF_END;
         ast_queue_frame(AST_LIST_NEXT(sub, list)->owner, &f);
      }
   } else {
      if (skinnydebug)
         ast_verb(1, "No owner: %s\n", l->name);
   }
   return 1;
}
static int handle_line_state_req_message ( struct skinny_req req,
struct skinnysession s 
) [static]
static int handle_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 6072 of file chan_skinny.c.

References ast_channel::_state, skinny_device::activeline, skinny_line::activesub, ALARM_MESSAGE, ast_free, ast_log(), AST_STATE_UP, ast_verb, keypad_button_message::button, BUTTON_TEMPLATE_REQ_MESSAGE, keypad_button_message::callReference, CAPABILITIES_RES_MESSAGE, skinny_req::data, skinnysession::device, skinny_req::e, ENBLOC_CALL_MESSAGE, find_subchannel_by_instance_reference(), handle_alarm_message(), handle_button_template_req_message(), handle_capabilities_res_message(), handle_enbloc_call_message(), handle_headset_status_message(), handle_ip_port_message(), handle_keep_alive_message(), handle_keypad_button_message(), handle_line_state_req_message(), handle_offhook_message(), handle_onhook_message(), handle_open_receive_channel_ack_message(), handle_register_available_lines_message(), handle_register_message(), handle_server_request_message(), handle_soft_key_event_message(), handle_soft_key_set_req_message(), handle_soft_key_template_req_message(), handle_speed_dial_stat_req_message(), handle_stimulus_message(), handle_time_date_req_message(), handle_unregister_message(), handle_version_req_message(), HEADSET_STATUS_MESSAGE, IP_PORT_MESSAGE, KEEP_ALIVE_MESSAGE, skinny_data::keypad, KEYPAD_BUTTON_MESSAGE, letohl, LINE_STATE_REQ_MESSAGE, keypad_button_message::lineInstance, LOG_WARNING, register_message::name, OFFHOOK_MESSAGE, skinny_subchannel::onhold, ONHOOK_MESSAGE, OPEN_RECEIVE_CHANNEL_ACK_MESSAGE, skinny_subchannel::owner, skinny_data::reg, REGISTER_AVAILABLE_LINES_MESSAGE, REGISTER_MESSAGE, SERVER_REQUEST_MESSAGE, SKINNY_DEVONLY, SOFT_KEY_EVENT_MESSAGE, SOFT_KEY_SET_REQ_MESSAGE, SOFT_KEY_TEMPLATE_REQ_MESSAGE, SPEED_DIAL_STAT_REQ_MESSAGE, STIMULUS_MESSAGE, TIME_DATE_REQ_MESSAGE, UNREGISTER_MESSAGE, and VERSION_REQ_MESSAGE.

Referenced by skinny_session().

{
   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);
      ast_free(req);
      return 0;
   }

   SKINNY_DEVONLY(if (skinnydebug > 1) {
      ast_verb(4, "Received %s from %s\n", message2str(req->e), s->device->name);
   })

   switch(letohl(req->e)) {
   case KEEP_ALIVE_MESSAGE:
      res = handle_keep_alive_message(req, s);
      break;
   case REGISTER_MESSAGE:
      if (skinnydebug)
         ast_verb(1, "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);
      break;
   case KEYPAD_BUTTON_MESSAGE:
       {
      struct skinny_device *d = s->device;
      struct skinny_subchannel *sub;
      int lineInstance;
      int callReference;

      if (skinnydebug)
         ast_verb(1, "Collected digit: [%d]\n", letohl(req->data.keypad.button));

      lineInstance = letohl(req->data.keypad.lineInstance);
      callReference = letohl(req->data.keypad.callReference);

      if (lineInstance) {
         sub = find_subchannel_by_instance_reference(d, lineInstance, callReference);
      } else {
         sub = d->activeline->activesub;
      }

      if (sub && ((sub->owner && sub->owner->_state <  AST_STATE_UP) || sub->onhold)) {
         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);
      }
      break;
   case ENBLOC_CALL_MESSAGE:
      res = handle_enbloc_call_message(req, s);
      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_verb(1, "Received CapabilitiesRes\n");

      res = handle_capabilities_res_message(req, s);
      break;
   case SPEED_DIAL_STAT_REQ_MESSAGE:
      if (skinnydebug)
         ast_verb(1, "Received SpeedDialStatRequest\n");

      res = handle_speed_dial_stat_req_message(req, s);
      break;
   case LINE_STATE_REQ_MESSAGE:
      if (skinnydebug)
         ast_verb(1, "Received LineStatRequest\n");
      res = handle_line_state_req_message(req, s);
      break;
   case TIME_DATE_REQ_MESSAGE:
      if (skinnydebug)
         ast_verb(1, "Received Time/Date Request\n");

      res = handle_time_date_req_message(req, s);
      break;
   case BUTTON_TEMPLATE_REQ_MESSAGE:
      if (skinnydebug)
         ast_verb(1, "Buttontemplate requested\n");

      res = handle_button_template_req_message(req, s);
      break;
   case VERSION_REQ_MESSAGE:
      if (skinnydebug)
         ast_verb(1, "Version Request\n");

      res = handle_version_req_message(req, s);
      break;
   case SERVER_REQUEST_MESSAGE:
      if (skinnydebug)
         ast_verb(1, "Received Server Request\n");

      res = handle_server_request_message(req, s);
      break;
   case ALARM_MESSAGE:
      res = handle_alarm_message(req, s);
      break;
   case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE:
      if (skinnydebug)
         ast_verb(1, "Received Open Receive Channel Ack\n");

      res = handle_open_receive_channel_ack_message(req, s);
      break;
   case SOFT_KEY_SET_REQ_MESSAGE:
      if (skinnydebug)
         ast_verb(1, "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_verb(1, "Received Unregister Request\n");

      res = handle_unregister_message(req, s);
      break;
   case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
      if (skinnydebug)
         ast_verb(1, "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);
      break;
   default:
      if (skinnydebug)
         ast_verb(1, "RECEIVED UNKNOWN MESSAGE TYPE:  %x\n", letohl(req->e));
      break;
   }
   if (res >= 0 && req)
      ast_free(req);
   return res;
}
static int handle_offhook_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 5060 of file chan_skinny.c.

References skinny_device::activeline, skinny_line::activesub, AST_CONTROL_ANSWER, ast_debug, AST_DEVICE_INUSE, ast_devstate_changed(), ast_hangup(), AST_LIST_TRAVERSE, ast_log(), ast_pthread_create, ast_queue_control(), ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_verb, ast_verbose(), skinny_subchannel::callid, skinny_req::data, skinnysession::device, errno, find_line_by_instance(), find_subchannel_by_instance_reference(), offhook_message::instance, KEYDEF_CONNECTED, KEYDEF_OFFHOOK, letohl, skinny_device::lines, LOG_WARNING, ast_channel::name, skinny_data::offhook, skinny_subchannel::onhold, skinny_subchannel::outgoing, skinny_subchannel::owner, skinny_subchannel::parent, offhook_message::reference, SKINNY_CONNECTED, SKINNY_DIALTONE, SKINNY_LAMP_ON, skinny_new(), SKINNY_OFFHOOK, SKINNY_RING_OFF, SKINNY_SILENCE, skinny_ss(), start_rtp(), STIMULUS_LINE, skinny_line::sub, ast_channel::tech_pvt, transmit_callstate(), transmit_callstateonly(), transmit_displaymessage(), transmit_lamp_indication(), transmit_ringer_mode(), transmit_selectsoftkeys(), transmit_tone(), and VERBOSE_PREFIX_3.

Referenced by handle_message().

{
   struct skinny_device *d = s->device;
   struct skinny_line *l;
   struct skinny_subchannel *sub;
   struct ast_channel *c;
   struct skinny_line *tmp;
   pthread_t t;
   int instance;
   int reference;

   /* if any line on a device is offhook, than the device must be offhook, 
      unless we have shared lines CCM seems that it would never get here, 
      but asterisk does, so we may need to do more work.  Ugly, we should 
      probably move hookstate from line to device, afterall, it's actually
       a device that changes hookstates */

   AST_LIST_TRAVERSE(&d->lines, tmp, list) {
      if (tmp->hookstate == SKINNY_OFFHOOK) {
         ast_verbose(VERBOSE_PREFIX_3 "Got offhook message when device (%s@%s) already offhook\n", tmp->name, d->name);
         return 0;
      }
   }

   instance = letohl(req->data.offhook.instance);
   reference = letohl(req->data.offhook.reference);

   if (instance) {
      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;
      }
   } else {
      l = d->activeline;
      sub = l->activesub;
   }

   transmit_ringer_mode(d, SKINNY_RING_OFF);
   l->hookstate = SKINNY_OFFHOOK;

   ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s@%s", l->name, d->name);

   if (sub && sub->onhold) {
      return 1;
   }

   transmit_lamp_indication(d, 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(d, l->instance, SKINNY_OFFHOOK, sub->callid);
      transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
      transmit_callstateonly(d, sub, SKINNY_CONNECTED);
      transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
      start_rtp(sub);
      ast_setstate(sub->owner, AST_STATE_UP);
   } else {
      if (sub && sub->owner) {
         ast_debug(1, "Current sub [%s] already has owner\n", sub->owner->name);
      } else {
         c = skinny_new(l, AST_STATE_DOWN);
         if (c) {
            sub = c->tech_pvt;
            l->activesub = sub;
            transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid);
            if (skinnydebug)
               ast_verb(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
            transmit_displaymessage(d, NULL, l->instance, sub->callid); /* clear display */
            transmit_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
            transmit_selectsoftkeys(d, 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;
}
static int handle_onhook_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 5150 of file chan_skinny.c.

References ast_channel::_state, skinny_device::activeline, skinny_line::activesub, skinny_subchannel::alreadygone, ast_debug, AST_DEVICE_NOT_INUSE, ast_devstate_changed(), AST_LIST_NEXT, AST_LIST_REMOVE, ast_log(), ast_queue_hangup(), AST_STATE_RING, skinny_subchannel::blindxfer, skinny_subchannel::callid, skinny_subchannel::cxmode, skinny_req::data, skinnysession::device, find_subchannel_by_instance_reference(), handle_transfer_button(), onhook_message::instance, letohl, LOG_WARNING, skinny_subchannel::onhold, skinny_data::onhook, skinny_subchannel::owner, skinny_subchannel::parent, onhook_message::reference, skinny_subchannel::related, SKINNY_CX_RECVONLY, SKINNY_ONHOOK, skinny_line::sub, transmit_callstate(), and skinny_subchannel::xferor.

Referenced by handle_message().

{
   struct skinny_device *d = s->device;
   struct skinny_line *l;
   struct skinny_subchannel *sub;
   int instance;
   int reference;
   int onlysub = 0;

   instance = letohl(req->data.onhook.instance);
   reference = letohl(req->data.onhook.reference);

   if (instance && reference) {
      sub = find_subchannel_by_instance_reference(d, instance, reference);
      if (!sub) {
         return 0;
      }
      l = sub->parent;
   } else {
      l = d->activeline;
      sub = l->activesub;
      if (!sub) {
         return 0;
      }
   }

   if (l->hookstate == SKINNY_ONHOOK) {
      /* Something else already put us back on hook */
      return 0;
   }

   ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);

   if (sub->onhold) {
      return 0;
   }

   if (!AST_LIST_NEXT(sub, list)) {
      onlysub = 1;
   } else {
      AST_LIST_REMOVE(&l->sub, sub, list);
   }

   sub->cxmode = SKINNY_CX_RECVONLY;
   if (onlysub || sub->xferor){  /* is this the only call to this device? */
      l->hookstate = SKINNY_ONHOOK;
      if (skinnydebug)
         ast_debug(1, "Skinny %s@%s-%d went on hook\n", l->name, d->name, reference);
   }

   transmit_callstate(d, l->instance, l->hookstate, sub->callid);
   if (l->transfer && sub->xferor && sub->owner->_state >= AST_STATE_RING) {
      /* We're allowed to transfer, we have two active calls and
         we made at least one of the calls.  Let's try and transfer */
      handle_transfer_button(sub);
   } else {
      /* Hangup the current call */
      /* If there is another active call, skinny_hangup will ring the phone with the other call */
      if (sub->xferor && sub->related){
         sub->related->related = NULL;
         sub->related->blindxfer = 0;
      }

      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);
      }
   }
   return 1;
}
static int handle_open_receive_channel_ack_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 5526 of file chan_skinny.c.

References ast_best_codec(), ast_codec_pref_getsize(), ast_inet_ntoa(), ast_log(), ast_rtp_get_us(), ast_rtp_set_peer(), ast_verb, media_qualifier::bitRate, ast_format_list::bits, skinny_subchannel::callid, codec_ast2skinny(), start_media_transmission_message::conferenceId, ast_format_list::cur_ms, skinny_req::data, skinnysession::device, find_subchannel_by_reference(), htolel, open_receive_channel_ack_message::ipAddr, letohl, LOG_ERROR, skinny_data::openreceivechannelack, skinny_device::ourip, media_qualifier::packets, start_media_transmission_message::packetSize, skinny_subchannel::parent, open_receive_channel_ack_message::passThruId, start_media_transmission_message::passThruPartyId, start_media_transmission_message::payloadType, open_receive_channel_ack_message::port, media_qualifier::precedence, start_media_transmission_message::qualifier, start_media_transmission_message::remoteIp, start_media_transmission_message::remotePort, req_alloc(), skinny_subchannel::rtp, START_MEDIA_TRANSMISSION_MESSAGE, skinny_data::startmedia, open_receive_channel_ack_message::status, status, transmit_response(), and media_qualifier::vad.

Referenced by handle_message().

{
   struct skinny_device *d = s->device;
   struct skinny_line *l;
   struct skinny_subchannel *sub;
   struct ast_format_list fmt;
   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)
      ast_verb(1, "ipaddr = %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));

   if (!(req = req_alloc(sizeof(struct start_media_transmission_message), START_MEDIA_TRANSMISSION_MESSAGE)))
      return -1;

   fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability));

   if (skinnydebug)
      ast_verb(1, "Setting payloadType to '%d' (%d ms)\n", fmt.bits, fmt.cur_ms);

   req->data.startmedia.conferenceId = htolel(sub->callid);
   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));
   req->data.startmedia.packetSize = htolel(fmt.cur_ms);
   req->data.startmedia.payloadType = htolel(codec_ast2skinny(fmt.bits));
   req->data.startmedia.qualifier.precedence = htolel(127);
   req->data.startmedia.qualifier.vad = htolel(0);
   req->data.startmedia.qualifier.packets = htolel(0);
   req->data.startmedia.qualifier.bitRate = htolel(0);
   transmit_response(d, req);

   return 1;
}
static int handle_register_available_lines_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 6066 of file chan_skinny.c.

Referenced by handle_message().

{
   /* XXX I have no clue what this is for, but my phone was sending it, so... */
   return 1;
}
static int handle_register_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 4528 of file chan_skinny.c.

References ast_atomic_fetchadd_int(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_verb, CAPABILITIES_REQ_MESSAGE, skinny_req::data, register_ack_message::dateTemplate, skinnysession::device, register_rej_message::errMsg, errno, skinnysession::fd, htolel, register_ack_message::keepAlive, skinny_req::len, letohl, skinnysession::lock, LOG_ERROR, LOG_WARNING, register_message::name, name, skinnysession::outbuf, skinny_data::reg, skinny_data::regack, REGISTER_ACK_MESSAGE, REGISTER_REJ_MESSAGE, skinny_data::regrej, req_alloc(), register_ack_message::res, register_ack_message::res2, register_ack_message::secondaryKeepAlive, SKINNY_MAX_PACKET, skinny_register(), and transmit_response().

Referenced by handle_message().

{
   struct skinny_device *d = NULL;
   char name[16];
   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);
      if (!(req = req_alloc(sizeof(struct register_rej_message), REGISTER_REJ_MESSAGE)))
         return -1;

      snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name);

      /* transmit_respons in line as we don't have a valid d */
      ast_mutex_lock(&s->lock);

      if (letohl(req->len > SKINNY_MAX_PACKET) || letohl(req->len < 0)) {
         ast_log(LOG_WARNING, "transmit_response: the length of the request is out of bounds\n");
         ast_mutex_unlock(&s->lock);
         return -1;
      }

      memset(s->outbuf, 0, sizeof(s->outbuf));
      memcpy(s->outbuf, req, skinny_header_size);
      memcpy(s->outbuf+skinny_header_size, &req->data, letohl(req->len));

      res = write(s->fd, s->outbuf, letohl(req->len)+8);

      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));
      }
   
      ast_mutex_unlock(&s->lock);

      return 0;
   }
   ast_atomic_fetchadd_int(&unauth_sessions, -1);

   ast_verb(3, "Device '%s' successfully registered\n", name);

   d = s->device;
   
   if (!(req = req_alloc(sizeof(struct register_ack_message), REGISTER_ACK_MESSAGE)))
      return -1;

   req->data.regack.res[0] = '0';
   req->data.regack.res[1] = '\0';
   req->data.regack.keepAlive = htolel(keep_alive);
   memcpy(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(d, req);
   if (skinnydebug)
      ast_verb(1, "Requesting capabilities\n");

   if (!(req = req_alloc(0, CAPABILITIES_REQ_MESSAGE)))
      return -1;

   transmit_response(d, req);

   return res;
}
static char* handle_skinny_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2734 of file chan_skinny.c.

References ast_cli_args::argc, ast_cli_entry::args, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, skinny_reload(), and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "skinny reload";
      e->usage =
         "Usage: skinny reload\n"
         "       Reloads the chan_skinny configuration\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }
   
   if (a->argc != e->args)
      return CLI_SHOWUSAGE;

   skinny_reload();
   return CLI_SUCCESS;

}
static char* handle_skinny_reset ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2799 of file chan_skinny.c.

References ast_cli_args::argc, ast_cli_args::argv, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_verb, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_skinny_reset(), skinny_req::data, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, req_alloc(), skinny_data::reset, RESET_MESSAGE, reset_message::resetType, skinny_device::session, transmit_response(), ast_cli_entry::usage, and ast_cli_args::word.

{
   struct skinny_device *d;
   struct skinny_req *req;

   switch (cmd) {
   case CLI_INIT:
      e->command = "skinny reset";
      e->usage =
         "Usage: skinny reset <DeviceId|DeviceName|all> [restart]\n"
         "       Causes a Skinny device to reset itself, optionally with a full restart\n";
      return NULL;
   case CLI_GENERATE:
      return complete_skinny_reset(a->line, a->word, a->pos, a->n);
   }

   if (a->argc < 3 || a->argc > 4)
      return CLI_SHOWUSAGE;

   AST_LIST_LOCK(&devices);
   AST_LIST_TRAVERSE(&devices, d, list) {
      int fullrestart = 0;
      if (!strcasecmp(a->argv[2], d->id) || !strcasecmp(a->argv[2], d->name) || !strcasecmp(a->argv[2], "all")) {
         if (!(d->session))
            continue;

         if (!(req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE)))
            continue;

         if (a->argc == 4 && !strcasecmp(a->argv[3], "restart"))
            fullrestart = 1;

         if (fullrestart)
            req->data.reset.resetType = 2;
         else
            req->data.reset.resetType = 1;

         ast_verb(3, "%s device %s.\n", (fullrestart) ? "Restarting" : "Resetting", d->id);
         transmit_response(d, req);
      }
   }
   AST_LIST_UNLOCK(&devices);
   return CLI_SUCCESS;
}
static char* handle_skinny_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 2692 of file chan_skinny.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
#ifdef SKINNY_DEVMODE
      e->command = "skinny set debug {off|on|packet}";
      e->usage =
         "Usage: skinny set debug {off|on|packet}\n"
         "       Enables/Disables dumping of Skinny packets for debugging purposes\n";
#else
      e->command = "skinny set debug {off|on}";
      e->usage =
         "Usage: skinny set debug {off|on}\n"
         "       Enables/Disables dumping of Skinny packets for debugging purposes\n";
#endif
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }
   
   if (a->argc != e->args)
      return CLI_SHOWUSAGE;

   if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
      skinnydebug = 1;
      ast_cli(a->fd, "Skinny Debugging Enabled\n");
      return CLI_SUCCESS;
   } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
      skinnydebug = 0;
      ast_cli(a->fd, "Skinny Debugging Disabled\n");
      return CLI_SUCCESS;
#ifdef SKINNY_DEVMODE
   } else if (!strncasecmp(a->argv[e->args - 1], "packet", 6)) {
      skinnydebug = 2;
      ast_cli(a->fd, "Skinny Debugging Enabled including Packets\n");
      return CLI_SUCCESS;
#endif
   } else {
      return CLI_SHOWUSAGE;
   }
}
static char* handle_skinny_show_device ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Show device information.

Definition at line 3192 of file chan_skinny.c.

References _skinny_show_device(), ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, ast_cli_entry::command, complete_skinny_show_device(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "skinny show device";
      e->usage =
         "Usage: skinny show device <DeviceId|DeviceName>\n"
         "       Lists all deviceinformation of a specific device known to the Skinny subsystem.\n";
      return NULL;
   case CLI_GENERATE:
      return complete_skinny_show_device(a->line, a->word, a->pos, a->n);
   }

   return _skinny_show_device(0, a->fd, NULL, NULL, a->argc, (const char **) a->argv);
}
static char* handle_skinny_show_devices ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 3052 of file chan_skinny.c.

References _skinny_show_devices(), ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

{

   switch (cmd) {
   case CLI_INIT:
      e->command = "skinny show devices";
      e->usage =
         "Usage: skinny show devices\n"
         "       Lists all devices known to the Skinny subsystem.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   return _skinny_show_devices(a->fd, NULL, NULL, NULL, a->argc, (const char **) a->argv);
}
static char* handle_skinny_show_line ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

List line information.

Definition at line 3502 of file chan_skinny.c.

References _skinny_show_line(), ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, ast_cli_entry::command, complete_skinny_show_line(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "skinny show line";
      e->usage =
         "Usage: skinny show line <Line> [ on <DeviceID|DeviceName> ]\n"
         "       List all lineinformation of a specific line known to the Skinny subsystem.\n";
      return NULL;
   case CLI_GENERATE:
      return complete_skinny_show_line(a->line, a->word, a->pos, a->n);
   }

   return _skinny_show_line(0, a->fd, NULL, NULL, a->argc, (const char **) a->argv);
}
static char* handle_skinny_show_lines ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 3313 of file chan_skinny.c.

References _skinny_show_lines(), ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

{
   int verbose = 0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "skinny show lines [verbose]";
      e->usage =
         "Usage: skinny show lines\n"
         "       Lists all lines known to the Skinny subsystem.\n"
         "       If 'verbose' is specified, the output includes\n"
         "       information about subs for each line.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc == e->args) {
      if (!strcasecmp(a->argv[e->args-1], "verbose")) {
         verbose = 1;
      } else {
         return CLI_SHOWUSAGE;
      }
   } else if (a->argc != e->args - 1) {
      return CLI_SHOWUSAGE;
   }

   return _skinny_show_lines(a->fd, NULL, NULL, NULL, a->argc, (const char **) a->argv);
}
static char* handle_skinny_show_settings ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

List global settings for the Skinny subsystem.

Definition at line 3519 of file chan_skinny.c.

References ast_cli_args::argc, ast_cli(), ast_inet_ntoa(), AST_JB_ENABLED, AST_JB_FORCED, AST_JB_LOG, ast_test_flag, bindaddr, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, global_jbconf, ast_jb_conf::impl, ast_jb_conf::max_size, ast_jb_conf::resync_threshold, S_OR, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "skinny show settings";
      e->usage =
         "Usage: skinny show settings\n"
         "       Lists all global configuration settings of the Skinny subsystem.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }  

   if (a->argc != 3)
      return CLI_SHOWUSAGE;

   ast_cli(a->fd, "\nGlobal Settings:\n");
   ast_cli(a->fd, "  Skinny Port:            %d\n", ntohs(bindaddr.sin_port));
   ast_cli(a->fd, "  Bindaddress:            %s\n", ast_inet_ntoa(bindaddr.sin_addr));
   ast_cli(a->fd, "  KeepAlive:              %d\n", keep_alive);
   ast_cli(a->fd, "  Date Format:            %s\n", date_format);
   ast_cli(a->fd, "  Voice Mail Extension:   %s\n", S_OR(global_vmexten, "(not set)"));
   ast_cli(a->fd, "  Reg. context:           %s\n", S_OR(regcontext, "(not set)"));
   ast_cli(a->fd, "  Jitterbuffer enabled:   %s\n", (ast_test_flag(&global_jbconf, AST_JB_ENABLED) ? "Yes" : "No"));
   ast_cli(a->fd, "  Jitterbuffer forced:    %s\n", (ast_test_flag(&global_jbconf, AST_JB_FORCED) ? "Yes" : "No"));
   ast_cli(a->fd, "  Jitterbuffer max size:  %ld\n", global_jbconf.max_size);
   ast_cli(a->fd, "  Jitterbuffer resync:    %ld\n", global_jbconf.resync_threshold);
   ast_cli(a->fd, "  Jitterbuffer impl:      %s\n", global_jbconf.impl);
   ast_cli(a->fd, "  Jitterbuffer log:       %s\n", (ast_test_flag(&global_jbconf, AST_JB_LOG) ? "Yes" : "No"));

   return CLI_SUCCESS;
}
static int handle_soft_key_event_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 5677 of file chan_skinny.c.

References ast_channel::_state, skinny_line::activesub, skinny_subchannel::alreadygone, ast_bridged_channel(), AST_CONTROL_ANSWER, ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, ast_devstate_changed(), ast_hangup(), ast_ignore_pattern(), AST_LIST_NEXT, AST_LIST_REMOVE, ast_log(), ast_masq_park_call(), ast_pthread_create, ast_queue_control(), ast_queue_hangup(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RING, AST_STATE_UP, ast_strlen_zero(), ast_verb, skinny_subchannel::blindxfer, skinny_subchannel::callid, soft_key_event_message::callreference, ast_channel::context, skinny_subchannel::cxmode, skinny_req::data, skinnysession::device, errno, ast_channel::exten, find_line_by_instance(), find_subchannel_by_instance_reference(), handle_callforward_button(), handle_hold_button(), handle_transfer_button(), soft_key_event_message::instance, KEYDEF_CONNECTED, KEYDEF_OFFHOOK, KEYDEF_ONHOLD, KEYDEF_RINGOUT, letohl, LOG_WARNING, skinny_subchannel::onhold, skinny_subchannel::outgoing, skinny_subchannel::owner, skinny_subchannel::related, skinny_subchannel::rtp, SKINNY_CFWD_ALL, SKINNY_CFWD_BUSY, SKINNY_CFWD_NOANSWER, SKINNY_CONNECTED, SKINNY_CX_RECVONLY, SKINNY_DIALTONE, skinny_hold(), SKINNY_LAMP_OFF, SKINNY_LAMP_ON, skinny_new(), skinny_newcall(), SKINNY_OFFHOOK, SKINNY_ONHOOK, SKINNY_RING_OFF, SKINNY_SILENCE, SKINNY_SPEAKEROFF, SKINNY_SPEAKERON, skinny_ss(), skinny_unhold(), SOFTKEY_ANSWER, SOFTKEY_BKSPC, SOFTKEY_CFWDALL, SOFTKEY_CFWDBUSY, SOFTKEY_CFWDNOANSWER, SOFTKEY_CONFRN, SOFTKEY_DND, SOFTKEY_ENDCALL, SOFTKEY_GPICKUP, SOFTKEY_HOLD, SOFTKEY_INFO, SOFTKEY_JOIN, SOFTKEY_MEETME, SOFTKEY_NEWCALL, SOFTKEY_NONE, SOFTKEY_PARK, SOFTKEY_PICKUP, SOFTKEY_REDIAL, SOFTKEY_RESUME, SOFTKEY_TRNSFER, soft_key_event_message::softKeyEvent, skinny_data::softkeyeventmessage, start_rtp(), STIMULUS_DND, STIMULUS_LINE, skinny_line::sub, ast_channel::tech_pvt, transmit_callstate(), transmit_callstateonly(), transmit_displaymessage(), transmit_displaynotify(), transmit_lamp_indication(), transmit_ringer_mode(), transmit_selectsoftkeys(), transmit_speaker_mode(), transmit_tone(), and skinny_subchannel::xferor.

Referenced by handle_message().

{
   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 callreference;

   event = letohl(req->data.softkeyeventmessage.softKeyEvent);
   instance = letohl(req->data.softkeyeventmessage.instance);
   callreference = letohl(req->data.softkeyeventmessage.callreference);

   if (instance) {
      l = find_line_by_instance(d, instance);
      if (callreference) {
         sub = find_subchannel_by_instance_reference(d, instance, callreference);
      } 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_verb(1, "Received Softkey Event: %d(%d/%d)\n", event, instance, callreference);
      return 0;
   }

   ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s@%s", l->name, d->name);

   switch(event) {
   case SOFTKEY_NONE:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: None(%d/%d)\n", instance, callreference);
      break;
   case SOFTKEY_REDIAL:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Redial(%d/%d)\n", instance, callreference);

      if (ast_strlen_zero(l->lastnumberdialed)) {
         ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found.\n");
         l->hookstate = SKINNY_ONHOOK;
         transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
         transmit_callstate(d, l->instance, SKINNY_ONHOOK, instance);
         break;
      }

      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->activesub = sub;
         if (l->hookstate == SKINNY_ONHOOK) {
            l->hookstate = SKINNY_OFFHOOK;
            transmit_speaker_mode(d, SKINNY_SPEAKERON);
            transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid);
         }
         if (skinnydebug)
            ast_verb(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
         transmit_displaymessage(d, NULL, l->instance, sub->callid); /* clear display */
         transmit_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
         transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);

         if (!ast_ignore_pattern(c->context, l->lastnumberdialed)) {
            transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
         }
         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);
         }
      }
      break;
   case SOFTKEY_NEWCALL:  /* Actually the DIAL softkey */
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: New Call(%d/%d)\n", instance, callreference);

      /* New Call ALWAYS gets a new sub-channel */
      c = skinny_new(l, AST_STATE_DOWN);
      sub = c->tech_pvt;
   
      /* transmit_ringer_mode(d, SKINNY_RING_OFF);
      transmit_lamp_indication(d, 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;
         l->activesub = sub;
         if (l->hookstate == SKINNY_ONHOOK) {
            l->hookstate = SKINNY_OFFHOOK;
            transmit_speaker_mode(d, SKINNY_SPEAKERON);
         }
         ast_verb(1, "Call-id: %d\n", sub->callid);

         transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid);

         if (skinnydebug)
            ast_verb(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
         transmit_displaymessage(d, NULL, l->instance, sub->callid); /* clear display */
         transmit_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
         transmit_selectsoftkeys(d, 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);
         }
      }
      break;
   case SOFTKEY_HOLD:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Hold(%d/%d)\n", instance, callreference);
      handle_hold_button(sub);   
      break;
   case SOFTKEY_TRNSFER:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Transfer(%d/%d)\n", instance, callreference);
      if (l->transfer)
         handle_transfer_button(sub);
      else
         transmit_displaynotify(d, "Transfer disabled", 10);

      break;
   case SOFTKEY_DND:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: DND(%d/%d)\n", instance, callreference);

      /* Do not disturb */
      if (l->dnd != 0){
         ast_verb(3, "Disabling DND on %s@%s\n", l->name, d->name);
         l->dnd = 0;
         transmit_lamp_indication(d, STIMULUS_DND, 1, SKINNY_LAMP_ON);
         transmit_displaynotify(d, "DnD disabled", 10);
      } else {
         ast_verb(3, "Enabling DND on %s@%s\n", l->name, d->name);
         l->dnd = 1;
         transmit_lamp_indication(d, STIMULUS_DND, 1, SKINNY_LAMP_OFF);
         transmit_displaynotify(d, "DnD enabled", 10);
      }
      break;
   case SOFTKEY_CFWDALL:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Forward All(%d/%d)\n", instance, callreference);

      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->activesub = sub;
         handle_callforward_button(sub, SKINNY_CFWD_ALL);
      }
      break;
   case SOFTKEY_CFWDBUSY:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Forward Busy (%d/%d)\n", instance, callreference);

      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->activesub = sub;
         handle_callforward_button(sub, SKINNY_CFWD_BUSY);
      }
      break;
   case SOFTKEY_CFWDNOANSWER:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Forward No Answer (%d/%d)\n", instance, callreference);

#if 0 /* Not sure how to handle this yet */
      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->activesub = sub;
         handle_callforward_button(sub, SKINNY_CFWD_NOANSWER);
      }
#endif
      break;
   case SOFTKEY_BKSPC:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Backspace(%d/%d)\n", instance, callreference);
      break;
   case SOFTKEY_ENDCALL:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: End Call(%d/%d)\n", instance, callreference);

      if (l->hookstate == SKINNY_ONHOOK) {
         /* Something else already put us back on hook */
         break;
      }
      if (sub) {
         int onlysub = 0;

         if (!AST_LIST_NEXT(sub, list)) {
            onlysub = 1;
         } else {
            AST_LIST_REMOVE(&l->sub, sub, list);
         }

         sub->cxmode = SKINNY_CX_RECVONLY;
         if (onlysub || sub->xferor){    /*Are there other calls to this device */
            l->hookstate = SKINNY_ONHOOK;
            if (skinnydebug)
               ast_debug(1, "Skinny %s@%s-%d went on hook\n", l->name, d->name, callreference);
         }

         transmit_callstate(d, l->instance, l->hookstate, sub->callid);
         ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
         if (skinnydebug)
            ast_verb(1, "Skinny %s@%s went on hook\n", l->name, d->name);
         if (l->transfer && sub->xferor && sub->owner->_state >= AST_STATE_RING) {
            /* We're allowed to transfer, we have two active calls and
               we made at least one of the calls.  Let's try and transfer */
            handle_transfer_button(sub);
         } else {
            /* Hangup the current call */
            /* If there is another active call, skinny_hangup will ring the phone with the other call */
            if (sub->xferor && sub->related){
               sub->related->related = NULL;
               sub->related->blindxfer = 0;
            }

            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) && (AST_LIST_NEXT(sub, list) && !AST_LIST_NEXT(sub, list)->rtp)) {
            ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
         }
      }
      break;
   case SOFTKEY_RESUME:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Resume(%d/%d)\n", instance, callreference);

      if (sub) {
         if (sub->onhold) {
            skinny_unhold(sub);
            transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
         } else {
            skinny_hold(sub);
            transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_ONHOLD);
         }
      }

      break;
   case SOFTKEY_ANSWER:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Answer(%d/%d)\n", instance, callreference);

      transmit_ringer_mode(d, SKINNY_RING_OFF);
      transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
      if (l->hookstate == SKINNY_ONHOOK) {
         transmit_speaker_mode(d, SKINNY_SPEAKERON);
         l->hookstate = SKINNY_OFFHOOK;
      }

      if (sub && sub->outgoing) {
         /* We're answering a ringing call */
         ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
         transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid);
         transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
         transmit_callstateonly(d, sub, SKINNY_CONNECTED);
         transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
         start_rtp(sub);
         ast_setstate(sub->owner, AST_STATE_UP);
      }
      break;
   case SOFTKEY_INFO:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Info(%d/%d)\n", instance, callreference);
      break;
   case SOFTKEY_CONFRN:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Conference(%d/%d)\n", instance, callreference);
      /* XXX determine the best way to pull off a conference.  Meetme? */
      break;
   case SOFTKEY_PARK:
      {
      int extout;
      char message[32];

      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Park Call(%d/%d)\n", instance, callreference);

      if ((sub && sub->owner) && (sub->owner->_state ==  AST_STATE_UP)){
         c = sub->owner;
         if (ast_bridged_channel(c)) {
            if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) {
               snprintf(message, sizeof(message), "Call Parked at: %d", extout);
               transmit_displaynotify(d, message, 10);
            } else {
               transmit_displaynotify(d, "Call Park failed", 10);
            }
         } else {
            transmit_displaynotify(d, "Call Park not available", 10);
         }
      } else {
         transmit_displaynotify(d, "Call Park not available", 10);
      }
      break;
      }
   case SOFTKEY_JOIN:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Join(%d/%d)\n", instance, callreference);
      break;
   case SOFTKEY_MEETME:
      /* XXX How is this different from CONFRN? */
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Meetme(%d/%d)\n", instance, callreference);
      break;
   case SOFTKEY_PICKUP:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Pickup(%d/%d)\n", instance, callreference);
      break;
   case SOFTKEY_GPICKUP:
      if (skinnydebug)
         ast_verb(1, "Received Softkey Event: Group Pickup(%d/%d)\n", instance, callreference);
      break;
   default:
      if (skinnydebug)
         ast_verb(1, "Received unknown Softkey Event: %d(%d/%d)\n", event, instance, callreference);
      break;
   }

   return 1;
}
static int handle_soft_key_set_req_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 5644 of file chan_skinny.c.

References soft_key_definitions::count, skinny_req::data, soft_key_definitions::defaults, skinnysession::device, htolel, KEYDEF_ONHOOK, soft_key_definitions::mode, req_alloc(), soft_key_default_definitions, SOFT_KEY_SET_RES_MESSAGE, soft_key_template_default, soft_key_set_definition::softKeyInfoIndex, soft_key_set_res_message::softKeySetCount, soft_key_set_res_message::softKeySetDefinition, soft_key_set_res_message::softKeySetOffset, skinny_data::softkeysets, soft_key_set_definition::softKeyTemplateIndex, soft_key_set_res_message::totalSoftKeySetCount, transmit_response(), and transmit_selectsoftkeys().

Referenced by handle_message().

{
   int i;
   int x;
   int y;
   const struct soft_key_definitions *softkeymode = soft_key_default_definitions;
   struct skinny_device *d = s->device;

   if (!(req = req_alloc(sizeof(struct soft_key_set_res_message), SOFT_KEY_SET_RES_MESSAGE)))
      return -1;

   req->data.softkeysets.softKeySetOffset = htolel(0);
   req->data.softkeysets.softKeySetCount = htolel(11);
   req->data.softkeysets.totalSoftKeySetCount = htolel(11);
   for (x = 0; x < sizeof(soft_key_default_definitions) / sizeof(struct soft_key_definitions); x++) {
      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++) {
         for (i = 0; i < (sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition)); i++) {
            if (defaults[y] == i+1) {
               req->data.softkeysets.softKeySetDefinition[softkeymode->mode].softKeyTemplateIndex[y] = htolel(i+1);
               req->data.softkeysets.softKeySetDefinition[softkeymode->mode].softKeyInfoIndex[y] = htolel(i+301);
            }
         }
      }
      softkeymode++;
   }
   transmit_response(d, req);
   transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK);
   return 1;
}
static int handle_stimulus_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 4710 of file chan_skinny.c.

References ast_channel::_state, skinny_device::activeline, skinny_line::activesub, ast_bridged_channel(), AST_CONTROL_ANSWER, ast_copy_string(), ast_debug, AST_DEVICE_UNKNOWN, ast_devstate_changed(), ast_exists_extension(), ast_hangup(), ast_ignore_pattern(), ast_log(), ast_masq_park_call(), ast_pthread_create, ast_queue_control(), ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_strlen_zero(), ast_verb, skinny_subchannel::callid, stimulus_message::callreference, ast_channel::context, skinny_req::data, skinnysession::device, errno, skinny_speeddial::exten, ast_channel::exten, find_line_by_instance(), find_speeddial_by_instance(), find_subchannel_by_instance_reference(), handle_callforward_button(), handle_hold_button(), handle_transfer_button(), KEYDEF_CONNECTED, KEYDEF_OFFHOOK, KEYDEF_RINGOUT, letohl, LOG_WARNING, ast_channel::name, skinny_subchannel::outgoing, skinny_subchannel::owner, skinny_subchannel::parent, SKINNY_CFWD_ALL, SKINNY_CFWD_BUSY, SKINNY_CFWD_NOANSWER, SKINNY_CONNECTED, SKINNY_DIALTONE, SKINNY_LAMP_OFF, SKINNY_LAMP_ON, skinny_new(), skinny_newcall(), SKINNY_OFFHOOK, SKINNY_ONHOOK, SKINNY_RING_OFF, SKINNY_SILENCE, SKINNY_SPEAKEROFF, SKINNY_SPEAKERON, skinny_ss(), start_rtp(), stimulus_message::stimulus, skinny_data::stimulus, STIMULUS_CALLPARK, STIMULUS_CONFERENCE, STIMULUS_DISPLAY, STIMULUS_DND, STIMULUS_FORWARDALL, STIMULUS_FORWARDBUSY, STIMULUS_FORWARDNOANSWER, STIMULUS_HOLD, STIMULUS_LINE, STIMULUS_REDIAL, STIMULUS_SPEEDDIAL, STIMULUS_TRANSFER, STIMULUS_VOICEMAIL, stimulus_message::stimulusInstance, ast_channel::tech_pvt, transmit_callstate(), transmit_callstateonly(), transmit_displaymessage(), transmit_displaynotify(), transmit_displaypromptstatus(), transmit_lamp_indication(), transmit_ringer_mode(), transmit_selectsoftkeys(), transmit_speaker_mode(), and transmit_tone().

Referenced by handle_message().

{
   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 callreference;
   /*int res = 0;*/

   event = letohl(req->data.stimulus.stimulus);
   instance = letohl(req->data.stimulus.stimulusInstance);
   callreference = letohl(req->data.stimulus.callreference); 
   if (skinnydebug)
      ast_verb(1, "callreference in handle_stimulus_message is '%d'\n", callreference);

   /*  Note that this call should be using the passed in instance and callreference */
   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;
      }
      sub = l->activesub;
   } else {
      l = sub->parent;
   }

   switch(event) {
   case STIMULUS_REDIAL:
      if (skinnydebug)
         ast_verb(1, "Received Stimulus: Redial(%d/%d)\n", instance, callreference);

      if (ast_strlen_zero(l->lastnumberdialed)) {
         ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found.\n");
         l->hookstate = SKINNY_ONHOOK;
         transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
         transmit_callstate(d, l->instance, SKINNY_ONHOOK, instance);
         break;
      }

      c = skinny_new(l, AST_STATE_DOWN);
      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;
         l->activesub = sub;
         if (l->hookstate == SKINNY_ONHOOK) {
            l->hookstate = SKINNY_OFFHOOK;
            transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid);
         }
         if (skinnydebug)
            ast_verb(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
         transmit_displaymessage(d, NULL, l->instance, sub->callid); /* clear display */
         transmit_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
         transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);

         if (!ast_ignore_pattern(c->context, l->lastnumberdialed)) {
            transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
         }
         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);
         }
      }
      break;
   case STIMULUS_SPEEDDIAL:
       {
      struct skinny_speeddial *sd;

      if (skinnydebug)
         ast_verb(1, "Received Stimulus: SpeedDial(%d/%d)\n", instance, callreference);
      if (!(sd = find_speeddial_by_instance(d, instance, 0))) {
         return 0;
      }

      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;
         l->activesub = sub;
         if (l->hookstate == SKINNY_ONHOOK) {
            l->hookstate = SKINNY_OFFHOOK;
            transmit_speaker_mode(d, SKINNY_SPEAKERON);
            transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid);
         }
         if (skinnydebug)
            ast_verb(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
         transmit_displaymessage(d, NULL, l->instance, sub->callid); /* clear display */
         transmit_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
         transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);

         if (!ast_ignore_pattern(c->context, sd->exten)) {
            transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
         }
         if (ast_exists_extension(c, c->context, sd->exten, 1, l->cid_num)) {
            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);
            }
            break;
         }
      }
       }
      break;
   case STIMULUS_HOLD:
      if (skinnydebug)
         ast_verb(1, "Received Stimulus: Hold(%d/%d)\n", instance, callreference);
      handle_hold_button(sub);
      break;
   case STIMULUS_TRANSFER:
      if (skinnydebug)
         ast_verb(1, "Received Stimulus: Transfer(%d/%d)\n", instance, callreference);
      if (l->transfer)
         handle_transfer_button(sub);
      else
         transmit_displaynotify(d, "Transfer disabled", 10);
      break;
   case STIMULUS_CONFERENCE:
      if (skinnydebug)
         ast_verb(1, "Received Stimulus: Conference(%d/%d)\n", instance, callreference);
      /* XXX determine the best way to pull off a conference.  Meetme? */
      break;
   case STIMULUS_VOICEMAIL:
      if (skinnydebug)
         ast_verb(1, "Received Stimulus: Voicemail(%d/%d)\n", instance, callreference);

      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;
         l->activesub = sub;

         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(d, SKINNY_SPEAKERON);
            transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid);
         }

         if (skinnydebug)
            ast_verb(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);

         transmit_displaymessage(d, NULL, l->instance, sub->callid); /* clear display */
         transmit_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
         transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);

         if (!ast_ignore_pattern(c->context, l->vmexten)) {
            transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
         }

         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;
         }
      }
      break;
   case STIMULUS_CALLPARK:
      {
      int extout;
      char message[32];

      if (skinnydebug)
         ast_verb(1, "Received Stimulus: Park Call(%d/%d)\n", instance, callreference);

      if ((sub && sub->owner) && (sub->owner->_state ==  AST_STATE_UP)){
         c = sub->owner;
         if (ast_bridged_channel(c)) {
            if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) {
               snprintf(message, sizeof(message), "Call Parked at: %d", extout);
               transmit_displaynotify(d, message, 10);
            } else {
               transmit_displaynotify(d, "Call Park failed", 10);
            }
         } else {
            transmit_displaynotify(d, "Call Park not available", 10);
         }
      } else {
         transmit_displaynotify(d, "Call Park not available", 10);
      }
      break;
      }
   case STIMULUS_DND:
      if (skinnydebug)
         ast_verb(1, "Received Stimulus: DND (%d/%d)\n", instance, callreference);

      /* Do not disturb */
      if (l->dnd != 0){
         ast_verb(3, "Disabling DND on %s@%s\n", l->name, d->name);
         l->dnd = 0;
         transmit_lamp_indication(d, STIMULUS_DND, 1, SKINNY_LAMP_ON);
         transmit_displaynotify(d, "DnD disabled", 10);
      } else {
         ast_verb(3, "Enabling DND on %s@%s\n", l->name, d->name);
         l->dnd = 1;
         transmit_lamp_indication(d, STIMULUS_DND, 1, SKINNY_LAMP_OFF);
         transmit_displaynotify(d, "DnD enabled", 10);
      }
      break;
   case STIMULUS_FORWARDALL:
      if (skinnydebug)
         ast_verb(1, "Received Stimulus: Forward All(%d/%d)\n", instance, callreference);

      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;
         handle_callforward_button(sub, SKINNY_CFWD_ALL);
      }
      break;
   case STIMULUS_FORWARDBUSY:
      if (skinnydebug)
         ast_verb(1, "Received Stimulus: Forward Busy (%d/%d)\n", instance, callreference);

      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;
         handle_callforward_button(sub, SKINNY_CFWD_BUSY);
      }
      break;
   case STIMULUS_FORWARDNOANSWER:
      if (skinnydebug)
         ast_verb(1, "Received Stimulus: Forward No Answer (%d/%d)\n", instance, callreference);

#if 0 /* Not sure how to handle this yet */
      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;
         handle_callforward_button(sub, SKINNY_CFWD_NOANSWER);
      }
#endif
      break;
   case STIMULUS_DISPLAY:
      /* Not sure what this is */
      if (skinnydebug)
         ast_verb(1, "Received Stimulus: Display(%d/%d)\n", instance, callreference);
      break;
   case STIMULUS_LINE:
      if (skinnydebug)
         ast_verb(1, "Received Stimulus: Line(%d/%d)\n", instance, callreference);

      l = find_line_by_instance(d, instance);

      if (!l) {
         return 0;
      }

      d->activeline = l;

      /* turn the speaker on */
      transmit_speaker_mode(d, SKINNY_SPEAKERON);
      transmit_ringer_mode(d, SKINNY_RING_OFF);
      transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);

      l->hookstate = SKINNY_OFFHOOK;

      if (sub && sub->outgoing) {
         /* We're answering a ringing call */
         ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
         transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid);
         transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
         transmit_callstateonly(d, sub, SKINNY_CONNECTED);
         transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid);
         transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
         start_rtp(sub);
         ast_setstate(sub->owner, AST_STATE_UP);
      } else {
         if (sub && sub->owner) {
            ast_debug(1, "Current subchannel [%s] already has owner\n", sub->owner->name);
         } else {
            c = skinny_new(l, AST_STATE_DOWN);
            if (c) {
               sub = c->tech_pvt;
               l->activesub = sub;
               transmit_callstate(d, l->instance, SKINNY_OFFHOOK, sub->callid);
               if (skinnydebug)
                  ast_verb(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
               transmit_displaymessage(d, NULL, l->instance, sub->callid); /* clear display */
               transmit_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
               transmit_selectsoftkeys(d, 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_verb(1, "RECEIVED UNKNOWN STIMULUS:  %d(%d/%d)\n", event, instance, callreference);
      break;
   }
   ast_devstate_changed(AST_DEVICE_UNKNOWN, "Skinny/%s@%s", l->name, d->name);

   return 1;
}
static int handle_time_date_req_message ( struct skinny_req req,
struct skinnysession s 
) [static]
static int handle_transfer_button ( struct skinny_subchannel sub) [static]

Definition at line 4458 of file chan_skinny.c.

References ast_channel::_state, skinny_line::activesub, ast_debug, ast_hangup(), ast_log(), ast_pthread_create, AST_STATE_DOWN, ast_verbose(), skinny_subchannel::blindxfer, skinny_subchannel::callid, skinny_line::device, errno, KEYDEF_OFFHOOKWITHFEAT, LOG_WARNING, skinny_subchannel::onhold, skinny_subchannel::owner, skinny_subchannel::parent, skinny_subchannel::related, SKINNY_DIALTONE, skinny_hold(), skinny_new(), SKINNY_OFFHOOK, skinny_ss(), skinny_transfer(), ast_channel::tech_pvt, transmit_callstate(), transmit_displaymessage(), transmit_selectsoftkeys(), transmit_tone(), and skinny_subchannel::xferor.

Referenced by handle_onhook_message(), handle_soft_key_event_message(), and handle_stimulus_message().

{
   struct skinny_line *l = sub->parent;
   struct skinny_device *d = l->device;
   struct skinny_subchannel *newsub;
   struct ast_channel *c;
   pthread_t t;

   if (!sub) {
      ast_verbose("Transfer: No subchannel to transfer\n");
      return -1;
   }
   if (!sub->related) {
      /* Another sub has not been created so this must be first XFER press */
      if (!sub->onhold) {
         skinny_hold(sub);
      }
      c = skinny_new(l, AST_STATE_DOWN);
      if (c) {
         newsub = c->tech_pvt;
         /* point the sub and newsub at each other so we know they are related */
         newsub->related = sub;
         sub->related = newsub;
         newsub->xferor = 1;
         l->activesub = newsub;
         transmit_callstate(d, l->instance, SKINNY_OFFHOOK, newsub->callid);
         if (skinnydebug)
            ast_debug(1, "Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
         transmit_displaymessage(d, NULL, l->instance, newsub->callid); /* clear display */
         transmit_tone(d, SKINNY_DIALTONE, l->instance, newsub->callid);
         transmit_selectsoftkeys(d, l->instance, newsub->callid, KEYDEF_OFFHOOKWITHFEAT);
         /* 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);
      }
   } else {
      /* We already have a related sub so we can either complete XFER or go into BLINDXFER (or cancel BLINDXFER */
      if (sub->blindxfer) {
         /* toggle blindxfer off */
         sub->blindxfer = 0;
         sub->related->blindxfer = 0;
         /* we really need some indications */
      } else {
         /* We were doing attended transfer */
         if (sub->owner->_state == AST_STATE_DOWN || sub->related->owner->_state == AST_STATE_DOWN) {
            /* one of the subs so we cant transfer yet, toggle blindxfer on */
            sub->blindxfer = 1;
            sub->related->blindxfer = 1;
         } else {
            /* big assumption we have two channels, lets transfer */
            skinny_transfer(sub);
         }
      }
   }
   return 0;
}
static int handle_unregister_message ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 6040 of file chan_skinny.c.

References skinny_unregister().

Referenced by handle_message().

{
   return skinny_unregister(req, s);
}
static int handle_version_req_message ( struct skinny_req req,
struct skinnysession s 
) [static]
static int load_module ( void  ) [static]

Definition at line 7363 of file chan_skinny.c.

References ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_log(), ast_manager_register2(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_rtp_proto_register(), cli_skinny, config_load(), EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, htolel, io_context_create(), LOG_ERROR, LOG_WARNING, manager_skinny_show_device(), manager_skinny_show_devices(), manager_skinny_show_line(), manager_skinny_show_lines(), mandescr_show_device, mandescr_show_devices, mandescr_show_line, mandescr_show_lines, skinny_req::res, restart_monitor(), sched_context_create(), skinny_rtp, skinny_tech, and soft_key_template_definition::softKeyEvent.

{
   int res = 0;

   for (; res < ARRAY_LEN(soft_key_template_default); res++) {
      soft_key_template_default[res].softKeyEvent = htolel(soft_key_template_default[res].softKeyEvent);
   }
   /* load and parse config */
   res = config_load();
   if (res == -1) {
      return AST_MODULE_LOAD_DECLINE;
   }

   /* 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;
   }

   ast_rtp_proto_register(&skinny_rtp);
   ast_cli_register_multiple(cli_skinny, ARRAY_LEN(cli_skinny));

   ast_manager_register2("SKINNYdevices", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_devices,
         "List SKINNY devices (text format)", mandescr_show_devices);
   ast_manager_register2("SKINNYshowdevice", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_device,
         "Show SKINNY device (text format)", mandescr_show_device);
   ast_manager_register2("SKINNYlines", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_lines,
         "List SKINNY lines (text format)", mandescr_show_lines);
   ast_manager_register2("SKINNYshowline", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_line,
         "Show SKINNY line (text format)", mandescr_show_line);

   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();

   return AST_MODULE_LOAD_SUCCESS;
}
static int manager_skinny_show_device ( struct mansession s,
const struct message m 
) [static]

Definition at line 3171 of file chan_skinny.c.

References _skinny_show_device(), ast_strlen_zero(), astman_append(), astman_get_header(), and astman_send_error().

Referenced by load_module().

{
   const char *a[4];
   const char *device;

   device = astman_get_header(m, "Device");
   if (ast_strlen_zero(device)) {
      astman_send_error(s, m, "Device: <name> missing.");
      return 0;
   }
   a[0] = "skinny";
   a[1] = "show";
   a[2] = "device";
   a[3] = device;

   _skinny_show_device(1, -1, s, m, 4, a);
   astman_append(s, "\r\n\r\n" );
   return 0;
}
static int manager_skinny_show_devices ( struct mansession s,
const struct message m 
) [static]

Show SKINNY devices in the manager API.

Definition at line 3029 of file chan_skinny.c.

References _skinny_show_devices(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_listack(), and total.

Referenced by load_module().

{
   const char *id = astman_get_header(m, "ActionID");
   const char *a[] = {"skinny", "show", "devices"};
   char idtext[256] = "";
   int total = 0;

   if (!ast_strlen_zero(id))
      snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);

   astman_send_listack(s, m, "Device status list will follow", "start");
   /* List the devices in separate manager events */
   _skinny_show_devices(-1, &total, s, m, 3, a);
   /* Send final confirmation */
   astman_append(s,
   "Event: DevicelistComplete\r\n"
   "EventList: Complete\r\n"
   "ListItems: %d\r\n"
   "%s"
   "\r\n", total, idtext);
   return 0;
}
static int manager_skinny_show_line ( struct mansession s,
const struct message m 
) [static]

Definition at line 3481 of file chan_skinny.c.

References _skinny_show_line(), ast_strlen_zero(), astman_append(), astman_get_header(), and astman_send_error().

Referenced by load_module().

{
   const char *a[4];
   const char *line;

   line = astman_get_header(m, "Line");
   if (ast_strlen_zero(line)) {
      astman_send_error(s, m, "Line: <name> missing.");
      return 0;
   }
   a[0] = "skinny";
   a[1] = "show";
   a[2] = "line";
   a[3] = line;

   _skinny_show_line(1, -1, s, m, 4, a);
   astman_append(s, "\r\n\r\n" );
   return 0;
}
static int manager_skinny_show_lines ( struct mansession s,
const struct message m 
) [static]

Show Skinny lines in the manager API.

Definition at line 3290 of file chan_skinny.c.

References _skinny_show_lines(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_listack(), and total.

Referenced by load_module().

{
   const char *id = astman_get_header(m, "ActionID");
   const char *a[] = {"skinny", "show", "lines"};
   char idtext[256] = "";
   int total = 0;

   if (!ast_strlen_zero(id))
      snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);

   astman_send_listack(s, m, "Line status list will follow", "start");
   /* List the lines in separate manager events */
   _skinny_show_lines(-1, &total, s, m, 3, a);
   /* Send final confirmation */
   astman_append(s,
   "Event: LinelistComplete\r\n"
   "EventList: Complete\r\n"
   "ListItems: %d\r\n"
   "%s"
   "\r\n", total, idtext);
   return 0;
}
static void mwi_event_cb ( const struct ast_event event,
void *  userdata 
) [static]

Definition at line 2526 of file chan_skinny.c.

References ast_event_get_ie_uint(), AST_EVENT_IE_NEWMSGS, AST_LIST_TRAVERSE, ast_verb, skinny_line::device, skinny_device::lines, skinny_line::newmsgs, s, skinny_device::session, SKINNY_LAMP_BLINK, SKINNY_LAMP_OFF, SKINNY_LAMP_ON, STIMULUS_VOICEMAIL, and transmit_lamp_indication().

Referenced by config_line(), and skinny_register().

{
   struct skinny_line *l = userdata;
   struct skinny_device *d = l->device;
   if (d) {
      struct skinnysession *s = d->session;
      struct skinny_line *l2;
      int new_msgs = 0;
      int dev_msgs = 0;

      if (s) {
         if (event) {
            l->newmsgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
         }

         if (l->newmsgs) {
            transmit_lamp_indication(d, STIMULUS_VOICEMAIL, l->instance, l->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON);
         } else {
            transmit_lamp_indication(d, STIMULUS_VOICEMAIL, l->instance, SKINNY_LAMP_OFF);
         }

         /* find out wether the device lamp should be on or off */
         AST_LIST_TRAVERSE(&d->lines, l2, list) {
            if (l2->newmsgs) {
               dev_msgs++;
            }
         }

         if (dev_msgs) {
            transmit_lamp_indication(d, STIMULUS_VOICEMAIL, 0, d->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON);
         } else {
            transmit_lamp_indication(d, STIMULUS_VOICEMAIL, 0, SKINNY_LAMP_OFF);
         }
         ast_verb(3, "Skinny mwi_event_cb found %d new messages\n", new_msgs);
      }
   }
}
static void print_codec_to_cli ( int  fd,
struct ast_codec_pref pref 
) [static]

Print codec list from preference to CLI/manager.

Definition at line 2934 of file chan_skinny.c.

References ast_cli(), ast_codec_pref_index(), ast_getformatname(), and ast_codec_pref::framing.

Referenced by _skinny_show_line().

{
   int x, codec;

   for(x = 0; x < 32 ; x++) {
      codec = ast_codec_pref_index(pref, x);
      if (!codec)
         break;
      ast_cli(fd, "%s", ast_getformatname(codec));
      ast_cli(fd, ":%d", pref->framing[x]);
      if (x < 31 && ast_codec_pref_index(pref, x + 1))
         ast_cli(fd, ",");
   }
   if (!x)
      ast_cli(fd, "none");
}
static void register_exten ( struct skinny_line l) [static]

Definition at line 1770 of file chan_skinny.c.

References ast_add_extension(), ast_context_find(), ast_copy_string(), ast_free_ptr, ast_log(), ast_strdup, ast_strlen_zero(), context, ext, LOG_WARNING, regcontext, S_OR, and strsep().

Referenced by skinny_register().

{
   char multi[256];
   char *stringp, *ext, *context;

   if (ast_strlen_zero(regcontext))
      return;

   ast_copy_string(multi, S_OR(l->regexten, l->name), sizeof(multi));
   stringp = multi;
   while ((ext = strsep(&stringp, "&"))) {
      if ((context = strchr(ext, '@'))) {
         *context++ = '\0'; /* split ext@context */
         if (!ast_context_find(context)) {
            ast_log(LOG_WARNING, "Context %s must exist in regcontext= in skinny.conf!\n", context);
            continue;
         }
      } else {
         context = regcontext;
      }
      ast_add_extension(context, 1, ext, 1, NULL, NULL, "Noop",
          ast_strdup(l->name), ast_free_ptr, "Skinny");
   }
}
static int reload ( void  ) [static]

Definition at line 7484 of file chan_skinny.c.

References skinny_reload().

{
   skinny_reload();
   return 0;
}
static int restart_monitor ( void  ) [static]

Definition at line 6513 of file chan_skinny.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, AST_PTHREADT_NULL, AST_PTHREADT_STOP, do_monitor(), LOG_ERROR, LOG_WARNING, and monlock.

Referenced by load_module(), and skinny_request().

{
   /* If we're supposed to be stopped -- stay stopped */
   if (monitor_thread == AST_PTHREADT_STOP)
      return 0;

   ast_mutex_lock(&monlock);
   if (monitor_thread == pthread_self()) {
      ast_mutex_unlock(&monlock);
      ast_log(LOG_WARNING, "Cannot kill myself\n");
      return -1;
   }
   if (monitor_thread != AST_PTHREADT_NULL) {
      /* Wake up the thread */
      pthread_kill(monitor_thread, SIGURG);
   } else {
      /* Start a new monitor */
      if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
         ast_mutex_unlock(&monlock);
         ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
         return -1;
      }
   }
   ast_mutex_unlock(&monlock);
   return 0;
}
static int set_callforwards ( struct skinny_line l,
const char *  cfwd,
int  cfwdtype 
) [static]

Definition at line 1712 of file chan_skinny.c.

References ast_copy_string(), ast_strlen_zero(), SKINNY_CFWD_ALL, SKINNY_CFWD_BUSY, and SKINNY_CFWD_NOANSWER.

Referenced by handle_callforward_button(), skinny_register(), and skinny_ss().

{
   if (!l)
      return 0;

   if (!ast_strlen_zero(cfwd)) {
      if (cfwdtype & SKINNY_CFWD_ALL) {
         l->cfwdtype |= SKINNY_CFWD_ALL;
         ast_copy_string(l->call_forward_all, cfwd, sizeof(l->call_forward_all));
      }
      if (cfwdtype & SKINNY_CFWD_BUSY) {
         l->cfwdtype |= SKINNY_CFWD_BUSY;
         ast_copy_string(l->call_forward_busy, cfwd, sizeof(l->call_forward_busy));
      }
      if (cfwdtype & SKINNY_CFWD_NOANSWER) {
         l->cfwdtype |= SKINNY_CFWD_NOANSWER;
         ast_copy_string(l->call_forward_noanswer, cfwd, sizeof(l->call_forward_noanswer));
      }
   } else {
      if (cfwdtype & SKINNY_CFWD_ALL) {
         l->cfwdtype &= ~SKINNY_CFWD_ALL;
         memset(l->call_forward_all, 0, sizeof(l->call_forward_all));
      }
      if (cfwdtype & SKINNY_CFWD_BUSY) {
         l->cfwdtype &= ~SKINNY_CFWD_BUSY;
         memset(l->call_forward_busy, 0, sizeof(l->call_forward_busy));
      }
      if (cfwdtype & SKINNY_CFWD_NOANSWER) {
         l->cfwdtype &= ~SKINNY_CFWD_NOANSWER;
         memset(l->call_forward_noanswer, 0, sizeof(l->call_forward_noanswer));
      }
   }
   return l->cfwdtype;
}
static int skinny_answer ( struct ast_channel ast) [static]

Definition at line 3873 of file chan_skinny.c.

References ast_channel::_state, skinny_line::activesub, ast_debug, ast_setstate(), AST_STATE_UP, ast_verb, skinny_subchannel::blindxfer, skinny_subchannel::callid, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, skinny_subchannel::cxmode, skinny_line::device, KEYDEF_CONNECTED, ast_channel::name, skinny_subchannel::parent, skinny_subchannel::rtp, SKINNY_CONNECTED, SKINNY_CX_SENDRECV, SKINNY_SILENCE, skinny_transfer(), start_rtp(), ast_channel::tech_pvt, transmit_callinfo(), transmit_callstateonly(), transmit_dialednumber(), transmit_displaypromptstatus(), transmit_selectsoftkeys(), and transmit_tone().

{
   int res = 0;
   struct skinny_subchannel *sub = ast->tech_pvt;
   struct skinny_line *l = sub->parent;
   struct skinny_device *d = l->device;

   if (sub->blindxfer) {
      if (skinnydebug)
         ast_debug(1, "skinny_answer(%s) on %s@%s-%d with BlindXFER, transferring\n",
            ast->name, l->name, d->name, sub->callid);
      ast_setstate(ast, AST_STATE_UP);
      skinny_transfer(sub);
      return 0;
   }

   sub->cxmode = SKINNY_CX_SENDRECV;
   if (!sub->rtp) {
      start_rtp(sub);
   }
   if (skinnydebug)
      ast_verb(1, "skinny_answer(%s) on %s@%s-%d\n", ast->name, l->name, d->name, sub->callid);
   if (ast->_state != AST_STATE_UP) {
      ast_setstate(ast, AST_STATE_UP);
   }

   transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
   /* 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(d, ast->cid.cid_name, ast->cid.cid_num, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2);
   transmit_callstateonly(d, sub, SKINNY_CONNECTED);
   transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
   transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
   transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid);
   l->activesub = sub;
   return res;
}
static int skinny_call ( struct ast_channel ast,
char *  dest,
int  timeout 
) [static]

Definition at line 3729 of file chan_skinny.c.

References ast_channel::_state, skinny_line::activesub, AST_CONTROL_BUSY, AST_CONTROL_RINGING, AST_LIST_NEXT, ast_log(), ast_queue_control(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RINGING, ast_verb, skinny_subchannel::callid, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, skinny_line::device, KEYDEF_RINGIN, LOG_ERROR, LOG_WARNING, ast_channel::name, skinny_subchannel::outgoing, skinny_subchannel::parent, SKINNY_ALERT, SKINNY_CALLWAITTONE, SKINNY_LAMP_BLINK, SKINNY_OFFHOOK, SKINNY_ONHOOK, SKINNY_RING_INSIDE, SKINNY_RINGIN, STIMULUS_LINE, ast_channel::tech_pvt, transmit_callinfo(), transmit_callstateonly(), transmit_displaypromptstatus(), transmit_lamp_indication(), transmit_ringer_mode(), and transmit_selectsoftkeys().

{
   int res = 0;
   int tone = 0;
   struct skinny_subchannel *sub = ast->tech_pvt;
   struct skinny_line *l = sub->parent;
   struct skinny_device *d = l->device;

   if (!d->registered) {
      ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
      return -1;
   }

   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;
   }

   if (skinnydebug)
      ast_verb(3, "skinny_call(%s)\n", ast->name);

   if (l->dnd) {
      ast_queue_control(ast, AST_CONTROL_BUSY);
      return -1;
   }

   if (AST_LIST_NEXT(sub,list) && !l->callwaiting) {
      ast_queue_control(ast, AST_CONTROL_BUSY);
      return -1;
   }
   
   switch (l->hookstate) {
   case SKINNY_OFFHOOK:
      tone = SKINNY_CALLWAITTONE;
      break;
   case SKINNY_ONHOOK:
      tone = SKINNY_ALERT;
      l->activesub = sub;
      break;
   default:
      ast_log(LOG_ERROR, "Don't know how to deal with hookstate %d\n", l->hookstate);
      break;
   }

   transmit_callstateonly(d, sub, SKINNY_RINGIN);
   transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN);
   transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid);
   transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1);
   transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
   transmit_ringer_mode(d, SKINNY_RING_INSIDE);

   ast_setstate(ast, AST_STATE_RINGING);
   ast_queue_control(ast, AST_CONTROL_RINGING);
   sub->outgoing = 1;
   return res;
}
static int skinny_devicestate ( void *  data) [static]

Definition at line 6540 of file chan_skinny.c.

References ast_strdupa, find_line_by_name(), and get_devicestate().

{
   struct skinny_line *l;
   char *tmp;

   tmp = ast_strdupa(data);

   l = find_line_by_name(tmp);

   return get_devicestate(l);
}
static int skinny_extensionstate_cb ( char *  context,
char *  exten,
int  state,
void *  data 
) [static]

Definition at line 2474 of file chan_skinny.c.

References AST_DEVICE_UNAVAILABLE, AST_EXTENSION_BUSY, AST_EXTENSION_DEACTIVATED, AST_EXTENSION_INUSE, AST_EXTENSION_NOT_INUSE, AST_EXTENSION_ONHOLD, AST_EXTENSION_REMOVED, AST_EXTENSION_RINGING, AST_EXTENSION_UNAVAILABLE, ast_get_hint(), AST_MAX_EXTENSION, ast_verb, skinny_speeddial::context, skinny_speeddial::exten, skinny_speeddial::instance, skinny_speeddial::laststate, skinny_speeddial::parent, SKINNY_CALLREMOTEMULTILINE, SKINNY_HOLD, SKINNY_LAMP_BLINK, SKINNY_LAMP_FLASH, SKINNY_LAMP_OFF, SKINNY_LAMP_ON, SKINNY_LAMP_WINK, SKINNY_ONHOOK, SKINNY_RINGIN, skinny_speeddial::stateid, STIMULUS_LINE, transmit_callstate(), and transmit_lamp_indication().

Referenced by skinny_register().

{
   struct skinny_speeddial *sd = data;
   struct skinny_device *d = sd->parent;
   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_verb(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(d, STIMULUS_LINE, sd->instance, lamp);
   transmit_callstate(d, sd->instance, callstate, 0);
   sd->laststate = state;

   return 0;
}
static int skinny_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
) [static]

Definition at line 3998 of file chan_skinny.c.

References ast_log(), LOG_NOTICE, LOG_WARNING, ast_channel::name, skinny_subchannel::owner, and ast_channel::tech_pvt.

{
   struct skinny_subchannel *sub = newchan->tech_pvt;
   ast_log(LOG_NOTICE, "skinny_fixup(%s, %s)\n", oldchan->name, newchan->name);
   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;
}
static enum ast_rtp_get_result skinny_get_rtp_peer ( struct ast_channel c,
struct ast_rtp **  rtp 
) [static]

Definition at line 2579 of file chan_skinny.c.

References ast_mutex_lock(), ast_mutex_unlock(), AST_RTP_GET_FAILED, AST_RTP_TRY_NATIVE, AST_RTP_TRY_PARTIAL, ast_verb, skinny_subchannel::lock, ast_channel::name, skinny_subchannel::parent, skinny_subchannel::rtp, and ast_channel::tech_pvt.

{
   struct skinny_subchannel *sub = NULL;
   struct skinny_line *l;
   enum ast_rtp_get_result res = AST_RTP_TRY_NATIVE;

   if (skinnydebug)
      ast_verb(1, "skinny_get_rtp_peer() Channel = %s\n", c->name);


   if (!(sub = c->tech_pvt))
      return AST_RTP_GET_FAILED;

   ast_mutex_lock(&sub->lock);

   if (!(sub->rtp)){
      ast_mutex_unlock(&sub->lock);
      return AST_RTP_GET_FAILED;
   }
   
   *rtp = sub->rtp;

   l = sub->parent;

   if (!l->directmedia || l->nat){
      res = AST_RTP_TRY_PARTIAL;
      if (skinnydebug)
         ast_verb(1, "skinny_get_rtp_peer() Using AST_RTP_TRY_PARTIAL \n");
   }

   ast_mutex_unlock(&sub->lock);

   return res;

}
static enum ast_rtp_get_result skinny_get_vrtp_peer ( struct ast_channel c,
struct ast_rtp **  rtp 
) [static]

Definition at line 2567 of file chan_skinny.c.

References AST_RTP_GET_FAILED, AST_RTP_TRY_NATIVE, ast_channel::tech_pvt, and skinny_subchannel::vrtp.

{
   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;
}
static int skinny_hangup ( struct ast_channel ast) [static]

Definition at line 3786 of file chan_skinny.c.

References skinny_device::activeline, skinny_line::activesub, skinny_subchannel::alreadygone, ast_debug, ast_free, AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_NEXT, AST_LIST_REMOVE, ast_module_unref(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtp_destroy(), ast_verb, skinny_subchannel::callid, skinny_line::device, skinny_subchannel::lock, skinny_subchannel::outgoing, skinny_subchannel::owner, skinny_subchannel::parent, skinny_subchannel::related, skinny_subchannel::rtp, s, ast_module_info::self, skinny_device::session, SKINNY_LAMP_BLINK, SKINNY_LAMP_OFF, SKINNY_LAMP_ON, SKINNY_ONHOOK, SKINNY_RING_OFF, SKINNY_SILENCE, SKINNY_SPEAKEROFF, STIMULUS_LINE, skinny_line::sub, ast_channel::tech_pvt, transmit_activatecallplane(), transmit_callstate(), transmit_closereceivechannel(), transmit_displaymessage(), transmit_lamp_indication(), transmit_ringer_mode(), transmit_speaker_mode(), transmit_stopmediatransmission(), and transmit_tone().

{
   struct skinny_subchannel *sub = ast->tech_pvt;
   struct skinny_line *l;
   struct skinny_device *d;
   struct skinnysession *s;

   if (!sub) {
      ast_debug(1, "Asked to hangup channel not connected\n");
      return 0;
   }

   l = sub->parent;
   d = l->device;
   s = d->session;

   if (skinnydebug)
      ast_verb(3,"Hanging up %s/%d\n",d->name,sub->callid);

   AST_LIST_REMOVE(&l->sub, sub, list);

   if (d->registered) {
      /* Ignoring l->type, doesn't seem relevant and previous code 
         assigned rather than tested, ie always true */
      if (!AST_LIST_EMPTY(&l->sub)) {
         if (sub->related) {
            sub->related->related = NULL;

         }
         if (sub == l->activesub) {      /* we are killing the active sub, but there are other subs on the line*/
            ast_verb(4,"Killing active sub %d\n", sub->callid);
            if (sub->related) {
               l->activesub = sub->related;
            } else {
               if (AST_LIST_NEXT(sub, list)) {
                  l->activesub = AST_LIST_NEXT(sub, list);
               } else {
                  l->activesub = AST_LIST_FIRST(&l->sub);
               }
            }
            //transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->callid);
            transmit_activatecallplane(d, l);
            transmit_closereceivechannel(d, sub);
            transmit_stopmediatransmission(d, sub);
            transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
            transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
         } else {    /* we are killing a background sub on the line with other subs*/
            ast_verb(4,"Killing inactive sub %d\n", sub->callid);
            if (AST_LIST_NEXT(sub, list)) {
               transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
            } else {
               transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
            }
         }
      } else {                                                /* no more subs on line so make idle */
         ast_verb(4,"Killing only sub %d\n", sub->callid);
         l->hookstate = SKINNY_ONHOOK;
         transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->callid);
         l->activesub = NULL;
         transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
         if (sub->parent == d->activeline) {
            transmit_activatecallplane(d, l);
            transmit_closereceivechannel(d, sub);
            transmit_stopmediatransmission(d, sub);
            transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
            transmit_ringer_mode(d, SKINNY_RING_OFF);
            transmit_displaymessage(d, NULL, l->instance, sub->callid); /* clear display */
            transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
            /* we should check to see if we can start the ringer if another line is ringing */
         }
      }
   }
   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);
   ast_free(sub);
   ast_module_unref(ast_module_info->self);
   return 0;
}
static int skinny_hold ( struct skinny_subchannel sub) [static]
static int skinny_indicate ( struct ast_channel ast,
int  ind,
const void *  data,
size_t  datalen 
) [static]

Definition at line 4175 of file chan_skinny.c.

References ast_channel::_state, skinny_subchannel::alreadygone, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_SRCCHANGE, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, ast_debug, ast_log(), ast_moh_start(), ast_moh_stop(), ast_rtp_change_source(), ast_rtp_new_source(), AST_SOFTHANGUP_DEV, ast_softhangup_nolock(), AST_STATE_UP, ast_verb, skinny_subchannel::blindxfer, skinny_subchannel::callid, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, control2str(), skinny_line::device, LOG_NOTICE, LOG_WARNING, ast_channel::name, skinny_subchannel::outgoing, skinny_subchannel::parent, skinny_subchannel::progress, skinny_subchannel::ringing, skinny_subchannel::rtp, s, skinny_device::session, SKINNY_ALERT, SKINNY_BUSY, SKINNY_BUSYTONE, SKINNY_CONGESTION, SKINNY_PROGRESS, SKINNY_REORDER, SKINNY_RINGOUT, SKINNY_SILENCE, skinny_transfer(), ast_channel::tech_pvt, transmit_callinfo(), transmit_callstateonly(), transmit_dialednumber(), transmit_displaypromptstatus(), and transmit_tone().

{
   struct skinny_subchannel *sub = ast->tech_pvt;
   struct skinny_line *l = sub->parent;
   struct skinny_device *d = l->device;
   struct skinnysession *s = d->session;

   if (!s) {
      ast_log(LOG_NOTICE, "Asked to indicate '%s' condition on channel %s, but session does not exist.\n", control2str(ind), ast->name);
      return -1;
   }

   if (skinnydebug)
      ast_verb(3, "Asked to indicate '%s' condition on channel %s\n", control2str(ind), ast->name);
   switch(ind) {
   case AST_CONTROL_RINGING:
      if (sub->blindxfer) {
         if (skinnydebug)
            ast_debug(1, "Channel %s set up for Blind Xfer, so Xfer rather than ring device\n", ast->name);
         skinny_transfer(sub);
         break;
      }
      if (ast->_state != AST_STATE_UP) {
         if (!sub->progress) {
            if (!d->earlyrtp) {
               transmit_tone(d, SKINNY_ALERT, l->instance, sub->callid);
            }
            transmit_callstateonly(d, sub, SKINNY_RINGOUT);
            transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
            transmit_displaypromptstatus(d, "Ring Out", 0, l->instance, sub->callid);
            transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2); /* 2 = outgoing from phone */
            sub->ringing = 1;
            if (!d->earlyrtp) {
               break;
            }
         }
      }
      return -1; /* Tell asterisk to provide inband signalling */
   case AST_CONTROL_BUSY:
      if (ast->_state != AST_STATE_UP) {
         if (!d->earlyrtp) {
            transmit_tone(d, SKINNY_BUSYTONE, l->instance, sub->callid);
         }
         transmit_callstateonly(d, sub, SKINNY_BUSY);
         sub->alreadygone = 1;
         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
         if (!d->earlyrtp) {
            break;
         }
      }
      return -1; /* Tell asterisk to provide inband signalling */
   case AST_CONTROL_CONGESTION:
      if (ast->_state != AST_STATE_UP) {
         if (!d->earlyrtp) {
            transmit_tone(d, SKINNY_REORDER, l->instance, sub->callid);
         }
         transmit_callstateonly(d, sub, SKINNY_CONGESTION);
         sub->alreadygone = 1;
         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
         if (!d->earlyrtp) {
            break;
         }
      }
      return -1; /* Tell asterisk to provide inband signalling */
   case AST_CONTROL_PROGRESS:
      if ((ast->_state != AST_STATE_UP) && !sub->progress && !sub->outgoing) {
         if (!d->earlyrtp) {
            transmit_tone(d, SKINNY_ALERT, l->instance, sub->callid);
         }
         transmit_callstateonly(d, sub, SKINNY_PROGRESS);
         transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid);
         transmit_callinfo(d, ast->cid.cid_name, ast->cid.cid_num, l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2); /* 2 = outgoing from phone */
         sub->progress = 1;
         if (!d->earlyrtp) {
            break;
         }
      }
      return -1; /* Tell asterisk to provide inband signalling */
   case -1:  /* STOP_TONE */
      transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
      break;
   case AST_CONTROL_HOLD:
      ast_moh_start(ast, data, l->mohinterpret);
      break;
   case AST_CONTROL_UNHOLD:
      ast_moh_stop(ast);
      break;
   case AST_CONTROL_PROCEEDING:
      break;
   case AST_CONTROL_SRCUPDATE:
      ast_rtp_new_source(sub->rtp);
      break;
   case AST_CONTROL_SRCCHANGE:
      ast_rtp_change_source(sub->rtp);
      break;
   default:
      ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
      return -1; /* Tell asterisk to provide inband signalling */
   }
   return 0;
}
static struct ast_channel* skinny_new ( struct skinny_line l,
int  state 
) [static, read]

Definition at line 4277 of file chan_skinny.c.

References accountcode, ast_channel::adsicpe, ast_channel::amaflags, AST_ADSI_UNAVAILABLE, ast_best_codec(), ast_calloc, ast_channel_alloc(), ast_channel_set_fd(), ast_copy_string(), AST_DEVICE_NOT_INUSE, ast_hangup(), ast_jb_configure(), AST_LIST_INSERT_HEAD, ast_log(), ast_module_ref(), ast_mutex_init(), ast_pbx_start(), ast_rtp_fd(), AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_verb, skinny_subchannel::blindxfer, ast_channel::callgroup, skinny_subchannel::callid, skinny_line::chanvars, ast_channel::cid, ast_callerid::cid_ani, ast_channel::context, skinny_subchannel::cxmode, default_capability, skinny_line::device, ast_channel::exten, get_devicestate(), global_jbconf, language, skinny_subchannel::lock, LOG_WARNING, ast_channel::name, ast_variable::name, skinny_subchannel::nat, ast_channel::nativeformats, ast_variable::next, skinny_subchannel::onhold, skinny_subchannel::owner, skinny_subchannel::parent, parkinglot, pbx_builtin_setvar_helper(), ast_channel::pickupgroup, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, skinny_subchannel::related, ast_channel::rings, skinny_subchannel::rtp, ast_module_info::self, SKINNY_CFWD_ALL, SKINNY_CFWD_BUSY, SKINNY_CX_INACTIVE, skinny_tech, skinny_line::sub, ast_channel::tech, ast_channel::tech_pvt, ast_variable::value, ast_channel::writeformat, and skinny_subchannel::xferor.

Referenced by handle_enbloc_call_message(), handle_offhook_message(), handle_soft_key_event_message(), handle_stimulus_message(), handle_transfer_button(), and skinny_request().

{
   struct ast_channel *tmp;
   struct skinny_subchannel *sub;
   struct skinny_device *d = l->device;
   struct ast_variable *v = NULL;
   int fmt;

   if (!l->device) {
      ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
      return NULL;
   }

   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);
   if (!tmp) {
      ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
      return NULL;
   } else {
      sub = ast_calloc(1, sizeof(*sub));
      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;
         sub->onhold = 0;
         sub->blindxfer = 0;
         sub->xferor = 0;
         sub->related = NULL;

         AST_LIST_INSERT_HEAD(&l->sub, sub, list);
         //l->activesub = sub;
      }
      tmp->tech = &skinny_tech;
      tmp->tech_pvt = sub;
      tmp->nativeformats = l->capability;
      if (!tmp->nativeformats)
         // Should throw an error
         tmp->nativeformats = default_capability;
      fmt = ast_best_codec(tmp->nativeformats);
      if (skinnydebug)
         ast_verb(1, "skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp->nativeformats, fmt);
      if (sub->rtp) {
         ast_channel_set_fd(tmp, 0, ast_rtp_fd(sub->rtp));
      }
      if (state == AST_STATE_RING) {
         tmp->rings = 1;
      }
      tmp->writeformat = fmt;
      tmp->rawwriteformat = fmt;
      tmp->readformat = fmt;
      tmp->rawreadformat = fmt;
      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 (!ast_strlen_zero(l->parkinglot))
         ast_string_field_set(tmp, parkinglot, l->parkinglot);
      if (l->amaflags)
         tmp->amaflags = l->amaflags;

      ast_module_ref(ast_module_info->self);
      tmp->callgroup = l->callgroup;
      tmp->pickupgroup = l->pickupgroup;

      /* XXX Need to figure out how to handle CFwdNoAnswer */
      if (l->cfwdtype & SKINNY_CFWD_ALL) {
         ast_string_field_set(tmp, call_forward, l->call_forward_all);
      } else if (l->cfwdtype & SKINNY_CFWD_BUSY) {
         if (get_devicestate(l) != AST_DEVICE_NOT_INUSE) {
            ast_string_field_set(tmp, call_forward, l->call_forward_busy);
         }
      }

      ast_copy_string(tmp->context, l->context, sizeof(tmp->context));
      ast_copy_string(tmp->exten, l->exten, sizeof(tmp->exten));

      /* Don't use ast_set_callerid() here because it will
       * generate a needless NewCallerID event */
      tmp->cid.cid_ani = ast_strdup(l->cid_num);

      tmp->priority = 1;
      tmp->adsicpe = AST_ADSI_UNAVAILABLE;

      if (sub->rtp)
         ast_jb_configure(tmp, &global_jbconf);

      /* Set channel variables for this call from configuration */
      for (v = l->chanvars ; v ; v = v->next)
         pbx_builtin_setvar_helper(tmp, v->name, v->value);

      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);
            tmp = NULL;
         }
      }
   }
   return tmp;
}
static void* skinny_newcall ( void *  data) [static]

Definition at line 3600 of file chan_skinny.c.

References ast_copy_string(), ast_log(), ast_pbx_run(), ast_set_callerid(), ast_setstate(), AST_STATE_RING, skinny_subchannel::callid, ast_channel::cid, ast_callerid::cid_ani, ast_channel::data, skinny_line::device, ast_channel::exten, LOG_WARNING, skinny_subchannel::parent, skinny_subchannel::rtp, SKINNY_REORDER, start_rtp(), ast_channel::tech_pvt, and transmit_tone().

Referenced by handle_enbloc_call_message(), handle_soft_key_event_message(), handle_stimulus_message(), and skinny_ss().

{
   struct ast_channel *c = data;
   struct skinny_subchannel *sub = c->tech_pvt;
   struct skinny_line *l = sub->parent;
   struct skinny_device *d = l->device;
   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);
   if (!sub->rtp) {
      start_rtp(sub);
   }
   res = ast_pbx_run(c);
   if (res) {
      ast_log(LOG_WARNING, "PBX exited non-zero\n");
      transmit_tone(d, SKINNY_REORDER, l->instance, sub->callid);
   }
   return NULL;
}
static struct ast_frame * skinny_read ( struct ast_channel ast) [static, read]

Definition at line 3960 of file chan_skinny.c.

References ast_mutex_lock(), ast_mutex_unlock(), skinny_subchannel::lock, skinny_rtp_read(), and ast_channel::tech_pvt.

{
   struct ast_frame *fr;
   struct skinny_subchannel *sub = ast->tech_pvt;
   ast_mutex_lock(&sub->lock);
   fr = skinny_rtp_read(sub);
   ast_mutex_unlock(&sub->lock);
   return fr;
}
static int skinny_register ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 1819 of file chan_skinny.c.

References __ourip, ast_app_has_voicemail(), ast_apply_ha(), ast_copy_string(), AST_DEVICE_NOT_INUSE, ast_devstate_changed(), ast_extension_state_add(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), ast_verb, skinny_speeddial::context, skinny_req::data, skinny_line::device, skinnysession::device, skinny_speeddial::exten, skinnysession::fd, skinny_device::ha, letohl, skinny_device::lines, LOG_WARNING, mwi_event_cb(), register_message::name, skinny_line::newmsgs, skinny_device::ourip, skinny_data::reg, register_exten(), s, skinny_device::session, set_callforwards(), skinnysession::sin, skinny_extensionstate_cb(), skinny_device::speeddials, skinny_speeddial::stateid, and register_message::type.

Referenced by handle_register_message().

{
   struct skinny_device *d;
   struct skinny_line *l;
   struct skinny_speeddial *sd;
   struct sockaddr_in sin;
   socklen_t slen;
   int instance;

   AST_LIST_LOCK(&devices);
   AST_LIST_TRAVERSE(&devices, d, list){
      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;

         AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
            sd->stateid = ast_extension_state_add(sd->context, sd->exten, skinny_extensionstate_cb, sd);
         }
         instance = 0;
         AST_LIST_TRAVERSE(&d->lines, l, list) {
            instance++;
         }
         AST_LIST_TRAVERSE(&d->lines, l, list) {
            /* FIXME: All sorts of issues will occur if this line is already connected to a device */
            if (l->device) {
               ast_verb(1, "Line %s already connected to %s. Not connecting to %s.\n", l->name, l->device->name, d->name);
            } else {
               l->device = d;
               l->capability = l->confcapability & d->capability;
               l->prefs = l->confprefs;
               if (!l->prefs.order[0]) {
                  l->prefs = d->confprefs;
               }
               /* l->capability = d->capability;
               l->prefs = d->prefs; */
               l->instance = instance;
               l->newmsgs = ast_app_has_voicemail(l->mailbox, NULL);
               set_callforwards(l, NULL, 0);
               register_exten(l);
               /* initialize MWI on line and device */
               mwi_event_cb(0, l);
               ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
            }
            --instance;
         }
         break;
      }
   }
   AST_LIST_UNLOCK(&devices);
   if (!d) {
      return 0;
   }
   return 1;
}
int skinny_reload ( void  ) [static]

Definition at line 7281 of file chan_skinny.c.

References skinny_device::addons, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_verb, config_load(), skinny_req::data, free, skinny_device::lines, req_alloc(), skinny_data::reset, RESET_MESSAGE, reset_message::resetType, skinny_device::session, skinny_device::speeddials, and transmit_response().

Referenced by handle_skinny_reload(), and reload().

{
   struct skinny_device *d;
   struct skinny_line *l;
   struct skinny_speeddial *sd;
   struct skinny_addon *a;
   struct skinny_req *req;

   if (skinnyreload) {
      ast_verb(3, "Chan_skinny is already reloading.\n");
      return 0;
   }

   skinnyreload = 1;

   /* Mark all devices and lines as candidates to be pruned */
   AST_LIST_LOCK(&devices);
   AST_LIST_TRAVERSE(&devices, d, list) {
      d->prune = 1;
   }
   AST_LIST_UNLOCK(&devices);

   AST_LIST_LOCK(&lines);
   AST_LIST_TRAVERSE(&lines, l, all) {
      l->prune = 1;
   }
   AST_LIST_UNLOCK(&lines);

        config_load();

   /* Remove any devices that no longer exist in the config */
   AST_LIST_LOCK(&devices);
   AST_LIST_TRAVERSE_SAFE_BEGIN(&devices, d, list) {
      if (!d->prune) {
         continue;
      }
      ast_verb(3, "Removing device '%s'\n", d->name);
      /* Delete all lines for this device. 
         We do not want to free the line here, that
         will happen below. */
      while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) {
      }
      /* Delete all speeddials for this device */
      while ((sd = AST_LIST_REMOVE_HEAD(&d->speeddials, list))) {
         free(sd);
      }
      /* Delete all addons for this device */
      while ((a = AST_LIST_REMOVE_HEAD(&d->addons, list))) {
         free(a);
      }
      AST_LIST_REMOVE_CURRENT(list);
      free(d);
   }
   AST_LIST_TRAVERSE_SAFE_END;
   AST_LIST_UNLOCK(&devices);

   AST_LIST_LOCK(&lines);  
   AST_LIST_TRAVERSE_SAFE_BEGIN(&lines, l, all) {
      if (l->prune) {
         AST_LIST_REMOVE_CURRENT(all);
         free(l);
      }
   }
   AST_LIST_TRAVERSE_SAFE_END;
   AST_LIST_UNLOCK(&lines);  

   AST_LIST_TRAVERSE(&devices, d, list) {
      /* Do a soft reset to re-register the devices after
         cleaning up the removed devices and lines */
      if (d->session) {
         ast_verb(3, "Restarting device '%s'\n", d->name);
         if ((req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE))) {
            req->data.reset.resetType = 2;
            transmit_response(d, req);
         }
      }
   }
   
   skinnyreload = 0;
        return 0;
}
static struct skinny_req* skinny_req_parse ( struct skinnysession s) [static, read]

Definition at line 6368 of file chan_skinny.c.

References ast_calloc, ast_free, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), skinny_req::data, skinny_req::e, skinnysession::fd, skinnysession::inbuf, letohl, skinnysession::lock, LOG_ERROR, and SKINNY_MAX_PACKET.

Referenced by skinny_session().

{
   struct skinny_req *req;
   int *bufaddr;

   if (!(req = ast_calloc(1, SKINNY_MAX_PACKET)))
      return NULL;

   ast_mutex_lock(&s->lock);
   memcpy(req, s->inbuf, skinny_header_size);
   bufaddr = (int *)(s->inbuf);
   memcpy(&req->data, s->inbuf+skinny_header_size, letohl(*bufaddr)-4);

   ast_mutex_unlock(&s->lock);

   if (letohl(req->e) < 0) {
      ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
      ast_free(req);
      return NULL;
   }

   return req;
}
static struct ast_channel * skinny_request ( const char *  type,
int  format,
void *  data,
int *  cause 
) [static, read]

Definition at line 6552 of file chan_skinny.c.

References ast_copy_string(), AST_FORMAT_AUDIO_MASK, ast_log(), AST_STATE_DOWN, ast_strlen_zero(), ast_verb, ast_channel::data, find_line_by_name(), format, LOG_NOTICE, LOG_WARNING, restart_monitor(), and skinny_new().

{
   int oldformat;
   
   struct skinny_line *l;
   struct ast_channel *tmpc = NULL;
   char tmp[256];
   char *dest = data;

   oldformat = format;
   
   if (!(format &= AST_FORMAT_AUDIO_MASK)) {
      ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
      return NULL;
   }

   ast_copy_string(tmp, dest, sizeof(tmp));
   if (ast_strlen_zero(tmp)) {
      ast_log(LOG_NOTICE, "Skinny channels require a device\n");
      return NULL;
   }
   l = find_line_by_name(tmp);
   if (!l) {
      ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
      return NULL;
   }
   ast_verb(3, "skinny_request(%s)\n", tmp);
   tmpc = skinny_new(l, AST_STATE_DOWN);
   if (!tmpc) {
      ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
   }
   restart_monitor();
   return tmpc;
}
static struct ast_frame* skinny_rtp_read ( struct skinny_subchannel sub) [static, read]

Definition at line 3913 of file chan_skinny.c.

References ast_debug, AST_FRAME_VOICE, ast_null_frame, ast_rtcp_read(), ast_rtp_read(), ast_set_read_format(), ast_set_write_format(), ast_udptl_read(), f, ast_channel::fdno, ast_frame::frametype, ast_channel::nativeformats, skinny_subchannel::owner, ast_channel::readformat, skinny_subchannel::rtp, ast_frame::subclass, skinny_subchannel::vrtp, and ast_channel::writeformat.

Referenced by skinny_read().

{
   struct ast_channel *ast = sub->owner;
   struct ast_frame *f;

   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;
   }

   if (ast) {
      /* We already hold the channel lock */
      if (f->frametype == AST_FRAME_VOICE) {
         if (f->subclass != ast->nativeformats) {
            ast_debug(1, "Oooh, format changed to %d\n", f->subclass);
            ast->nativeformats = f->subclass;
            ast_set_read_format(ast, ast->readformat);
            ast_set_write_format(ast, ast->writeformat);
         }
      }
   }
   return f;
}
static int skinny_senddigit_begin ( struct ast_channel ast,
char  digit 
) [static]

Definition at line 4010 of file chan_skinny.c.

{
   return -1; /* Start inband indications */
}
static int skinny_senddigit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
) [static]

Definition at line 4015 of file chan_skinny.c.

References skinny_subchannel::callid, skinny_line::device, skinny_subchannel::parent, ast_channel::tech_pvt, and transmit_tone().

{
#if 0
   struct skinny_subchannel *sub = ast->tech_pvt;
   struct skinny_line *l = sub->parent;
   struct skinny_device *d = l->device;
   int tmp;
   /* not right */
   sprintf(tmp, "%d", digit);
   transmit_tone(d, digit, l->instance, sub->callid);
#endif
   return -1; /* Stop inband indications */
}
static void* skinny_session ( void *  data) [static]

Definition at line 6392 of file chan_skinny.c.

References ast_debug, ast_inet_ntoa(), ast_verb, destroy_session(), errno, get_input(), handle_message(), skinny_req::res, s, skinnysession::sin, and skinny_req_parse().

Referenced by accept_thread().

{
   int res;
   struct skinny_req *req;
   struct skinnysession *s = data;

   ast_verb(3, "Starting Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));

   for (;;) {
      res = get_input(s);
      if (res < 0) {
         break;
      }

      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;
         }
      }
   }
   ast_debug(3, "Skinny Session returned: %s\n", strerror(errno));

   if (s) 
      destroy_session(s);
   
   return 0;
}
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 
) [static]

Definition at line 2615 of file chan_skinny.c.

References ast_channel::_state, ast_best_codec(), ast_codec_pref_getsize(), ast_inet_ntoa(), ast_rtp_get_peer(), ast_rtp_get_us(), AST_STATE_UP, ast_verb, media_qualifier::bitRate, ast_format_list::bits, skinny_subchannel::callid, codec_ast2skinny(), start_media_transmission_message::conferenceId, stop_media_transmission_message::conferenceId, ast_format_list::cur_ms, skinny_req::data, skinny_line::device, htolel, skinny_device::ourip, media_qualifier::packets, start_media_transmission_message::packetSize, skinny_subchannel::parent, start_media_transmission_message::passThruPartyId, stop_media_transmission_message::passThruPartyId, start_media_transmission_message::payloadType, media_qualifier::precedence, start_media_transmission_message::qualifier, start_media_transmission_message::remoteIp, start_media_transmission_message::remotePort, req_alloc(), s, skinny_device::session, START_MEDIA_TRANSMISSION_MESSAGE, skinny_data::startmedia, STOP_MEDIA_TRANSMISSION_MESSAGE, skinny_data::stopmedia, ast_channel::tech_pvt, transmit_response(), and media_qualifier::vad.

{
   struct skinny_subchannel *sub;
   struct skinny_line *l;
   struct skinny_device *d;
   struct skinnysession *s;
   struct ast_format_list fmt;
   struct sockaddr_in us;
   struct sockaddr_in them;
   struct skinny_req *req;
   
   sub = c->tech_pvt;

   if (c->_state != AST_STATE_UP)
      return 0;

   if (!sub) {
      return -1;
   }

   l = sub->parent;
   d = l->device;
   s = d->session;

   if (rtp){
      ast_rtp_get_peer(rtp, &them);

      /* Shutdown any early-media or previous media on re-invite */
      if (!(req = req_alloc(sizeof(struct stop_media_transmission_message), STOP_MEDIA_TRANSMISSION_MESSAGE)))
         return -1;

      req->data.stopmedia.conferenceId = htolel(sub->callid);
      req->data.stopmedia.passThruPartyId = htolel(sub->callid);
      transmit_response(d, req);

      if (skinnydebug)
         ast_verb(1, "Peerip = %s:%d\n", ast_inet_ntoa(them.sin_addr), ntohs(them.sin_port));

      if (!(req = req_alloc(sizeof(struct start_media_transmission_message), START_MEDIA_TRANSMISSION_MESSAGE)))
         return -1;

      fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability));

      if (skinnydebug)
         ast_verb(1, "Setting payloadType to '%d' (%d ms)\n", fmt.bits, fmt.cur_ms);

      req->data.startmedia.conferenceId = htolel(sub->callid);
      req->data.startmedia.passThruPartyId = htolel(sub->callid);
      if (!(l->directmedia) || (l->nat)){
         ast_rtp_get_us(rtp, &us);
         req->data.startmedia.remoteIp = htolel(d->ourip.s_addr);
         req->data.startmedia.remotePort = htolel(ntohs(us.sin_port));
      } else {
         req->data.startmedia.remoteIp = htolel(them.sin_addr.s_addr);
         req->data.startmedia.remotePort = htolel(ntohs(them.sin_port));
      }
      req->data.startmedia.packetSize = htolel(fmt.cur_ms);
      req->data.startmedia.payloadType = htolel(codec_ast2skinny(fmt.bits));
      req->data.startmedia.qualifier.precedence = htolel(127);
      req->data.startmedia.qualifier.vad = htolel(0);
      req->data.startmedia.qualifier.packets = htolel(0);
      req->data.startmedia.qualifier.bitRate = htolel(0);
      transmit_response(d, req);

      return 0;
   }
   /* Need a return here to break the bridge */
   return 0;
}
static void* skinny_ss ( void *  data) [static]

Definition at line 3625 of file chan_skinny.c.

References ast_channel::_state, ast_canmatch_extension(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_hangup(), ast_ignore_pattern(), ast_indicate(), ast_log(), ast_matchmore_extension(), AST_MAX_EXTENSION, ast_safe_sleep(), AST_STATE_UP, ast_strlen_zero(), ast_verb, skinny_subchannel::callid, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::data, skinny_line::device, ast_channel::exten, firstdigittimeout, gendigittimeout, len(), LOG_WARNING, matchdigittimeout, ast_channel::name, skinny_subchannel::owner, skinny_subchannel::parent, set_callforwards(), SKINNY_DIALTONE, SKINNY_LAMP_ON, skinny_newcall(), SKINNY_OFFHOOK, SKINNY_REORDER, SKINNY_SILENCE, STIMULUS_FORWARDALL, ast_channel::tech_pvt, transmit_cfwdstate(), transmit_displaynotify(), transmit_lamp_indication(), and transmit_tone().

Referenced by handle_callforward_button(), handle_offhook_message(), handle_soft_key_event_message(), handle_stimulus_message(), and handle_transfer_button().

{
   struct ast_channel *c = data;
   struct skinny_subchannel *sub = c->tech_pvt;
   struct skinny_line *l = sub->parent;
   struct skinny_device *d = l->device;
   int len = 0;
   int timeout = firstdigittimeout;
   int res = 0;
   int loop_pause = 100;

   ast_verb(3, "Starting simple switch on '%s@%s'\n", l->name, d->name);

   len = strlen(d->exten);

   while (len < AST_MAX_EXTENSION-1) {
      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;
         }
      res = 1;
      }

      timeout = 0;
      len = strlen(d->exten);

      if (!ast_ignore_pattern(c->context, d->exten)) {
         transmit_tone(d, SKINNY_SILENCE, l->instance, sub->callid);
      }
      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)) {
            if (l->getforward) {
               /* Record this as the forwarding extension */
               set_callforwards(l, d->exten, l->getforward);
               ast_verb(3, "Setting call forward (%d) to '%s' on channel %s\n",
                     l->cfwdtype, d->exten, c->name);
               transmit_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
               transmit_lamp_indication(d, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
               transmit_displaynotify(d, "CFwd enabled", 10);
               transmit_cfwdstate(d, l);
               ast_safe_sleep(c, 500);
               ast_indicate(c, -1);
               ast_safe_sleep(c, 1000);
               memset(d->exten, 0, sizeof(d->exten));
               len = 0;
               l->getforward = 0;
               if (sub->owner && sub->owner->_state != AST_STATE_UP) {
                  ast_indicate(c, -1);
                  ast_hangup(c);
               }
               return NULL;
            } else {
               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));
               skinny_newcall(c);
               return NULL;
            }
         } 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;
         }
      } else if (res == 0) {
         ast_debug(1, "Not enough digits (%s) (and no ambiguous match)...\n", d->exten);
         memset(d->exten, 0, sizeof(d->exten));
         if (l->hookstate == SKINNY_OFFHOOK) {
            transmit_tone(d, SKINNY_REORDER, l->instance, sub->callid);
         }
         if (sub->owner && sub->owner->_state != AST_STATE_UP) {
            ast_indicate(c, -1);
            ast_hangup(c);
         }
         return NULL;
      } 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);
         memset(d->exten, 0, sizeof(d->exten));
         if (l->hookstate == SKINNY_OFFHOOK) {
            transmit_tone(d, SKINNY_REORDER, l->instance, sub->callid);
            /* hang out for 3 seconds to let congestion play */
            ast_safe_sleep(c, 3000);
         }
         break;
      }
      if (!timeout) {
         timeout = gendigittimeout;
      }
      if (len && !ast_ignore_pattern(c->context, d->exten)) {
         ast_indicate(c, -1);
      }
   }
   if (c)
      ast_hangup(c);
   memset(d->exten, 0, sizeof(d->exten));
   return NULL;
}
static int skinny_transfer ( struct skinny_subchannel sub) [static]

Definition at line 4108 of file chan_skinny.c.

References ast_channel::_state, ast_bridged_channel(), ast_channel_masquerade(), AST_CONTROL_UNHOLD, ast_debug, ast_get_indication_tone(), ast_log(), ast_playtones_start(), ast_queue_control(), AST_STATE_RING, ast_tone_zone_sound_unref(), ast_tone_zone_sound::data, LOG_DEBUG, LOG_WARNING, ast_channel::name, option_debug, skinny_subchannel::owner, skinny_subchannel::related, skinny_subchannel::xferor, and ast_channel::zone.

Referenced by handle_transfer_button(), skinny_answer(), and skinny_indicate().

{
   struct skinny_subchannel *xferor; /* the sub doing the transferring */
   struct skinny_subchannel *xferee; /* the sub being transferred */
   struct ast_tone_zone_sound *ts = NULL;
      
   if (ast_bridged_channel(sub->owner) || ast_bridged_channel(sub->related->owner)) {
      if (sub->xferor) {
         xferor = sub;
         xferee = sub->related;
      } else {
         xferor = sub;
         xferee = sub->related;
      }
      
      if (skinnydebug) {
         ast_debug(1, "Transferee channels (local/remote): %s and %s\n",
            xferee->owner->name, ast_bridged_channel(xferee->owner)?ast_bridged_channel(xferee->owner)->name:"");
         ast_debug(1, "Transferor channels (local/remote): %s and %s\n",
            xferor->owner->name, ast_bridged_channel(xferor->owner)?ast_bridged_channel(xferor->owner)->name:"");
      }
      if (ast_bridged_channel(xferor->owner)) {
         if (ast_bridged_channel(xferee->owner)) {
            ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
         }
         if (xferor->owner->_state == AST_STATE_RING) {
            /* play ringing inband */
            if ((ts = ast_get_indication_tone(xferor->owner->zone, "ring"))) {
               ast_playtones_start(xferor->owner, 0, ts->data, 1);
               ts = ast_tone_zone_sound_unref(ts);
            }
         }
         if (skinnydebug)
            ast_debug(1, "Transfer Masquerading %s to %s\n",
               xferee->owner->name, ast_bridged_channel(xferor->owner)?ast_bridged_channel(xferor->owner)->name:"");
         if (ast_channel_masquerade(xferee->owner, ast_bridged_channel(xferor->owner))) {
            ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
               ast_bridged_channel(xferor->owner)->name, xferee->owner->name);
            return -1;
         }
      } else if (ast_bridged_channel(xferee->owner)) {
         ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
         if (xferor->owner->_state == AST_STATE_RING) {
            /* play ringing inband */
            if ((ts = ast_get_indication_tone(xferor->owner->zone, "ring"))) {
               ast_playtones_start(xferor->owner, 0, ts->data, 1);
               ts = ast_tone_zone_sound_unref(ts);
            }
         }
         if (skinnydebug)
            ast_debug(1, "Transfer Masquerading %s to %s\n",
               xferor->owner->name, ast_bridged_channel(xferee->owner)?ast_bridged_channel(xferee->owner)->name:"");
         if (ast_channel_masquerade(xferor->owner, ast_bridged_channel(xferee->owner))) {
            ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
               ast_bridged_channel(xferee->owner)->name, xferor->owner->name);
            return -1;
         }
         return 0;
      } else {
         if (option_debug)
            ast_log(LOG_DEBUG, "Neither %s nor %s are in a bridge, nothing to transfer\n",
               xferor->owner->name, xferee->owner->name);
      }
   }
   return 0;
}
static int skinny_unhold ( struct skinny_subchannel sub) [static]

Definition at line 4413 of file chan_skinny.c.

References AST_CONTROL_UNHOLD, ast_queue_control(), ast_verb, skinny_line::device, skinny_subchannel::onhold, skinny_subchannel::owner, skinny_subchannel::parent, SKINNY_CONNECTED, SKINNY_LAMP_ON, SKINNY_OFFHOOK, STIMULUS_LINE, transmit_activatecallplane(), transmit_callstateonly(), transmit_connect(), and transmit_lamp_indication().

Referenced by handle_hold_button(), and handle_soft_key_event_message().

{
   struct skinny_line *l = sub->parent;
   struct skinny_device *d = l->device;

   /* Don't try to unhold a channel that doesn't exist */
   if (!sub || !sub->owner)
      return 0;

   /* Channel is on hold, so we will unhold */
   if (skinnydebug)
      ast_verb(1, "Taking off Hold(%d)\n", l->instance);

   ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);

   transmit_activatecallplane(d, l);

   transmit_connect(d, sub);
   transmit_callstateonly(d, sub, SKINNY_CONNECTED);
   transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
   l->hookstate = SKINNY_OFFHOOK;
   sub->onhold = 0;
   return 1;
}
static int skinny_unregister ( struct skinny_req req,
struct skinnysession s 
) [static]

Definition at line 1887 of file chan_skinny.c.

References AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_extension_state_del(), AST_LIST_TRAVERSE, ast_parse_allow_disallow(), skinny_line::device, skinnysession::device, skinny_device::lines, skinny_device::session, skinny_device::speeddials, skinny_speeddial::stateid, and unregister_exten().

Referenced by get_input(), handle_unregister_message(), and transmit_response().

{
   struct skinny_device *d;
   struct skinny_line *l;
   struct skinny_speeddial *sd;

   d = s->device;

   if (d) {
      d->session = NULL;
      d->registered = 0;

      AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
         if (sd->stateid > -1)
            ast_extension_state_del(sd->stateid, NULL);
      }
      AST_LIST_TRAVERSE(&d->lines, l, list) {
         if (l->device == d) {
            l->device = NULL;
            l->capability = 0;
            ast_parse_allow_disallow(&l->prefs, &l->capability, "all", 0);       
            l->instance = 0;
            unregister_exten(l);
            ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Skinny/%s@%s", l->name, d->name);
         }
      }
   }

   return -1; /* main loop will destroy the session */
}
static int skinny_write ( struct ast_channel ast,
struct ast_frame frame 
) [static]

Definition at line 3970 of file chan_skinny.c.

References AST_FRAME_IMAGE, AST_FRAME_VOICE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtp_write(), ast_frame::frametype, skinny_subchannel::lock, LOG_WARNING, ast_channel::nativeformats, ast_channel::readformat, skinny_subchannel::rtp, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.

{
   struct skinny_subchannel *sub = ast->tech_pvt;
   int res = 0;
   if (frame->frametype != AST_FRAME_VOICE) {
      if (frame->frametype == AST_FRAME_IMAGE) {
         return 0;
      } else {
         ast_log(LOG_WARNING, "Can't send %d type frames with skinny_write\n", frame->frametype);
         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) {
         res = ast_rtp_write(sub->rtp, frame);
      }
      ast_mutex_unlock(&sub->lock);
   }
   return res;
}
static void start_rtp ( struct skinny_subchannel sub) [static]

Definition at line 3563 of file chan_skinny.c.

References ast_channel_set_fd(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtcp_fd(), ast_rtp_codec_setpref(), ast_rtp_fd(), ast_rtp_new_with_bindaddr(), ast_rtp_setnat(), ast_rtp_setqos(), bindaddr, skinny_line::device, skinny_subchannel::lock, skinny_subchannel::owner, skinny_subchannel::parent, qos, skinny_subchannel::rtp, transmit_connect(), and skinny_subchannel::vrtp.

Referenced by handle_offhook_message(), handle_soft_key_event_message(), handle_stimulus_message(), skinny_answer(), and skinny_newcall().

{
   struct skinny_line *l = sub->parent;
   struct skinny_device *d = l->device;
   int hasvideo = 0;

   ast_mutex_lock(&sub->lock);
   /* Allocate the RTP */
   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);
   
   if (sub->rtp && sub->owner) {
      ast_channel_set_fd(sub->owner, 0, ast_rtp_fd(sub->rtp));
      ast_channel_set_fd(sub->owner, 1, ast_rtcp_fd(sub->rtp));
   }
   if (hasvideo && sub->vrtp && sub->owner) {
      ast_channel_set_fd(sub->owner, 2, ast_rtp_fd(sub->vrtp));
      ast_channel_set_fd(sub->owner, 3, ast_rtcp_fd(sub->vrtp));
   }
   if (sub->rtp) {
      ast_rtp_setqos(sub->rtp, qos.tos_audio, qos.cos_audio, "Skinny RTP");
      ast_rtp_setnat(sub->rtp, l->nat);
   }
   if (sub->vrtp) {
      ast_rtp_setqos(sub->vrtp, qos.tos_video, qos.cos_video, "Skinny VRTP");
      ast_rtp_setnat(sub->vrtp, l->nat);
   }
   /* Set Frame packetization */
   if (sub->rtp)
      ast_rtp_codec_setpref(sub->rtp, &l->prefs);

   /* Create the RTP connection */
   transmit_connect(d, sub);
   ast_mutex_unlock(&sub->lock);
}
static void transmit_activatecallplane ( struct skinny_device d,
struct skinny_line l 
) [static]
static void transmit_callinfo ( struct skinny_device d,
const char *  fromname,
const char *  fromnum,
const char *  toname,
const char *  tonum,
int  instance,
int  callid,
int  calltype 
) [static]

Definition at line 2113 of file chan_skinny.c.

References ast_copy_string(), ast_verb, CALL_INFO_MESSAGE, call_info_message::calledParty, call_info_message::calledPartyName, skinny_data::callinfo, call_info_message::callingParty, call_info_message::callingPartyName, skinny_req::data, htolel, call_info_message::instance, call_info_message::reference, req_alloc(), transmit_response(), and call_info_message::type.

Referenced by skinny_answer(), skinny_call(), and skinny_indicate().

{
   struct skinny_req *req;

   /* We should not be able to get here without a device */
   if (!d)
      return;

   if (!(req = req_alloc(sizeof(struct call_info_message), CALL_INFO_MESSAGE)))
      return;

   if (skinnydebug)
         ast_verb(1, "Setting Callinfo to %s(%s) from %s(%s) on %s(%d)\n", fromname, fromnum, toname, tonum, d->name, instance);

   if (fromname) {
      ast_copy_string(req->data.callinfo.callingPartyName, fromname, sizeof(req->data.callinfo.callingPartyName));
   }
   if (fromnum) {
      ast_copy_string(req->data.callinfo.callingParty, fromnum, sizeof(req->data.callinfo.callingParty));
   }
   if (toname) {
      ast_copy_string(req->data.callinfo.calledPartyName, toname, sizeof(req->data.callinfo.calledPartyName));
   }
   if (tonum) {
      ast_copy_string(req->data.callinfo.calledParty, tonum, sizeof(req->data.callinfo.calledParty));
   }
   req->data.callinfo.instance = htolel(instance);
   req->data.callinfo.reference = htolel(callid);
   req->data.callinfo.type = htolel(calltype);
   transmit_response(d, req);
}
static void transmit_callstate ( struct skinny_device d,
int  instance,
int  state,
unsigned  callid 
) [static]

Definition at line 2384 of file chan_skinny.c.

References ACTIVATE_CALL_PLANE_MESSAGE, skinny_data::activatecallplane, CALL_STATE_MESSAGE, call_state_message::callReference, call_state_message::callState, skinny_data::callstate, CLOSE_RECEIVE_CHANNEL_MESSAGE, skinny_data::closereceivechannel, stop_media_transmission_message::conferenceId, close_receive_channel_message::conferenceId, skinny_req::data, htolel, KEYDEF_ONHOOK, activate_call_plane_message::lineInstance, call_state_message::lineInstance, close_receive_channel_message::partyId, stop_media_transmission_message::passThruPartyId, req_alloc(), SKINNY_OFFHOOK, SKINNY_ONHOOK, SKINNY_SPEAKEROFF, STOP_MEDIA_TRANSMISSION_MESSAGE, skinny_data::stopmedia, transmit_displaypromptstatus(), transmit_response(), transmit_selectsoftkeys(), and transmit_speaker_mode().

Referenced by handle_callforward_button(), handle_enbloc_call_message(), handle_offhook_message(), handle_onhook_message(), handle_soft_key_event_message(), handle_stimulus_message(), handle_transfer_button(), skinny_extensionstate_cb(), and skinny_hangup().

static void transmit_cfwdstate ( struct skinny_device d,
struct skinny_line l 
) [static]

Definition at line 2430 of file chan_skinny.c.

References forward_stat_message::activeforward, ast_copy_string(), ast_strlen_zero(), skinny_req::data, FORWARD_STAT_MESSAGE, skinny_data::forwardstat, forward_stat_message::fwdall, forward_stat_message::fwdallnum, forward_stat_message::fwdbusy, forward_stat_message::fwdbusynum, forward_stat_message::fwdnoanswer, forward_stat_message::fwdnoanswernum, htolel, forward_stat_message::lineNumber, req_alloc(), SKINNY_CFWD_ALL, SKINNY_CFWD_BUSY, SKINNY_CFWD_NOANSWER, and transmit_response().

Referenced by handle_callforward_button(), and skinny_ss().

{
   struct skinny_req *req;
   int anyon = 0;

   if (!(req = req_alloc(sizeof(struct forward_stat_message), FORWARD_STAT_MESSAGE)))
      return;

   if (l->cfwdtype & SKINNY_CFWD_ALL) {
      if (!ast_strlen_zero(l->call_forward_all)) {
         ast_copy_string(req->data.forwardstat.fwdallnum, l->call_forward_all, sizeof(req->data.forwardstat.fwdallnum));
         req->data.forwardstat.fwdall = htolel(1);
         anyon++;
      } else {
         req->data.forwardstat.fwdall = htolel(0);
      }
   }
   if (l->cfwdtype & SKINNY_CFWD_BUSY) {
      if (!ast_strlen_zero(l->call_forward_busy)) {
         ast_copy_string(req->data.forwardstat.fwdbusynum, l->call_forward_busy, sizeof(req->data.forwardstat.fwdbusynum));
         req->data.forwardstat.fwdbusy = htolel(1);
         anyon++;
      } else {
         req->data.forwardstat.fwdbusy = htolel(0);
      }
   }
   if (l->cfwdtype & SKINNY_CFWD_NOANSWER) {
      if (!ast_strlen_zero(l->call_forward_noanswer)) {
         ast_copy_string(req->data.forwardstat.fwdnoanswernum, l->call_forward_noanswer, sizeof(req->data.forwardstat.fwdnoanswernum));
         req->data.forwardstat.fwdnoanswer = htolel(1);
         anyon++;
      } else {
         req->data.forwardstat.fwdnoanswer = htolel(0);
      }
   }
   req->data.forwardstat.lineNumber = htolel(l->instance);
   if (anyon)
      req->data.forwardstat.activeforward = htolel(7);
   else
      req->data.forwardstat.activeforward = htolel(0);

   transmit_response(d, req);
}
static void transmit_dialednumber ( struct skinny_device d,
const char *  text,
int  instance,
int  callid 
) [static]
static void transmit_displaymessage ( struct skinny_device d,
const char *  text,
int  instance,
int  reference 
) [static]

Definition at line 2247 of file chan_skinny.c.

References ast_copy_string(), ast_verb, CLEAR_DISPLAY_MESSAGE, skinny_req::data, skinny_data::displaytext, DISPLAYTEXT_MESSAGE, handle_time_date_req_message(), req_alloc(), skinny_device::session, displaytext_message::text, and transmit_response().

Referenced by handle_callforward_button(), handle_enbloc_call_message(), handle_offhook_message(), handle_soft_key_event_message(), handle_stimulus_message(), handle_transfer_button(), and skinny_hangup().

{
   struct skinny_req *req;

   if (text == 0) {
      if (!(req = req_alloc(0, CLEAR_DISPLAY_MESSAGE)))
         return;

      //what do we want hear CLEAR_DISPLAY_MESSAGE or CLEAR_PROMPT_STATUS???
      //if we are clearing the display, it appears there is no instance and refernece info (size 0)
      //req->data.clearpromptstatus.lineInstance = instance;
      //req->data.clearpromptstatus.callReference = reference;

      /* send datetime message. We have to do it here because it will clear the display on the phone if we do it elsewhere */
      handle_time_date_req_message(NULL, d->session);

      if (skinnydebug)
         ast_verb(1, "Clearing Display\n");
   } else {
      if (!(req = req_alloc(sizeof(struct displaytext_message), DISPLAYTEXT_MESSAGE)))
         return;

      ast_copy_string(req->data.displaytext.text, text, sizeof(req->data.displaytext.text));
      if (skinnydebug)
         ast_verb(1, "Displaying message '%s'\n", req->data.displaytext.text);
   }

   transmit_response(d, req);
}
static void transmit_displaypromptstatus ( struct skinny_device d,
const char *  text,
int  t,
int  instance,
int  callid 
) [static]
static int transmit_response ( struct skinny_device d,
struct skinny_req req 
) [static]

Definition at line 2049 of file chan_skinny.c.

References ast_free, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_verb, skinny_req::data, skinny_req::e, errno, skinnysession::fd, skinny_req::len, letohl, skinnysession::lock, LOG_WARNING, skinnysession::outbuf, s, skinny_device::session, SKINNY_DEVONLY, SKINNY_MAX_PACKET, and skinny_unregister().

Referenced by handle_button_template_req_message(), handle_keep_alive_message(), handle_line_state_req_message(), handle_open_receive_channel_ack_message(), handle_register_message(), handle_server_request_message(), handle_skinny_reset(), handle_soft_key_set_req_message(), handle_soft_key_template_req_message(), handle_speed_dial_stat_req_message(), handle_time_date_req_message(), handle_version_req_message(), skinny_reload(), skinny_set_rtp_peer(), transmit_activatecallplane(), transmit_callinfo(), transmit_callstate(), transmit_callstateonly(), transmit_cfwdstate(), transmit_closereceivechannel(), transmit_connect(), transmit_dialednumber(), transmit_displaymessage(), transmit_displaynotify(), transmit_displaypromptstatus(), transmit_lamp_indication(), transmit_ringer_mode(), transmit_selectsoftkeys(), transmit_speaker_mode(), transmit_stopmediatransmission(), and transmit_tone().

{
   struct skinnysession *s = d->session;
   int res = 0;

   if (!s) {
      ast_log(LOG_WARNING, "Asked to transmit to a non-existent session!\n");
      return -1;
   }

   ast_mutex_lock(&s->lock);

   SKINNY_DEVONLY(if (skinnydebug>1) ast_verb(4, "Transmitting %s to %s\n", message2str(req->e), d->name);)

   if (letohl(req->len > SKINNY_MAX_PACKET) || letohl(req->len < 0)) {
      ast_log(LOG_WARNING, "transmit_response: the length of the request is out of bounds\n");
      ast_mutex_unlock(&s->lock);
      return -1;
   }

   memset(s->outbuf, 0, sizeof(s->outbuf));
   memcpy(s->outbuf, req, skinny_header_size);
   memcpy(s->outbuf+skinny_header_size, &req->data, letohl(req->len));

   res = write(s->fd, s->outbuf, letohl(req->len)+8);
   
   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));
      if (res == -1) {
         if (skinnydebug)
            ast_log(LOG_WARNING, "Transmit: Skinny Client was lost, unregistering\n");
         skinny_unregister(NULL, s);
      }
      
   }
   
   ast_free(req);
   ast_mutex_unlock(&s->lock);
   return 1;
}
static void transmit_ringer_mode ( struct skinny_device d,
int  mode 
) [static]

Definition at line 2222 of file chan_skinny.c.

References ast_verb, skinny_req::data, htolel, req_alloc(), set_ringer_message::ringerMode, SET_RINGER_MESSAGE, skinny_data::setringer, transmit_response(), set_ringer_message::unknown1, and set_ringer_message::unknown2.

Referenced by handle_offhook_message(), handle_soft_key_event_message(), handle_stimulus_message(), skinny_call(), and skinny_hangup().

{
   struct skinny_req *req;

   if (skinnydebug)
      ast_verb(1, "Setting ringer mode to '%d'.\n", mode);

   if (!(req = req_alloc(sizeof(struct set_ringer_message), SET_RINGER_MESSAGE)))
      return;

   req->data.setringer.ringerMode = htolel(mode);
   /* 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);
   transmit_response(d, req);
}
static void transmit_speaker_mode ( struct skinny_device d,
int  mode 
) [static]
static void transmit_tone ( struct skinny_device d,
int  tone,
int  instance,
int  reference 
) [static]

Definition at line 2165 of file chan_skinny.c.

References skinny_req::data, htolel, stop_tone_message::instance, start_tone_message::instance, stop_tone_message::reference, start_tone_message::reference, req_alloc(), SKINNY_NOTONE, START_TONE_MESSAGE, skinny_data::starttone, STOP_TONE_MESSAGE, skinny_data::stoptone, start_tone_message::tone, and transmit_response().

Referenced by handle_callforward_button(), handle_enbloc_call_message(), handle_offhook_message(), handle_soft_key_event_message(), handle_stimulus_message(), handle_transfer_button(), skinny_answer(), skinny_hangup(), skinny_indicate(), skinny_newcall(), skinny_senddigit_end(), and skinny_ss().

{
   struct skinny_req *req;

   if (tone == SKINNY_NOTONE) {
      /* This is bad, mmm'kay? */
      return;
   }

   if (tone > 0) {
      if (!(req = req_alloc(sizeof(struct start_tone_message), START_TONE_MESSAGE)))
         return;
      req->data.starttone.tone = htolel(tone);
      req->data.starttone.instance = htolel(instance);
      req->data.starttone.reference = htolel(reference);
   } else {
      if (!(req = req_alloc(sizeof(struct stop_tone_message), STOP_TONE_MESSAGE)))
         return;
      req->data.stoptone.instance = htolel(instance);
      req->data.stoptone.reference = htolel(reference);
   }

   //Bad, tone is already set so this is redundant and a change to the if above
   //may lead to issues where we try to set a tone to a stop_tone_message
   //if (tone > 0) {
   // req->data.starttone.tone = htolel(tone);
   //}
   transmit_response(d, req);
}
static int unload_module ( void  ) [static]

Definition at line 7408 of file chan_skinny.c.

References skinny_subchannel::alreadygone, ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_context_destroy(), ast_context_find(), ast_event_unsubscribe(), AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_manager_unregister(), ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_rtp_proto_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, cli_skinny, delete_devices(), skinnysession::device, skinnysession::fd, free, skinny_device::lines, skinny_subchannel::lock, skinny_line::lock, monlock, skinny_line::mwi_event_sub, netlock, skinny_subchannel::owner, s, sched_context_destroy(), skinny_rtp, skinny_tech, skinny_line::sub, skinnysession::t, and unregister_exten().

{
   struct skinnysession *s;
   struct skinny_device *d;
   struct skinny_line *l;
   struct skinny_subchannel *sub;
   struct ast_context *con;

   ast_rtp_proto_unregister(&skinny_rtp);
   ast_channel_unregister(&skinny_tech);
   ast_cli_unregister_multiple(cli_skinny, ARRAY_LEN(cli_skinny));

   ast_manager_unregister("SKINNYdevices");
   ast_manager_unregister("SKINNYshowdevice");
   ast_manager_unregister("SKINNYlines");
   ast_manager_unregister("SKINNYshowline");
   
   AST_LIST_LOCK(&sessions);
   /* Destroy all the interfaces and free their memory */
   while((s = AST_LIST_REMOVE_HEAD(&sessions, list))) {
      d = s->device;
      AST_LIST_TRAVERSE(&d->lines, l, list){
         ast_mutex_lock(&l->lock);
         AST_LIST_TRAVERSE(&l->sub, sub, list) {
            ast_mutex_lock(&sub->lock);
            if (sub->owner) {
               sub->alreadygone = 1;
               ast_softhangup(sub->owner, AST_SOFTHANGUP_APPUNLOAD);
            }
            ast_mutex_unlock(&sub->lock);
         }
         if (l->mwi_event_sub)
            ast_event_unsubscribe(l->mwi_event_sub);
         ast_mutex_unlock(&l->lock);
         unregister_exten(l);
      }
      if (s->fd > -1)
         close(s->fd);
      pthread_cancel(s->t);
      pthread_kill(s->t, SIGURG);
      pthread_join(s->t, NULL);
      free(s);
   }
   AST_LIST_UNLOCK(&sessions);

   delete_devices();

   ast_mutex_lock(&monlock);
   if ((monitor_thread != AST_PTHREADT_NULL) && (monitor_thread != AST_PTHREADT_STOP)) {
      pthread_cancel(monitor_thread);
      pthread_kill(monitor_thread, SIGURG);
      pthread_join(monitor_thread, NULL);
   }
   monitor_thread = AST_PTHREADT_STOP;
   ast_mutex_unlock(&monlock);

   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);

   close(skinnysock);
   if (sched)
      sched_context_destroy(sched);

   con = ast_context_find(used_context);
   if (con)
      ast_context_destroy(con, "Skinny");
   
   return 0;
}
static void unregister_exten ( struct skinny_line l) [static]

Definition at line 1795 of file chan_skinny.c.

References ast_context_find(), ast_context_remove_extension(), ast_copy_string(), ast_log(), ast_strlen_zero(), context, ext, LOG_WARNING, regcontext, S_OR, and strsep().

Referenced by skinny_unregister(), and unload_module().

{
   char multi[256];
   char *stringp, *ext, *context;

   if (ast_strlen_zero(regcontext))
      return;

   ast_copy_string(multi, S_OR(l->regexten, l->name), sizeof(multi));
   stringp = multi;
   while ((ext = strsep(&stringp, "&"))) {
      if ((context = strchr(ext, '@'))) {
         *context++ = '\0'; /* split ext@context */
         if (!ast_context_find(context)) {
            ast_log(LOG_WARNING, "Context %s must exist in regcontext= in skinny.conf!\n", context);
            continue;
         }
      } else {
         context = regcontext;
      }
      ast_context_remove_extension(context, ext, 1, NULL);
   }
}

Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Skinny Client Control Protocol (Skinny)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 7494 of file chan_skinny.c.

struct in_addr __ourip [static]

Definition at line 985 of file chan_skinny.c.

Referenced by config_load(), and skinny_register().

pthread_t accept_t [static]

Definition at line 989 of file chan_skinny.c.

struct ast_hostent ahp

Definition at line 986 of file chan_skinny.c.

Referenced by __init_manager(), config_load(), config_parse_variables(), and rpt_exec().

Definition at line 7494 of file chan_skinny.c.

int auth_limit = DEFAULT_AUTH_LIMIT [static]

Definition at line 117 of file chan_skinny.c.

int auth_timeout = DEFAULT_AUTH_TIMEOUT [static]

Definition at line 116 of file chan_skinny.c.

struct sockaddr_in bindaddr [static]
int callnums = 1 [static]

Definition at line 990 of file chan_skinny.c.

struct ast_cli_entry cli_skinny[] [static]

Definition at line 3552 of file chan_skinny.c.

Referenced by load_module(), and unload_module().

const char config[] = "skinny.conf" [static]

Definition at line 85 of file chan_skinny.c.

unsigned int cos

Definition at line 110 of file chan_skinny.c.

unsigned int cos_audio

Definition at line 111 of file chan_skinny.c.

unsigned int cos_video

Definition at line 112 of file chan_skinny.c.

char date_format[6] = "D-M-Y" [static]

Definition at line 122 of file chan_skinny.c.

int default_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW [static]

Definition at line 87 of file chan_skinny.c.

Referenced by config_load(), and skinny_new().

struct ast_jb_conf default_jbconf [static]

Global jitterbuffer configuration - by default, jb is disabled

Definition at line 166 of file chan_skinny.c.

Definition at line 1226 of file chan_skinny.c.

Referenced by config_line(), and config_load().

struct ast_codec_pref default_prefs [static]

Definition at line 88 of file chan_skinny.c.

Referenced by config_load(), and config_parse_variables().

struct devices devices [static]
int firstdigittimeout = 16000 [static]

Definition at line 1109 of file chan_skinny.c.

Referenced by skinny_ss().

int gendigittimeout = 8000 [static]

Definition at line 1112 of file chan_skinny.c.

Referenced by skinny_ss().

char global_vmexten[AST_MAX_EXTENSION] [static]

Definition at line 119 of file chan_skinny.c.

struct io_context* io [static]

Definition at line 1096 of file chan_skinny.c.

int keep_alive = 120 [static]

Definition at line 115 of file chan_skinny.c.

struct lines lines [static]
char mandescr_show_device[] = " ActionID: <id> Optional action ID for this AMI transaction.\n" [static]

Definition at line 3165 of file chan_skinny.c.

Referenced by load_module().

char mandescr_show_devices[] = " ActionID: <id> Action ID for this transaction. Will be returned.\n" [static]

Definition at line 3020 of file chan_skinny.c.

Referenced by load_module().

char mandescr_show_line[] = " ActionID: <id> Optional action ID for this AMI transaction.\n" [static]

Definition at line 3475 of file chan_skinny.c.

Referenced by load_module().

char mandescr_show_lines[] = " ActionID: <id> Action ID for this transaction. Will be returned.\n" [static]

Definition at line 3281 of file chan_skinny.c.

Referenced by load_module().

int matchdigittimeout = 3000 [static]

Definition at line 1115 of file chan_skinny.c.

Referenced by skinny_ss().

pthread_t monitor_thread = AST_PTHREADT_NULL [static]

Definition at line 1106 of file chan_skinny.c.

ast_mutex_t monlock = AST_MUTEX_INIT_VALUE [static]

Definition at line 1100 of file chan_skinny.c.

Referenced by do_monitor(), restart_monitor(), and unload_module().

ast_mutex_t netlock = AST_MUTEX_INIT_VALUE [static]

Definition at line 1102 of file chan_skinny.c.

Referenced by config_load(), and unload_module().

char ourhost[256] [static]

Definition at line 983 of file chan_skinny.c.

int ourport [static]

Definition at line 984 of file chan_skinny.c.

struct { ... } qos [static]
char regcontext[AST_MAX_CONTEXT] [static]

Definition at line 121 of file chan_skinny.c.

Referenced by register_exten(), and unregister_exten().

struct sched_context* sched = NULL [static]

Definition at line 1095 of file chan_skinny.c.

struct sessions sessions [static]

Definition at line 972 of file chan_skinny.c.

struct ast_rtp_protocol skinny_rtp [static]

Definition at line 2685 of file chan_skinny.c.

Referenced by load_module(), and unload_module().

struct ast_channel_tech skinny_tech [static]

Definition at line 1341 of file chan_skinny.c.

Referenced by load_module(), skinny_new(), and unload_module().

int skinnydebug = 0 [static]

Definition at line 978 of file chan_skinny.c.

int skinnyreload = 0 [static]

Definition at line 979 of file chan_skinny.c.

int skinnysock = -1 [static]

Definition at line 988 of file chan_skinny.c.

const uint8_t soft_key_default_connected[] [static]

Definition at line 767 of file chan_skinny.c.

const uint8_t soft_key_default_connwithconf[] [static]
Initial value:

Definition at line 811 of file chan_skinny.c.

const uint8_t soft_key_default_connwithtrans[] [static]

Definition at line 797 of file chan_skinny.c.

const uint8_t soft_key_default_dadfd[] [static]
Initial value:

Definition at line 806 of file chan_skinny.c.

Definition at line 830 of file chan_skinny.c.

Referenced by handle_soft_key_set_req_message().

const uint8_t soft_key_default_offhook[] [static]

Definition at line 789 of file chan_skinny.c.

const uint8_t soft_key_default_offhookwithfeat[] [static]
Initial value:

Definition at line 820 of file chan_skinny.c.

const uint8_t soft_key_default_onhold[] [static]

Definition at line 776 of file chan_skinny.c.

const uint8_t soft_key_default_onhook[] [static]

Definition at line 757 of file chan_skinny.c.

const uint8_t soft_key_default_ringin[] [static]
Initial value:

Definition at line 783 of file chan_skinny.c.

const uint8_t soft_key_default_ringout[] [static]
Initial value:

Definition at line 815 of file chan_skinny.c.

const uint8_t soft_key_default_unknown[] [static]
Initial value:

Definition at line 826 of file chan_skinny.c.

const char tdesc[] = "Skinny Client Control Protocol (Skinny)" [static]

Definition at line 84 of file chan_skinny.c.

unsigned int tos

Definition at line 107 of file chan_skinny.c.

unsigned int tos_audio

Definition at line 108 of file chan_skinny.c.

unsigned int tos_video

Definition at line 109 of file chan_skinny.c.

int unauth_sessions = 0 [static]

Definition at line 118 of file chan_skinny.c.

char used_context[AST_MAX_EXTENSION] [static]

Definition at line 120 of file chan_skinny.c.

char version_id[16] = "P002F202" [static]

Definition at line 123 of file chan_skinny.c.