2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * chan_skinny was developed by Jeremy McNamara & Florian Overkamp
7 * chan_skinny was heavily modified/fixed by North Antara
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
22 * \brief Implementation of the Skinny protocol
24 * \author Jeremy McNamara & Florian Overkamp & North Antara
25 * \ingroup channel_drivers
31 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <netinet/tcp.h>
40 #include <sys/ioctl.h>
45 #include <arpa/inet.h>
46 #include <sys/signal.h>
50 #include "asterisk/lock.h"
51 #include "asterisk/channel.h"
52 #include "asterisk/config.h"
53 #include "asterisk/logger.h"
54 #include "asterisk/module.h"
55 #include "asterisk/pbx.h"
56 #include "asterisk/options.h"
57 #include "asterisk/lock.h"
58 #include "asterisk/sched.h"
59 #include "asterisk/io.h"
60 #include "asterisk/rtp.h"
61 #include "asterisk/acl.h"
62 #include "asterisk/callerid.h"
63 #include "asterisk/cli.h"
64 #include "asterisk/say.h"
65 #include "asterisk/cdr.h"
66 #include "asterisk/astdb.h"
67 #include "asterisk/features.h"
68 #include "asterisk/app.h"
69 #include "asterisk/musiconhold.h"
70 #include "asterisk/utils.h"
71 #include "asterisk/dsp.h"
72 #include "asterisk/stringfields.h"
73 #include "asterisk/astobj.h"
74 #include "asterisk/abstract_jb.h"
75 #include "asterisk/threadstorage.h"
77 /*************************************
78 * Skinny/Asterisk Protocol Settings *
79 *************************************/
80 static const char tdesc
[] = "Skinny Client Control Protocol (Skinny)";
81 static const char config
[] = "skinny.conf";
83 static int default_capability
= AST_FORMAT_ULAW
| AST_FORMAT_ALAW
;
84 static struct ast_codec_pref default_prefs
;
87 SKINNY_CODEC_ALAW
= 2,
88 SKINNY_CODEC_ULAW
= 4,
89 SKINNY_CODEC_G723_1
= 9,
90 SKINNY_CODEC_G729A
= 12,
91 SKINNY_CODEC_G726_32
= 82, /* XXX Which packing order does this translate to? */
92 SKINNY_CODEC_H261
= 100,
93 SKINNY_CODEC_H263
= 101
96 #define DEFAULT_SKINNY_PORT 2000
97 #define DEFAULT_SKINNY_BACKLOG 2
98 #define SKINNY_MAX_PACKET 1000
100 static int keep_alive
= 120;
101 static char date_format
[6] = "D-M-Y";
102 static char version_id
[16] = "P002F202";
104 #if __BYTE_ORDER == __LITTLE_ENDIAN
105 #define letohl(x) (x)
106 #define letohs(x) (x)
107 #define htolel(x) (x)
108 #define htoles(x) (x)
110 #if defined(SOLARIS) || defined(__Darwin__) || defined(__NetBSD__)
111 #define __bswap_16(x) \
112 ((((x) & 0xff00) >> 8) | \
113 (((x) & 0x00ff) << 8))
114 #define __bswap_32(x) \
115 ((((x) & 0xff000000) >> 24) | \
116 (((x) & 0x00ff0000) >> 8) | \
117 (((x) & 0x0000ff00) << 8) | \
118 (((x) & 0x000000ff) << 24))
120 #include <bits/byteswap.h>
122 #define letohl(x) __bswap_32(x)
123 #define letohs(x) __bswap_16(x)
124 #define htolel(x) __bswap_32(x)
125 #define htoles(x) __bswap_16(x)
128 /*! Global jitterbuffer configuration - by default, jb is disabled */
129 static struct ast_jb_conf default_jbconf
=
133 .resync_threshold
= -1,
136 static struct ast_jb_conf global_jbconf
;
138 AST_THREADSTORAGE(device2str_threadbuf
, device2str_threadbuf_init
);
139 #define DEVICE2STR_BUFSIZE 15
141 AST_THREADSTORAGE(control2str_threadbuf
, control2str_threadbuf_init
);
142 #define CONTROL2STR_BUFSIZE 100
144 /*********************
145 * Protocol Messages *
146 *********************/
148 #define KEEP_ALIVE_MESSAGE 0x0000
149 /* no additional struct */
151 #define REGISTER_MESSAGE 0x0001
152 struct register_message
{
161 #define IP_PORT_MESSAGE 0x0002
163 #define KEYPAD_BUTTON_MESSAGE 0x0003
164 struct keypad_button_message
{
166 uint32_t lineInstance
;
167 uint32_t callReference
;
170 #define STIMULUS_MESSAGE 0x0005
171 struct stimulus_message
{
173 uint32_t stimulusInstance
;
177 #define OFFHOOK_MESSAGE 0x0006
178 struct offhook_message
{
183 #define ONHOOK_MESSAGE 0x0007
184 struct onhook_message
{
189 #define CAPABILITIES_RES_MESSAGE 0x0010
190 struct station_capabilities
{
199 struct capabilities_res_message
{
201 struct station_capabilities caps
[18];
204 #define SPEED_DIAL_STAT_REQ_MESSAGE 0x000A
205 struct speed_dial_stat_req_message
{
206 uint32_t speedDialNumber
;
209 #define LINE_STATE_REQ_MESSAGE 0x000B
210 struct line_state_req_message
{
214 #define TIME_DATE_REQ_MESSAGE 0x000D
215 #define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
216 #define VERSION_REQ_MESSAGE 0x000F
217 #define SERVER_REQUEST_MESSAGE 0x0012
219 #define ALARM_MESSAGE 0x0020
220 struct alarm_message
{
221 uint32_t alarmSeverity
;
222 char displayMessage
[80];
223 uint32_t alarmParam1
;
224 uint32_t alarmParam2
;
227 #define OPEN_RECEIVE_CHANNEL_ACK_MESSAGE 0x0022
228 struct open_receive_channel_ack_message
{
235 #define SOFT_KEY_SET_REQ_MESSAGE 0x0025
237 #define SOFT_KEY_EVENT_MESSAGE 0x0026
238 struct soft_key_event_message
{
239 uint32_t softKeyEvent
;
244 #define UNREGISTER_MESSAGE 0x0027
245 #define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028
246 #define HEADSET_STATUS_MESSAGE 0x002B
247 #define REGISTER_AVAILABLE_LINES_MESSAGE 0x002D
249 #define REGISTER_ACK_MESSAGE 0x0081
250 struct register_ack_message
{
252 char dateTemplate
[6];
254 uint32_t secondaryKeepAlive
;
258 #define START_TONE_MESSAGE 0x0082
259 struct start_tone_message
{
263 #define STOP_TONE_MESSAGE 0x0083
265 #define SET_RINGER_MESSAGE 0x0085
266 struct set_ringer_message
{
268 uint32_t unknown1
; /* See notes in transmit_ringer_mode */
272 #define SET_LAMP_MESSAGE 0x0086
273 struct set_lamp_message
{
275 uint32_t stimulusInstance
;
276 uint32_t deviceStimulus
;
279 #define SET_SPEAKER_MESSAGE 0x0088
280 struct set_speaker_message
{
284 /* XXX When do we need to use this? */
285 #define SET_MICROPHONE_MESSAGE 0x0089
286 struct set_microphone_message
{
290 #define START_MEDIA_TRANSMISSION_MESSAGE 0x008A
291 struct media_qualifier
{
298 struct start_media_transmission_message
{
299 uint32_t conferenceId
;
300 uint32_t passThruPartyId
;
304 uint32_t payloadType
;
305 struct media_qualifier qualifier
;
308 #define STOP_MEDIA_TRANSMISSION_MESSAGE 0x008B
309 struct stop_media_transmission_message
{
310 uint32_t conferenceId
;
311 uint32_t passThruPartyId
;
314 #define CALL_INFO_MESSAGE 0x008F
315 struct call_info_message
{
316 char callingPartyName
[40];
317 char callingParty
[24];
318 char calledPartyName
[40];
319 char calledParty
[24];
323 char originalCalledPartyName
[40];
324 char originalCalledParty
[24];
325 char lastRedirectingPartyName
[40];
326 char lastRedirectingParty
[24];
327 uint32_t originalCalledPartyRedirectReason
;
328 uint32_t lastRedirectingReason
;
329 char callingPartyVoiceMailbox
[24];
330 char calledPartyVoiceMailbox
[24];
331 char originalCalledPartyVoiceMailbox
[24];
332 char lastRedirectingVoiceMailbox
[24];
335 #define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
336 struct speed_dial_stat_res_message
{
337 uint32_t speedDialNumber
;
338 char speedDialDirNumber
[24];
339 char speedDialDisplayName
[40];
342 #define LINE_STAT_RES_MESSAGE 0x0092
343 struct line_stat_res_message
{
345 char lineDirNumber
[24];
346 char lineDisplayName
[42];
350 #define DEFINETIMEDATE_MESSAGE 0x0094
351 struct definetimedate_message
{
352 uint32_t year
; /* since 1900 */
354 uint32_t dayofweek
; /* monday = 1 */
359 uint32_t milliseconds
;
363 #define BUTTON_TEMPLATE_RES_MESSAGE 0x0097
364 struct button_definition
{
365 uint8_t instanceNumber
;
366 uint8_t buttonDefinition
;
369 struct button_definition_template
{
370 uint8_t buttonDefinition
;
371 /* for now, anything between 0xB0 and 0xCF is custom */
375 #define STIMULUS_REDIAL 0x01
376 #define STIMULUS_SPEEDDIAL 0x02
377 #define STIMULUS_HOLD 0x03
378 #define STIMULUS_TRANSFER 0x04
379 #define STIMULUS_FORWARDALL 0x05
380 #define STIMULUS_FORWARDBUSY 0x06
381 #define STIMULUS_FORWARDNOANSWER 0x07
382 #define STIMULUS_DISPLAY 0x08
383 #define STIMULUS_LINE 0x09
384 #define STIMULUS_VOICEMAIL 0x0F
385 #define STIMULUS_AUTOANSWER 0x11
386 #define STIMULUS_CONFERENCE 0x7D
387 #define STIMULUS_CALLPARK 0x7E
388 #define STIMULUS_CALLPICKUP 0x7F
389 #define STIMULUS_NONE 0xFF
392 #define BT_REDIAL STIMULUS_REDIAL
393 #define BT_SPEEDDIAL STIMULUS_SPEEDDIAL
394 #define BT_HOLD STIMULUS_HOLD
395 #define BT_TRANSFER STIMULUS_TRANSFER
396 #define BT_FORWARDALL STIMULUS_FORWARDALL
397 #define BT_FORWARDBUSY STIMULUS_FORWARDBUSY
398 #define BT_FORWARDNOANSWER STIMULUS_FORWARDNOANSWER
399 #define BT_DISPLAY STIMULUS_DISPLAY
400 #define BT_LINE STIMULUS_LINE
401 #define BT_VOICEMAIL STIMULUS_VOICEMAIL
402 #define BT_AUTOANSWER STIMULUS_AUTOANSWER
403 #define BT_CONFERENCE STIMULUS_CONFERENCE
404 #define BT_CALLPARK STIMULUS_CALLPARK
405 #define BT_CALLPICKUP STIMULUS_CALLPICKUP
408 /* Custom button types - add our own between 0xB0 and 0xCF.
409 This may need to be revised in the future,
410 if stimuluses are ever added in this range. */
411 #define BT_CUST_LINESPEEDDIAL 0xB0 /* line or speeddial */
412 #define BT_CUST_HINT 0xB1 /* pipe dream */
414 struct button_template_res_message
{
415 uint32_t buttonOffset
;
416 uint32_t buttonCount
;
417 uint32_t totalButtonCount
;
418 struct button_definition definition
[42];
421 #define VERSION_RES_MESSAGE 0x0098
422 struct version_res_message
{
426 #define DISPLAYTEXT_MESSAGE 0x0099
427 struct displaytext_message
{
431 #define CLEAR_NOTIFY_MESSAGE 0x0115
432 #define CLEAR_PROMPT_MESSAGE 0x0113
433 #define CLEAR_DISPLAY_MESSAGE 0x009A
435 #define CAPABILITIES_REQ_MESSAGE 0x009B
437 #define REGISTER_REJ_MESSAGE 0x009D
438 struct register_rej_message
{
442 #define SERVER_RES_MESSAGE 0x009E
443 struct server_identifier
{
447 struct server_res_message
{
448 struct server_identifier server
[5];
449 uint32_t serverListenPort
[5];
450 uint32_t serverIpAddr
[5];
453 #define RESET_MESSAGE 0x009F
454 struct reset_message
{
458 #define KEEP_ALIVE_ACK_MESSAGE 0x0100
460 #define OPEN_RECEIVE_CHANNEL_MESSAGE 0x0105
461 struct open_receive_channel_message
{
462 uint32_t conferenceId
;
470 #define CLOSE_RECEIVE_CHANNEL_MESSAGE 0x0106
471 struct close_receive_channel_message
{
472 uint32_t conferenceId
;
476 #define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108
478 struct soft_key_template_definition
{
479 char softKeyLabel
[16];
480 uint32_t softKeyEvent
;
483 #define KEYDEF_ONHOOK 0
484 #define KEYDEF_CONNECTED 1
485 #define KEYDEF_ONHOLD 2
486 #define KEYDEF_RINGIN 3
487 #define KEYDEF_OFFHOOK 4
488 #define KEYDEF_CONNWITHTRANS 5
489 #define KEYDEF_DADFD 6 /* Digits After Dialing First Digit */
490 #define KEYDEF_CONNWITHCONF 7
491 #define KEYDEF_RINGOUT 8
492 #define KEYDEF_OFFHOOKWITHFEAT 9
493 #define KEYDEF_UNKNOWN 10
495 #define SOFTKEY_NONE 0x00
496 #define SOFTKEY_REDIAL 0x01
497 #define SOFTKEY_NEWCALL 0x02
498 #define SOFTKEY_HOLD 0x03
499 #define SOFTKEY_TRNSFER 0x04
500 #define SOFTKEY_CFWDALL 0x05
501 #define SOFTKEY_CFWDBUSY 0x06
502 #define SOFTKEY_CFWDNOANSWER 0x07
503 #define SOFTKEY_BKSPC 0x08
504 #define SOFTKEY_ENDCALL 0x09
505 #define SOFTKEY_RESUME 0x0A
506 #define SOFTKEY_ANSWER 0x0B
507 #define SOFTKEY_INFO 0x0C
508 #define SOFTKEY_CONFRN 0x0D
509 #define SOFTKEY_PARK 0x0E
510 #define SOFTKEY_JOIN 0x0F
511 #define SOFTKEY_MEETME 0x10
512 #define SOFTKEY_PICKUP 0x11
513 #define SOFTKEY_GPICKUP 0x12
515 struct soft_key_template_definition soft_key_template_default
[] = {
521 { "CFwdBusy", 0x06 },
522 { "CFwdNoAnswer", 0x07 },
536 struct soft_key_definitions
{
538 const uint8_t *defaults
;
542 static const uint8_t soft_key_default_onhook
[] = {
550 static const uint8_t soft_key_default_connected
[] = {
559 static const uint8_t soft_key_default_onhold
[] = {
566 static const uint8_t soft_key_default_ringin
[] = {
572 static const uint8_t soft_key_default_offhook
[] = {
580 static const uint8_t soft_key_default_connwithtrans
[] = {
589 static const uint8_t soft_key_default_dadfd
[] = {
594 static const uint8_t soft_key_default_connwithconf
[] = {
598 static const uint8_t soft_key_default_ringout
[] = {
605 static const uint8_t soft_key_default_offhookwithfeat
[] = {
610 static const uint8_t soft_key_default_unknown
[] = {
614 static const struct soft_key_definitions soft_key_default_definitions
[] = {
615 {KEYDEF_ONHOOK
, soft_key_default_onhook
, sizeof(soft_key_default_onhook
) / sizeof(uint8_t)},
616 {KEYDEF_CONNECTED
, soft_key_default_connected
, sizeof(soft_key_default_connected
) / sizeof(uint8_t)},
617 {KEYDEF_ONHOLD
, soft_key_default_onhold
, sizeof(soft_key_default_onhold
) / sizeof(uint8_t)},
618 {KEYDEF_RINGIN
, soft_key_default_ringin
, sizeof(soft_key_default_ringin
) / sizeof(uint8_t)},
619 {KEYDEF_OFFHOOK
, soft_key_default_offhook
, sizeof(soft_key_default_offhook
) / sizeof(uint8_t)},
620 {KEYDEF_CONNWITHTRANS
, soft_key_default_connwithtrans
, sizeof(soft_key_default_connwithtrans
) / sizeof(uint8_t)},
621 {KEYDEF_DADFD
, soft_key_default_dadfd
, sizeof(soft_key_default_dadfd
) / sizeof(uint8_t)},
622 {KEYDEF_CONNWITHCONF
, soft_key_default_connwithconf
, sizeof(soft_key_default_connwithconf
) / sizeof(uint8_t)},
623 {KEYDEF_RINGOUT
, soft_key_default_ringout
, sizeof(soft_key_default_ringout
) / sizeof(uint8_t)},
624 {KEYDEF_OFFHOOKWITHFEAT
, soft_key_default_offhookwithfeat
, sizeof(soft_key_default_offhookwithfeat
) / sizeof(uint8_t)},
625 {KEYDEF_UNKNOWN
, soft_key_default_unknown
, sizeof(soft_key_default_unknown
) / sizeof(uint8_t)}
628 struct soft_key_template_res_message
{
629 uint32_t softKeyOffset
;
630 uint32_t softKeyCount
;
631 uint32_t totalSoftKeyCount
;
632 struct soft_key_template_definition softKeyTemplateDefinition
[32];
635 #define SOFT_KEY_SET_RES_MESSAGE 0x0109
637 struct soft_key_set_definition
{
638 uint8_t softKeyTemplateIndex
[16];
639 uint16_t softKeyInfoIndex
[16];
642 struct soft_key_set_res_message
{
643 uint32_t softKeySetOffset
;
644 uint32_t softKeySetCount
;
645 uint32_t totalSoftKeySetCount
;
646 struct soft_key_set_definition softKeySetDefinition
[16];
650 #define SELECT_SOFT_KEYS_MESSAGE 0x0110
651 struct select_soft_keys_message
{
654 uint32_t softKeySetIndex
;
655 uint32_t validKeyMask
;
658 #define CALL_STATE_MESSAGE 0x0111
659 struct call_state_message
{
661 uint32_t lineInstance
;
662 uint32_t callReference
;
665 #define DISPLAY_PROMPT_STATUS_MESSAGE 0x0112
666 struct display_prompt_status_message
{
667 uint32_t messageTimeout
;
668 char promptMessage
[32];
669 uint32_t lineInstance
;
670 uint32_t callReference
;
673 #define DISPLAY_NOTIFY_MESSAGE 0x0114
674 struct display_notify_message
{
675 uint32_t displayTimeout
;
676 char displayMessage
[100];
679 #define ACTIVATE_CALL_PLANE_MESSAGE 0x0116
680 struct activate_call_plane_message
{
681 uint32_t lineInstance
;
684 #define DIALED_NUMBER_MESSAGE 0x011D
685 struct dialed_number_message
{
686 char dialedNumber
[24];
687 uint32_t lineInstance
;
688 uint32_t callReference
;
692 struct alarm_message alarm
;
693 struct speed_dial_stat_req_message speeddialreq
;
694 struct register_message reg
;
695 struct register_ack_message regack
;
696 struct register_rej_message regrej
;
697 struct capabilities_res_message caps
;
698 struct version_res_message version
;
699 struct button_template_res_message buttontemplate
;
700 struct displaytext_message displaytext
;
701 struct display_prompt_status_message displaypromptstatus
;
702 struct definetimedate_message definetimedate
;
703 struct start_tone_message starttone
;
704 struct speed_dial_stat_res_message speeddial
;
705 struct line_state_req_message line
;
706 struct line_stat_res_message linestat
;
707 struct soft_key_set_res_message softkeysets
;
708 struct soft_key_template_res_message softkeytemplate
;
709 struct server_res_message serverres
;
710 struct reset_message reset
;
711 struct set_lamp_message setlamp
;
712 struct set_ringer_message setringer
;
713 struct call_state_message callstate
;
714 struct keypad_button_message keypad
;
715 struct select_soft_keys_message selectsoftkey
;
716 struct activate_call_plane_message activatecallplane
;
717 struct stimulus_message stimulus
;
718 struct offhook_message offhook
;
719 struct onhook_message onhook
;
720 struct set_speaker_message setspeaker
;
721 struct set_microphone_message setmicrophone
;
722 struct call_info_message callinfo
;
723 struct start_media_transmission_message startmedia
;
724 struct stop_media_transmission_message stopmedia
;
725 struct open_receive_channel_message openreceivechannel
;
726 struct open_receive_channel_ack_message openreceivechannelack
;
727 struct close_receive_channel_message closereceivechannel
;
728 struct display_notify_message displaynotify
;
729 struct dialed_number_message dialednumber
;
730 struct soft_key_event_message softkeyeventmessage
;
733 /* packet composition */
738 union skinny_data data
;
741 /* XXX This is the combined size of the variables above. (len, res, e)
742 If more are added, this MUST change.
743 (sizeof(skinny_req) - sizeof(skinny_data)) DOES NOT WORK on all systems (amd64?). */
744 int skinny_header_size
= 12;
746 /*****************************
747 * Asterisk specific globals *
748 *****************************/
750 static int skinnydebug
= 0;
752 /* a hostname, portnumber, socket and such is usefull for VoIP protocols */
753 static struct sockaddr_in bindaddr
;
754 static char ourhost
[256];
756 static struct in_addr __ourip
;
757 struct ast_hostent ahp
;
759 static int skinnysock
= -1;
760 static pthread_t accept_t
;
761 static char context
[AST_MAX_CONTEXT
] = "default";
762 static char language
[MAX_LANGUAGE
] = "";
763 static char mohinterpret
[MAX_MUSICCLASS
] = "default";
764 static char mohsuggest
[MAX_MUSICCLASS
] = "";
765 static char cid_num
[AST_MAX_EXTENSION
] = "";
766 static char cid_name
[AST_MAX_EXTENSION
] = "";
767 static char linelabel
[AST_MAX_EXTENSION
] ="";
769 static ast_group_t cur_callergroup
= 0;
770 static ast_group_t cur_pickupgroup
= 0;
771 static int immediate
= 0;
772 static int callwaiting
= 0;
773 static int callreturn
= 0;
774 static int threewaycalling
= 0;
775 static int mwiblink
= 0;
776 /* This is for flashhook transfers */
777 static int transfer
= 0;
778 static int cancallforward
= 0;
779 /* static int busycount = 3;*/
780 static char accountcode
[AST_MAX_ACCOUNT_CODE
] = "";
781 static char mailbox
[AST_MAX_EXTENSION
];
782 static int amaflags
= 0;
783 static int callnums
= 1;
785 #define SKINNY_DEVICE_UNKNOWN -1
786 #define SKINNY_DEVICE_NONE 0
787 #define SKINNY_DEVICE_30SPPLUS 1
788 #define SKINNY_DEVICE_12SPPLUS 2
789 #define SKINNY_DEVICE_12SP 3
790 #define SKINNY_DEVICE_12 4
791 #define SKINNY_DEVICE_30VIP 5
792 #define SKINNY_DEVICE_7910 6
793 #define SKINNY_DEVICE_7960 7
794 #define SKINNY_DEVICE_7940 8
795 #define SKINNY_DEVICE_7935 9
796 #define SKINNY_DEVICE_ATA186 12 /* Cisco ATA-186 */
797 #define SKINNY_DEVICE_7941 115
798 #define SKINNY_DEVICE_7971 119
799 #define SKINNY_DEVICE_7985 302
800 #define SKINNY_DEVICE_7911 307
801 #define SKINNY_DEVICE_7961GE 308
802 #define SKINNY_DEVICE_7941GE 309
803 #define SKINNY_DEVICE_7905 20000
804 #define SKINNY_DEVICE_7920 30002
805 #define SKINNY_DEVICE_7970 30006
806 #define SKINNY_DEVICE_7912 30007
807 #define SKINNY_DEVICE_7902 30008
808 #define SKINNY_DEVICE_CIPC 30016 /* Cisco IP Communicator */
809 #define SKINNY_DEVICE_7961 30018
810 #define SKINNY_DEVICE_7936 30019
811 #define SKINNY_DEVICE_SCCPGATEWAY_AN 30027 /* ??? */
812 #define SKINNY_DEVICE_SCCPGATEWAY_BRI 30028 /* ??? */
814 #define SKINNY_SPEAKERON 1
815 #define SKINNY_SPEAKEROFF 2
817 #define SKINNY_MICON 1
818 #define SKINNY_MICOFF 2
820 #define SKINNY_OFFHOOK 1
821 #define SKINNY_ONHOOK 2
822 #define SKINNY_RINGOUT 3
823 #define SKINNY_RINGIN 4
824 #define SKINNY_CONNECTED 5
825 #define SKINNY_BUSY 6
826 #define SKINNY_CONGESTION 7
827 #define SKINNY_HOLD 8
828 #define SKINNY_CALLWAIT 9
829 #define SKINNY_TRANSFER 10
830 #define SKINNY_PARK 11
831 #define SKINNY_PROGRESS 12
832 #define SKINNY_INVALID 14
834 #define SKINNY_SILENCE 0x00
835 #define SKINNY_DIALTONE 0x21
836 #define SKINNY_BUSYTONE 0x23
837 #define SKINNY_ALERT 0x24
838 #define SKINNY_REORDER 0x25
839 #define SKINNY_CALLWAITTONE 0x2D
840 #define SKINNY_NOTONE 0x7F
842 #define SKINNY_LAMP_OFF 1
843 #define SKINNY_LAMP_ON 2
844 #define SKINNY_LAMP_WINK 3
845 #define SKINNY_LAMP_FLASH 4
846 #define SKINNY_LAMP_BLINK 5
848 #define SKINNY_RING_OFF 1
849 #define SKINNY_RING_INSIDE 2
850 #define SKINNY_RING_OUTSIDE 3
851 #define SKINNY_RING_FEATURE 4
856 /* Skinny rtp stream modes. Do we really need this? */
857 #define SKINNY_CX_SENDONLY 0
858 #define SKINNY_CX_RECVONLY 1
859 #define SKINNY_CX_SENDRECV 2
860 #define SKINNY_CX_CONF 3
861 #define SKINNY_CX_CONFERENCE 3
862 #define SKINNY_CX_MUTE 4
863 #define SKINNY_CX_INACTIVE 4
866 static char *skinny_cxmodes
[] = {
875 /* driver scheduler */
876 static struct sched_context
*sched
;
877 static struct io_context
*io
;
879 /* Protect the monitoring thread, so only one process can kill or start it, and not
880 when it's doing something critical. */
881 AST_MUTEX_DEFINE_STATIC(monlock
);
882 /* Protect the network socket */
883 AST_MUTEX_DEFINE_STATIC(netlock
);
884 /* Protect the session list */
885 AST_MUTEX_DEFINE_STATIC(sessionlock
);
886 /* Protect the device list */
887 AST_MUTEX_DEFINE_STATIC(devicelock
);
889 /* Protect the paging device list */
890 AST_MUTEX_DEFINE_STATIC(pagingdevicelock
);
893 /* This is the thread for the monitor which checks for input on the channels
894 which are not currently in use. */
895 static pthread_t monitor_thread
= AST_PTHREADT_NULL
;
897 /* Wait up to 16 seconds for first digit */
898 static int firstdigittimeout
= 16000;
900 /* How long to wait for following digits */
901 static int gendigittimeout
= 8000;
903 /* How long to wait for an extra digit, if there is an ambiguous match */
904 static int matchdigittimeout
= 3000;
906 struct skinny_subchannel
{
908 struct ast_channel
*owner
;
910 struct ast_rtp
*vrtp
;
912 /* time_t lastouttime; */ /* Unused */
916 /* int lastout; */ /* Unused */
922 struct skinny_subchannel
*next
;
923 struct skinny_line
*parent
;
929 char label
[42]; /* Label that shows next to the line buttons */
930 char accountcode
[AST_MAX_ACCOUNT_CODE
];
931 char exten
[AST_MAX_EXTENSION
]; /* Extension where to start */
932 char context
[AST_MAX_CONTEXT
];
933 char language
[MAX_LANGUAGE
];
934 char cid_num
[AST_MAX_EXTENSION
]; /* Caller*ID */
935 char cid_name
[AST_MAX_EXTENSION
]; /* Caller*ID */
936 char lastcallerid
[AST_MAX_EXTENSION
]; /* Last Caller*ID */
937 char call_forward
[AST_MAX_EXTENSION
];
938 char mailbox
[AST_MAX_EXTENSION
];
939 char mohinterpret
[MAX_MUSICCLASS
];
940 char mohsuggest
[MAX_MUSICCLASS
];
941 char lastnumberdialed
[AST_MAX_EXTENSION
]; /* Last number that was dialed - used for redial */
942 int curtone
; /* Current tone being played */
943 ast_group_t callgroup
;
944 ast_group_t pickupgroup
;
951 int dnd
; /* How does this affect callwait? Do we just deny a skinny_request if we're dnd? */
960 int nonCodecCapability
;
962 int msgstate
; /* voicemail message state */
967 struct ast_codec_pref prefs
;
968 struct skinny_subchannel
*sub
;
969 struct skinny_line
*next
;
970 struct skinny_device
*parent
;
973 struct skinny_speeddial
{
976 char exten
[AST_MAX_EXTENSION
];
979 struct skinny_speeddial
*next
;
980 struct skinny_device
*parent
;
983 struct skinny_addon
{
987 struct skinny_addon
*next
;
988 struct skinny_device
*parent
;
991 static struct skinny_device
{
992 /* A device containing one or more lines */
998 int lastlineinstance
;
999 int lastcallreference
;
1001 struct sockaddr_in addr
;
1002 struct in_addr ourip
;
1003 struct skinny_line
*lines
;
1004 struct skinny_speeddial
*speeddials
;
1005 struct skinny_addon
*addons
;
1006 struct ast_codec_pref prefs
;
1008 struct skinnysession
*session
;
1009 struct skinny_device
*next
;
1012 struct skinny_paging_device
{
1015 struct skinny_device
** devices
;
1016 struct skinny_paging_device
*next
;
1019 static struct skinnysession
{
1022 struct sockaddr_in sin
;
1024 char inbuf
[SKINNY_MAX_PACKET
];
1025 char outbuf
[SKINNY_MAX_PACKET
];
1026 struct skinny_device
*device
;
1027 struct skinnysession
*next
;
1030 static struct ast_channel
*skinny_request(const char *type
, int format
, void *data
, int *cause
);
1031 static int skinny_call(struct ast_channel
*ast
, char *dest
, int timeout
);
1032 static int skinny_hangup(struct ast_channel
*ast
);
1033 static int skinny_answer(struct ast_channel
*ast
);
1034 static struct ast_frame
*skinny_read(struct ast_channel
*ast
);
1035 static int skinny_write(struct ast_channel
*ast
, struct ast_frame
*frame
);
1036 static int skinny_indicate(struct ast_channel
*ast
, int ind
, const void *data
, size_t datalen
);
1037 static int skinny_fixup(struct ast_channel
*oldchan
, struct ast_channel
*newchan
);
1038 static int skinny_senddigit_begin(struct ast_channel
*ast
, char digit
);
1039 static int skinny_senddigit_end(struct ast_channel
*ast
, char digit
, unsigned int duration
);
1041 static const struct ast_channel_tech skinny_tech
= {
1043 .description
= tdesc
,
1044 .capabilities
= ((AST_FORMAT_MAX_AUDIO
<< 1) - 1),
1045 .properties
= AST_CHAN_TP_WANTSJITTER
| AST_CHAN_TP_CREATESJITTER
,
1046 .requester
= skinny_request
,
1047 .call
= skinny_call
,
1048 .hangup
= skinny_hangup
,
1049 .answer
= skinny_answer
,
1050 .read
= skinny_read
,
1051 .write
= skinny_write
,
1052 .indicate
= skinny_indicate
,
1053 .fixup
= skinny_fixup
,
1054 .send_digit_begin
= skinny_senddigit_begin
,
1055 .send_digit_end
= skinny_senddigit_end
,
1056 /* .bridge = ast_rtp_bridge, */
1059 static void *get_button_template(struct skinnysession
*s
, struct button_definition_template
*btn
)
1061 struct skinny_device
*d
= s
->device
;
1062 struct skinny_addon
*a
= d
->addons
;
1066 case SKINNY_DEVICE_30SPPLUS
:
1067 case SKINNY_DEVICE_30VIP
:
1068 /* 13 rows, 2 columns */
1069 for (i
= 0; i
< 4; i
++)
1070 (btn
++)->buttonDefinition
= BT_LINE
;
1071 (btn
++)->buttonDefinition
= BT_REDIAL
;
1072 (btn
++)->buttonDefinition
= BT_VOICEMAIL
;
1073 (btn
++)->buttonDefinition
= BT_CALLPARK
;
1074 (btn
++)->buttonDefinition
= BT_FORWARDALL
;
1075 (btn
++)->buttonDefinition
= BT_CONFERENCE
;
1076 for (i
= 0; i
< 4; i
++)
1077 (btn
++)->buttonDefinition
= BT_NONE
;
1078 for (i
= 0; i
< 13; i
++)
1079 (btn
++)->buttonDefinition
= BT_SPEEDDIAL
;
1082 case SKINNY_DEVICE_12SPPLUS
:
1083 case SKINNY_DEVICE_12SP
:
1084 case SKINNY_DEVICE_12
:
1085 /* 6 rows, 2 columns */
1086 for (i
= 0; i
< 2; i
++)
1087 (btn
++)->buttonDefinition
= BT_LINE
;
1088 (btn
++)->buttonDefinition
= BT_REDIAL
;
1089 for (i
= 0; i
< 3; i
++)
1090 (btn
++)->buttonDefinition
= BT_SPEEDDIAL
;
1091 (btn
++)->buttonDefinition
= BT_HOLD
;
1092 (btn
++)->buttonDefinition
= BT_TRANSFER
;
1093 (btn
++)->buttonDefinition
= BT_FORWARDALL
;
1094 (btn
++)->buttonDefinition
= BT_CALLPARK
;
1095 (btn
++)->buttonDefinition
= BT_VOICEMAIL
;
1096 (btn
++)->buttonDefinition
= BT_CONFERENCE
;
1098 case SKINNY_DEVICE_7910
:
1099 (btn
++)->buttonDefinition
= BT_LINE
;
1100 (btn
++)->buttonDefinition
= BT_HOLD
;
1101 (btn
++)->buttonDefinition
= BT_TRANSFER
;
1102 (btn
++)->buttonDefinition
= BT_DISPLAY
;
1103 (btn
++)->buttonDefinition
= BT_VOICEMAIL
;
1104 (btn
++)->buttonDefinition
= BT_CONFERENCE
;
1105 (btn
++)->buttonDefinition
= BT_FORWARDALL
;
1106 for (i
= 0; i
< 2; i
++)
1107 (btn
++)->buttonDefinition
= BT_SPEEDDIAL
;
1108 (btn
++)->buttonDefinition
= BT_REDIAL
;
1110 case SKINNY_DEVICE_7960
:
1111 case SKINNY_DEVICE_7961
:
1112 case SKINNY_DEVICE_7961GE
:
1113 for (i
= 0; i
< 6; i
++)
1114 (btn
++)->buttonDefinition
= BT_CUST_LINESPEEDDIAL
;
1116 case SKINNY_DEVICE_7940
:
1117 case SKINNY_DEVICE_7941
:
1118 case SKINNY_DEVICE_7941GE
:
1119 for (i
= 0; i
< 2; i
++)
1120 (btn
++)->buttonDefinition
= BT_CUST_LINESPEEDDIAL
;
1122 case SKINNY_DEVICE_7935
:
1123 case SKINNY_DEVICE_7936
:
1124 for (i
= 0; i
< 2; i
++)
1125 (btn
++)->buttonDefinition
= BT_LINE
;
1127 case SKINNY_DEVICE_ATA186
:
1128 (btn
++)->buttonDefinition
= BT_LINE
;
1130 case SKINNY_DEVICE_7970
:
1131 case SKINNY_DEVICE_7971
:
1132 case SKINNY_DEVICE_CIPC
:
1133 for (i
= 0; i
< 8; i
++)
1134 (btn
++)->buttonDefinition
= BT_CUST_LINESPEEDDIAL
;
1136 case SKINNY_DEVICE_7985
:
1137 /* XXX I have no idea what the buttons look like on these. */
1138 ast_log(LOG_WARNING
, "Unsupported device type '%d (7985)' found.\n", d
->type
);
1140 case SKINNY_DEVICE_7912
:
1141 case SKINNY_DEVICE_7911
:
1142 case SKINNY_DEVICE_7905
:
1143 (btn
++)->buttonDefinition
= BT_LINE
;
1144 (btn
++)->buttonDefinition
= BT_HOLD
;
1146 case SKINNY_DEVICE_7920
:
1147 /* XXX I don't know if this is right. */
1148 for (i
= 0; i
< 4; i
++)
1149 (btn
++)->buttonDefinition
= BT_CUST_LINESPEEDDIAL
;
1151 case SKINNY_DEVICE_7902
:
1152 ast_log(LOG_WARNING
, "Unsupported device type '%d (7902)' found.\n", d
->type
);
1154 case SKINNY_DEVICE_SCCPGATEWAY_AN
:
1155 case SKINNY_DEVICE_SCCPGATEWAY_BRI
:
1156 ast_log(LOG_WARNING
, "Unsupported device type '%d (SCCP gateway)' found.\n", d
->type
);
1159 ast_log(LOG_WARNING
, "Unknown device type '%d' found.\n", d
->type
);
1163 for (a
= d
->addons
; a
; a
= a
->next
) {
1164 if (!strcasecmp(a
->type
, "7914")) {
1165 for (i
= 0; i
< 14; i
++)
1166 (btn
++)->buttonDefinition
= BT_CUST_LINESPEEDDIAL
;
1168 ast_log(LOG_WARNING
, "Unknown addon type '%s' found. Skipping.\n", a
->type
);
1175 static struct skinny_req
*req_alloc(size_t size
, int response_message
)
1177 struct skinny_req
*req
;
1179 if (!(req
= ast_calloc(1, skinny_header_size
+ size
+ 4)))
1182 req
->len
= htolel(size
+4);
1183 req
->e
= htolel(response_message
);
1188 static struct skinny_line
*find_line_by_instance(struct skinny_device
*d
, int instance
)
1190 struct skinny_line
*l
;
1192 for (l
= d
->lines
; l
; l
= l
->next
) {
1193 if (l
->instance
== instance
)
1198 ast_log(LOG_WARNING
, "Could not find line with instance '%d' on device '%s'\n", instance
, d
->name
);
1203 static struct skinny_line
*find_line_by_name(const char *dest
)
1205 struct skinny_line
*l
;
1206 struct skinny_device
*d
;
1211 ast_copy_string(line
, dest
, sizeof(line
));
1212 at
= strchr(line
, '@');
1214 ast_log(LOG_NOTICE
, "Device '%s' has no @ (at) sign!\n", dest
);
1219 ast_mutex_lock(&devicelock
);
1220 for (d
= devices
; d
; d
= d
->next
) {
1221 if (!strcasecmp(d
->name
, device
)) {
1223 ast_verbose("Found device: %s\n", d
->name
);
1224 /* Found the device */
1225 for (l
= d
->lines
; l
; l
= l
->next
) {
1226 /* Search for the right line */
1227 if (!strcasecmp(l
->name
, line
)) {
1228 ast_mutex_unlock(&devicelock
);
1234 /* Device not found */
1235 ast_mutex_unlock(&devicelock
);
1239 /* It's quicker/easier to find the subchannel when we know the instance number too */
1240 static struct skinny_subchannel
*find_subchannel_by_instance_reference(struct skinny_device
*d
, int instance
, int reference
)
1242 struct skinny_line
*l
= find_line_by_instance(d
, instance
);
1243 struct skinny_subchannel
*sub
;
1249 for (sub
= l
->sub
; sub
; sub
= sub
->next
) {
1250 if (sub
->callid
== reference
)
1255 ast_log(LOG_WARNING
, "Could not find subchannel with reference '%d' on '%s'\n", reference
, d
->name
);
1260 /* Find the subchannel when we only have the callid - this shouldn't happen often */
1261 static struct skinny_subchannel
*find_subchannel_by_reference(struct skinny_device
*d
, int reference
)
1263 struct skinny_line
*l
;
1264 struct skinny_subchannel
*sub
= NULL
;
1266 for (l
= d
->lines
; l
; l
= l
->next
) {
1267 for (sub
= l
->sub
; sub
; sub
= sub
->next
) {
1268 if (sub
->callid
== reference
)
1276 ast_log(LOG_WARNING
, "Could not find any lines that contained a subchannel with reference '%d' on device '%s'\n", reference
, d
->name
);
1279 ast_log(LOG_WARNING
, "Could not find subchannel with reference '%d' on '%s@%s'\n", reference
, l
->name
, d
->name
);
1285 static struct skinny_speeddial
*find_speeddial_by_instance(struct skinny_device
*d
, int instance
)
1287 struct skinny_speeddial
*sd
;
1289 for (sd
= d
->speeddials
; sd
; sd
= sd
->next
) {
1290 if (sd
->instance
== instance
)
1295 ast_log(LOG_WARNING
, "Could not find speeddial with instance '%d' on device '%s'\n", instance
, d
->name
);
1300 static int codec_skinny2ast(enum skinny_codecs skinnycodec
)
1302 switch (skinnycodec
) {
1303 case SKINNY_CODEC_ALAW
:
1304 return AST_FORMAT_ALAW
;
1305 case SKINNY_CODEC_ULAW
:
1306 return AST_FORMAT_ULAW
;
1307 case SKINNY_CODEC_G723_1
:
1308 return AST_FORMAT_G723_1
;
1309 case SKINNY_CODEC_G729A
:
1310 return AST_FORMAT_G729A
;
1311 case SKINNY_CODEC_G726_32
:
1312 return AST_FORMAT_G726_AAL2
; /* XXX Is this right? */
1313 case SKINNY_CODEC_H261
:
1314 return AST_FORMAT_H261
;
1315 case SKINNY_CODEC_H263
:
1316 return AST_FORMAT_H263
;
1322 static int codec_ast2skinny(int astcodec
)
1325 case AST_FORMAT_ALAW
:
1326 return SKINNY_CODEC_ALAW
;
1327 case AST_FORMAT_ULAW
:
1328 return SKINNY_CODEC_ULAW
;
1329 case AST_FORMAT_G723_1
:
1330 return SKINNY_CODEC_G723_1
;
1331 case AST_FORMAT_G729A
:
1332 return SKINNY_CODEC_G729A
;
1333 case AST_FORMAT_G726_AAL2
: /* XXX Is this right? */
1334 return SKINNY_CODEC_G726_32
;
1335 case AST_FORMAT_H261
:
1336 return SKINNY_CODEC_H261
;
1337 case AST_FORMAT_H263
:
1338 return SKINNY_CODEC_H263
;
1345 static int skinny_register(struct skinny_req
*req
, struct skinnysession
*s
)
1347 struct skinny_device
*d
;
1348 struct sockaddr_in sin
;
1351 ast_mutex_lock(&devicelock
);
1352 for (d
= devices
; d
; d
= d
->next
) {
1353 if (!strcasecmp(req
->data
.reg
.name
, d
->id
)
1354 && ast_apply_ha(d
->ha
, &(s
->sin
))) {
1356 d
->type
= letohl(req
->data
.reg
.type
);
1357 if (ast_strlen_zero(d
->version_id
)) {
1358 ast_copy_string(d
->version_id
, version_id
, sizeof(d
->version_id
));
1364 if (getsockname(s
->fd
, (struct sockaddr
*)&sin
, &slen
)) {
1365 ast_log(LOG_WARNING
, "Cannot get socket name\n");
1366 sin
.sin_addr
= __ourip
;
1368 d
->ourip
= sin
.sin_addr
;
1372 ast_mutex_unlock(&devicelock
);
1379 static int skinny_unregister(struct skinny_req
*req
, struct skinnysession
*s
)
1381 struct skinny_device
*d
;
1390 return -1; /* main loop will destroy the session */
1393 static int transmit_response(struct skinnysession
*s
, struct skinny_req
*req
)
1398 ast_log(LOG_WARNING
, "Asked to transmit to a non-existant session!\n");
1402 ast_mutex_lock(&s
->lock
);
1405 ast_log(LOG_VERBOSE
, "writing packet type %04X (%d bytes) to socket %d\n", letohl(req
->e
), letohl(req
->len
)+8, s
->fd
);
1407 if (letohl(req
->len
> SKINNY_MAX_PACKET
) || letohl(req
->len
< 0)) {
1408 ast_log(LOG_WARNING
, "transmit_response: the length of the request is out of bounds\n");
1412 memset(s
->outbuf
,0,sizeof(s
->outbuf
));
1413 memcpy(s
->outbuf
, req
, skinny_header_size
);
1414 memcpy(s
->outbuf
+skinny_header_size
, &req
->data
, letohl(req
->len
));
1416 res
= write(s
->fd
, s
->outbuf
, letohl(req
->len
)+8);
1418 if (res
!= letohl(req
->len
)+8) {
1419 ast_log(LOG_WARNING
, "Transmit: write only sent %d out of %d bytes: %s\n", res
, letohl(req
->len
)+8, strerror(errno
));
1422 ast_log(LOG_WARNING
, "Transmit: Skinny Client was lost, unregistering\n");
1423 skinny_unregister(NULL
, s
);
1428 ast_mutex_unlock(&s
->lock
);
1432 static void transmit_speaker_mode(struct skinnysession
*s
, int mode
)
1434 struct skinny_req
*req
;
1436 if (!(req
= req_alloc(sizeof(struct set_speaker_message
), SET_SPEAKER_MESSAGE
)))
1439 req
->data
.setspeaker
.mode
= htolel(mode
);
1440 transmit_response(s
, req
);
1443 static void transmit_microphone_mode(struct skinnysession *s, int mode)
1445 struct skinny_req *req;
1447 if (!(req = req_alloc(sizeof(struct set_microphone_message), SET_MICROPHONE_MESSAGE)))
1450 req->data.setmicrophone.mode = htolel(mode);
1451 transmit_response(s, req);
1454 static void transmit_callstate(struct skinnysession
*s
, int instance
, int state
, unsigned callid
)
1456 struct skinny_req
*req
;
1458 if (!(req
= req_alloc(sizeof(struct call_state_message
), CALL_STATE_MESSAGE
)))
1461 if (state
== SKINNY_ONHOOK
) {
1462 transmit_speaker_mode(s
, SKINNY_SPEAKEROFF
);
1464 req
->data
.callstate
.callState
= htolel(state
);
1465 req
->data
.callstate
.lineInstance
= htolel(instance
);
1466 req
->data
.callstate
.callReference
= htolel(callid
);
1467 transmit_response(s
, req
);
1468 if (state
== SKINNY_OFFHOOK
) {
1469 if (!(req
= req_alloc(sizeof(struct activate_call_plane_message
), ACTIVATE_CALL_PLANE_MESSAGE
)))
1472 req
->data
.activatecallplane
.lineInstance
= htolel(instance
);
1473 transmit_response(s
, req
);
1474 } else if (state
== SKINNY_ONHOOK
) {
1475 if (!(req
= req_alloc(sizeof(struct activate_call_plane_message
), ACTIVATE_CALL_PLANE_MESSAGE
)))
1478 req
->data
.activatecallplane
.lineInstance
= htolel(instance
);
1479 transmit_response(s
, req
);
1481 if (!(req
= req_alloc(sizeof(struct close_receive_channel_message
), CLOSE_RECEIVE_CHANNEL_MESSAGE
)))
1484 req
->data
.closereceivechannel
.conferenceId
= 0;
1485 req
->data
.closereceivechannel
.partyId
= htolel(callid
);
1486 transmit_response(s
, req
);
1488 if (!(req
= req_alloc(sizeof(struct stop_media_transmission_message
), STOP_MEDIA_TRANSMISSION_MESSAGE
)))
1491 req
->data
.stopmedia
.conferenceId
= 0;
1492 req
->data
.stopmedia
.passThruPartyId
= htolel(callid
);
1493 transmit_response(s
, req
);
1497 static void transmit_callinfo(struct skinnysession
*s
, const char *fromname
, const char *fromnum
, const char *toname
, const char *tonum
, int instance
, int callid
, int calltype
)
1499 struct skinny_req
*req
;
1501 if (!(req
= req_alloc(sizeof(struct call_info_message
), CALL_INFO_MESSAGE
)))
1505 ast_verbose("Setting Callinfo to %s(%s) from %s(%s) on %s(%d)\n", fromname
, fromnum
, toname
, tonum
, s
->device
->name
, instance
);
1508 ast_copy_string(req
->data
.callinfo
.callingPartyName
, fromname
, sizeof(req
->data
.callinfo
.callingPartyName
));
1511 ast_copy_string(req
->data
.callinfo
.callingParty
, fromnum
, sizeof(req
->data
.callinfo
.callingParty
));
1514 ast_copy_string(req
->data
.callinfo
.calledPartyName
, toname
, sizeof(req
->data
.callinfo
.calledPartyName
));
1517 ast_copy_string(req
->data
.callinfo
.calledParty
, tonum
, sizeof(req
->data
.callinfo
.calledParty
));
1519 req
->data
.callinfo
.instance
= htolel(instance
);
1520 req
->data
.callinfo
.reference
= htolel(callid
);
1521 req
->data
.callinfo
.type
= htolel(calltype
);
1522 transmit_response(s
, req
);
1525 static void transmit_connect(struct skinnysession
*s
, struct skinny_subchannel
*sub
)
1527 struct skinny_req
*req
;
1528 struct skinny_line
*l
= sub
->parent
;
1529 struct ast_format_list fmt
;
1531 if (!(req
= req_alloc(sizeof(struct open_receive_channel_message
), OPEN_RECEIVE_CHANNEL_MESSAGE
)))
1534 fmt
= ast_codec_pref_getsize(&l
->prefs
, ast_best_codec(l
->capability
));
1536 req
->data
.openreceivechannel
.conferenceId
= htolel(0);
1537 req
->data
.openreceivechannel
.partyId
= htolel(sub
->callid
);
1538 req
->data
.openreceivechannel
.packets
= htolel(fmt
.cur_ms
);
1539 req
->data
.openreceivechannel
.capability
= htolel(codec_ast2skinny(fmt
.bits
));
1540 req
->data
.openreceivechannel
.echo
= htolel(0);
1541 req
->data
.openreceivechannel
.bitrate
= htolel(0);
1542 transmit_response(s
, req
);
1545 static void transmit_tone(struct skinnysession
*s
, int tone
)
1547 struct skinny_req
*req
;
1549 if (tone
== SKINNY_NOTONE
) {
1550 /* This is bad, mmm'kay? */
1555 if (!(req
= req_alloc(sizeof(struct start_tone_message
), START_TONE_MESSAGE
)))
1558 if (!(req
= req_alloc(0, STOP_TONE_MESSAGE
)))
1563 req
->data
.starttone
.tone
= htolel(tone
);
1565 transmit_response(s
, req
);
1568 static void transmit_selectsoftkeys(struct skinnysession
*s
, int instance
, int callid
, int softkey
)
1570 struct skinny_req
*req
;
1572 if (!(req
= req_alloc(sizeof(struct select_soft_keys_message
), SELECT_SOFT_KEYS_MESSAGE
)))
1575 req
->data
.selectsoftkey
.instance
= htolel(instance
);
1576 req
->data
.selectsoftkey
.reference
= htolel(callid
);
1577 req
->data
.selectsoftkey
.softKeySetIndex
= htolel(softkey
);
1578 req
->data
.selectsoftkey
.validKeyMask
= htolel(0xFFFFFFFF);
1579 transmit_response(s
, req
);
1582 static void transmit_lamp_indication(struct skinnysession
*s
, int stimulus
, int instance
, int indication
)
1584 struct skinny_req
*req
;
1586 if (!(req
= req_alloc(sizeof(struct set_lamp_message
), SET_LAMP_MESSAGE
)))
1589 req
->data
.setlamp
.stimulus
= htolel(stimulus
);
1590 req
->data
.setlamp
.stimulusInstance
= htolel(instance
);
1591 req
->data
.setlamp
.deviceStimulus
= htolel(indication
);
1592 transmit_response(s
, req
);
1595 static void transmit_ringer_mode(struct skinnysession
*s
, int mode
)
1597 struct skinny_req
*req
;
1600 ast_verbose("Setting ringer mode to '%d'.\n", mode
);
1602 if (!(req
= req_alloc(sizeof(struct set_ringer_message
), SET_RINGER_MESSAGE
)))
1605 req
->data
.setringer
.ringerMode
= htolel(mode
);
1606 /* XXX okay, I don't quite know what this is, but here's what happens (on a 7960).
1607 Note: The phone will always show as ringing on the display.
1609 1: phone will audibly ring over and over
1610 2: phone will audibly ring only once
1611 any other value, will NOT cause the phone to audibly ring
1613 req
->data
.setringer
.unknown1
= htolel(1);
1614 /* XXX the value here doesn't seem to change anything. Must be higher than 0.
1615 Perhaps a packet capture can shed some light on this. */
1616 req
->data
.setringer
.unknown2
= htolel(1);
1617 transmit_response(s
, req
);
1620 static void transmit_displaymessage(struct skinnysession
*s
, const char *text
)
1622 struct skinny_req
*req
;
1625 if (!(req
= req_alloc(0, CLEAR_DISPLAY_MESSAGE
)))
1629 ast_verbose("Clearing Display\n");
1631 if (!(req
= req_alloc(sizeof(struct displaytext_message
), DISPLAYTEXT_MESSAGE
)))
1634 ast_copy_string(req
->data
.displaytext
.text
, text
, sizeof(req
->data
.displaytext
.text
));
1636 ast_verbose("Displaying message '%s'\n", req
->data
.displaytext
.text
);
1639 transmit_response(s
, req
);
1642 static void transmit_displaynotify(struct skinnysession
*s
, const char *text
, int t
)
1644 struct skinny_req
*req
;
1646 if (!(req
= req_alloc(sizeof(struct display_notify_message
), DISPLAY_NOTIFY_MESSAGE
)))
1649 ast_copy_string(req
->data
.displaynotify
.displayMessage
, text
, sizeof(req
->data
.displaynotify
.displayMessage
));
1650 req
->data
.displaynotify
.displayTimeout
= htolel(t
);
1653 ast_verbose("Displaying notify '%s'\n", text
);
1655 transmit_response(s
, req
);
1658 static void transmit_displaypromptstatus(struct skinnysession
*s
, const char *text
, int t
, int instance
, int callid
)
1660 struct skinny_req
*req
;
1662 if (!(req
= req_alloc(sizeof(struct display_prompt_status_message
), DISPLAY_PROMPT_STATUS_MESSAGE
)))
1665 ast_copy_string(req
->data
.displaypromptstatus
.promptMessage
, text
, sizeof(req
->data
.displaypromptstatus
.promptMessage
));
1666 req
->data
.displaypromptstatus
.messageTimeout
= htolel(t
);
1667 req
->data
.displaypromptstatus
.lineInstance
= htolel(instance
);
1668 req
->data
.displaypromptstatus
.callReference
= htolel(callid
);
1671 ast_verbose("Displaying Prompt Status '%s'\n", text
);
1673 transmit_response(s
, req
);
1676 static void transmit_dialednumber(struct skinnysession
*s
, const char *text
, int instance
, int callid
)
1678 struct skinny_req
*req
;
1680 if (!(req
= req_alloc(sizeof(struct dialed_number_message
), DIALED_NUMBER_MESSAGE
)))
1683 ast_copy_string(req
->data
.dialednumber
.dialedNumber
, text
, sizeof(req
->data
.dialednumber
.dialedNumber
));
1684 req
->data
.dialednumber
.lineInstance
= htolel(instance
);
1685 req
->data
.dialednumber
.callReference
= htolel(callid
);
1687 transmit_response(s
, req
);
1691 static int has_voicemail(struct skinny_line *l)
1693 return ast_app_has_voicemail(l->mailbox, NULL);
1697 static void do_housekeeping(struct skinnysession
*s
)
1702 struct skinny_device *d = s->device;
1703 struct skinny_line *l;
1706 transmit_displaymessage(s
, NULL
);
1709 for (l = d->lines; l; l = l->next) {
1710 if (has_voicemail(l)) {
1712 ast_verbose("Checking for voicemail Skinny %s@%s\n", l->name, d->name);
1713 ast_app_inboxcount(l->mailbox, &new, &old);
1715 ast_verbose("Skinny %s@%s has voicemail!\n", l->name, d->name);
1716 transmit_lamp_indication(s, STIMULUS_VOICEMAIL, l->instance, l->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON);
1718 transmit_lamp_indication(s, STIMULUS_VOICEMAIL, l->instance, SKINNY_LAMP_OFF);
1724 /* I do not believe skinny can deal with video.
1725 Anyone know differently? */
1726 /* Yes, it can. Currently 7985 and Cisco VT Advantage do video. */
1727 static enum ast_rtp_get_result
skinny_get_vrtp_peer(struct ast_channel
*c
, struct ast_rtp
**rtp
)
1729 struct skinny_subchannel
*sub
= NULL
;
1731 if (!(sub
= c
->tech_pvt
) || !(sub
->vrtp
))
1732 return AST_RTP_GET_FAILED
;
1736 return AST_RTP_TRY_NATIVE
;
1739 static enum ast_rtp_get_result
skinny_get_rtp_peer(struct ast_channel
*c
, struct ast_rtp
**rtp
)
1741 struct skinny_subchannel
*sub
= NULL
;
1743 if (!(sub
= c
->tech_pvt
) || !(sub
->rtp
))
1744 return AST_RTP_GET_FAILED
;
1748 return AST_RTP_TRY_NATIVE
;
1751 static int skinny_set_rtp_peer(struct ast_channel
*c
, struct ast_rtp
*rtp
, struct ast_rtp
*vrtp
, int codecs
, int nat_active
)
1753 struct skinny_subchannel
*sub
;
1756 /* transmit_modify_with_sdp(sub, rtp); @@FIXME@@ if needed */
1762 static struct ast_rtp_protocol skinny_rtp
= {
1764 .get_rtp_info
= skinny_get_rtp_peer
,
1765 .get_vrtp_info
= skinny_get_vrtp_peer
,
1766 .set_rtp_peer
= skinny_set_rtp_peer
,
1769 static int skinny_do_debug(int fd
, int argc
, char *argv
[])
1772 return RESULT_SHOWUSAGE
;
1775 ast_cli(fd
, "Skinny Debugging Enabled\n");
1776 return RESULT_SUCCESS
;
1779 static int skinny_no_debug(int fd
, int argc
, char *argv
[])
1782 return RESULT_SHOWUSAGE
;
1785 ast_cli(fd
, "Skinny Debugging Disabled\n");
1786 return RESULT_SUCCESS
;
1789 static char *complete_skinny_reset(const char *line
, const char *word
, int pos
, int state
)
1791 struct skinny_device
*d
;
1793 char *result
= NULL
;
1794 int wordlen
= strlen(word
);
1798 for (d
= devices
; d
&& !result
; d
= d
->next
) {
1799 if (!strncasecmp(word
, d
->id
, wordlen
) && ++which
> state
)
1800 result
= ast_strdup(d
->id
);
1807 static int skinny_reset_device(int fd
, int argc
, char *argv
[])
1809 struct skinny_device
*d
;
1810 struct skinny_req
*req
;
1812 if (argc
< 3 || argc
> 4) {
1813 return RESULT_SHOWUSAGE
;
1815 ast_mutex_lock(&devicelock
);
1817 for (d
= devices
; d
; d
= d
->next
) {
1818 int fullrestart
= 0;
1819 if (!strcasecmp(argv
[2], d
->id
) || !strcasecmp(argv
[2], "all")) {
1823 if (!(req
= req_alloc(sizeof(struct reset_message
), RESET_MESSAGE
)))
1826 if (argc
== 4 && !strcasecmp(argv
[3], "restart"))
1830 req
->data
.reset
.resetType
= 2;
1832 req
->data
.reset
.resetType
= 1;
1834 if (option_verbose
> 2)
1835 ast_verbose(VERBOSE_PREFIX_3
"%s device %s.\n", (fullrestart
) ? "Restarting" : "Resetting", d
->id
);
1836 transmit_response(d
->session
, req
);
1839 ast_mutex_unlock(&devicelock
);
1840 return RESULT_SUCCESS
;
1843 static char *device2str(int type
)
1848 case SKINNY_DEVICE_NONE
:
1850 case SKINNY_DEVICE_30SPPLUS
:
1852 case SKINNY_DEVICE_12SPPLUS
:
1854 case SKINNY_DEVICE_12SP
:
1856 case SKINNY_DEVICE_12
:
1858 case SKINNY_DEVICE_30VIP
:
1860 case SKINNY_DEVICE_7910
:
1862 case SKINNY_DEVICE_7960
:
1864 case SKINNY_DEVICE_7940
:
1866 case SKINNY_DEVICE_7935
:
1868 case SKINNY_DEVICE_ATA186
:
1870 case SKINNY_DEVICE_7941
:
1872 case SKINNY_DEVICE_7971
:
1874 case SKINNY_DEVICE_7985
:
1876 case SKINNY_DEVICE_7911
:
1878 case SKINNY_DEVICE_7961GE
:
1880 case SKINNY_DEVICE_7941GE
:
1882 case SKINNY_DEVICE_7905
:
1884 case SKINNY_DEVICE_7920
:
1886 case SKINNY_DEVICE_7970
:
1888 case SKINNY_DEVICE_7912
:
1890 case SKINNY_DEVICE_7902
:
1892 case SKINNY_DEVICE_CIPC
:
1893 return "IP Communicator";
1894 case SKINNY_DEVICE_7961
:
1896 case SKINNY_DEVICE_7936
:
1898 case SKINNY_DEVICE_SCCPGATEWAY_AN
:
1899 return "SCCPGATEWAY_AN";
1900 case SKINNY_DEVICE_SCCPGATEWAY_BRI
:
1901 return "SCCPGATEWAY_BRI";
1902 case SKINNY_DEVICE_UNKNOWN
:
1905 if (!(tmp
= ast_threadstorage_get(&device2str_threadbuf
, DEVICE2STR_BUFSIZE
)))
1907 snprintf(tmp
, DEVICE2STR_BUFSIZE
, "UNKNOWN-%d", type
);
1912 static int skinny_show_devices(int fd
, int argc
, char *argv
[])
1914 struct skinny_device
*d
;
1915 struct skinny_line
*l
;
1919 return RESULT_SHOWUSAGE
;
1921 ast_mutex_lock(&devicelock
);
1923 ast_cli(fd
, "Name DeviceId IP Type R NL\n");
1924 ast_cli(fd
, "-------------------- ---------------- --------------- --------------- - --\n");
1925 for (d
= devices
; d
; d
= d
->next
) {
1927 for (l
= d
->lines
; l
; l
= l
->next
) {
1931 ast_cli(fd
, "%-20s %-16s %-15s %-15s %c %2d\n",
1934 d
->session
?ast_inet_ntoa(d
->session
->sin
.sin_addr
):"",
1935 device2str(d
->type
),
1936 d
->registered
?'Y':'N',
1939 ast_mutex_unlock(&devicelock
);
1940 return RESULT_SUCCESS
;
1943 static int skinny_show_lines(int fd
, int argc
, char *argv
[])
1945 struct skinny_device
*d
;
1946 struct skinny_line
*l
;
1949 return RESULT_SHOWUSAGE
;
1951 ast_mutex_lock(&devicelock
);
1953 ast_cli(fd
, "Device Name Instance Name Label \n");
1954 ast_cli(fd
, "-------------------- -------- -------------------- --------------------\n");
1955 for (d
= devices
; d
; d
= d
->next
) {
1956 for (l
= d
->lines
; l
; l
= l
->next
) {
1957 ast_cli(fd
, "%-20s %8d %-20s %-20s\n",
1965 ast_mutex_unlock(&devicelock
);
1966 return RESULT_SUCCESS
;
1969 static char show_devices_usage
[] =
1970 "Usage: skinny show devices\n"
1971 " Lists all devices known to the Skinny subsystem.\n";
1973 static char show_lines_usage
[] =
1974 "Usage: skinny show lines\n"
1975 " Lists all lines known to the Skinny subsystem.\n";
1977 static char debug_usage
[] =
1978 "Usage: skinny set debug\n"
1979 " Enables dumping of Skinny packets for debugging purposes\n";
1981 static char no_debug_usage
[] =
1982 "Usage: skinny set debug off\n"
1983 " Disables dumping of Skinny packets for debugging purposes\n";
1985 static char reset_usage
[] =
1986 "Usage: skinny reset <DeviceId|all> [restart]\n"
1987 " Causes a Skinny device to reset itself, optionally with a full restart\n";
1989 static struct ast_cli_entry cli_skinny
[] = {
1990 { { "skinny", "show", "devices", NULL
},
1991 skinny_show_devices
, "List defined Skinny devices",
1992 show_devices_usage
},
1994 { { "skinny", "show", "lines", NULL
},
1995 skinny_show_lines
, "List defined Skinny lines per device",
1998 { { "skinny", "set", "debug", NULL
},
1999 skinny_do_debug
, "Enable Skinny debugging",
2002 { { "skinny", "set", "debug", "off", NULL
},
2003 skinny_no_debug
, "Disable Skinny debugging",
2006 { { "skinny", "reset", NULL
},
2007 skinny_reset_device
, "Reset Skinny device(s)",
2008 reset_usage
, complete_skinny_reset
},
2012 static struct skinny_paging_device
*build_paging_device(const char *cat
, struct ast_variable
*v
)
2018 static struct skinny_device
*build_device(const char *cat
, struct ast_variable
*v
)
2020 struct skinny_device
*d
;
2021 struct skinny_line
*l
;
2022 struct skinny_speeddial
*sd
;
2023 struct skinny_addon
*a
;
2024 int lineInstance
= 1;
2025 int speeddialInstance
= 1;
2028 if (!(d
= ast_calloc(1, sizeof(struct skinny_device
)))) {
2031 ast_copy_string(d
->name
, cat
, sizeof(d
->name
));
2032 d
->lastlineinstance
= 1;
2033 d
->capability
= default_capability
;
2034 d
->prefs
= default_prefs
;
2036 if (!strcasecmp(v
->name
, "host")) {
2037 if (ast_get_ip(&d
->addr
, v
->value
)) {
2041 } else if (!strcasecmp(v
->name
, "port")) {
2042 d
->addr
.sin_port
= htons(atoi(v
->value
));
2043 } else if (!strcasecmp(v
->name
, "device")) {
2044 ast_copy_string(d
->id
, v
->value
, sizeof(d
->id
));
2045 } else if (!strcasecmp(v
->name
, "permit") || !strcasecmp(v
->name
, "deny")) {
2046 d
->ha
= ast_append_ha(v
->name
, v
->value
, d
->ha
);
2047 } else if (!strcasecmp(v
->name
, "context")) {
2048 ast_copy_string(context
, v
->value
, sizeof(context
));
2049 } else if (!strcasecmp(v
->name
, "allow")) {
2050 ast_parse_allow_disallow(&d
->prefs
, &d
->capability
, v
->value
, 1);
2051 } else if (!strcasecmp(v
->name
, "disallow")) {
2052 ast_parse_allow_disallow(&d
->prefs
, &d
->capability
, v
->value
, 0);
2053 } else if (!strcasecmp(v
->name
, "version")) {
2054 ast_copy_string(d
->version_id
, v
->value
, sizeof(d
->version_id
));
2055 } else if (!strcasecmp(v
->name
, "nat")) {
2056 nat
= ast_true(v
->value
);
2057 } else if (!strcasecmp(v
->name
, "callerid")) {
2058 if (!strcasecmp(v
->value
, "asreceived")) {
2062 ast_callerid_split(v
->value
, cid_name
, sizeof(cid_name
), cid_num
, sizeof(cid_num
));
2064 } else if (!strcasecmp(v
->name
, "language")) {
2065 ast_copy_string(language
, v
->value
, sizeof(language
));
2066 } else if (!strcasecmp(v
->name
, "accountcode")) {
2067 ast_copy_string(accountcode
, v
->value
, sizeof(accountcode
));
2068 } else if (!strcasecmp(v
->name
, "amaflags")) {
2069 y
= ast_cdr_amaflags2int(v
->value
);
2071 ast_log(LOG_WARNING
, "Invalid AMA flags: %s at line %d\n", v
->value
, v
->lineno
);
2075 } else if (!strcasecmp(v
->name
, "mohinterpret") || !strcasecmp(v
->name
, "musiconhold")) {
2076 ast_copy_string(mohinterpret
, v
->value
, sizeof(mohinterpret
));
2077 } else if (!strcasecmp(v
->name
, "mohsuggest")) {
2078 ast_copy_string(mohsuggest
, v
->value
, sizeof(mohsuggest
));
2079 } else if (!strcasecmp(v
->name
, "callgroup")) {
2080 cur_callergroup
= ast_get_group(v
->value
);
2081 } else if (!strcasecmp(v
->name
, "pickupgroup")) {
2082 cur_pickupgroup
= ast_get_group(v
->value
);
2083 } else if (!strcasecmp(v
->name
, "immediate")) {
2084 immediate
= ast_true(v
->value
);
2085 } else if (!strcasecmp(v
->name
, "cancallforward")) {
2086 cancallforward
= ast_true(v
->value
);
2087 } else if (!strcasecmp(v
->name
, "mailbox")) {
2088 ast_copy_string(mailbox
, v
->value
, sizeof(mailbox
));
2089 } else if (!strcasecmp(v
->name
, "callreturn")) {
2090 callreturn
= ast_true(v
->value
);
2091 } else if (!strcasecmp(v
->name
, "callwaiting")) {
2092 callwaiting
= ast_true(v
->value
);
2093 } else if (!strcasecmp(v
->name
, "transfer")) {
2094 transfer
= ast_true(v
->value
);
2095 } else if (!strcasecmp(v
->name
, "threewaycalling")) {
2096 threewaycalling
= ast_true(v
->value
);
2097 } else if (!strcasecmp(v
->name
, "mwiblink")) {
2098 mwiblink
= ast_true(v
->value
);
2099 } else if (!strcasecmp(v
->name
, "linelabel")) {
2100 ast_copy_string(linelabel
, v
->value
, sizeof(linelabel
));
2101 } else if (!strcasecmp(v
->name
, "speeddial")) {
2102 if (!(sd
= ast_calloc(1, sizeof(struct skinny_speeddial
)))) {
2105 char *stringp
, *exten
, *label
;
2107 exten
= strsep(&stringp
, ",");
2108 label
= strsep(&stringp
, ",");
2109 ast_mutex_init(&sd
->lock
);
2110 ast_copy_string(sd
->exten
, exten
, sizeof(sd
->exten
));
2112 ast_copy_string(sd
->label
, label
, sizeof(sd
->label
));
2114 ast_copy_string(sd
->label
, exten
, sizeof(sd
->label
));
2115 sd
->instance
= speeddialInstance
++;
2119 sd
->next
= d
->speeddials
;
2122 } else if (!strcasecmp(v
->name
, "addon")) {
2123 if (!(a
= ast_calloc(1, sizeof(struct skinny_addon
)))) {
2126 ast_mutex_init(&a
->lock
);
2127 ast_copy_string(a
->type
, v
->value
, sizeof(a
->type
));
2129 a
->next
= d
->addons
;
2132 } else if (!strcasecmp(v
->name
, "trunk") || !strcasecmp(v
->name
, "line")) {
2133 if (!(l
= ast_calloc(1, sizeof(struct skinny_line
)))) {
2136 ast_mutex_init(&l
->lock
);
2137 ast_copy_string(l
->name
, v
->value
, sizeof(l
->name
));
2139 /* XXX Should we check for uniqueness?? XXX */
2140 ast_copy_string(l
->context
, context
, sizeof(l
->context
));
2141 ast_copy_string(l
->cid_num
, cid_num
, sizeof(l
->cid_num
));
2142 ast_copy_string(l
->cid_name
, cid_name
, sizeof(l
->cid_name
));
2143 ast_copy_string(l
->label
, linelabel
, sizeof(l
->label
));
2144 ast_copy_string(l
->language
, language
, sizeof(l
->language
));
2145 ast_copy_string(l
->mohinterpret
, mohinterpret
, sizeof(l
->mohinterpret
));
2146 ast_copy_string(l
->mohsuggest
, mohsuggest
, sizeof(l
->mohsuggest
));
2147 ast_copy_string(l
->mailbox
, mailbox
, sizeof(l
->mailbox
));
2148 ast_copy_string(l
->mailbox
, mailbox
, sizeof(l
->mailbox
));
2149 if (!ast_strlen_zero(mailbox
)) {
2150 if (option_verbose
> 2)
2151 ast_verbose(VERBOSE_PREFIX_3
"Setting mailbox '%s' on %s@%s\n", mailbox
, d
->name
, l
->name
);
2154 l
->capability
= d
->capability
;
2155 l
->prefs
= d
->prefs
;
2157 if (!strcasecmp(v
->name
, "trunk")) {
2158 l
->type
= TYPE_TRUNK
;
2160 l
->type
= TYPE_LINE
;
2162 l
->immediate
= immediate
;
2163 l
->callgroup
= cur_callergroup
;
2164 l
->pickupgroup
= cur_pickupgroup
;
2165 l
->callreturn
= callreturn
;
2166 l
->cancallforward
= cancallforward
;
2167 l
->callwaiting
= callwaiting
;
2168 l
->transfer
= transfer
;
2169 l
->threewaycalling
= threewaycalling
;
2170 l
->mwiblink
= mwiblink
;
2171 l
->onhooktime
= time(NULL
);
2172 l
->instance
= lineInstance
++;
2173 /* ASSUME we're onhook at this point */
2174 l
->hookstate
= SKINNY_ONHOOK
;
2181 ast_log(LOG_WARNING
, "Don't know keyword '%s' at line %d\n", v
->name
, v
->lineno
);
2187 ast_log(LOG_ERROR
, "A Skinny device must have at least one line!\n");
2190 if (/*d->addr.sin_addr.s_addr && */!ntohs(d
->addr
.sin_port
)) {
2191 d
->addr
.sin_port
= htons(DEFAULT_SKINNY_PORT
);
2194 /* I don't think we need this anymore at all, since d->ourip is set in skinny_register now */
2195 if (d
->addr
.sin_addr
.s_addr
) {
2196 /* XXX See note above, in 'host' option. */
2197 if (ast_ouraddrfor(&d
->addr
.sin_addr
, &d
->ourip
)) {
2208 static void start_rtp(struct skinny_subchannel
*sub
)
2210 struct skinny_line
*l
= sub
->parent
;
2211 struct skinny_device
*d
= l
->parent
;
2214 ast_mutex_lock(&sub
->lock
);
2215 /* Allocate the RTP */
2216 sub
->rtp
= ast_rtp_new_with_bindaddr(sched
, io
, 1, 0, bindaddr
.sin_addr
);
2218 sub
->vrtp
= ast_rtp_new_with_bindaddr(sched
, io
, 1, 0, bindaddr
.sin_addr
);
2220 if (sub
->rtp
&& sub
->owner
) {
2221 sub
->owner
->fds
[0] = ast_rtp_fd(sub
->rtp
);
2222 sub
->owner
->fds
[1] = ast_rtcp_fd(sub
->rtp
);
2224 if (hasvideo
&& sub
->vrtp
&& sub
->owner
) {
2225 sub
->owner
->fds
[2] = ast_rtp_fd(sub
->vrtp
);
2226 sub
->owner
->fds
[3] = ast_rtcp_fd(sub
->vrtp
);
2229 ast_rtp_setnat(sub
->rtp
, l
->nat
);
2232 ast_rtp_setnat(sub
->vrtp
, l
->nat
);
2234 /* Set Frame packetization */
2236 ast_rtp_codec_setpref(sub
->rtp
, &l
->prefs
);
2238 /* Create the RTP connection */
2239 transmit_connect(d
->session
, sub
);
2240 ast_mutex_unlock(&sub
->lock
);
2243 static void *skinny_newcall(void *data
)
2245 struct ast_channel
*c
= data
;
2246 struct skinny_subchannel
*sub
= c
->tech_pvt
;
2247 struct skinny_line
*l
= sub
->parent
;
2248 struct skinny_device
*d
= l
->parent
;
2249 struct skinnysession
*s
= d
->session
;
2252 ast_copy_string(l
->lastnumberdialed
, c
->exten
, sizeof(l
->lastnumberdialed
));
2254 l
->hidecallerid
? "" : l
->cid_num
,
2255 l
->hidecallerid
? "" : l
->cid_name
,
2256 c
->cid
.cid_ani
? NULL
: l
->cid_num
);
2257 ast_setstate(c
, AST_STATE_RING
);
2258 res
= ast_pbx_run(c
);
2260 ast_log(LOG_WARNING
, "PBX exited non-zero\n");
2261 transmit_tone(s
, SKINNY_REORDER
);
2266 static void *skinny_ss(void *data
)
2268 struct ast_channel
*c
= data
;
2269 struct skinny_subchannel
*sub
= c
->tech_pvt
;
2270 struct skinny_line
*l
= sub
->parent
;
2271 struct skinny_device
*d
= l
->parent
;
2272 struct skinnysession
*s
= d
->session
;
2273 char exten
[AST_MAX_EXTENSION
] = "";
2275 int timeout
= firstdigittimeout
;
2279 if (option_verbose
> 2)
2280 ast_verbose( VERBOSE_PREFIX_3
"Starting simple switch on '%s@%s'\n", l
->name
, d
->name
);
2282 while (len
< AST_MAX_EXTENSION
-1) {
2283 res
= ast_waitfordigit(c
, timeout
);
2287 ast_verbose("Skinny(%s@%s): waitfordigit returned < 0\n", l
->name
, d
->name
);
2288 ast_indicate(c
, -1);
2295 if (!ast_ignore_pattern(c
->context
, exten
)) {
2296 transmit_tone(s
, SKINNY_SILENCE
);
2298 if (ast_exists_extension(c
, c
->context
, exten
, 1, l
->cid_num
)) {
2299 if (!res
|| !ast_matchmore_extension(c
, c
->context
, exten
, 1, l
->cid_num
)) {
2301 /* Record this as the forwarding extension */
2302 ast_copy_string(l
->call_forward
, exten
, sizeof(l
->call_forward
));
2303 if (option_verbose
> 2)
2304 ast_verbose(VERBOSE_PREFIX_3
"Setting call forward to '%s' on channel %s\n",
2305 l
->call_forward
, c
->name
);
2306 transmit_tone(s
, SKINNY_DIALTONE
);
2310 ast_safe_sleep(c
, 500);
2311 ast_indicate(c
, -1);
2312 ast_safe_sleep(c
, 1000);
2313 memset(exten
, 0, sizeof(exten
));
2314 transmit_tone(s
, SKINNY_DIALTONE
);
2318 ast_copy_string(c
->exten
, exten
, sizeof(c
->exten
));
2319 ast_copy_string(l
->lastnumberdialed
, exten
, sizeof(l
->lastnumberdialed
));
2324 /* It's a match, but they just typed a digit, and there is an ambiguous match,
2325 so just set the timeout to matchdigittimeout and wait some more */
2326 timeout
= matchdigittimeout
;
2328 } else if (res
== 0) {
2329 ast_log(LOG_DEBUG
, "Not enough digits (and no ambiguous match)...\n");
2330 transmit_tone(s
, SKINNY_REORDER
);
2333 } else if (!ast_canmatch_extension(c
, c
->context
, exten
, 1, c
->cid
.cid_num
) &&
2334 ((exten
[0] != '*') || (!ast_strlen_zero(exten
) > 2))) {
2335 ast_log(LOG_WARNING
, "Can't match [%s] from '%s' in context %s\n", exten
, c
->cid
.cid_num
? c
->cid
.cid_num
: "<Unknown Caller>", c
->context
);
2336 transmit_tone(s
, SKINNY_REORDER
);
2337 /* hang out for 3 seconds to let congestion play */
2338 ast_safe_sleep(c
, 3000);
2342 timeout
= gendigittimeout
;
2344 if (len
&& !ast_ignore_pattern(c
->context
, exten
)) {
2345 ast_indicate(c
, -1);
2354 static int skinny_call(struct ast_channel
*ast
, char *dest
, int timeout
)
2358 struct skinny_subchannel
*sub
= ast
->tech_pvt
;
2359 struct skinny_line
*l
= sub
->parent
;
2360 struct skinny_device
*d
= l
->parent
;
2361 struct skinnysession
*s
= d
->session
;
2363 if (!d
->registered
) {
2364 ast_log(LOG_ERROR
, "Device not registered, cannot call %s\n", dest
);
2368 if ((ast
->_state
!= AST_STATE_DOWN
) && (ast
->_state
!= AST_STATE_RESERVED
)) {
2369 ast_log(LOG_WARNING
, "skinny_call called on %s, neither down nor reserved\n", ast
->name
);
2374 ast_verbose(VERBOSE_PREFIX_3
"skinny_call(%s)\n", ast
->name
);
2377 ast_queue_control(ast
, AST_CONTROL_BUSY
);
2381 switch (l
->hookstate
) {
2382 case SKINNY_OFFHOOK
:
2383 tone
= SKINNY_CALLWAITTONE
;
2386 tone
= SKINNY_ALERT
;
2389 ast_log(LOG_ERROR
, "Don't know how to deal with hookstate %d\n", l
->hookstate
);
2393 transmit_callstate(s
, l
->instance
, SKINNY_RINGIN
, sub
->callid
);
2394 transmit_selectsoftkeys(s
, l
->instance
, sub
->callid
, KEYDEF_RINGIN
);
2395 transmit_displaypromptstatus(s
, "Ring-In", 0, l
->instance
, sub
->callid
);
2396 transmit_callinfo(s
, ast
->cid
.cid_name
, ast
->cid
.cid_num
, l
->cid_name
, l
->cid_num
, l
->instance
, sub
->callid
, 1);
2397 transmit_lamp_indication(s
, STIMULUS_LINE
, l
->instance
, SKINNY_LAMP_BLINK
);
2398 transmit_ringer_mode(s
, SKINNY_RING_INSIDE
);
2400 ast_setstate(ast
, AST_STATE_RINGING
);
2401 ast_queue_control(ast
, AST_CONTROL_RINGING
);
2406 static int skinny_hangup(struct ast_channel
*ast
)
2408 struct skinny_subchannel
*sub
= ast
->tech_pvt
;
2409 struct skinny_line
*l
;
2410 struct skinny_device
*d
;
2411 struct skinnysession
*s
;
2414 ast_log(LOG_DEBUG
, "Asked to hangup channel not connected\n");
2421 ast_verbose("skinny_hangup(%s) on %s@%s\n", ast
->name
, l
->name
, d
->name
);
2423 if (d
->registered
) {
2424 if ((l
->type
= TYPE_LINE
) && (l
->hookstate
== SKINNY_OFFHOOK
)) {
2425 l
->hookstate
= SKINNY_ONHOOK
;
2426 transmit_callstate(s
, l
->instance
, SKINNY_ONHOOK
, sub
->callid
);
2427 transmit_lamp_indication(s
, STIMULUS_LINE
, l
->instance
, SKINNY_LAMP_OFF
);
2428 transmit_speaker_mode(s
, SKINNY_SPEAKEROFF
);
2429 } else if ((l
->type
= TYPE_LINE
) && (l
->hookstate
== SKINNY_ONHOOK
)) {
2430 transmit_callstate(s
, l
->instance
, SKINNY_ONHOOK
, sub
->callid
);
2431 transmit_speaker_mode(s
, SKINNY_SPEAKEROFF
);
2432 transmit_ringer_mode(s
, SKINNY_RING_OFF
);
2433 transmit_tone(s
, SKINNY_SILENCE
);
2434 transmit_lamp_indication(s
, STIMULUS_LINE
, l
->instance
, SKINNY_LAMP_OFF
);
2438 ast_mutex_lock(&sub
->lock
);
2440 ast
->tech_pvt
= NULL
;
2441 sub
->alreadygone
= 0;
2444 ast_rtp_destroy(sub
->rtp
);
2447 ast_mutex_unlock(&sub
->lock
);
2451 static int skinny_answer(struct ast_channel
*ast
)
2454 struct skinny_subchannel
*sub
= ast
->tech_pvt
;
2455 struct skinny_line
*l
= sub
->parent
;
2456 struct skinny_device
*d
= l
->parent
;
2457 struct skinnysession
*s
= d
->session
;
2459 sub
->cxmode
= SKINNY_CX_SENDRECV
;
2464 ast_verbose("skinny_answer(%s) on %s@%s-%d\n", ast
->name
, l
->name
, d
->name
, sub
->callid
);
2465 if (ast
->_state
!= AST_STATE_UP
) {
2466 ast_setstate(ast
, AST_STATE_UP
);
2469 transmit_tone(s
, SKINNY_SILENCE
);
2470 /* order matters here...
2471 for some reason, transmit_callinfo must be before transmit_callstate,
2472 or you won't get keypad messages in some situations. */
2473 transmit_callinfo(s
, ast
->cid
.cid_name
, ast
->cid
.cid_num
, ast
->exten
, ast
->exten
, l
->instance
, sub
->callid
, 2);
2474 transmit_callstate(s
, l
->instance
, SKINNY_CONNECTED
, sub
->callid
);
2475 transmit_selectsoftkeys(s
, l
->instance
, sub
->callid
, KEYDEF_CONNECTED
);
2476 transmit_displaypromptstatus(s
, "Connected", 0, l
->instance
, sub
->callid
);
2480 /* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
2481 static struct ast_frame
*skinny_rtp_read(struct skinny_subchannel
*sub
)
2483 struct ast_channel
*ast
= sub
->owner
;
2484 struct ast_frame
*f
;
2487 /* We have no RTP allocated for this channel */
2488 return &ast_null_frame
;
2493 f
= ast_rtp_read(sub
->rtp
); /* RTP Audio */
2496 f
= ast_rtcp_read(sub
->rtp
); /* RTCP Control Channel */
2499 f
= ast_rtp_read(sub
->vrtp
); /* RTP Video */
2502 f
= ast_rtcp_read(sub
->vrtp
); /* RTCP Control Channel for video */
2506 /* Not yet supported */
2507 f
= ast_udptl_read(sub
->udptl
); /* UDPTL for T.38 */
2511 f
= &ast_null_frame
;
2515 /* We already hold the channel lock */
2516 if (f
->frametype
== AST_FRAME_VOICE
) {
2517 if (f
->subclass
!= ast
->nativeformats
) {
2518 ast_log(LOG_DEBUG
, "Oooh, format changed to %d\n", f
->subclass
);
2519 ast
->nativeformats
= f
->subclass
;
2520 ast_set_read_format(ast
, ast
->readformat
);
2521 ast_set_write_format(ast
, ast
->writeformat
);
2528 static struct ast_frame
*skinny_read(struct ast_channel
*ast
)
2530 struct ast_frame
*fr
;
2531 struct skinny_subchannel
*sub
= ast
->tech_pvt
;
2532 ast_mutex_lock(&sub
->lock
);
2533 fr
= skinny_rtp_read(sub
);
2534 ast_mutex_unlock(&sub
->lock
);
2538 static int skinny_write(struct ast_channel
*ast
, struct ast_frame
*frame
)
2540 struct skinny_subchannel
*sub
= ast
->tech_pvt
;
2542 if (frame
->frametype
!= AST_FRAME_VOICE
) {
2543 if (frame
->frametype
== AST_FRAME_IMAGE
) {
2546 ast_log(LOG_WARNING
, "Can't send %d type frames with skinny_write\n", frame
->frametype
);
2550 if (!(frame
->subclass
& ast
->nativeformats
)) {
2551 ast_log(LOG_WARNING
, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
2552 frame
->subclass
, ast
->nativeformats
, ast
->readformat
, ast
->writeformat
);
2557 ast_mutex_lock(&sub
->lock
);
2559 res
= ast_rtp_write(sub
->rtp
, frame
);
2561 ast_mutex_unlock(&sub
->lock
);
2566 static int skinny_fixup(struct ast_channel
*oldchan
, struct ast_channel
*newchan
)
2568 struct skinny_subchannel
*sub
= newchan
->tech_pvt
;
2569 ast_log(LOG_NOTICE
, "skinny_fixup(%s, %s)\n", oldchan
->name
, newchan
->name
);
2570 if (sub
->owner
!= oldchan
) {
2571 ast_log(LOG_WARNING
, "old channel wasn't %p but was %p\n", oldchan
, sub
->owner
);
2574 sub
->owner
= newchan
;
2578 static int skinny_senddigit_begin(struct ast_channel
*ast
, char digit
)
2580 return -1; /* Start inband indications */
2583 static int skinny_senddigit_end(struct ast_channel
*ast
, char digit
, unsigned int duration
)
2586 struct skinny_subchannel
*sub
= ast
->tech_pvt
;
2587 struct skinny_line
*l
= sub
->parent
;
2588 struct skinny_device
*d
= l
->parent
;
2591 sprintf(tmp
, "%d", digit
);
2592 transmit_tone(d
->session
, digit
);
2594 return -1; /* Stop inband indications */
2597 static char *control2str(int ind
) {
2601 case AST_CONTROL_HANGUP
:
2602 return "Other end has hungup";
2603 case AST_CONTROL_RING
:
2604 return "Local ring";
2605 case AST_CONTROL_RINGING
:
2606 return "Remote end is ringing";
2607 case AST_CONTROL_ANSWER
:
2608 return "Remote end has answered";
2609 case AST_CONTROL_BUSY
:
2610 return "Remote end is busy";
2611 case AST_CONTROL_TAKEOFFHOOK
:
2612 return "Make it go off hook";
2613 case AST_CONTROL_OFFHOOK
:
2614 return "Line is off hook";
2615 case AST_CONTROL_CONGESTION
:
2616 return "Congestion (circuits busy)";
2617 case AST_CONTROL_FLASH
:
2618 return "Flash hook";
2619 case AST_CONTROL_WINK
:
2621 case AST_CONTROL_OPTION
:
2622 return "Set a low-level option";
2623 case AST_CONTROL_RADIO_KEY
:
2625 case AST_CONTROL_RADIO_UNKEY
:
2626 return "Un-Key Radio";
2627 case AST_CONTROL_PROGRESS
:
2628 return "Remote end is making Progress";
2629 case AST_CONTROL_PROCEEDING
:
2630 return "Remote end is proceeding";
2631 case AST_CONTROL_HOLD
:
2633 case AST_CONTROL_UNHOLD
:
2638 if (!(tmp
= ast_threadstorage_get(&control2str_threadbuf
, CONTROL2STR_BUFSIZE
)))
2640 snprintf(tmp
, CONTROL2STR_BUFSIZE
, "UNKNOWN-%d", ind
);
2646 static int skinny_indicate(struct ast_channel
*ast
, int ind
, const void *data
, size_t datalen
)
2648 struct skinny_subchannel
*sub
= ast
->tech_pvt
;
2649 struct skinny_line
*l
= sub
->parent
;
2650 struct skinny_device
*d
= l
->parent
;
2651 struct skinnysession
*s
= d
->session
;
2654 ast_verbose(VERBOSE_PREFIX_3
"Asked to indicate '%s' condition on channel %s\n", control2str(ind
), ast
->name
);
2656 case AST_CONTROL_RINGING
:
2657 if (ast
->_state
!= AST_STATE_UP
) {
2658 if (!sub
->progress
) {
2659 transmit_tone(s
, SKINNY_ALERT
);
2660 transmit_callstate(s
, l
->instance
, SKINNY_RINGOUT
, sub
->callid
);
2661 transmit_dialednumber(s
, ast
->exten
, l
->instance
, sub
->callid
);
2662 transmit_displaypromptstatus(s
, "Ring Out", 0, l
->instance
, sub
->callid
);
2663 transmit_callinfo(s
, ast
->cid
.cid_name
, ast
->cid
.cid_num
, ast
->exten
, ast
->exten
, l
->instance
, sub
->callid
, 2); /* 2 = outgoing from phone */
2669 case AST_CONTROL_BUSY
:
2670 if (ast
->_state
!= AST_STATE_UP
) {
2671 transmit_tone(s
, SKINNY_BUSYTONE
);
2672 transmit_callstate(s
, l
->instance
, SKINNY_BUSY
, sub
->callid
);
2673 sub
->alreadygone
= 1;
2674 ast_softhangup_nolock(ast
, AST_SOFTHANGUP_DEV
);
2678 case AST_CONTROL_CONGESTION
:
2679 if (ast
->_state
!= AST_STATE_UP
) {
2680 transmit_tone(s
, SKINNY_REORDER
);
2681 transmit_callstate(s
, l
->instance
, SKINNY_CONGESTION
, sub
->callid
);
2682 sub
->alreadygone
= 1;
2683 ast_softhangup_nolock(ast
, AST_SOFTHANGUP_DEV
);
2687 case AST_CONTROL_PROGRESS
:
2688 if ((ast
->_state
!= AST_STATE_UP
) && !sub
->progress
&& !sub
->outgoing
) {
2689 transmit_tone(s
, SKINNY_ALERT
);
2690 transmit_callstate(s
, l
->instance
, SKINNY_PROGRESS
, sub
->callid
);
2691 transmit_displaypromptstatus(s
, "Call Progress", 0, l
->instance
, sub
->callid
);
2692 transmit_callinfo(s
, ast
->cid
.cid_name
, ast
->cid
.cid_num
, ast
->exten
, ast
->exten
, l
->instance
, sub
->callid
, 2); /* 2 = outgoing from phone */
2698 transmit_tone(s
, SKINNY_SILENCE
);
2700 case AST_CONTROL_HOLD
:
2701 ast_moh_start(ast
, data
, l
->mohinterpret
);
2703 case AST_CONTROL_UNHOLD
:
2706 case AST_CONTROL_PROCEEDING
:
2709 ast_log(LOG_WARNING
, "Don't know how to indicate condition %d\n", ind
);
2715 static struct ast_channel
*skinny_new(struct skinny_line
*l
, int state
)
2717 struct ast_channel
*tmp
;
2718 struct skinny_subchannel
*sub
;
2719 struct skinny_device
*d
= l
->parent
;
2722 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
);
2724 ast_log(LOG_WARNING
, "Unable to allocate channel structure\n");
2727 sub
= ast_calloc(1, sizeof(struct skinny_subchannel
));
2729 ast_log(LOG_WARNING
, "Unable to allocate Skinny subchannel\n");
2732 ast_mutex_init(&sub
->lock
);
2735 sub
->callid
= callnums
++;
2736 d
->lastlineinstance
= l
->instance
;
2737 d
->lastcallreference
= sub
->callid
;
2738 sub
->cxmode
= SKINNY_CX_INACTIVE
;
2746 tmp
->tech
= &skinny_tech
;
2747 tmp
->tech_pvt
= sub
;
2748 tmp
->nativeformats
= l
->capability
;
2749 if (!tmp
->nativeformats
)
2750 tmp
->nativeformats
= default_capability
;
2751 fmt
= ast_best_codec(tmp
->nativeformats
);
2753 ast_verbose("skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp
->nativeformats
, fmt
);
2755 tmp
->fds
[0] = ast_rtp_fd(sub
->rtp
);
2757 if (state
== AST_STATE_RING
) {
2760 tmp
->writeformat
= fmt
;
2761 tmp
->rawwriteformat
= fmt
;
2762 tmp
->readformat
= fmt
;
2763 tmp
->rawreadformat
= fmt
;
2764 if (!ast_strlen_zero(l
->language
))
2765 ast_string_field_set(tmp
, language
, l
->language
);
2766 if (!ast_strlen_zero(l
->accountcode
))
2767 ast_string_field_set(tmp
, accountcode
, l
->accountcode
);
2769 tmp
->amaflags
= l
->amaflags
;
2771 ast_module_ref(ast_module_info
->self
);
2772 tmp
->callgroup
= l
->callgroup
;
2773 tmp
->pickupgroup
= l
->pickupgroup
;
2774 ast_string_field_set(tmp
, call_forward
, l
->call_forward
);
2775 ast_copy_string(tmp
->context
, l
->context
, sizeof(tmp
->context
));
2776 ast_copy_string(tmp
->exten
, l
->exten
, sizeof(tmp
->exten
));
2778 /* Don't use ast_set_callerid() here because it will
2779 * generate a needless NewCallerID event */
2780 tmp
->cid
.cid_num
= ast_strdup(l
->cid_num
);
2781 tmp
->cid
.cid_ani
= ast_strdup(l
->cid_num
);
2782 tmp
->cid
.cid_name
= ast_strdup(l
->cid_name
);
2785 tmp
->adsicpe
= AST_ADSI_UNAVAILABLE
;
2788 ast_jb_configure(tmp
, &global_jbconf
);
2790 if (state
!= AST_STATE_DOWN
) {
2791 if (ast_pbx_start(tmp
)) {
2792 ast_log(LOG_WARNING
, "Unable to start PBX on %s\n", tmp
->name
);
2801 static int skinny_hold(struct skinny_subchannel
*sub
)
2803 struct skinny_line
*l
= sub
->parent
;
2804 struct skinny_device
*d
= l
->parent
;
2805 struct skinnysession
*s
= d
->session
;
2806 struct skinny_req
*req
;
2808 /* Channel needs to be put on hold */
2810 ast_verbose("Putting on Hold(%d)\n", l
->instance
);
2812 ast_queue_control_data(sub
->owner
, AST_CONTROL_HOLD
,
2813 S_OR(l
->mohsuggest
, NULL
),
2814 !ast_strlen_zero(l
->mohsuggest
) ? strlen(l
->mohsuggest
) + 1 : 0);
2816 if (!(req
= req_alloc(sizeof(struct activate_call_plane_message
), ACTIVATE_CALL_PLANE_MESSAGE
)))
2819 req
->data
.activatecallplane
.lineInstance
= htolel(l
->instance
);
2820 transmit_response(s
, req
);
2822 if (!(req
= req_alloc(sizeof(struct close_receive_channel_message
), CLOSE_RECEIVE_CHANNEL_MESSAGE
)))
2825 req
->data
.closereceivechannel
.conferenceId
= htolel(0);
2826 req
->data
.closereceivechannel
.partyId
= htolel(sub
->callid
);
2827 transmit_response(s
, req
);
2829 if (!(req
= req_alloc(sizeof(struct stop_media_transmission_message
), STOP_MEDIA_TRANSMISSION_MESSAGE
)))
2832 req
->data
.stopmedia
.conferenceId
= htolel(0);
2833 req
->data
.stopmedia
.passThruPartyId
= htolel(sub
->callid
);
2834 transmit_response(s
, req
);
2836 transmit_lamp_indication(s
, STIMULUS_LINE
, l
->instance
, SKINNY_LAMP_BLINK
);
2841 static int skinny_unhold(struct skinny_subchannel
*sub
)
2843 struct skinny_line
*l
= sub
->parent
;
2844 struct skinny_device
*d
= l
->parent
;
2845 struct skinnysession
*s
= d
->session
;
2846 struct skinny_req
*req
;
2848 /* Channel is on hold, so we will unhold */
2850 ast_verbose("Taking off Hold(%d)\n", l
->instance
);
2852 ast_queue_control(sub
->owner
, AST_CONTROL_UNHOLD
);
2854 if (!(req
= req_alloc(sizeof(struct activate_call_plane_message
), ACTIVATE_CALL_PLANE_MESSAGE
)))
2857 req
->data
.activatecallplane
.lineInstance
= htolel(l
->instance
);
2858 transmit_response(s
, req
);
2860 transmit_connect(s
, sub
);
2861 transmit_lamp_indication(s
, STIMULUS_LINE
, l
->instance
, SKINNY_LAMP_ON
);
2866 static int handle_keep_alive_message(struct skinny_req
*req
, struct skinnysession
*s
)
2868 if (!(req
= req_alloc(0, KEEP_ALIVE_ACK_MESSAGE
)))
2871 transmit_response(s
, req
);
2876 static int handle_register_message(struct skinny_req
*req
, struct skinnysession
*s
)
2881 memcpy(&name
, req
->data
.reg
.name
, sizeof(name
));
2883 res
= skinny_register(req
, s
);
2885 ast_log(LOG_ERROR
, "Rejecting Device %s: Device not found\n", name
);
2886 if (!(req
= req_alloc(sizeof(struct register_rej_message
), REGISTER_REJ_MESSAGE
)))
2889 snprintf(req
->data
.regrej
.errMsg
, sizeof(req
->data
.regrej
.errMsg
), "No Authority: %s", name
);
2890 transmit_response(s
, req
);
2893 if (option_verbose
> 2)
2894 ast_verbose(VERBOSE_PREFIX_3
"Device '%s' successfully registered\n", name
);
2896 if (!(req
= req_alloc(sizeof(struct register_ack_message
), REGISTER_ACK_MESSAGE
)))
2899 req
->data
.regack
.res
[0] = '0';
2900 req
->data
.regack
.res
[1] = '\0';
2901 req
->data
.regack
.keepAlive
= htolel(keep_alive
);
2902 ast_copy_string(req
->data
.regack
.dateTemplate
, date_format
, sizeof(req
->data
.regack
.dateTemplate
));
2903 req
->data
.regack
.res2
[0] = '0';
2904 req
->data
.regack
.res2
[1] = '\0';
2905 req
->data
.regack
.secondaryKeepAlive
= htolel(keep_alive
);
2906 transmit_response(s
, req
);
2908 ast_verbose("Requesting capabilities\n");
2910 if (!(req
= req_alloc(0, CAPABILITIES_REQ_MESSAGE
)))
2913 transmit_response(s
, req
);
2918 static int handle_ip_port_message(struct skinny_req
*req
, struct skinnysession
*s
)
2920 /* no response necessary */
2924 static int handle_keypad_button_message(struct skinny_req
*req
, struct skinnysession
*s
)
2926 struct skinny_subchannel
*sub
= NULL
;
2927 struct skinny_line
*l
;
2928 struct skinny_device
*d
= s
->device
;
2929 struct ast_frame f
= { 0, };
2935 digit
= letohl(req
->data
.keypad
.button
);
2936 lineInstance
= letohl(req
->data
.keypad
.lineInstance
);
2937 callReference
= letohl(req
->data
.keypad
.callReference
);
2941 } else if (digit
== 15) {
2943 } else if (digit
>= 0 && digit
<= 9) {
2946 /* digit=10-13 (A,B,C,D ?), or
2947 * digit is bad value
2949 * probably should not end up here, but set
2950 * value for backward compatibility, and log
2954 ast_log(LOG_WARNING
, "Unsupported digit %d\n", digit
);
2961 if (lineInstance
&& callReference
)
2962 sub
= find_subchannel_by_instance_reference(d
, lineInstance
, callReference
);
2964 sub
= find_subchannel_by_instance_reference(d
, d
->lastlineinstance
, d
->lastcallreference
);
2971 if (sub
->owner
->_state
== 0) {
2972 f
.frametype
= AST_FRAME_DTMF_BEGIN
;
2973 ast_queue_frame(sub
->owner
, &f
);
2975 /* XXX MUST queue this frame to all lines in threeway call if threeway call is active */
2976 f
.frametype
= AST_FRAME_DTMF_END
;
2977 ast_queue_frame(sub
->owner
, &f
);
2978 /* XXX This seriously needs to be fixed */
2979 if (sub
->next
&& sub
->next
->owner
) {
2980 if (sub
->owner
->_state
== 0) {
2981 f
.frametype
= AST_FRAME_DTMF_BEGIN
;
2982 ast_queue_frame(sub
->next
->owner
, &f
);
2984 f
.frametype
= AST_FRAME_DTMF_END
;
2985 ast_queue_frame(sub
->next
->owner
, &f
);
2989 ast_verbose("No owner: %s\n", l
->name
);
2994 static int handle_stimulus_message(struct skinny_req
*req
, struct skinnysession
*s
)
2996 struct skinny_device
*d
= s
->device
;
2997 struct skinny_line
*l
;
2998 struct skinny_subchannel
*sub
;
2999 /*struct skinny_speeddial *sd;*/
3000 struct ast_channel
*c
;
3007 event
= letohl(req
->data
.stimulus
.stimulus
);
3008 instance
= letohl(req
->data
.stimulus
.stimulusInstance
);
3009 unknown1
= letohl(req
->data
.stimulus
.unknown1
); /* No clue.. */
3011 ast_verbose("unknown1 in handle_stimulus_message is '%d'\n", unknown1
);
3013 sub
= find_subchannel_by_instance_reference(d
, d
->lastlineinstance
, d
->lastcallreference
);
3016 l
= find_line_by_instance(d
, d
->lastlineinstance
);
3025 case STIMULUS_REDIAL
:
3027 ast_verbose("Received Stimulus: Redial(%d)\n", instance
);
3030 c
= skinny_new(l
, AST_STATE_DOWN
);
3032 ast_log(LOG_WARNING
, "Unable to create channel for %s@%s\n", l
->name
, d
->name
);
3035 transmit_callstate(s
, l
->instance
, SKINNY_OFFHOOK
, sub
->callid
);
3037 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l
->name
, d
->name
);
3038 transmit_displaymessage(s
, NULL
); /* clear display */
3039 transmit_tone(s
, SKINNY_DIALTONE
);
3041 if (ast_strlen_zero(l
->lastnumberdialed
)) {
3042 ast_log(LOG_WARNING
, "Attempted redial, but no previously dialed number found.\n");
3045 if (!ast_ignore_pattern(c
->context
, l
->lastnumberdialed
)) {
3046 transmit_tone(s
, SKINNY_SILENCE
);
3048 ast_copy_string(c
->exten
, l
->lastnumberdialed
, sizeof(c
->exten
));
3049 if (ast_pthread_create(&t
, NULL
, skinny_newcall
, c
)) {
3050 ast_log(LOG_WARNING
, "Unable to create new call thread: %s\n", strerror(errno
));
3056 case STIMULUS_SPEEDDIAL
:
3058 ast_verbose("Received Stimulus: SpeedDial(%d)\n", instance
);
3061 if (!(sd
= find_speeddial_by_instance(d
, instance
))) {
3065 c
= skinny_new(l
, AST_STATE_DOWN
);
3069 transmit_callstate(s
, l
->instance
, SKINNY_OFFHOOK
, sub
->callid
);
3071 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l
->name
, d
->name
);
3072 transmit_displaymessage(s
, NULL
); /* clear display */
3073 transmit_tone(s
, SKINNY_DIALTONE
);
3075 if (!ast_ignore_pattern(c
->context
, sd
->exten
)) {
3076 transmit_tone(s
, SKINNY_SILENCE
);
3078 if (ast_exists_extension(c
, c
->context
, sd
->exten
, 1, l
->cid_num
)) {
3079 if (!ast_matchmore_extension(c
, c
->context
, sd
->exten
, 1, l
->cid_num
)) {
3080 ast_copy_string(c
->exten
, sd
->exten
, sizeof(c
->exten
));
3081 ast_copy_string(l
->lastnumberdialed
, sd
->exten
, sizeof(l
->lastnumberdialed
));
3087 ast_log(LOG_WARNING
, "Unable to create channel for %s@%s\n", l
->name
, d
->name
);
3093 ast_verbose("Received Stimulus: Hold(%d)\n", instance
);
3104 case STIMULUS_TRANSFER
:
3106 ast_verbose("Received Stimulus: Transfer(%d)\n", instance
);
3107 transmit_tone(s
, SKINNY_DIALTONE
);
3108 /* XXX figure out how to transfer */
3110 case STIMULUS_CONFERENCE
:
3112 ast_verbose("Received Stimulus: Conference(%d)\n", instance
);
3113 transmit_tone(s
, SKINNY_DIALTONE
);
3114 /* XXX determine the best way to pull off a conference. Meetme? */
3116 case STIMULUS_VOICEMAIL
:
3118 ast_verbose("Received Stimulus: Voicemail(%d)\n", instance
);
3119 /* XXX Find and dial voicemail extension */
3121 case STIMULUS_CALLPARK
:
3123 ast_verbose("Received Stimulus: Park Call(%d)\n", instance
);
3124 /* XXX Park the call */
3126 case STIMULUS_FORWARDALL
:
3128 ast_verbose("Received Stimulus: Forward All(%d)\n", instance
);
3129 /* Why is DND under FORWARDALL? */
3130 /* Because it's the same thing. */
3132 /* Do not disturb */
3133 transmit_tone(s
, SKINNY_DIALTONE
);
3135 if (option_verbose
> 2)
3136 ast_verbose(VERBOSE_PREFIX_3
"Disabling DND on %s@%s\n", l
->name
, d
->name
);
3138 transmit_lamp_indication(s
, STIMULUS_FORWARDALL
, 1, SKINNY_LAMP_ON
);
3139 transmit_displaynotify(s
, "DnD disabled", 10);
3141 if (option_verbose
> 2)
3142 ast_verbose(VERBOSE_PREFIX_3
"Enabling DND on %s@%s\n", l
->name
, d
->name
);
3144 transmit_lamp_indication(s
, STIMULUS_FORWARDALL
, 1, SKINNY_LAMP_OFF
);
3145 transmit_displaynotify(s
, "DnD enabled", 10);
3148 case STIMULUS_FORWARDBUSY
:
3150 ast_verbose("Received Stimulus: Forward Busy (%d)\n", instance
);
3152 case STIMULUS_FORWARDNOANSWER
:
3154 ast_verbose("Received Stimulus: Forward No Answer (%d)\n", instance
);
3156 case STIMULUS_DISPLAY
:
3157 /* Not sure what this is */
3159 ast_verbose("Received Stimulus: Display(%d)\n", instance
);
3163 ast_verbose("Received Stimulus: Line(%d)\n", instance
);
3165 l
= find_line_by_instance(s
->device
, instance
);
3171 /* turn the speaker on */
3172 transmit_speaker_mode(s
, SKINNY_SPEAKERON
);
3173 transmit_ringer_mode(s
, SKINNY_RING_OFF
);
3174 transmit_lamp_indication(s
, STIMULUS_LINE
, l
->instance
, SKINNY_LAMP_ON
);
3176 l
->hookstate
= SKINNY_OFFHOOK
;
3178 if (sub
&& sub
->outgoing
) {
3179 /* We're answering a ringing call */
3180 ast_queue_control(sub
->owner
, AST_CONTROL_ANSWER
);
3181 transmit_callstate(s
, l
->instance
, SKINNY_OFFHOOK
, sub
->callid
);
3182 transmit_tone(s
, SKINNY_SILENCE
);
3183 transmit_callstate(s
, l
->instance
, SKINNY_CONNECTED
, sub
->callid
);
3184 transmit_displaypromptstatus(s
, "Connected", 0, l
->instance
, sub
->callid
);
3185 transmit_selectsoftkeys(s
, l
->instance
, sub
->callid
, KEYDEF_CONNECTED
);
3187 ast_setstate(sub
->owner
, AST_STATE_UP
);
3189 if (sub
&& sub
->owner
) {
3190 ast_log(LOG_DEBUG
, "Current subchannel [%s] already has owner\n", sub
->owner
->name
);
3192 c
= skinny_new(l
, AST_STATE_DOWN
);
3195 transmit_callstate(s
, l
->instance
, SKINNY_OFFHOOK
, sub
->callid
);
3197 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l
->name
, d
->name
);
3198 transmit_displaymessage(s
, NULL
); /* clear display */
3199 transmit_tone(s
, SKINNY_DIALTONE
);
3200 transmit_selectsoftkeys(s
, l
->instance
, sub
->callid
, KEYDEF_OFFHOOK
);
3202 /* start the switch thread */
3203 if (ast_pthread_create(&t
, NULL
, skinny_ss
, c
)) {
3204 ast_log(LOG_WARNING
, "Unable to create switch thread: %s\n", strerror(errno
));
3208 ast_log(LOG_WARNING
, "Unable to create channel for %s@%s\n", l
->name
, d
->name
);
3215 ast_verbose("RECEIVED UNKNOWN STIMULUS: %d(%d)\n", event
, instance
);
3221 static int handle_offhook_message(struct skinny_req
*req
, struct skinnysession
*s
)
3223 struct skinny_device
*d
= s
->device
;
3224 struct skinny_line
*l
;
3225 struct skinny_subchannel
*sub
;
3226 struct ast_channel
*c
;
3231 unknown1
= letohl(req
->data
.offhook
.unknown1
);
3232 unknown2
= letohl(req
->data
.offhook
.unknown2
);
3234 sub
= find_subchannel_by_instance_reference(d
, d
->lastlineinstance
, d
->lastcallreference
);
3237 l
= find_line_by_instance(d
, d
->lastlineinstance
);
3245 if (sub
&& sub
->onhold
) {
3246 transmit_ringer_mode(s
, SKINNY_RING_OFF
);
3247 l
->hookstate
= SKINNY_OFFHOOK
;
3251 transmit_ringer_mode(s
, SKINNY_RING_OFF
);
3252 transmit_lamp_indication(s
, STIMULUS_LINE
, l
->instance
, SKINNY_LAMP_ON
);
3253 l
->hookstate
= SKINNY_OFFHOOK
;
3255 if (sub
&& sub
->outgoing
) {
3256 /* We're answering a ringing call */
3257 ast_queue_control(sub
->owner
, AST_CONTROL_ANSWER
);
3258 transmit_callstate(s
, l
->instance
, SKINNY_OFFHOOK
, sub
->callid
);
3259 transmit_tone(s
, SKINNY_SILENCE
);
3260 transmit_callstate(s
, l
->instance
, SKINNY_CONNECTED
, sub
->callid
);
3261 transmit_selectsoftkeys(s
, l
->instance
, sub
->callid
, KEYDEF_CONNECTED
);
3263 ast_setstate(sub
->owner
, AST_STATE_UP
);
3265 if (sub
&& sub
->owner
) {
3266 ast_log(LOG_DEBUG
, "Current sub [%s] already has owner\n", sub
->owner
->name
);
3268 c
= skinny_new(l
, AST_STATE_DOWN
);
3271 transmit_callstate(s
, l
->instance
, SKINNY_OFFHOOK
, sub
->callid
);
3273 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l
->name
, d
->name
);
3274 transmit_displaymessage(s
, NULL
); /* clear display */
3275 transmit_tone(s
, SKINNY_DIALTONE
);
3276 transmit_selectsoftkeys(s
, l
->instance
, sub
->callid
, KEYDEF_OFFHOOK
);
3278 /* start the switch thread */
3279 if (ast_pthread_create(&t
, NULL
, skinny_ss
, c
)) {
3280 ast_log(LOG_WARNING
, "Unable to create switch thread: %s\n", strerror(errno
));
3284 ast_log(LOG_WARNING
, "Unable to create channel for %s@%s\n", l
->name
, d
->name
);
3291 static int handle_onhook_message(struct skinny_req
*req
, struct skinnysession
*s
)
3293 struct skinny_device
*d
= s
->device
;
3294 struct skinny_line
*l
;
3295 struct skinny_subchannel
*sub
;
3299 unknown1
= letohl(req
->data
.onhook
.unknown1
);
3300 unknown2
= letohl(req
->data
.onhook
.unknown2
);
3302 sub
= find_subchannel_by_instance_reference(d
, d
->lastlineinstance
, d
->lastcallreference
);
3310 l
->hookstate
= SKINNY_ONHOOK
;
3314 if (l
->hookstate
== SKINNY_ONHOOK
) {
3315 /* Something else already put us back on hook */
3318 sub
->cxmode
= SKINNY_CX_RECVONLY
;
3319 l
->hookstate
= SKINNY_ONHOOK
;
3320 transmit_callstate(s
, l
->instance
, l
->hookstate
, sub
->callid
);
3322 ast_verbose("Skinny %s@%s went on hook\n", l
->name
, d
->name
);
3323 if (l
->transfer
&& (sub
->owner
&& sub
->next
&& sub
->next
->owner
) && ((!sub
->outgoing
) || (sub
->next
&& !sub
->next
->outgoing
))) {
3324 /* We're allowed to transfer, we have two active calls and
3325 we made at least one of the calls. Let's try and transfer */
3328 if ((res
= attempt_transfer(p
)) < 0) {
3329 if (sub
->next
&& sub
->next
->owner
) {
3330 sub
->next
->alreadygone
= 1;
3331 ast_queue_hangup(sub
->next
->owner
,1);
3334 ast_log(LOG_WARNING
, "Transfer attempt failed\n");
3339 /* Hangup the current call */
3340 /* If there is another active call, skinny_hangup will ring the phone with the other call */
3342 sub
->alreadygone
= 1;
3343 ast_queue_hangup(sub
->owner
);
3345 ast_log(LOG_WARNING
, "Skinny(%s@%s-%d) channel already destroyed\n",
3346 l
->name
, d
->name
, sub
->callid
);
3349 if ((l
->hookstate
== SKINNY_ONHOOK
) && (sub
->next
&& !sub
->next
->rtp
)) {
3355 static int handle_capabilities_res_message(struct skinny_req
*req
, struct skinnysession
*s
)
3357 struct skinny_device
*d
= s
->device
;
3358 struct skinny_line
*l
;
3363 count
= letohl(req
->data
.caps
.count
);
3365 for (i
= 0; i
< count
; i
++) {
3368 scodec
= letohl(req
->data
.caps
.caps
[i
].codec
);
3369 acodec
= codec_skinny2ast(scodec
);
3371 ast_verbose("Adding codec capability '%d (%d)'\n", acodec
, scodec
);
3375 d
->capability
&= codecs
;
3376 ast_verbose("Device capability set to '%d'\n", d
->capability
);
3377 for (l
= d
->lines
; l
; l
= l
->next
) {
3378 ast_mutex_lock(&l
->lock
);
3379 l
->capability
= d
->capability
;
3380 ast_mutex_unlock(&l
->lock
);
3386 static int handle_speed_dial_stat_req_message(struct skinny_req
*req
, struct skinnysession
*s
)
3388 struct skinny_device
*d
= s
->device
;
3389 struct skinny_speeddial
*sd
;
3392 instance
= letohl(req
->data
.speeddialreq
.speedDialNumber
);
3394 sd
= find_speeddial_by_instance(d
, instance
);
3400 if (!(req
= req_alloc(sizeof(struct speed_dial_stat_res_message
), SPEED_DIAL_STAT_RES_MESSAGE
)))
3403 req
->data
.speeddialreq
.speedDialNumber
= htolel(instance
);
3404 snprintf(req
->data
.speeddial
.speedDialDirNumber
, sizeof(req
->data
.speeddial
.speedDialDirNumber
), sd
->exten
);
3405 snprintf(req
->data
.speeddial
.speedDialDisplayName
, sizeof(req
->data
.speeddial
.speedDialDisplayName
), sd
->label
);
3407 transmit_response(s
, req
);
3411 static int handle_line_state_req_message(struct skinny_req
*req
, struct skinnysession
*s
)
3413 struct skinny_device
*d
= s
->device
;
3414 struct skinny_line
*l
;
3417 instance
= letohl(req
->data
.line
.lineNumber
);
3419 ast_mutex_lock(&devicelock
);
3421 l
= find_line_by_instance(d
, instance
);
3427 ast_mutex_unlock(&devicelock
);
3429 if (!(req
= req_alloc(sizeof(struct line_stat_res_message
), LINE_STAT_RES_MESSAGE
)))
3432 req
->data
.linestat
.lineNumber
= letohl(instance
);
3433 memcpy(req
->data
.linestat
.lineDirNumber
, l
->name
,
3434 sizeof(req
->data
.linestat
.lineDirNumber
));
3435 memcpy(req
->data
.linestat
.lineDisplayName
, l
->label
,
3436 sizeof(req
->data
.linestat
.lineDisplayName
));
3437 transmit_response(s
,req
);
3441 static int handle_time_date_req_message(struct skinny_req
*req
, struct skinnysession
*s
)
3446 if (!(req
= req_alloc(sizeof(struct definetimedate_message
), DEFINETIMEDATE_MESSAGE
)))
3450 cmtime
= localtime(&timer
);
3451 req
->data
.definetimedate
.year
= htolel(cmtime
->tm_year
+1900);
3452 req
->data
.definetimedate
.month
= htolel(cmtime
->tm_mon
+1);
3453 req
->data
.definetimedate
.dayofweek
= htolel(cmtime
->tm_wday
);
3454 req
->data
.definetimedate
.day
= htolel(cmtime
->tm_mday
);
3455 req
->data
.definetimedate
.hour
= htolel(cmtime
->tm_hour
);
3456 req
->data
.definetimedate
.minute
= htolel(cmtime
->tm_min
);
3457 req
->data
.definetimedate
.seconds
= htolel(cmtime
->tm_sec
);
3458 transmit_response(s
, req
);
3462 static int handle_button_template_req_message(struct skinny_req
*req
, struct skinnysession
*s
)
3464 struct skinny_device
*d
= s
->device
;
3465 struct skinny_line
*l
;
3468 struct skinny_speeddial
*sd
;
3469 struct button_definition_template btn
[42];
3470 int lineInstance
= 1;
3471 int speeddialInstance
= 1;
3472 int buttonCount
= 0;
3474 if (!(req
= req_alloc(sizeof(struct button_template_res_message
), BUTTON_TEMPLATE_RES_MESSAGE
)))
3477 memset(&btn
, 0, sizeof(btn
));
3479 get_button_template(s
, btn
);
3481 for (i
=0; i
<42; i
++) {
3483 switch (btn
[i
].buttonDefinition
) {
3484 case BT_CUST_LINESPEEDDIAL
:
3485 /* assume failure */
3486 req
->data
.buttontemplate
.definition
[i
].buttonDefinition
= BT_NONE
;
3487 req
->data
.buttontemplate
.definition
[i
].instanceNumber
= htolel(0);
3489 for (l
= d
->lines
; l
; l
= l
->next
) {
3490 if (l
->instance
== lineInstance
) {
3491 ast_verbose("Adding button: %d, %d\n", BT_LINE
, lineInstance
);
3492 req
->data
.buttontemplate
.definition
[i
].buttonDefinition
= BT_LINE
;
3493 req
->data
.buttontemplate
.definition
[i
].instanceNumber
= htolel(lineInstance
);
3502 for (sd
= d
->speeddials
; sd
; sd
= sd
->next
) {
3503 if (sd
->instance
== speeddialInstance
) {
3504 ast_verbose("Adding button: %d, %d\n", BT_SPEEDDIAL
, speeddialInstance
);
3505 req
->data
.buttontemplate
.definition
[i
].buttonDefinition
= BT_SPEEDDIAL
;
3506 req
->data
.buttontemplate
.definition
[i
].instanceNumber
= htolel(speeddialInstance
);
3507 speeddialInstance
++;
3516 req
->data
.buttontemplate
.definition
[i
].buttonDefinition
= htolel(BT_NONE
);
3517 req
->data
.buttontemplate
.definition
[i
].instanceNumber
= htolel(0);
3519 for (l
= d
->lines
; l
; l
= l
->next
) {
3520 if (l
->instance
== lineInstance
) {
3521 ast_verbose("Adding button: %d, %d\n", BT_LINE
, lineInstance
);
3522 req
->data
.buttontemplate
.definition
[i
].buttonDefinition
= BT_LINE
;
3523 req
->data
.buttontemplate
.definition
[i
].instanceNumber
= htolel(lineInstance
);
3532 req
->data
.buttontemplate
.definition
[i
].buttonDefinition
= BT_NONE
;
3533 req
->data
.buttontemplate
.definition
[i
].instanceNumber
= 0;
3535 for (sd
= d
->speeddials
; sd
; sd
= sd
->next
) {
3536 if (sd
->instance
== speeddialInstance
) {
3537 ast_verbose("Adding button: %d, %d\n", BT_SPEEDDIAL
, speeddialInstance
);
3538 req
->data
.buttontemplate
.definition
[i
].buttonDefinition
= BT_SPEEDDIAL
;
3539 req
->data
.buttontemplate
.definition
[i
].instanceNumber
= htolel(speeddialInstance
);
3540 speeddialInstance
++;
3552 ast_verbose("Adding button: %d, %d\n", btn
[i
].buttonDefinition
, 0);
3553 req
->data
.buttontemplate
.definition
[i
].buttonDefinition
= htolel(btn
[i
].buttonDefinition
);
3554 req
->data
.buttontemplate
.definition
[i
].instanceNumber
= htolel(0);
3561 req
->data
.buttontemplate
.buttonOffset
= htolel(0);
3562 req
->data
.buttontemplate
.buttonCount
= htolel(buttonCount
);
3563 req
->data
.buttontemplate
.totalButtonCount
= htolel(buttonCount
);
3566 ast_verbose("Sending %d template to %s\n",
3569 transmit_response(s
, req
);
3573 static int handle_version_req_message(struct skinny_req
*req
, struct skinnysession
*s
)
3575 struct skinny_device
*d
= s
->device
;
3576 if (!(req
= req_alloc(sizeof(struct version_res_message
), VERSION_RES_MESSAGE
)))
3579 snprintf(req
->data
.version
.version
, sizeof(req
->data
.version
.version
), d
->version_id
);
3580 transmit_response(s
, req
);
3584 static int handle_server_request_message(struct skinny_req
*req
, struct skinnysession
*s
)
3586 struct skinny_device
*d
= s
->device
;
3587 if (!(req
= req_alloc(sizeof(struct server_res_message
), SERVER_RES_MESSAGE
)))
3590 memcpy(req
->data
.serverres
.server
[0].serverName
, ourhost
,
3591 sizeof(req
->data
.serverres
.server
[0].serverName
));
3592 req
->data
.serverres
.serverListenPort
[0] = htolel(ourport
);
3593 req
->data
.serverres
.serverIpAddr
[0] = htolel(d
->ourip
.s_addr
);
3594 transmit_response(s
, req
);
3598 static int handle_alarm_message(struct skinny_req
*req
, struct skinnysession
*s
)
3600 /* no response necessary */
3602 ast_verbose("Received Alarm Message: %s\n", req
->data
.alarm
.displayMessage
);
3607 static int handle_open_receive_channel_ack_message(struct skinny_req
*req
, struct skinnysession
*s
)
3609 struct skinny_device
*d
= s
->device
;
3610 struct skinny_line
*l
;
3611 struct skinny_subchannel
*sub
;
3612 struct ast_format_list fmt
;
3613 struct sockaddr_in sin
;
3614 struct sockaddr_in us
;
3620 status
= letohl(req
->data
.openreceivechannelack
.status
);
3622 ast_log(LOG_ERROR
, "Open Receive Channel Failure\n");
3625 addr
= letohl(req
->data
.openreceivechannelack
.ipAddr
);
3626 port
= letohl(req
->data
.openreceivechannelack
.port
);
3627 passthruid
= letohl(req
->data
.openreceivechannelack
.passThruId
);
3629 sin
.sin_family
= AF_INET
;
3630 sin
.sin_addr
.s_addr
= addr
;
3631 sin
.sin_port
= htons(port
);
3633 sub
= find_subchannel_by_reference(d
, passthruid
);
3641 ast_rtp_set_peer(sub
->rtp
, &sin
);
3642 ast_rtp_get_us(sub
->rtp
, &us
);
3644 ast_log(LOG_ERROR
, "No RTP structure, this is very bad\n");
3649 ast_verbose("ipaddr = %s:%d\n", ast_inet_ntoa(sin
.sin_addr
), ntohs(sin
.sin_port
));
3650 ast_verbose("ourip = %s:%d\n", ast_inet_ntoa(d
->ourip
), ntohs(us
.sin_port
));
3653 if (!(req
= req_alloc(sizeof(struct start_media_transmission_message
), START_MEDIA_TRANSMISSION_MESSAGE
)))
3656 fmt
= ast_codec_pref_getsize(&l
->prefs
, ast_best_codec(l
->capability
));
3659 ast_verbose("Setting payloadType to '%d' (%d ms)\n", fmt
.bits
, fmt
.cur_ms
);
3661 req
->data
.startmedia
.conferenceId
= htolel(0);
3662 req
->data
.startmedia
.passThruPartyId
= htolel(sub
->callid
);
3663 req
->data
.startmedia
.remoteIp
= htolel(d
->ourip
.s_addr
);
3664 req
->data
.startmedia
.remotePort
= htolel(ntohs(us
.sin_port
));
3665 req
->data
.startmedia
.packetSize
= htolel(fmt
.cur_ms
);
3666 req
->data
.startmedia
.payloadType
= htolel(codec_ast2skinny(fmt
.bits
));
3667 req
->data
.startmedia
.qualifier
.precedence
= htolel(127);
3668 req
->data
.startmedia
.qualifier
.vad
= htolel(0);
3669 req
->data
.startmedia
.qualifier
.packets
= htolel(0);
3670 req
->data
.startmedia
.qualifier
.bitRate
= htolel(0);
3671 transmit_response(s
, req
);
3676 static int handle_soft_key_set_req_message(struct skinny_req
*req
, struct skinnysession
*s
)
3681 const struct soft_key_definitions
*softkeymode
= soft_key_default_definitions
;
3683 if (!(req
= req_alloc(sizeof(struct soft_key_set_res_message
), SOFT_KEY_SET_RES_MESSAGE
)))
3686 req
->data
.softkeysets
.softKeySetOffset
= htolel(0);
3687 req
->data
.softkeysets
.softKeySetCount
= htolel(11);
3688 req
->data
.softkeysets
.totalSoftKeySetCount
= htolel(11);
3689 for (x
= 0; x
< sizeof(soft_key_default_definitions
) / sizeof(struct soft_key_definitions
); x
++) {
3690 const uint8_t *defaults
= softkeymode
->defaults
;
3691 /* XXX I wanted to get the size of the array dynamically, but that wasn't wanting to work.
3692 This will have to do for now. */
3693 for (y
= 0; y
< softkeymode
->count
; y
++) {
3694 for (i
= 0; i
< (sizeof(soft_key_template_default
) / sizeof(struct soft_key_template_definition
)); i
++) {
3695 if (defaults
[y
] == i
+1) {
3696 req
->data
.softkeysets
.softKeySetDefinition
[softkeymode
->mode
].softKeyTemplateIndex
[y
] = htolel(i
+1);
3702 transmit_response(s
,req
);
3703 transmit_selectsoftkeys(s
, 0, 0, KEYDEF_ONHOOK
);
3707 static int handle_soft_key_event_message(struct skinny_req
*req
, struct skinnysession
*s
)
3709 struct skinny_device
*d
= s
->device
;
3710 struct skinny_line
*l
;
3711 struct skinny_subchannel
*sub
= NULL
;
3712 struct ast_channel
*c
;
3718 event
= letohl(req
->data
.softkeyeventmessage
.softKeyEvent
);
3719 instance
= letohl(req
->data
.softkeyeventmessage
.instance
);
3720 reference
= letohl(req
->data
.softkeyeventmessage
.reference
);
3723 l
= find_line_by_instance(d
, instance
);
3725 sub
= find_subchannel_by_instance_reference(d
, instance
, reference
);
3727 sub
= find_subchannel_by_instance_reference(d
, instance
, d
->lastcallreference
);
3730 l
= find_line_by_instance(d
, d
->lastlineinstance
);
3735 ast_verbose("Received Softkey Event: %d(%d)\n", event
, instance
);
3742 ast_verbose("Received Softkey Event: None(%d)\n", instance
);
3744 case SOFTKEY_REDIAL
:
3746 ast_verbose("Received Softkey Event: Redial(%d)\n", instance
);
3749 if (!sub
|| !sub
->owner
) {
3750 c
= skinny_new(l
, AST_STATE_DOWN
);
3756 ast_log(LOG_WARNING
, "Unable to create channel for %s@%s\n", l
->name
, d
->name
);
3759 transmit_callstate(s
, l
->instance
, SKINNY_OFFHOOK
, sub
->callid
);
3761 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l
->name
, d
->name
);
3762 transmit_displaymessage(s
, NULL
); /* clear display */
3763 transmit_tone(s
, SKINNY_DIALTONE
);
3765 if (ast_strlen_zero(l
->lastnumberdialed
)) {
3766 ast_log(LOG_WARNING
, "Attempted redial, but no previously dialed number found.\n");
3769 if (!ast_ignore_pattern(c
->context
, l
->lastnumberdialed
)) {
3770 transmit_tone(s
, SKINNY_SILENCE
);
3772 ast_copy_string(c
->exten
, l
->lastnumberdialed
, sizeof(c
->exten
));
3773 if (ast_pthread_create(&t
, NULL
, skinny_newcall
, c
)) {
3774 ast_log(LOG_WARNING
, "Unable to create new call thread: %s\n", strerror(errno
));
3780 case SOFTKEY_NEWCALL
:
3783 ast_verbose("Received Softkey Event: New Call(%d)\n", instance
);
3785 transmit_ringer_mode(s
,SKINNY_RING_OFF
);
3786 transmit_lamp_indication(s
, STIMULUS_LINE
, l
->instance
, SKINNY_LAMP_ON
);
3788 l
->hookstate
= SKINNY_OFFHOOK
;
3791 transmit_callstate(s
, l
->instance
, SKINNY_OFFHOOK
, sub
->callid
);
3793 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l
->name
, d
->name
);
3794 transmit_displaymessage(s
, NULL
); /* clear display */
3795 transmit_tone(s
, SKINNY_DIALTONE
);
3796 transmit_selectsoftkeys(s
, l
->instance
, sub
->callid
, KEYDEF_OFFHOOK
);
3797 c
= skinny_new(l
, AST_STATE_DOWN
);
3799 /* start the switch thread */
3800 if (ast_pthread_create(&t
, NULL
, skinny_ss
, c
)) {
3801 ast_log(LOG_WARNING
, "Unable to create switch thread: %s\n", strerror(errno
));
3805 ast_log(LOG_WARNING
, "Unable to create channel for %s@%s\n", l
->name
, d
->name
);
3811 ast_verbose("Received Softkey Event: Hold(%d)\n", instance
);
3822 case SOFTKEY_TRNSFER
:
3824 ast_verbose("Received Softkey Event: Transfer(%d)\n", instance
);
3825 transmit_tone(s
, SKINNY_DIALTONE
);
3826 /* XXX figure out how to transfer */
3828 case SOFTKEY_CFWDALL
:
3830 ast_verbose("Received Softkey Event: Forward All(%d)\n", instance
);
3832 /* Do not disturb */
3833 transmit_tone(s
, SKINNY_DIALTONE
);
3835 if (option_verbose
> 2)
3836 ast_verbose(VERBOSE_PREFIX_3
"Disabling DND on %s@%s\n", l
->name
, d
->name
);
3838 transmit_lamp_indication(s
, STIMULUS_FORWARDALL
, 1, SKINNY_LAMP_ON
);
3839 transmit_displaynotify(s
, "DnD disabled", 10);
3841 if (option_verbose
> 2)
3842 ast_verbose(VERBOSE_PREFIX_3
"Enabling DND on %s@%s\n", l
->name
, d
->name
);
3844 transmit_lamp_indication(s
, STIMULUS_FORWARDALL
, 1, SKINNY_LAMP_OFF
);
3845 transmit_displaynotify(s
, "DnD enabled", 10);
3848 case SOFTKEY_CFWDBUSY
:
3850 ast_verbose("Received Softkey Event: Forward Busy (%d)\n", instance
);
3852 case SOFTKEY_CFWDNOANSWER
:
3854 ast_verbose("Received Softkey Event: Forward No Answer (%d)\n", instance
);
3858 ast_verbose("Received Softkey Event: Backspace(%d)\n", instance
);
3860 case SOFTKEY_ENDCALL
:
3862 ast_verbose("Received Softkey Event: End Call(%d)\n", instance
);
3864 if (l
->hookstate
== SKINNY_ONHOOK
) {
3865 /* Something else already put us back on hook */
3869 sub
->cxmode
= SKINNY_CX_RECVONLY
;
3870 l
->hookstate
= SKINNY_ONHOOK
;
3871 transmit_callstate(s
, l
->instance
, l
->hookstate
, sub
->callid
);
3873 ast_verbose("Skinny %s@%s went on hook\n", l
->name
, d
->name
);
3874 if (l
->transfer
&& (sub
->owner
&& sub
->next
&& sub
->next
->owner
) && ((!sub
->outgoing
) || (sub
->next
&& !sub
->next
->outgoing
))) {
3875 /* We're allowed to transfer, we have two active calls and
3876 we made at least one of the calls. Let's try and transfer */
3879 if ((res
= attempt_transfer(p
)) < 0) {
3880 if (sub
->next
&& sub
->next
->owner
) {
3881 sub
->next
->alreadygone
= 1;
3882 ast_queue_hangup(sub
->next
->owner
, 1);
3885 ast_log(LOG_WARNING
, "Transfer attempt failed\n");
3890 /* Hangup the current call */
3891 /* If there is another active call, skinny_hangup will ring the phone with the other call */
3893 sub
->alreadygone
= 1;
3894 ast_queue_hangup(sub
->owner
);
3896 ast_log(LOG_WARNING
, "Skinny(%s@%s-%d) channel already destroyed\n",
3897 l
->name
, d
->name
, sub
->callid
);
3900 if ((l
->hookstate
== SKINNY_ONHOOK
) && (sub
->next
&& !sub
->next
->rtp
)) {
3905 case SOFTKEY_RESUME
:
3907 ast_verbose("Received Softkey Event: Resume(%d)\n", instance
);
3909 case SOFTKEY_ANSWER
:
3911 ast_verbose("Received Softkey Event: Answer(%d)\n", instance
);
3913 transmit_ringer_mode(s
,SKINNY_RING_OFF
);
3914 transmit_lamp_indication(s
, STIMULUS_LINE
, l
->instance
, SKINNY_LAMP_ON
);
3916 l
->hookstate
= SKINNY_OFFHOOK
;
3918 if (sub
&& sub
->outgoing
) {
3919 /* We're answering a ringing call */
3920 ast_queue_control(sub
->owner
, AST_CONTROL_ANSWER
);
3921 transmit_callstate(s
, l
->instance
, SKINNY_OFFHOOK
, sub
->callid
);
3922 transmit_tone(s
, SKINNY_SILENCE
);
3923 transmit_callstate(s
, l
->instance
, SKINNY_CONNECTED
, sub
->callid
);
3924 transmit_selectsoftkeys(s
, l
->instance
, sub
->callid
, KEYDEF_CONNECTED
);
3926 ast_setstate(sub
->owner
, AST_STATE_UP
);
3931 ast_verbose("Received Softkey Event: Info(%d)\n", instance
);
3933 case SOFTKEY_CONFRN
:
3935 ast_verbose("Received Softkey Event: Transfer(%d)\n", instance
);
3936 transmit_tone(s
, SKINNY_DIALTONE
);
3937 /* XXX determine the best way to pull off a conference. Meetme? */
3941 ast_verbose("Received Softkey Event: Park Call(%d)\n", instance
);
3942 /* XXX Park the call */
3946 ast_verbose("Received Softkey Event: Join(%d)\n", instance
);
3948 case SOFTKEY_MEETME
:
3949 /* XXX How is this different from CONFRN? */
3951 ast_verbose("Received Softkey Event: Meetme(%d)\n", instance
);
3953 case SOFTKEY_PICKUP
:
3955 ast_verbose("Received Softkey Event: None(%d)\n", instance
);
3957 case SOFTKEY_GPICKUP
:
3959 ast_verbose("Received Softkey Event: Group Pickup (%d)\n", instance
);
3963 ast_verbose("Received unknown Softkey Event: %d(%d)\n", event
, instance
);
3969 static int handle_unregister_message(struct skinny_req
*req
, struct skinnysession
*s
)
3971 return skinny_unregister(req
, s
);
3974 static int handle_soft_key_template_req_message(struct skinny_req
*req
, struct skinnysession
*s
)
3976 if (!(req
= req_alloc(sizeof(struct soft_key_template_res_message
), SOFT_KEY_TEMPLATE_RES_MESSAGE
)))
3979 req
->data
.softkeytemplate
.softKeyOffset
= htolel(0);
3980 req
->data
.softkeytemplate
.softKeyCount
= htolel(sizeof(soft_key_template_default
) / sizeof(struct soft_key_template_definition
));
3981 req
->data
.softkeytemplate
.totalSoftKeyCount
= htolel(sizeof(soft_key_template_default
) / sizeof(struct soft_key_template_definition
));
3982 memcpy(req
->data
.softkeytemplate
.softKeyTemplateDefinition
,
3983 soft_key_template_default
,
3984 sizeof(soft_key_template_default
));
3985 transmit_response(s
,req
);
3989 static int handle_headset_status_message(struct skinny_req
*req
, struct skinnysession
*s
)
3991 /* XXX umm...okay? Why do I care? */
3995 static int handle_register_available_lines_message(struct skinny_req
*req
, struct skinnysession
*s
)
3997 /* XXX I have no clue what this is for, but my phone was sending it, so... */
4001 static int handle_message(struct skinny_req
*req
, struct skinnysession
*s
)
4005 if ((!s
->device
) && (letohl(req
->e
) != REGISTER_MESSAGE
&& letohl(req
->e
) != ALARM_MESSAGE
)) {
4006 ast_log(LOG_WARNING
, "Client sent message #%d without first registering.\n", req
->e
);
4011 switch(letohl(req
->e
)) {
4012 case KEEP_ALIVE_MESSAGE
:
4013 res
= handle_keep_alive_message(req
, s
);
4015 case REGISTER_MESSAGE
:
4017 ast_verbose("Device %s is attempting to register\n", req
->data
.reg
.name
);
4019 res
= handle_register_message(req
, s
);
4021 case IP_PORT_MESSAGE
:
4022 res
= handle_ip_port_message(req
, s
);
4024 case KEYPAD_BUTTON_MESSAGE
:
4026 ast_verbose("Collected digit: [%d]\n", letohl(req
->data
.keypad
.button
));
4028 res
= handle_keypad_button_message(req
, s
);
4030 case STIMULUS_MESSAGE
:
4031 res
= handle_stimulus_message(req
, s
);
4033 case OFFHOOK_MESSAGE
:
4034 res
= handle_offhook_message(req
, s
);
4036 case ONHOOK_MESSAGE
:
4037 res
= handle_onhook_message(req
, s
);
4039 case CAPABILITIES_RES_MESSAGE
:
4041 ast_verbose("Received CapabilitiesRes\n");
4043 res
= handle_capabilities_res_message(req
, s
);
4045 case SPEED_DIAL_STAT_REQ_MESSAGE
:
4047 ast_verbose("Received SpeedDialStatRequest\n");
4049 res
= handle_speed_dial_stat_req_message(req
, s
);
4051 case LINE_STATE_REQ_MESSAGE
:
4052 res
= handle_line_state_req_message(req
, s
);
4054 case TIME_DATE_REQ_MESSAGE
:
4056 ast_verbose("Received Time/Date Request\n");
4058 res
= handle_time_date_req_message(req
, s
);
4060 case BUTTON_TEMPLATE_REQ_MESSAGE
:
4062 ast_verbose("Buttontemplate requested\n");
4064 res
= handle_button_template_req_message(req
, s
);
4066 case VERSION_REQ_MESSAGE
:
4068 ast_verbose("Version Request\n");
4070 res
= handle_version_req_message(req
, s
);
4072 case SERVER_REQUEST_MESSAGE
:
4074 ast_verbose("Received Server Request\n");
4076 res
= handle_server_request_message(req
, s
);
4079 res
= handle_alarm_message(req
, s
);
4081 case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE
:
4083 ast_verbose("Received Open Receive Channel Ack\n");
4085 res
= handle_open_receive_channel_ack_message(req
, s
);
4087 case SOFT_KEY_SET_REQ_MESSAGE
:
4089 ast_verbose("Received SoftKeySetReq\n");
4091 res
= handle_soft_key_set_req_message(req
, s
);
4093 case SOFT_KEY_EVENT_MESSAGE
:
4094 res
= handle_soft_key_event_message(req
, s
);
4096 case UNREGISTER_MESSAGE
:
4098 ast_verbose("Received Unregister Request\n");
4100 res
= handle_unregister_message(req
, s
);
4102 case SOFT_KEY_TEMPLATE_REQ_MESSAGE
:
4104 ast_verbose("Received SoftKey Template Request\n");
4106 res
= handle_soft_key_template_req_message(req
, s
);
4108 case HEADSET_STATUS_MESSAGE
:
4109 res
= handle_headset_status_message(req
, s
);
4111 case REGISTER_AVAILABLE_LINES_MESSAGE
:
4112 res
= handle_register_available_lines_message(req
, s
);
4116 ast_verbose("RECEIVED UNKNOWN MESSAGE TYPE: %x\n", letohl(req
->e
));
4119 if (res
>= 0 && req
)
4124 static void destroy_session(struct skinnysession
*s
)
4126 struct skinnysession
*cur
, *prev
= NULL
;
4127 ast_mutex_lock(&sessionlock
);
4138 prev
->next
= cur
->next
;
4140 sessions
= cur
->next
;
4145 ast_mutex_destroy(&s
->lock
);
4148 ast_log(LOG_WARNING
, "Trying to delete nonexistent session %p?\n", s
);
4150 ast_mutex_unlock(&sessionlock
);
4153 static int get_input(struct skinnysession
*s
)
4157 struct pollfd fds
[1];
4160 fds
[0].events
= POLLIN
;
4162 res
= poll(fds
, 1, -1);
4167 ast_log(LOG_WARNING
, "Select returned error: %s\n", strerror(errno
));
4171 if (fds
[0].revents
) {
4172 ast_mutex_lock(&s
->lock
);
4173 memset(s
->inbuf
,0,sizeof(s
->inbuf
));
4174 res
= read(s
->fd
, s
->inbuf
, 4);
4176 ast_log(LOG_WARNING
, "read() returned error: %s\n", strerror(errno
));
4179 ast_verbose("Skinny Client was lost, unregistering\n");
4181 skinny_unregister(NULL
,s
);
4182 ast_mutex_unlock(&s
->lock
);
4184 } else if (res
!= 4) {
4185 ast_log(LOG_WARNING
, "Skinny Client sent less data than expected. Expected 4 but got %d.\n", res
);
4186 ast_mutex_unlock(&s
->lock
);
4190 ast_verbose("Skinny Client was lost, unregistering\n");
4191 skinny_unregister(NULL
, s
);
4197 dlen
= letohl(*(int *)s
->inbuf
);
4199 ast_log(LOG_WARNING
, "Skinny Client sent invalid data.\n");
4200 ast_mutex_unlock(&s
->lock
);
4203 if (dlen
+8 > sizeof(s
->inbuf
)) {
4204 dlen
= sizeof(s
->inbuf
) - 8;
4206 *(int *)s
->inbuf
= htolel(dlen
);
4208 res
= read(s
->fd
, s
->inbuf
+4, dlen
+4);
4209 ast_mutex_unlock(&s
->lock
);
4211 ast_log(LOG_WARNING
, "read() returned error: %s\n", strerror(errno
));
4213 } else if (res
!= (dlen
+4)) {
4214 ast_log(LOG_WARNING
, "Skinny Client sent less data than expected.\n");
4222 static struct skinny_req
*skinny_req_parse(struct skinnysession
*s
)
4224 struct skinny_req
*req
;
4226 if (!(req
= ast_calloc(1, SKINNY_MAX_PACKET
)))
4229 ast_mutex_lock(&s
->lock
);
4230 memcpy(req
, s
->inbuf
, skinny_header_size
);
4231 memcpy(&req
->data
, s
->inbuf
+skinny_header_size
, letohl(*(int*)(s
->inbuf
))-4);
4233 ast_mutex_unlock(&s
->lock
);
4235 if (letohl(req
->e
) < 0) {
4236 ast_log(LOG_ERROR
, "Event Message is NULL from socket %d, This is bad\n", s
->fd
);
4244 static void *skinny_session(void *data
)
4247 struct skinny_req
*req
;
4248 struct skinnysession
*s
= data
;
4250 if (option_verbose
> 2)
4251 ast_verbose(VERBOSE_PREFIX_3
"Starting Skinny session from %s\n", ast_inet_ntoa(s
->sin
.sin_addr
));
4261 if (!(req
= skinny_req_parse(s
))) {
4266 res
= handle_message(req
, s
);
4273 ast_log(LOG_NOTICE
, "Skinny Session returned: %s\n", strerror(errno
));
4281 static void *accept_thread(void *ignore
)
4284 struct sockaddr_in sin
;
4286 struct skinnysession
*s
;
4289 pthread_attr_t attr
;
4290 pthread_t tcp_thread
;
4292 pthread_attr_init(&attr
);
4293 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
4296 sinlen
= sizeof(sin
);
4297 as
= accept(skinnysock
, (struct sockaddr
*)&sin
, &sinlen
);
4299 ast_log(LOG_NOTICE
, "Accept returned -1: %s\n", strerror(errno
));
4302 p
= getprotobyname("tcp");
4304 if( setsockopt(as
, p
->p_proto
, TCP_NODELAY
, (char *)&arg
, sizeof(arg
) ) < 0 ) {
4305 ast_log(LOG_WARNING
, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno
));
4308 if (!(s
= ast_calloc(1, sizeof(struct skinnysession
))))
4311 memcpy(&s
->sin
, &sin
, sizeof(sin
));
4312 ast_mutex_init(&s
->lock
);
4314 ast_mutex_lock(&sessionlock
);
4317 ast_mutex_unlock(&sessionlock
);
4319 if (ast_pthread_create(&tcp_thread
, &attr
, skinny_session
, s
)) {
4324 ast_verbose("killing accept thread\n");
4326 pthread_attr_destroy(&attr
);
4330 static void *do_monitor(void *data
)
4334 /* This thread monitors all the interfaces which are not yet in use
4335 (and thus do not have a separate thread) indefinitely */
4336 /* From here on out, we die whenever asked */
4338 pthread_testcancel();
4339 /* Wait for sched or io */
4340 res
= ast_sched_wait(sched
);
4341 if ((res
< 0) || (res
> 1000)) {
4344 res
= ast_io_wait(io
, res
);
4345 ast_mutex_lock(&monlock
);
4347 ast_sched_runq(sched
);
4349 ast_mutex_unlock(&monlock
);
4356 static int restart_monitor(void)
4358 /* If we're supposed to be stopped -- stay stopped */
4359 if (monitor_thread
== AST_PTHREADT_STOP
)
4362 ast_mutex_lock(&monlock
);
4363 if (monitor_thread
== pthread_self()) {
4364 ast_mutex_unlock(&monlock
);
4365 ast_log(LOG_WARNING
, "Cannot kill myself\n");
4368 if (monitor_thread
!= AST_PTHREADT_NULL
) {
4369 /* Wake up the thread */
4370 pthread_kill(monitor_thread
, SIGURG
);
4372 /* Start a new monitor */
4373 if (ast_pthread_create_background(&monitor_thread
, NULL
, do_monitor
, NULL
) < 0) {
4374 ast_mutex_unlock(&monlock
);
4375 ast_log(LOG_ERROR
, "Unable to start monitor thread.\n");
4379 ast_mutex_unlock(&monlock
);
4383 static struct ast_channel
*skinny_request(const char *type
, int format
, void *data
, int *cause
)
4387 struct skinny_line
*l
;
4388 struct ast_channel
*tmpc
= NULL
;
4394 if (!(format
&= ((AST_FORMAT_MAX_AUDIO
<< 1) - 1))) {
4395 ast_log(LOG_NOTICE
, "Asked to get a channel of unsupported format '%d'\n", format
);
4399 ast_copy_string(tmp
, dest
, sizeof(tmp
));
4400 if (ast_strlen_zero(tmp
)) {
4401 ast_log(LOG_NOTICE
, "Skinny channels require a device\n");
4404 l
= find_line_by_name(tmp
);
4406 ast_log(LOG_NOTICE
, "No available lines on: %s\n", dest
);
4409 if (option_verbose
> 2) {
4410 ast_verbose(VERBOSE_PREFIX_3
"skinny_request(%s)\n", tmp
);
4412 tmpc
= skinny_new(l
, AST_STATE_DOWN
);
4414 ast_log(LOG_WARNING
, "Unable to make channel for '%s'\n", tmp
);
4420 static int reload_config(void)
4423 struct ast_config
*cfg
;
4424 struct ast_variable
*v
;
4426 struct skinny_device
*d
;
4427 int oldport
= ntohs(bindaddr
.sin_port
);
4429 if (gethostname(ourhost
, sizeof(ourhost
))) {
4430 ast_log(LOG_WARNING
, "Unable to get hostname, Skinny disabled\n");
4433 cfg
= ast_config_load(config
);
4435 /* We *must* have a config file otherwise stop immediately */
4437 ast_log(LOG_NOTICE
, "Unable to load config %s, Skinny disabled\n", config
);
4440 memset(&bindaddr
, 0, sizeof(bindaddr
));
4441 memset(&default_prefs
, 0, sizeof(default_prefs
));
4443 /* Copy the default jb config over global_jbconf */
4444 memcpy(&global_jbconf
, &default_jbconf
, sizeof(struct ast_jb_conf
));
4446 /* load the general section */
4447 v
= ast_variable_browse(cfg
, "general");
4449 /* handle jb conf */
4450 if (!ast_jb_read_conf(&global_jbconf
, v
->name
, v
->value
)) {
4455 /* Create the interface list */
4456 if (!strcasecmp(v
->name
, "bindaddr")) {
4457 if (!(hp
= ast_gethostbyname(v
->value
, &ahp
))) {
4458 ast_log(LOG_WARNING
, "Invalid address: %s\n", v
->value
);
4460 memcpy(&bindaddr
.sin_addr
, hp
->h_addr
, sizeof(bindaddr
.sin_addr
));
4462 } else if (!strcasecmp(v
->name
, "keepalive")) {
4463 keep_alive
= atoi(v
->value
);
4464 } else if (!strcasecmp(v
->name
, "dateformat")) {
4465 ast_copy_string(date_format
, v
->value
, sizeof(date_format
));
4466 } else if (!strcasecmp(v
->name
, "allow")) {
4467 ast_parse_allow_disallow(&default_prefs
, &default_capability
, v
->value
, 1);
4468 } else if (!strcasecmp(v
->name
, "disallow")) {
4469 ast_parse_allow_disallow(&default_prefs
, &default_capability
, v
->value
, 0);
4470 } else if (!strcasecmp(v
->name
, "bindport") || !strcasecmp(v
->name
, "port")) {
4471 if (sscanf(v
->value
, "%d", &ourport
) == 1) {
4472 bindaddr
.sin_port
= htons(ourport
);
4474 ast_log(LOG_WARNING
, "Invalid bindport '%s' at line %d of %s\n", v
->value
, v
->lineno
, config
);
4476 if (!strcasecmp(v
->name
, "port")) { /*! \todo Remove 'port' option after 1.4 */
4477 ast_log(LOG_WARNING
, "Option 'port' at line %d of %s has been deprecated. Please use 'bindport' instead.\n", v
->lineno
, config
);
4483 if (ntohl(bindaddr
.sin_addr
.s_addr
)) {
4484 __ourip
= bindaddr
.sin_addr
;
4486 hp
= ast_gethostbyname(ourhost
, &ahp
);
4488 ast_log(LOG_WARNING
, "Unable to get our IP address, Skinny disabled\n");
4489 ast_config_destroy(cfg
);
4492 memcpy(&__ourip
, hp
->h_addr
, sizeof(__ourip
));
4494 if (!ntohs(bindaddr
.sin_port
)) {
4495 bindaddr
.sin_port
= ntohs(DEFAULT_SKINNY_PORT
);
4497 bindaddr
.sin_family
= AF_INET
;
4499 /* load the device sections */
4500 cat
= ast_category_browse(cfg
, NULL
);
4502 if (!strcasecmp(cat
, "general")) {
4505 } else if (!strncasecmp(cat
, "paging-", 7)) {
4506 p
= build_paging_device(cat
, ast_variable_browse(cfg
, cat
));
4511 d
= build_device(cat
, ast_variable_browse(cfg
, cat
));
4513 if (option_verbose
> 2)
4514 ast_verbose(VERBOSE_PREFIX_3
"Added device '%s'\n", d
->name
);
4515 ast_mutex_lock(&devicelock
);
4518 ast_mutex_unlock(&devicelock
);
4521 cat
= ast_category_browse(cfg
, cat
);
4523 ast_mutex_lock(&netlock
);
4524 if ((skinnysock
> -1) && (ntohs(bindaddr
.sin_port
) != oldport
)) {
4528 if (skinnysock
< 0) {
4529 skinnysock
= socket(AF_INET
, SOCK_STREAM
, 0);
4530 if(setsockopt(skinnysock
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) == -1) {
4531 ast_log(LOG_ERROR
, "Set Socket Options failed: errno %d, %s\n", errno
, strerror(errno
));
4532 ast_config_destroy(cfg
);
4535 if (skinnysock
< 0) {
4536 ast_log(LOG_WARNING
, "Unable to create Skinny socket: %s\n", strerror(errno
));
4538 if (bind(skinnysock
, (struct sockaddr
*)&bindaddr
, sizeof(bindaddr
)) < 0) {
4539 ast_log(LOG_WARNING
, "Failed to bind to %s:%d: %s\n",
4540 ast_inet_ntoa(bindaddr
.sin_addr
), ntohs(bindaddr
.sin_port
),
4544 ast_config_destroy(cfg
);
4547 if (listen(skinnysock
,DEFAULT_SKINNY_BACKLOG
)) {
4548 ast_log(LOG_WARNING
, "Failed to start listening to %s:%d: %s\n",
4549 ast_inet_ntoa(bindaddr
.sin_addr
), ntohs(bindaddr
.sin_port
),
4553 ast_config_destroy(cfg
);
4556 if (option_verbose
> 1)
4557 ast_verbose(VERBOSE_PREFIX_2
"Skinny listening on %s:%d\n",
4558 ast_inet_ntoa(bindaddr
.sin_addr
), ntohs(bindaddr
.sin_port
));
4559 ast_pthread_create_background(&accept_t
,NULL
, accept_thread
, NULL
);
4562 ast_mutex_unlock(&netlock
);
4563 ast_config_destroy(cfg
);
4567 static void delete_devices(void)
4569 struct skinny_device
*d
, *dlast
;
4570 struct skinny_line
*l
, *llast
;
4571 struct skinny_speeddial
*sd
, *sdlast
;
4572 struct skinny_addon
*a
, *alast
;
4574 ast_mutex_lock(&devicelock
);
4576 /* Delete all devices */
4577 for (d
=devices
;d
;) {
4578 /* Delete all lines for this device */
4579 for (l
=d
->lines
;l
;) {
4582 ast_mutex_destroy(&llast
->lock
);
4585 /* Delete all speeddials for this device */
4586 for (sd
=d
->speeddials
;sd
;) {
4589 ast_mutex_destroy(&sdlast
->lock
);
4592 /* Delete all addons for this device */
4593 for (a
=d
->addons
;a
;) {
4596 ast_mutex_destroy(&alast
->lock
);
4604 ast_mutex_unlock(&devicelock
);
4609 * XXX This never worked properly anyways.
4610 * Let's get rid of it, until we can fix it.
4612 static int reload(void)
4621 static int load_module(void)
4625 for (; res
< (sizeof(soft_key_template_default
) / sizeof(soft_key_template_default
[0])); res
++) {
4626 soft_key_template_default
[res
].softKeyEvent
= htolel(soft_key_template_default
[res
].softKeyEvent
);
4628 /* load and parse config */
4629 res
= reload_config();
4631 return AST_MODULE_LOAD_DECLINE
;
4634 /* Make sure we can register our skinny channel type */
4635 if (ast_channel_register(&skinny_tech
)) {
4636 ast_log(LOG_ERROR
, "Unable to register channel class 'Skinny'\n");
4640 ast_rtp_proto_register(&skinny_rtp
);
4641 ast_cli_register_multiple(cli_skinny
, sizeof(cli_skinny
) / sizeof(struct ast_cli_entry
));
4642 sched
= sched_context_create();
4644 ast_log(LOG_WARNING
, "Unable to create schedule context\n");
4646 io
= io_context_create();
4648 ast_log(LOG_WARNING
, "Unable to create I/O context\n");
4650 /* And start the monitor for the first time */
4656 static int unload_module(void)
4658 struct skinnysession
*s
, *slast
;
4659 struct skinny_device
*d
;
4660 struct skinny_line
*l
;
4661 struct skinny_subchannel
*sub
;
4663 ast_mutex_lock(&sessionlock
);
4664 /* Destroy all the interfaces and free their memory */
4669 for (d
= slast
->device
; d
; d
= d
->next
) {
4670 for (l
= d
->lines
; l
; l
= l
->next
) {
4671 ast_mutex_lock(&l
->lock
);
4672 for (sub
= l
->sub
; sub
; sub
= sub
->next
) {
4673 ast_mutex_lock(&sub
->lock
);
4675 sub
->alreadygone
= 1;
4676 ast_softhangup(sub
->owner
, AST_SOFTHANGUP_APPUNLOAD
);
4678 ast_mutex_unlock(&sub
->lock
);
4680 ast_mutex_unlock(&l
->lock
);
4685 ast_mutex_destroy(&slast
->lock
);
4689 ast_mutex_unlock(&sessionlock
);
4693 ast_mutex_lock(&monlock
);
4694 if (monitor_thread
&& (monitor_thread
!= AST_PTHREADT_STOP
)) {
4695 pthread_cancel(monitor_thread
);
4696 pthread_kill(monitor_thread
, SIGURG
);
4697 pthread_join(monitor_thread
, NULL
);
4699 monitor_thread
= AST_PTHREADT_STOP
;
4700 ast_mutex_unlock(&monlock
);
4702 ast_mutex_lock(&netlock
);
4703 if (accept_t
&& (accept_t
!= AST_PTHREADT_STOP
)) {
4704 pthread_cancel(accept_t
);
4705 pthread_kill(accept_t
, SIGURG
);
4706 pthread_join(accept_t
, NULL
);
4708 accept_t
= AST_PTHREADT_STOP
;
4709 ast_mutex_unlock(&netlock
);
4711 ast_rtp_proto_unregister(&skinny_rtp
);
4712 ast_channel_unregister(&skinny_tech
);
4713 ast_cli_unregister_multiple(cli_skinny
, sizeof(cli_skinny
) / sizeof(struct ast_cli_entry
));
4716 sched_context_destroy(sched
);
4721 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "Skinny Client Control Protocol (Skinny)",
4722 .load
= load_module
,
4723 .unload
= unload_module
,