Asterisk - The Open Source Telephony Project  18.5.0
chan_skinny.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * chan_skinny was developed by Jeremy McNamara & Florian Overkamp
7  * chan_skinny was heavily modified/fixed by North Antara
8  *
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.
14  *
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.
18  */
19 
20 /*! \file
21  *
22  * \brief Implementation of the Skinny protocol
23  *
24  * \author Jeremy McNamara & Florian Overkamp & North Antara
25  * \ingroup channel_drivers
26  */
27 
28 /*! \li \ref chan_skinny.c uses the configuration file \ref skinny.conf
29  * \addtogroup configuration_file
30  */
31 
32 /*! \page skinny.conf skinny.conf
33  * \verbinclude skinny.conf.sample
34  */
35 
36 /*** MODULEINFO
37  <support_level>extended</support_level>
38  ***/
39 
40 #include "asterisk.h"
41 
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <netinet/tcp.h>
45 #include <sys/ioctl.h>
46 #include <net/if.h>
47 #include <fcntl.h>
48 #include <netdb.h>
49 #include <arpa/inet.h>
50 #include <signal.h>
51 #include <ctype.h>
52 
53 #include "asterisk/lock.h"
54 #include "asterisk/channel.h"
55 #include "asterisk/config.h"
56 #include "asterisk/module.h"
57 #include "asterisk/pbx.h"
58 #include "asterisk/sched.h"
59 #include "asterisk/io.h"
60 #include "asterisk/rtp_engine.h"
61 #include "asterisk/netsock2.h"
62 #include "asterisk/acl.h"
63 #include "asterisk/callerid.h"
64 #include "asterisk/cli.h"
65 #include "asterisk/manager.h"
66 #include "asterisk/say.h"
67 #include "asterisk/astdb.h"
68 #include "asterisk/causes.h"
69 #include "asterisk/pickup.h"
70 #include "asterisk/app.h"
71 #include "asterisk/mwi.h"
72 #include "asterisk/musiconhold.h"
73 #include "asterisk/utils.h"
74 #include "asterisk/dsp.h"
75 #include "asterisk/stringfields.h"
76 #include "asterisk/abstract_jb.h"
77 #include "asterisk/threadstorage.h"
78 #include "asterisk/devicestate.h"
79 #include "asterisk/indications.h"
80 #include "asterisk/linkedlists.h"
82 #include "asterisk/bridge.h"
83 #include "asterisk/parking.h"
85 #include "asterisk/format_cache.h"
86 
87 /*** DOCUMENTATION
88  <manager name="SKINNYdevices" language="en_US">
89  <synopsis>
90  List SKINNY devices (text format).
91  </synopsis>
92  <syntax>
93  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
94  </syntax>
95  <description>
96  <para>Lists Skinny devices in text format with details on current status.
97  Devicelist will follow as separate events, followed by a final event called
98  DevicelistComplete.</para>
99  </description>
100  </manager>
101  <manager name="SKINNYshowdevice" language="en_US">
102  <synopsis>
103  Show SKINNY device (text format).
104  </synopsis>
105  <syntax>
106  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
107  <parameter name="Device" required="true">
108  <para>The device name you want to check.</para>
109  </parameter>
110  </syntax>
111  <description>
112  <para>Show one SKINNY device with details on current status.</para>
113  </description>
114  </manager>
115  <manager name="SKINNYlines" language="en_US">
116  <synopsis>
117  List SKINNY lines (text format).
118  </synopsis>
119  <syntax>
120  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
121  </syntax>
122  <description>
123  <para>Lists Skinny lines in text format with details on current status.
124  Linelist will follow as separate events, followed by a final event called
125  LinelistComplete.</para>
126  </description>
127  </manager>
128  <manager name="SKINNYshowline" language="en_US">
129  <synopsis>
130  Show SKINNY line (text format).
131  </synopsis>
132  <syntax>
133  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
134  <parameter name="Line" required="true">
135  <para>The line name you want to check.</para>
136  </parameter>
137  </syntax>
138  <description>
139  <para>Show one SKINNY line with details on current status.</para>
140  </description>
141  </manager>
142  ***/
143 
144 /* Skinny debugging only available if asterisk configured with --enable-dev-mode */
145 #ifdef AST_DEVMODE
146 static int skinnydebug = 0;
147 char dbgcli_buf[256];
148 #define DEBUG_GENERAL (1 << 1)
149 #define DEBUG_SUB (1 << 2)
150 #define DEBUG_PACKET (1 << 3)
151 #define DEBUG_AUDIO (1 << 4)
152 #define DEBUG_LOCK (1 << 5)
153 #define DEBUG_TEMPLATE (1 << 6)
154 #define DEBUG_THREAD (1 << 7)
155 #define DEBUG_HINT (1 << 8)
156 #define DEBUG_KEEPALIVE (1 << 9)
157 #define SKINNY_DEBUG(type, verb_level, text, ...) \
158  do{ \
159  if (skinnydebug & (type)) { \
160  ast_verb(verb_level, "[%d] " text, ast_get_tid(), ##__VA_ARGS__); \
161  } \
162  }while(0)
163 #else
164 #define SKINNY_DEBUG(type, verb_level, text, ...)
165 #endif
166 
167 /*************************************
168  * Skinny/Asterisk Protocol Settings *
169  *************************************/
170 static const char tdesc[] = "Skinny Client Control Protocol (Skinny)";
171 static const char config[] = "skinny.conf";
172 
174 
181  SKINNY_CODEC_G726_32 = 82, /* XXX Which packing order does this translate to? */
184 };
185 
186 #define DEFAULT_SKINNY_PORT 2000
187 #define DEFAULT_SKINNY_BACKLOG 2
188 #define SKINNY_MAX_PACKET 2000
189 #define DEFAULT_AUTH_TIMEOUT 30
190 #define DEFAULT_AUTH_LIMIT 50
191 
192 static struct {
193  unsigned int tos;
194  unsigned int tos_audio;
195  unsigned int tos_video;
196  unsigned int cos;
197  unsigned int cos_audio;
198  unsigned int cos_video;
199 } qos = { 0, 0, 0, 0, 0, 0 };
200 
201 static int keep_alive = 120;
204 static int unauth_sessions = 0;
205 static char immed_dialchar;
206 static char vmexten[AST_MAX_EXTENSION]; /* Voicemail pilot number */
207 static char used_context[AST_MAX_EXTENSION]; /* placeholder to check if context are already used in regcontext */
208 static char regcontext[AST_MAX_CONTEXT]; /* Context for auto-extension */
209 static char date_format[6] = "D-M-Y";
210 static char version_id[16] = "P002F202";
211 
212 #if __BYTE_ORDER == __LITTLE_ENDIAN
213 #define letohl(x) (x)
214 #define letohs(x) (x)
215 #define htolel(x) (x)
216 #define htoles(x) (x)
217 #else
218 #if defined(HAVE_BYTESWAP_H)
219 #include <byteswap.h>
220 #define letohl(x) bswap_32(x)
221 #define letohs(x) bswap_16(x)
222 #define htolel(x) bswap_32(x)
223 #define htoles(x) bswap_16(x)
224 #elif defined(HAVE_SYS_ENDIAN_SWAP16)
225 #include <sys/endian.h>
226 #define letohl(x) __swap32(x)
227 #define letohs(x) __swap16(x)
228 #define htolel(x) __swap32(x)
229 #define htoles(x) __swap16(x)
230 #elif defined(HAVE_SYS_ENDIAN_BSWAP16)
231 #include <sys/endian.h>
232 #define letohl(x) bswap32(x)
233 #define letohs(x) bswap16(x)
234 #define htolel(x) bswap32(x)
235 #define htoles(x) bswap16(x)
236 #else
237 #define __bswap_16(x) \
238  ((((x) & 0xff00) >> 8) | \
239  (((x) & 0x00ff) << 8))
240 #define __bswap_32(x) \
241  ((((x) & 0xff000000) >> 24) | \
242  (((x) & 0x00ff0000) >> 8) | \
243  (((x) & 0x0000ff00) << 8) | \
244  (((x) & 0x000000ff) << 24))
245 #define letohl(x) __bswap_32(x)
246 #define letohs(x) __bswap_16(x)
247 #define htolel(x) __bswap_32(x)
248 #define htoles(x) __bswap_16(x)
249 #endif
250 #endif
251 
252 /*! Global jitterbuffer configuration - by default, jb is disabled
253  * \note Values shown here match the defaults shown in skinny.conf.sample */
255 {
256  .flags = 0,
257  .max_size = 200,
258  .resync_threshold = 1000,
259  .impl = "fixed",
260  .target_extra = 40,
261 };
263 
264 #ifdef AST_DEVMODE
266 #define MESSAGE2STR_BUFSIZE 35
267 #endif
268 
270 #define DEVICE2STR_BUFSIZE 15
271 
273 #define CONTROL2STR_BUFSIZE 100
274 
276 #define SUBSTATE2STR_BUFSIZE 15
277 
279 #define CALLSTATE2STR_BUFSIZE 15
280 
281 /*********************
282  * Protocol Messages *
283  *********************/
284 /* message types */
285 #define KEEP_ALIVE_MESSAGE 0x0000
286 /* no additional struct */
287 
288 #define REGISTER_MESSAGE 0x0001
290  char name[16];
291  uint32_t userId;
292  uint32_t instance;
293  uint32_t ip;
294  uint32_t type;
295  uint32_t maxStreams;
296  uint32_t space;
298  /*! \brief space2 is used for newer version of skinny */
299  char space2[3];
300 };
301 
302 #define IP_PORT_MESSAGE 0x0002
303 
304 #define KEYPAD_BUTTON_MESSAGE 0x0003
306  uint32_t button;
307  uint32_t lineInstance;
308  uint32_t callReference;
309 };
310 
311 
312 #define ENBLOC_CALL_MESSAGE 0x0004
314  char calledParty[24];
315 };
316 
317 #define STIMULUS_MESSAGE 0x0005
319  uint32_t stimulus;
321  uint32_t callreference;
322 };
323 
324 #define OFFHOOK_MESSAGE 0x0006
326  uint32_t instance;
327  uint32_t reference;
328 };
329 
330 #define ONHOOK_MESSAGE 0x0007
332  uint32_t instance;
333  uint32_t reference;
334 };
335 
336 #define CAPABILITIES_RES_MESSAGE 0x0010
338  uint32_t codec; /* skinny codec, not ast codec */
339  uint32_t frames;
340  union {
341  char res[8];
342  uint32_t rate;
343  } payloads;
344 };
345 
346 #define SKINNY_MAX_CAPABILITIES 18
347 
349  uint32_t count;
351 };
352 
353 #define SPEED_DIAL_STAT_REQ_MESSAGE 0x000A
355  uint32_t speedDialNumber;
356 };
357 
358 #define LINE_STATE_REQ_MESSAGE 0x000B
360  uint32_t lineNumber;
361 };
362 
363 #define TIME_DATE_REQ_MESSAGE 0x000D
364 #define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
365 #define VERSION_REQ_MESSAGE 0x000F
366 #define SERVER_REQUEST_MESSAGE 0x0012
367 
368 #define ALARM_MESSAGE 0x0020
370  uint32_t alarmSeverity;
371  char displayMessage[80];
372  uint32_t alarmParam1;
373  uint32_t alarmParam2;
374 };
375 
376 #define OPEN_RECEIVE_CHANNEL_ACK_MESSAGE 0x0022
378  uint32_t status;
379  uint32_t ipAddr;
380  uint32_t port;
381  uint32_t callReference;
382 };
384  uint32_t status;
385  uint32_t space;
386  char ipAddr[16];
387  uint32_t port;
388  uint32_t callReference;
389 };
390 
391 #define SOFT_KEY_SET_REQ_MESSAGE 0x0025
392 
393 #define SOFT_KEY_EVENT_MESSAGE 0x0026
395  uint32_t softKeyEvent;
396  uint32_t instance;
397  uint32_t callreference;
398 };
399 
400 #define UNREGISTER_MESSAGE 0x0027
401 #define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028
402 #define HEADSET_STATUS_MESSAGE 0x002B
403 #define REGISTER_AVAILABLE_LINES_MESSAGE 0x002D
404 
405 #define SERVICEURL_STATREQ_MESSAGE 0x0033
407  uint32_t instance;
408 };
409 
410 #define REGISTER_ACK_MESSAGE 0x0081
412  uint32_t keepAlive;
413  char dateTemplate[6];
414  char res[2];
416  char res2[4];
417 };
418 
419 #define START_TONE_MESSAGE 0x0082
421  uint32_t tone;
422  uint32_t space;
423  uint32_t instance;
424  uint32_t reference;
425 };
426 
427 #define STOP_TONE_MESSAGE 0x0083
429  uint32_t instance;
430  uint32_t reference;
431  uint32_t space;
432 };
433 
434 #define SET_RINGER_MESSAGE 0x0085
436  uint32_t ringerMode;
437  uint32_t unknown1; /* See notes in transmit_ringer_mode */
438  uint32_t unknown2;
439  uint32_t space[2];
440 };
441 
442 #define SET_LAMP_MESSAGE 0x0086
444  uint32_t stimulus;
446  uint32_t deviceStimulus;
447 };
448 
449 #define SET_SPEAKER_MESSAGE 0x0088
451  uint32_t mode;
452 };
453 
454 /* XXX When do we need to use this? */
455 #define SET_MICROPHONE_MESSAGE 0x0089
457  uint32_t mode;
458 };
459 
460 #define START_MEDIA_TRANSMISSION_MESSAGE 0x008A
462  uint32_t precedence;
463  uint32_t vad;
464  uint32_t packets;
465  uint32_t bitRate;
466 };
467 
469  uint32_t conferenceId;
470  uint32_t passThruPartyId;
471  uint32_t remoteIp;
472  uint32_t remotePort;
473  uint32_t packetSize;
474  uint32_t payloadType;
475  struct media_qualifier qualifier;
476  uint32_t space[19];
477 };
478 
480  uint32_t conferenceId;
481  uint32_t passThruPartyId;
482  uint32_t space;
483  char remoteIp[16];
484  uint32_t remotePort;
485  uint32_t packetSize;
486  uint32_t payloadType;
487  struct media_qualifier qualifier;
488  /*! \brief space2 is used for newer version of skinny */
489  uint32_t space2[19];
490 };
491 
492 #define STOP_MEDIA_TRANSMISSION_MESSAGE 0x008B
494  uint32_t conferenceId;
495  uint32_t passThruPartyId;
496  uint32_t space[3];
497 };
498 
499 #define CALL_INFO_MESSAGE 0x008F
501  char callingPartyName[40];
502  char callingParty[24];
503  char calledPartyName[40];
504  char calledParty[24];
505  uint32_t instance;
506  uint32_t reference;
507  uint32_t type;
508  char originalCalledPartyName[40];
509  char originalCalledParty[24];
510  char lastRedirectingPartyName[40];
511  char lastRedirectingParty[24];
514  char callingPartyVoiceMailbox[24];
515  char calledPartyVoiceMailbox[24];
516  char originalCalledPartyVoiceMailbox[24];
517  char lastRedirectingVoiceMailbox[24];
518  uint32_t space[3];
519 };
520 
521 #define FORWARD_STAT_MESSAGE 0x0090
523  uint32_t activeforward;
524  uint32_t lineNumber;
525  uint32_t fwdall;
526  char fwdallnum[24];
527  uint32_t fwdbusy;
528  char fwdbusynum[24];
529  uint32_t fwdnoanswer;
530  char fwdnoanswernum[24];
531 };
532 
533 #define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
535  uint32_t speedDialNumber;
536  char speedDialDirNumber[24];
537  char speedDialDisplayName[40];
538 };
539 
540 #define LINE_STAT_RES_MESSAGE 0x0092
542  uint32_t lineNumber;
543  char lineDirNumber[24];
544  char lineDisplayName[24];
545  uint32_t space[15];
546 };
547 
548 #define DEFINETIMEDATE_MESSAGE 0x0094
550  uint32_t year; /* since 1900 */
551  uint32_t month;
552  uint32_t dayofweek; /* monday = 1 */
553  uint32_t day;
554  uint32_t hour;
555  uint32_t minute;
556  uint32_t seconds;
557  uint32_t milliseconds;
558  uint32_t timestamp;
559 };
560 
561 #define BUTTON_TEMPLATE_RES_MESSAGE 0x0097
563  uint8_t instanceNumber;
565 };
566 
569  /* for now, anything between 0xB0 and 0xCF is custom */
570  /*int custom;*/
571 };
572 
573 #define STIMULUS_REDIAL 0x01
574 #define STIMULUS_SPEEDDIAL 0x02
575 #define STIMULUS_HOLD 0x03
576 #define STIMULUS_TRANSFER 0x04
577 #define STIMULUS_FORWARDALL 0x05
578 #define STIMULUS_FORWARDBUSY 0x06
579 #define STIMULUS_FORWARDNOANSWER 0x07
580 #define STIMULUS_DISPLAY 0x08
581 #define STIMULUS_LINE 0x09
582 #define STIMULUS_VOICEMAIL 0x0F
583 #define STIMULUS_AUTOANSWER 0x11
584 #define STIMULUS_SERVICEURL 0x14
585 #define STIMULUS_DND 0x3F
586 #define STIMULUS_CONFERENCE 0x7D
587 #define STIMULUS_CALLPARK 0x7E
588 #define STIMULUS_CALLPICKUP 0x7F
589 #define STIMULUS_NONE 0xFF
590 
591 /* Button types */
592 #define BT_REDIAL STIMULUS_REDIAL
593 #define BT_SPEEDDIAL STIMULUS_SPEEDDIAL
594 #define BT_HOLD STIMULUS_HOLD
595 #define BT_TRANSFER STIMULUS_TRANSFER
596 #define BT_FORWARDALL STIMULUS_FORWARDALL
597 #define BT_FORWARDBUSY STIMULUS_FORWARDBUSY
598 #define BT_FORWARDNOANSWER STIMULUS_FORWARDNOANSWER
599 #define BT_DISPLAY STIMULUS_DISPLAY
600 #define BT_LINE STIMULUS_LINE
601 #define BT_VOICEMAIL STIMULUS_VOICEMAIL
602 #define BT_AUTOANSWER STIMULUS_AUTOANSWER
603 #define BT_SERVICEURL STIMULUS_SERVICEURL
604 #define BT_DND STIMULUS_DND
605 #define BT_CONFERENCE STIMULUS_CONFERENCE
606 #define BT_CALLPARK STIMULUS_CALLPARK
607 #define BT_CALLPICKUP STIMULUS_CALLPICKUP
608 #define BT_NONE 0x00
609 
610 /* Custom button types - add our own between 0xB0 and 0xCF.
611  This may need to be revised in the future,
612  if stimuluses are ever added in this range. */
613 #define BT_CUST_LINESPEEDDIAL 0xB0 /* line or speeddial with/without hint */
614 #define BT_CUST_LINE 0xB1 /* line or speeddial with hint only */
615 
617  uint32_t buttonOffset;
618  uint32_t buttonCount;
620  struct button_definition definition[42];
621 };
622 
623 #define VERSION_RES_MESSAGE 0x0098
625  char version[16];
626 };
627 
628 #define DISPLAYTEXT_MESSAGE 0x0099
630  char text[40];
631 };
632 
633 #define CLEAR_NOTIFY_MESSAGE 0x0115
634 #define CLEAR_DISPLAY_MESSAGE 0x009A
636  uint32_t space;
637 };
638 
639 #define CAPABILITIES_REQ_MESSAGE 0x009B
640 
641 #define REGISTER_REJ_MESSAGE 0x009D
643  char errMsg[33];
644 };
645 
646 #define SERVER_RES_MESSAGE 0x009E
648  char serverName[48];
649 };
650 
652  struct server_identifier server[5];
653  uint32_t serverListenPort[5];
654  uint32_t serverIpAddr[5];
655 };
656 
657 #define RESET_MESSAGE 0x009F
659  uint32_t resetType;
660 };
661 
662 #define KEEP_ALIVE_ACK_MESSAGE 0x0100
663 
664 #define OPEN_RECEIVE_CHANNEL_MESSAGE 0x0105
666  uint32_t conferenceId;
667  uint32_t partyId;
668  uint32_t packets;
669  uint32_t capability;
670  uint32_t echo;
671  uint32_t bitrate;
672  uint32_t space[36];
673 };
674 
675 #define CLOSE_RECEIVE_CHANNEL_MESSAGE 0x0106
677  uint32_t conferenceId;
678  uint32_t partyId;
679  uint32_t space[2];
680 };
681 
682 #define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108
684  char softKeyLabel[16];
685  uint32_t softKeyEvent;
686 };
687 
688 #define BKSP_REQ_MESSAGE 0x0119
690  uint32_t instance;
691  uint32_t callreference;
692 };
693 
694 #define KEYDEF_ONHOOK 0
695 #define KEYDEF_CONNECTED 1
696 #define KEYDEF_ONHOLD 2
697 #define KEYDEF_RINGIN 3
698 #define KEYDEF_OFFHOOK 4
699 #define KEYDEF_CONNWITHTRANS 5
700 #define KEYDEF_DADFD 6 /* Digits After Dialing First Digit */
701 #define KEYDEF_CONNWITHCONF 7
702 #define KEYDEF_RINGOUT 8
703 #define KEYDEF_OFFHOOKWITHFEAT 9
704 #define KEYDEF_UNKNOWN 10
705 #define KEYDEF_SLAHOLD 11
706 #define KEYDEF_SLACONNECTEDNOTACTIVE 12
707 #define KEYDEF_RINGOUTWITHTRANS 13
708 
709 #define SOFTKEY_NONE 0x00
710 #define SOFTKEY_REDIAL 0x01
711 #define SOFTKEY_NEWCALL 0x02
712 #define SOFTKEY_HOLD 0x03
713 #define SOFTKEY_TRNSFER 0x04
714 #define SOFTKEY_CFWDALL 0x05
715 #define SOFTKEY_CFWDBUSY 0x06
716 #define SOFTKEY_CFWDNOANSWER 0x07
717 #define SOFTKEY_BKSPC 0x08
718 #define SOFTKEY_ENDCALL 0x09
719 #define SOFTKEY_RESUME 0x0A
720 #define SOFTKEY_ANSWER 0x0B
721 #define SOFTKEY_INFO 0x0C
722 #define SOFTKEY_CONFRN 0x0D
723 #define SOFTKEY_PARK 0x0E
724 #define SOFTKEY_JOIN 0x0F
725 #define SOFTKEY_MEETME 0x10
726 #define SOFTKEY_PICKUP 0x11
727 #define SOFTKEY_GPICKUP 0x12
728 #define SOFTKEY_DND 0x13
729 #define SOFTKEY_IDIVERT 0x14
730 #define SOFTKEY_FORCEDIAL 0x15
731 
732 #define KEYMASK_ALL 0xFFFFFFFF
733 #define KEYMASK_NONE (1 << 0)
734 #define KEYMASK_REDIAL (1 << 1)
735 #define KEYMASK_NEWCALL (1 << 2)
736 #define KEYMASK_HOLD (1 << 3)
737 #define KEYMASK_TRNSFER (1 << 4)
738 #define KEYMASK_CFWDALL (1 << 5)
739 #define KEYMASK_CFWDBUSY (1 << 6)
740 #define KEYMASK_CFWDNOANSWER (1 << 7)
741 #define KEYMASK_BKSPC (1 << 8)
742 #define KEYMASK_ENDCALL (1 << 9)
743 #define KEYMASK_RESUME (1 << 10)
744 #define KEYMASK_ANSWER (1 << 11)
745 #define KEYMASK_INFO (1 << 12)
746 #define KEYMASK_CONFRN (1 << 13)
747 #define KEYMASK_PARK (1 << 14)
748 #define KEYMASK_JOIN (1 << 15)
749 #define KEYMASK_MEETME (1 << 16)
750 #define KEYMASK_PICKUP (1 << 17)
751 #define KEYMASK_GPICKUP (1 << 18)
752 #define KEYMASK_DND (1 << 29)
753 #define KEYMASK_IDIVERT (1 << 20)
754 #define KEYMASK_FORCEDIAL (1 << 21)
755 
756 /* Localized message "codes" (in octal)
757  Below is en_US (taken from a 7970) */
758 
759 /* "\200\000" ??? */
760 #define OCTAL_REDIAL "\200\001" /* Redial */
761 #define OCTAL_NEWCALL "\200\002" /* New Call */
762 #define OCTAL_HOLD "\200\003" /* Hold */
763 #define OCTAL_TRANSFER "\200\004" /* Transfer */
764 #define OCTAL_CFWDALL "\200\005" /* CFwdALL */
765 #define OCTAL_CFWDBUSY "\200\006" /* CFwdBusy */
766 #define OCTAL_CFWDNOAN "\200\007" /* CFwdNoAnswer */
767 #define OCTAL_BKSPC "\200\010" /* << */
768 #define OCTAL_ENDCALL "\200\011" /* EndCall */
769 #define OCTAL_RESUME "\200\012" /* Resume */
770 #define OCTAL_ANSWER "\200\013" /* Answer */
771 #define OCTAL_INFO "\200\014" /* Info */
772 #define OCTAL_CONFRN "\200\015" /* Confrn */
773 #define OCTAL_PARK "\200\016" /* Park */
774 #define OCTAL_JOIN "\200\017" /* Join */
775 #define OCTAL_MEETME "\200\020" /* MeetMe */
776 #define OCTAL_PICKUP "\200\021" /* PickUp */
777 #define OCTAL_GPICKUP "\200\022" /* GPickUp */
778 #define OCTAL_CUROPTS "\200\023" /* Your current options */
779 #define OCTAL_OFFHOOK "\200\024" /* Off Hook */
780 #define OCTAL_ONHOOK "\200\025" /* On Hook */
781 #define OCTAL_RINGOUT "\200\026" /* Ring out */
782 #define OCTAL_FROM "\200\027" /* From */
783 #define OCTAL_CONNECTED "\200\030" /* Connected */
784 #define OCTAL_BUSY "\200\031" /* Busy */
785 #define OCTAL_LINEINUSE "\200\032" /* Line In Use */
786 #define OCTAL_CALLWAITING "\200\033" /* Call Waiting */
787 #define OCTAL_CALLXFER "\200\034" /* Call Transfer */
788 #define OCTAL_CALLPARK "\200\035" /* Call Park */
789 #define OCTAL_CALLPROCEED "\200\036" /* Call Proceed */
790 #define OCTAL_INUSEREMOTE "\200\037" /* In Use Remote */
791 #define OCTAL_ENTRNUM "\200\040" /* Enter number */
792 #define OCTAL_PARKAT "\200\041" /* Call park At */
793 #define OCTAL_PRIMONLY "\200\042" /* Primary Only */
794 #define OCTAL_TMPFAIL "\200\043" /* Temp Fail */
795 #define OCTAL_HAVEVMAIL "\200\044" /* You Have VoiceMail */
796 #define OCTAL_FWDEDTO "\200\045" /* Forwarded to */
797 #define OCTAL_CANTCOMPCNF "\200\046" /* Can Not Complete Conference */
798 #define OCTAL_NOCONFBRDG "\200\047" /* No Conference Bridge */
799 #define OCTAL_NOPRIMARYCTL "\200\050" /* Can Not Hold Primary Control */
800 #define OCTAL_INVALCONFPART "\200\051" /* Invalid Conference Participant */
801 #define OCTAL_INCONFALREADY "\200\052" /* In Conference Already */
802 #define OCTAL_NOPARTINFO "\200\053" /* No Participant Info */
803 #define OCTAL_MAXPARTEXCEED "\200\054" /* Exceed Maximum Parties */
804 #define OCTAL_KEYNOTACTIVE "\200\055" /* Key Is Not Active */
805 #define OCTAL_ERRNOLIC "\200\056" /* Error No License */
806 #define OCTAL_ERRDBCFG "\200\057" /* Error DBConfig */
807 #define OCTAL_ERRDB "\200\060" /* Error Database */
808 #define OCTAL_ERRPASSLMT "\200\061" /* Error Pass Limit */
809 #define OCTAL_ERRUNK "\200\062" /* Error Unknown */
810 #define OCTAL_ERRMISMATCH "\200\063" /* Error Mismatch */
811 #define OCTAL_CONFERENCE "\200\064" /* Conference */
812 #define OCTAL_PARKNO "\200\065" /* Park Number */
813 #define OCTAL_PRIVATE "\200\066" /* Private */
814 #define OCTAL_INSUFBANDW "\200\067" /* Not Enough Bandwidth */
815 #define OCTAL_UNKNUM "\200\070" /* Unknown Number */
816 #define OCTAL_RMLSTC "\200\071" /* RmLstC */
817 #define OCTAL_VOICEMAIL "\200\072" /* Voicemail */
818 #define OCTAL_IMMDIV "\200\073" /* ImmDiv */
819 #define OCTAL_INTRCPT "\200\074" /* Intrcpt */
820 #define OCTAL_SETWTCH "\200\075" /* SetWtch */
821 #define OCTAL_TRNSFVM "\200\076" /* TrnsfVM */
822 #define OCTAL_DND "\200\077" /* DND */
823 #define OCTAL_DIVALL "\200\100" /* DivAll */
824 #define OCTAL_CALLBACK "\200\101" /* CallBack */
825 #define OCTAL_NETCNGREROUT "\200\102" /* Network congestion,rerouting */
826 #define OCTAL_BARGE "\200\103" /* Barge */
827 #define OCTAL_BARGEFAIL "\200\104" /* Failed to setup Barge */
828 #define OCTAL_BARGEEXIST "\200\105" /* Another Barge exists */
829 #define OCTAL_INCOMPATDEV "\200\106" /* Incompatible device type */
830 #define OCTAL_PARKNONUM "\200\107" /* No Park Number Available */
831 #define OCTAL_PARKREVERSION "\200\110" /* CallPark Reversion */
832 #define OCTAL_SRVNOTACTIVE "\200\111" /* Service is not Active */
833 #define OCTAL_HITRAFFIC "\200\112" /* High Traffic Try Again Later */
834 #define OCTAL_QRT "\200\113" /* QRT */
835 #define OCTAL_MCID "\200\114" /* MCID */
836 #define OCTAL_DIRTRFR "\200\115" /* DirTrfr */
837 #define OCTAL_SELECT "\200\116" /* Select */
838 #define OCTAL_CONFLIST "\200\117" /* ConfList */
839 #define OCTAL_IDIVERT "\200\120" /* iDivert */
840 #define OCTAL_CBARGE "\200\121" /* cBarge */
841 #define OCTAL_CANTCOMPLXFER "\200\122" /* Can Not Complete Transfer */
842 #define OCTAL_CANTJOINCALLS "\200\123" /* Can Not Join Calls */
843 #define OCTAL_MCIDSUCCESS "\200\124" /* Mcid Successful */
844 #define OCTAL_NUMNOTCFG "\200\125" /* Number Not Configured */
845 #define OCTAL_SECERROR "\200\126" /* Security Error */
846 #define OCTAL_VIDBANDWNA "\200\127" /* Video Bandwidth Unavailable */
847 #define OCTAL_VIDMODE "\200\130" /* VidMode */
848 #define OCTAL_CALLDURTIMEOUT "\200\131" /* Max Call Duration Timeout */
849 #define OCTAL_HOLDDURTIMEOUT "\200\132" /* Max Hold Duration Timeout */
850 #define OCTAL_OPICKUP "\200\133" /* OPickUp */
851 /* "\200\134" ??? */
852 /* "\200\135" ??? */
853 /* "\200\136" ??? */
854 /* "\200\137" ??? */
855 /* "\200\140" ??? */
856 #define OCTAL_EXTXFERRESTRICT "\200\141" /* External Transfer Restricted */
857 /* "\200\142" ??? */
858 /* "\200\143" ??? */
859 /* "\200\144" ??? */
860 #define OCTAL_MACADD "\200\145" /* Mac Address */
861 #define OCTAL_HOST "\200\146" /* Host Name */
862 #define OCTAL_DOMAIN "\200\147" /* Domain Name */
863 #define OCTAL_IPADD "\200\150" /* IP Address */
864 #define OCTAL_SUBMASK "\200\151" /* Subnet Mask */
865 #define OCTAL_TFTP1 "\200\152" /* TFTP Server 1 */
866 #define OCTAL_ROUTER1 "\200\153" /* Default Router 1 */
867 #define OCTAL_ROUTER2 "\200\154" /* Default Router 2 */
868 #define OCTAL_ROUTER3 "\200\155" /* Default Router 3 */
869 #define OCTAL_ROUTER4 "\200\156" /* Default Router 4 */
870 #define OCTAL_ROUTER5 "\200\157" /* Default Router 5 */
871 #define OCTAL_DNS1 "\200\160" /* DNS Server 1 */
872 #define OCTAL_DNS2 "\200\161" /* DNS Server 2 */
873 #define OCTAL_DNS3 "\200\162" /* DNS Server 3 */
874 #define OCTAL_DNS4 "\200\163" /* DNS Server 4 */
875 #define OCTAL_DNS5 "\200\164" /* DNS Server 5 */
876 #define OCTAL_VLANOPID "\200\165" /* Operational VLAN Id */
877 #define OCTAL_VLANADID "\200\166" /* Admin. VLAN Id */
878 #define OCTAL_CM1 "\200\167" /* CallManager 1 */
879 #define OCTAL_CM2 "\200\170" /* CallManager 2 */
880 #define OCTAL_CM3 "\200\171" /* CallManager 3 */
881 #define OCTAL_CM4 "\200\172" /* CallManager 4 */
882 #define OCTAL_CM5 "\200\173" /* CallManager 5 */
883 #define OCTAL_URLINFO "\200\174" /* Information URL */
884 #define OCTAL_URLDIRS "\200\175" /* Directories URL */
885 #define OCTAL_URLMSGS "\200\176" /* Messages URL */
886 #define OCTAL_URLSRVS "\200\177" /* Services URL */
887 
907  { OCTAL_DND, SOFTKEY_DND },
909  { "Dial", SOFTKEY_FORCEDIAL},
910 };
911 
913  const uint8_t mode;
914  const uint8_t *defaults;
915  const int count;
916 };
917 
918 static const uint8_t soft_key_default_onhook[] = {
924  SOFTKEY_DND,
926  /*SOFTKEY_CONFRN,*/
927 };
928 
929 static const uint8_t soft_key_default_connected[] = {
930  SOFTKEY_HOLD,
933  SOFTKEY_PARK,
937 };
938 
939 static const uint8_t soft_key_default_onhold[] = {
944 };
945 
946 static const uint8_t soft_key_default_ringin[] = {
950 };
951 
952 static const uint8_t soft_key_default_offhook[] = {
960 };
961 
962 static const uint8_t soft_key_default_connwithtrans[] = {
963  SOFTKEY_HOLD,
966  SOFTKEY_PARK,
970 };
971 
972 static const uint8_t soft_key_default_dadfd[] = {
977 };
978 
979 static const uint8_t soft_key_default_connwithconf[] = {
980  SOFTKEY_NONE,
981 };
982 
983 static const uint8_t soft_key_default_ringout[] = {
984  SOFTKEY_NONE,
986 };
987 
988 static const uint8_t soft_key_default_ringoutwithtransfer[] = {
989  SOFTKEY_NONE,
992 };
993 
994 static const uint8_t soft_key_default_offhookwithfeat[] = {
998 };
999 
1000 static const uint8_t soft_key_default_unknown[] = {
1001  SOFTKEY_NONE,
1002 };
1003 
1004 static const uint8_t soft_key_default_SLAhold[] = {
1008 };
1009 
1010 static const uint8_t soft_key_default_SLAconnectednotactive[] = {
1013  SOFTKEY_JOIN,
1014 };
1015 
1017  {KEYDEF_ONHOOK, soft_key_default_onhook, sizeof(soft_key_default_onhook) / sizeof(uint8_t)},
1019  {KEYDEF_ONHOLD, soft_key_default_onhold, sizeof(soft_key_default_onhold) / sizeof(uint8_t)},
1020  {KEYDEF_RINGIN, soft_key_default_ringin, sizeof(soft_key_default_ringin) / sizeof(uint8_t)},
1023  {KEYDEF_DADFD, soft_key_default_dadfd, sizeof(soft_key_default_dadfd) / sizeof(uint8_t)},
1031 };
1032 
1034  uint32_t softKeyOffset;
1035  uint32_t softKeyCount;
1037  struct soft_key_template_definition softKeyTemplateDefinition[32];
1038 };
1039 
1040 #define SOFT_KEY_SET_RES_MESSAGE 0x0109
1041 
1043  uint8_t softKeyTemplateIndex[16];
1044  uint16_t softKeyInfoIndex[16];
1045 };
1046 
1051  struct soft_key_set_definition softKeySetDefinition[16];
1052  uint32_t res;
1053 };
1054 
1055 #define SELECT_SOFT_KEYS_MESSAGE 0x0110
1057  uint32_t instance;
1058  uint32_t reference;
1060  uint32_t validKeyMask;
1061 };
1062 
1063 #define CALL_STATE_MESSAGE 0x0111
1065  uint32_t callState;
1066  uint32_t lineInstance;
1067  uint32_t callReference;
1068  uint32_t space[3];
1069 };
1070 
1071 #define DISPLAY_PROMPT_STATUS_MESSAGE 0x0112
1073  uint32_t messageTimeout;
1074  char promptMessage[32];
1075  uint32_t lineInstance;
1076  uint32_t callReference;
1077  uint32_t space[3];
1078 };
1079 
1080 #define CLEAR_PROMPT_MESSAGE 0x0113
1082  uint32_t lineInstance;
1083  uint32_t callReference;
1084 };
1085 
1086 #define DISPLAY_NOTIFY_MESSAGE 0x0114
1088  uint32_t displayTimeout;
1089  char displayMessage[100];
1090 };
1091 
1092 #define ACTIVATE_CALL_PLANE_MESSAGE 0x0116
1094  uint32_t lineInstance;
1095 };
1096 
1097 #define DIALED_NUMBER_MESSAGE 0x011D
1099  char dialedNumber[24];
1100  uint32_t lineInstance;
1101  uint32_t callReference;
1102 };
1103 
1104 #define MAX_SERVICEURL 256
1105 #define SERVICEURL_STAT_MESSAGE 0x012F
1107  uint32_t instance;
1109  char displayName[40];
1110 };
1111 
1112 #define MAXCALLINFOSTR 256
1113 #define MAXDISPLAYNOTIFYSTR 32
1114 
1115 #define DISPLAY_PRINOTIFY_MESSAGE 0x0120
1117  uint32_t timeout;
1118  uint32_t priority;
1120 };
1121 
1122 #define CLEAR_PRINOTIFY_MESSAGE 0x0121
1124  uint32_t priority;
1125 };
1126 
1127 #define CALL_INFO_MESSAGE_VARIABLE 0x014A
1129  uint32_t instance;
1130  uint32_t callreference;
1131  uint32_t calldirection;
1132  uint32_t unknown1;
1133  uint32_t unknown2;
1134  uint32_t unknown3;
1135  uint32_t unknown4;
1136  uint32_t unknown5;
1137  char calldetails[MAXCALLINFOSTR];
1138 };
1139 
1140 #define DISPLAY_PRINOTIFY_MESSAGE_VARIABLE 0x0144
1142  uint32_t timeout;
1143  uint32_t priority;
1145 };
1146 
1147 #define DISPLAY_PROMPT_STATUS_MESSAGE_VARIABLE 0x0145
1149  uint32_t unknown;
1150  uint32_t lineInstance;
1151  uint32_t callReference;
1152  char promptMessage[MAXCALLINFOSTR];
1153 };
1154 
1157  struct speed_dial_stat_req_message speeddialreq;
1158  struct register_message reg;
1159  struct register_ack_message regack;
1160  struct register_rej_message regrej;
1163  struct button_template_res_message buttontemplate;
1164  struct displaytext_message displaytext;
1166  struct display_prompt_status_message displaypromptstatus;
1167  struct clear_prompt_message clearpromptstatus;
1168  struct definetimedate_message definetimedate;
1169  struct start_tone_message starttone;
1170  struct stop_tone_message stoptone;
1173  struct line_stat_res_message linestat;
1174  struct soft_key_set_res_message softkeysets;
1175  struct soft_key_template_res_message softkeytemplate;
1176  struct server_res_message serverres;
1177  struct reset_message reset;
1178  struct set_lamp_message setlamp;
1179  struct set_ringer_message setringer;
1180  struct call_state_message callstate;
1181  struct keypad_button_message keypad;
1182  struct select_soft_keys_message selectsoftkey;
1183  struct activate_call_plane_message activatecallplane;
1185  struct offhook_message offhook;
1186  struct onhook_message onhook;
1187  struct set_speaker_message setspeaker;
1188  struct set_microphone_message setmicrophone;
1189  struct call_info_message callinfo;
1193  struct open_receive_channel_message openreceivechannel;
1194  struct open_receive_channel_ack_message_ip4 openreceivechannelack_ip4;
1195  struct open_receive_channel_ack_message_ip6 openreceivechannelack_ip6;
1196  struct close_receive_channel_message closereceivechannel;
1197  struct display_notify_message displaynotify;
1198  struct dialed_number_message dialednumber;
1199  struct soft_key_event_message softkeyeventmessage;
1200  struct enbloc_call_message enbloccallmessage;
1201  struct forward_stat_message forwardstat;
1202  struct bksp_req_message bkspmessage;
1203  struct call_info_message_variable callinfomessagevariable;
1204  struct display_prompt_status_message_variable displaypromptstatusvar;
1205  struct serviceurl_stat_message serviceurlmessage;
1206  struct clear_prinotify_message clearprinotify;
1207  struct display_prinotify_message displayprinotify;
1208  struct display_prinotify_message_variable displayprinotifyvar;
1209 };
1210 
1211 /* packet composition */
1212 struct skinny_req {
1213  uint32_t len;
1214  uint32_t res;
1215  uint32_t e;
1216  union skinny_data data;
1217 };
1218 
1219 /* XXX This is the combined size of the variables above. (len, res, e)
1220  If more are added, this MUST change.
1221  (sizeof(skinny_req) - sizeof(skinny_data)) DOES NOT WORK on all systems (amd64?). */
1222 static int skinny_header_size = 12;
1223 
1224 /*****************************
1225  * Asterisk specific globals *
1226  *****************************/
1227 
1228 static int skinnyreload = 0;
1229 
1230 /* a hostname, portnumber, socket and such is usefull for VoIP protocols */
1231 static struct sockaddr_in bindaddr;
1232 static char ourhost[256];
1233 static int ourport;
1234 static struct in_addr __ourip;
1235 static struct ast_hostent ahp;
1236 static struct hostent *hp;
1237 static int skinnysock = -1;
1238 static pthread_t accept_t;
1239 static int callnums = 1;
1240 
1241 #define SKINNY_DEVICE_UNKNOWN -1
1242 #define SKINNY_DEVICE_NONE 0
1243 #define SKINNY_DEVICE_30SPPLUS 1
1244 #define SKINNY_DEVICE_12SPPLUS 2
1245 #define SKINNY_DEVICE_12SP 3
1246 #define SKINNY_DEVICE_12 4
1247 #define SKINNY_DEVICE_30VIP 5
1248 #define SKINNY_DEVICE_7910 6
1249 #define SKINNY_DEVICE_7960 7
1250 #define SKINNY_DEVICE_7940 8
1251 #define SKINNY_DEVICE_7935 9
1252 #define SKINNY_DEVICE_ATA186 12 /* Cisco ATA-186 */
1253 #define SKINNY_DEVICE_7941 115
1254 #define SKINNY_DEVICE_7971 119
1255 #define SKINNY_DEVICE_7914 124 /* Expansion module */
1256 #define SKINNY_DEVICE_7985 302
1257 #define SKINNY_DEVICE_7911 307
1258 #define SKINNY_DEVICE_7961GE 308
1259 #define SKINNY_DEVICE_7941GE 309
1260 #define SKINNY_DEVICE_7931 348
1261 #define SKINNY_DEVICE_7921 365
1262 #define SKINNY_DEVICE_7906 369
1263 #define SKINNY_DEVICE_7962 404 /* Not found */
1264 #define SKINNY_DEVICE_7937 431
1265 #define SKINNY_DEVICE_7942 434
1266 #define SKINNY_DEVICE_7945 435
1267 #define SKINNY_DEVICE_7965 436
1268 #define SKINNY_DEVICE_7975 437
1269 #define SKINNY_DEVICE_7905 20000
1270 #define SKINNY_DEVICE_7920 30002
1271 #define SKINNY_DEVICE_7970 30006
1272 #define SKINNY_DEVICE_7912 30007
1273 #define SKINNY_DEVICE_7902 30008
1274 #define SKINNY_DEVICE_CIPC 30016 /* Cisco IP Communicator */
1275 #define SKINNY_DEVICE_7961 30018
1276 #define SKINNY_DEVICE_7936 30019
1277 #define SKINNY_DEVICE_SCCPGATEWAY_AN 30027 /* Analog gateway */
1278 #define SKINNY_DEVICE_SCCPGATEWAY_BRI 30028 /* BRI gateway */
1279 
1280 #define SKINNY_SPEAKERON 1
1281 #define SKINNY_SPEAKEROFF 2
1282 
1283 #define SKINNY_MICON 1
1284 #define SKINNY_MICOFF 2
1285 
1286 #define SKINNY_OFFHOOK 1
1287 #define SKINNY_ONHOOK 2
1288 #define SKINNY_RINGOUT 3
1289 #define SKINNY_RINGIN 4
1290 #define SKINNY_CONNECTED 5
1291 #define SKINNY_BUSY 6
1292 #define SKINNY_CONGESTION 7
1293 #define SKINNY_HOLD 8
1294 #define SKINNY_CALLWAIT 9
1295 #define SKINNY_TRANSFER 10
1296 #define SKINNY_PARK 11
1297 #define SKINNY_PROGRESS 12
1298 #define SKINNY_CALLREMOTEMULTILINE 13
1299 #define SKINNY_INVALID 14
1300 
1301 #define SKINNY_INCOMING 1
1302 #define SKINNY_OUTGOING 2
1303 
1304 #define SKINNY_SILENCE 0x00 /* Note sure this is part of the protocol, remove? */
1305 #define SKINNY_DIALTONE 0x21
1306 #define SKINNY_BUSYTONE 0x23
1307 #define SKINNY_ALERT 0x24
1308 #define SKINNY_REORDER 0x25
1309 #define SKINNY_CALLWAITTONE 0x2D
1310 #define SKINNY_ZIPZIP 0x31
1311 #define SKINNY_ZIP 0x32
1312 #define SKINNY_BEEPBONK 0x33
1313 #define SKINNY_BARGIN 0x43
1314 #define SKINNY_NOTONE 0x7F
1315 
1316 #define SKINNY_LAMP_OFF 1
1317 #define SKINNY_LAMP_ON 2
1318 #define SKINNY_LAMP_WINK 3
1319 #define SKINNY_LAMP_FLASH 4
1320 #define SKINNY_LAMP_BLINK 5
1321 
1322 #define SKINNY_RING_OFF 1
1323 #define SKINNY_RING_INSIDE 2
1324 #define SKINNY_RING_OUTSIDE 3
1325 #define SKINNY_RING_FEATURE 4
1326 
1327 #define SKINNY_CFWD_ALL (1 << 0)
1328 #define SKINNY_CFWD_BUSY (1 << 1)
1329 #define SKINNY_CFWD_NOANSWER (1 << 2)
1330 
1331 /* Skinny rtp stream modes. Do we really need this? */
1332 #define SKINNY_CX_SENDONLY 0
1333 #define SKINNY_CX_RECVONLY 1
1334 #define SKINNY_CX_SENDRECV 2
1335 #define SKINNY_CX_CONF 3
1336 #define SKINNY_CX_CONFERENCE 3
1337 #define SKINNY_CX_MUTE 4
1338 #define SKINNY_CX_INACTIVE 4
1339 
1340 #if 0
1341 static const char * const skinny_cxmodes[] = {
1342  "sendonly",
1343  "recvonly",
1344  "sendrecv",
1345  "confrnce",
1346  "inactive"
1347 };
1348 #endif
1349 
1350 /* driver scheduler */
1351 static struct ast_sched_context *sched = NULL;
1352 
1353 /* Protect the network socket */
1355 
1356 /* Wait up to 16 seconds for first digit */
1357 static int firstdigittimeout = 16000;
1358 
1359 /* How long to wait for following digits */
1360 static int gendigittimeout = 8000;
1361 
1362 /* How long to wait for an extra digit, if there is an ambiguous match */
1363 static int matchdigittimeout = 3000;
1364 
1365 /*!
1366  * To apease the stupid compiler option on ast_sched_del()
1367  * since we don't care about the return value.
1368  */
1369 static int not_used;
1370 
1371 #define SUBSTATE_UNSET 0
1372 #define SUBSTATE_OFFHOOK 1
1373 #define SUBSTATE_ONHOOK 2
1374 #define SUBSTATE_RINGOUT 3
1375 #define SUBSTATE_RINGIN 4
1376 #define SUBSTATE_CONNECTED 5
1377 #define SUBSTATE_BUSY 6
1378 #define SUBSTATE_CONGESTION 7
1379 #define SUBSTATE_HOLD 8
1380 #define SUBSTATE_CALLWAIT 9
1381 #define SUBSTATE_PROGRESS 12
1382 #define SUBSTATE_DIALING 101
1383 
1384 #define DIALTYPE_NORMAL 1<<0
1385 #define DIALTYPE_CFWD 1<<1
1386 #define DIALTYPE_XFER 1<<2
1387 
1392  unsigned int callid;
1394  /* time_t lastouttime; */ /* Unused */
1396  int ringing;
1397  /* int lastout; */ /* Unused */
1398  int cxmode;
1399  int nat;
1402  int xferor;
1405  int aa_beep;
1406  int aa_mute;
1411  char *origtonum;
1412  char *origtoname;
1413 
1418 };
1419 
1420 #define SKINNY_LINE_OPTIONS \
1421  char name[80]; \
1422  char label[24]; \
1423  char accountcode[AST_MAX_ACCOUNT_CODE]; \
1424  char exten[AST_MAX_EXTENSION]; \
1425  char context[AST_MAX_CONTEXT]; \
1426  char language[MAX_LANGUAGE]; \
1427  char cid_num[AST_MAX_EXTENSION]; \
1428  char cid_name[AST_MAX_EXTENSION]; \
1429  char lastcallerid[AST_MAX_EXTENSION]; \
1430  int cfwdtype; \
1431  char call_forward_all[AST_MAX_EXTENSION]; \
1432  char call_forward_busy[AST_MAX_EXTENSION]; \
1433  char call_forward_noanswer[AST_MAX_EXTENSION]; \
1434  char mailbox[AST_MAX_MAILBOX_UNIQUEID]; \
1435  char vmexten[AST_MAX_EXTENSION]; \
1436  char regexten[AST_MAX_EXTENSION]; \
1437  char regcontext[AST_MAX_CONTEXT]; \
1438  char parkinglot[AST_MAX_CONTEXT]; \
1439  char mohinterpret[MAX_MUSICCLASS]; \
1440  char mohsuggest[MAX_MUSICCLASS]; \
1441  char lastnumberdialed[AST_MAX_EXTENSION]; \
1442  char dialoutexten[AST_MAX_EXTENSION]; \
1443  char dialoutcontext[AST_MAX_CONTEXT]; \
1444  ast_group_t callgroup; \
1445  ast_group_t pickupgroup; \
1446  struct ast_namedgroups *named_callgroups; \
1447  struct ast_namedgroups *named_pickupgroups; \
1448  int callwaiting; \
1449  int transfer; \
1450  int threewaycalling; \
1451  int mwiblink; \
1452  int cancallforward; \
1453  int callfwdtimeout; \
1454  int dnd; \
1455  int hidecallerid; \
1456  int amaflags; \
1457  int instance; \
1458  int group; \
1459  int nonCodecCapability; \
1460  int immediate; \
1461  int nat; \
1462  int directmedia; \
1463  int prune;
1464 
1465 struct skinny_line {
1469  struct ast_mwi_subscriber *mwi_event_sub; /* Event based MWI */
1478  struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
1479  int newmsgs;
1480 };
1481 
1482 static struct skinny_line_options{
1484 } default_line_struct = {
1485  .callwaiting = 1,
1486  .transfer = 1,
1487  .mwiblink = 0,
1488  .dnd = 0,
1489  .hidecallerid = 0,
1490  .amaflags = 0,
1491  .instance = 0,
1492  .directmedia = 0,
1493  .nat = 0,
1494  .callfwdtimeout = 20000,
1495  .prune = 0,
1496 };
1498 
1500 
1506  char name[80];
1509  char stname[AST_MAX_EXTENSION];
1510  char lnname[AST_MAX_EXTENSION];
1511  char ourName[40];
1512  char ourNum[24];
1513  char theirName[40];
1514  char theirNum[24];
1518  unsigned int callid;
1519 };
1520 
1524  char label[42];
1528  int stateid;
1530  int isHint;
1531 
1534 };
1535 
1539  char displayName[40];
1542 };
1543 
1544 #define SKINNY_DEVICECONTAINER 1
1545 #define SKINNY_LINECONTAINER 2
1546 #define SKINNY_SUBLINECONTAINER 3
1547 #define SKINNY_SDCONTAINER 4
1548 
1550  int type;
1551  void *data;
1552 };
1553 
1556  char type[10];
1559 };
1560 
1561 #define SKINNY_DEVICE_OPTIONS \
1562  char name[80]; \
1563  char id[16]; \
1564  char version_id[16]; \
1565  char vmexten[AST_MAX_EXTENSION]; \
1566  int type; \
1567  int protocolversion; \
1568  int hookstate; \
1569  int lastlineinstance; \
1570  int lastcallreference; \
1571  int earlyrtp; \
1572  int transfer; \
1573  int callwaiting; \
1574  int mwiblink; \
1575  int dnd; \
1576  int prune;
1577 
1580  struct type *first;
1581  struct type *last;
1583  struct sockaddr_in addr;
1584  struct in_addr ourip;
1585  struct ast_ha *ha;
1596 };
1597 
1598 static struct skinny_device_options {
1601  .transfer = 1,
1602  .earlyrtp = 1,
1603  .callwaiting = 1,
1604  .mwiblink = 0,
1605  .dnd = 0,
1606  .prune = 0,
1607  .hookstate = SKINNY_ONHOOK,
1608 };
1610 
1612 
1614  pthread_t t;
1616  struct timeval start;
1617  struct sockaddr_in sin;
1618  int fd;
1619  char outbuf[SKINNY_MAX_PACKET];
1622  int lockstate; /* Only for use in the skinny_session thread */
1625  struct timeval last_keepalive;
1627 };
1628 
1629 static struct ast_channel *skinny_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest, int *cause);
1631 
1632 static int skinny_devicestate(const char *data);
1633 static int skinny_call(struct ast_channel *ast, const char *dest, int timeout);
1634 static int skinny_hangup(struct ast_channel *ast);
1635 static int skinny_answer(struct ast_channel *ast);
1636 static struct ast_frame *skinny_read(struct ast_channel *ast);
1637 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame);
1638 static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
1639 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
1640 static int skinny_senddigit_begin(struct ast_channel *ast, char digit);
1641 static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
1642 static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg);
1643 static int skinny_dialer_cb(const void *data);
1644 static int skinny_reload(void);
1645 
1646 static void skinny_set_owner(struct skinny_subchannel* sub, struct ast_channel* chan);
1647 static void setsubstate(struct skinny_subchannel *sub, int state);
1648 static void dumpsub(struct skinny_subchannel *sub, int forcehangup);
1649 static void activatesub(struct skinny_subchannel *sub, int state);
1650 static void dialandactivatesub(struct skinny_subchannel *sub, char exten[AST_MAX_EXTENSION]);
1651 static int skinny_nokeepalive_cb(const void *data);
1652 
1653 static void transmit_definetimedate(struct skinny_device *d);
1654 
1656  .type = "Skinny",
1657  .description = tdesc,
1659  .requester = skinny_request,
1660  .devicestate = skinny_devicestate,
1661  .call = skinny_call,
1662  .hangup = skinny_hangup,
1663  .answer = skinny_answer,
1664  .read = skinny_read,
1665  .write = skinny_write,
1666  .indicate = skinny_indicate,
1667  .fixup = skinny_fixup,
1668  .send_digit_begin = skinny_senddigit_begin,
1669  .send_digit_end = skinny_senddigit_end,
1670 };
1671 
1672 static int skinny_extensionstate_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data);
1673 
1674 static struct skinny_line *skinny_line_alloc(void)
1675 {
1676  struct skinny_line *l;
1677  if (!(l = ast_calloc(1, sizeof(*l)))) {
1678  return NULL;
1679  }
1680 
1683  if (!l->cap || !l->confcap) {
1684  ao2_cleanup(l->cap);
1685  ao2_cleanup(l->confcap);
1686  ast_free(l);
1687  return NULL;
1688  }
1689  return l;
1690 }
1692 {
1693  ao2_ref(l->cap, -1);
1694  ao2_ref(l->confcap, -1);
1695  l->named_callgroups = ast_unref_namedgroups(l->named_callgroups);
1696  l->named_pickupgroups = ast_unref_namedgroups(l->named_pickupgroups);
1697  ast_free(l->container);
1698  ast_free(l);
1699  return NULL;
1700 }
1701 static struct skinny_device *skinny_device_alloc(const char *dname)
1702 {
1703  struct skinny_device *d;
1704  if (!(d = ast_calloc(1, sizeof(*d)))) {
1705  return NULL;
1706  }
1707 
1710  d->endpoint = ast_endpoint_create("Skinny", dname);
1711  if (!d->cap || !d->confcap || !d->endpoint) {
1712  ao2_cleanup(d->cap);
1713  ao2_cleanup(d->confcap);
1714  ast_free(d);
1715  return NULL;
1716  }
1717 
1718  ast_copy_string(d->name, dname, sizeof(d->name));
1719 
1720  return d;
1721 }
1723 {
1724  ao2_ref(d->cap, -1);
1725  ao2_ref(d->confcap, -1);
1727  ast_free(d);
1728  return NULL;
1729 }
1730 
1732 {
1733  struct skinny_device *d = s->device;
1734  struct skinny_addon *a;
1735  int i;
1736 
1737  switch (d->type) {
1739  case SKINNY_DEVICE_30VIP:
1740  /* 13 rows, 2 columns */
1741  for (i = 0; i < 4; i++)
1742  (btn++)->buttonDefinition = BT_CUST_LINE;
1743  (btn++)->buttonDefinition = BT_REDIAL;
1744  (btn++)->buttonDefinition = BT_VOICEMAIL;
1745  (btn++)->buttonDefinition = BT_CALLPARK;
1746  (btn++)->buttonDefinition = BT_FORWARDALL;
1747  (btn++)->buttonDefinition = BT_CONFERENCE;
1748  for (i = 0; i < 4; i++)
1749  (btn++)->buttonDefinition = BT_NONE;
1750  for (i = 0; i < 13; i++)
1751  (btn++)->buttonDefinition = BT_SPEEDDIAL;
1752 
1753  break;
1755  case SKINNY_DEVICE_12SP:
1756  case SKINNY_DEVICE_12:
1757  /* 6 rows, 2 columns */
1758  for (i = 0; i < 2; i++)
1759  (btn++)->buttonDefinition = BT_CUST_LINE;
1760  for (i = 0; i < 4; i++)
1761  (btn++)->buttonDefinition = BT_SPEEDDIAL;
1762  (btn++)->buttonDefinition = BT_HOLD;
1763  (btn++)->buttonDefinition = BT_REDIAL;
1764  (btn++)->buttonDefinition = BT_TRANSFER;
1765  (btn++)->buttonDefinition = BT_FORWARDALL;
1766  (btn++)->buttonDefinition = BT_CALLPARK;
1767  (btn++)->buttonDefinition = BT_VOICEMAIL;
1768  break;
1769  case SKINNY_DEVICE_7910:
1770  (btn++)->buttonDefinition = BT_LINE;
1771  (btn++)->buttonDefinition = BT_HOLD;
1772  (btn++)->buttonDefinition = BT_TRANSFER;
1773  (btn++)->buttonDefinition = BT_DISPLAY;
1774  (btn++)->buttonDefinition = BT_VOICEMAIL;
1775  (btn++)->buttonDefinition = BT_CONFERENCE;
1776  (btn++)->buttonDefinition = BT_FORWARDALL;
1777  for (i = 0; i < 2; i++)
1778  (btn++)->buttonDefinition = BT_SPEEDDIAL;
1779  (btn++)->buttonDefinition = BT_REDIAL;
1780  break;
1781  case SKINNY_DEVICE_7960:
1782  case SKINNY_DEVICE_7961:
1783  case SKINNY_DEVICE_7961GE:
1784  case SKINNY_DEVICE_7962:
1785  case SKINNY_DEVICE_7965:
1786  for (i = 0; i < 6; i++)
1787  (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
1788  break;
1789  case SKINNY_DEVICE_7940:
1790  case SKINNY_DEVICE_7941:
1791  case SKINNY_DEVICE_7941GE:
1792  case SKINNY_DEVICE_7942:
1793  case SKINNY_DEVICE_7945:
1794  for (i = 0; i < 2; i++)
1795  (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
1796  break;
1797  case SKINNY_DEVICE_7935:
1798  case SKINNY_DEVICE_7936:
1799  for (i = 0; i < 2; i++)
1800  (btn++)->buttonDefinition = BT_LINE;
1801  break;
1802  case SKINNY_DEVICE_ATA186:
1803  (btn++)->buttonDefinition = BT_LINE;
1804  break;
1805  case SKINNY_DEVICE_7970:
1806  case SKINNY_DEVICE_7971:
1807  case SKINNY_DEVICE_7975:
1808  case SKINNY_DEVICE_CIPC:
1809  for (i = 0; i < 8; i++)
1810  (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
1811  break;
1812  case SKINNY_DEVICE_7985:
1813  /* XXX I have no idea what the buttons look like on these. */
1814  ast_log(LOG_WARNING, "Unsupported device type '%d (7985)' found.\n", d->type);
1815  break;
1816  case SKINNY_DEVICE_7912:
1817  case SKINNY_DEVICE_7911:
1818  case SKINNY_DEVICE_7905:
1819  (btn++)->buttonDefinition = BT_LINE;
1820  (btn++)->buttonDefinition = BT_HOLD;
1821  break;
1822  case SKINNY_DEVICE_7920:
1823  /* XXX I don't know if this is right. */
1824  for (i = 0; i < 4; i++)
1825  (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
1826  break;
1827  case SKINNY_DEVICE_7921:
1828  for (i = 0; i < 6; i++)
1829  (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
1830  break;
1831  case SKINNY_DEVICE_7902:
1832  ast_log(LOG_WARNING, "Unsupported device type '%d (7902)' found.\n", d->type);
1833  break;
1834  case SKINNY_DEVICE_7906:
1835  ast_log(LOG_WARNING, "Unsupported device type '%d (7906)' found.\n", d->type);
1836  break;
1837  case SKINNY_DEVICE_7931:
1838  ast_log(LOG_WARNING, "Unsupported device type '%d (7931)' found.\n", d->type);
1839  break;
1840  case SKINNY_DEVICE_7937:
1841  ast_log(LOG_WARNING, "Unsupported device type '%d (7937)' found.\n", d->type);
1842  break;
1843  case SKINNY_DEVICE_7914:
1844  ast_log(LOG_WARNING, "Unsupported device type '%d (7914)' found. Expansion module registered by itself?\n", d->type);
1845  break;
1848  ast_log(LOG_WARNING, "Unsupported device type '%d (SCCP gateway)' found.\n", d->type);
1849  break;
1850  default:
1851  ast_log(LOG_WARNING, "Unknown device type '%d' found.\n", d->type);
1852  break;
1853  }
1854 
1855  AST_LIST_LOCK(&d->addons);
1856  AST_LIST_TRAVERSE(&d->addons, a, list) {
1857  if (!strcasecmp(a->type, "7914")) {
1858  for (i = 0; i < 14; i++)
1859  (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
1860  } else {
1861  ast_log(LOG_WARNING, "Unknown addon type '%s' found. Skipping.\n", a->type);
1862  }
1863  }
1864  AST_LIST_UNLOCK(&d->addons);
1865 
1866  return btn;
1867 }
1868 
1869 static struct skinny_req *req_alloc(size_t size, int response_message)
1870 {
1871  struct skinny_req *req;
1872 
1873  if (!(req = ast_calloc(1, skinny_header_size + size + 4)))
1874  return NULL;
1875 
1876  req->len = htolel(size+4);
1877  req->e = htolel(response_message);
1878 
1879  return req;
1880 }
1881 
1882 static struct skinny_line *find_line_by_instance(struct skinny_device *d, int instance)
1883 {
1884  struct skinny_line *l;
1885 
1886  /*Dialing from on hook or on a 7920 uses instance 0 in requests
1887  but we need to start looking at instance 1 */
1888 
1889  if (!instance)
1890  instance = 1;
1891 
1892  AST_LIST_TRAVERSE(&d->lines, l, list){
1893  if (l->instance == instance)
1894  break;
1895  }
1896 
1897  if (!l) {
1898  ast_log(LOG_WARNING, "Could not find line with instance '%d' on device '%s'\n", instance, d->name);
1899  }
1900  return l;
1901 }
1902 
1903 static struct skinny_line *find_line_by_name(const char *dest)
1904 {
1905  struct skinny_line *l;
1906  struct skinny_line *tmpl = NULL;
1907  struct skinny_device *d;
1908  char line[256];
1909  char *at;
1910  char *device;
1911  int checkdevice = 0;
1912 
1913  ast_copy_string(line, dest, sizeof(line));
1914  at = strchr(line, '@');
1915  if (at)
1916  *at++ = '\0';
1917  device = at;
1918 
1919  if (!ast_strlen_zero(device))
1920  checkdevice = 1;
1921 
1924  if (checkdevice && tmpl)
1925  break;
1926  else if (!checkdevice) {
1927  /* This is a match, since we're checking for line on every device. */
1928  } else if (!strcasecmp(d->name, device)) {
1929  } else
1930  continue;
1931 
1932  /* Found the device (or we don't care which device) */
1933  AST_LIST_TRAVERSE(&d->lines, l, list){
1934  /* Search for the right line */
1935  if (!strcasecmp(l->name, line)) {
1936  if (tmpl) {
1937  ast_log(LOG_WARNING, "Ambiguous line name: %s\n", line);
1939  return NULL;
1940  } else
1941  tmpl = l;
1942  }
1943  }
1944  }
1946  return tmpl;
1947 }
1948 
1949 static struct skinny_subline *find_subline_by_name(const char *dest)
1950 {
1951  struct skinny_line *l;
1952  struct skinny_subline *subline;
1953  struct skinny_subline *tmpsubline = NULL;
1954  struct skinny_device *d;
1955 
1958  AST_LIST_TRAVERSE(&d->lines, l, list){
1959  AST_LIST_TRAVERSE(&l->sublines, subline, list){
1960  if (!strcasecmp(subline->name, dest)) {
1961  if (tmpsubline) {
1962  ast_verb(2, "Ambiguous subline name: %s\n", dest);
1964  return NULL;
1965  } else
1966  tmpsubline = subline;
1967  }
1968  }
1969  }
1970  }
1972  return tmpsubline;
1973 }
1974 
1976 {
1977  struct skinny_subline *subline;
1978  struct skinny_line *l;
1979 
1980  AST_LIST_TRAVERSE(&d->lines, l, list){
1981  AST_LIST_TRAVERSE(&l->sublines, subline, list){
1982  if (subline->callid == callid) {
1983  return subline;
1984  }
1985  }
1986  }
1987  return NULL;
1988 }
1989 
1990 /*!
1991  * implement the setvar config line
1992  */
1993 static struct ast_variable *add_var(const char *buf, struct ast_variable *list)
1994 {
1995  struct ast_variable *tmpvar = NULL;
1996  char *varname = ast_strdupa(buf), *varval = NULL;
1997 
1998  if ((varval = strchr(varname,'='))) {
1999  *varval++ = '\0';
2000  if ((tmpvar = ast_variable_new(varname, varval, ""))) {
2001  tmpvar->next = list;
2002  list = tmpvar;
2003  }
2004  }
2005  return list;
2006 }
2007 
2009 {
2010  if (sub && sub->owner) {
2011  ast_channel_lock(sub->owner);
2012  }
2013 }
2014 
2016 {
2017  if (sub && sub->owner) {
2018  ast_channel_unlock(sub->owner);
2019  }
2020 }
2021 
2023 {
2024  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Deleting SCHED %d\n",
2025  sub->callid, sched_id);
2026  return ast_sched_del(sched, sched_id);
2027 }
2028 
2029 static int skinny_sched_add(int when, ast_sched_cb callback, struct skinny_subchannel *sub)
2030 {
2031  int ret;
2032  ret = ast_sched_add(sched, when, callback, sub);
2033  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Added SCHED %d\n",
2034  sub->callid, ret);
2035  return ret;
2036 }
2037 
2038 /* It's quicker/easier to find the subchannel when we know the instance number too */
2039 static struct skinny_subchannel *find_subchannel_by_instance_reference(struct skinny_device *d, int instance, int reference)
2040 {
2041  struct skinny_line *l = find_line_by_instance(d, instance);
2042  struct skinny_subchannel *sub;
2043 
2044  if (!l) {
2045  return NULL;
2046  }
2047 
2048  /* 7920 phones set call reference to 0, so use the first
2049  sub-channel on the list.
2050  This MIGHT need more love to be right */
2051  if (!reference)
2052  sub = AST_LIST_FIRST(&l->sub);
2053  else {
2054  AST_LIST_TRAVERSE(&l->sub, sub, list) {
2055  if (sub->callid == reference)
2056  break;
2057  }
2058  }
2059  if (!sub) {
2060  ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s'\n", reference, d->name);
2061  }
2062  return sub;
2063 }
2064 
2065 /* Find the subchannel when we only have the callid - this shouldn't happen often */
2066 static struct skinny_subchannel *find_subchannel_by_reference(struct skinny_device *d, int reference)
2067 {
2068  struct skinny_line *l;
2069  struct skinny_subchannel *sub = NULL;
2070 
2071  AST_LIST_TRAVERSE(&d->lines, l, list){
2072  AST_LIST_TRAVERSE(&l->sub, sub, list){
2073  if (sub->callid == reference)
2074  break;
2075  }
2076  if (sub)
2077  break;
2078  }
2079 
2080  if (!l) {
2081  ast_log(LOG_WARNING, "Could not find any lines that contained a subchannel with reference '%d' on device '%s'\n", reference, d->name);
2082  } else {
2083  if (!sub) {
2084  ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s@%s'\n", reference, l->name, d->name);
2085  }
2086  }
2087  return sub;
2088 }
2089 
2091 {
2092  struct skinny_speeddial *sd;
2093 
2094  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
2095  if (sd->isHint == isHint && sd->instance == instance)
2096  break;
2097  }
2098 
2099  if (!sd) {
2100  ast_log(LOG_WARNING, "Could not find speeddial with instance '%d' on device '%s'\n", instance, d->name);
2101  }
2102  return sd;
2103 }
2104 
2105 static struct ast_format *codec_skinny2ast(enum skinny_codecs skinnycodec)
2106 {
2107  switch (skinnycodec) {
2108  case SKINNY_CODEC_ALAW:
2109  return ast_format_alaw;
2110  case SKINNY_CODEC_ULAW:
2111  return ast_format_ulaw;
2112  case SKINNY_CODEC_G722:
2113  return ast_format_g722;
2114  case SKINNY_CODEC_G723_1:
2115  return ast_format_g723;
2116  case SKINNY_CODEC_G729A:
2117  return ast_format_g729;
2118  case SKINNY_CODEC_G726_32:
2119  return ast_format_g726; /* XXX Is this right? */
2120  case SKINNY_CODEC_H261:
2121  return ast_format_h261;
2122  case SKINNY_CODEC_H263:
2123  return ast_format_h263;
2124  default:
2125  return ast_format_none;
2126  }
2127 }
2128 
2129 static int codec_ast2skinny(const struct ast_format *astcodec)
2130 {
2132  return SKINNY_CODEC_ALAW;
2133  } else if (ast_format_cmp(astcodec, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
2134  return SKINNY_CODEC_ULAW;
2135  } else if (ast_format_cmp(astcodec, ast_format_g722) == AST_FORMAT_CMP_EQUAL) {
2136  return SKINNY_CODEC_G722;
2137  } else if (ast_format_cmp(astcodec, ast_format_g723) == AST_FORMAT_CMP_EQUAL) {
2138  return SKINNY_CODEC_G723_1;
2139  } else if (ast_format_cmp(astcodec, ast_format_g729) == AST_FORMAT_CMP_EQUAL) {
2140  return SKINNY_CODEC_G729A;
2141  } else if (ast_format_cmp(astcodec, ast_format_g726) == AST_FORMAT_CMP_EQUAL) {
2142  return SKINNY_CODEC_G726_32;
2143  } else if (ast_format_cmp(astcodec, ast_format_h261) == AST_FORMAT_CMP_EQUAL) {
2144  return SKINNY_CODEC_H261;
2145  } else if (ast_format_cmp(astcodec, ast_format_h263) == AST_FORMAT_CMP_EQUAL) {
2146  return SKINNY_CODEC_H263;
2147  } else {
2148  return 0;
2149  }
2150 }
2151 
2152 static int set_callforwards(struct skinny_line *l, const char *cfwd, int cfwdtype)
2153 {
2154  if (!l)
2155  return 0;
2156 
2157  if (!ast_strlen_zero(cfwd)) {
2158  if (cfwdtype & SKINNY_CFWD_ALL) {
2159  l->cfwdtype |= SKINNY_CFWD_ALL;
2160  ast_copy_string(l->call_forward_all, cfwd, sizeof(l->call_forward_all));
2161  }
2162  if (cfwdtype & SKINNY_CFWD_BUSY) {
2163  l->cfwdtype |= SKINNY_CFWD_BUSY;
2164  ast_copy_string(l->call_forward_busy, cfwd, sizeof(l->call_forward_busy));
2165  }
2166  if (cfwdtype & SKINNY_CFWD_NOANSWER) {
2167  l->cfwdtype |= SKINNY_CFWD_NOANSWER;
2168  ast_copy_string(l->call_forward_noanswer, cfwd, sizeof(l->call_forward_noanswer));
2169  }
2170  } else {
2171  if (cfwdtype & SKINNY_CFWD_ALL) {
2172  l->cfwdtype &= ~SKINNY_CFWD_ALL;
2173  memset(l->call_forward_all, 0, sizeof(l->call_forward_all));
2174  }
2175  if (cfwdtype & SKINNY_CFWD_BUSY) {
2176  l->cfwdtype &= ~SKINNY_CFWD_BUSY;
2177  memset(l->call_forward_busy, 0, sizeof(l->call_forward_busy));
2178  }
2179  if (cfwdtype & SKINNY_CFWD_NOANSWER) {
2180  l->cfwdtype &= ~SKINNY_CFWD_NOANSWER;
2181  memset(l->call_forward_noanswer, 0, sizeof(l->call_forward_noanswer));
2182  }
2183  }
2184  return l->cfwdtype;
2185 }
2186 
2187 static void cleanup_stale_contexts(char *new, char *old)
2188 {
2189  char *oldcontext, *newcontext, *stalecontext, *stringp, newlist[AST_MAX_CONTEXT];
2190 
2191  while ((oldcontext = strsep(&old, "&"))) {
2192  stalecontext = NULL;
2193  ast_copy_string(newlist, new, sizeof(newlist));
2194  stringp = newlist;
2195  while ((newcontext = strsep(&stringp, "&"))) {
2196  if (strcmp(newcontext, oldcontext) == 0) {
2197  /* This is not the context you're looking for */
2198  stalecontext = NULL;
2199  break;
2200  } else if (strcmp(newcontext, oldcontext)) {
2201  stalecontext = oldcontext;
2202  }
2203 
2204  }
2205  ast_context_destroy_by_name(stalecontext, "Skinny");
2206  }
2207 }
2208 
2209 static void register_exten(struct skinny_line *l)
2210 {
2211  char multi[256];
2212  char *stringp, *ext, *context;
2213 
2215  return;
2216 
2217  ast_copy_string(multi, S_OR(l->regexten, l->name), sizeof(multi));
2218  stringp = multi;
2219  while ((ext = strsep(&stringp, "&"))) {
2220  if ((context = strchr(ext, '@'))) {
2221  *context++ = '\0'; /* split ext@context */
2222  if (!ast_context_find(context)) {
2223  ast_log(LOG_WARNING, "Context %s must exist in regcontext= in skinny.conf!\n", context);
2224  continue;
2225  }
2226  } else {
2227  context = regcontext;
2228  }
2229  ast_add_extension(context, 1, ext, 1, NULL, NULL, "Noop",
2230  ast_strdup(l->name), ast_free_ptr, "Skinny");
2231  }
2232 }
2233 
2234 static void unregister_exten(struct skinny_line *l)
2235 {
2236  char multi[256];
2237  char *stringp, *ext, *context;
2238 
2240  return;
2241 
2242  ast_copy_string(multi, S_OR(l->regexten, l->name), sizeof(multi));
2243  stringp = multi;
2244  while ((ext = strsep(&stringp, "&"))) {
2245  if ((context = strchr(ext, '@'))) {
2246  *context++ = '\0'; /* split ext@context */
2247  if (!ast_context_find(context)) {
2248  ast_log(LOG_WARNING, "Context %s must exist in regcontext= in skinny.conf!\n", context);
2249  continue;
2250  }
2251  } else {
2252  context = regcontext;
2253  }
2254  ast_context_remove_extension(context, ext, 1, NULL);
2255  }
2256 }
2257 
2258 static int skinny_register(struct skinny_req *req, struct skinnysession *s)
2259 {
2260  struct skinny_device *d;
2261  struct skinny_line *l;
2262  struct skinny_subline *subline;
2263  struct skinny_speeddial *sd;
2264  struct sockaddr_in sin;
2265  socklen_t slen;
2266  int instance;
2267  int res = -1;
2268 
2269  if (-1 < s->auth_timeout_sched) {
2271  s->auth_timeout_sched = -1;
2272  }
2273 
2275  AST_LIST_TRAVERSE(&devices, d, list){
2276  struct ast_sockaddr addr;
2277  ast_sockaddr_from_sin(&addr, &s->sin);
2278  if (!strcasecmp(req->data.reg.name, d->id)
2279  && ast_apply_ha(d->ha, &addr)) {
2280  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
2281 
2282  if (d->session) {
2283  ast_log(LOG_WARNING, "Device already registered.\n");
2285  res = 0;
2286  break;
2287  }
2288  s->device = d;
2289  d->type = letohl(req->data.reg.type);
2290  d->protocolversion = letohl(req->data.reg.protocolVersion);
2291  if (ast_strlen_zero(d->version_id)) {
2292  ast_copy_string(d->version_id, version_id, sizeof(d->version_id));
2293  }
2294  d->session = s;
2295 
2296  slen = sizeof(sin);
2297  if (getsockname(s->fd, (struct sockaddr *)&sin, &slen)) {
2298  ast_log(LOG_WARNING, "Cannot get socket name\n");
2299  sin.sin_addr = __ourip;
2300  }
2301  d->ourip = sin.sin_addr;
2302 
2303  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
2305  }
2306  instance = 0;
2307  AST_LIST_TRAVERSE(&d->lines, l, list) {
2308  instance++;
2309  }
2310  AST_LIST_TRAVERSE(&d->lines, l, list) {
2312  /* l->capability = d->capability; */
2313  l->instance = instance;
2314  l->newmsgs = ast_app_has_voicemail(l->mailbox, NULL);
2316  register_exten(l);
2317  /* initialize MWI on line and device */
2318  mwi_event_cb(l, NULL, NULL);
2319  AST_LIST_TRAVERSE(&l->sublines, subline, list) {
2321  }
2323  --instance;
2324  }
2326  blob = ast_json_pack("{s: s}", "peer_status", "Registered");
2328  res = 1;
2329  break;
2330  }
2331  }
2333  return res;
2334 }
2335 
2336 static void end_session(struct skinnysession *s)
2337 {
2338  pthread_cancel(s->t);
2339 }
2340 
2341 #ifdef AST_DEVMODE
2342 static char *callstate2str(int ind)
2343 {
2344  char *tmp;
2345 
2346  switch (ind) {
2347  case SKINNY_OFFHOOK:
2348  return "SKINNY_OFFHOOK";
2349  case SKINNY_ONHOOK:
2350  return "SKINNY_ONHOOK";
2351  case SKINNY_RINGOUT:
2352  return "SKINNY_RINGOUT";
2353  case SKINNY_RINGIN:
2354  return "SKINNY_RINGIN";
2355  case SKINNY_CONNECTED:
2356  return "SKINNY_CONNECTED";
2357  case SKINNY_BUSY:
2358  return "SKINNY_BUSY";
2359  case SKINNY_CONGESTION:
2360  return "SKINNY_CONGESTION";
2361  case SKINNY_PROGRESS:
2362  return "SKINNY_PROGRESS";
2363  case SKINNY_HOLD:
2364  return "SKINNY_HOLD";
2365  case SKINNY_CALLWAIT:
2366  return "SKINNY_CALLWAIT";
2367  default:
2369  return "Unknown";
2370  snprintf(tmp, CALLSTATE2STR_BUFSIZE, "UNKNOWN-%d", ind);
2371  return tmp;
2372  }
2373 }
2374 
2375 #endif
2376 
2377 static int transmit_response_bysession(struct skinnysession *s, struct skinny_req *req)
2378 {
2379  int res = 0;
2380  unsigned long len;
2381 
2382  if (!s) {
2383  ast_log(LOG_WARNING, "Asked to transmit to a non-existent session!\n");
2384  return -1;
2385  }
2386 
2387  ast_mutex_lock(&s->lock);
2388 
2389  /* Don't optimize out assigning letohl() to len. It is necessary to guarantee that the comparison will always catch invalid values.
2390  * letohl() may or may not return a signed value depending upon which definition is used. */
2391  len = letohl(req->len);
2392  if (SKINNY_MAX_PACKET < len) {
2393  ast_log(LOG_WARNING, "transmit_response: the length of the request (%u) is out of bounds (%d)\n", letohl(req->len), SKINNY_MAX_PACKET);
2394  ast_mutex_unlock(&s->lock);
2395  return -1;
2396  }
2397 
2398  memset(s->outbuf, 0, sizeof(s->outbuf));
2399  memcpy(s->outbuf, req, skinny_header_size);
2400  memcpy(s->outbuf+skinny_header_size, &req->data, letohl(req->len));
2401 
2402  res = write(s->fd, s->outbuf, letohl(req->len)+8);
2403 
2404  if (res != letohl(req->len)+8) {
2405  ast_log(LOG_WARNING, "Transmit: write only sent %d out of %u bytes: %s\n", res, letohl(req->len)+8, strerror(errno));
2406  if (res == -1) {
2407  ast_log(LOG_WARNING, "Transmit: Skinny Client was lost, unregistering\n");
2408  end_session(s);
2409  }
2410 
2411  }
2412 
2413  ast_free(req);
2414  ast_mutex_unlock(&s->lock);
2415  return 1;
2416 }
2417 
2418 static void transmit_response(struct skinny_device *d, struct skinny_req *req)
2419 {
2421 }
2422 
2423 static void transmit_registerrej(struct skinnysession *s)
2424 {
2425  struct skinny_req *req;
2426  char name[16];
2427 
2428  if (!(req = req_alloc(sizeof(struct register_rej_message), REGISTER_REJ_MESSAGE)))
2429  return;
2430 
2431  memcpy(&name, req->data.reg.name, sizeof(name));
2432  snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name);
2433 
2434  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting REGISTER_REJ_MESSAGE to UNKNOWN_DEVICE\n");
2436 }
2437 
2438 static void transmit_speaker_mode(struct skinny_device *d, int mode)
2439 {
2440  struct skinny_req *req;
2441 
2442  if (!(req = req_alloc(sizeof(struct set_speaker_message), SET_SPEAKER_MESSAGE)))
2443  return;
2444 
2445  req->data.setspeaker.mode = htolel(mode);
2446 
2447  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SET_SPEAKER_MESSAGE to %s, mode %d\n", d->name, mode);
2448  transmit_response(d, req);
2449 }
2450 
2451 static void transmit_microphone_mode(struct skinny_device *d, int mode)
2452 {
2453  struct skinny_req *req;
2454 
2455  if (!(req = req_alloc(sizeof(struct set_microphone_message), SET_MICROPHONE_MESSAGE)))
2456  return;
2457 
2458  req->data.setmicrophone.mode = htolel(mode);
2459 
2460  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SET_MICROPHONE_MESSAGE to %s, mode %d\n", d->name, mode);
2461  transmit_response(d, req);
2462 }
2463 
2464 //static void transmit_callinfo(struct skinny_subchannel *sub)
2465 static void transmit_callinfo(struct skinny_device *d, int instance, int callid,
2466  char *fromname, char *fromnum, char *toname, char *tonum, int calldirection, char *origtonum, char *origtoname)
2467 {
2468  struct skinny_req *req;
2469 
2470  if (!(req = req_alloc(sizeof(struct call_info_message), CALL_INFO_MESSAGE)))
2471  return;
2472 
2474  ast_copy_string(req->data.callinfo.callingParty, fromnum, sizeof(req->data.callinfo.callingParty));
2476  ast_copy_string(req->data.callinfo.calledParty, tonum, sizeof(req->data.callinfo.calledParty));
2477  if (origtoname) {
2479  }
2480  if (origtonum) {
2482  }
2483 
2484  req->data.callinfo.instance = htolel(instance);
2485  req->data.callinfo.reference = htolel(callid);
2486  req->data.callinfo.type = htolel(calldirection);
2487 
2488  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting CALL_INFO_MESSAGE to %s, to %s(%s) from %s(%s), origto %s(%s) (dir=%d) on %s(%d)\n",
2489  d->name, toname, tonum, fromname, fromnum, origtoname, origtonum, calldirection, d->name, instance);
2490  transmit_response(d, req);
2491 }
2492 
2493 static void transmit_callinfo_variable(struct skinny_device *d, int instance, int callreference,
2494  char *fromname, char *fromnum, char *toname, char *tonum, int calldirection, char *origtonum, char *origtoname)
2495 {
2496  struct skinny_req *req;
2497  char *strptr;
2498  char *thestrings[13];
2499  int i;
2500  int callinfostrleft = MAXCALLINFOSTR;
2501 
2502  if (!(req = req_alloc(sizeof(struct call_info_message_variable), CALL_INFO_MESSAGE_VARIABLE)))
2503  return;
2504 
2505  req->data.callinfomessagevariable.instance = htolel(instance);
2506  req->data.callinfomessagevariable.callreference = htolel(callreference);
2507  req->data.callinfomessagevariable.calldirection = htolel(calldirection);
2508 
2514 
2515  thestrings[0] = fromnum;
2516  thestrings[1] = ""; /* Appears to be origfrom */
2517  if (calldirection == SKINNY_OUTGOING) {
2518  thestrings[2] = tonum;
2519  thestrings[3] = origtonum;
2520  } else {
2521  thestrings[2] = "";
2522  thestrings[3] = "";
2523  }
2524  thestrings[4] = "";
2525  thestrings[5] = "";
2526  thestrings[6] = "";
2527  thestrings[7] = "";
2528 
2529  thestrings[8] = "";
2530  thestrings[9] = fromname;
2531  thestrings[10] = toname;
2532  thestrings[11] = origtoname;
2533  thestrings[12] = "";
2534 
2536 
2537  for(i = 0; i < 13; i++) {
2538  if (thestrings[i]) {
2539  ast_copy_string(strptr, thestrings[i], callinfostrleft);
2540  strptr += strlen(thestrings[i]) + 1;
2541  callinfostrleft -= strlen(thestrings[i]) + 1;
2542  } else {
2543  ast_copy_string(strptr, "", callinfostrleft);
2544  strptr++;
2545  callinfostrleft--;
2546  }
2547  }
2548 
2549  req->len = req->len - (callinfostrleft & ~0x3);
2550 
2551  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting CALL_INFO_MESSAGE_VARIABLE to %s, to %s(%s) from %s(%s), origto %s(%s) (dir=%d) on %s(%d)\n",
2552  d->name, toname, tonum, fromname, fromnum, origtoname, origtonum, calldirection, d->name, instance);
2553  transmit_response(d, req);
2554 }
2555 
2557 {
2558  struct ast_channel *ast;
2559  struct skinny_device *d;
2560  struct skinny_line *l;
2561  struct ast_party_id connected_id;
2562  char *fromname;
2563  char *fromnum;
2564  char *toname;
2565  char *tonum;
2566 
2567  if (!sub || !sub->owner || !sub->line || !sub->line->device) {
2568  return;
2569  }
2570 
2571  ast = sub->owner;
2572  l = sub->line;
2573  d = l->device;
2574  connected_id = ast_channel_connected_effective_id(ast);
2575 
2576  if (sub->calldirection == SKINNY_INCOMING) {
2578  fromname = S_COR(connected_id.name.valid, connected_id.name.str, "");
2579  fromnum = S_COR(connected_id.number.valid, connected_id.number.str, "");
2580  } else {
2581  fromname = "";
2582  fromnum = "";
2583  }
2584  toname = S_COR(ast_channel_caller(ast)->id.name.valid, ast_channel_caller(ast)->id.name.str, "");
2585  tonum = S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, "");
2586  } else if (sub->calldirection == SKINNY_OUTGOING) {
2587  fromname = S_COR(ast_channel_caller(ast)->id.name.valid, ast_channel_caller(ast)->id.name.str, "");
2588  fromnum = S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, "");
2589  toname = S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, "");
2590  tonum = S_COR(ast_channel_connected(ast)->id.number.valid, ast_channel_connected(ast)->id.number.str, l->lastnumberdialed);
2591  } else {
2592  ast_verb(1, "Error sending Callinfo to %s(%d) - No call direction in sub\n", d->name, l->instance);
2593  return;
2594  }
2595 
2596  if (d->protocolversion < 17) {
2597  transmit_callinfo(d, l->instance, sub->callid, fromname, fromnum, toname, tonum, sub->calldirection, sub->origtonum, sub->origtoname);
2598  } else {
2599  transmit_callinfo_variable(d, l->instance, sub->callid, fromname, fromnum, toname, tonum, sub->calldirection, sub->origtonum, sub->origtoname);
2600  }
2601 }
2602 
2603 static void push_callinfo(struct skinny_subline *subline, struct skinny_subchannel *sub)
2604 {
2605  struct ast_channel *ast;
2606  struct skinny_device *d;
2607  struct skinny_line *l;
2608  struct ast_party_id connected_id;
2609  char *fromname;
2610  char *fromnum;
2611  char *toname;
2612  char *tonum;
2613 
2614  if (!sub || !sub->owner || !sub->line || !sub->line->device) {
2615  return;
2616  }
2617 
2618  ast = sub->owner;
2619  l = sub->line;
2620  d = l->device;
2621  connected_id = ast_channel_connected_effective_id(ast);
2622 
2623  if (sub->calldirection == SKINNY_INCOMING) {
2625  fromname = S_COR(connected_id.name.valid, connected_id.name.str, "");
2626  fromnum = S_COR(connected_id.number.valid, connected_id.number.str, "");
2627  } else {
2628  fromname = "";
2629  fromnum = "";
2630  }
2631  toname = S_COR(ast_channel_caller(ast)->id.name.valid, ast_channel_caller(ast)->id.name.str, "");
2632  tonum = S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, "");
2633  } else if (sub->calldirection == SKINNY_OUTGOING) {
2634  fromname = S_COR(ast_channel_caller(ast)->id.name.valid, ast_channel_caller(ast)->id.name.str, "");
2635  fromnum = S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, "");
2636  toname = S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, "");
2637  tonum = S_COR(ast_channel_connected(ast)->id.number.valid, ast_channel_connected(ast)->id.number.str, l->lastnumberdialed);
2638  } else {
2639  ast_verb(1, "Error sending Callinfo to %s(%d) - No call direction in sub\n", d->name, l->instance);
2640  return;
2641  }
2642 
2643  if (d->protocolversion < 17) {
2644  transmit_callinfo(subline->line->device, subline->line->instance, subline->callid, fromname, fromnum, toname, tonum, sub->calldirection, sub->origtonum, sub->origtoname);
2645  } else {
2646  transmit_callinfo_variable(subline->line->device, subline->line->instance, subline->callid, fromname, fromnum, toname, tonum, sub->calldirection, sub->origtonum, sub->origtoname);
2647  }
2648 }
2649 
2651 {
2652  struct skinny_req *req;
2653  struct skinny_line *l = sub->line;
2654  struct ast_format *tmpfmt;
2655  unsigned int framing;
2656 
2658  return;
2659 
2660  tmpfmt = ast_format_cap_get_format(l->cap, 0);
2661  framing = ast_format_cap_get_format_framing(l->cap, tmpfmt);
2662 
2665  req->data.openreceivechannel.packets = htolel(framing);
2667  req->data.openreceivechannel.echo = htolel(0);
2669 
2670  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting OPEN_RECEIVE_CHANNEL_MESSAGE to %s, confid %u, partyid %u, ms %u, fmt %d, echo %d, brate %d\n",
2671  d->name, sub->callid, sub->callid, framing, codec_ast2skinny(tmpfmt), 0, 0);
2672 
2673  ao2_ref(tmpfmt, -1);
2674 
2675  transmit_response(d, req);
2676 }
2677 
2678 static void transmit_start_tone(struct skinny_device *d, int tone, int instance, int reference)
2679 {
2680  struct skinny_req *req;
2681  if (!(req = req_alloc(sizeof(struct start_tone_message), START_TONE_MESSAGE)))
2682  return;
2683  req->data.starttone.tone = htolel(tone);
2684  req->data.starttone.instance = htolel(instance);
2685  req->data.starttone.reference = htolel(reference);
2686 
2687  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting START_TONE_MESSAGE to %s, tone %d, inst %d, ref %d\n",
2688  d->name, tone, instance, reference);
2689  transmit_response(d, req);
2690 }
2691 
2692 static void transmit_stop_tone(struct skinny_device *d, int instance, int reference)
2693 {
2694  struct skinny_req *req;
2695  if (!(req = req_alloc(sizeof(struct stop_tone_message), STOP_TONE_MESSAGE)))
2696  return;
2697  req->data.stoptone.instance = htolel(instance);
2698  req->data.stoptone.reference = htolel(reference);
2699 
2700  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting STOP_TONE_MESSAGE to %s, inst %d, ref %d\n",
2701  d->name, instance, reference);
2702  transmit_response(d, req);
2703 }
2704 
2705 static int keyset_translatebitmask(int keyset, int intmask)
2706 {
2707  int extmask = 0;
2708  int x, y;
2709  const struct soft_key_definitions *softkeymode = soft_key_default_definitions;
2710 
2711  for(x = 0; x < ARRAY_LEN(soft_key_default_definitions); x++) {
2712  if (softkeymode[x].mode == keyset) {
2713  const uint8_t *defaults = softkeymode[x].defaults;
2714 
2715  for (y = 0; y < softkeymode[x].count; y++) {
2716  if (intmask & (1 << (defaults[y]))) {
2717  extmask |= (1 << ((y)));
2718  }
2719  }
2720  break;
2721  }
2722  }
2723 
2724  return extmask;
2725 }
2726 
2727 static void transmit_selectsoftkeys(struct skinny_device *d, int instance, int callid, int softkey, int mask)
2728 {
2729  struct skinny_req *req;
2730  int newmask;
2731 
2732  if (!(req = req_alloc(sizeof(struct select_soft_keys_message), SELECT_SOFT_KEYS_MESSAGE)))
2733  return;
2734 
2735  newmask = keyset_translatebitmask(softkey, mask);
2736  req->data.selectsoftkey.instance = htolel(instance);
2737  req->data.selectsoftkey.reference = htolel(callid);
2738  req->data.selectsoftkey.softKeySetIndex = htolel(softkey);
2739  req->data.selectsoftkey.validKeyMask = htolel(newmask);
2740 
2741  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SELECT_SOFT_KEYS_MESSAGE to %s, inst %d, callid %d, softkey %d, mask 0x%08x\n",
2742  d->name, instance, callid, softkey, (unsigned)newmask);
2743  transmit_response(d, req);
2744 }
2745 
2746 static void transmit_lamp_indication(struct skinny_device *d, int stimulus, int instance, int indication)
2747 {
2748  struct skinny_req *req;
2749 
2750  if (!(req = req_alloc(sizeof(struct set_lamp_message), SET_LAMP_MESSAGE)))
2751  return;
2752 
2753  req->data.setlamp.stimulus = htolel(stimulus);
2754  req->data.setlamp.stimulusInstance = htolel(instance);
2755  req->data.setlamp.deviceStimulus = htolel(indication);
2756 
2757  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SET_LAMP_MESSAGE to %s, stim %d, inst %d, ind %d\n",
2758  d->name, stimulus, instance, indication);
2759  transmit_response(d, req);
2760 }
2761 
2762 static void transmit_ringer_mode(struct skinny_device *d, int mode)
2763 {
2764  struct skinny_req *req;
2765 
2766  if (!(req = req_alloc(sizeof(struct set_ringer_message), SET_RINGER_MESSAGE)))
2767  return;
2768 
2769  req->data.setringer.ringerMode = htolel(mode);
2770  /* XXX okay, I don't quite know what this is, but here's what happens (on a 7960).
2771  Note: The phone will always show as ringing on the display.
2772 
2773  1: phone will audibly ring over and over
2774  2: phone will audibly ring only once
2775  any other value, will NOT cause the phone to audibly ring
2776  */
2777  req->data.setringer.unknown1 = htolel(1);
2778  /* XXX the value here doesn't seem to change anything. Must be higher than 0.
2779  Perhaps a packet capture can shed some light on this. */
2780  req->data.setringer.unknown2 = htolel(1);
2781 
2782  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SET_RINGER_MESSAGE to %s, mode %d, unk1 1, unk2 1\n",
2783  d->name, mode);
2784  transmit_response(d, req);
2785 }
2786 
2787 static void transmit_clear_display_message(struct skinny_device *d, int instance, int reference)
2788 {
2789  struct skinny_req *req;
2790  if (!(req = req_alloc(sizeof(struct clear_display_message), CLEAR_DISPLAY_MESSAGE)))
2791  return;
2792 
2793  //what do we want hear CLEAR_DISPLAY_MESSAGE or CLEAR_PROMPT_STATUS???
2794  //if we are clearing the display, it appears there is no instance and refernece info (size 0)
2795  //req->data.clearpromptstatus.lineInstance = instance;
2796  //req->data.clearpromptstatus.callReference = reference;
2797 
2798  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting CLEAR_DISPLAY_MESSAGE to %s\n", d->name);
2799  transmit_response(d, req);
2800 }
2801 
2802 /* This function is not currently used, but will be (wedhorn)*/
2803 /* static void transmit_display_message(struct skinny_device *d, const char *text, int instance, int reference)
2804 {
2805  struct skinny_req *req;
2806 
2807  if (text == 0) {
2808  ast_verb(1, "Bug, Asked to display empty message\n");
2809  return;
2810  }
2811 
2812  if (!(req = req_alloc(sizeof(struct displaytext_message), DISPLAYTEXT_MESSAGE)))
2813  return;
2814 
2815  ast_copy_string(req->data.displaytext.text, text, sizeof(req->data.displaytext.text));
2816  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAYTEXT_MESSAGE to %s, text %s\n", d->name, text);
2817  transmit_response(d, req);
2818 } */
2819 
2820 static void transmit_displaynotify(struct skinny_device *d, const char *text, int t)
2821 {
2822  struct skinny_req *req;
2823 
2824  if (!(req = req_alloc(sizeof(struct display_notify_message), DISPLAY_NOTIFY_MESSAGE)))
2825  return;
2826 
2829 
2830  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_NOTIFY_MESSAGE to %s, text %s\n", d->name, text);
2831  transmit_response(d, req);
2832 }
2833 
2835 {
2836  struct skinny_req *req;
2837 
2838  if (!(req = req_alloc(sizeof(struct clear_prinotify_message), CLEAR_PRINOTIFY_MESSAGE)))
2839  return;
2840 
2841  req->data.clearprinotify.priority = htolel(priority);
2842 
2843  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting CLEAR_PRINOTIFY_MESSAGE to %s, priority %d\n", d->name, priority);
2844  transmit_response(d, req);
2845 }
2846 
2847 static void _transmit_displayprinotify(struct skinny_device *d, const char *text, const char *extratext, int timeout, int priority)
2848 {
2849  struct skinny_req *req;
2850 
2851  if (!(req = req_alloc(sizeof(struct display_prinotify_message), DISPLAY_PRINOTIFY_MESSAGE)))
2852  return;
2853 
2854  req->data.displayprinotify.timeout = htolel(timeout);
2855  req->data.displayprinotify.priority = htolel(priority);
2856 
2857  if ((char)*text == '\200') {
2858  int octalstrlen = strlen(text);
2860  ast_copy_string(req->data.displayprinotify.text+octalstrlen, extratext, sizeof(req->data.displayprinotify.text)-octalstrlen);
2861  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PRINOTIFY_MESSAGE to %s, '\\%03o\\%03o', '%s', timeout=%d, priority=%d\n",
2862  d->name, (unsigned)*text, (unsigned)*(text+1), extratext, timeout, priority);
2863  } else {
2865  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PRINOTIFY_MESSAGE to %s, '%s', timeout=%d, priority=%d\n",
2866  d->name, text, timeout, priority);
2867  }
2868 
2869  transmit_response(d, req);
2870 }
2871 
2872 static void _transmit_displayprinotifyvar(struct skinny_device *d, const char *text, const char *extratext, int timeout, int priority)
2873 {
2874  struct skinny_req *req;
2875  int packetlen;
2876 
2878  return;
2879 
2880  req->data.displayprinotifyvar.timeout = htolel(timeout);
2881  req->data.displayprinotifyvar.priority = htolel(priority);
2882 
2883  if ((char)*text == '\200') {
2884  int octalstrlen = strlen(text);
2886  ast_copy_string(req->data.displayprinotifyvar.text+octalstrlen, extratext, sizeof(req->data.displayprinotifyvar.text)-octalstrlen);
2887  packetlen = req->len - MAXDISPLAYNOTIFYSTR + strlen(text) + strlen(extratext);
2888  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PRINOTIFY_MESSAGE_VARIABLE to %s, '\\%03o\\%03o', '%s', timeout=%d, priority=%d\n",
2889  d->name, (unsigned)*text, (unsigned)*(text+1), extratext, timeout, priority);
2890  } else {
2892  packetlen = req->len - MAXDISPLAYNOTIFYSTR + strlen(text);
2893  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PRINOTIFY_MESSAGE_VARIABLE to %s, '%s', timeout=%d, priority=%d\n",
2894  d->name, text, timeout, priority);
2895  }
2896 
2897  req->len = (packetlen & ~0x3) + 4;
2898 
2899  transmit_response(d, req);
2900 }
2901 
2902 static void send_displayprinotify(struct skinny_device *d, const char *text, const char *extratext, int timeout, int priority)
2903 {
2904  if (d->protocolversion < 17) {
2905  _transmit_displayprinotify(d, text, extratext, timeout, priority);
2906  } else {
2907  _transmit_displayprinotifyvar(d, text, extratext, timeout, priority);
2908  }
2909 }
2910 
2911 static void transmit_displaypromptstatus(struct skinny_device *d, const char *text, const char *extratext, int t, int instance, int callid)
2912 {
2913  struct skinny_req *req;
2914 
2916  return;
2917 
2919  req->data.displaypromptstatus.lineInstance = htolel(instance);
2921 
2922  if ((char)*text == '\200') {
2923  int octalstrlen = strlen(text);
2925  ast_copy_string(req->data.displaypromptstatus.promptMessage+octalstrlen, extratext, sizeof(req->data.displaypromptstatus.promptMessage)-octalstrlen);
2926  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PROMPT_STATUS_MESSAGE to %s, '\\%03o\\%03o', '%s'\n",
2927  d->name, (unsigned)*text, (unsigned)*(text+1), extratext);
2928  } else {
2930  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PROMPT_STATUS_MESSAGE to %s, '%s'\n",
2931  d->name, text);
2932  }
2933  transmit_response(d, req);
2934 }
2935 
2936 static void transmit_displaypromptstatusvar(struct skinny_device *d, const char *text, const char *extratext, int t, int instance, int callid)
2937 {
2938  struct skinny_req *req;
2939  int packetlen;
2940 
2942  return;
2943 
2946 
2947  if ((char)*text == '\200') {
2948  int octalstrlen = strlen(text);
2950  ast_copy_string(req->data.displaypromptstatusvar.promptMessage+octalstrlen, extratext, sizeof(req->data.displaypromptstatusvar.promptMessage)-octalstrlen);
2951  packetlen = req->len - MAXCALLINFOSTR + strlen(text) + strlen(extratext);
2952  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PROMPT_STATUS_MESSAGE_VARIABLE to %s, '\\%03o\\%03o', '%s'\n",
2953  d->name, (unsigned)*text, (unsigned)*(text+1), extratext);
2954  } else {
2956  packetlen = req->len - MAXCALLINFOSTR + strlen(text);
2957  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DISPLAY_PROMPT_STATUS_MESSAGE_VARIABLE to %s, '%s'\n",
2958  d->name, text);
2959  }
2960  req->len = (packetlen & ~0x3) + 4;
2961 
2962  transmit_response(d, req);
2963 }
2964 
2965 static void send_displaypromptstatus(struct skinny_device *d, const char *text, const char *extratext, int t, int instance, int callid)
2966 {
2967  if (d->protocolversion < 17) {
2968  transmit_displaypromptstatus(d, text, extratext, t, instance, callid);
2969  } else {
2970  transmit_displaypromptstatusvar(d, text, extratext, t, instance, callid);
2971  }
2972 }
2973 
2974 static void transmit_clearpromptmessage(struct skinny_device *d, int instance, int callid)
2975 {
2976  struct skinny_req *req;
2977 
2978  if (!(req = req_alloc(sizeof(struct clear_prompt_message), CLEAR_PROMPT_MESSAGE)))
2979  return;
2980 
2981  req->data.clearpromptstatus.lineInstance = htolel(instance);
2982  req->data.clearpromptstatus.callReference = htolel(callid);
2983 
2984  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting CLEAR_PROMPT_MESSAGE to %s, inst %d, callid %d\n",
2985  d->name, instance, callid);
2986  transmit_response(d, req);
2987 }
2988 
2989 static void transmit_dialednumber(struct skinny_device *d, const char *text, int instance, int callid)
2990 {
2991  struct skinny_req *req;
2992 
2993  if (!(req = req_alloc(sizeof(struct dialed_number_message), DIALED_NUMBER_MESSAGE)))
2994  return;
2995 
2997  req->data.dialednumber.lineInstance = htolel(instance);
2998  req->data.dialednumber.callReference = htolel(callid);
2999 
3000  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DIALED_NUMBER_MESSAGE to %s, num %s, inst %d, callid %d\n",
3001  d->name, text, instance, callid);
3002  transmit_response(d, req);
3003 }
3004 
3006 {
3007  struct skinny_req *req;
3008 
3010  return;
3011 
3014 
3015  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting CLOSE_RECEIVE_CHANNEL_MESSAGE to %s, confid %d, callid %u\n",
3016  d->name, 0, sub->callid);
3017  transmit_response(d, req);
3018 }
3019 
3021 {
3022  struct skinny_req *req;
3023 
3025  return;
3026 
3027  req->data.stopmedia.conferenceId = htolel(0);
3029 
3030  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting STOP_MEDIA_TRANSMISSION_MESSAGE to %s, confid %d, passthrupartyid %u\n",
3031  d->name, 0, sub->callid);
3032  transmit_response(d, req);
3033 }
3034 
3035 static void transmit_startmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub, struct sockaddr_in dest,
3036  struct ast_format *format, unsigned int framing)
3037 {
3038  struct skinny_req *req;
3039 
3040  if (d->protocolversion < 17) {
3042  return;
3045  req->data.startmedia_ip4.remoteIp = dest.sin_addr.s_addr;
3046  req->data.startmedia_ip4.remotePort = htolel(ntohs(dest.sin_port));
3047  req->data.startmedia_ip4.packetSize = htolel(framing);
3053  } else {
3055  return;
3058  memcpy(req->data.startmedia_ip6.remoteIp, &dest.sin_addr.s_addr, sizeof(dest.sin_addr.s_addr));
3059  req->data.startmedia_ip6.remotePort = htolel(ntohs(dest.sin_port));
3060  req->data.startmedia_ip6.packetSize = htolel(framing);
3066  }
3067 
3068  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting START_MEDIA_TRANSMISSION_MESSAGE to %s, callid %u, passthrupartyid %u, ip %s:%d, ms %u, fmt %d, prec 127\n",
3069  d->name, sub->callid, sub->callid, ast_inet_ntoa(dest.sin_addr), dest.sin_port, framing, codec_ast2skinny(format));
3070  transmit_response(d, req);
3071 }
3072 
3074 {
3075  struct skinny_req *req;
3076 
3078  return;
3079 
3080  req->data.activatecallplane.lineInstance = htolel(l->instance);
3081 
3082  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting ACTIVATE_CALL_PLANE_MESSAGE to %s, inst %d\n",
3083  d->name, l->instance);
3084  transmit_response(d, req);
3085 }
3086 
3087 static void transmit_callstate(struct skinny_device *d, int buttonInstance, unsigned callid, int state)
3088 {
3089  struct skinny_req *req;
3090 
3091  if (!(req = req_alloc(sizeof(struct call_state_message), CALL_STATE_MESSAGE)))
3092  return;
3093 
3094  req->data.callstate.callState = htolel(state);
3095  req->data.callstate.lineInstance = htolel(buttonInstance);
3096  req->data.callstate.callReference = htolel(callid);
3097 
3098  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting CALL_STATE_MESSAGE to %s, state %s, inst %d, callid %u\n",
3099  d->name, callstate2str(state), buttonInstance, callid);
3100  transmit_response(d, req);
3101 }
3102 
3103 static void transmit_cfwdstate(struct skinny_device *d, struct skinny_line *l)
3104 {
3105  struct skinny_req *req;
3106  int anyon = 0;
3107 
3108  if (!(req = req_alloc(sizeof(struct forward_stat_message), FORWARD_STAT_MESSAGE)))
3109  return;
3110 
3111  if (l->cfwdtype & SKINNY_CFWD_ALL) {
3112  if (!ast_strlen_zero(l->call_forward_all)) {
3113  ast_copy_string(req->data.forwardstat.fwdallnum, l->call_forward_all, sizeof(req->data.forwardstat.fwdallnum));
3114  req->data.forwardstat.fwdall = htolel(1);
3115  anyon++;
3116  } else {
3117  req->data.forwardstat.fwdall = htolel(0);
3118  }
3119  }
3120  if (l->cfwdtype & SKINNY_CFWD_BUSY) {
3121  if (!ast_strlen_zero(l->call_forward_busy)) {
3122  ast_copy_string(req->data.forwardstat.fwdbusynum, l->call_forward_busy, sizeof(req->data.forwardstat.fwdbusynum));
3123  req->data.forwardstat.fwdbusy = htolel(1);
3124  anyon++;
3125  } else {
3126  req->data.forwardstat.fwdbusy = htolel(0);
3127  }
3128  }
3129  if (l->cfwdtype & SKINNY_CFWD_NOANSWER) {
3130  if (!ast_strlen_zero(l->call_forward_noanswer)) {
3131  ast_copy_string(req->data.forwardstat.fwdnoanswernum, l->call_forward_noanswer, sizeof(req->data.forwardstat.fwdnoanswernum));
3132  req->data.forwardstat.fwdnoanswer = htolel(1);
3133  anyon++;
3134  } else {
3135  req->data.forwardstat.fwdnoanswer = htolel(0);
3136  }
3137  }
3138  req->data.forwardstat.lineNumber = htolel(l->instance);
3139  if (anyon)
3141  else
3143 
3144  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting FORWARD_STAT_MESSAGE to %s, inst %d, all %s, busy %s, noans %s, acitve %d\n",
3145  d->name, l->instance, l->call_forward_all, l->call_forward_busy, l->call_forward_noanswer, anyon ? 7 : 0);
3146  transmit_response(d, req);
3147 }
3148 
3150 {
3151  struct skinny_req *req;
3152 
3154  return;
3155 
3159 
3160  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SPEED_DIAL_STAT_RES_MESSAGE to %s, inst %d, dir %s, display %s\n",
3161  d->name, sd->instance, sd->exten, sd->label);
3162  transmit_response(d, req);
3163 }
3164 
3165 //static void transmit_linestatres(struct skinny_device *d, struct skinny_line *l)
3166 static void transmit_linestatres(struct skinny_device *d, int instance)
3167 {
3168  struct skinny_req *req;
3169  struct skinny_line *l;
3170  struct skinny_speeddial *sd;
3171 
3172  if (!(req = req_alloc(sizeof(struct line_stat_res_message), LINE_STAT_RES_MESSAGE)))
3173  return;
3174 
3175  if ((l = find_line_by_instance(d, instance))) {
3176  req->data.linestat.lineNumber = letohl(l->instance);
3177  memcpy(req->data.linestat.lineDirNumber, l->name, sizeof(req->data.linestat.lineDirNumber));
3178  memcpy(req->data.linestat.lineDisplayName, l->label, sizeof(req->data.linestat.lineDisplayName));
3179  } else if ((sd = find_speeddial_by_instance(d, instance, 1))) {
3180  req->data.linestat.lineNumber = letohl(sd->instance);
3181  memcpy(req->data.linestat.lineDirNumber, sd->label, sizeof(req->data.linestat.lineDirNumber));
3182  memcpy(req->data.linestat.lineDisplayName, sd->label, sizeof(req->data.linestat.lineDisplayName));
3183  }
3184 
3185  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting LINE_STAT_RES_MESSAGE to %s, inst %d, num %s, label %s\n",
3186  d->name, l->instance, req->data.linestat.lineDirNumber, req->data.linestat.lineDisplayName);
3187  transmit_response(d, req);
3188 }
3189 
3191 {
3192  struct skinny_req *req;
3193  struct timeval now = ast_tvnow();
3194  struct ast_tm cmtime;
3195 
3196  if (!(req = req_alloc(sizeof(struct definetimedate_message), DEFINETIMEDATE_MESSAGE)))
3197  return;
3198 
3199  ast_localtime(&now, &cmtime, NULL);
3200  req->data.definetimedate.year = htolel(cmtime.tm_year+1900);
3201  req->data.definetimedate.month = htolel(cmtime.tm_mon+1);
3202  req->data.definetimedate.dayofweek = htolel(cmtime.tm_wday);
3203  req->data.definetimedate.day = htolel(cmtime.tm_mday);
3204  req->data.definetimedate.hour = htolel(cmtime.tm_hour);
3205  req->data.definetimedate.minute = htolel(cmtime.tm_min);
3206  req->data.definetimedate.seconds = htolel(cmtime.tm_sec);
3207  req->data.definetimedate.milliseconds = htolel(cmtime.tm_usec / 1000);
3208  req->data.definetimedate.timestamp = htolel(now.tv_sec);
3209 
3210  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting DEFINETIMEDATE_MESSAGE to %s, date %u %u %u dow %u time %u:%u:%u.%u\n",
3213  transmit_response(d, req);
3214 }
3215 
3217 {
3218  struct skinny_req *req;
3219  if (!(req = req_alloc(sizeof(struct version_res_message), VERSION_RES_MESSAGE)))
3220  return;
3221 
3222  ast_copy_string(req->data.version.version, d->version_id, sizeof(req->data.version.version));
3223 
3224  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting VERSION_RES_MESSAGE to %s, version %s\n", d->name, d->version_id);
3225  transmit_response(d, req);
3226 }
3227 
3228 static void transmit_serverres(struct skinny_device *d)
3229 {
3230  struct skinny_req *req;
3231  if (!(req = req_alloc(sizeof(struct server_res_message), SERVER_RES_MESSAGE)))
3232  return;
3233 
3234  memcpy(req->data.serverres.server[0].serverName, ourhost,
3235  sizeof(req->data.serverres.server[0].serverName));
3237  req->data.serverres.serverIpAddr[0] = htolel(d->ourip.s_addr);
3238 
3239  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SERVER_RES_MESSAGE to %s, srvname %s %s:%d\n",
3240  d->name, ourhost, ast_inet_ntoa(d->ourip), ourport);
3241  transmit_response(d, req);
3242 }
3243 
3245 {
3246  struct skinny_req *req;
3247  int i;
3248  int x;
3249  int y;
3250  int keydefcount;
3251  const struct soft_key_definitions *softkeymode = soft_key_default_definitions;
3252 
3253  if (!(req = req_alloc(sizeof(struct soft_key_set_res_message), SOFT_KEY_SET_RES_MESSAGE)))
3254  return;
3255 
3256  SKINNY_DEBUG(DEBUG_TEMPLATE, 3, "Creating Softkey Template\n");
3257 
3258  keydefcount = ARRAY_LEN(soft_key_default_definitions);
3260  req->data.softkeysets.softKeySetCount = htolel(keydefcount);
3261  req->data.softkeysets.totalSoftKeySetCount = htolel(keydefcount);
3262  for (x = 0; x < keydefcount; x++) {
3263  const uint8_t *defaults = softkeymode->defaults;
3264  /* XXX I wanted to get the size of the array dynamically, but that wasn't wanting to work.
3265  This will have to do for now. */
3266  for (y = 0; y < softkeymode->count; y++) {
3267  for (i = 0; i < (sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition)); i++) {
3268  if (defaults[y] == i+1) {
3269  req->data.softkeysets.softKeySetDefinition[softkeymode->mode].softKeyTemplateIndex[y] = (i+1);
3270  req->data.softkeysets.softKeySetDefinition[softkeymode->mode].softKeyInfoIndex[y] = htoles(i+301);
3271  SKINNY_DEBUG(DEBUG_TEMPLATE, 4, "softKeySetDefinition : softKeyTemplateIndex: %d softKeyInfoIndex: %d\n",
3272  i+1, i+301);
3273  }
3274  }
3275  }
3276  softkeymode++;
3277  }
3278 
3279  SKINNY_DEBUG(DEBUG_PACKET | DEBUG_TEMPLATE, 3, "Transmitting SOFT_KEY_SET_RES_MESSAGE to %s, template data\n",
3280  d->name);
3281  transmit_response(d, req);
3282 }
3283 
3285 {
3286  struct skinny_req *req;
3287 
3289  return;
3290 
3292  req->data.softkeytemplate.softKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition));
3293  req->data.softkeytemplate.totalSoftKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition));
3295  soft_key_template_default,
3296  sizeof(soft_key_template_default));
3297 
3298  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SOFT_KEY_TEMPLATE_RES_MESSAGE to %s, offset 0, keycnt %u, totalkeycnt %u, template data\n",
3300  transmit_response(d, req);
3301 }
3302 
3303 static void transmit_reset(struct skinny_device *d, int fullrestart)
3304 {
3305  struct skinny_req *req;
3306 
3307  if (!(req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE)))
3308  return;
3309 
3310  if (fullrestart)
3311  req->data.reset.resetType = 2;
3312  else
3313  req->data.reset.resetType = 1;
3314 
3315  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting RESET_MESSAGE to %s, type %s\n",
3316  d->name, (fullrestart) ? "Restarting" : "Resetting");
3317  transmit_response(d, req);
3318 }
3319 
3320 static void transmit_keepaliveack(struct skinnysession *s)
3321 {
3322  struct skinny_req *req;
3323 
3324  if (!(req = req_alloc(0, KEEP_ALIVE_ACK_MESSAGE)))
3325  return;
3326 
3327 #ifdef AST_DEVMODE
3328  {
3329  struct skinny_device *d = s->device;
3330  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting KEEP_ALIVE_ACK_MESSAGE to %s\n", (d ? d->name : "unregistered"));
3331  }
3332 #endif
3334 }
3335 
3337 {
3338  struct skinny_req *req;
3339 
3340  if (!(req = req_alloc(sizeof(struct register_ack_message), REGISTER_ACK_MESSAGE)))
3341  return;
3342 
3343  req->data.regack.res[0] = '0';
3344  req->data.regack.res[1] = '\0';
3346  memcpy(req->data.regack.dateTemplate, date_format, sizeof(req->data.regack.dateTemplate));
3347  req->data.regack.res2[0] = '0';
3348  req->data.regack.res2[1] = '\0';
3350 
3351 #ifdef AST_DEVMODE
3352  {
3353  short res = req->data.regack.res[0] << 8 | req->data.regack.res[1];
3354  unsigned int res2 = req->data.regack.res2[0] << 24 | req->data.regack.res2[1] << 16 | req->data.regack.res2[2] << 8 | req->data.regack.res2[3];
3355  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting REGISTER_ACK_MESSAGE to %s, keepalive %d, datetemplate %s, seckeepalive %d, res 0x%04x, res2 0x%08x\n",
3356  d->name, keep_alive, date_format, keep_alive, (unsigned)res, res2);
3357  }
3358 #endif
3359 
3360  transmit_response(d, req);
3361 }
3362 
3364 {
3365  struct skinny_req *req;
3366 
3367  if (!(req = req_alloc(0, CAPABILITIES_REQ_MESSAGE)))
3368  return;
3369 
3370  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting CAPABILITIES_REQ_MESSAGE to %s\n", d->name);
3371  transmit_response(d, req);
3372 }
3373 
3374 static void transmit_backspace(struct skinny_device *d, int instance, unsigned callid)
3375 {
3376  struct skinny_req *req;
3377 
3378  if (!(req = req_alloc(sizeof(struct bksp_req_message), BKSP_REQ_MESSAGE)))
3379  return;
3380 
3381  req->data.bkspmessage.instance = htolel(instance);
3382  req->data.bkspmessage.callreference = htolel(callid);
3383 
3384  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting BKSP_REQ_MESSAGE to %s, inst %d, callid %u \n",
3385  d->name, instance, callid);
3386  transmit_response(d, req);
3387 }
3388 
3389 static void transmit_serviceurlstat(struct skinny_device *d, int instance)
3390 {
3391  struct skinny_req *req;
3392  struct skinny_serviceurl *surl;
3393 
3394  if (!(req = req_alloc(sizeof(struct serviceurl_stat_message), SERVICEURL_STAT_MESSAGE)))
3395  return;
3396 
3397  AST_LIST_TRAVERSE(&d->serviceurls, surl, list) {
3398  if (surl->instance == instance) {
3399  break;
3400  }
3401  }
3402 
3403  if (surl) {
3405  memcpy(req->data.serviceurlmessage.url, surl->url, sizeof(req->data.serviceurlmessage.url));
3406  }
3407  req->data.serviceurlmessage.instance = htolel(instance);
3408 
3409  SKINNY_DEBUG(DEBUG_PACKET, 3, "Transmitting SERVICEURL_STAT_MESSAGE to %s, inst %d\n",
3410  d->name, instance);
3411  transmit_response(d, req);
3412 }
3413 
3414 static int skinny_extensionstate_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
3415 {
3416  struct skinny_container *container = data;
3417  struct skinny_device *d = NULL;
3418  char hint[AST_MAX_EXTENSION];
3419  int state = info->exten_state;
3420 
3421  /* only interested in device state here */
3422  if (info->reason != AST_HINT_UPDATE_DEVICE) {
3423  return 0;
3424  }
3425 
3426  if (container->type == SKINNY_SDCONTAINER) {
3427  struct skinny_speeddial *sd = container->data;
3428  d = sd->parent;
3429 
3430  SKINNY_DEBUG(DEBUG_HINT, 3, "Got hint %s on speeddial %s\n", ast_extension_state2str(state), sd->label);
3431 
3432  if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, sd->context, sd->exten)) {
3433  /* If they are not registered, we will override notification and show no availability */
3437  return 0;
3438  }
3439  switch (state) {
3440  case AST_EXTENSION_DEACTIVATED: /* Retry after a while */
3441  case AST_EXTENSION_REMOVED: /* Extension is gone */
3442  SKINNY_DEBUG(DEBUG_HINT, 3, "Extension state: Watcher for hint %s %s. Notify Device %s\n",
3443  exten, state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", d->name);
3444  sd->stateid = -1;
3447  break;
3448  case AST_EXTENSION_RINGING:
3452  break;
3453  case AST_EXTENSION_BUSY: /* callstate = SKINNY_BUSY wasn't wanting to work - I'll settle for this */
3454  case AST_EXTENSION_INUSE:
3457  break;
3458  case AST_EXTENSION_ONHOLD:
3461  break;
3463  default:
3466  break;
3467  }
3468  }
3469  sd->laststate = state;
3470  } else if (container->type == SKINNY_SUBLINECONTAINER) {
3471  struct skinny_subline *subline = container->data;
3472  struct skinny_line *l = subline->line;
3473  d = l->device;
3474 
3475  SKINNY_DEBUG(DEBUG_HINT, 3, "Got hint %s on subline %s (%s@%s)\n", ast_extension_state2str(state), subline->name, exten, context);
3476 
3477  subline->extenstate = state;
3478 
3479  if (subline->callid == 0) {
3480  return 0;
3481  }
3482 
3483  switch (state) {
3484  case AST_EXTENSION_RINGING: /* Handled by normal ringin */
3485  break;
3486  case AST_EXTENSION_INUSE:
3487  if (subline->sub && (subline->sub->substate == SKINNY_CONNECTED)) { /* Device has a real call */
3488  transmit_callstate(d, l->instance, subline->callid, SKINNY_CONNECTED);
3489  transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_CONNECTED, KEYMASK_ALL);
3490  send_displaypromptstatus(d, OCTAL_CONNECTED, "", 0, l->instance, subline->callid);
3491  } else { /* Some other device has active call */
3492  transmit_callstate(d, l->instance, subline->callid, SKINNY_CALLREMOTEMULTILINE);
3494  send_displaypromptstatus(d, "In Use", "", 0, l->instance, subline->callid);
3495  }
3499  break;
3500  case AST_EXTENSION_ONHOLD:
3501  transmit_callstate(d, l->instance, subline->callid, SKINNY_HOLD);
3502  transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_SLAHOLD, KEYMASK_ALL);
3503  send_displaypromptstatus(d, "Hold", "", 0, l->instance, subline->callid);
3506  break;
3508  transmit_callstate(d, l->instance, subline->callid, SKINNY_ONHOOK);
3509  transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_ONHOOK, KEYMASK_ALL);
3510  transmit_clearpromptmessage(d, l->instance, subline->callid);
3513  subline->callid = 0;
3514  break;
3515  default:
3516  ast_log(LOG_WARNING, "AST_EXTENSION_STATE %s not configured\n", ast_extension_state2str(state));
3517  }
3518  } else {
3519  ast_log(LOG_WARNING, "Invalid data supplied to skinny_extensionstate_cb\n");
3520  }
3521 
3522  return 0;
3523 }
3524 
3525 static void update_connectedline(struct skinny_subchannel *sub, const void *data, size_t datalen)
3526 {
3527  struct ast_channel *c = sub->owner;
3528  struct skinny_line *l = sub->line;
3529  struct skinny_device *d = l->device;
3530 
3531  if (!d->session) {
3532  return;
3533  }
3534 
3535  if (sub->calldirection == SKINNY_OUTGOING && !sub->origtonum) {
3536  /* Do not set origtonum before here or origtoname won't be set */
3537  sub->origtonum = ast_strdup(sub->exten);
3538  if (ast_channel_connected(c)->id.name.valid) {
3539  sub->origtoname = ast_strdup(ast_channel_connected(c)->id.name.str);
3540  }
3541  }
3542 
3543  if (!ast_channel_caller(c)->id.number.valid
3545  || !ast_channel_connected(c)->id.number.valid
3547  return;
3548 
3549  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Updating\n", sub->callid);
3550 
3551  send_callinfo(sub);
3552 }
3553 
3554 static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
3555 {
3556  struct skinny_line *l = userdata;
3557  struct skinny_device *d = l->device;
3558  struct skinny_line *l2;
3559  int dev_msgs = 0;
3560 
3561  if (!d || !d->session) {
3562  return;
3563  }
3564 
3565  if (msg && ast_mwi_state_type() == stasis_message_type(msg)) {
3566  struct ast_mwi_state *mwi_state = stasis_message_data(msg);
3567  l->newmsgs = mwi_state->new_msgs;
3568  }
3569 
3570  if (l->newmsgs) {
3572  } else {
3574  }
3575 
3576  /* find out wether the device lamp should be on or off */
3577  AST_LIST_TRAVERSE(&d->lines, l2, list) {
3578  if (l2->newmsgs) {
3579  dev_msgs++;
3580  }
3581  }
3582 
3583  if (dev_msgs) {
3585  } else {
3587  }
3588  ast_verb(3, "Skinny mwi_event_cb found %d new messages\n", l->newmsgs);
3589 }
3590 
3591 /* I do not believe skinny can deal with video.
3592  Anyone know differently? */
3593 /* Yes, it can. Currently 7985 and Cisco VT Advantage do video. */
3595 {
3596  struct skinny_subchannel *sub = NULL;
3597 
3598  if (!(sub = ast_channel_tech_pvt(c)) || !(sub->vrtp))
3600 
3601  ao2_ref(sub->vrtp, +1);
3602  *instance = sub->vrtp;
3603 
3605 }
3606 
3608 {
3609  struct skinny_subchannel *sub = NULL;
3610  struct skinny_line *l;
3612 
3613  SKINNY_DEBUG(DEBUG_AUDIO, 4, "skinny_get_rtp_peer() Channel = %s\n", ast_channel_name(c));
3614 
3615  if (!(sub = ast_channel_tech_pvt(c)))
3617 
3618  skinny_locksub(sub);
3619 
3620  if (!(sub->rtp)){
3621  skinny_unlocksub(sub);
3623  }
3624 
3625  ao2_ref(sub->rtp, +1);
3626  *instance = sub->rtp;
3627 
3628  l = sub->line;
3629 
3630  if (!l->directmedia || l->nat){
3632  SKINNY_DEBUG(DEBUG_AUDIO, 4, "skinny_get_rtp_peer() Using AST_RTP_GLUE_RESULT_LOCAL \n");
3633  }
3634 
3635  skinny_unlocksub(sub);
3636 
3637  return res;
3638 
3639 }
3640 
3641 static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, const struct ast_format_cap *codecs, int nat_active)
3642 {
3643  struct skinny_subchannel *sub;
3644  struct skinny_line *l;
3645  struct skinny_device *d;
3646  struct sockaddr_in us = { 0, };
3647  struct sockaddr_in them = { 0, };
3648  struct ast_sockaddr them_tmp;
3649  struct ast_sockaddr us_tmp;
3650 
3651  sub = ast_channel_tech_pvt(c);
3652 
3653  if (ast_channel_state(c) != AST_STATE_UP)
3654  return 0;
3655 
3656  if (!sub) {
3657  return -1;
3658  }
3659 
3660  l = sub->line;
3661  d = l->device;
3662 
3663  if (rtp){
3664  struct ast_format *tmpfmt;
3665  unsigned int framing;
3666  ast_rtp_instance_get_remote_address(rtp, &them_tmp);
3667  ast_sockaddr_to_sin(&them_tmp, &them);
3668 
3669  /* Shutdown any early-media or previous media on re-invite */
3671 
3672  SKINNY_DEBUG(DEBUG_AUDIO, 4, "Peerip = %s:%d\n", ast_inet_ntoa(them.sin_addr), ntohs(them.sin_port));
3673 
3674  tmpfmt = ast_format_cap_get_format(l->cap, 0);
3675  framing = ast_format_cap_get_format_framing(l->cap, tmpfmt);
3676 
3677  SKINNY_DEBUG(DEBUG_AUDIO, 4, "Setting payloadType to '%s' (%u ms)\n", ast_format_get_name(tmpfmt), framing);
3678 
3679  if (!(l->directmedia) || (l->nat)){
3680  ast_rtp_instance_get_local_address(rtp, &us_tmp);
3681  ast_sockaddr_to_sin(&us_tmp, &us);
3682  us.sin_addr.s_addr = us.sin_addr.s_addr ? us.sin_addr.s_addr : d->ourip.s_addr;
3683  transmit_startmediatransmission(d, sub, us, tmpfmt, framing);
3684  } else {
3685  transmit_startmediatransmission(d, sub, them, tmpfmt, framing);
3686  }
3687 
3688  ao2_ref(tmpfmt, -1);
3689 
3690  return 0;
3691  }
3692  /* Need a return here to break the bridge */
3693  return 0;
3694 }
3695 
3697  .type = "Skinny",
3698  .get_rtp_info = skinny_get_rtp_peer,
3699  .get_vrtp_info = skinny_get_vrtp_peer,
3700  .update_peer = skinny_set_rtp_peer,
3701 };
3702 
3703 #ifdef AST_DEVMODE
3704 static char *skinny_debugs(void)
3705 {
3706  char *ptr;
3707  int posn = 0;
3708 
3709  ptr = dbgcli_buf;
3710  ptr[0] = '\0';
3711  if (skinnydebug & DEBUG_GENERAL) {
3712  strcpy(ptr, "general "); /* SAFE */
3713  posn += 8;
3714  ptr += 8;
3715  }
3716  if (skinnydebug & DEBUG_SUB) {
3717  strcpy(ptr, "sub "); /* SAFE */
3718  posn += 4;
3719  ptr += 4;
3720  }
3721  if (skinnydebug & DEBUG_AUDIO) {
3722  strcpy(ptr, "audio "); /* SAFE */
3723  posn += 6;
3724  ptr += 6;
3725  }
3726  if (skinnydebug & DEBUG_PACKET) {
3727  strcpy(ptr, "packet "); /* SAFE */
3728  posn += 7;
3729  ptr += 7;
3730  }
3731  if (skinnydebug & DEBUG_LOCK) {
3732  strcpy(ptr, "lock "); /* SAFE */
3733  posn += 5;
3734  ptr += 5;
3735  }
3736  if (skinnydebug & DEBUG_TEMPLATE) {
3737  strcpy(ptr, "template "); /* SAFE */
3738  posn += 9;
3739  ptr += 9;
3740  }
3741  if (skinnydebug & DEBUG_THREAD) {
3742  strcpy(ptr, "thread "); /* SAFE */
3743  posn += 7;
3744  ptr += 7;
3745  }
3746  if (skinnydebug & DEBUG_HINT) {
3747  strcpy(ptr, "hint "); /* SAFE */
3748  posn += 5;
3749  ptr += 5;
3750  }
3751  if (skinnydebug & DEBUG_KEEPALIVE) {
3752  strcpy(ptr, "keepalive "); /* SAFE */
3753  posn += 10;
3754  ptr += 10;
3755  }
3756  if (posn > 0) {
3757  strncpy(--ptr, "\0", 1);
3758  }
3759  return dbgcli_buf;
3760 }
3761 
3762 static char *complete_skinny_debug(const char *line, const char *word, int pos, int state)
3763 {
3764  const char *debugOpts[]={ "all","audio","hint","keepalive","lock","off","packet","show","sub","template","thread",NULL };
3765  char *wordptr = (char *)word;
3766  char buf[32];
3767  char *bufptr = buf;
3768  int buflen = sizeof(buf);
3769  int wordlen;
3770  int which = 0;
3771  int i = 0;
3772 
3773  if (*word == '+' || *word == '-' || *word == '!') {
3774  *bufptr = *word;
3775  wordptr++;
3776  bufptr++;
3777  buflen--;
3778  }
3779  wordlen = strlen(wordptr);
3780 
3781  while (debugOpts[i]) {
3782  if (!strncasecmp(wordptr, debugOpts[i], wordlen) && ++which > state) {
3783  ast_copy_string(bufptr, debugOpts[i], buflen);
3784  return ast_strdup(buf);
3785  }
3786  i++;
3787  }
3788 
3789  return NULL;
3790 }
3791 
3792 static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3793 {
3794  int i;
3795  int result = 0;
3796  const char *arg;
3797  int bitmask;
3798  int negate;
3799 
3800  switch (cmd) {
3801  case CLI_INIT:
3802  e->command = "skinny debug";
3803  e->usage =
3804  "Usage: skinny debug {audio|hint|keepalive|lock|off|packet|show|sub|template|thread}\n"
3805  " Enables/Disables various Skinny debugging messages\n";
3806  return NULL;
3807  case CLI_GENERATE:
3808  return complete_skinny_debug(a->line, a->word, a->pos, a->n);
3809 
3810  }
3811 
3812  if (a->argc < 3)
3813  return CLI_SHOWUSAGE;
3814 
3815  if (a->argc == 3 && !strncasecmp(a->argv[e->args-1], "show", 4)) {
3816  ast_cli(a->fd, "Skinny Debugging - %s\n", skinny_debugs());
3817  return CLI_SUCCESS;
3818  }
3819 
3820  for(i = e->args; i < a->argc; i++) {
3821  result++;
3822  arg = a->argv[i];
3823 
3824  if (!strncasecmp(arg, "off", 3)) {
3825  skinnydebug = 0;
3826  continue;
3827  }
3828 
3829  if (!strncasecmp(arg, "all", 3)) {
3831  continue;
3832  }
3833 
3834  if (!strncasecmp(arg, "-", 1) || !strncasecmp(arg, "!", 1)) {
3835  negate = 1;
3836  arg++;
3837  } else if (!strncasecmp(arg, "+", 1)) {
3838  negate = 0;
3839  arg++;
3840  } else {
3841  negate = 0;
3842  }
3843 
3844  if (!strncasecmp(arg, "general", 7)) {
3845  bitmask = DEBUG_GENERAL;
3846  } else if (!strncasecmp(arg, "sub", 3)) {
3847  bitmask = DEBUG_SUB;
3848  } else if (!strncasecmp(arg, "packet", 6)) {
3849  bitmask = DEBUG_PACKET;
3850  } else if (!strncasecmp(arg, "audio", 5)) {
3851  bitmask = DEBUG_AUDIO;
3852  } else if (!strncasecmp(arg, "lock", 4)) {
3853  bitmask = DEBUG_LOCK;
3854  } else if (!strncasecmp(arg, "template", 8)) {
3855  bitmask = DEBUG_TEMPLATE;
3856  } else if (!strncasecmp(arg, "thread", 6)) {
3857  bitmask = DEBUG_THREAD;
3858  } else if (!strncasecmp(arg, "hint", 4)) {
3859  bitmask = DEBUG_HINT;
3860  } else if (!strncasecmp(arg, "keepalive", 9)) {
3861  bitmask = DEBUG_KEEPALIVE;
3862  } else {
3863  ast_cli(a->fd, "Skinny Debugging - option '%s' unknown\n", a->argv[i]);
3864  result--;
3865  continue;
3866  }
3867 
3868  if (negate) {
3869  skinnydebug &= ~bitmask;
3870  } else {
3871  skinnydebug |= bitmask;
3872  }
3873  }
3874  if (result) {
3875  ast_cli(a->fd, "Skinny Debugging - %s\n", skinnydebug ? skinny_debugs() : "off");
3876  return CLI_SUCCESS;
3877  } else {
3878  return CLI_SHOWUSAGE;
3879  }
3880 }
3881 #endif
3882 
3883 static char *handle_skinny_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3884 {
3885  switch (cmd) {
3886  case CLI_INIT:
3887  e->command = "skinny reload";
3888  e->usage =
3889  "Usage: skinny reload\n"
3890  " Reloads the chan_skinny configuration\n";
3891  return NULL;
3892  case CLI_GENERATE:
3893  return NULL;
3894  }
3895 
3896  if (a->argc != e->args)
3897  return CLI_SHOWUSAGE;
3898 
3899  skinny_reload();
3900  return CLI_SUCCESS;
3901 
3902 }
3903 
3904 static char *complete_skinny_devices(const char *word, int state)
3905 {
3906  struct skinny_device *d;
3907  int wordlen = strlen(word), which = 0;
3908 
3910  if (!strncasecmp(word, d->name, wordlen) && ++which > state) {
3911  return ast_strdup(d->name);
3912  }
3913  }
3914 
3915  return NULL;
3916 }
3917 
3918 static char *complete_skinny_show_device(const char *line, const char *word, int pos, int state)
3919 {
3920  return (pos == 3 ? complete_skinny_devices(word, state) : NULL);
3921 }
3922 
3923 static char *complete_skinny_reset(const char *line, const char *word, int pos, int state)
3924 {
3925  if (pos == 2) {
3926  static const char * const completions[] = { "all", NULL };
3927  char *ret = ast_cli_complete(word, completions, state);
3928  if (!ret) {
3929  ret = complete_skinny_devices(word, state - 1);
3930  }
3931  return ret;
3932  } else if (pos == 3) {
3933  static const char * const completions[] = { "restart", NULL };
3934  return ast_cli_complete(word, completions, state);
3935  }
3936 
3937  return NULL;
3938 }
3939 
3940 static char *complete_skinny_show_line(const char *line, const char *word, int pos, int state)
3941 {
3942  if (pos == 3) {
3943  struct skinny_device *d;
3944  struct skinny_line *l;
3945  int wordlen = strlen(word), which = 0;
3946 
3948  AST_LIST_TRAVERSE(&d->lines, l, list) {
3949  if (!strncasecmp(word, l->name, wordlen) && ++which > state) {
3950  return ast_strdup(l->name);
3951  }
3952  }
3953  }
3954  } else if (pos == 4) {
3955  static const char * const completions[] = { "on", NULL };
3956  return ast_cli_complete(word, completions, state);
3957  } else if (pos == 5) {
3958  return complete_skinny_devices(word, state);
3959  }
3960 
3961  return NULL;
3962 }
3963 
3964 static char *handle_skinny_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3965 {
3966  struct skinny_device *d;
3967 
3968  switch (cmd) {
3969  case CLI_INIT:
3970  e->command = "skinny reset";
3971  e->usage =
3972  "Usage: skinny reset <DeviceId|DeviceName|all> [restart]\n"
3973  " Causes a Skinny device to reset itself, optionally with a full restart\n";
3974  return NULL;
3975  case CLI_GENERATE:
3976  return complete_skinny_reset(a->line, a->word, a->pos, a->n);
3977  }
3978 
3979  if (a->argc < 3 || a->argc > 4)
3980  return CLI_SHOWUSAGE;
3981 
3984  int resetonly = 1;
3985  if (!strcasecmp(a->argv[2], d->id) || !strcasecmp(a->argv[2], d->name) || !strcasecmp(a->argv[2], "all")) {
3986  if (!(d->session))
3987  continue;
3988 
3989  if (a->argc == 4 && !strcasecmp(a->argv[3], "restart"))
3990  resetonly = 0;
3991 
3992  transmit_reset(d, resetonly);
3993  }
3994  }
3996  return CLI_SUCCESS;
3997 }
3998 
3999 static char *device2str(int type)
4000 {
4001  char *tmp;
4002 
4003  switch (type) {
4004  case SKINNY_DEVICE_NONE:
4005  return "No Device";
4007  return "30SP Plus";
4009  return "12SP Plus";
4010  case SKINNY_DEVICE_12SP:
4011  return "12SP";
4012  case SKINNY_DEVICE_12:
4013  return "12";
4014  case SKINNY_DEVICE_30VIP:
4015  return "30VIP";
4016  case SKINNY_DEVICE_7910:
4017  return "7910";
4018  case SKINNY_DEVICE_7960:
4019  return "7960";
4020  case SKINNY_DEVICE_7940:
4021  return "7940";
4022  case SKINNY_DEVICE_7935:
4023  return "7935";
4024  case SKINNY_DEVICE_ATA186:
4025  return "ATA186";
4026  case SKINNY_DEVICE_7941:
4027  return "7941";
4028  case SKINNY_DEVICE_7971:
4029  return "7971";
4030  case SKINNY_DEVICE_7914:
4031  return "7914";
4032  case SKINNY_DEVICE_7985:
4033  return "7985";
4034  case SKINNY_DEVICE_7911:
4035  return "7911";
4036  case SKINNY_DEVICE_7961GE:
4037  return "7961GE";
4038  case SKINNY_DEVICE_7941GE:
4039  return "7941GE";
4040  case SKINNY_DEVICE_7931:
4041  return "7931";
4042  case SKINNY_DEVICE_7921:
4043  return "7921";
4044  case SKINNY_DEVICE_7906:
4045  return "7906";
4046  case SKINNY_DEVICE_7962:
4047  return "7962";
4048  case SKINNY_DEVICE_7937:
4049  return "7937";
4050  case SKINNY_DEVICE_7942:
4051  return "7942";
4052  case SKINNY_DEVICE_7945:
4053  return "7945";
4054  case SKINNY_DEVICE_7965:
4055  return "7965";
4056  case SKINNY_DEVICE_7975:
4057  return "7975";
4058  case SKINNY_DEVICE_7905:
4059  return "7905";
4060  case SKINNY_DEVICE_7920:
4061  return "7920";
4062  case SKINNY_DEVICE_7970:
4063  return "7970";
4064  case SKINNY_DEVICE_7912:
4065  return "7912";
4066  case SKINNY_DEVICE_7902:
4067  return "7902";
4068  case SKINNY_DEVICE_CIPC:
4069  return "IP Communicator";
4070  case SKINNY_DEVICE_7961:
4071  return "7961";
4072  case SKINNY_DEVICE_7936:
4073  return "7936";
4075  return "SCCPGATEWAY_AN";
4077  return "SCCPGATEWAY_BRI";
4078  case SKINNY_DEVICE_UNKNOWN:
4079  return "Unknown";
4080  default:
4082  return "Unknown";
4083  snprintf(tmp, DEVICE2STR_BUFSIZE, "UNKNOWN-%d", type);
4084  return tmp;
4085  }
4086 }
4087 
4088 static char *_skinny_show_devices(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char * const *argv)
4089 {
4090  struct skinny_device *d;
4091  struct skinny_line *l;
4092  const char *id;
4093  char idtext[256] = "";
4094  int total_devices = 0;
4095 
4096  if (s) { /* Manager - get ActionID */
4097  id = astman_get_header(m, "ActionID");
4098  if (!ast_strlen_zero(id))
4099  snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
4100  }
4101 
4102  switch (argc) {
4103  case 3:
4104  break;
4105  default:
4106  return CLI_SHOWUSAGE;
4107  }
4108 
4109  if (!s) {
4110  ast_cli(fd, "Name DeviceId IP Type R NL\n");
4111  ast_cli(fd, "-------------------- ---------------- --------------- --------------- - --\n");
4112  }
4113 
4116  int numlines = 0;
4117  total_devices++;
4118  AST_LIST_TRAVERSE(&d->lines, l, list) {
4119  numlines++;
4120  }
4121  if (!s) {
4122  ast_cli(fd, "%-20s %-16s %-15s %-15s %c %2d\n",
4123  d->name,
4124  d->id,
4125  d->session?ast_inet_ntoa(d->session->sin.sin_addr):"",
4126  device2str(d->type),
4127  d->session?'Y':'N',
4128  numlines);
4129  } else {
4130  astman_append(s,
4131  "Event: DeviceEntry\r\n%s"
4132  "Channeltype: SKINNY\r\n"
4133  "ObjectName: %s\r\n"
4134  "ChannelObjectType: device\r\n"
4135  "DeviceId: %s\r\n"
4136  "IPaddress: %s\r\n"
4137  "Type: %s\r\n"
4138  "Devicestatus: %s\r\n"
4139  "NumberOfLines: %d\r\n",
4140  idtext,
4141  d->name,
4142  d->id,
4143  d->session?ast_inet_ntoa(d->session->sin.sin_addr):"-none-",
4144  device2str(d->type),
4145  d->session?"registered":"unregistered",
4146  numlines);
4147  }
4148  }
4150 
4151  if (total)
4152  *total = total_devices;
4153 
4154  return CLI_SUCCESS;
4155 }
4156 
4157 /*! \brief Show SKINNY devices in the manager API */
4158 /* Inspired from chan_sip */
4159 static int manager_skinny_show_devices(struct mansession *s, const struct message *m)
4160 {
4161  const char *a[] = {"skinny", "show", "devices"};
4162  int total = 0;
4163 
4164  astman_send_listack(s, m, "Device status list will follow", "start");
4165 
4166  /* List the devices in separate manager events */
4167  _skinny_show_devices(-1, &total, s, m, 3, a);
4168 
4169  /* Send final confirmation */
4170  astman_send_list_complete_start(s, m, "DevicelistComplete", total);
4172  return 0;
4173 }
4174 
4175 static char *handle_skinny_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4176 {
4177 
4178  switch (cmd) {
4179  case CLI_INIT:
4180  e->command = "skinny show devices";
4181  e->usage =
4182  "Usage: skinny show devices\n"
4183  " Lists all devices known to the Skinny subsystem.\n";
4184  return NULL;
4185  case CLI_GENERATE:
4186  return NULL;
4187  }
4188 
4189  return _skinny_show_devices(a->fd, NULL, NULL, NULL, a->argc, a->argv);
4190 }
4191 
4192 static char *_skinny_show_device(int type, int fd, struct mansession *s, const struct message *m, int argc, const char * const *argv)
4193 {
4194  struct skinny_device *d;
4195  struct skinny_line *l;
4196  struct skinny_speeddial *sd;
4197  struct skinny_addon *sa;
4198  struct skinny_serviceurl *surl;
4199  struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
4200 
4201  if (argc < 4) {
4202  return CLI_SHOWUSAGE;
4203  }
4204 
4206  AST_LIST_TRAVERSE(&devices, d, list) {
4207  if (!strcasecmp(argv[3], d->id) || !strcasecmp(argv[3], d->name)) {
4208  int numlines = 0, numaddons = 0, numspeeddials = 0, numserviceurls = 0;
4209 
4210  AST_LIST_TRAVERSE(&d->lines, l, list){
4211  numlines++;
4212  }
4213 
4214  AST_LIST_TRAVERSE(&d->addons, sa, list) {
4215  numaddons++;
4216  }
4217 
4218  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
4219  numspeeddials++;
4220  }
4221 
4222  AST_LIST_TRAVERSE(&d->serviceurls, surl, list) {
4223  numserviceurls++;
4224  }
4225 
4226  if (type == 0) { /* CLI */
4227  ast_cli(fd, "Name: %s\n", d->name);
4228  ast_cli(fd, "Id: %s\n", d->id);
4229  ast_cli(fd, "version: %s\n", S_OR(d->version_id, "Unknown"));
4230  ast_cli(fd, "Ip address: %s\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown"));
4231  ast_cli(fd, "Port: %d\n", (d->session ? ntohs(d->session->sin.sin_port) : 0));
4232  ast_cli(fd, "Device Type: %s\n", device2str(d->type));
4233  ast_cli(fd, "Conf Codecs: %s\n", ast_format_cap_get_names(d->confcap, &codec_buf));
4234  ast_cli(fd, "Neg Codecs: %s\n", ast_format_cap_get_names(d->cap, &codec_buf));
4235  ast_cli(fd, "Registered: %s\n", (d->session ? "Yes" : "No"));
4236  ast_cli(fd, "Lines: %d\n", numlines);
4237  AST_LIST_TRAVERSE(&d->lines, l, list) {
4238  ast_cli(fd, " %s (%s)\n", l->name, l->label);
4239  }
4240  ast_cli(fd, "Addons: %d\n", numaddons);
4241  AST_LIST_TRAVERSE(&d->addons, sa, list) {
4242  ast_cli(fd, " %s\n", sa->type);
4243  }
4244  ast_cli(fd, "Speeddials: %d\n", numspeeddials);
4245  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
4246  ast_cli(fd, " %s (%s) ishint: %d\n", sd->exten, sd->label, sd->isHint);
4247  }
4248  ast_cli(fd, "ServiceURLs: %d\n", numserviceurls);
4249  AST_LIST_TRAVERSE(&d->serviceurls, surl, list) {
4250  ast_cli(fd, " %s (%s)\n", surl->displayName, surl->url);
4251  }
4252  } else { /* manager */
4253  astman_append(s, "Channeltype: SKINNY\r\n");
4254  astman_append(s, "ObjectName: %s\r\n", d->name);
4255  astman_append(s, "ChannelObjectType: device\r\n");
4256  astman_append(s, "Id: %s\r\n", d->id);
4257  astman_append(s, "version: %s\r\n", S_OR(d->version_id, "Unknown"));
4258  astman_append(s, "Ipaddress: %s\r\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown"));
4259  astman_append(s, "Port: %d\r\n", (d->session ? ntohs(d->session->sin.sin_port) : 0));
4260  astman_append(s, "DeviceType: %s\r\n", device2str(d->type));
4261  astman_append(s, "Codecs: %s\r\n", ast_format_cap_get_names(d->confcap, &codec_buf));
4262  astman_append(s, "CodecOrder: %s\r\n", ast_format_cap_get_names(d->cap, &codec_buf));
4263  astman_append(s, "Devicestatus: %s\r\n", (d->session?"registered":"unregistered"));
4264  astman_append(s, "NumberOfLines: %d\r\n", numlines);
4265  AST_LIST_TRAVERSE(&d->lines, l, list) {
4266  astman_append(s, "Line: %s (%s)\r\n", l->name, l->label);
4267  }
4268  astman_append(s, "NumberOfAddons: %d\r\n", numaddons);
4269  AST_LIST_TRAVERSE(&d->addons, sa, list) {
4270  astman_append(s, "Addon: %s\r\n", sa->type);
4271  }
4272  astman_append(s, "NumberOfSpeeddials: %d\r\n", numspeeddials);
4273  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
4274  astman_append(s, "Speeddial: %s (%s) ishint: %d\r\n", sd->exten, sd->label, sd->isHint);
4275  }
4276  astman_append(s, "ServiceURLs: %d\r\n", numserviceurls);
4277  AST_LIST_TRAVERSE(&d->serviceurls, surl, list) {
4278  astman_append(s, " %s (%s)\r\n", surl->displayName, surl->url);
4279  }
4280  }
4281  }
4282  }
4284  return CLI_SUCCESS;
4285 }
4286 
4287 static int manager_skinny_show_device(struct mansession *s, const struct message *m)
4288 {
4289  const char *a[4];
4290  const char *device;
4291 
4292  device = astman_get_header(m, "Device");
4293  if (ast_strlen_zero(device)) {
4294  astman_send_error(s, m, "Device: <name> missing.");
4295  return 0;
4296  }
4297  a[0] = "skinny";
4298  a[1] = "show";
4299  a[2] = "device";
4300  a[3] = device;
4301 
4302  _skinny_show_device(1, -1, s, m, 4, a);
4303  astman_append(s, "\r\n\r\n" );
4304  return 0;
4305 }
4306 
4307 /*! \brief Show device information */
4308 static char *handle_skinny_show_device(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4309 {
4310  switch (cmd) {
4311  case CLI_INIT:
4312  e->command = "skinny show device";
4313  e->usage =
4314  "Usage: skinny show device <DeviceId|DeviceName>\n"
4315  " Lists all deviceinformation of a specific device known to the Skinny subsystem.\n";
4316  return NULL;
4317  case CLI_GENERATE:
4318  return complete_skinny_show_device(a->line, a->word, a->pos, a->n);
4319  }
4320 
4321  return _skinny_show_device(0, a->fd, NULL, NULL, a->argc, a->argv);
4322 }
4323 
4324 static char *_skinny_show_lines(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char * const *argv)
4325 {
4326  struct skinny_line *l;
4327  struct skinny_subchannel *sub;
4328  int total_lines = 0;
4329  int verbose = 0;
4330  const char *id;
4331  char idtext[256] = "";
4332 
4333  if (s) { /* Manager - get ActionID */
4334  id = astman_get_header(m, "ActionID");
4335  if (!ast_strlen_zero(id))
4336  snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
4337  }
4338 
4339  switch (argc) {
4340  case 4:
4341  verbose = 1;
4342  break;
4343  case 3:
4344  verbose = 0;
4345  break;
4346  default:
4347  return CLI_SHOWUSAGE;
4348  }
4349 
4350  if (!s) {
4351  ast_cli(fd, "Name Device Name Instance Label \n");
4352  ast_cli(fd, "-------------------- -------------------- -------- --------------------\n");
4353  }
4354  AST_LIST_LOCK(&lines);
4355  AST_LIST_TRAVERSE(&lines, l, all) {
4356  total_lines++;
4357  if (!s) {
4358  ast_cli(fd, "%-20s %-20s %8d %-20s\n",
4359  l->name,
4360  (l->device ? l->device->name : "Not connected"),
4361  l->instance,
4362  l->label);
4363  if (verbose) {
4364  AST_LIST_TRAVERSE(&l->sub, sub, list) {
4365  RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(sub->owner), ao2_cleanup);
4366 
4367  ast_cli(fd, " %s> %s to %s\n",
4368  (sub == l->activesub?"Active ":"Inactive"),
4369  ast_channel_name(sub->owner),
4370  bridged ? ast_channel_name(bridged) : ""
4371  );
4372  }
4373  }
4374  } else {
4375  astman_append(s,
4376  "Event: LineEntry\r\n%s"
4377  "Channeltype: SKINNY\r\n"
4378  "ObjectName: %s\r\n"
4379  "ChannelObjectType: line\r\n"
4380  "Device: %s\r\n"
4381  "Instance: %d\r\n"
4382  "Label: %s\r\n",
4383  idtext,
4384  l->name,
4385  (l->device ? l->device->name : "None"),
4386  l->instance,
4387  l->label);
4388  }
4389  }
4391 
4392  if (total) {
4393  *total = total_lines;
4394  }
4395 
4396  return CLI_SUCCESS;
4397 }
4398 
4399 /*! \brief Show Skinny lines in the manager API */
4400 /* Inspired from chan_sip */
4401 static int manager_skinny_show_lines(struct mansession *s, const struct message *m)
4402 {
4403  const char *a[] = {"skinny", "show", "lines"};
4404  int total = 0;
4405 
4406  astman_send_listack(s, m, "Line status list will follow", "start");
4407 
4408  /* List the lines in separate manager events */
4409  _skinny_show_lines(-1, &total, s, m, 3, a);
4410 
4411  /* Send final confirmation */
4412  astman_send_list_complete_start(s, m, "LinelistComplete", total);
4414  return 0;
4415 }
4416 
4417 static char *handle_skinny_show_lines(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4418 {
4419  switch (cmd) {
4420  case CLI_INIT:
4421  e->command = "skinny show lines [verbose]";
4422  e->usage =
4423  "Usage: skinny show lines\n"
4424  " Lists all lines known to the Skinny subsystem.\n"
4425  " If 'verbose' is specified, the output includes\n"
4426  " information about subs for each line.\n";
4427  return NULL;
4428  case CLI_GENERATE:
4429  return NULL;
4430  }
4431 
4432  if (a->argc == e->args) {
4433  if (strcasecmp(a->argv[e->args-1], "verbose")) {
4434  return CLI_SHOWUSAGE;
4435  }
4436  } else if (a->argc != e->args - 1) {
4437  return CLI_SHOWUSAGE;
4438  }
4439 
4440  return _skinny_show_lines(a->fd, NULL, NULL, NULL, a->argc, a->argv);
4441 }
4442 
4443 static char *_skinny_show_line(int type, int fd, struct mansession *s, const struct message *m, int argc, const char * const *argv)
4444 {
4445  struct skinny_device *d;
4446  struct skinny_line *l;
4447  struct skinny_subline *subline;
4448  struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
4449  char group_buf[256];
4450  char cbuf[256];
4451 
4452  switch (argc) {
4453  case 4:
4454  break;
4455  case 6:
4456  break;
4457  default:
4458  return CLI_SHOWUSAGE;
4459  }
4460 
4462 
4463  /* Show all lines matching the one supplied */
4464  AST_LIST_TRAVERSE(&devices, d, list) {
4465  if (argc == 6 && (strcasecmp(argv[5], d->id) && strcasecmp(argv[5], d->name))) {
4466  continue;
4467  }
4468  AST_LIST_TRAVERSE(&d->lines, l, list) {
4469  struct ast_str *tmp_str = ast_str_alloca(512);
4470 
4471  if (strcasecmp(argv[3], l->name)) {
4472  continue;
4473  }
4474  if (type == 0) { /* CLI */
4475  ast_cli(fd, "Line: %s\n", l->name);
4476  ast_cli(fd, "On Device: %s\n", d->name);
4477  ast_cli(fd, "Line Label: %s\n", l->label);
4478  ast_cli(fd, "Extension: %s\n", S_OR(l->exten, "<not set>"));
4479  ast_cli(fd, "Context: %s\n", l->context);
4480  ast_cli(fd, "CallGroup: %s\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup));
4481  ast_cli(fd, "PickupGroup: %s\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup));
4482  ast_cli(fd, "NamedCallGroup: %s\n", ast_print_namedgroups(&tmp_str, l->named_callgroups));
4483  ast_str_reset(tmp_str);
4484  ast_cli(fd, "NamedPickupGroup: %s\n", ast_print_namedgroups(&tmp_str, l->named_pickupgroups));
4485  ast_str_reset(tmp_str);
4486  ast_cli(fd, "Language: %s\n", S_OR(l->language, "<not set>"));
4487  ast_cli(fd, "Accountcode: %s\n", S_OR(l->accountcode, "<not set>"));
4488  ast_cli(fd, "AmaFlag: %s\n", ast_channel_amaflags2string(l->amaflags));
4489  ast_cli(fd, "CallerId Number: %s\n", S_OR(l->cid_num, "<not set>"));
4490  ast_cli(fd, "CallerId Name: %s\n", S_OR(l->cid_name, "<not set>"));
4491  ast_cli(fd, "Hide CallerId: %s\n", (l->hidecallerid ? "Yes" : "No"));
4492  ast_cli(fd, "CFwdAll: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "<not set>"));
4493  ast_cli(fd, "CFwdBusy: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
4494  ast_cli(fd, "CFwdNoAnswer: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
4495  ast_cli(fd, "CFwdTimeout: %dms\n", l->callfwdtimeout);
4496  ast_cli(fd, "VoicemailBox: %s\n", S_OR(l->mailbox, "<not set>"));
4497  ast_cli(fd, "VoicemailNumber: %s\n", S_OR(l->vmexten, "<not set>"));
4498  ast_cli(fd, "MWIblink: %d\n", l->mwiblink);
4499  ast_cli(fd, "Regextension: %s\n", S_OR(l->regexten, "<not set>"));
4500  ast_cli(fd, "Regcontext: %s\n", S_OR(l->regcontext, "<not set>"));
4501  ast_cli(fd, "MoHInterpret: %s\n", S_OR(l->mohinterpret, "<not set>"));
4502  ast_cli(fd, "MoHSuggest: %s\n", S_OR(l->mohsuggest, "<not set>"));
4503  ast_cli(fd, "Last dialed nr: %s\n", S_OR(l->lastnumberdialed, "<no calls made yet>"));
4504  ast_cli(fd, "Last CallerID: %s\n", S_OR(l->lastcallerid, "<not set>"));
4505  ast_cli(fd, "Transfer enabled: %s\n", (l->transfer ? "Yes" : "No"));
4506  ast_cli(fd, "Callwaiting: %s\n", (l->callwaiting ? "Yes" : "No"));
4507  ast_cli(fd, "3Way Calling: %s\n", (l->threewaycalling ? "Yes" : "No"));
4508  ast_cli(fd, "Can forward: %s\n", (l->cancallforward ? "Yes" : "No"));
4509  ast_cli(fd, "Do Not Disturb: %s\n", (l->dnd ? "Yes" : "No"));
4510  ast_cli(fd, "NAT: %s\n", (l->nat ? "Yes" : "No"));
4511  ast_cli(fd, "immediate: %s\n", (l->immediate ? "Yes" : "No"));
4512  ast_cli(fd, "Group: %d\n", l->group);
4513  ast_cli(fd, "Parkinglot: %s\n", S_OR(l->parkinglot, "<not set>"));
4514  ast_cli(fd, "Conf Codecs: %s\n", ast_format_cap_get_names(l->confcap, &codec_buf));
4515  ast_cli(fd, "Neg Codecs: %s\n", ast_format_cap_get_names(l->cap, &codec_buf));
4516  if (AST_LIST_FIRST(&l->sublines)) {
4517  ast_cli(fd, "Sublines:\n");
4518  AST_LIST_TRAVERSE(&l->sublines, subline, list) {
4519  ast_cli(fd, " %s, %s@%s\n", subline->name, subline->exten, subline->context);
4520  }
4521  }
4522  ast_cli(fd, "\n");
4523  } else { /* manager */
4524  astman_append(s, "Channeltype: SKINNY\r\n");
4525  astman_append(s, "ObjectName: %s\r\n", l->name);
4526  astman_append(s, "ChannelObjectType: line\r\n");
4527  astman_append(s, "Device: %s\r\n", d->name);
4528  astman_append(s, "LineLabel: %s\r\n", l->label);
4529  astman_append(s, "Extension: %s\r\n", S_OR(l->exten, "<not set>"));
4530  astman_append(s, "Context: %s\r\n", l->context);
4531  astman_append(s, "CallGroup: %s\r\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup));
4532  astman_append(s, "PickupGroup: %s\r\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup));
4533  astman_append(s, "NamedCallGroup: %s\r\n", ast_print_namedgroups(&tmp_str, l->named_callgroups));
4534  ast_str_reset(tmp_str);
4535  astman_append(s, "NamedPickupGroup: %s\r\n", ast_print_namedgroups(&tmp_str, l->named_pickupgroups));
4536  ast_str_reset(tmp_str);
4537  astman_append(s, "Language: %s\r\n", S_OR(l->language, "<not set>"));
4538  astman_append(s, "Accountcode: %s\r\n", S_OR(l->accountcode, "<not set>"));
4539  astman_append(s, "AMAflags: %s\r\n", ast_channel_amaflags2string(l->amaflags));
4540  astman_append(s, "Callerid: %s\r\n", ast_callerid_merge(cbuf, sizeof(cbuf), l->cid_name, l->cid_num, ""));
4541  astman_append(s, "HideCallerId: %s\r\n", (l->hidecallerid ? "Yes" : "No"));
4542  astman_append(s, "CFwdAll: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "<not set>"));
4543  astman_append(s, "CFwdBusy: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
4544  astman_append(s, "CFwdNoAnswer: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
4545  astman_append(s, "VoicemailBox: %s\r\n", S_OR(l->mailbox, "<not set>"));
4546  astman_append(s, "VoicemailNumber: %s\r\n", S_OR(l->vmexten, "<not set>"));
4547  astman_append(s, "MWIblink: %d\r\n", l->mwiblink);
4548  astman_append(s, "RegExtension: %s\r\n", S_OR(l->regexten, "<not set>"));
4549  astman_append(s, "Regcontext: %s\r\n", S_OR(l->regcontext, "<not set>"));
4550  astman_append(s, "MoHInterpret: %s\r\n", S_OR(l->mohinterpret, "<not set>"));
4551  astman_append(s, "MoHSuggest: %s\r\n", S_OR(l->mohsuggest, "<not set>"));
4552  astman_append(s, "LastDialedNr: %s\r\n", S_OR(l->lastnumberdialed, "<no calls made yet>"));
4553  astman_append(s, "LastCallerID: %s\r\n", S_OR(l->lastcallerid, "<not set>"));
4554  astman_append(s, "Transfer: %s\r\n", (l->transfer ? "Yes" : "No"));
4555  astman_append(s, "Callwaiting: %s\r\n", (l->callwaiting ? "Yes" : "No"));
4556  astman_append(s, "3WayCalling: %s\r\n", (l->threewaycalling ? "Yes" : "No"));
4557  astman_append(s, "CanForward: %s\r\n", (l->cancallforward ? "Yes" : "No"));
4558  astman_append(s, "DoNotDisturb: %s\r\n", (l->dnd ? "Yes" : "No"));
4559  astman_append(s, "NAT: %s\r\n", (l->nat ? "Yes" : "No"));
4560  astman_append(s, "immediate: %s\r\n", (l->immediate ? "Yes" : "No"));
4561  astman_append(s, "Group: %d\r\n", l->group);
4562  astman_append(s, "Parkinglot: %s\r\n", S_OR(l->parkinglot, "<not set>"));
4563  astman_append(s, "Codecs: %s\r\n", ast_format_cap_get_names(l->confcap, &codec_buf));
4564  astman_append(s, "\r\n");
4565  }
4566  }
4567  }
4568 
4570  return CLI_SUCCESS;
4571 }
4572 
4573 static int manager_skinny_show_line(struct mansession *s, const struct message *m)
4574 {
4575  const char *a[4];
4576  const char *line;
4577 
4578  line = astman_get_header(m, "Line");
4579  if (ast_strlen_zero(line)) {
4580  astman_send_error(s, m, "Line: <name> missing.");
4581  return 0;
4582  }
4583  a[0] = "skinny";
4584  a[1] = "show";
4585  a[2] = "line";
4586  a[3] = line;
4587 
4588  _skinny_show_line(1, -1, s, m, 4, a);
4589  astman_append(s, "\r\n\r\n" );
4590  return 0;
4591 }
4592 
4593 /*! \brief List line information. */
4594 static char *handle_skinny_show_line(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4595 {
4596  switch (cmd) {
4597  case CLI_INIT:
4598  e->command = "skinny show line";
4599  e->usage =
4600  "Usage: skinny show line <Line> [on <DeviceID|DeviceName>]\n"
4601  " List all lineinformation of a specific line known to the Skinny subsystem.\n";
4602  return NULL;
4603  case CLI_GENERATE:
4604  return complete_skinny_show_line(a->line, a->word, a->pos, a->n);
4605  }
4606 
4607  return _skinny_show_line(0, a->fd, NULL, NULL, a->argc, a->argv);
4608 }
4609 
4610 /*! \brief List global settings for the Skinny subsystem. */
4611 static char *handle_skinny_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4612 {
4613  char immed_str[2] = {immed_dialchar, '\0'};
4614 
4615  switch (cmd) {
4616  case CLI_INIT:
4617  e->command = "skinny show settings";
4618  e->usage =
4619  "Usage: skinny show settings\n"
4620  " Lists all global configuration settings of the Skinny subsystem.\n";
4621  return NULL;
4622  case CLI_GENERATE:
4623  return NULL;
4624  }
4625 
4626  if (a->argc != 3)
4627  return CLI_SHOWUSAGE;
4628 
4629  ast_cli(a->fd, "\nGlobal Settings:\n");
4630  ast_cli(a->fd, " Skinny Port: %d\n", ntohs(bindaddr.sin_port));
4631  ast_cli(a->fd, " Bindaddress: %s\n", ast_inet_ntoa(bindaddr.sin_addr));
4632  ast_cli(a->fd, " KeepAlive: %d\n", keep_alive);
4633  ast_cli(a->fd, " Date Format: %s\n", date_format);
4634  ast_cli(a->fd, " Voice Mail Extension: %s\n", S_OR(vmexten, "(not set)"));
4635  ast_cli(a->fd, " Reg. context: %s\n", S_OR(regcontext, "(not set)"));
4636  ast_cli(a->fd, " Immed. Dial Key: %s\n", S_OR(immed_str, "(not set)"));
4637  ast_cli(a->fd, " Jitterbuffer enabled: %s\n", AST_CLI_YESNO(ast_test_flag(&global_jbconf, AST_JB_ENABLED)));
4639  ast_cli(a->fd, " Jitterbuffer forced: %s\n", AST_CLI_YESNO(ast_test_flag(&global_jbconf, AST_JB_FORCED)));
4640  ast_cli(a->fd, " Jitterbuffer max size: %ld\n", global_jbconf.max_size);
4641  ast_cli(a->fd, " Jitterbuffer resync: %ld\n", global_jbconf.resync_threshold);
4642  ast_cli(a->fd, " Jitterbuffer impl: %s\n", global_jbconf.impl);
4643  if (!strcasecmp(global_jbconf.impl, "adaptive")) {
4644  ast_cli(a->fd, " Jitterbuffer tgt extra: %ld\n", global_jbconf.target_extra);
4645  }
4646  ast_cli(a->fd, " Jitterbuffer log: %s\n", AST_CLI_YESNO(ast_test_flag(&global_jbconf, AST_JB_LOG)));
4647  }
4648 
4649  return CLI_SUCCESS;
4650 }
4651 
4652 static char *_skinny_message_set(int type, int fd, struct mansession *s, const struct message *m, int argc, const char * const *argv)
4653 {
4654  struct skinny_device *d;
4655  char text_buf[32];
4656 
4657  if (argc < 7) {
4658  return CLI_SHOWUSAGE;
4659  }
4660 
4663  if (!strcasecmp(argv[3], d->name)) {
4664  int i;
4665  char *strp = text_buf;
4666  int charleft = sizeof(text_buf);
4667  int priority = atoi(argv[4]);
4668  int timeout = atoi(argv[5]);
4669  ast_copy_string(strp, argv[6], charleft);
4670  charleft -= strlen(strp);
4671  strp += strlen(strp);
4672  for(i=7; i<argc; i++) {
4673  ast_copy_string(strp++, " ", charleft--);
4674  ast_copy_string(strp, argv[i], charleft);
4675  charleft -= strlen(strp);
4676  strp += strlen(strp);
4677  }
4678  send_displayprinotify(d, text_buf, "", timeout, priority);
4679  }
4680  }
4682  return CLI_SUCCESS;
4683 }
4684 
4685 /*! \brief Handle sending messages to devices. */
4686 static char *handle_skinny_message_set(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4687 {
4688  switch (cmd) {
4689  case CLI_INIT:
4690  e->command = "skinny message set";
4691  e->usage =
4692  "Usage: skinny message set <device> <priority> <timeout> <message>\n"
4693  " Set the current priority level message on a device.\n";
4694  return NULL;
4695  case CLI_GENERATE:
4696  return complete_skinny_show_device(a->line, a->word, a->pos, a->n);
4697  }
4698 
4699  return _skinny_message_set(0, a->fd, NULL, NULL, a->argc, a->argv);
4700 }
4701 
4702 static char *_skinny_message_clear(int type, int fd, struct mansession *s, const struct message *m, int argc, const char * const *argv)
4703 {
4704  struct skinny_device *d;
4705 
4706  if (argc != 5) {
4707  return CLI_SHOWUSAGE;
4708  }
4709 
4712  if (!strcasecmp(argv[3], d->name)) {
4713  int priority = atoi(argv[4]);
4714  transmit_clearprinotify(d, priority);
4715  }
4716  }
4718  return CLI_SUCCESS;
4719 }
4720 
4721 /*! \brief Handle clearing messages to devices. */
4722 static char *handle_skinny_message_clear(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4723 {
4724  switch (cmd) {
4725  case CLI_INIT:
4726  e->command = "skinny message clear";
4727  e->usage =
4728  "Usage: skinny message clear <device> <priority>\n"
4729  " Clear the current priority level message on device.\n";
4730  return NULL;
4731  case CLI_GENERATE:
4732  return complete_skinny_show_device(a->line, a->word, a->pos, a->n);
4733  }
4734 
4735  return _skinny_message_clear(0, a->fd, NULL, NULL, a->argc, a->argv);
4736 }
4737 
4738 static struct ast_cli_entry cli_skinny[] = {
4739  AST_CLI_DEFINE(handle_skinny_show_devices, "List defined Skinny devices"),
4740  AST_CLI_DEFINE(handle_skinny_show_device, "List Skinny device information"),
4741  AST_CLI_DEFINE(handle_skinny_show_lines, "List defined Skinny lines per device"),
4742  AST_CLI_DEFINE(handle_skinny_show_line, "List Skinny line information"),
4743  AST_CLI_DEFINE(handle_skinny_show_settings, "List global Skinny settings"),
4744 #ifdef AST_DEVMODE
4745  AST_CLI_DEFINE(handle_skinny_set_debug, "Enable/Disable Skinny debugging"),
4746 #endif
4747  AST_CLI_DEFINE(handle_skinny_reset, "Reset Skinny device(s)"),
4748  AST_CLI_DEFINE(handle_skinny_reload, "Reload Skinny config"),
4749  AST_CLI_DEFINE(handle_skinny_message_set, "Send message to devices"),
4750  AST_CLI_DEFINE(handle_skinny_message_clear, "Clear message to devices"),
4751 };
4752 
4753 static void start_rtp(struct skinny_subchannel *sub)
4754 {
4755  struct skinny_line *l = sub->line;
4756  struct skinny_device *d = l->device;
4757 #if 0
4758  int hasvideo = 0;
4759 #endif
4760  struct ast_sockaddr bindaddr_tmp;
4761 
4762  skinny_locksub(sub);
4763  SKINNY_DEBUG(DEBUG_AUDIO, 3, "Sub %u - Starting RTP\n", sub->callid);
4764  ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
4765  sub->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL);
4766 #if 0
4767  if (hasvideo)
4768  sub->vrtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL);
4769 #endif
4770 
4771  if (sub->rtp) {
4773  }
4774  if (sub->vrtp) {
4776  }
4777 
4778  if (sub->rtp && sub->owner) {
4780  ast_channel_set_fd(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
4781  ast_channel_set_fd(sub->owner, 1, ast_rtp_instance_fd(sub->rtp, 1));
4782  }
4783 #if 0
4784  if (hasvideo && sub->vrtp && sub->owner) {
4786  ast_channel_set_fd(sub->owner, 2, ast_rtp_instance_fd(sub->vrtp, 0));
4787  ast_channel_set_fd(sub->owner, 3, ast_rtp_instance_fd(sub->vrtp, 1));
4788  }
4789 #endif
4790  if (sub->rtp) {
4791  ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "Skinny RTP");
4793  /* Set frame packetization */
4796  }
4797  if (sub->vrtp) {
4798  ast_rtp_instance_set_qos(sub->vrtp, qos.tos_video, qos.cos_video, "Skinny VRTP");
4800  }
4801 
4802  /* Create the RTP connection */
4803  transmit_connect(d, sub);
4804  skinny_unlocksub(sub);
4805 }
4806 
4807 static void destroy_rtp(struct skinny_subchannel *sub)
4808 {
4809  if (sub->rtp) {
4810  SKINNY_DEBUG(DEBUG_AUDIO, 3, "Sub %u - Destroying RTP\n", sub->callid);
4811  ast_rtp_instance_stop(sub->rtp);
4813  sub->rtp = NULL;
4814  }
4815  if (sub->vrtp) {
4816  SKINNY_DEBUG(DEBUG_AUDIO, 3, "Sub %u - Destroying VRTP\n", sub->callid);
4819  sub->vrtp = NULL;
4820  }
4821 }
4822 
4823 static void *skinny_newcall(void *data)
4824 {
4825  struct ast_channel *c = data;
4827  struct skinny_line *l = sub->line;
4828  struct skinny_device *d = l->device;
4829  int res = 0;
4830 
4831  ast_channel_lock(c);
4832  ast_set_callerid(c,
4833  l->hidecallerid ? "" : l->cid_num,
4834  l->hidecallerid ? "" : l->cid_name,
4835  ast_channel_caller(c)->ani.number.valid ? NULL : l->cid_num);
4836 #if 1 /* XXX This code is probably not necessary */
4843 #endif
4845  ast_channel_unlock(c);
4846  if (!sub->rtp) {
4847  start_rtp(sub);
4848  }
4849  ast_verb(3, "Sub %u - Calling %s@%s\n", sub->callid, ast_channel_exten(c), ast_channel_context(c));
4850  res = ast_pbx_run(c);
4851  if (res) {
4852  ast_log(LOG_WARNING, "PBX exited non-zero\n");
4853  transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
4854  }
4855  return NULL;
4856 }
4857 
4858 static void skinny_dialer(struct skinny_subchannel *sub, int timedout)
4859 {
4860  struct ast_channel *c = sub->owner;
4861  struct skinny_line *l = sub->line;
4862  struct skinny_device *d = l->device;
4863 
4864  if (timedout || !ast_matchmore_extension(c, ast_channel_context(c), sub->exten, 1, l->cid_num)) {
4865  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Force dialing '%s' because of %s\n", sub->callid, sub->exten, (timedout ? "timeout" : "exactmatch"));
4866  if (ast_exists_extension(c, ast_channel_context(c), sub->exten, 1, l->cid_num)) {
4867  if (sub->substate == SUBSTATE_OFFHOOK) {
4868  dialandactivatesub(sub, sub->exten);
4869  }
4870  } else {
4871  if (d->hookstate == SKINNY_OFFHOOK) {
4872  // FIXME: redundant because below will onhook before the sound plays, but it correct to send it.
4873  transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
4874  }
4875  dumpsub(sub, 0);
4876  }
4877  } else {
4878  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Wait for more digits\n", sub->callid);
4879  if (ast_exists_extension(c, ast_channel_context(c), sub->exten, 1, l->cid_num)) {
4880  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_DADFD, KEYMASK_ALL);
4882  } else {
4884  }
4885  }
4886 }
4887 
4888 static int skinny_dialer_cb(const void *data)
4889 {
4890  struct skinny_subchannel *sub = (struct skinny_subchannel *)data;
4891  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Dialer called from SCHED %d\n", sub->callid, sub->dialer_sched);
4892  sub->dialer_sched = -1;
4893  skinny_dialer(sub, 1);
4894  return 0;
4895 }
4896 
4897 static int skinny_autoanswer_cb(const void *data)
4898 {
4899  struct skinny_subchannel *sub = (struct skinny_subchannel *)data;
4900  skinny_locksub(sub);
4901  sub->aa_sched = -1;
4903  skinny_unlocksub(sub);
4904  return 0;
4905 }
4906 
4907 static int skinny_cfwd_cb(const void *data)
4908 {
4909  struct skinny_subchannel *sub = (struct skinny_subchannel *)data;
4910  struct skinny_line *l = sub->line;
4911  sub->cfwd_sched = -1;
4912  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - CFWDNOANS to %s.\n", sub->callid, l->call_forward_noanswer);
4913  ast_channel_call_forward_set(sub->owner, l->call_forward_noanswer);
4915  return 0;
4916 }
4917 
4918 static int skinny_call(struct ast_channel *ast, const char *dest, int timeout)
4919 {
4920  int res = 0;
4922  struct skinny_line *l = sub->line;
4923  struct skinny_device *d = l->device;
4924  struct ast_var_t *current;
4925  int doautoanswer = 0;
4926 
4927  if (!d || !d->session) {
4928  ast_log(LOG_WARNING, "Device not registered, cannot call %s\n", dest);
4929  return -1;
4930  }
4931 
4933  ast_log(LOG_WARNING, "skinny_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
4934  return -1;
4935  }
4936 
4937  SKINNY_DEBUG(DEBUG_SUB, 3, "Skinny Call (%s) - Sub %u\n",
4938  ast_channel_name(ast), sub->callid);
4939 
4940  if (l->dnd) {
4942  return -1;
4943  }
4944 
4945  if (AST_LIST_NEXT(sub,list) && !l->callwaiting) {
4947  return -1;
4948  }
4949 
4950  skinny_locksub(sub);
4952  if (!(strcmp(ast_var_name(current), "SKINNY_AUTOANSWER"))) {
4953  if (d->hookstate == SKINNY_ONHOOK && sub->aa_sched < 0) {
4954  char buf[24];
4955  int aatime;
4956  char *stringp = buf, *curstr;
4957  ast_copy_string(buf, ast_var_value(current), sizeof(buf));
4958  curstr = strsep(&stringp, ":");
4959  aatime = atoi(curstr);
4960  while ((curstr = strsep(&stringp, ":"))) {
4961  if (!(strcasecmp(curstr,"BEEP"))) {
4962  sub->aa_beep = 1;
4963  } else if (!(strcasecmp(curstr,"MUTE"))) {
4964  sub->aa_mute = 1;
4965  }
4966  }
4967  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - setting autoanswer time=%dms %s%s\n",
4968  sub->callid, aatime, sub->aa_beep ? "BEEP " : "", sub->aa_mute ? "MUTE" : "");
4969  if (aatime) {
4970  //sub->aa_sched = ast_sched_add(sched, aatime, skinny_autoanswer_cb, sub);
4971  sub->aa_sched = skinny_sched_add(aatime, skinny_autoanswer_cb, sub);
4972  } else {
4973  doautoanswer = 1;
4974  }
4975  }
4976  }
4977  }
4978 
4980  if (doautoanswer) {
4982  }
4983  skinny_unlocksub(sub);
4984  return res;
4985 }
4986 
4987 static int skinny_hangup(struct ast_channel *ast)
4988 {
4990 
4991  if (!sub) {
4992  ast_debug(1, "Asked to hangup channel not connected\n");
4993  return 0;
4994  }
4995 
4996  dumpsub(sub, 1);
4997 
4998  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Destroying\n", sub->callid);
4999 
5000  skinny_set_owner(sub, NULL);
5002  destroy_rtp(sub);
5003  ast_free(sub->origtonum);
5004  ast_free(sub->origtoname);
5005  ast_free(sub);
5007  return 0;
5008 }
5009 
5010 static int skinny_answer(struct ast_channel *ast)
5011 {
5012  int res = 0;
5014 
5015  sub->cxmode = SKINNY_CX_SENDRECV;
5016 
5017  SKINNY_DEBUG(DEBUG_SUB, 3, "skinny_answer(%s) on %s@%s-%u\n",
5018  ast_channel_name(ast), sub->line->name, sub->line->device->name, sub->callid);
5019 
5021 
5022  return res;
5023 }
5024 
5025 /* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
5027 {
5028  struct ast_channel *ast = sub->owner;
5029  struct ast_frame *f;
5030 
5031  if (!sub->rtp) {
5032  /* We have no RTP allocated for this channel */
5033  return &ast_null_frame;
5034  }
5035 
5036  switch(ast_channel_fdno(ast)) {
5037  case 0:
5038  f = ast_rtp_instance_read(sub->rtp, 0); /* RTP Audio */
5039  break;
5040  case 1:
5041  f = ast_rtp_instance_read(sub->rtp, 1); /* RTCP Control Channel */
5042  break;
5043  case 2:
5044  f = ast_rtp_instance_read(sub->vrtp, 0); /* RTP Video */
5045  break;
5046  case 3:
5047  f = ast_rtp_instance_read(sub->vrtp, 1); /* RTCP Control Channel for video */
5048  break;
5049 #if 0
5050  case 5:
5051  /* Not yet supported */
5052  f = ast_udptl_read(sub->udptl); /* UDPTL for T.38 */
5053  break;
5054 #endif
5055  default:
5056  f = &ast_null_frame;
5057  }
5058 
5059  if (ast) {
5060  /* We already hold the channel lock */
5061  if (f->frametype == AST_FRAME_VOICE) {
5063  struct ast_format_cap *caps;
5064 
5065  ast_debug(1, "Oooh, format changed to %s\n", ast_format_get_name(f->subclass.format));
5066 
5068  if (caps) {
5069  ast_format_cap_append(caps, f->subclass.format, 0);
5070  ast_channel_nativeformats_set(ast, caps);
5071  ao2_ref(caps, -1);
5072  }
5075  }
5076  }
5077  }
5078  return f;
5079 }
5080 
5081 static struct ast_frame *skinny_read(struct ast_channel *ast)
5082 {
5083  struct ast_frame *fr;
5085  skinny_locksub(sub);
5086  fr = skinny_rtp_read(sub);
5087  skinny_unlocksub(sub);
5088  return fr;
5089 }
5090 
5091 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
5092 {
5094  int res = 0;
5095  if (frame->frametype != AST_FRAME_VOICE) {
5096  if (frame->frametype == AST_FRAME_IMAGE) {
5097  return 0;
5098  } else {
5099  ast_log(LOG_WARNING, "Can't send %u type frames with skinny_write\n", frame->frametype);
5100  return 0;
5101  }
5102  } else {
5104  struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
5105  ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
5110  return -1;
5111  }
5112  }
5113  if (sub) {
5114  skinny_locksub(sub);
5115  if (sub->rtp) {
5116  res = ast_rtp_instance_write(sub->rtp, frame);
5117  }
5118  skinny_unlocksub(sub);
5119  }
5120  return res;
5121 }
5122 
5123 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
5124 {
5125  struct skinny_subchannel *sub = ast_channel_tech_pvt(newchan);
5126  ast_log(LOG_NOTICE, "skinny_fixup(%s, %s)\n", ast_channel_name(oldchan), ast_channel_name(newchan));
5127  if (sub->owner != oldchan) {
5128  ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
5129  return -1;
5130  }
5131  skinny_set_owner(sub, newchan);
5132  return 0;
5133 }
5134 
5135 static int skinny_senddigit_begin(struct ast_channel *ast, char digit)
5136 {
5137  return -1; /* Start inband indications */
5138 }
5139 
5140 static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
5141 {
5142 #if 0
5143  struct skinny_subchannel *sub = ast->tech_pvt;
5144  struct skinny_line *l = sub->line;
5145  struct skinny_device *d = l->device;
5146  int tmp;
5147  /* not right */
5148  sprintf(tmp, "%d", digit);
5149  //transmit_tone(d, digit, l->instance, sub->callid);
5150 #endif
5151  return -1; /* Stop inband indications */
5152 }
5153 
5154 static int get_devicestate(struct skinny_line *l)
5155 {
5156  struct skinny_subchannel *sub;
5157  int res = AST_DEVICE_UNKNOWN;
5158 
5159  if (!l)
5160  res = AST_DEVICE_INVALID;
5161  else if (!l->device || !l->device->session)
5162  res = AST_DEVICE_UNAVAILABLE;
5163  else if (l->dnd)
5164  res = AST_DEVICE_BUSY;
5165  else {
5166  if (l->device->hookstate == SKINNY_ONHOOK) {
5167  res = AST_DEVICE_NOT_INUSE;
5168  } else {
5169  res = AST_DEVICE_INUSE;
5170  }
5171 
5172  AST_LIST_TRAVERSE(&l->sub, sub, list) {
5173  if (sub->substate == SUBSTATE_HOLD) {
5174  res = AST_DEVICE_ONHOLD;
5175  break;
5176  }
5177  }
5178  }
5179 
5180  return res;
5181 }
5182 
5183 static char *control2str(int ind) {
5184  char *tmp;
5185 
5186  switch (ind) {
5187  case AST_CONTROL_HANGUP:
5188  return "Other end has hungup";
5189  case AST_CONTROL_RING:
5190  return "Local ring";
5191  case AST_CONTROL_RINGING:
5192  return "Remote end is ringing";
5193  case AST_CONTROL_ANSWER:
5194  return "Remote end has answered";
5195  case AST_CONTROL_BUSY:
5196  return "Remote end is busy";
5198  return "Make it go off hook";
5199  case AST_CONTROL_OFFHOOK:
5200  return "Line is off hook";
5202  return "Congestion (circuits busy)";
5203  case AST_CONTROL_FLASH:
5204  return "Flash hook";
5205  case AST_CONTROL_WINK:
5206  return "Wink";
5207  case AST_CONTROL_OPTION:
5208  return "Set a low-level option";
5209  case AST_CONTROL_RADIO_KEY:
5210  return "Key Radio";
5212  return "Un-Key Radio";
5213  case AST_CONTROL_PROGRESS:
5214  return "Remote end is making Progress";
5216  return "Remote end is proceeding";
5217  case AST_CONTROL_HOLD:
5218  return "Hold";
5219  case AST_CONTROL_UNHOLD:
5220  return "Unhold";
5221  case AST_CONTROL_VIDUPDATE:
5222  return "VidUpdate";
5223  case AST_CONTROL_SRCUPDATE:
5224  return "Media Source Update";
5225  case AST_CONTROL_TRANSFER:
5226  return "Transfer";
5228  return "Connected Line";
5230  return "Redirecting";
5232  return "T38_Parameters";
5233  case AST_CONTROL_CC:
5234  return "CC Not Possible";
5235  case AST_CONTROL_SRCCHANGE:
5236  return "Media Source Change";
5238  return "Incomplete";
5239  case -1:
5240  return "Stop tone";
5241  default:
5243  return "Unknown";
5244  snprintf(tmp, CONTROL2STR_BUFSIZE, "UNKNOWN-%d", ind);
5245  return tmp;
5246  }
5247 }
5248 
5250 {
5251  struct skinny_subchannel *xferee;
5252  struct skinny_subchannel *xferor;
5253  enum ast_transfer_result res;
5254 
5255  if (sub->xferor) {
5256  xferor = sub;
5257  xferee = sub->related;
5258  } else {
5259  xferor = sub;
5260  xferee = sub->related;
5261  }
5262 
5264  if (ast_channel_state(xferor->owner) == AST_STATE_RINGING) {
5266  }
5267  res = ast_bridge_transfer_attended(xferee->owner, xferor->owner);
5268 
5269  if (res != AST_BRIDGE_TRANSFER_SUCCESS) {
5270  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u failed to transfer %u to '%s'@'%s' - %u\n",
5271  xferor->callid, xferee->callid, xferor->exten, xferor->line->context, res);
5272  send_displayprinotify(xferor->line->device, "Transfer failed", NULL, 10, 5);
5274  }
5275 }
5276 
5278 {
5279  struct skinny_subchannel *xferee = sub->related;
5280  enum ast_transfer_result res;
5281 
5282  sub->related = NULL;
5283  xferee->related = NULL;
5284 
5286  res = ast_bridge_transfer_blind(1, xferee->owner, sub->exten, sub->line->context, NULL, NULL);
5287 
5288  if (res != AST_BRIDGE_TRANSFER_SUCCESS) {
5289  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u failed to blind transfer %u to '%s'@'%s' - %u\n",
5290  sub->callid, xferee->callid, sub->exten, sub->line->context, res);
5291  send_displayprinotify(sub->line->device, "Transfer failed", NULL, 10, 5);
5293  }
5294  dumpsub(sub, 1);
5295 }
5296 
5297 static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
5298 {
5300  struct skinny_line *l = sub->line;
5301  struct skinny_device *d = l->device;
5302  struct skinnysession *s = d->session;
5303 
5304  if (!s) {
5305  ast_log(LOG_NOTICE, "Asked to indicate '%s' condition on channel %s, but session does not exist.\n", control2str(ind), ast_channel_name(ast));
5306  return -1;
5307  }
5308 
5309  SKINNY_DEBUG(DEBUG_SUB, 3, "Asked to indicate '%s' condition on channel %s (Sub %u)\n",
5310  control2str(ind), ast_channel_name(ast), sub->callid);
5311  switch(ind) {
5312  case AST_CONTROL_RINGING:
5314  return (d->earlyrtp ? -1 : 0); /* Tell asterisk to provide inband signalling if rtp started */
5315  case AST_CONTROL_BUSY:
5316  setsubstate(sub, SUBSTATE_BUSY);
5317  return (d->earlyrtp ? -1 : 0); /* Tell asterisk to provide inband signalling if rtp started */
5319  /* Support for incomplete not supported for chan_skinny; treat as congestion */
5322  return (d->earlyrtp ? -1 : 0); /* Tell asterisk to provide inband signalling if rtp started */
5323  case AST_CONTROL_PROGRESS:
5325  return (d->earlyrtp ? -1 : 0); /* Tell asterisk to provide inband signalling if rtp started */
5326  case -1: /* STOP_TONE */
5327  transmit_stop_tone(d, l->instance, sub->callid);
5328  break;
5329  case AST_CONTROL_HOLD:
5330  ast_moh_start(ast, data, l->mohinterpret);
5331  break;
5332  case AST_CONTROL_UNHOLD:
5333  ast_moh_stop(ast);
5334  break;
5336  break;
5337  case AST_CONTROL_SRCUPDATE:
5338  if (sub->rtp) {
5340  }
5341  break;
5342  case AST_CONTROL_SRCCHANGE:
5343  if (sub->rtp) {
5345  }
5346  break;
5348  update_connectedline(sub, data, datalen);
5349  break;
5350  default:
5351  ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
5352  /* fallthrough */
5355  return -1; /* Tell asterisk to provide inband signalling */
5356  }
5357  return 0;
5358 }
5359 
5360 static void skinny_set_owner(struct skinny_subchannel* sub, struct ast_channel* chan)
5361 {
5362  sub->owner = chan;
5363  if (sub->rtp) {
5365  }
5366  if (sub->vrtp) {
5368  }
5369 }
5370 
5371 static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subline *subline, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, int direction)
5372 {
5373  struct ast_channel *tmp;
5374  struct skinny_subchannel *sub;
5375  struct skinny_device *d = l->device;
5376  struct ast_variable *v = NULL;
5377  struct ast_format *tmpfmt;
5378  struct ast_format_cap *caps;
5379 #ifdef AST_DEVMODE
5380  struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
5381 #endif
5382 
5383  if (!l->device || !l->device->session) {
5384  ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
5385  return NULL;
5386  }
5387 
5389  if (!caps) {
5390  return NULL;
5391  }
5392 
5393  tmp = ast_channel_alloc(1, state, l->cid_num, l->cid_name, l->accountcode, l->exten, l->context, assignedids, requestor, l->amaflags, "Skinny/%s@%s-%d", l->name, d->name, callnums);
5394  if (!tmp) {
5395  ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
5396  ao2_ref(caps, -1);
5397  return NULL;
5398  } else {
5399  sub = ast_calloc(1, sizeof(*sub));
5400  if (!sub) {
5401  ast_log(LOG_WARNING, "Unable to allocate Skinny subchannel\n");
5402  ast_channel_unlock(tmp);
5403  ast_channel_unref(tmp);
5404  ao2_ref(caps, -1);
5405  return NULL;
5406  } else {
5407  skinny_set_owner(sub, tmp);
5408  sub->callid = callnums++;
5409  d->lastlineinstance = l->instance;
5410  d->lastcallreference = sub->callid;
5411  sub->cxmode = SKINNY_CX_INACTIVE;
5412  sub->nat = l->nat;
5413  sub->line = l;
5414  sub->blindxfer = 0;
5415  sub->xferor = 0;
5416  sub->related = NULL;
5417  sub->calldirection = direction;
5418  sub->aa_sched = -1;
5419  sub->dialer_sched = -1;
5420  sub->cfwd_sched = -1;
5421  sub->dialType = DIALTYPE_NORMAL;
5422  sub->getforward = 0;
5423 
5424  if (subline) {
5425  sub->subline = subline;
5426  subline->sub = sub;
5427  } else {
5428  sub->subline = NULL;
5429  }
5430 
5431  AST_LIST_INSERT_HEAD(&l->sub, sub, list);
5432  //l->activesub = sub;
5433  }
5435  ast_channel_tech_set(tmp, &skinny_tech);
5436  ast_channel_tech_pvt_set(tmp, sub);
5437  if (!ast_format_cap_count(l->cap)) {
5439  } else {
5441  }
5442  ast_channel_nativeformats_set(tmp, caps);
5443  ao2_ref(caps, -1);
5445  SKINNY_DEBUG(DEBUG_SUB, 3, "skinny_new: tmp->nativeformats=%s fmt=%s\n",
5447  ast_format_get_name(tmpfmt));
5448  if (sub->rtp) {
5449  ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
5450  }
5451  if (state == AST_STATE_RING) {
5452  ast_channel_rings_set(tmp, 1);
5453  }
5454  ast_channel_set_writeformat(tmp, tmpfmt);
5455  ast_channel_set_rawwriteformat(tmp, tmpfmt);
5456  ast_channel_set_readformat(tmp, tmpfmt);
5457  ast_channel_set_rawreadformat(tmp, tmpfmt);
5458  ao2_ref(tmpfmt, -1);
5459 
5460  if (!ast_strlen_zero(l->language))
5461  ast_channel_language_set(tmp, l->language);
5462  if (!ast_strlen_zero(l->accountcode))
5463  ast_channel_accountcode_set(tmp, l->accountcode);
5464  if (!ast_strlen_zero(l->parkinglot))
5465  ast_channel_parkinglot_set(tmp, l->parkinglot);
5466  if (l->amaflags)
5467  ast_channel_amaflags_set(tmp, l->amaflags);
5468 
5470  ast_channel_callgroup_set(tmp, l->callgroup);
5471  ast_channel_pickupgroup_set(tmp, l->pickupgroup);
5472 
5473  ast_channel_named_callgroups_set(tmp, l->named_callgroups);
5474  ast_channel_named_pickupgroups_set(tmp, l->named_pickupgroups);
5475 
5476  if (l->cfwdtype & SKINNY_CFWD_ALL) {
5477  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - CFWDALL to %s.\n", sub->callid, l->call_forward_all);
5478  ast_channel_call_forward_set(tmp, l->call_forward_all);
5479  } else if ((l->cfwdtype & SKINNY_CFWD_BUSY) && (get_devicestate(l) != AST_DEVICE_NOT_INUSE)) {
5480  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - CFWDBUSY to %s.\n", sub->callid, l->call_forward_busy);
5481  ast_channel_call_forward_set(tmp, l->call_forward_busy);
5482  } else if (l->cfwdtype & SKINNY_CFWD_NOANSWER) {
5483  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - CFWDNOANS Scheduling for %d seconds.\n", sub->callid, l->callfwdtimeout/1000);
5484  sub->cfwd_sched = skinny_sched_add(l->callfwdtimeout, skinny_cfwd_cb, sub);
5485  }
5486 
5487  if (subline) {
5488  ast_channel_context_set(tmp, subline->context);
5489  } else {
5490  ast_channel_context_set(tmp, l->context);
5491  }
5492  ast_channel_exten_set(tmp, l->exten);
5493 
5494  /* Don't use ast_set_callerid() here because it will
5495  * generate a needless NewCallerID event */
5496  if (!ast_strlen_zero(l->cid_num)) {
5497  ast_channel_caller(tmp)->ani.number.valid = 1;
5498  ast_channel_caller(tmp)->ani.number.str = ast_strdup(l->cid_num);
5499  }
5500 
5501  ast_channel_priority_set(tmp, 1);
5503 
5504  if (sub->rtp)
5506 
5507  /* Set channel variables for this call from configuration */
5508  for (v = l->chanvars ; v ; v = v->next)
5509  pbx_builtin_setvar_helper(tmp, v->name, v->value);
5510 
5512  ast_channel_unlock(tmp);
5513 
5514  if (state != AST_STATE_DOWN) {
5515  if (ast_pbx_start(tmp)) {
5516  ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
5517  ast_hangup(tmp);
5518  tmp = NULL;
5519  }
5520  }
5521  }
5522  return tmp;
5523 }
5524 static char *substate2str(int ind) {
5525  char *tmp;
5526 
5527  switch (ind) {
5528  case SUBSTATE_UNSET:
5529  return "SUBSTATE_UNSET";
5530  case SUBSTATE_OFFHOOK:
5531  return "SUBSTATE_OFFHOOK";
5532  case SUBSTATE_ONHOOK:
5533  return "SUBSTATE_ONHOOK";
5534  case SUBSTATE_RINGOUT:
5535  return "SUBSTATE_RINGOUT";
5536  case SUBSTATE_RINGIN:
5537  return "SUBSTATE_RINGIN";
5538  case SUBSTATE_CONNECTED:
5539  return "SUBSTATE_CONNECTED";
5540  case SUBSTATE_BUSY:
5541  return "SUBSTATE_BUSY";
5542  case SUBSTATE_CONGESTION:
5543  return "SUBSTATE_CONGESTION";
5544  case SUBSTATE_PROGRESS:
5545  return "SUBSTATE_PROGRESS";
5546  case SUBSTATE_HOLD:
5547  return "SUBSTATE_HOLD";
5548  case SUBSTATE_CALLWAIT:
5549  return "SUBSTATE_CALLWAIT";
5550  case SUBSTATE_DIALING:
5551  return "SUBSTATE_DIALING";
5552  default:
5554  return "Unknown";
5555  snprintf(tmp, SUBSTATE2STR_BUFSIZE, "UNKNOWN-%d", ind);
5556  return tmp;
5557  }
5558 }
5559 
5560 static void setsubstate(struct skinny_subchannel *sub, int state)
5561 {
5562  struct skinny_line *l = sub->line;
5563  struct skinny_subline *subline = sub->subline;
5564  struct skinny_device *d = l->device;
5565  struct ast_channel *c = sub->owner;
5566  struct ast_party_id connected_id;
5567  pthread_t t;
5568  int actualstate = state;
5569  char *fromnum;
5570 
5571  if (sub->substate == SUBSTATE_ONHOOK) {
5572  return;
5573  }
5574 
5575  skinny_locksub(sub);
5576 
5577  if (-1 < sub->dialer_sched) {
5578  skinny_sched_del(sub->dialer_sched, sub);
5579  sub->dialer_sched = -1;
5580  }
5581 
5582  if (state != SUBSTATE_RINGIN && -1 < sub->aa_sched) {
5583  skinny_sched_del(sub->aa_sched, sub);
5584  sub->aa_sched = -1;
5585  sub->aa_beep = 0;
5586  sub->aa_mute = 0;
5587  }
5588 
5589  if (sub->cfwd_sched > -1) {
5590  if (state == SUBSTATE_CONNECTED) {
5591  if (skinny_sched_del(sub->cfwd_sched, sub)) {
5592  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - trying to change state from %s to %s, but already forwarded because no answer.\n",
5593  sub->callid, substate2str(sub->substate), substate2str(actualstate));
5594  skinny_unlocksub(sub);
5595  return;
5596  }
5597  sub->cfwd_sched = -1;
5598  } else if (state == SUBSTATE_ONHOOK) {
5599  skinny_sched_del(sub->cfwd_sched, sub);
5600  sub->cfwd_sched = -1;
5601  }
5602  }
5603 
5604  if ((state == SUBSTATE_RINGIN) && ((d->hookstate == SKINNY_OFFHOOK) || (AST_LIST_NEXT(AST_LIST_FIRST(&l->sub), list)))) {
5605  actualstate = SUBSTATE_CALLWAIT;
5606  }
5607 
5608  if (sub->substate == SUBSTATE_RINGIN && state != SUBSTATE_RINGIN) {
5610  }
5611 
5612  if ((state == SUBSTATE_CONNECTED) && (!subline) && (AST_LIST_FIRST(&l->sublines))) {
5613  const char *slastation;
5614  struct skinny_subline *tmpsubline;
5615  slastation = pbx_builtin_getvar_helper(c, "SLASTATION");
5616  ast_verb(3, "Connecting %s to subline\n", slastation);
5617  if (slastation) {
5618  AST_LIST_TRAVERSE(&l->sublines, tmpsubline, list) {
5619  if (!strcasecmp(tmpsubline->stname, slastation)) {
5620  subline = tmpsubline;
5621  break;
5622  }
5623  }
5624  if (subline) {
5625  struct skinny_line *tmpline;
5626  subline->sub = sub;
5627  sub->subline = subline;
5628  subline->callid = sub->callid;
5629  send_callinfo(sub);
5630  AST_LIST_TRAVERSE(&lines, tmpline, all) {
5631  AST_LIST_TRAVERSE(&tmpline->sublines, tmpsubline, list) {
5632  if (!(subline == tmpsubline)) {
5633  if (!strcasecmp(subline->lnname, tmpsubline->lnname)) {
5634  struct ast_state_cb_info info = {
5635  .exten_state = tmpsubline->extenstate,
5636  };
5637  tmpsubline->callid = callnums++;
5638  transmit_callstate(tmpsubline->line->device, tmpsubline->line->instance, tmpsubline->callid, SKINNY_OFFHOOK);
5639  push_callinfo(tmpsubline, sub);
5640  skinny_extensionstate_cb(NULL, NULL, &info, tmpsubline->container);
5641  }
5642  }
5643  }
5644  }
5645  }
5646  }
5647  }
5648 
5649  if (subline) { /* Different handling for subs under a subline, indications come through hints */
5650  switch (actualstate) {
5651  case SUBSTATE_ONHOOK:
5652  AST_LIST_REMOVE(&l->sub, sub, list);
5653  if (sub->related) {
5654  sub->related->related = NULL;
5655  }
5656 
5657  if (sub == l->activesub) {
5658  l->activesub = NULL;
5661  }
5662 
5663  if (subline->callid) {
5664  transmit_stop_tone(d, l->instance, sub->callid);
5665  transmit_callstate(d, l->instance, subline->callid, SKINNY_CALLREMOTEMULTILINE);
5667  send_displaypromptstatus(d, "In Use", "", 0, l->instance, subline->callid);
5668  }
5669 
5670  sub->cxmode = SKINNY_CX_RECVONLY;
5671  sub->substate = SUBSTATE_ONHOOK;
5672  sub->substate = SUBSTATE_ONHOOK;
5673  if (sub->owner) {
5674  ast_queue_hangup(sub->owner);
5675  }
5676  break;
5677  case SUBSTATE_CONNECTED:
5679  transmit_stop_tone(d, l->instance, sub->callid);
5680  transmit_selectsoftkeys(d, l->instance, subline->callid, KEYDEF_CONNECTED, KEYMASK_ALL);
5681  transmit_callstate(d, l->instance, subline->callid, SKINNY_CONNECTED);
5682  if (!sub->rtp) {
5683  start_rtp(sub);
5684  }
5685  if (sub->substate == SUBSTATE_RINGIN || sub->substate == SUBSTATE_CALLWAIT) {
5687  }
5688  if (sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_RINGOUT) {
5689  transmit_dialednumber(d, sub->exten, l->instance, sub->callid);
5690  }
5691  if (ast_channel_state(sub->owner) != AST_STATE_UP) {
5693  }
5695  l->activesub = sub;
5696  break;
5697  case SUBSTATE_HOLD:
5698  if (sub->substate != SUBSTATE_CONNECTED) {
5699  ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_HOLD from %s (on call-%u)\n", substate2str(sub->substate), sub->callid);
5700  return;
5701  }
5705 
5706  transmit_callstate(d, l->instance, subline->callid, SKINNY_CALLREMOTEMULTILINE);
5708  send_displaypromptstatus(d, "In Use", "", 0, l->instance, subline->callid);
5709 
5710  sub->substate = SUBSTATE_HOLD;
5711 
5712  ast_queue_hold(sub->owner, l->mohsuggest);
5713 
5714  break;
5715  default:
5716  ast_log(LOG_WARNING, "Substate handling under subline for state %d not implemented on Sub-%u\n", state, sub->callid);
5717  }
5718  skinny_unlocksub(sub);
5719  return;
5720  }
5721 
5722  if ((d->hookstate == SKINNY_ONHOOK) && ((actualstate == SUBSTATE_OFFHOOK) || (actualstate == SUBSTATE_DIALING)
5723  || (actualstate == SUBSTATE_RINGOUT) || (actualstate == SUBSTATE_CONNECTED) || (actualstate == SUBSTATE_BUSY)
5724  || (actualstate == SUBSTATE_CONGESTION) || (actualstate == SUBSTATE_PROGRESS))) {
5725  d->hookstate = SKINNY_OFFHOOK;
5727  }
5728 
5729  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - change state from %s to %s\n",
5730  sub->callid, substate2str(sub->substate), substate2str(actualstate));
5731 
5732  if (actualstate == sub->substate) {
5733  skinny_unlocksub(sub);
5734  return;
5735  }
5736 
5737  switch (actualstate) {
5738  case SUBSTATE_OFFHOOK:
5739  ast_verb(1, "Call-id: %u\n", sub->callid);
5740  l->activesub = sub;
5741  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5743  transmit_clear_display_message(d, l->instance, sub->callid);
5744  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
5745  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK, KEYMASK_ALL);
5746  send_displaypromptstatus(d, OCTAL_ENTRNUM, "", 0, l->instance, sub->callid);
5747 
5748  sub->substate = SUBSTATE_OFFHOOK;
5750  break;
5751  case SUBSTATE_ONHOOK:
5752  AST_LIST_REMOVE(&l->sub, sub, list);
5753  if (sub->related) {
5754  sub->related->related = NULL;
5755  }
5756 
5758  transmit_callstate(d, l->instance, sub->callid, SKINNY_CONNECTED);
5759  }
5760 
5761  if (sub == l->activesub) {
5762  l->activesub = NULL;
5765  transmit_stop_tone(d, l->instance, sub->callid);
5766  transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
5767  transmit_clearpromptmessage(d, l->instance, sub->callid);
5771  } else {
5772  transmit_stop_tone(d, l->instance, sub->callid);
5773  transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
5774  transmit_clearpromptmessage(d, l->instance, sub->callid);
5775  }
5776 
5777  sub->cxmode = SKINNY_CX_RECVONLY;
5778  if (sub->owner) {
5779  if (sub->substate == SUBSTATE_OFFHOOK) {
5780  sub->substate = SUBSTATE_ONHOOK;
5781  skinny_unlocksub(sub);
5782  ast_hangup(sub->owner);
5783  return;
5784  } else {
5785  sub->substate = SUBSTATE_ONHOOK;
5786  ast_queue_hangup(sub->owner);
5787  }
5788  } else {
5789  sub->substate = SUBSTATE_ONHOOK;
5790  }
5791  break;
5792  case SUBSTATE_DIALING:
5793  if (ast_strlen_zero(sub->exten) || !ast_exists_extension(c, ast_channel_context(c), sub->exten, 1, l->cid_num)) {
5794  ast_log(LOG_WARNING, "Exten (%s)@(%s) does not exist, unable to set substate DIALING on sub %u\n", sub->exten, ast_channel_context(c), sub->callid);
5795  break;
5796  }
5797 
5798  if (d->hookstate == SKINNY_ONHOOK) {
5799  d->hookstate = SKINNY_OFFHOOK;
5802  }
5803 
5804  if (!sub->subline) {
5805  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5806  transmit_stop_tone(d, l->instance, sub->callid);
5807  transmit_clear_display_message(d, l->instance, sub->callid);
5808  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT, KEYMASK_ALL);
5809  send_displaypromptstatus(d, "Dialing", "", 0, l->instance, sub->callid);
5810  }
5811 
5812  if (AST_LIST_FIRST(&l->sublines)) {
5813  if (subline) {
5814  ast_channel_exten_set(c, subline->exten);
5815  ast_channel_context_set(c, "sla_stations");
5816  } else {
5817  pbx_builtin_setvar_helper(c, "_DESTEXTEN", sub->exten);
5818  pbx_builtin_setvar_helper(c, "_DESTCONTEXT", ast_channel_context(c));
5819  ast_channel_exten_set(c, l->dialoutexten);
5820  ast_channel_context_set(c, l->dialoutcontext);
5821  ast_copy_string(l->lastnumberdialed, sub->exten, sizeof(l->lastnumberdialed));
5822  }
5823  } else {
5824  ast_channel_exten_set(c, sub->exten);
5825  ast_copy_string(l->lastnumberdialed, sub->exten, sizeof(l->lastnumberdialed));
5826  }
5827 
5828  sub->substate = SUBSTATE_DIALING;
5829 
5830  if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
5831  ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
5832  ast_hangup(c);
5833  }
5834  break;
5835  case SUBSTATE_RINGOUT:
5836  if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS)) {
5837  ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_RINGOUT from %s (on call-%u)\n", substate2str(sub->substate), sub->callid);
5838  break;
5839  }
5840  if (sub->substate != SUBSTATE_PROGRESS) {
5841  transmit_callstate(d, l->instance, sub->callid, SKINNY_PROGRESS);
5842  }
5843 
5844  if (!d->earlyrtp) {
5845  transmit_start_tone(d, SKINNY_ALERT, l->instance, sub->callid);
5846  }
5847  transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGOUT);
5848  if (sub->related) {
5850  } else {
5851  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT, KEYMASK_ALL);
5852  }
5853  transmit_dialednumber(d, sub->exten, l->instance, sub->callid);
5854  send_displaypromptstatus(d, OCTAL_RINGOUT, "", 0, l->instance, sub->callid);
5855  send_callinfo(sub);
5856  sub->substate = SUBSTATE_RINGOUT;
5857  break;
5858  case SUBSTATE_RINGIN:
5859  connected_id = ast_channel_connected_effective_id(c);
5861  fromnum = S_COR(connected_id.number.valid, connected_id.number.str, "Unknown");
5862  } else {
5863  fromnum = "Unknown";
5864  }
5865  transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGIN);
5866  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN, KEYMASK_ALL);
5867  send_displaypromptstatus(d, OCTAL_FROM, fromnum, 0, l->instance, sub->callid);
5868  send_displayprinotify(d, OCTAL_FROM, fromnum, 10, 5);
5869  send_callinfo(sub);
5873 
5874  if (d->hookstate == SKINNY_ONHOOK) {
5875  l->activesub = sub;
5876  }
5877 
5878  if (sub->substate != SUBSTATE_RINGIN || sub->substate != SUBSTATE_CALLWAIT) {
5881  }
5882  sub->substate = SUBSTATE_RINGIN;
5883  break;
5884  case SUBSTATE_CALLWAIT:
5885  transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGIN);
5886  transmit_callstate(d, l->instance, sub->callid, SKINNY_CALLWAIT);
5887  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN, KEYMASK_ALL);
5888  send_displaypromptstatus(d, OCTAL_CALLWAITING, "", 0, l->instance, sub->callid);
5889  send_callinfo(sub);
5891  transmit_start_tone(d, SKINNY_CALLWAITTONE, l->instance, sub->callid);
5892 
5895  sub->substate = SUBSTATE_CALLWAIT;
5896  break;
5897  case SUBSTATE_CONNECTED:
5898  if (sub->substate == SUBSTATE_RINGIN) {
5899  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5900  }
5901  if (sub->substate == SUBSTATE_HOLD) {
5902  ast_queue_unhold(sub->owner);
5903  transmit_connect(d, sub);
5904  }
5907  transmit_stop_tone(d, l->instance, sub->callid);
5908  send_callinfo(sub);
5909  transmit_callstate(d, l->instance, sub->callid, SKINNY_CONNECTED);
5910  send_displaypromptstatus(d, OCTAL_CONNECTED, "", 0, l->instance, sub->callid);
5912  if (!sub->rtp) {
5913  start_rtp(sub);
5914  }
5915  if (sub->aa_beep) {
5916  transmit_start_tone(d, SKINNY_ZIP, l->instance, sub->callid);
5917  }
5918  if (sub->aa_mute) {
5920  }
5921  if (sub->substate == SUBSTATE_RINGIN || sub->substate == SUBSTATE_CALLWAIT) {
5923  }
5924  if (sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_RINGOUT) {
5925  transmit_dialednumber(d, sub->exten, l->instance, sub->callid);
5926  }
5927  if (ast_channel_state(sub->owner) != AST_STATE_UP) {
5929  }
5931  l->activesub = sub;
5932  break;
5933  case SUBSTATE_BUSY:
5934  if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS || sub->substate == SUBSTATE_RINGOUT)) {
5935  ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_BUSY from %s (on call-%u)\n", substate2str(sub->substate), sub->callid);
5936  break;
5937  }
5938 
5939  if (!d->earlyrtp) {
5940  transmit_start_tone(d, SKINNY_BUSYTONE, l->instance, sub->callid);
5941  }
5942  send_callinfo(sub);
5943  transmit_callstate(d, l->instance, sub->callid, SKINNY_BUSY);
5944  send_displaypromptstatus(d, OCTAL_BUSY, "", 0, l->instance, sub->callid);
5945  sub->substate = SUBSTATE_BUSY;
5946  break;
5947  case SUBSTATE_CONGESTION:
5948  if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS || sub->substate == SUBSTATE_RINGOUT)) {
5949  ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_CONGESTION from %s (on call-%u)\n", substate2str(sub->substate), sub->callid);
5950  break;
5951  }
5952 
5953  if (!d->earlyrtp) {
5954  transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
5955  }
5956  send_callinfo(sub);
5957  transmit_callstate(d, l->instance, sub->callid, SKINNY_CONGESTION);
5958  send_displaypromptstatus(d, "Congestion", "", 0, l->instance, sub->callid);
5960  break;
5961  case SUBSTATE_PROGRESS:
5962  if (sub->substate != SUBSTATE_DIALING) {
5963  ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_PROGRESS from %s (on call-%u)\n", substate2str(sub->substate), sub->callid);
5964  break;
5965  }
5966 
5967  if (!d->earlyrtp) {
5968  transmit_start_tone(d, SKINNY_ALERT, l->instance, sub->callid);
5969  }
5970  send_callinfo(sub);
5971  transmit_callstate(d, l->instance, sub->callid, SKINNY_PROGRESS);
5972  send_displaypromptstatus(d, "Call Progress", "", 0, l->instance, sub->callid);
5973  sub->substate = SUBSTATE_PROGRESS;
5974  break;
5975  case SUBSTATE_HOLD:
5976  if (sub->substate != SUBSTATE_CONNECTED) {
5977  ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_HOLD from %s (on call-%u)\n", substate2str(sub->substate), sub->callid);
5978  break;
5979  }
5980  ast_queue_hold(sub->owner, l->mohsuggest);
5981 
5985 
5986  transmit_callstate(d, l->instance, sub->callid, SKINNY_HOLD);
5988  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_ONHOLD, KEYMASK_ALL);
5989  sub->substate = SUBSTATE_HOLD;
5990  break;
5991  default:
5992  ast_log(LOG_WARNING, "Was asked to change to nonexistant substate %d on Sub-%u\n", state, sub->callid);
5993  }
5994  skinny_unlocksub(sub);
5995 }
5996 
5997 static void dumpsub(struct skinny_subchannel *sub, int forcehangup)
5998 {
5999  struct skinny_line *l = sub->line;
6000  struct skinny_device *d = l->device;
6001  struct skinny_subchannel *activate_sub = NULL;
6002  struct skinny_subchannel *tsub;
6003 
6004  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Dumping\n", sub->callid);
6005 
6006  if (!forcehangup && sub->substate == SUBSTATE_HOLD) {
6007  l->activesub = NULL;
6008  return;
6009  }
6010 
6011  if (sub == l->activesub) {
6012  d->hookstate = SKINNY_ONHOOK;
6014  if (sub->related) {
6015  activate_sub = sub->related;
6017  l->activesub = activate_sub;
6018  if (l->activesub->substate != SUBSTATE_HOLD) {
6019  ast_log(LOG_WARNING, "Sub-%u was related but not at SUBSTATE_HOLD\n", sub->callid);
6020  return;
6021  }
6023  } else {
6025  AST_LIST_TRAVERSE(&l->sub, tsub, list) {
6026  if (tsub->substate == SUBSTATE_CALLWAIT) {
6027  activate_sub = tsub;
6028  }
6029  }
6030  if (activate_sub) {
6031  setsubstate(activate_sub, SUBSTATE_RINGIN);
6032  return;
6033  }
6034  AST_LIST_TRAVERSE(&l->sub, tsub, list) {
6035  if (tsub->substate == SUBSTATE_HOLD) {
6036  activate_sub = tsub;
6037  }
6038  }
6039  if (activate_sub) {
6040  setsubstate(activate_sub, SUBSTATE_HOLD);
6041  return;
6042  }
6043  }
6044  } else {
6046  }
6047 }
6048 
6049 static void activatesub(struct skinny_subchannel *sub, int state)
6050 {
6051  struct skinny_line *l = sub->line;
6052 
6053  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Activating, and deactivating sub %u\n",
6054  sub->callid, l->activesub ? l->activesub->callid : 0);
6055 
6056  if (sub == l->activesub) {
6057  setsubstate(sub, state);
6058  } else {
6059  if (l->activesub) {
6060  if (l->activesub->substate == SUBSTATE_RINGIN) {
6062  } else if (l->activesub->substate != SUBSTATE_HOLD) {
6064  }
6065  }
6066  l->activesub = sub;
6067  setsubstate(sub, state);
6068  }
6069 }
6070 
6072 {
6073  struct skinny_line *l = sub->line;
6074  struct skinny_device *d = l->device;
6075 
6076  if (sub->dialType == DIALTYPE_NORMAL) {
6077  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Dial %s and Activate\n", sub->callid, exten);
6078  ast_copy_string(sub->exten, exten, sizeof(sub->exten));
6080  } else if (sub->dialType == DIALTYPE_CFWD) {
6081  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Set callforward(%d) to %s\n", sub->callid, sub->getforward, exten);
6082  set_callforwards(l, sub->exten, sub->getforward);
6083  dumpsub(sub, 1);
6084  transmit_cfwdstate(d, l);
6085  transmit_displaynotify(d, "CFwd enabled", 10);
6086  } else if (sub->dialType == DIALTYPE_XFER) {
6087  ast_copy_string(sub->exten, exten, sizeof(sub->exten));
6088  skinny_transfer_blind(sub);
6089  }
6090 }
6091 
6093 {
6094  if (!sub)
6095  return -1;
6096  if (sub->related) {
6097  setsubstate(sub, SUBSTATE_HOLD);
6099  } else {
6100  if (sub->substate == SUBSTATE_HOLD) {
6102  } else {
6103  setsubstate(sub, SUBSTATE_HOLD);
6104  }
6105  }
6106  return 1;
6107 }
6108 
6110 {
6111  struct skinny_line *l;
6112  struct skinny_device *d;
6113  struct skinny_subchannel *newsub;
6114  struct ast_channel *c;
6115 
6116  if (!sub) {
6117  ast_verbose("Transfer: No subchannel to transfer\n");
6118  return -1;
6119  }
6120 
6121  l = sub->line;
6122  d = l->device;
6123 
6124  if (!d->session) {
6125  ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
6126  return -1;
6127  }
6128 
6129  if (!sub->related) {
6130  /* Another sub has not been created so this must be first XFER press */
6131  if (!(sub->substate == SUBSTATE_HOLD)) {
6132  setsubstate(sub, SUBSTATE_HOLD);
6133  }
6135  if (c) {
6136  newsub = ast_channel_tech_pvt(c);
6137  /* point the sub and newsub at each other so we know they are related */
6138  newsub->related = sub;
6139  sub->related = newsub;
6140  newsub->xferor = 1;
6141  setsubstate(newsub, SUBSTATE_OFFHOOK);
6142  } else {
6143  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
6144  }
6145  } else {
6146  /* We already have a related sub so we can either complete XFER or go into BLINDXFER (or cancel BLINDXFER */
6147  if (sub->substate == SUBSTATE_OFFHOOK) {
6148  if (sub->dialType == DIALTYPE_XFER) {
6149  sub->dialType = DIALTYPE_NORMAL;
6150  } else {
6151  sub->dialType = DIALTYPE_XFER;
6152  }
6153  } else {
6155  }
6156  }
6157  return 0;
6158 }
6159 
6160 static void handle_callforward_button(struct skinny_line *l, struct skinny_subchannel *sub, int cfwdtype)
6161 {
6162  struct skinny_device *d = l->device;
6163  struct ast_channel *c;
6164 
6165  if (!d->session) {
6166  ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
6167  return;
6168  }
6169 
6170  if (!sub && (l->cfwdtype & cfwdtype)) {
6171  set_callforwards(l, NULL, cfwdtype);
6172  if (sub) {
6173  dumpsub(sub, 1);
6174  }
6175  transmit_cfwdstate(d, l);
6176  transmit_displaynotify(d, "CFwd disabled", 10);
6177  } else {
6178  if (!sub || !sub->owner) {
6179  if (!(c = skinny_new(l, NULL, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING))) {
6180  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
6181  return;
6182  }
6183  sub = ast_channel_tech_pvt(c);
6184  l->activesub = sub;
6186  }
6187  sub->getforward |= cfwdtype;
6188  sub->dialType = DIALTYPE_CFWD;
6189  }
6190 }
6191 
6192 static int handle_ip_port_message(struct skinny_req *req, struct skinnysession *s)
6193 {
6194  /* no response necessary */
6195  return 1;
6196 }
6197 
6198 static void handle_keepalive_message(struct skinny_req *req, struct skinnysession *s)
6199 {
6201 
6202 #ifdef AST_DEVMODE
6203  {
6204  long keepalive_diff;
6205  keepalive_diff = (long) ast_tvdiff_ms(ast_tvnow(), ast_tvadd(s->last_keepalive, ast_tv(keep_alive, 0)));
6207  "Keep_alive %d on %s, %.3fs %s\n",
6208  ++s->keepalive_count,
6209  (s->device ? s->device->name : "unregistered"),
6210  (float) labs(keepalive_diff) / 1000,
6211  (keepalive_diff > 0 ? "late" : "early"));
6212  }
6213 #endif
6214 
6216  s->last_keepalive = ast_tvnow();
6218 }
6219 
6220 static int handle_keypad_button_message(struct skinny_req *req, struct skinnysession *s)
6221 {
6222  struct skinny_subchannel *sub = NULL;
6223  struct skinny_line *l;
6224  struct skinny_device *d = s->device;
6225  struct ast_frame f = { 0, };
6226  char dgt;
6227  int digit;
6228  int lineInstance;
6229  int callReference;
6230  size_t len;
6231 
6232  digit = letohl(req->data.keypad.button);
6233  lineInstance = letohl(req->data.keypad.lineInstance);
6234  callReference = letohl(req->data.keypad.callReference);
6235 
6236  if (lineInstance && callReference) {
6237  sub = find_subchannel_by_instance_reference(d, lineInstance, callReference);
6238  } else {
6239  sub = d->activeline->activesub;
6240  }
6241 
6242  if (!sub)
6243  return 0;
6244 
6245  l = sub->line;
6246 
6247  if (digit == 14) {
6248  dgt = '*';
6249  } else if (digit == 15) {
6250  dgt = '#';
6251  } else if (digit >= 0 && digit <= 9) {
6252  dgt = '0' + digit;
6253  } else {
6254  /* digit=10-13 (A,B,C,D ?), or
6255  * digit is bad value
6256  *
6257  * probably should not end up here, but set
6258  * value for backward compatibility, and log
6259  * a warning.
6260  */
6261  dgt = '0' + digit;
6262  ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
6263  }
6264 
6265  if ((sub->owner && ast_channel_state(sub->owner) < AST_STATE_UP)) {
6266  if (-1 < sub->dialer_sched && !skinny_sched_del(sub->dialer_sched, sub)) {
6267  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Got a digit and not timed out, so try dialing\n", sub->callid);
6268  sub->dialer_sched = -1;
6269  len = strlen(sub->exten);
6270  if (len == 0) {
6271  transmit_stop_tone(d, l->instance, sub->callid);
6273  }
6274  if (len < sizeof(sub->exten) - 1 && dgt != immed_dialchar) {
6275  sub->exten[len] = dgt;
6276  sub->exten[len + 1] = '\0';
6277  }
6278  if (len == sizeof(sub->exten) - 1 || dgt == immed_dialchar) {
6279  skinny_dialer(sub, 1);
6280  } else {
6281  skinny_dialer(sub, 0);
6282  }
6283  } else {
6284  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u Got a digit already timedout, ignore\n", sub->callid);
6285  /* Timed out so the call is being progressed elsewhere, to late for digits */
6286  return 0;
6287  }
6288  } else {
6289  SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %u - Got a digit and sending as DTMF\n", sub->callid);
6290  f.subclass.integer = dgt;
6291  f.src = "skinny";
6292  if (sub->owner) {
6293  if (ast_channel_state(sub->owner) == 0) {
6295  ast_queue_frame(sub->owner, &f);
6296  }
6297  /* XXX MUST queue this frame to all lines in threeway call if threeway call is active */
6299  ast_queue_frame(sub->owner, &f);
6300  /* XXX This seriously needs to be fixed */
6301  if (AST_LIST_NEXT(sub, list) && AST_LIST_NEXT(sub, list)->owner) {
6302  if (ast_channel_state(sub->owner) == 0) {
6304  ast_queue_frame(AST_LIST_NEXT(sub, list)->owner, &f);
6305  }
6307  ast_queue_frame(AST_LIST_NEXT(sub, list)->owner, &f);
6308  }
6309  } else {
6310  ast_log(LOG_WARNING, "Got digit on %s, but not associated with channel\n", l->name);
6311  }
6312  }
6313  return 1;
6314 }
6315 
6316 static int handle_stimulus_message(struct skinny_req *req, struct skinnysession *s)
6317 {
6318  struct skinny_device *d = s->device;
6319  struct skinny_line *l;
6320  struct skinny_subchannel *sub;
6321  /*struct skinny_speeddial *sd;*/
6322  struct ast_channel *c;
6323  int event;
6324  int instance;
6325 #ifdef AST_DEVMODE
6326  int callreference;
6327  /* This is only used in AST_DEVMODE, as an argument to SKINNY_DEBUG */
6328  callreference = letohl(req->data.stimulus.callreference);
6329 #endif
6330 
6331  event = letohl(req->data.stimulus.stimulus);
6332  instance = letohl(req->data.stimulus.stimulusInstance);
6333 
6334  /* Note that this call should be using the passed in instance and callreference */
6335  sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
6336 
6337  if (!sub) {
6338  l = find_line_by_instance(d, d->lastlineinstance);
6339  if (!l) {
6340  return 0;
6341  }
6342  sub = l->activesub;
6343  } else {
6344  l = sub->line;
6345  }
6346 
6347  switch(event) {
6348  case STIMULUS_REDIAL:
6349  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_REDIAL from %s, inst %d, callref %d\n",
6350  d->name, instance, callreference);
6351 
6352  if (ast_strlen_zero(l->lastnumberdialed)) {
6353  ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found. Ignoring button.\n");
6354  break;
6355  }
6356 
6358  if (!c) {
6359  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
6360  } else {
6361  sub = ast_channel_tech_pvt(c);
6362  l = sub->line;
6363  dialandactivatesub(sub, l->lastnumberdialed);
6364  }
6365  break;
6366  case STIMULUS_SPEEDDIAL:
6367  {
6368  struct skinny_speeddial *sd;
6369 
6370  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_SPEEDDIAL from %s, inst %d, callref %d\n",
6371  d->name, instance, callreference);
6372 
6373  if (!(sd = find_speeddial_by_instance(d, instance, 0))) {
6374  return 0;
6375  }
6376 
6377  if (!sub || !sub->owner)
6379  else
6380  c = sub->owner;
6381 
6382  if (!c) {
6383  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
6384  } else {
6385  sub = ast_channel_tech_pvt(c);
6386  dialandactivatesub(sub, sd->exten);
6387  }
6388  }
6389  break;
6390  case STIMULUS_HOLD:
6391  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_HOLD from %s, inst %d, callref %d\n",
6392  d->name, instance, callreference);
6393  handle_hold_button(sub);
6394  break;
6395  case STIMULUS_TRANSFER:
6396  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_TRANSFER from %s, inst %d, callref %d\n",
6397  d->name, instance, callreference);
6398  if (l->transfer)
6400  else
6401  transmit_displaynotify(d, "Transfer disabled", 10);
6402  break;
6403  case STIMULUS_CONFERENCE:
6404  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_CONFERENCE from %s, inst %d, callref %d\n",
6405  d->name, instance, callreference);
6406  /* XXX determine the best way to pull off a conference. Meetme? */
6407  break;
6408  case STIMULUS_VOICEMAIL:
6409  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_VOICEMAIL from %s, inst %d, callref %d\n",
6410  d->name, instance, callreference);
6411 
6412  if (!sub || !sub->owner) {
6414  } else {
6415  c = sub->owner;
6416  }
6417 
6418  if (!c) {
6419  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
6420  break;
6421  }
6422 
6423  sub = ast_channel_tech_pvt(c);
6424  if (sub->substate == SUBSTATE_UNSET || sub->substate == SUBSTATE_OFFHOOK){
6425  dialandactivatesub(sub, l->vmexten);
6426  }
6427  break;
6428  case STIMULUS_CALLPARK:
6429  {
6430  char extout[AST_MAX_EXTENSION];
6431  RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
6432  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_CALLPARK from %s, inst %d, callref %d\n",
6433  d->name, instance, callreference);
6434 
6436  transmit_displaynotify(d, "Call Park not available", 10);
6437  break;
6438  }
6439 
6440  if ((sub && sub->owner) && (ast_channel_state(sub->owner) == AST_STATE_UP)) {
6441  c = sub->owner;
6442  ast_channel_lock(c);
6443  bridge_channel = ast_channel_get_bridge_channel(c);
6444  ast_channel_unlock(c);
6445 
6446  if (!bridge_channel) {
6447  transmit_displaynotify(d, "Call Park failed", 10);
6448  break;
6449  }
6450 
6451  if (!ast_parking_park_call(bridge_channel, extout, sizeof(extout))) {
6452  static const char msg_prefix[] = "Call Parked at: ";
6453  char message[sizeof(msg_prefix) + sizeof(extout)];
6454 
6455  snprintf(message, sizeof(message), "%s%s", msg_prefix, extout);
6456  transmit_displaynotify(d, message, 10);
6457  break;
6458  }
6459  transmit_displaynotify(d, "Call Park failed", 10);
6460  } else {
6461  transmit_displaynotify(d, "Call Park not available", 10);
6462  }
6463  break;
6464  }
6465  case STIMULUS_DND:
6466  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_DND from %s, inst %d, callref %d\n",
6467  d->name, instance, callreference);
6468 
6469  /* Do not disturb */
6470  if (l->dnd != 0){
6471  ast_verb(3, "Disabling DND on %s@%s\n", l->name, d->name);
6472  l->dnd = 0;
6474  transmit_displaynotify(d, "DnD disabled", 10);
6475  } else {
6476  ast_verb(3, "Enabling DND on %s@%s\n", l->name, d->name);
6477  l->dnd = 1;
6479  transmit_displaynotify(d, "DnD enabled", 10);
6480  }
6481  break;
6482  case STIMULUS_FORWARDALL:
6483  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_FORWARDALL from %s, inst %d, callref %d\n",
6484  d->name, instance, callreference);
6486  break;
6487  case STIMULUS_FORWARDBUSY:
6488  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_FORWARDBUSY from %s, inst %d, callref %d\n",
6489  d->name, instance, callreference);
6491  break;
6493  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_FORWARDNOANSWER from %s, inst %d, callref %d\n",
6494  d->name, instance, callreference);
6496  break;
6497  case STIMULUS_DISPLAY:
6498  /* Not sure what this is */
6499  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_DISPLAY from %s, inst %d, callref %d\n",
6500  d->name, instance, callreference);
6501  break;
6502  case STIMULUS_LINE:
6503  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_LINE from %s, inst %d, callref %d\n",
6504  d->name, instance, callreference);
6505 
6506  l = find_line_by_instance(d, instance);
6507 
6508  if (!l) {
6509  return 0;
6510  }
6511 
6512  d->activeline = l;
6513 
6514  /* turn the speaker on */
6518 
6519  d->hookstate = SKINNY_OFFHOOK;
6520 
6521  if (sub && sub->calldirection == SKINNY_INCOMING) {
6523  } else {
6524  if (sub && sub->owner) {
6525  ast_debug(1, "Current subchannel [%s] already has owner\n", ast_channel_name(sub->owner));
6526  } else {
6528  if (c) {
6530  } else {
6531  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
6532  }
6533  }
6534  }
6535  break;
6536  default:
6537  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received UNKNOWN_STIMULUS(%d) from %s, inst %d, callref %d\n",
6538  event, d->name, instance, callreference);
6539  break;
6540  }
6542 
6543  return 1;
6544 }
6545 
6546 static int handle_offhook_message(struct skinny_req *req, struct skinnysession *s)
6547 {
6548  struct skinny_device *d = s->device;
6549  struct skinny_line *l = NULL;
6550  struct skinny_subchannel *sub = NULL;
6551  struct ast_channel *c;
6552  int instance;
6553  int reference;
6554 
6555  instance = letohl(req->data.offhook.instance);
6556  reference = letohl(req->data.offhook.reference);
6557 
6558  if (d->hookstate == SKINNY_OFFHOOK) {
6559  ast_verb(3, "Got offhook message when device (%s) already offhook\n", d->name);
6560  return 0;
6561  }
6562 
6563  if (reference) {
6564  sub = find_subchannel_by_instance_reference(d, instance, reference);
6565  if (sub) {
6566  l = sub->line;
6567  }
6568  }
6569  if (!sub) {
6570  if (instance) {
6571  l = find_line_by_instance(d, instance);
6572  } else {
6573  l = d->activeline;
6574  }
6575  sub = l->activesub;
6576  }
6577 
6579  d->hookstate = SKINNY_OFFHOOK;
6580 
6582 
6583  if (sub && sub->substate == SUBSTATE_HOLD) {
6584  return 1;
6585  }
6586 
6588 
6589  if (sub && sub->calldirection == SKINNY_INCOMING) {
6591  } else {
6592  /* Not ideal, but let's send updated time at onhook and offhook, as it clears the display */
6594 
6595  if (sub && sub->owner) {
6596  ast_debug(1, "Current sub [%s] already has owner\n", ast_channel_name(sub->owner));
6597  } else {
6599  if (c) {
6601  } else {
6602  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
6603  }
6604  }
6605  }
6606  return 1;
6607 }
6608 
6609 static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s)
6610 {
6611  struct skinny_device *d = s->device;
6612  struct skinny_line *l;
6613  struct skinny_subchannel *sub;
6614  int instance;
6615  int reference;
6616 
6617  instance = letohl(req->data.onhook.instance);
6618  reference = letohl(req->data.onhook.reference);
6619 
6620  if (instance && reference) {
6621  sub = find_subchannel_by_instance_reference(d, instance, reference);
6622  if (!sub) {
6623  return 0;
6624  }
6625  l = sub->line;
6626  } else {
6627  l = d->activeline;
6628  sub = l->activesub;
6629  if (!sub) {
6630  return 0;
6631  }
6632  }
6633 
6634  if (d->hookstate == SKINNY_ONHOOK) {
6635  /* Something else already put us back on hook */
6636  /* Not ideal, but let's send updated time anyway, as it clears the display */
6638  return 0;
6639  }
6640 
6641  if (l->transfer && sub->xferor && ast_channel_state(sub->owner) >= AST_STATE_RING) {
6642  /* We're allowed to transfer, we have two active calls and
6643  we made at least one of the calls. Let's try and transfer */
6645  return 0;
6646  }
6647 
6649 
6650  dumpsub(sub, 0);
6651 
6652  d->hookstate = SKINNY_ONHOOK;
6653 
6654  /* Not ideal, but let's send updated time at onhook and offhook, as it clears the display */
6656 
6657  return 1;
6658 }
6659 
6661 {
6662  struct skinny_device *d = s->device;
6663  struct skinny_line *l;
6664  uint32_t count = 0;
6666  int i;
6667 #ifdef AST_DEVMODE
6668  struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
6669 #endif
6670 
6671 
6672  if (!codecs) {
6673  return 0;
6674  }
6675 
6676  count = letohl(req->data.caps.count);
6677  if (count > SKINNY_MAX_CAPABILITIES) {
6678  count = SKINNY_MAX_CAPABILITIES;
6679  ast_log(LOG_WARNING, "Received more capabilities than we can handle (%d). Ignoring the rest.\n", SKINNY_MAX_CAPABILITIES);
6680  }
6681 
6682  for (i = 0; i < count; i++) {
6683  struct ast_format *acodec;
6684  int scodec = 0;
6685  scodec = letohl(req->data.caps.caps[i].codec);
6686  acodec = codec_skinny2ast(scodec);
6687  SKINNY_DEBUG(DEBUG_AUDIO, 4, "Adding codec capability %s (%d)\n", ast_format_get_name(acodec), scodec);
6688  ast_format_cap_append(codecs, acodec, 0);
6689  }
6690 
6691  ast_format_cap_get_compatible(d->confcap, codecs, d->cap);
6692  SKINNY_DEBUG(DEBUG_AUDIO, 4, "Device capability set to '%s'\n", ast_format_cap_get_names(d->cap, &codec_buf));
6693  AST_LIST_TRAVERSE(&d->lines, l, list) {
6694  ast_mutex_lock(&l->lock);
6696  ast_mutex_unlock(&l->lock);
6697  }
6698 
6699  ao2_ref(codecs, -1);
6700  return 1;
6701 }
6702 
6704 {
6705  struct skinny_device *d = s->device;
6706  struct skinny_line *l;
6707  int i;
6708  struct skinny_speeddial *sd;
6709  struct skinny_serviceurl *surl;
6710  struct button_definition_template btn[42];
6711  int lineInstance = 1;
6712  int speeddialInstance = 1;
6713  int serviceurlInstance = 1;
6714  int buttonCount = 0;
6715 
6717  return -1;
6718 
6719  SKINNY_DEBUG(DEBUG_TEMPLATE, 3, "Creating Button Template\n");
6720 
6721  memset(&btn, 0, sizeof(btn));
6722  get_button_template(s, btn);
6723 
6724  for (i=0; i<42; i++) {
6725  int btnSet = 0;
6726  switch (btn[i].buttonDefinition) {
6727  case BT_CUST_LINE:
6728  /* assume failure */
6731 
6732  AST_LIST_TRAVERSE(&d->lines, l, list) {
6733  if (l->instance == lineInstance) {
6734  SKINNY_DEBUG(DEBUG_TEMPLATE, 4, "Adding button: %d, %d\n", BT_LINE, lineInstance);
6736  req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
6737  lineInstance++;
6738  buttonCount++;
6739  btnSet = 1;
6740  break;
6741  }
6742  }
6743 
6744  if (!btnSet) {
6745  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
6746  if (sd->isHint && sd->instance == lineInstance) {
6747  SKINNY_DEBUG(DEBUG_TEMPLATE, 4, "Adding button: %d, %d\n", BT_LINE, lineInstance);
6749  req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
6750  lineInstance++;
6751  buttonCount++;
6752  btnSet = 1;
6753  break;
6754  }
6755  }
6756  }
6757  break;
6758  case BT_CUST_LINESPEEDDIAL:
6759  /* assume failure */
6762 
6763  AST_LIST_TRAVERSE(&d->lines, l, list) {
6764  if (l->instance == lineInstance) {
6765  SKINNY_DEBUG(DEBUG_TEMPLATE, 4, "Adding button: %d, %d\n", BT_LINE, lineInstance);
6767  req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
6768  lineInstance++;
6769  buttonCount++;
6770  btnSet = 1;
6771  break;
6772  }
6773  }
6774 
6775  if (!btnSet) {
6776  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
6777  if (sd->isHint && sd->instance == lineInstance) {
6778  SKINNY_DEBUG(DEBUG_TEMPLATE, 4, "Adding button: %d, %d\n", BT_LINE, lineInstance);
6780  req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
6781  lineInstance++;
6782  buttonCount++;
6783  btnSet = 1;
6784  break;
6785  } else if (!sd->isHint && sd->instance == speeddialInstance) {
6786  SKINNY_DEBUG(DEBUG_TEMPLATE, 4, "Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
6788  req->data.buttontemplate.definition[i].instanceNumber = speeddialInstance;
6789  speeddialInstance++;
6790  buttonCount++;
6791  btnSet = 1;
6792  break;
6793  }
6794  }
6795  }
6796 
6797  if (!btnSet) {
6798  AST_LIST_TRAVERSE(&d->serviceurls, surl, list) {
6799  if (surl->instance == serviceurlInstance) {
6800  SKINNY_DEBUG(DEBUG_TEMPLATE, 4, "Adding button: %d, %d\n", BT_SERVICEURL, serviceurlInstance);
6802  req->data.buttontemplate.definition[i].instanceNumber = serviceurlInstance;
6803  serviceurlInstance++;
6804  buttonCount++;
6805  btnSet = 1;
6806  break;
6807  }
6808  }
6809  }
6810  break;
6811  case BT_LINE:
6814 
6815  AST_LIST_TRAVERSE(&d->lines, l, list) {
6816  if (l->instance == lineInstance) {
6817  SKINNY_DEBUG(DEBUG_TEMPLATE, 4, "Adding button: %d, %d\n", BT_LINE, lineInstance);
6819  req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
6820  lineInstance++;
6821  buttonCount++;
6822  btnSet = 1;
6823  break;
6824  }
6825  }
6826  break;
6827  case BT_SPEEDDIAL:
6830 
6831  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
6832  if (!sd->isHint && sd->instance == speeddialInstance) {
6833  SKINNY_DEBUG(DEBUG_TEMPLATE, 4, "Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
6835  req->data.buttontemplate.definition[i].instanceNumber = speeddialInstance - 1;
6836  speeddialInstance++;
6837  buttonCount++;
6838  btnSet = 1;
6839  break;
6840  }
6841  }
6842  break;
6843  case BT_NONE:
6844  break;
6845  default:
6846  SKINNY_DEBUG(DEBUG_TEMPLATE, 4, "Adding button: %d, %d\n", btn[i].buttonDefinition, 0);
6847  req->data.buttontemplate.definition[i].buttonDefinition = htolel(btn[i].buttonDefinition);
6849  buttonCount++;
6850  btnSet = 1;
6851  break;
6852  }
6853  }
6854 
6855  req->data.buttontemplate.buttonOffset = 0;
6856  req->data.buttontemplate.buttonCount = htolel(buttonCount);
6857  req->data.buttontemplate.totalButtonCount = htolel(buttonCount);
6858 
6859  SKINNY_DEBUG(DEBUG_PACKET | DEBUG_TEMPLATE, 3, "Transmitting BUTTON_TEMPLATE_RES_MESSAGE to %s, type %d\n",
6860  d->name, d->type);
6861  transmit_response(d, req);
6862  return 1;
6863 }
6864 
6866 {
6867  struct skinny_device *d = s->device;
6868  struct skinny_line *l;
6869  struct skinny_subchannel *sub;
6870  struct sockaddr_in sin = { 0, };
6871  struct sockaddr_in us = { 0, };
6872  struct ast_sockaddr sin_tmp;
6873  struct ast_sockaddr us_tmp;
6874  struct ast_format *tmpfmt;
6875  uint32_t addr;
6876  int port;
6877  int status;
6878  int callid;
6879  unsigned int framing;
6880 
6881  status = (d->protocolversion<17) ? letohl(req->data.openreceivechannelack_ip4.status) : letohl(req->data.openreceivechannelack_ip6.status);
6882 
6883  if (status) {
6884  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received OPEN_RECEIVE_CHANNEL_ACK_MESSAGE from %s, status %d\n",
6885  d->name, status);
6886  ast_log(LOG_ERROR, "Open Receive Channel Failure\n");
6887  return 0;
6888  }
6889 
6890  if (d->protocolversion<17) {
6894  } else {
6895  memcpy(&addr, &req->data.openreceivechannelack_ip6.ipAddr, sizeof(addr));
6898  }
6899 
6900  sin.sin_family = AF_INET;
6901  sin.sin_addr.s_addr = addr;
6902  sin.sin_port = htons(port);
6903 
6904  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received OPEN_RECEIVE_CHANNEL_ACK_MESSAGE from %s, status %d, callid %d, ip %s:%d\n",
6905  d->name, status, callid, ast_inet_ntoa(sin.sin_addr), port);
6906 
6907  sub = find_subchannel_by_reference(d, callid);
6908 
6909  if (!sub) {
6910  ast_log(LOG_ERROR, "Open Receive Channel Failure - can't find sub for %d\n", callid);
6911  return 0;
6912  }
6913 
6914  l = sub->line;
6915 
6916  if (sub->rtp) {
6917  ast_sockaddr_from_sin(&sin_tmp, &sin);
6918  ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
6919  ast_rtp_instance_get_local_address(sub->rtp, &us_tmp);
6920  ast_sockaddr_to_sin(&us_tmp, &us);
6921  us.sin_addr.s_addr = us.sin_addr.s_addr ? us.sin_addr.s_addr : d->ourip.s_addr;
6922  } else {
6923  ast_log(LOG_ERROR, "No RTP structure, this is very bad\n");
6924  return 0;
6925  }
6926 
6927  SKINNY_DEBUG(DEBUG_PACKET, 4, "device ipaddr = %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
6928  SKINNY_DEBUG(DEBUG_PACKET, 4, "asterisk ipaddr = %s:%d\n", ast_inet_ntoa(us.sin_addr), ntohs(us.sin_port));
6929 
6930  tmpfmt = ast_format_cap_get_format(l->cap, 0);
6931  framing = ast_format_cap_get_format_framing(l->cap, tmpfmt);
6932 
6933  SKINNY_DEBUG(DEBUG_PACKET, 4, "Setting payloadType to '%s' (%u ms)\n", ast_format_get_name(tmpfmt), framing);
6934 
6935  transmit_startmediatransmission(d, sub, us, tmpfmt, framing);
6936 
6937  ao2_ref(tmpfmt, -1);
6938 
6939  return 1;
6940 }
6941 
6942 static int handle_enbloc_call_message(struct skinny_req *req, struct skinnysession *s)
6943 {
6944  struct skinny_device *d = s->device;
6945  struct skinny_line *l;
6946  struct skinny_subchannel *sub = NULL;
6947  struct ast_channel *c;
6948 
6949  sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
6950 
6951  if (!sub) {
6952  l = find_line_by_instance(d, d->lastlineinstance);
6953  if (!l) {
6954  return 0;
6955  }
6956  } else {
6957  l = sub->line;
6958  }
6959 
6961 
6962  if(!c) {
6963  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
6964  } else {
6965  d->hookstate = SKINNY_OFFHOOK;
6966 
6967  sub = ast_channel_tech_pvt(c);
6969  }
6970 
6971  return 1;
6972 }
6973 
6974 static int handle_soft_key_event_message(struct skinny_req *req, struct skinnysession *s)
6975 {
6976  struct skinny_device *d = s->device;
6977  struct skinny_line *l;
6978  struct skinny_subchannel *sub = NULL;
6979  struct ast_channel *c;
6980  int event;
6981  int instance;
6982  int callreference;
6983 
6985  instance = letohl(req->data.softkeyeventmessage.instance);
6986  callreference = letohl(req->data.softkeyeventmessage.callreference);
6987 
6988  if (instance) {
6989  l = find_line_by_instance(d, instance);
6990  if (callreference) {
6991  sub = find_subchannel_by_instance_reference(d, instance, callreference);
6992  } else {
6993  sub = find_subchannel_by_instance_reference(d, instance, d->lastcallreference);
6994  }
6995  } else {
6996  l = find_line_by_instance(d, d->lastlineinstance);
6997  }
6998 
6999  if (!l) {
7000  ast_log(LOG_WARNING, "Received Softkey Event: %d(%d/%d) but can't find line\n", event, instance, callreference);
7001  return 0;
7002  }
7003 
7005 
7006  switch(event) {
7007  case SOFTKEY_NONE:
7008  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_NONE from %s, inst %d, callref %d\n",
7009  d->name, instance, callreference);
7010  break;
7011  case SOFTKEY_REDIAL:
7012  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_REDIAL from %s, inst %d, callref %d\n",
7013  d->name, instance, callreference);
7014 
7015  if (ast_strlen_zero(l->lastnumberdialed)) {
7016  ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found. Ignoring button.\n");
7017  break;
7018  }
7019 
7020  if (!sub || !sub->owner) {
7022  } else {
7023  c = sub->owner;
7024  }
7025 
7026  if (!c) {
7027  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
7028  } else {
7029  sub = ast_channel_tech_pvt(c);
7030  dialandactivatesub(sub, l->lastnumberdialed);
7031  }
7032  break;
7033  case SOFTKEY_NEWCALL: /* Actually the DIAL softkey */
7034  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_NEWCALL from %s, inst %d, callref %d\n",
7035  d->name, instance, callreference);
7036 
7037  /* New Call ALWAYS gets a new sub-channel */
7039  sub = ast_channel_tech_pvt(c);
7040 
7041  if (!c) {
7042  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
7043  } else {
7045  }
7046  break;
7047  case SOFTKEY_HOLD:
7048  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_HOLD from %s, inst %d, callref %d\n",
7049  d->name, instance, callreference);
7050 
7051  if (sub) {
7052  setsubstate(sub, SUBSTATE_HOLD);
7053  } else { /* No sub, maybe an SLA call */
7054  struct skinny_subline *subline;
7055  if ((subline = find_subline_by_callid(d, callreference))) {
7056  setsubstate(subline->sub, SUBSTATE_HOLD);
7057  }
7058  }
7059 
7060  break;
7061  case SOFTKEY_TRNSFER:
7062  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_TRNSFER from %s, inst %d, callref %d\n",
7063  d->name, instance, callreference);
7064  if (l->transfer)
7066  else
7067  transmit_displaynotify(d, "Transfer disabled", 10);
7068 
7069  break;
7070  case SOFTKEY_DND:
7071  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_DND from %s, inst %d, callref %d\n",
7072  d->name, instance, callreference);
7073 
7074  /* Do not disturb */
7075  if (l->dnd != 0){
7076  ast_verb(3, "Disabling DND on %s@%s\n", l->name, d->name);
7077  l->dnd = 0;
7079  transmit_displaynotify(d, "DnD disabled", 10);
7080  } else {
7081  ast_verb(3, "Enabling DND on %s@%s\n", l->name, d->name);
7082  l->dnd = 1;
7084  transmit_displaynotify(d, "DnD enabled", 10);
7085  }
7086  break;
7087  case SOFTKEY_CFWDALL:
7088  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_CFWDALL from %s, inst %d, callref %d\n",
7089  d->name, instance, callreference);
7091  break;
7092  case SOFTKEY_CFWDBUSY:
7093  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_CFWDBUSY from %s, inst %d, callref %d\n",
7094  d->name, instance, callreference);
7096  break;
7097  case SOFTKEY_CFWDNOANSWER:
7098  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_CFWDNOANSWER from %s, inst %d, callref %d\n",
7099  d->name, instance, callreference);
7101  break;
7102  case SOFTKEY_BKSPC:
7103  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_BKSPC from %s, inst %d, callref %d\n",
7104  d->name, instance, callreference);
7105  if (-1 < sub->dialer_sched && !skinny_sched_del(sub->dialer_sched, sub)) {
7106  size_t len;
7107  sub->dialer_sched = -1;
7108  len = strlen(sub->exten);
7109  if (len > 0) {
7110  sub->exten[len-1] = '\0';
7111  if (len == 1) {
7112  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
7113  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK, KEYMASK_ALL);
7114  }
7115  transmit_backspace(d, l->instance, sub->callid);
7116  }
7118  }
7119  break;
7120  case SOFTKEY_ENDCALL:
7121  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_ENDCALL from %s, inst %d, callref %d\n",
7122  d->name, instance, callreference);
7123 
7125 
7126  if (sub) {
7127  dumpsub(sub, 1);
7128  } else { /* No sub, maybe an SLA call */
7129  struct skinny_subline *subline;
7130  if ((subline = find_subline_by_callid(d, callreference))) {
7131  dumpsub(subline->sub, 1);
7132  }
7133  }
7134 
7135  d->hookstate = SKINNY_ONHOOK;
7136 
7137  /* Not ideal, but let's send updated time at onhook and offhook, as it clears the display */
7139 
7140  break;
7141  case SOFTKEY_RESUME:
7142  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_RESUME from %s, inst %d, callref %d\n",
7143  d->name, instance, callreference);
7144 
7145  if (sub) {
7147  } else { /* No sub, maybe an inactive SLA call */
7148  struct skinny_subline *subline;
7149  subline = find_subline_by_callid(d, callreference);
7150  c = skinny_new(l, subline, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
7151  if (!c) {
7152  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
7153  } else {
7154  sub = ast_channel_tech_pvt(c);
7155  dialandactivatesub(sub, subline->exten);
7156  }
7157  }
7158  break;
7159  case SOFTKEY_ANSWER:
7160  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_ANSWER from %s, inst %d, callref %d\n",
7161  d->name, instance, callreference);
7162 
7165  if (d->hookstate == SKINNY_ONHOOK) {
7167  d->hookstate = SKINNY_OFFHOOK;
7168  }
7169 
7170  if (sub && sub->calldirection == SKINNY_INCOMING) {
7172  }
7173  break;
7174  case SOFTKEY_INFO:
7175  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_INFO from %s, inst %d, callref %d\n",
7176  d->name, instance, callreference);
7177  break;
7178  case SOFTKEY_CONFRN:
7179  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_CONFRN from %s, inst %d, callref %d\n",
7180  d->name, instance, callreference);
7181  /* XXX determine the best way to pull off a conference. Meetme? */
7182  break;
7183  case SOFTKEY_PARK:
7184  {
7185  char extout[AST_MAX_EXTENSION];
7186  RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
7187  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_PARK from %s, inst %d, callref %d\n",
7188  d->name, instance, callreference);
7189 
7191  transmit_displaynotify(d, "Call Park not available", 10);
7192  break;
7193  }
7194 
7195  if ((sub && sub->owner) && (ast_channel_state(sub->owner) == AST_STATE_UP)) {
7196  c = sub->owner;
7197  ast_channel_lock(c);
7198  bridge_channel = ast_channel_get_bridge_channel(c);
7199  ast_channel_unlock(c);
7200 
7201  if (!bridge_channel) {
7202  transmit_displaynotify(d, "Call Park failed", 10);
7203  break;
7204  }
7205 
7206  if (!ast_parking_park_call(bridge_channel, extout, sizeof(extout))) {
7207  static const char msg_prefix[] = "Call Parked at: ";
7208  char message[sizeof(msg_prefix) + sizeof(extout)];
7209 
7210  snprintf(message, sizeof(message), "%s%s", msg_prefix, extout);
7211  transmit_displaynotify(d, message, 10);
7212  break;
7213  }
7214  transmit_displaynotify(d, "Call Park failed", 10);
7215  } else {
7216  transmit_displaynotify(d, "Call Park not available", 10);
7217  }
7218  break;
7219  }
7220  case SOFTKEY_JOIN:
7221  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_JOIN from %s, inst %d, callref %d\n",
7222  d->name, instance, callreference);
7223  /* this is SLA territory, should not get here unless there is a meetme at subline */
7224  {
7225  struct skinny_subline *subline;
7226  subline = find_subline_by_callid(d, callreference);
7227  c = skinny_new(l, subline, AST_STATE_DOWN, NULL, NULL, SKINNY_OUTGOING);
7228  if (!c) {
7229  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
7230  } else {
7231  sub = ast_channel_tech_pvt(c);
7232  dialandactivatesub(sub, subline->exten);
7233  }
7234  }
7235  break;
7236  case SOFTKEY_MEETME:
7237  /* XXX How is this different from CONFRN? */
7238  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_MEETME from %s, inst %d, callref %d\n",
7239  d->name, instance, callreference);
7240  break;
7241  case SOFTKEY_PICKUP:
7242  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_PICKUP from %s, inst %d, callref %d\n",
7243  d->name, instance, callreference);
7244  break;
7245  case SOFTKEY_GPICKUP:
7246  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_GPICKUP from %s, inst %d, callref %d\n",
7247  d->name, instance, callreference);
7248  if (!sub || !sub->owner) {
7250  } else {
7251  c = sub->owner;
7252  }
7253 
7254  if (!c) {
7255  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
7256  } else {
7257  ast_channel_ref(c);
7258  sub = ast_channel_tech_pvt(c);
7259  ast_pickup_call(c);
7260  if (sub->owner == c) {
7261  ast_channel_unref(c);
7262  dumpsub(sub, 1);
7263  } else {
7264  ast_hangup(c);
7266  ast_channel_unref(c);
7267  }
7268  }
7269  break;
7270  case SOFTKEY_FORCEDIAL:
7271  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_FORCEDIAL from %s, inst %d, callref %d\n",
7272  d->name, instance, callreference);
7273  skinny_dialer(sub, 1);
7274 
7275  break;
7276  default:
7277  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_UNKNOWN(%d) from %s, inst %d, callref %d\n",
7278  event, d->name, instance, callreference);
7279  break;
7280  }
7281 
7282  return 1;
7283 }
7284 
7285 static int handle_message(struct skinny_req *req, struct skinnysession *s)
7286 {
7287  int res = 0;
7288  struct skinny_speeddial *sd;
7289  struct skinny_device *d = s->device;
7290 
7291  if (!d && !(letohl(req->e) == REGISTER_MESSAGE || letohl(req->e) == ALARM_MESSAGE || letohl(req->e) == KEEP_ALIVE_MESSAGE)) {
7292  ast_log(LOG_WARNING, "Client sent message #%u without first registering.\n", req->e);
7293  return 0;
7294  }
7295 
7296  switch(letohl(req->e)) {
7297  case KEEP_ALIVE_MESSAGE:
7298  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received KEEP_ALIVE_MESSAGE from %s\n", (d ? d->name : "unregistered"));
7299  handle_keepalive_message(req, s);
7300  break;
7301  case REGISTER_MESSAGE:
7302  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received REGISTER_MESSAGE from %s, name %s, type %u, protovers %d\n",
7303  d->name, req->data.reg.name, letohl(req->data.reg.type), letohl(req->data.reg.protocolVersion));
7304  res = skinny_register(req, s);
7305  if (!res) {
7306  sleep(2);
7307  res = skinny_register(req, s);
7308  }
7309  if (res != 1) {
7311  return -1;
7312  }
7314  ast_verb(3, "Device '%s' successfully registered (protoVers %d)\n", s->device->name, s->device->protocolversion);
7317  res = 0;
7318  break;
7319  case IP_PORT_MESSAGE:
7320  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received IP_PORT_MESSAGE from %s\n", d->name);
7321  res = handle_ip_port_message(req, s);
7322  break;
7323  case KEYPAD_BUTTON_MESSAGE:
7324  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received KEYPAD_BUTTON_MESSAGE from %s, digit %u, inst %u, callref %u\n",
7326  res = handle_keypad_button_message(req, s);
7327  break;
7328  case ENBLOC_CALL_MESSAGE:
7329  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received ENBLOC_CALL_MESSAGE from %s, calledParty %s\n",
7330  d->name, req->data.enbloccallmessage.calledParty);
7331  res = handle_enbloc_call_message(req, s);
7332  break;
7333  case STIMULUS_MESSAGE:
7334  /* SKINNY_PACKETDEBUG handled in handle_stimulus_message */
7335  res = handle_stimulus_message(req, s);
7336  break;
7337  case OFFHOOK_MESSAGE:
7338  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received OFFHOOK_MESSAGE from %s, inst %u, ref %u\n",
7339  d->name, letohl(req->data.offhook.instance), letohl(req->data.offhook.reference));
7340  res = handle_offhook_message(req, s);
7341  break;
7342  case ONHOOK_MESSAGE:
7343  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received ONHOOK_MESSAGE from %s, inst %u, ref %u\n",
7344  d->name, letohl(req->data.offhook.instance), letohl(req->data.offhook.reference));
7345  res = handle_onhook_message(req, s);
7346  break;
7348  SKINNY_DEBUG(DEBUG_PACKET | DEBUG_AUDIO, 3, "Received CAPABILITIES_RES_MESSAGE from %s, count %u, codec data\n",
7349  d->name, letohl(req->data.caps.count));
7350  res = handle_capabilities_res_message(req, s);
7351  break;
7353  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SPEED_DIAL_STAT_REQ_MESSAGE from %s, sdNum %u\n",
7354  d->name, letohl(req->data.speeddialreq.speedDialNumber));
7357  }
7358  break;
7360  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received LINE_STATE_REQ_MESSAGE from %s, lineNum %u\n",
7361  d->name, letohl(req->data.line.lineNumber));
7363  break;
7364  case TIME_DATE_REQ_MESSAGE:
7365  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received TIME_DATE_REQ_MESSAGE from %s\n", d->name);
7367  break;
7369  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received BUTTON_TEMPLATE_REQ_MESSAGE from %s\n", d->name);
7370  res = handle_button_template_req_message(req, s);
7371  break;
7372  case VERSION_REQ_MESSAGE:
7373  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received VERSION_REQ_MESSAGE from %s\n", d->name);
7375  break;
7377  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SERVER_REQUEST_MESSAGE from %s\n", d->name);
7378  transmit_serverres(d);
7379  break;
7380  case ALARM_MESSAGE:
7381  /* no response necessary */
7382  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received ALARM_MESSAGE from %s, alarm %s\n",
7383  d->name, req->data.alarm.displayMessage);
7384  break;
7386  /* SKINNY_PACKETDEBUG handled in handle_open_receive_channel_ack_message */
7388  break;
7390  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFT_KEY_SET_REQ_MESSAGE from %s\n", d->name);
7393  break;
7395  /* SKINNY_PACKETDEBUG handled in handle_soft_key_event_message */
7396  res = handle_soft_key_event_message(req, s);
7397  break;
7398  case UNREGISTER_MESSAGE:
7399  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received UNREGISTER_MESSAGE from %s\n", d->name);
7400  ast_log(LOG_NOTICE, "Received UNREGISTER_MESSAGE from %s\n", d->name);
7401  end_session(s);
7402  break;
7404  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFT_KEY_TEMPLATE_REQ_MESSAGE from %s\n", d->name);
7406  break;
7408  /* XXX umm...okay? Why do I care? */
7409  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received HEADSET_STATUS_MESSAGE from %s\n", d->name);
7410  break;
7412  /* XXX I have no clue what this is for, but my phone was sending it, so... */
7413  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received REGISTER_AVAILABLE_LINES_MESSAGE from %s\n", d->name);
7414  break;
7416  SKINNY_DEBUG(DEBUG_PACKET, 3, "SERVICEURL_STATREQ_MESSAGE from %s\n", d->name);
7418  break;
7419  default:
7420  SKINNY_DEBUG(DEBUG_PACKET, 3, "Received UNKNOWN_MESSAGE(%x) from %s\n", (unsigned)letohl(req->e), d->name);
7421  break;
7422  }
7423  return res;
7424 }
7425 
7426 static void destroy_session(struct skinnysession *s)
7427 {
7428  ast_mutex_lock(&s->lock);
7429  if (s->fd > -1) {
7430  close(s->fd);
7431  }
7432 
7433  if (s->device) {
7434  s->device->session = NULL;
7435  } else {
7437  }
7438  ast_mutex_unlock(&s->lock);
7439  ast_mutex_destroy(&s->lock);
7440 
7441  if (s->t != AST_PTHREADT_NULL) {
7442  pthread_detach(s->t);
7443  }
7444 
7445  ast_free(s);
7446 }
7447 
7448 static int skinny_noauth_cb(const void *data)
7449 {
7450  struct skinnysession *s = (struct skinnysession *)data;
7451  ast_log(LOG_WARNING, "Skinny Client failed to authenticate in %d seconds (SCHED %d)\n", auth_timeout, s->auth_timeout_sched);
7452  s->auth_timeout_sched = -1;
7453  end_session(s);
7454  return 0;
7455 }
7456 
7457 static int skinny_nokeepalive_cb(const void *data)
7458 {
7459  struct skinnysession *s = (struct skinnysession *)data;
7460  ast_log(LOG_WARNING, "Skinny Client failed to send keepalive in last %d seconds (SCHED %d)\n", keep_alive*3, s->keepalive_timeout_sched);
7461  s->keepalive_timeout_sched = -1;
7462  end_session(s);
7463  return 0;
7464 }
7465 
7466 static void skinny_session_cleanup(void *data)
7467 {
7468  struct skinnysession *s = (struct skinnysession *)data;
7469  struct skinny_device *d = s->device;
7470  struct skinny_line *l;
7471  struct skinny_speeddial *sd;
7472 
7473  ast_log(LOG_NOTICE, "Ending Skinny session from %s at %s\n", d ? d->name : "unknown", ast_inet_ntoa(s->sin.sin_addr));
7474 
7475  if (s->lockstate) {
7476  ast_mutex_unlock(&s->lock);
7477  }
7478 
7479  if (-1 < s->auth_timeout_sched) {
7481  s->auth_timeout_sched = -1;
7482  }
7483  if (-1 < s->keepalive_timeout_sched) {
7485  s->keepalive_timeout_sched = -1;
7486  }
7487 
7488  if (d) {
7489  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
7490  d->session = NULL;
7491 
7492  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
7493  if (sd->stateid > -1)
7495  }
7496  AST_LIST_TRAVERSE(&d->lines, l, list) {
7497  if (l->device != d) {
7498  continue;
7499  }
7502  l->instance = 0;
7503  unregister_exten(l);
7505  }
7507  blob = ast_json_pack("{s: s}", "peer_status", "Unregistered");
7509  }
7510 
7514 
7515  destroy_session(s);
7516 }
7517 
7518 #define PACKET_TIMEOUT 10000
7519 
7520 static void *skinny_session(void *data)
7521 {
7522  int res;
7523  int bytesread;
7524  struct skinny_req *req = NULL;
7525  struct skinnysession *s = data;
7526 
7527  int dlen = 0;
7528  int eventmessage = 0;
7529  struct pollfd fds[1];
7530 
7531  ast_log(LOG_NOTICE, "Starting Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));
7532 
7533  pthread_cleanup_push(skinny_session_cleanup, s);
7534 
7535  s->start = ast_tvnow();
7536  s->last_keepalive = ast_tvnow();
7537  s->keepalive_count = 0;
7538  s->lockstate = 0;
7539 
7541  AST_LIST_INSERT_HEAD(&sessions, s, list);
7543 
7546 
7547  for (;;) {
7548 
7549  fds[0].fd = s->fd;
7550  fds[0].events = POLLIN;
7551  fds[0].revents = 0;
7552  res = ast_poll(fds, 1, -1); /* block */
7553  if (res < 0) {
7554  if (errno != EINTR) {
7555  ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
7556  ast_verb(3, "Ending Skinny session from %s (bad input)\n", ast_inet_ntoa(s->sin.sin_addr));
7557  break;
7558  }
7559  }
7560 
7561  if (!fds[0].revents) {
7562  continue;
7563  }
7564  ast_debug(1, "Reading header\n");
7565 
7566  if (!(req = ast_calloc(1, SKINNY_MAX_PACKET))) {
7567  ast_log(LOG_WARNING, "Unable to allocated memorey for skinny_req.\n");
7568  break;
7569  }
7570 
7571  ast_mutex_lock(&s->lock);
7572  s->lockstate = 1;
7573 
7574  if ((res = read(s->fd, req, skinny_header_size)) != skinny_header_size) {
7575  if (res < 0) {
7576  ast_log(LOG_WARNING, "Header read() returned error: %s\n", strerror(errno));
7577  } else {
7578  ast_log(LOG_WARNING, "Unable to read header. Only found %d bytes.\n", res);
7579  }
7580  break;
7581  }
7582 
7583  eventmessage = letohl(req->e);
7584  if (eventmessage < 0) {
7585  ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
7586  break;
7587  }
7588 
7589  dlen = letohl(req->len) - 4;
7590  if (dlen < 0) {
7591  ast_log(LOG_WARNING, "Skinny Client sent invalid data.\n");
7592  break;
7593  }
7594  if (dlen > (SKINNY_MAX_PACKET - skinny_header_size)) {
7595  ast_log(LOG_WARNING, "Skinny packet too large (%d bytes), max length(%d bytes)\n", dlen+8, SKINNY_MAX_PACKET);
7596  break;
7597  }
7598 
7599  ast_debug(1, "Read header: Message ID: 0x%04x, %d bytes in packet\n", eventmessage, dlen);
7600 
7601  bytesread = 0;
7602  while (bytesread < dlen) {
7603  ast_debug(1, "Waiting %dms for %d bytes of %d\n", PACKET_TIMEOUT, dlen - bytesread, dlen);
7604  fds[0].revents = 0;
7605  res = ast_poll(fds, 1, PACKET_TIMEOUT);
7606  if (res <= 0) {
7607  if (res == 0) {
7608  ast_debug(1, "Poll timed out waiting for %d bytes\n", dlen - bytesread);
7609  } else {
7610  ast_log(LOG_WARNING, "Poll failed waiting for %d bytes: %s\n",
7611  dlen - bytesread, strerror(errno));
7612  }
7613  ast_verb(3, "Ending Skinny session from %s (bad input)\n", ast_inet_ntoa(s->sin.sin_addr));
7614  res = -1;
7615 
7616  break;
7617  }
7618  if (!fds[0].revents) {
7619  continue;
7620  }
7621 
7622  res = read(s->fd, ((char*)&req->data)+bytesread, dlen-bytesread);
7623  if (res < 0) {
7624  ast_log(LOG_WARNING, "Data read() returned error: %s\n", strerror(errno));
7625  break;
7626  }
7627  bytesread += res;
7628  ast_debug(1, "Read %d bytes. %d of %d now read\n", res, bytesread, dlen);
7629  }
7630 
7631  s->lockstate = 0;
7632  ast_mutex_unlock(&s->lock);
7633  if (res < 0) {
7634  break;
7635  }
7636 
7637  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
7638  res = handle_message(req, s);
7639  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
7640 
7641  if (req) {
7642  ast_free(req);
7643  req = NULL;
7644  }
7645  }
7646 
7647  ast_log(LOG_NOTICE, "Skinny Session returned: %s\n", strerror(errno));
7648  if (req) {
7649  ast_free(req);
7650  }
7651 
7652  pthread_cleanup_pop(1);
7653 
7654  return 0;
7655 }
7656 
7657 static void *accept_thread(void *ignore)
7658 {
7659  int as;
7660  struct sockaddr_in sin;
7661  socklen_t sinlen;
7662  struct skinnysession *s;
7663  int arg = 1;
7664 
7665  for (;;) {
7666  sinlen = sizeof(sin);
7667  as = accept(skinnysock, (struct sockaddr *)&sin, &sinlen);
7668  if (as < 0) {
7669  ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
7670  continue;
7671  }
7672 
7674  close(as);
7676  continue;
7677  }
7678 
7679  if (setsockopt(as, IPPROTO_TCP, TCP_NODELAY, (char *) &arg, sizeof(arg)) < 0) {
7680  ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on Skinny TCP connection: %s\n", strerror(errno));
7681  }
7682 
7683  if (!(s = ast_calloc(1, sizeof(struct skinnysession)))) {
7684  close(as);
7686  continue;
7687  }
7688 
7689  ast_mutex_init(&s->lock);
7690  memcpy(&s->sin, &sin, sizeof(sin));
7691  s->fd = as;
7692  s->auth_timeout_sched = -1;
7693  s->keepalive_timeout_sched = -1;
7694 
7695  if (ast_pthread_create(&s->t, NULL, skinny_session, s)) {
7696  s->t = AST_PTHREADT_NULL;
7697  destroy_session(s);
7698  }
7699  }
7700  SKINNY_DEBUG(DEBUG_THREAD, 3, "Killing accept thread\n");
7701  close(as);
7702  return 0;
7703 }
7704 
7705 static int skinny_devicestate(const char *data)
7706 {
7707  struct skinny_line *l;
7708  char *tmp;
7709 
7710  tmp = ast_strdupa(data);
7711 
7712  l = find_line_by_name(tmp);
7713 
7714  return get_devicestate(l);
7715 }
7716 
7717 static struct ast_channel *skinny_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest, int *cause)
7718 {
7719  struct skinny_line *l;
7720  struct skinny_subline *subline = NULL;
7721  struct ast_channel *tmpc = NULL;
7722  char tmp[256];
7723 
7725  struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
7726  ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf));
7727  return NULL;
7728  }
7729 
7730  ast_copy_string(tmp, dest, sizeof(tmp));
7731  if (ast_strlen_zero(tmp)) {
7732  ast_log(LOG_NOTICE, "Skinny channels require a device\n");
7733  return NULL;
7734  }
7735  l = find_line_by_name(tmp);
7736  if (!l) {
7737  subline = find_subline_by_name(tmp);
7738  if (!subline) {
7739  ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
7740  return NULL;
7741  }
7742  l = subline->line;
7743  }
7744  ast_verb(3, "skinny_request(%s)\n", tmp);
7745  tmpc = skinny_new(l, subline, AST_STATE_DOWN, assignedids, requestor, SKINNY_INCOMING);
7746  if (!tmpc) {
7747  ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
7748  } else if (subline) {
7749  struct skinny_subchannel *sub = ast_channel_tech_pvt(tmpc);
7750  subline->sub = sub;
7751  subline->calldirection = SKINNY_INCOMING;
7752  subline->substate = SUBSTATE_UNSET;
7753  subline->callid = sub->callid;
7754  sub->subline = subline;
7755  }
7756  return tmpc;
7757 }
7758 
7759 #define TYPE_GENERAL 1
7760 #define TYPE_DEF_DEVICE 2
7761 #define TYPE_DEF_LINE 4
7762 #define TYPE_DEVICE 8
7763 #define TYPE_LINE 16
7764 
7765 #define CLINE_OPTS ((struct skinny_line_options *)item)
7766 #define CLINE ((struct skinny_line *)item)
7767 #define CDEV_OPTS ((struct skinny_device_options *)item)
7768 #define CDEV ((struct skinny_device *)item)
7769 
7770 static void config_parse_variables(int type, void *item, struct ast_variable *vptr)
7771 {
7772  struct ast_variable *v;
7773  int lineInstance = 1;
7774  int speeddialInstance = 1;
7775  int serviceUrlInstance = 1;
7776 
7777  while(vptr) {
7778  v = vptr;
7779  vptr = vptr->next;
7780 
7781  if (type & (TYPE_GENERAL)) {
7782  char newcontexts[AST_MAX_CONTEXT];
7783  char oldcontexts[AST_MAX_CONTEXT];
7784  char *stringp, *context, *oldregcontext;
7785  if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
7786  v = v->next;
7787  continue;
7788  }
7789  if (!strcasecmp(v->name, "bindaddr")) {
7790  if (!(hp = ast_gethostbyname(v->value, &ahp))) {
7791  ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
7792  } else {
7793  memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
7794  }
7795  continue;
7796  } else if (!strcasecmp(v->name, "keepalive")) {
7797  keep_alive = atoi(v->value);
7798  continue;
7799  } else if (!strcasecmp(v->name, "authtimeout")) {
7800  int timeout = atoi(v->value);
7801 
7802  if (timeout < 1) {
7803  ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", v->value);
7805  } else {
7807  }
7808  continue;
7809  } else if (!strcasecmp(v->name, "authlimit")) {
7810  int limit = atoi(v->value);
7811 
7812  if (limit < 1) {
7813  ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", v->value);
7815  } else {
7816  auth_limit = limit;
7817  }
7818  continue;
7819  } else if (!strcasecmp(v->name, "regcontext")) {
7820  ast_copy_string(newcontexts, v->value, sizeof(newcontexts));
7821  stringp = newcontexts;
7822  /* Initialize copy of current global_regcontext for later use in removing stale contexts */
7823  ast_copy_string(oldcontexts, regcontext, sizeof(oldcontexts));
7824  oldregcontext = oldcontexts;
7825  /* Let's remove any contexts that are no longer defined in regcontext */
7826  cleanup_stale_contexts(stringp, oldregcontext);
7827  /* Create contexts if they don't exist already */
7828  while ((context = strsep(&stringp, "&"))) {
7829  ast_copy_string(used_context, context, sizeof(used_context));
7830  ast_context_find_or_create(NULL, NULL, context, "Skinny");
7831  }
7833  continue;
7834  } else if (!strcasecmp(v->name, "vmexten")) {
7835  ast_copy_string(vmexten, v->value, sizeof(vmexten));
7836  continue;
7837  } else if (!strcasecmp(v->name, "immeddialkey")) {
7838  if (!strcmp(v->value,"#")) {
7839  immed_dialchar = '#';
7840  } else if (!strcmp(v->value,"*")) {
7841  immed_dialchar = '*';
7842  } else {
7843  ast_log(LOG_WARNING, "Invalid immeddialkey '%s' at line %d, only # or * accepted. Immeddial key disabled\n", v->value, v->lineno);
7844  }
7845 
7846  continue;
7847  } else if (!strcasecmp(v->name, "dateformat")) {
7848  memcpy(date_format, v->value, sizeof(date_format));
7849  continue;
7850  } else if (!strcasecmp(v->name, "tos")) {
7851  if (ast_str2tos(v->value, &qos.tos))
7852  ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
7853  continue;
7854  } else if (!strcasecmp(v->name, "tos_audio")) {
7855  if (ast_str2tos(v->value, &qos.tos_audio))
7856  ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
7857  continue;
7858  } else if (!strcasecmp(v->name, "tos_video")) {
7859  if (ast_str2tos(v->value, &qos.tos_video))
7860  ast_log(LOG_WARNING, "Invalid tos_video value at line %d, refer to QoS documentation\n", v->lineno);
7861  continue;
7862  } else if (!strcasecmp(v->name, "cos")) {
7863  if (ast_str2cos(v->value, &qos.cos))
7864  ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
7865  continue;
7866  } else if (!strcasecmp(v->name, "cos_audio")) {
7867  if (ast_str2cos(v->value, &qos.cos_audio))
7868  ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
7869  continue;
7870  } else if (!strcasecmp(v->name, "cos_video")) {
7871  if (ast_str2cos(v->value, &qos.cos_video))
7872  ast_log(LOG_WARNING, "Invalid cos_video value at line %d, refer to QoS documentation\n", v->lineno);
7873  continue;
7874  } else if (!strcasecmp(v->name, "bindport")) {
7875  if (sscanf(v->value, "%5d", &ourport) == 1) {
7876  bindaddr.sin_port = htons(ourport);
7877  } else {
7878  ast_log(LOG_WARNING, "Invalid bindport '%s' at line %d of %s\n", v->value, v->lineno, config);
7879  }
7880  continue;
7881  } else if (!strcasecmp(v->name, "allow")) {
7882  ast_format_cap_update_by_allow_disallow(default_cap, v->value, 1);
7883  continue;
7884  } else if (!strcasecmp(v->name, "disallow")) {
7885  ast_format_cap_update_by_allow_disallow(default_cap, v->value, 0);
7886  continue;
7887  }
7888  }
7889 
7890  if (!strcasecmp(v->name, "transfer")) {
7891  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
7892  CDEV_OPTS->transfer = ast_true(v->value);
7893  continue;
7894  } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7895  CLINE_OPTS->transfer = ast_true(v->value);
7896  continue;
7897  }
7898  } else if (!strcasecmp(v->name, "callwaiting")) {
7899  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
7900  CDEV_OPTS->callwaiting = ast_true(v->value);
7901  continue;
7902  } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7903  CLINE_OPTS->callwaiting = ast_true(v->value);
7904  continue;
7905  }
7906  } else if (!strcasecmp(v->name, "directmedia") || !strcasecmp(v->name, "canreinvite")) {
7907  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7908  CLINE_OPTS->directmedia = ast_true(v->value);
7909  continue;
7910  }
7911  } else if (!strcasecmp(v->name, "nat")) {
7912  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7913  CLINE_OPTS->nat = ast_true(v->value);
7914  continue;
7915  }
7916  } else if (!strcasecmp(v->name, "context")) {
7917  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7918  ast_copy_string(CLINE_OPTS->context, v->value, sizeof(CLINE_OPTS->context));
7919  continue;
7920  }
7921  }else if (!strcasecmp(v->name, "vmexten")) {
7922  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
7923  ast_copy_string(CDEV_OPTS->vmexten, v->value, sizeof(CDEV_OPTS->vmexten));
7924  continue;
7925  } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7926  ast_copy_string(CLINE_OPTS->vmexten, v->value, sizeof(CLINE_OPTS->vmexten));
7927  continue;
7928  }
7929  } else if (!strcasecmp(v->name, "mwiblink")) {
7930  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
7931  CDEV_OPTS->mwiblink = ast_true(v->value);
7932  continue;
7933  } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7934  CLINE_OPTS->mwiblink = ast_true(v->value);
7935  continue;
7936  }
7937  } else if (!strcasecmp(v->name, "linelabel")) {
7938  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7939  ast_copy_string(CLINE_OPTS->label, v->value, sizeof(CLINE_OPTS->label));
7940  continue;
7941  }
7942  } else if (!strcasecmp(v->name, "callerid")) {
7943  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7944  if (!strcasecmp(v->value, "asreceived")) {
7945  CLINE_OPTS->cid_num[0] = '\0';
7946  CLINE_OPTS->cid_name[0] = '\0';
7947  } else {
7948  ast_callerid_split(v->value, CLINE_OPTS->cid_name, sizeof(CLINE_OPTS->cid_name), CLINE_OPTS->cid_num, sizeof(CLINE_OPTS->cid_num));
7949  }
7950  continue;
7951  }
7952  } else if (!strcasecmp(v->name, "amaflags")) {
7953  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7954  int tempamaflags = ast_channel_string2amaflag(v->value);
7955  if (tempamaflags < 0) {
7956  ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
7957  } else {
7958  CLINE_OPTS->amaflags = tempamaflags;
7959  }
7960  continue;
7961  }
7962  } else if (!strcasecmp(v->name, "regexten")) {
7963  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7964  ast_copy_string(CLINE_OPTS->regexten, v->value, sizeof(CLINE_OPTS->regexten));
7965  continue;
7966  }
7967  } else if (!strcasecmp(v->name, "language")) {
7968  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7969  ast_copy_string(CLINE_OPTS->language, v->value, sizeof(CLINE_OPTS->language));
7970  continue;
7971  }
7972  } else if (!strcasecmp(v->name, "accountcode")) {
7973  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7974  ast_copy_string(CLINE_OPTS->accountcode, v->value, sizeof(CLINE_OPTS->accountcode));
7975  continue;
7976  }
7977  } else if (!strcasecmp(v->name, "mohinterpret") || !strcasecmp(v->name, "musiconhold")) {
7978  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7979  ast_copy_string(CLINE_OPTS->mohinterpret, v->value, sizeof(CLINE_OPTS->mohinterpret));
7980  continue;
7981  }
7982  } else if (!strcasecmp(v->name, "mohsuggest")) {
7983  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7984  ast_copy_string(CLINE_OPTS->mohsuggest, v->value, sizeof(CLINE_OPTS->mohsuggest));
7985  continue;
7986  }
7987  } else if (!strcasecmp(v->name, "callgroup")) {
7988  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7989  CLINE_OPTS->callgroup = ast_get_group(v->value);
7990  continue;
7991  }
7992  } else if (!strcasecmp(v->name, "pickupgroup")) {
7993  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7994  CLINE_OPTS->pickupgroup = ast_get_group(v->value);
7995  continue;
7996  }
7997  } else if (!strcasecmp(v->name, "namedcallgroup")) {
7998  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7999  CLINE_OPTS->named_callgroups = ast_get_namedgroups(v->value);
8000  continue;
8001  }
8002  } else if (!strcasecmp(v->name, "namedpickupgroup")) {
8003  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
8004  CLINE_OPTS->named_pickupgroups = ast_get_namedgroups(v->value);
8005  continue;
8006  }
8007  } else if (!strcasecmp(v->name, "immediate")) {
8008  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE | TYPE_DEF_LINE | TYPE_LINE)) {
8009  CLINE_OPTS->immediate = ast_true(v->value);
8010  continue;
8011  }
8012  } else if (!strcasecmp(v->name, "cancallforward")) {
8013  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
8014  CLINE_OPTS->cancallforward = ast_true(v->value);
8015  continue;
8016  }
8017  } else if (!strcasecmp(v->name, "callfwdtimeout")) {
8018  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
8019  CLINE_OPTS->callfwdtimeout = atoi(v->value);
8020  continue;
8021  }
8022  } else if (!strcasecmp(v->name, "mailbox")) {
8023  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
8024  ast_copy_string(CLINE_OPTS->mailbox, v->value, sizeof(CLINE_OPTS->mailbox));
8025  continue;
8026  }
8027  } else if ( !strcasecmp(v->name, "parkinglot")) {
8028  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
8029  ast_copy_string(CLINE_OPTS->parkinglot, v->value, sizeof(CLINE_OPTS->parkinglot));
8030  continue;
8031  }
8032  } else if (!strcasecmp(v->name, "hasvoicemail")) {
8033  if (type & (TYPE_LINE)) {
8034  if (ast_true(v->value) && ast_strlen_zero(CLINE->mailbox)) {
8035  /*
8036  * hasvoicemail is a users.conf legacy voicemail enable method.
8037  * hasvoicemail is only going to work for app_voicemail mailboxes.
8038  */
8039  if (strchr(CLINE->name, '@')) {
8040  ast_copy_string(CLINE->mailbox, CLINE->name, sizeof(CLINE->mailbox));
8041  } else {
8042  snprintf(CLINE->mailbox, sizeof(CLINE->mailbox), "%s@default",
8043  CLINE->name);
8044  }
8045  }
8046  continue;
8047  }
8048  } else if (!strcasecmp(v->name, "threewaycalling")) {
8049  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
8050  CLINE_OPTS->threewaycalling = ast_true(v->value);
8051  continue;
8052  }
8053  } else if (!strcasecmp(v->name, "setvar")) {
8054  if (type & (TYPE_LINE)) {
8055  CLINE->chanvars = add_var(v->value, CLINE->chanvars);
8056  continue;
8057  }
8058  } else if (!strcasecmp(v->name, "earlyrtp")) {
8059  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
8060  CDEV_OPTS->earlyrtp = ast_true(v->value);
8061  continue;
8062  }
8063  } else if (!strcasecmp(v->name, "host")) {
8064  if (type & (TYPE_DEVICE)) {
8065  struct ast_sockaddr CDEV_addr_tmp;
8066 
8067  CDEV_addr_tmp.ss.ss_family = AF_INET;
8068  if (ast_get_ip(&CDEV_addr_tmp, v->value)) {
8069  ast_log(LOG_WARNING, "Bad IP '%s' at line %d.\n", v->value, v->lineno);
8070  }
8071  ast_sockaddr_to_sin(&CDEV_addr_tmp,
8072  &CDEV->addr);
8073  continue;
8074  }
8075  } else if (!strcasecmp(v->name, "port")) {
8076  if (type & (TYPE_DEF_DEVICE)) {
8077  CDEV->addr.sin_port = htons(atoi(v->value));
8078  continue;
8079  }
8080  } else if (!strcasecmp(v->name, "device")) {
8081  if (type & (TYPE_DEVICE)) {
8082  ast_copy_string(CDEV_OPTS->id, v->value, sizeof(CDEV_OPTS->id));
8083  continue;
8084  }
8085  } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
8086  if (type & (TYPE_DEVICE)) {
8087  int acl_error = 0;
8088 
8089  CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, &acl_error);
8090  if (acl_error) {
8091  ast_log(LOG_ERROR, "Invalid ACL '%s' on line '%d'. Deleting device\n",
8092  v->value, v->lineno);
8093  CDEV->prune = 1;
8094  }
8095  continue;
8096  }
8097  } else if (!strcasecmp(v->name, "allow")) {
8098  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
8100  continue;
8101  }
8102  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
8104  continue;
8105  }
8106  } else if (!strcasecmp(v->name, "disallow")) {
8107  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
8109  continue;
8110  }
8111  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
8113  continue;
8114  }
8115  } else if (!strcasecmp(v->name, "version")) {
8116  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
8117  ast_copy_string(CDEV_OPTS->version_id, v->value, sizeof(CDEV_OPTS->version_id));
8118  continue;
8119  }
8120  } else if (!strcasecmp(v->name, "line")) {
8121  if (type & (TYPE_DEVICE)) {
8122  struct skinny_line *l;
8123  AST_LIST_TRAVERSE(&lines, l, all) {
8124  if (!strcasecmp(v->value, l->name) && !l->prune) {
8125 
8126  /* FIXME: temp solution about line conflicts */
8127  struct skinny_device *d;
8128  struct skinny_line *l2;
8129  int lineinuse = 0;
8131  AST_LIST_TRAVERSE(&d->lines, l2, list) {
8132  if (l2 == l && strcasecmp(d->id, CDEV->id)) {
8133  ast_log(LOG_WARNING, "Line %s already used by %s. Not connecting to %s.\n", l->name, d->name, CDEV->name);
8134  lineinuse++;
8135  }
8136  }
8137  }
8138  if (!lineinuse) {
8139  if (!AST_LIST_FIRST(&CDEV->lines)) {
8140  CDEV->activeline = l;
8141  }
8142  lineInstance++;
8143  AST_LIST_INSERT_HEAD(&CDEV->lines, l, list);
8144  l->device = CDEV;
8145  }
8146  break;
8147  }
8148  }
8149  continue;
8150  }
8151  } else if (!strcasecmp(v->name, "subline")) {
8152  if (type & (TYPE_LINE)) {
8153  struct skinny_subline *subline;
8154  struct skinny_container *container;
8155  char buf[256];
8156  char *stringp = buf, *exten, *stname, *context;
8157 
8158  if (!(subline = ast_calloc(1, sizeof(*subline)))) {
8159  ast_log(LOG_WARNING, "Unable to allocate memory for subline %s. Ignoring subline.\n", v->value);
8160  continue;
8161  }
8162  if (!(container = ast_calloc(1, sizeof(*container)))) {
8163  ast_log(LOG_WARNING, "Unable to allocate memory for subline %s container. Ignoring subline.\n", v->value);
8164  ast_free(subline);
8165  continue;
8166  }
8167 
8168  ast_copy_string(buf, v->value, sizeof(buf));
8169  exten = strsep(&stringp, "@");
8170  ast_copy_string(subline->exten, ast_strip(exten), sizeof(subline->exten));
8171  stname = strsep(&exten, "_");
8172  ast_copy_string(subline->stname, ast_strip(stname), sizeof(subline->stname));
8173  ast_copy_string(subline->lnname, ast_strip(exten), sizeof(subline->lnname));
8174  context = strsep(&stringp, ",");
8175  ast_copy_string(subline->name, ast_strip(stringp), sizeof(subline->name));
8176  ast_copy_string(subline->context, ast_strip(context), sizeof(subline->context));
8177 
8178  subline->line = CLINE;
8179  subline->sub = NULL;
8180 
8181  container->type = SKINNY_SUBLINECONTAINER;
8182  container->data = subline;
8183  subline->container = container;
8184  AST_LIST_INSERT_HEAD(&CLINE->sublines, subline, list);
8185  continue;
8186  }
8187  } else if (!strcasecmp(v->name, "dialoutcontext")) {
8188  if (type & (TYPE_LINE)) {
8189  ast_copy_string(CLINE_OPTS->dialoutcontext, v->value, sizeof(CLINE_OPTS->dialoutcontext));
8190  continue;
8191  }
8192  } else if (!strcasecmp(v->name, "dialoutexten")) {
8193  if (type & (TYPE_LINE)) {
8194  ast_copy_string(CLINE_OPTS->dialoutexten, v->value, sizeof(CLINE_OPTS->dialoutexten));
8195  continue;
8196  }
8197  } else if (!strcasecmp(v->name, "speeddial")) {
8198  if (type & (TYPE_DEVICE)) {
8199  struct skinny_speeddial *sd;
8200  struct skinny_container *container;
8201  char buf[256];
8202  char *stringp = buf, *exten, *context, *label;
8203 
8204  if (!(sd = ast_calloc(1, sizeof(*sd)))) {
8205  ast_log(LOG_WARNING, "Unable to allocate memory for speeddial %s. Ignoring speeddial.\n", v->name);
8206  continue;
8207  }
8208  if (!(container = ast_calloc(1, sizeof(*container)))) {
8209  ast_log(LOG_WARNING, "Unable to allocate memory for speeddial %s container. Ignoring speeddial.\n", v->name);
8210  ast_free(sd);
8211  continue;
8212  }
8213 
8214  ast_copy_string(buf, v->value, sizeof(buf));
8215  exten = strsep(&stringp, ",");
8216  if ((context = strchr(exten, '@'))) {
8217  *context++ = '\0';
8218  }
8219  label = stringp;
8220  ast_mutex_init(&sd->lock);
8221  ast_copy_string(sd->exten, exten, sizeof(sd->exten));
8222  if (!ast_strlen_zero(context)) {
8223  sd->isHint = 1;
8224  sd->instance = lineInstance++;
8225  ast_copy_string(sd->context, context, sizeof(sd->context));
8226  } else {
8227  sd->isHint = 0;
8228  sd->instance = speeddialInstance++;
8229  sd->context[0] = '\0';
8230  }
8231  ast_copy_string(sd->label, S_OR(label, exten), sizeof(sd->label));
8232  sd->parent = CDEV;
8233  container->type = SKINNY_SDCONTAINER;
8234  container->data = sd;
8235  sd->container = container;
8236  AST_LIST_INSERT_HEAD(&CDEV->speeddials, sd, list);
8237  continue;
8238  }
8239  } else if (!strcasecmp(v->name, "serviceurl")) {
8240  if (type & (TYPE_DEVICE)) {
8241  struct skinny_serviceurl *surl;
8242  char buf[256];
8243  char *stringp = buf, *serviceUrl, *displayName;
8244  if (!(surl = ast_calloc(1, sizeof(*surl)))) {
8245  ast_log(LOG_WARNING, "Unable to allocate memory for serviceurl %s. Ignoring service URL.\n", v->name);
8246  continue;
8247  }
8248  ast_copy_string(buf, v->value, sizeof(buf));
8249  displayName = strsep(&stringp, ",");
8250  if (stringp) {
8251  serviceUrl = stringp;
8252  ast_copy_string(surl->url, ast_strip(serviceUrl), sizeof(surl->url));
8253  ast_copy_string(surl->displayName, displayName, sizeof(surl->displayName));
8254  surl->instance = serviceUrlInstance++;
8255  surl->device = CDEV;
8256  AST_LIST_INSERT_HEAD(&CDEV->serviceurls, surl, list);
8257  } else {
8258  ast_free(surl);
8259  ast_log(LOG_WARNING, "Badly formed option for service URL in %s. Ignoring service URL.\n", v->name);
8260  }
8261  continue;
8262  }
8263  } else if (!strcasecmp(v->name, "addon")) {
8264  if (type & (TYPE_DEVICE)) {
8265  struct skinny_addon *a;
8266  if (!(a = ast_calloc(1, sizeof(*a)))) {
8267  ast_log(LOG_WARNING, "Unable to allocate memory for addon %s. Ignoring addon.\n", v->name);
8268  continue;
8269  } else {
8270  ast_mutex_init(&a->lock);
8271  ast_copy_string(a->type, v->value, sizeof(a->type));
8272  AST_LIST_INSERT_HEAD(&CDEV->addons, a, list);
8273  }
8274  continue;
8275  }
8276 
8277  } else {
8278  ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
8279  continue;
8280  }
8281  ast_log(LOG_WARNING, "Invalid category used: %s at line %d\n", v->name, v->lineno);
8282  }
8283 }
8284 
8285 static struct skinny_line *config_line(const char *lname, struct ast_variable *v)
8286 {
8287  struct skinny_line *l, *temp;
8288  int update = 0;
8289  struct skinny_container *container;
8290 
8291  ast_log(LOG_NOTICE, "Configuring skinny line %s.\n", lname);
8292 
8293  /* We find the old line and remove it just before the new
8294  line is created */
8295  AST_LIST_LOCK(&lines);
8296  AST_LIST_TRAVERSE(&lines, temp, all) {
8297  if (!strcasecmp(lname, temp->name) && temp->prune) {
8298  update = 1;
8299  break;
8300  }
8301  }
8302 
8303  if (!(l = skinny_line_alloc())) {
8304  ast_verb(1, "Unable to allocate memory for line %s.\n", lname);
8306  return NULL;
8307  }
8308  if (!(container = ast_calloc(1, sizeof(*container)))) {
8309  ast_log(LOG_WARNING, "Unable to allocate memory for line %s container.\n", lname);
8312  return NULL;
8313  }
8314 
8315  container->type = SKINNY_LINECONTAINER;
8316  container->data = l;
8317  l->container = container;
8318 
8319  memcpy(l, default_line, sizeof(*default_line));
8320  ast_mutex_init(&l->lock);
8321  ast_copy_string(l->name, lname, sizeof(l->name));
8323  AST_LIST_INSERT_TAIL(&lines, l, all);
8324 
8325  ast_mutex_lock(&l->lock);
8327 
8329 
8330  if (!ast_strlen_zero(l->mailbox)) {
8331  ast_verb(3, "Setting mailbox '%s' on line %s\n", l->mailbox, l->name);
8332  l->mwi_event_sub = ast_mwi_subscribe_pool(l->mailbox, mwi_event_cb, l);
8333  }
8334 
8335  if (!ast_strlen_zero(vmexten) && ast_strlen_zero(l->vmexten)) {
8336  ast_copy_string(l->vmexten, vmexten, sizeof(l->vmexten));
8337  }
8338 
8339  ast_mutex_unlock(&l->lock);
8340 
8341  /* We do not want to unlink or free the line yet, it needs
8342  to be available to detect a device reconfig when we load the
8343  devices. Old lines will be pruned after the reload completes */
8344 
8345  ast_verb(3, "%s config for line '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), l->name);
8346 
8347  return l;
8348 }
8349 
8350 static struct skinny_device *config_device(const char *dname, struct ast_variable *v)
8351 {
8352  struct skinny_device *d, *temp;
8353  struct skinny_line *l, *ltemp;
8354  struct skinny_subchannel *sub;
8355  int update = 0;
8356 
8357  ast_log(LOG_NOTICE, "Configuring skinny device %s.\n", dname);
8358 
8360  AST_LIST_TRAVERSE(&devices, temp, list) {
8361  if (!strcasecmp(dname, temp->name) && temp->prune) {
8362  update = 1;
8363  break;
8364  }
8365  }
8366 
8367  if (!(d = skinny_device_alloc(dname))) {
8368  ast_verb(1, "Unable to allocate memory for device %s.\n", dname);
8370  return NULL;
8371  }
8372  memcpy(d, default_device, sizeof(*default_device));
8373  ast_mutex_init(&d->lock);
8374  ast_copy_string(d->name, dname, sizeof(d->name));
8377 
8378  ast_mutex_lock(&d->lock);
8380 
8382 
8383  if (!AST_LIST_FIRST(&d->lines)) {
8384  ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n");
8385  ast_mutex_unlock(&d->lock);
8386  return NULL;
8387  }
8388  if (/*d->addr.sin_addr.s_addr && */!ntohs(d->addr.sin_port)) {
8389  d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
8390  }
8391 
8392  if (skinnyreload){
8394  AST_LIST_TRAVERSE(&devices, temp, list) {
8395  if (strcasecmp(d->id, temp->id) || !temp->prune || !temp->session) {
8396  continue;
8397  }
8398  ast_mutex_lock(&d->lock);
8399  d->session = temp->session;
8400  d->session->device = d;
8401  d->hookstate = temp->hookstate;
8402 
8403  AST_LIST_LOCK(&d->lines);
8404  AST_LIST_TRAVERSE(&d->lines, l, list){
8405 
8406  AST_LIST_LOCK(&temp->lines);
8407  AST_LIST_TRAVERSE(&temp->lines, ltemp, list) {
8408  if (strcasecmp(l->name, ltemp->name)) {
8409  continue;
8410  }
8411  ast_mutex_lock(&ltemp->lock);
8412  l->instance = ltemp->instance;
8413  if (l == temp->activeline) {
8414  d->activeline = l;
8415  }
8416  if (!AST_LIST_EMPTY(&ltemp->sub)) {
8417  ast_mutex_lock(&l->lock);
8418  l->sub = ltemp->sub;
8419  l->activesub = ltemp->activesub;
8420  AST_LIST_TRAVERSE(&l->sub, sub, list) {
8421  sub->line = l;
8422  }
8423  ast_mutex_unlock(&l->lock);
8424  }
8425  ast_mutex_unlock(&ltemp->lock);
8426  }
8427  AST_LIST_UNLOCK(&temp->lines);
8428  }
8429  AST_LIST_UNLOCK(&d->lines);
8430  ast_mutex_unlock(&d->lock);
8431  }
8433  }
8434 
8435  ast_mutex_unlock(&d->lock);
8436 
8437  ast_verb(3, "%s config for device '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), d->name);
8438 
8439  return d;
8440 
8441 }
8442 
8443 static int config_load(void)
8444 {
8445  int on = 1;
8446  struct ast_config *cfg;
8447  char *cat;
8448  int oldport = ntohs(bindaddr.sin_port);
8449  struct ast_flags config_flags = { 0 };
8450 
8451  ast_log(LOG_NOTICE, "Configuring skinny from %s\n", config);
8452 
8453  if (gethostname(ourhost, sizeof(ourhost))) {
8454  ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled.\n");
8455  return 0;
8456  }
8457  cfg = ast_config_load(config, config_flags);
8458 
8459  /* We *must* have a config file otherwise stop immediately */
8460  if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
8461  ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled.\n", config);
8462  return -1;
8463  }
8464 
8465  memset(&bindaddr, 0, sizeof(bindaddr));
8466  immed_dialchar = '\0';
8467  memset(&vmexten, '\0', sizeof(vmexten));
8468 
8469 
8470  /* Copy the default jb config over global_jbconf */
8471  memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
8472 
8473  /* load the general section */
8474  cat = ast_category_browse(cfg, "general");
8476 
8477  if (ntohl(bindaddr.sin_addr.s_addr)) {
8478  __ourip = bindaddr.sin_addr;
8479  } else {
8481  if (!hp) {
8482  ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
8483  ast_config_destroy(cfg);
8484  return 0;
8485  }
8486  memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
8487  }
8488  if (!ntohs(bindaddr.sin_port)) {
8489  bindaddr.sin_port = htons(DEFAULT_SKINNY_PORT);
8490  }
8491  bindaddr.sin_family = AF_INET;
8492 
8493  /* load the lines sections */
8494  config_parse_variables(TYPE_DEF_LINE, default_line, ast_variable_browse(cfg, "lines"));
8495  cat = ast_category_browse(cfg, "lines");
8496  while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "devices")) {
8497  config_line(cat, ast_variable_browse(cfg, cat));
8498  cat = ast_category_browse(cfg, cat);
8499  }
8500 
8501  /* load the devices sections */
8502  config_parse_variables(TYPE_DEF_DEVICE, default_device, ast_variable_browse(cfg, "devices"));
8503  cat = ast_category_browse(cfg, "devices");
8504  while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "lines")) {
8505  config_device(cat, ast_variable_browse(cfg, cat));
8506  cat = ast_category_browse(cfg, cat);
8507  }
8508 
8510  if ((skinnysock > -1) && (ntohs(bindaddr.sin_port) != oldport)) {
8511  close(skinnysock);
8512  skinnysock = -1;
8513  }
8514  if (skinnysock < 0) {
8515  skinnysock = socket(AF_INET, SOCK_STREAM, 0);
8516  if(setsockopt(skinnysock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
8517  ast_log(LOG_ERROR, "Set Socket Options failed: errno %d, %s\n", errno, strerror(errno));
8518  ast_config_destroy(cfg);
8520  return 0;
8521  }
8522  if (skinnysock < 0) {
8523  ast_log(LOG_WARNING, "Unable to create Skinny socket: %s\n", strerror(errno));
8524  } else {
8525  if (bind(skinnysock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
8526  ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
8527  ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
8528  strerror(errno));
8529  close(skinnysock);
8530  skinnysock = -1;
8531  ast_config_destroy(cfg);
8533  return 0;
8534  }
8535  if (listen(skinnysock, DEFAULT_SKINNY_BACKLOG)) {
8536  ast_log(LOG_WARNING, "Failed to start listening to %s:%d: %s\n",
8537  ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
8538  strerror(errno));
8539  close(skinnysock);
8540  skinnysock = -1;
8541  ast_config_destroy(cfg);
8543  return 0;
8544  }
8545  ast_verb(2, "Skinny listening on %s:%d\n",
8546  ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
8547  ast_set_qos(skinnysock, qos.tos, qos.cos, "Skinny");
8549  }
8550  }
8552  ast_config_destroy(cfg);
8553  return 1;
8554 }
8555 
8556 static void delete_devices(void)
8557 {
8558  struct skinny_device *d;
8559  struct skinny_line *l;
8560  struct skinny_speeddial *sd;
8561  struct skinny_addon *a;
8562  struct skinny_serviceurl *surl;
8563 
8565  AST_LIST_LOCK(&lines);
8566 
8567  /* Delete all devices */
8568  while ((d = AST_LIST_REMOVE_HEAD(&devices, list))) {
8569  /* Delete all lines for this device */
8570  while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) {
8571  AST_LIST_REMOVE(&lines, l, all);
8572  AST_LIST_REMOVE(&d->lines, l, list);
8573  l = skinny_line_destroy(l);
8574  }
8575  /* Delete all speeddials for this device */
8576  while ((sd = AST_LIST_REMOVE_HEAD(&d->speeddials, list))) {
8577  ast_free(sd->container);
8578  ast_free(sd);
8579  }
8580  /* Delete all serviceurls for this device */
8581  while ((surl = AST_LIST_REMOVE_HEAD(&d->serviceurls, list))) {
8582  ast_free(surl);
8583  }
8584  /* Delete all addons for this device */
8585  while ((a = AST_LIST_REMOVE_HEAD(&d->addons, list))) {
8586  ast_free(a);
8587  }
8588  d = skinny_device_destroy(d);
8589  }
8592 }
8593 
8594 int skinny_reload(void)
8595 {
8596  struct skinny_device *d;
8597  struct skinny_line *l;
8598  struct skinny_speeddial *sd;
8599  struct skinny_addon *a;
8600 
8601  if (skinnyreload) {
8602  ast_verb(3, "Chan_skinny is already reloading.\n");
8603  return 0;
8604  }
8605 
8606  skinnyreload = 1;
8607 
8608  /* Mark all devices and lines as candidates to be pruned */
8611  d->prune = 1;
8612  }
8614 
8615  AST_LIST_LOCK(&lines);
8616  AST_LIST_TRAVERSE(&lines, l, all) {
8617  l->prune = 1;
8618  }
8620 
8621  config_load();
8622 
8623  /* Remove any devices that no longer exist in the config */
8626  if (!d->prune) {
8627  continue;
8628  }
8629  ast_verb(3, "Removing device '%s'\n", d->name);
8630  /* Delete all lines for this device.
8631  We do not want to free the line here, that
8632  will happen below. */
8633  while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) {
8634  if (l->mwi_event_sub) {
8636  }
8637  }
8638  /* Delete all speeddials for this device */
8639  while ((sd = AST_LIST_REMOVE_HEAD(&d->speeddials, list))) {
8640  ast_free(sd);
8641  }
8642  /* Delete all addons for this device */
8643  while ((a = AST_LIST_REMOVE_HEAD(&d->addons, list))) {
8644  ast_free(a);
8645  }
8647  d = skinny_device_destroy(d);
8648  }
8651 
8652  AST_LIST_LOCK(&lines);
8654  if (l->prune) {
8656  l = skinny_line_destroy(l);
8657  }
8658  }
8661 
8663  /* Do a soft reset to re-register the devices after
8664  cleaning up the removed devices and lines */
8665  if (d->session) {
8666  ast_verb(3, "Restarting device '%s'\n", d->name);
8667  transmit_reset(d, 1);
8668  }
8669  }
8670 
8671  skinnyreload = 0;
8672  return 0;
8673 }
8674 
8675 /*!
8676  * \brief Load the module
8677  *
8678  * Module loading including tests for configuration or dependencies.
8679  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
8680  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
8681  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
8682  * configuration file or other non-critical problem return
8683  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
8684  */
8685 static int load_module(void)
8686 {
8687  int res = 0;
8688 
8689  if (!(default_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
8690  return AST_MODULE_LOAD_DECLINE;
8691  }
8693  ao2_ref(default_cap, -1);
8694  return AST_MODULE_LOAD_DECLINE;
8695  }
8696 
8698  ast_format_cap_append(default_cap, ast_format_ulaw, 0);
8699  ast_format_cap_append(default_cap, ast_format_alaw, 0);
8700 
8701  for (; res < ARRAY_LEN(soft_key_template_default); res++) {
8702  soft_key_template_default[res].softKeyEvent = htolel(soft_key_template_default[res].softKeyEvent);
8703  }
8704  /* load and parse config */
8705  res = config_load();
8706  if (res == -1) {
8707  ao2_ref(skinny_tech.capabilities, -1);
8708  ao2_ref(default_cap, -1);
8709  return AST_MODULE_LOAD_DECLINE;
8710  }
8711 
8712  sched = ast_sched_context_create();
8713  if (!sched) {
8714  ao2_ref(skinny_tech.capabilities, -1);
8715  ao2_ref(default_cap, -1);
8716  ast_log(LOG_WARNING, "Unable to create schedule context\n");
8717  return AST_MODULE_LOAD_DECLINE;
8718  }
8719 
8720  /* Make sure we can register our skinny channel type */
8721  if (ast_channel_register(&skinny_tech)) {
8722  ao2_ref(default_cap, -1);
8723  ao2_ref(skinny_tech.capabilities, -1);
8724  ast_log(LOG_ERROR, "Unable to register channel class 'Skinny'\n");
8725  return AST_MODULE_LOAD_DECLINE;
8726  }
8727 
8728  ast_rtp_glue_register(&skinny_rtp_glue);
8729  ast_cli_register_multiple(cli_skinny, ARRAY_LEN(cli_skinny));
8730 
8735 
8736  if (ast_sched_start_thread(sched)) {
8738  sched = NULL;
8739  ast_channel_unregister(&skinny_tech);
8740  ao2_ref(default_cap, -1);
8741  ao2_ref(skinny_tech.capabilities, -1);
8742  return AST_MODULE_LOAD_DECLINE;
8743  }
8744 
8745  return AST_MODULE_LOAD_SUCCESS;
8746 }
8747 
8748 static int unload_module(void)
8749 {
8750  struct skinnysession *s;
8751  struct skinny_device *d;
8752  struct skinny_line *l;
8753  struct skinny_subchannel *sub;
8754  pthread_t tempthread;
8755 
8756  ast_rtp_glue_unregister(&skinny_rtp_glue);
8757  ast_channel_unregister(&skinny_tech);
8758  ao2_cleanup(skinny_tech.capabilities);
8759  ast_cli_unregister_multiple(cli_skinny, ARRAY_LEN(cli_skinny));
8760 
8761  ast_manager_unregister("SKINNYdevices");
8762  ast_manager_unregister("SKINNYshowdevice");
8763  ast_manager_unregister("SKINNYlines");
8764  ast_manager_unregister("SKINNYshowline");
8765 
8767  if (accept_t && (accept_t != AST_PTHREADT_STOP)) {
8768  pthread_cancel(accept_t);
8769  pthread_kill(accept_t, SIGURG);
8770  pthread_join(accept_t, NULL);
8771  }
8774 
8776  /* Destroy all the interfaces and free their memory */
8777  while((s = AST_LIST_REMOVE_HEAD(&sessions, list))) {
8778  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
8779 
8781  d = s->device;
8782  AST_LIST_TRAVERSE(&d->lines, l, list){
8783  ast_mutex_lock(&l->lock);
8784  AST_LIST_TRAVERSE(&l->sub, sub, list) {
8785  skinny_locksub(sub);
8786  if (sub->owner) {
8788  }
8789  skinny_unlocksub(sub);
8790  }
8791  if (l->mwi_event_sub) {
8793  }
8794  ast_mutex_unlock(&l->lock);
8795  unregister_exten(l);
8796  }
8798  blob = ast_json_pack("{s: s}", "peer_status", "Unregistered");
8800  tempthread = s->t;
8801  pthread_cancel(tempthread);
8802  pthread_join(tempthread, NULL);
8804  }
8806 
8807  delete_devices();
8808 
8809  close(skinnysock);
8810  if (sched) {
8812  }
8813 
8815 
8816  ao2_ref(default_cap, -1);
8817  return 0;
8818 }
8819 
8820 static int reload(void)
8821 {
8822  skinny_reload();
8823  return 0;
8824 }
8825 
8826 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Skinny Client Control Protocol (Skinny)",
8827  .support_level = AST_MODULE_SUPPORT_EXTENDED,
8828  .load = load_module,
8829  .unload = unload_module,
8830  .reload = reload,
8831  .load_pri = AST_MODPRI_CHANNEL_DRIVER,
8832 );
#define SKINNY_DEVICE_7931
Definition: chan_skinny.c:1260
static const uint8_t soft_key_default_connwithconf[]
Definition: chan_skinny.c:979
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
union skinny_data data
Definition: chan_skinny.c:1216
#define START_TONE_MESSAGE
Definition: chan_skinny.c:419
static void transmit_dialednumber(struct skinny_device *d, const char *text, int instance, int callid)
Definition: chan_skinny.c:2989
#define OCTAL_TRANSFER
Definition: chan_skinny.c:763
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
Definition: sched.c:195
static struct lines lines
struct ast_variable * next
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:84
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1150
static const char type[]
Definition: chan_ooh323.c:109
struct ast_format * ast_format_g726
Built-in cached g726 format.
Definition: format_cache.c:116
static void * get_button_template(struct skinnysession *s, struct button_definition_template *btn)
Definition: chan_skinny.c:1731
struct soft_key_template_res_message softkeytemplate
Definition: chan_skinny.c:1175
struct sockaddr_storage ss
Definition: netsock2.h:98
char displayMessage[80]
Definition: chan_skinny.c:371
Information needed to identify an endpoint in a call.
Definition: channel.h:339
enum sip_cc_notify_state state
Definition: chan_sip.c:959
Tone Indication Support.
void ast_channel_pickupgroup_set(struct ast_channel *chan, ast_group_t value)
#define SOFTKEY_TRNSFER
Definition: chan_skinny.c:713
int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
If an extension hint exists, return non-zero.
Definition: pbx.c:4141
char digit
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition: channel.c:7434
int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks to see if adding anything to this extension might match something. (exists ^ canmatch) ...
Definition: pbx.c:4199
#define SKINNY_HOLD
Definition: chan_skinny.c:1293
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define OCTAL_DND
Definition: chan_skinny.c:822
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
#define SKINNY_DEVICE_7960
Definition: chan_skinny.c:1249
static const uint8_t soft_key_default_SLAhold[]
Definition: chan_skinny.c:1004
struct display_prompt_status_message_variable displaypromptstatusvar
Definition: chan_skinny.c:1204
struct skinny_container * container
Definition: chan_skinny.c:1502
Music on hold handling.
static int skinny_call(struct ast_channel *ast, const char *dest, int timeout)
Definition: chan_skinny.c:4918
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
static enum ast_rtp_glue_result skinny_get_rtp_peer(struct ast_channel *c, struct ast_rtp_instance **instance)
Definition: chan_skinny.c:3607
ast_device_state
Device States.
Definition: devicestate.h:52
#define DEFAULT_AUTH_LIMIT
Definition: chan_skinny.c:190
#define DEBUG_PACKET
Definition: chan_skinny.c:150
struct ast_format * ast_format_g723
Built-in cached g723.1 format.
Definition: format_cache.c:151
static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: chan_skinny.c:3554
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
#define DIALTYPE_XFER
Definition: chan_skinny.c:1386
ast_mutex_t lock
Definition: chan_skinny.c:1582
static int reload(void)
Definition: chan_skinny.c:8820
uint32_t deviceStimulus
Definition: chan_skinny.c:446
static void transmit_capabilitiesreq(struct skinny_device *d)
Definition: chan_skinny.c:3363
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static char * complete_skinny_show_device(const char *line, const char *word, int pos, int state)
Definition: chan_skinny.c:3918
#define SKINNY_CX_RECVONLY
Definition: chan_skinny.c:1333
const char *const type
Definition: channel.h:630
static char * _skinny_show_device(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *const *argv)
Definition: chan_skinny.c:4192
static void transmit_cfwdstate(struct skinny_device *d, struct skinny_line *l)
Definition: chan_skinny.c:3103
Asterisk locking-related definitions:
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
#define SKINNY_DIALTONE
Definition: chan_skinny.c:1305
#define BUTTON_TEMPLATE_REQ_MESSAGE
Definition: chan_skinny.c:364
void * ast_mwi_unsubscribe(struct ast_mwi_subscriber *sub)
Unsubscribe from the stasis topic and MWI.
Definition: mwi.c:249
unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap)
Get the global framing.
Definition: format_cap.c:438
struct ast_ha * ha
Definition: chan_skinny.c:1585
#define OCTAL_GPICKUP
Definition: chan_skinny.c:777
#define TYPE_DEF_DEVICE
Definition: chan_skinny.c:7760
enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_transferee, struct ast_channel *to_transfer_target)
Attended transfer.
Definition: bridge.c:4729
struct button_template_res_message buttontemplate
Definition: chan_skinny.c:1163
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define SKINNY_RINGIN
Definition: chan_skinny.c:1289
static struct skinny_device * config_device(const char *dname, struct ast_variable *v)
Definition: chan_skinny.c:8350
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition: channel.c:1231
#define PACKET_TIMEOUT
Definition: chan_skinny.c:7518
struct register_ack_message regack
Definition: chan_skinny.c:1159
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
struct register_rej_message regrej
Definition: chan_skinny.c:1160
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
#define STOP_TONE_MESSAGE
Definition: chan_skinny.c:427
#define START_MEDIA_TRANSMISSION_MESSAGE
Definition: chan_skinny.c:460
int tm_usec
Definition: localtime.h:48
uint32_t alarmSeverity
Definition: chan_skinny.c:370
void ast_rtp_instance_set_channel_id(struct ast_rtp_instance *instance, const char *uniqueid)
Set the channel that owns this RTP instance.
Definition: rtp_engine.c:553
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
Definition: callerid.c:1092
#define SKINNY_SPEAKERON
Definition: chan_skinny.c:1280
static void * accept_thread(void *ignore)
Definition: chan_skinny.c:7657
#define SOFT_KEY_SET_RES_MESSAGE
Definition: chan_skinny.c:1040
#define OCTAL_CONNECTED
Definition: chan_skinny.c:783
char callingParty[24]
Definition: chan_skinny.c:502
#define SUBSTATE_RINGIN
Definition: chan_skinny.c:1375
#define SKINNY_DEVICE_7921
Definition: chan_skinny.c:1261
struct skinny_addon::@142 list
static int gendigittimeout
Definition: chan_skinny.c:1360
static int skinny_nokeepalive_cb(const void *data)
Definition: chan_skinny.c:7457
struct open_receive_channel_ack_message_ip4 openreceivechannelack_ip4
Definition: chan_skinny.c:1194
static void register_exten(struct skinny_line *l)
Definition: chan_skinny.c:2209
Channels have this property if they can accept input with jitter; i.e. most VoIP channels.
Definition: channel.h:961
struct keypad_button_message keypad
Definition: chan_skinny.c:1181
static int skinny_noauth_cb(const void *data)
Definition: chan_skinny.c:7448
#define LINE_STAT_RES_MESSAGE
Definition: chan_skinny.c:540
#define KEYMASK_FORCEDIAL
Definition: chan_skinny.c:754
static char * _skinny_show_lines(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *const *argv)
Definition: chan_skinny.c:4324
#define SOFTKEY_INFO
Definition: chan_skinny.c:721
void ast_rtp_instance_change_source(struct ast_rtp_instance *instance)
Indicate a new source of audio has dropped in and the ssrc should change.
Definition: rtp_engine.c:2160
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
static struct skinny_line * skinny_line_alloc(void)
Definition: chan_skinny.c:1674
struct serviceurl_stat_message serviceurlmessage
Definition: chan_skinny.c:1205
struct enbloc_call_message enbloccallmessage
Definition: chan_skinny.c:1200
char stname[AST_MAX_EXTENSION]
Definition: chan_skinny.c:1509
static void transmit_displaypromptstatusvar(struct skinny_device *d, const char *text, const char *extratext, int t, int instance, int callid)
Definition: chan_skinny.c:2936
Call Parking API.
static char ourhost[256]
Definition: chan_skinny.c:1232
ast_mutex_t lock
Definition: chan_skinny.c:1615
struct ast_party_id id
Connected party ID.
Definition: channel.h:459
#define CALL_INFO_MESSAGE_VARIABLE
Definition: chan_skinny.c:1127
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
void * ast_channel_tech_pvt(const struct ast_channel *chan)
struct skinny_subline::@139 list
struct skinny_device::@147 list
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
struct ast_endpoint * ast_endpoint_create(const char *tech, const char *resource)
Create an endpoint struct.
#define SKINNY_LAMP_BLINK
Definition: chan_skinny.c:1320
#define SOFTKEY_FORCEDIAL
Definition: chan_skinny.c:730
static struct ast_jb_conf default_jbconf
Definition: chan_skinny.c:254
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define SKINNY_CONGESTION
Definition: chan_skinny.c:1292
static struct skinny_line * find_line_by_instance(struct skinny_device *d, int instance)
Definition: chan_skinny.c:1882
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
static int auth_timeout
Definition: chan_skinny.c:202
uint8_t protocolVersion
Definition: chan_skinny.c:297
Device state management.
static void update(int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, struct g726_state *state_ptr)
Definition: codec_g726.c:367
#define STIMULUS_SPEEDDIAL
Definition: chan_skinny.c:574
#define KEEP_ALIVE_MESSAGE
Definition: chan_skinny.c:285
#define CLEAR_DISPLAY_MESSAGE
Definition: chan_skinny.c:634
struct skinnysession * session
Definition: chan_skinny.c:1586
const char * ast_var_value(const struct ast_var_t *var)
Definition: chanvars.c:80
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_party_name name
Subscriber name.
Definition: channel.h:341
static int skinny_sched_add(int when, ast_sched_cb callback, struct skinny_subchannel *sub)
Definition: chan_skinny.c:2029
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:570
#define SKINNY_DEVICE_12
Definition: chan_skinny.c:1246
struct ast_endpoint * endpoint
Definition: chan_skinny.c:1590
#define TYPE_DEF_LINE
Definition: chan_skinny.c:7761
static struct in_addr __ourip
Definition: chan_skinny.c:1234
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition: pbx.c:3858
char displayName[40]
Definition: chan_skinny.c:1539
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int handle_stimulus_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:6316
#define SUBSTATE_CALLWAIT
Definition: chan_skinny.c:1380
struct forward_stat_message forwardstat
Definition: chan_skinny.c:1201
#define SELECT_SOFT_KEYS_MESSAGE
Definition: chan_skinny.c:1055
int ast_queue_unhold(struct ast_channel *chan)
Queue an unhold frame.
Definition: channel.c:1216
#define CALLSTATE2STR_BUFSIZE
Definition: chan_skinny.c:279
struct ast_format_cap * confcap
Definition: chan_skinny.c:1477
Convenient Signal Processing routines.
#define OCTAL_IDIVERT
Definition: chan_skinny.c:839
#define STIMULUS_DISPLAY
Definition: chan_skinny.c:580
struct set_speaker_message setspeaker
Definition: chan_skinny.c:1187
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
char calldetails[MAXCALLINFOSTR]
Definition: chan_skinny.c:1137
#define DISPLAY_PRINOTIFY_MESSAGE_VARIABLE
Definition: chan_skinny.c:1140
struct ast_rtp_codecs * ast_rtp_instance_get_codecs(struct ast_rtp_instance *instance)
Get the codecs structure of an RTP instance.
Definition: rtp_engine.c:727
#define SOFTKEY_RESUME
Definition: chan_skinny.c:719
Call Pickup API.
static char * handle_skinny_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_skinny.c:4175
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3237
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
Definition: format_cache.c:86
static int codec_ast2skinny(const struct ast_format *astcodec)
Definition: chan_skinny.c:2129
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
#define OCTAL_CFWDBUSY
Definition: chan_skinny.c:765
#define DIALED_NUMBER_MESSAGE
Definition: chan_skinny.c:1097
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4712
static void destroy_session(struct skinnysession *s)
Definition: chan_skinny.c:7426
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
struct start_tone_message starttone
Definition: chan_skinny.c:1169
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:326
struct version_res_message version
Definition: chan_skinny.c:1162
static const char tdesc[]
Definition: chan_skinny.c:170
static char * skinny_debugs(void)
Definition: chan_skinny.c:3704
#define CONTROL2STR_BUFSIZE
Definition: chan_skinny.c:273
static struct test_val d
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1821
struct ast_rtp_instance * rtp
Definition: chan_skinny.c:1390
int ast_jb_read_conf(struct ast_jb_conf *conf, const char *varname, const char *value)
Sets jitterbuffer configuration property.
Definition: abstract_jb.c:545
uint32_t callreference
Definition: chan_skinny.c:321
#define CONFIG_STATUS_FILEINVALID
#define REGISTER_AVAILABLE_LINES_MESSAGE
Definition: chan_skinny.c:403
static void transmit_response(struct skinny_device *d, struct skinny_req *req)
Definition: chan_skinny.c:2418
#define DEBUG_THREAD
Definition: chan_skinny.c:154
#define SOFTKEY_DND
Definition: chan_skinny.c:728
static const uint8_t soft_key_default_ringin[]
Definition: chan_skinny.c:946
static int skinny_sched_del(int sched_id, struct skinny_subchannel *sub)
Definition: chan_skinny.c:2022
#define CDEV_OPTS
Definition: chan_skinny.c:7767
int keepalive_timeout_sched
Definition: chan_skinny.c:1624
#define SKINNY_DEVICE_7962
Definition: chan_skinny.c:1263
static void transmit_definetimedate(struct skinny_device *d)
Definition: chan_skinny.c:3190
uint32_t len
Definition: chan_skinny.c:1213
static int timeout
Definition: cdr_mysql.c:86
uint8_t instanceNumber
Definition: chan_skinny.c:563
static int tmp()
Definition: bt_open.c:389
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
#define SUBSTATE_OFFHOOK
Definition: chan_skinny.c:1372
enum ast_state_cb_update_reason reason
Definition: pbx.h:103
struct start_media_transmission_message_ip6 startmedia_ip6
Definition: chan_skinny.c:1191
#define SKINNY_DEVICE_SCCPGATEWAY_AN
Definition: chan_skinny.c:1277
#define CLINE_OPTS
Definition: chan_skinny.c:7765
uint32_t resetType
Definition: chan_skinny.c:659
Structure for variables, used for configurations and for channel variables.
int ast_rtp_instance_set_qos(struct ast_rtp_instance *instance, int tos, int cos, const char *desc)
Set QoS parameters on an RTP session.
Definition: rtp_engine.c:2169
static int handle_offhook_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:6546
struct skinny_device::@145 serviceurls
#define CLINE
Definition: chan_skinny.c:7766
static void transmit_registerrej(struct skinnysession *s)
Definition: chan_skinny.c:2423
#define SERVER_RES_MESSAGE
Definition: chan_skinny.c:646
int ast_rtp_instance_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
Send a frame out over RTP.
Definition: rtp_engine.c:568
char calledPartyName[40]
Definition: chan_skinny.c:503
#define SKINNY_ALERT
Definition: chan_skinny.c:1307
#define SOFTKEY_NEWCALL
Definition: chan_skinny.c:711
static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
Definition: chan_skinny.c:5123
struct register_message reg
Definition: chan_skinny.c:1158
static struct ast_threadstorage device2str_threadbuf
Definition: chan_skinny.c:269
#define ast_rtp_glue_register(glue)
Definition: rtp_engine.h:847
ast_mutex_t lock
Definition: chan_skinny.c:1522
struct skinny_line * line
Definition: chan_skinny.c:1416
static char * handle_skinny_message_clear(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Handle clearing messages to devices.
Definition: chan_skinny.c:4722
#define STIMULUS_LINE
Definition: chan_skinny.c:581
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
char serverName[48]
Definition: chan_skinny.c:648
static char date_format[6]
Definition: chan_skinny.c:209
struct soft_key_set_res_message softkeysets
Definition: chan_skinny.c:1174
#define SKINNY_CONNECTED
Definition: chan_skinny.c:1290
struct call_state_message callstate
Definition: chan_skinny.c:1180
struct close_receive_channel_message closereceivechannel
Definition: chan_skinny.c:1196
uint32_t stimulus
Definition: chan_skinny.c:319
#define BT_CALLPARK
Definition: chan_skinny.c:606
#define SKINNY_CFWD_BUSY
Definition: chan_skinny.c:1328
#define OCTAL_RINGOUT
Definition: chan_skinny.c:781
struct dialed_number_message dialednumber
Definition: chan_skinny.c:1198
char originalCalledParty[24]
Definition: chan_skinny.c:509
Definition: sched.c:76
static void activatesub(struct skinny_subchannel *sub, int state)
Definition: chan_skinny.c:6049
struct line_stat_res_message linestat
Definition: chan_skinny.c:1173
Definition: cli.h:152
char exten[AST_MAX_EXTENSION]
Definition: chan_skinny.c:1526
#define SKINNY_CALLWAITTONE
Definition: chan_skinny.c:1309
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:605
enum ast_acl_sense ast_apply_ha(const struct ast_ha *ha, const struct ast_sockaddr *addr)
Apply a set of rules to a given IP address.
Definition: acl.c:808
void ast_channel_callgroup_set(struct ast_channel *chan, ast_group_t value)
struct stop_media_transmission_message stopmedia
Definition: chan_skinny.c:1192
ast_channel_state
ast_channel states
Definition: channelstate.h:35
static const uint8_t soft_key_default_unknown[]
Definition: chan_skinny.c:1000
#define SOFTKEY_BKSPC
Definition: chan_skinny.c:717
char * str
Subscriber name (Malloced)
Definition: channel.h:265
static char * complete_skinny_debug(const char *line, const char *word, int pos, int state)
Definition: chan_skinny.c:3762
char outbuf[SKINNY_MAX_PACKET]
Definition: chan_skinny.c:1619
struct open_receive_channel_ack_message_ip6 openreceivechannelack_ip6
Definition: chan_skinny.c:1195
struct skinny_line::@136 sublines
Definition: astman.c:222
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4418
Scheduler ID holder.
Definition: sched.c:70
static struct skinny_subchannel * find_subchannel_by_instance_reference(struct skinny_device *d, int instance, int reference)
Definition: chan_skinny.c:2039
Definition of a media format.
Definition: format.c:43
#define OCTAL_PICKUP
Definition: chan_skinny.c:776
#define OCTAL_HOLD
Definition: chan_skinny.c:762
uint32_t stimulusInstance
Definition: chan_skinny.c:320
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define KEYDEF_CONNWITHCONF
Definition: chan_skinny.c:701
void ast_channel_named_pickupgroups_set(struct ast_channel *chan, struct ast_namedgroups *value)
static int transmit_response_bysession(struct skinnysession *s, struct skinny_req *req)
Definition: chan_skinny.c:2377
int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_type type)
Add all codecs Asterisk knows about for a specific type to the capabilities structure.
Definition: format_cap.c:216
static struct aco_type item
Definition: test_config.c:1463
struct ast_mwi_subscriber * mwi_event_sub
Definition: chan_skinny.c:1469
#define DEFAULT_AUTH_TIMEOUT
Definition: chan_skinny.c:189
uint32_t packets
Definition: chan_skinny.c:464
static char * control2str(int ind)
Definition: chan_skinny.c:5183
static int auth_limit
Definition: chan_skinny.c:203
#define KEYMASK_ALL
Definition: chan_skinny.c:732
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define SOFTKEY_HOLD
Definition: chan_skinny.c:712
size_t ast_format_cap_count(const struct ast_format_cap *cap)
Get the number of formats present within the capabilities structure.
Definition: format_cap.c:395
void ast_endpoint_set_state(struct ast_endpoint *endpoint, enum ast_endpoint_state state)
Updates the state of the given endpoint.
#define SKINNY_DEVICE_7920
Definition: chan_skinny.c:1270
static int skinny_senddigit_begin(struct ast_channel *ast, char digit)
Definition: chan_skinny.c:5135
uint32_t lastRedirectingReason
Definition: chan_skinny.c:513
#define OCTAL_ANSWER
Definition: chan_skinny.c:770
static void transmit_callinfo(struct skinny_device *d, int instance, int callid, char *fromname, char *fromnum, char *toname, char *tonum, int calldirection, char *origtonum, char *origtoname)
Definition: chan_skinny.c:2465
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
static struct ast_threadstorage callstate2str_threadbuf
Definition: chan_skinny.c:278
#define ast_mutex_lock(a)
Definition: lock.h:187
static void transmit_serviceurlstat(struct skinny_device *d, int instance)
Definition: chan_skinny.c:3389
struct station_capabilities caps[SKINNY_MAX_CAPABILITIES]
Definition: chan_skinny.c:350
static void * skinny_newcall(void *data)
Definition: chan_skinny.c:4823
static struct ast_threadstorage substate2str_threadbuf
Definition: chan_skinny.c:275
static struct test_val c
#define SKINNY_DEVICE_7975
Definition: chan_skinny.c:1268
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
Definition: channel.c:539
static char * handle_skinny_show_device(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Show device information.
Definition: chan_skinny.c:4308
char * text
Definition: app_queue.c:1508
#define ast_str_alloca(init_len)
Definition: strings.h:800
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2207
struct display_prompt_status_message displaypromptstatus
Definition: chan_skinny.c:1166
#define BT_FORWARDALL
Definition: chan_skinny.c:596
char exten[AST_MAX_EXTENSION]
Definition: chan_skinny.c:1508
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
struct activate_call_plane_message activatecallplane
Definition: chan_skinny.c:1183
static void transmit_reset(struct skinny_device *d, int fullrestart)
Definition: chan_skinny.c:3303
struct ast_format_cap * cap
Definition: chan_skinny.c:1588
void ast_rtp_codecs_set_framing(struct ast_rtp_codecs *codecs, unsigned int framing)
Set the framing used for a set of codecs.
Definition: rtp_engine.c:1558
#define htolel(x)
Definition: chan_skinny.c:222
struct skinny_device * device
Definition: chan_skinny.c:1475
struct varshead * ast_channel_varshead(struct ast_channel *chan)
static struct soft_key_template_definition soft_key_template_default[]
Definition: chan_skinny.c:888
SKINNY_LINE_OPTIONS ast_mutex_t lock
Definition: chan_skinny.c:1467
struct bksp_req_message bkspmessage
Definition: chan_skinny.c:1202
int ast_str2tos(const char *value, unsigned int *tos)
Convert a string to the appropriate TOS value.
Definition: acl.c:967
#define SKINNY_DEVICE_7937
Definition: chan_skinny.c:1264
#define SKINNY_LINE_OPTIONS
Definition: chan_skinny.c:1420
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
struct definetimedate_message definetimedate
Definition: chan_skinny.c:1168
static void end_session(struct skinnysession *s)
Definition: chan_skinny.c:2336
static int skinny_header_size
Definition: chan_skinny.c:1222
#define SKINNY_PROGRESS
Definition: chan_skinny.c:1297
static void start_rtp(struct skinny_subchannel *sub)
Definition: chan_skinny.c:4753
#define NULL
Definition: resample.c:96
const char * data
static struct ast_format * codec_skinny2ast(enum skinny_codecs skinnycodec)
Definition: chan_skinny.c:2105
#define SKINNY_DEVICE_OPTIONS
Definition: chan_skinny.c:1561
static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
Definition: chan_skinny.c:5297
I/O Management (derived from Cheops-NG)
static int config_load(void)
Definition: chan_skinny.c:8443
Definitions to aid in the use of thread local storage.
#define ALARM_MESSAGE
Definition: chan_skinny.c:368
struct ast_format * ast_format_g722
Built-in cached g722 format.
Definition: format_cache.c:111
#define DISPLAY_PROMPT_STATUS_MESSAGE_VARIABLE
Definition: chan_skinny.c:1147
#define OCTAL_RESUME
Definition: chan_skinny.c:769
struct set_microphone_message setmicrophone
Definition: chan_skinny.c:1188
#define UNREGISTER_MESSAGE
Definition: chan_skinny.c:400
Common implementation-independent jitterbuffer stuff.
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
struct soft_key_set_definition softKeySetDefinition[16]
Definition: chan_skinny.c:1051
ast_transfer_result
Definition: bridge.h:1115
static void push_callinfo(struct skinny_subline *subline, struct skinny_subchannel *sub)
Definition: chan_skinny.c:2603
#define LINE_STATE_REQ_MESSAGE
Definition: chan_skinny.c:358
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:855
#define BT_SPEEDDIAL
Definition: chan_skinny.c:593
static void transmit_displaynotify(struct skinny_device *d, const char *text, int t)
Definition: chan_skinny.c:2820
#define SKINNY_LAMP_FLASH
Definition: chan_skinny.c:1319
#define SKINNY_DEVICE_7905
Definition: chan_skinny.c:1269
#define KEYDEF_DADFD
Definition: chan_skinny.c:700
#define SOFTKEY_CFWDNOANSWER
Definition: chan_skinny.c:716
static int priority
const char * ext
Definition: http.c:147
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7876
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1771
#define TYPE_LINE
Definition: chan_skinny.c:7763
struct offhook_message offhook
Definition: chan_skinny.c:1185
Socket address structure.
Definition: netsock2.h:97
static int skinnydebug
Definition: chan_skinny.c:146
static int firstdigittimeout
Definition: chan_skinny.c:1357
int tm_year
Definition: localtime.h:41
struct skinny_device * device
Definition: chan_skinny.c:1541
char callingPartyName[40]
Definition: chan_skinny.c:501
struct speed_dial_stat_res_message speeddial
Definition: chan_skinny.c:1171
#define ast_verb(level,...)
Definition: logger.h:463
static void transmit_startmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub, struct sockaddr_in dest, struct ast_format *format, unsigned int framing)
Definition: chan_skinny.c:3035
char context[AST_MAX_CONTEXT]
Definition: chan_skinny.c:1507
#define OCTAL_MEETME
Definition: chan_skinny.c:775
struct ast_format * ast_format_none
Built-in "null" format.
Definition: format_cache.c:251
const char * type
Definition: rtp_engine.h:722
unsigned int callid
Definition: chan_skinny.c:1392
static void cleanup_stale_contexts(char *new, char *old)
Definition: chan_skinny.c:2187
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
static int skinnyreload
Definition: chan_skinny.c:1228
const char * line
Definition: cli.h:162
struct skinny_line::@135 sub
struct skinny_serviceurl::@141 list
uint32_t secondaryKeepAlive
Definition: chan_skinny.c:415
#define BT_HOLD
Definition: chan_skinny.c:594
#define SOFTKEY_GPICKUP
Definition: chan_skinny.c:727
uint32_t reference
Definition: chan_skinny.c:506
#define SOFTKEY_PICKUP
Definition: chan_skinny.c:726
static int skinny_devicestate(const char *data)
Definition: chan_skinny.c:7705
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
static char * handle_skinny_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_skinny.c:3964
static char * _skinny_show_line(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *const *argv)
Definition: chan_skinny.c:4443
struct ast_frame_subclass subclass
uint32_t alarmParam2
Definition: chan_skinny.c:373
#define OCTAL_CONFRN
Definition: chan_skinny.c:772
#define SUBSTATE_DIALING
Definition: chan_skinny.c:1382
#define SOFTKEY_CFWDBUSY
Definition: chan_skinny.c:715
static char * complete_skinny_devices(const char *word, int state)
Definition: chan_skinny.c:3904
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
Simply remove extension from context.
Definition: pbx.c:4952
char dbgcli_buf[256]
Definition: chan_skinny.c:147
static void _transmit_displayprinotifyvar(struct skinny_device *d, const char *text, const char *extratext, int timeout, int priority)
Definition: chan_skinny.c:2872
Utility functions.
#define SOFTKEY_NONE
Definition: chan_skinny.c:709
char * ast_print_group(char *buf, int buflen, ast_group_t group)
Print call and pickup groups into buffer.
Definition: channel.c:8133
int args
This gets set in ast_cli_register()
Definition: cli.h:185
struct ast_format * ast_format_h261
Built-in cached h261 format.
Definition: format_cache.c:166
static void transmit_stopmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub)
Definition: chan_skinny.c:3020
uint32_t instance
Definition: chan_skinny.c:326
int ast_context_destroy_by_name(const char *context, const char *registrar)
Destroy a context by name.
Definition: pbx.c:8244
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
struct skinny_device * device
Definition: chan_skinny.c:1620
#define SKINNY_DEVICE_SCCPGATEWAY_BRI
Definition: chan_skinny.c:1278
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define ast_strlen_zero(foo)
Definition: strings.h:52
static int handle_button_template_req_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:6703
static int skinny_cfwd_cb(const void *data)
Definition: chan_skinny.c:4907
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
char context[AST_MAX_CONTEXT]
Definition: chan_skinny.c:1525
struct soft_key_template_definition softKeyTemplateDefinition[32]
Definition: chan_skinny.c:1037
static char * callstate2str(int ind)
Definition: chan_skinny.c:2342
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
Definition: main/cli.c:1811
enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap, const struct ast_format *format)
Find if ast_format is within the capabilities of the ast_format_cap object.
Definition: format_cap.c:583
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:567
int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
Parse an "allow" or "deny" list and modify a format capabilities structure accordingly.
Definition: format_cap.c:320
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
#define OCTAL_ENTRNUM
Definition: chan_skinny.c:791
#define HEADSET_STATUS_MESSAGE
Definition: chan_skinny.c:402
static void transmit_keepaliveack(struct skinnysession *s)
Definition: chan_skinny.c:3320
Number structure.
Definition: app_followme.c:154
static void skinny_locksub(struct skinny_subchannel *sub)
Definition: chan_skinny.c:2008
uint32_t reference
Definition: chan_skinny.c:430
static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
Definition: chan_skinny.c:5091
enum ama_flags ast_channel_string2amaflag(const char *flag)
Convert a string to a detail record AMA flag.
Definition: channel.c:4405
long resync_threshold
Resynchronization threshold of the jitterbuffer implementation.
Definition: abstract_jb.h:76
char calledParty[24]
Definition: chan_skinny.c:504
internal representation of ACL entries In principle user applications would have no need for this...
Definition: acl.h:51
static const uint8_t soft_key_default_SLAconnectednotactive[]
Definition: chan_skinny.c:1010
static int handle_enbloc_call_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:6942
static struct skinny_line * skinny_line_destroy(struct skinny_line *l)
Definition: chan_skinny.c:1691
#define KEYDEF_ONHOLD
Definition: chan_skinny.c:696
static void dumpsub(struct skinny_subchannel *sub, int forcehangup)
Definition: chan_skinny.c:5997
uint32_t serverIpAddr[5]
Definition: chan_skinny.c:654
#define MAXDISPLAYNOTIFYSTR
Definition: chan_skinny.c:1113
#define SKINNY_LINECONTAINER
Definition: chan_skinny.c:1545
#define BUTTON_TEMPLATE_RES_MESSAGE
Definition: chan_skinny.c:561
struct skinny_line * activeline
Definition: chan_skinny.c:1587
Configuration File Parser.
enum ast_extension_states exten_state
Definition: pbx.h:104
static int matchdigittimeout
Definition: chan_skinny.c:1363
#define SKINNY_DEVICE_7971
Definition: chan_skinny.c:1254
static char used_context[AST_MAX_EXTENSION]
Definition: chan_skinny.c:207
static struct ast_channel * skinny_new(struct skinny_line *l, struct skinny_subline *subline, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, int direction)
Definition: chan_skinny.c:5371
#define BT_CUST_LINE
Definition: chan_skinny.c:614
#define STIMULUS_FORWARDALL
Definition: chan_skinny.c:577
struct skinny_subchannel * sub
Definition: chan_skinny.c:1504
#define EVENT_FLAG_SYSTEM
Definition: manager.h:71
static char * complete_skinny_reset(const char *line, const char *word, int pos, int state)
Definition: chan_skinny.c:3923
struct skinny_container * container
Definition: chan_skinny.c:1468
uint32_t instance
Definition: chan_skinny.c:332
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
ast_mutex_t lock
Definition: chan_skinny.c:1555
static struct skinny_device_options * default_device
Definition: chan_skinny.c:1609
struct skinny_subchannel * activesub
Definition: chan_skinny.c:1470
#define DEBUG_AUDIO
Definition: chan_skinny.c:151
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
struct sockaddr_in sin
Definition: chan_skinny.c:1617
struct skinny_line * line
Definition: chan_skinny.c:1503
static void send_displaypromptstatus(struct skinny_device *d, const char *text, const char *extratext, int t, int instance, int callid)
Definition: chan_skinny.c:2965
#define REGISTER_REJ_MESSAGE
Definition: chan_skinny.c:641
struct timeval start
Definition: chan_skinny.c:1616
static void skinny_dialer(struct skinny_subchannel *sub, int timedout)
Definition: chan_skinny.c:4858
#define OCTAL_CFWDALL
Definition: chan_skinny.c:764
void ast_rtp_instance_stop(struct ast_rtp_instance *instance)
Stop an RTP instance.
Definition: rtp_engine.c:2183
#define KEEP_ALIVE_ACK_MESSAGE
Definition: chan_skinny.c:662
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: extconf.c:4174
#define ast_config_load(filename, flags)
Load a config file.
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
static struct @132 qos
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:510
char originalCalledPartyName[40]
Definition: chan_skinny.c:508
static struct skinny_line_options default_line_struct
struct ast_module * self
Definition: module.h:342
struct ast_rtp_instance * vrtp
Definition: chan_skinny.c:1391
enum ast_transfer_result ast_bridge_transfer_blind(int is_external, struct ast_channel *transferer, const char *exten, const char *context, transfer_channel_cb new_channel_cb, void *user_data)
Blind transfer target to the extension and context provided.
Definition: bridge.c:4477
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition: callerid.c:1073
static struct skinny_line_options * default_line
Definition: chan_skinny.c:1497
uint32_t maxStreams
Definition: chan_skinny.c:295
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:428
#define SUBSTATE2STR_BUFSIZE
Definition: chan_skinny.c:276
#define SERVICEURL_STATREQ_MESSAGE
Definition: chan_skinny.c:405
#define BT_CONFERENCE
Definition: chan_skinny.c:605
SKINNY_DEVICE_OPTIONS struct type * first
Definition: chan_skinny.c:1580
static int skinny_reload(void)
Definition: chan_skinny.c:8594
static char * handle_skinny_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_skinny.c:3883
General Asterisk PBX channel definitions.
static char * substate2str(int ind)
Definition: chan_skinny.c:5524
static struct ast_rtp_glue skinny_rtp_glue
Definition: chan_skinny.c:3696
#define SKINNY_DEVICE_7961GE
Definition: chan_skinny.c:1258
unsigned int callid
Definition: chan_skinny.c:1518
void ast_channel_rings_set(struct ast_channel *chan, int value)
#define STIMULUS_VOICEMAIL
Definition: chan_skinny.c:582
#define SET_MICROPHONE_MESSAGE
Definition: chan_skinny.c:455
const char * src
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
#define ast_sockaddr_from_sin(addr, sin)
Converts a struct sockaddr_in to a struct ast_sockaddr.
Definition: netsock2.h:782
#define SKINNY_LAMP_ON
Definition: chan_skinny.c:1317
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5849
#define OCTAL_CALLWAITING
Definition: chan_skinny.c:786
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
static int ourport
Definition: chan_skinny.c:1233
int auth_timeout_sched
Definition: chan_skinny.c:1623
#define DEBUG_SUB
Definition: chan_skinny.c:149
const int fd
Definition: cli.h:159
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
uint32_t precedence
Definition: chan_skinny.c:462
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
#define SKINNY_INCOMING
Definition: chan_skinny.c:1301
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
#define AST_PTHREADT_NULL
Definition: lock.h:66
static struct skinny_device * skinny_device_alloc(const char *dname)
Definition: chan_skinny.c:1701
#define letohl(x)
Definition: chan_skinny.c:220
const int n
Definition: cli.h:165
static void transmit_clear_display_message(struct skinny_device *d, int instance, int reference)
Definition: chan_skinny.c:2787
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
struct ast_variable * chanvars
Definition: chan_skinny.c:1478
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition: causes.h:113
Access Control of various sorts.
static struct ao2_container * codecs
Registered codecs.
Definition: codec.c:48
#define OPEN_RECEIVE_CHANNEL_MESSAGE
Definition: chan_skinny.c:664
#define htoles(x)
Definition: chan_skinny.c:223
static char * _skinny_message_set(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *const *argv)
Definition: chan_skinny.c:4652
static struct ast_frame * skinny_read(struct ast_channel *ast)
Definition: chan_skinny.c:5081
#define AST_MAX_EXTENSION
Definition: channel.h:135
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
Scheduler Routines (derived from cheops)
static void setsubstate(struct skinny_subchannel *sub, int state)
Definition: chan_skinny.c:5560
static void config_parse_variables(int type, void *item, struct ast_variable *vptr)
Definition: chan_skinny.c:7770
#define SKINNY_DEVICE_7911
Definition: chan_skinny.c:1257
uint32_t callreference
Definition: chan_skinny.c:691
static void skinny_transfer_attended(struct skinny_subchannel *sub)
Definition: chan_skinny.c:5249
static void transmit_selectsoftkeys(struct skinny_device *d, int instance, int callid, int softkey, int mask)
Definition: chan_skinny.c:2727
static int skinny_hangup(struct ast_channel *ast)
Definition: chan_skinny.c:4987
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition: channel.c:1644
#define BT_NONE
Definition: chan_skinny.c:608
int tm_mon
Definition: localtime.h:40
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#define KEYDEF_SLAHOLD
Definition: chan_skinny.c:705
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
static void update_connectedline(struct skinny_subchannel *sub, const void *data, size_t datalen)
Definition: chan_skinny.c:3525
const char * ast_extension_state2str(int extension_state)
Return string representation of the state of an extension.
Definition: pbx.c:3126
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2476
struct call_info_message callinfo
Definition: chan_skinny.c:1189
#define DEFAULT_SKINNY_PORT
Definition: chan_skinny.c:186
struct in_addr ourip
Definition: chan_skinny.c:1584
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
In case you didn&#39;t read that giant block of text above the mansession_session struct, the struct mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1625
static char * handle_skinny_show_line(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
List line information.
Definition: chan_skinny.c:4594
static char * device2str(int type)
Definition: chan_skinny.c:3999
struct display_prinotify_message displayprinotify
Definition: chan_skinny.c:1207
#define CLOSE_RECEIVE_CHANNEL_MESSAGE
Definition: chan_skinny.c:675
static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
Definition: chan_skinny.c:5140
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define VERSION_REQ_MESSAGE
Definition: chan_skinny.c:365
#define TYPE_GENERAL
Definition: chan_skinny.c:7759
struct line_state_req_message line
Definition: chan_skinny.c:1172
long target_extra
amount of additional jitterbuffer adjustment
Definition: abstract_jb.h:80
#define SKINNY_DEVICE_30SPPLUS
Definition: chan_skinny.c:1243
struct skinny_device::@144 speeddials
static const uint8_t soft_key_default_onhold[]
Definition: chan_skinny.c:939
#define DEBUG_TEMPLATE
Definition: chan_skinny.c:153
struct skinny_line::@138 all
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
static void transmit_softkeysetres(struct skinny_device *d)
Definition: chan_skinny.c:3244
void ast_channel_amaflags_set(struct ast_channel *chan, enum ama_flags value)
#define SUBSTATE_CONNECTED
Definition: chan_skinny.c:1376
A set of macros to manage forward-linked lists.
static void transmit_linestatres(struct skinny_device *d, int instance)
Definition: chan_skinny.c:3166
struct ao2_container * container
Definition: res_fax.c:502
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5890
#define SKINNY_RING_OFF
Definition: chan_skinny.c:1322
static const uint8_t soft_key_default_ringout[]
Definition: chan_skinny.c:983
static char immed_dialchar
Definition: chan_skinny.c:205
#define ast_variable_new(name, value, filename)
ast_group_t ast_get_group(const char *s)
Definition: channel.c:7718
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
int tm_mday
Definition: localtime.h:39
static int handle_open_receive_channel_ack_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:6865
struct alarm_message alarm
Definition: chan_skinny.c:1156
#define STIMULUS_REDIAL
Definition: chan_skinny.c:573
#define SUBSTATE_CONGESTION
Definition: chan_skinny.c:1378
#define SOFT_KEY_EVENT_MESSAGE
Definition: chan_skinny.c:393
static const char config[]
Definition: chan_skinny.c:171
#define STIMULUS_DND
Definition: chan_skinny.c:585
#define CLEAR_PROMPT_MESSAGE
Definition: chan_skinny.c:1080
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4179
ast_rtp_glue_result
Definition: rtp_engine.h:158
#define DEFINETIMEDATE_MESSAGE
Definition: chan_skinny.c:548
#define SKINNY_CALLWAIT
Definition: chan_skinny.c:1294
#define OCTAL_FROM
Definition: chan_skinny.c:782
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
static struct skinny_subline * find_subline_by_callid(struct skinny_device *d, int callid)
Definition: chan_skinny.c:1975
#define SKINNY_ZIP
Definition: chan_skinny.c:1311
int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
Queue a hold frame.
Definition: channel.c:1191
static char regcontext[AST_MAX_CONTEXT]
Definition: chan_skinny.c:208
#define ENBLOC_CALL_MESSAGE
Definition: chan_skinny.c:312
#define SKINNY_CFWD_NOANSWER
Definition: chan_skinny.c:1329
char impl[AST_JB_IMPL_NAME_SIZE]
Name of the jitterbuffer implementation to be used.
Definition: abstract_jb.h:78
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:629
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
const char * ast_channel_exten(const struct ast_channel *chan)
Network socket handling.
Core PBX routines and definitions.
struct ast_format_cap * confcap
Definition: chan_skinny.c:1589
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel&#39;s frame queue.
Definition: channel.c:1139
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition: channel.c:1691
void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type)
Remove all formats matching a specific format type.
Definition: format_cap.c:525
#define SOFTKEY_CFWDALL
Definition: chan_skinny.c:714
char text[MAXDISPLAYNOTIFYSTR]
Definition: chan_skinny.c:1119
unsigned int cos_audio
Definition: chan_skinny.c:197
static int manager_skinny_show_device(struct mansession *s, const struct message *m)
Definition: chan_skinny.c:4287
static void transmit_start_tone(struct skinny_device *d, int tone, int instance, int reference)
Definition: chan_skinny.c:2678
#define SERVER_REQUEST_MESSAGE
Definition: chan_skinny.c:366
#define SOFTKEY_PARK
Definition: chan_skinny.c:723
struct type * last
Definition: chan_skinny.c:1581
struct ast_channel * owner
Definition: chan_skinny.c:1389
static struct skinny_line * config_line(const char *lname, struct ast_variable *v)
Definition: chan_skinny.c:8285
#define SKINNY_REORDER
Definition: chan_skinny.c:1308
#define SKINNY_CALLREMOTEMULTILINE
Definition: chan_skinny.c:1298
struct ast_format_cap * cap
Definition: chan_skinny.c:1476
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:290
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:236
static struct ast_hostent ahp
Definition: chan_skinny.c:1235
int ast_channel_fdno(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
static int handle_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:7285
const char *const * argv
Definition: cli.h:161
#define SKINNY_DEBUG(type, verb_level, text,...)
Definition: chan_skinny.c:157
#define DEFAULT_SKINNY_BACKLOG
Definition: chan_skinny.c:187
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7258
struct skinny_speeddial::@140 list
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
uint32_t reference
Definition: chan_skinny.c:327
#define BKSP_REQ_MESSAGE
Definition: chan_skinny.c:688
uint32_t stimulus
Definition: chan_skinny.c:444
static int skinny_answer(struct ast_channel *ast)
Definition: chan_skinny.c:5010
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
static int manager_skinny_show_lines(struct mansession *s, const struct message *m)
Show Skinny lines in the manager API.
Definition: chan_skinny.c:4401
#define SET_RINGER_MESSAGE
Definition: chan_skinny.c:434
#define BT_SERVICEURL
Definition: chan_skinny.c:603
static enum ast_rtp_glue_result skinny_get_vrtp_peer(struct ast_channel *c, struct ast_rtp_instance **instance)
Definition: chan_skinny.c:3594
static int manager_skinny_show_line(struct mansession *s, const struct message *m)
Definition: chan_skinny.c:4573
#define BT_TRANSFER
Definition: chan_skinny.c:595
static pthread_t accept_t
Definition: chan_skinny.c:1238
uint32_t e
Definition: chan_skinny.c:1215
struct ast_namedgroups * ast_get_namedgroups(const char *s)
Create an ast_namedgroups set with group names from comma separated string.
Definition: channel.c:7775
#define OCTAL_NEWCALL
Definition: chan_skinny.c:761
static int load_module(void)
Load the module.
Definition: chan_skinny.c:8685
static int skinny_extensionstate_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: chan_skinny.c:3414
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define DIALTYPE_NORMAL
Definition: chan_skinny.c:1384
int ast_pickup_call(struct ast_channel *chan)
Pickup a call.
Definition: pickup.c:200
static struct skinny_line * find_line_by_name(const char *dest)
Definition: chan_skinny.c:1903
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
#define KEYDEF_UNKNOWN
Definition: chan_skinny.c:704
char url[MAX_SERVICEURL]
Definition: chan_skinny.c:1538
static int handle_transfer_button(struct skinny_subchannel *sub)
Definition: chan_skinny.c:6109
unsigned int tos
Definition: chan_skinny.c:193
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
static struct ast_threadstorage control2str_threadbuf
Definition: chan_skinny.c:272
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
#define DEBUG_GENERAL
Definition: chan_skinny.c:148
#define KEYPAD_BUTTON_MESSAGE
Definition: chan_skinny.c:304
#define ACTIVATE_CALL_PLANE_MESSAGE
Definition: chan_skinny.c:1092
struct ast_party_id ast_channel_connected_effective_id(struct ast_channel *chan)
static void skinny_session_cleanup(void *data)
Definition: chan_skinny.c:7466
static int manager_skinny_show_devices(struct mansession *s, const struct message *m)
Show SKINNY devices in the manager API.
Definition: chan_skinny.c:4159
#define CLI_SHOWUSAGE
Definition: cli.h:45
static const uint8_t soft_key_default_ringoutwithtransfer[]
Definition: chan_skinny.c:988
#define SKINNY_SPEAKEROFF
Definition: chan_skinny.c:1281
#define SKINNY_OFFHOOK
Definition: chan_skinny.c:1286
#define SOFTKEY_ENDCALL
Definition: chan_skinny.c:718
#define DISPLAY_PRINOTIFY_MESSAGE
Definition: chan_skinny.c:1115
void ast_channel_named_callgroups_set(struct ast_channel *chan, struct ast_namedgroups *value)
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
static struct ast_channel_tech skinny_tech
Definition: chan_skinny.c:1655
char url[MAX_SERVICEURL]
Definition: chan_skinny.c:1108
struct open_receive_channel_message openreceivechannel
Definition: chan_skinny.c:1193
static const uint8_t soft_key_default_connected[]
Definition: chan_skinny.c:929
struct stimulus_message stimulus
Definition: chan_skinny.c:1184
static int handle_soft_key_event_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:6974
int ast_set_qos(int sockfd, int tos, int cos, const char *desc)
Set type of service.
Definition: netsock2.c:621
static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, const struct ast_format_cap *codecs, int nat_active)
Definition: chan_skinny.c:3641
static int not_used
Definition: chan_skinny.c:1369
static ast_mutex_t netlock
Definition: chan_skinny.c:1354
static int keyset_translatebitmask(int keyset, int intmask)
Definition: chan_skinny.c:2705
#define SKINNY_DEVICE_7941GE
Definition: chan_skinny.c:1259
uint32_t bitRate
Definition: chan_skinny.c:465
void ast_party_name_init(struct ast_party_name *init)
Initialize the given name structure.
Definition: channel.c:1591
#define SKINNY_ONHOOK
Definition: chan_skinny.c:1287
#define SUBSTATE_RINGOUT
Definition: chan_skinny.c:1374
#define ast_rtp_instance_set_remote_address(instance, address)
Set the address of the remote endpoint that we are sending RTP to.
Definition: rtp_engine.h:1080
static const uint8_t soft_key_default_dadfd[]
Definition: chan_skinny.c:972
def info(msg)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct stasis_message_type * ast_endpoint_state_type(void)
Message type for endpoint state changes.
int errno
struct media_qualifier qualifier
Definition: chan_skinny.c:487
struct skinny_device::@143 lines
struct skinny_device::@146 addons
struct set_lamp_message setlamp
Definition: chan_skinny.c:1178
#define CLEAR_PRINOTIFY_MESSAGE
Definition: chan_skinny.c:1122
#define KEYDEF_SLACONNECTEDNOTACTIVE
Definition: chan_skinny.c:706
static int unauth_sessions
Definition: chan_skinny.c:204
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2283
static struct ast_frame * skinny_rtp_read(struct skinny_subchannel *sub)
Definition: chan_skinny.c:5026
def ignore(key=None, val=None, section=None, pjsip=None, nmapped=None, type='endpoint')
Definition: sip_to_pjsip.py:48
#define SKINNY_DEVICE_NONE
Definition: chan_skinny.c:1242
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7866
static char * handle_skinny_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
List global settings for the Skinny subsystem.
Definition: chan_skinny.c:4611
#define SKINNY_DEVICE_12SP
Definition: chan_skinny.c:1245
void ast_party_name_free(struct ast_party_name *doomed)
Destroy the party name contents.
Definition: channel.c:1638
struct select_soft_keys_message selectsoftkey
Definition: chan_skinny.c:1182
#define SKINNY_DEVICE_7985
Definition: chan_skinny.c:1256
static void handle_keepalive_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:6198
#define SKINNY_CFWD_ALL
Definition: chan_skinny.c:1327
static void transmit_clearprinotify(struct skinny_device *d, int priority)
Definition: chan_skinny.c:2834
static void send_callinfo(struct skinny_subchannel *sub)
Definition: chan_skinny.c:2556
int ast_get_ip(struct ast_sockaddr *addr, const char *hostname)
Get the IP address given a hostname.
Definition: acl.c:1000
static char * handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_skinny.c:3792
struct speed_dial_stat_req_message speeddialreq
Definition: chan_skinny.c:1157
#define SOFTKEY_CONFRN
Definition: chan_skinny.c:722
unsigned int ast_format_cap_get_format_framing(const struct ast_format_cap *cap, const struct ast_format *format)
Get the framing for a format.
Definition: format_cap.c:443
#define LOG_NOTICE
Definition: logger.h:263
static int skinny_autoanswer_cb(const void *data)
Definition: chan_skinny.c:4897
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition: format_cap.c:736
#define IP_PORT_MESSAGE
Definition: chan_skinny.c:302
#define SUBSTATE_PROGRESS
Definition: chan_skinny.c:1381
#define DEBUG_HINT
Definition: chan_skinny.c:155
#define DEBUG_KEEPALIVE
Definition: chan_skinny.c:156
#define KEYDEF_CONNECTED
Definition: chan_skinny.c:695
struct ast_format_cap * capabilities
Definition: channel.h:633
uint32_t serverListenPort[5]
Definition: chan_skinny.c:653
#define KEYDEF_ONHOOK
Definition: chan_skinny.c:694
#define SKINNY_LAMP_OFF
Definition: chan_skinny.c:1316
static const struct soft_key_definitions soft_key_default_definitions[]
Definition: chan_skinny.c:1016
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
#define KEYDEF_OFFHOOK
Definition: chan_skinny.c:698
struct skinny_subline * subline
Definition: chan_skinny.c:1417
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
int ast_parking_provider_registered(void)
Check whether a parking provider is registered.
Definition: parking.c:241
static int cleardisplay(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
Definition: app_adsiprog.c:750
#define ast_channel_unlock(chan)
Definition: channel.h:2946
struct skinny_line::@137 list
static char version[AST_MAX_EXTENSION]
Definition: chan_ooh323.c:391
int tm_wday
Definition: localtime.h:42
#define SET_SPEAKER_MESSAGE
Definition: chan_skinny.c:449
static void transmit_connect(struct skinny_device *d, struct skinny_subchannel *sub)
Definition: chan_skinny.c:2650
#define SKINNY_DEVICE_7970
Definition: chan_skinny.c:1271
#define AST_MAX_CONTEXT
Definition: channel.h:136
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
Definition: main/utils.c:782
static const char name[]
Definition: cdr_mysql.c:74
#define BT_REDIAL
Definition: chan_skinny.c:592
#define CALL_STATE_MESSAGE
Definition: chan_skinny.c:1063
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
static void transmit_activatecallplane(struct skinny_device *d, struct skinny_line *l)
Definition: chan_skinny.c:3073
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define ast_pthread_create(a, b, c, d)
Definition: utils.h:559
static int handle_capabilities_res_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:6660
#define SKINNY_MAX_CAPABILITIES
Definition: chan_skinny.c:346
struct ast_var_t::@249 entries
#define STIMULUS_HOLD
Definition: chan_skinny.c:575
static struct ast_cli_entry cli_skinny[]
Definition: chan_skinny.c:4738
static void transmit_displaypromptstatus(struct skinny_device *d, const char *text, const char *extratext, int t, int instance, int callid)
Definition: chan_skinny.c:2911
#define SKINNY_DEVICE_7912
Definition: chan_skinny.c:1272
#define KEYDEF_RINGOUT
Definition: chan_skinny.c:702
static struct skinny_subchannel * find_subchannel_by_reference(struct skinny_device *d, int reference)
Definition: chan_skinny.c:2066
#define CDEV
Definition: chan_skinny.c:7768
#define TIME_DATE_REQ_MESSAGE
Definition: chan_skinny.c:363
#define SUBSTATE_HOLD
Definition: chan_skinny.c:1379
static void transmit_serverres(struct skinny_device *d)
Definition: chan_skinny.c:3228
#define SKINNY_DEVICE_7935
Definition: chan_skinny.c:1251
#define SPEED_DIAL_STAT_REQ_MESSAGE
Definition: chan_skinny.c:353
#define SKINNY_BUSYTONE
Definition: chan_skinny.c:1306
char exten[AST_MAX_EXTENSION]
Definition: chan_skinny.c:1393
#define STIMULUS_TRANSFER
Definition: chan_skinny.c:576
int ast_str2cos(const char *value, unsigned int *cos)
Convert a string to the appropriate COS value.
Definition: acl.c:953
struct skinny_device * parent
Definition: chan_skinny.c:1533
void * ast_mwi_unsubscribe_and_join(struct ast_mwi_subscriber *sub)
Unsubscribe from the stasis topic, block until the final message is received, and then unsubscribe fr...
Definition: mwi.c:254
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
struct skinny_device * parent
Definition: chan_skinny.c:1558
static struct ast_threadstorage message2str_threadbuf
Definition: chan_skinny.c:265
#define SKINNY_DEVICE_UNKNOWN
Definition: chan_skinny.c:1241
static struct skinny_device_options default_device_struct
int ast_rtp_instance_fd(struct ast_rtp_instance *instance, int rtcp)
Get the file descriptor for an RTP session (or RTCP)
Definition: rtp_engine.c:2192
const char * word
Definition: cli.h:163
#define OCTAL_REDIAL
Definition: chan_skinny.c:760
#define SUBSTATE_ONHOOK
Definition: chan_skinny.c:1373
struct stasis_message_type * ast_mwi_state_type(void)
Get the Stasis Message Bus API message type for MWI messages.
int ast_sched_del(struct ast_sched_context *con, int id) attribute_warn_unused_result
Deletes a scheduled event.
Definition: sched.c:610
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static char * _skinny_message_clear(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *const *argv)
Definition: chan_skinny.c:4702
int alarm
Definition: chan_dahdi.c:4360
unsigned int flags
Combination of the AST_JB_ENABLED, AST_JB_FORCED and AST_JB_LOG flags.
Definition: abstract_jb.h:72
#define SKINNY_BUSY
Definition: chan_skinny.c:1291
struct clear_prompt_message clearpromptstatus
Definition: chan_skinny.c:1167
int tm_hour
Definition: localtime.h:38
#define SKINNY_DEVICE_12SPPLUS
Definition: chan_skinny.c:1244
#define OCTAL_INFO
Definition: chan_skinny.c:771
struct clear_prinotify_message clearprinotify
Definition: chan_skinny.c:1206
static struct ast_format_cap * default_cap
Definition: chan_skinny.c:173
#define SKINNY_DEVICE_CIPC
Definition: chan_skinny.c:1274
#define BT_VOICEMAIL
Definition: chan_skinny.c:601
int(* ast_sched_cb)(const void *data)
scheduler callback
Definition: sched.h:175
#define OFFHOOK_MESSAGE
Definition: chan_skinny.c:324
uint32_t originalCalledPartyRedirectReason
Definition: chan_skinny.c:512
#define FORWARD_STAT_MESSAGE
Definition: chan_skinny.c:521
#define SKINNY_DEVICE_7961
Definition: chan_skinny.c:1275
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
Definition: sched.c:565
static void transmit_lamp_indication(struct skinny_device *d, int stimulus, int instance, int indication)
Definition: chan_skinny.c:2746
void ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address)
Get the local address that we are expecting RTP on.
Definition: rtp_engine.c:643
Structure used to handle boolean flags.
Definition: utils.h:199
static struct skinny_speeddial * find_speeddial_by_instance(struct skinny_device *d, int instance, int isHint)
Definition: chan_skinny.c:2090
static int get_devicestate(struct skinny_line *l)
Definition: chan_skinny.c:5154
int ast_rtp_instance_destroy(struct ast_rtp_instance *instance)
Destroy an RTP instance.
Definition: rtp_engine.c:458
int ast_app_has_voicemail(const char *mailboxes, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX". If folder is "INBOX", includes the number of messages in the "Urgent" folder.
Definition: main/app.c:655
#define SOFTKEY_MEETME
Definition: chan_skinny.c:725
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2431
static void skinny_unlocksub(struct skinny_subchannel *sub)
Definition: chan_skinny.c:2015
#define SKINNY_MICOFF
Definition: chan_skinny.c:1284
#define SKINNY_DEVICE_7965
Definition: chan_skinny.c:1267
struct ast_bridge_channel * ast_channel_get_bridge_channel(struct ast_channel *chan)
Get a reference to the channel&#39;s bridge pointer.
Definition: channel.c:10783
#define SKINNY_DEVICE_7902
Definition: chan_skinny.c:1273
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
static struct sockaddr_in bindaddr
Definition: chan_skinny.c:1231
void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf)
Configures a jitterbuffer on a channel.
Definition: abstract_jb.c:593
#define SKINNY_DEVICE_30VIP
Definition: chan_skinny.c:1247
const char * usage
Definition: cli.h:177
static void transmit_speaker_mode(struct skinny_device *d, int mode)
Definition: chan_skinny.c:2438
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
static int callnums
Definition: chan_skinny.c:1239
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
static char speeddial[ADSI_MAX_SPEED_DIAL][3][SPEEDDIAL_MAX_LEN]
Definition: res_adsi.c:69
struct button_definition definition[42]
Definition: chan_skinny.c:620
void ast_endpoint_blob_publish(struct ast_endpoint *endpoint, struct stasis_message_type *type, struct ast_json *blob)
Creates and publishes a ast_endpoint_blob message.
struct ast_frame * ast_udptl_read(struct ast_udptl *udptl)
Definition: udptl.c:762
static struct skinny_subline * find_subline_by_name(const char *dest)
Definition: chan_skinny.c:1949
#define OCTAL_BUSY
Definition: chan_skinny.c:784
#define AST_PRES_RESTRICTION
Definition: callerid.h:323
struct ast_frame ast_null_frame
Definition: main/frame.c:79
unsigned int tos_video
Definition: chan_skinny.c:195
#define STIMULUS_FORWARDBUSY
Definition: chan_skinny.c:578
int tm_sec
Definition: localtime.h:36
static int set_callforwards(struct skinny_line *l, const char *cfwd, int cfwdtype)
Definition: chan_skinny.c:2152
static char * handle_skinny_show_lines(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_skinny.c:4417
#define SKINNY_DEVICE_7941
Definition: chan_skinny.c:1253
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:653
#define EVENT_FLAG_REPORTING
Definition: manager.h:80
#define SKINNY_DEVICE_ATA186
Definition: chan_skinny.c:1252
#define CLI_SUCCESS
Definition: cli.h:44
static void transmit_clearpromptmessage(struct skinny_device *d, int instance, int callid)
Definition: chan_skinny.c:2974
static void skinny_set_owner(struct skinny_subchannel *sub, struct ast_channel *chan)
Definition: chan_skinny.c:5360
static struct ast_jb_conf global_jbconf
Definition: chan_skinny.c:262
struct stop_tone_message stoptone
Definition: chan_skinny.c:1170
#define DEBUG_LOCK
Definition: chan_skinny.c:152
struct timeval last_keepalive
Definition: chan_skinny.c:1625
#define SKINNY_DEVICE_7936
Definition: chan_skinny.c:1276
struct skinny_container * container
Definition: chan_skinny.c:1523
struct hostent * ast_gethostbyname(const char *host, struct ast_hostent *hp)
Thread-safe gethostbyname function to use in Asterisk.
Definition: main/utils.c:197
static void transmit_versionres(struct skinny_device *d)
Definition: chan_skinny.c:3216
skinny_codecs
Definition: chan_skinny.c:175
#define SUBSTATE_BUSY
Definition: chan_skinny.c:1377
static void transmit_speeddialstatres(struct skinny_device *d, struct skinny_speeddial *sd)
Definition: chan_skinny.c:3149
struct soft_key_event_message softkeyeventmessage
Definition: chan_skinny.c:1199
Structure that contains information regarding a channel in a bridge.
#define BT_CUST_LINESPEEDDIAL
Definition: chan_skinny.c:613
#define SKINNY_CX_INACTIVE
Definition: chan_skinny.c:1338
char * strsep(char **str, const char *delims)
unsigned int cos
Definition: chan_skinny.c:196
#define STIMULUS_CONFERENCE
Definition: chan_skinny.c:586
#define SOFTKEY_ANSWER
Definition: chan_skinny.c:720
static void transmit_backspace(struct skinny_device *d, int instance, unsigned callid)
Definition: chan_skinny.c:3374
#define SKINNY_RING_INSIDE
Definition: chan_skinny.c:1323
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2970
#define STOP_MEDIA_TRANSMISSION_MESSAGE
Definition: chan_skinny.c:492
const uint8_t mode
Definition: chan_skinny.c:913
static void transmit_callinfo_variable(struct skinny_device *d, int instance, int callreference, char *fromname, char *fromnum, char *toname, char *tonum, int calldirection, char *origtonum, char *origtoname)
Definition: chan_skinny.c:2493
int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Add and extension to an extension context.
Definition: pbx.c:6970
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define OCTAL_ENDCALL
Definition: chan_skinny.c:768
struct skinny_subchannel * related
Definition: chan_skinny.c:1415
Standard Command Line Interface.
#define SPEED_DIAL_STAT_RES_MESSAGE
Definition: chan_skinny.c:533
#define DISPLAY_PROMPT_STATUS_MESSAGE
Definition: chan_skinny.c:1071
pthread_t t
Definition: chan_skinny.c:1614
int ast_channel_hangupcause(const struct ast_channel *chan)
uint32_t reference
Definition: chan_skinny.c:333
static char * complete_skinny_show_line(const char *line, const char *word, int pos, int state)
Definition: chan_skinny.c:3940
void ast_channel_context_set(struct ast_channel *chan, const char *value)
static const uint8_t soft_key_default_connwithtrans[]
Definition: chan_skinny.c:962
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
struct call_info_message_variable callinfomessagevariable
Definition: chan_skinny.c:1203
uint32_t alarmParam1
Definition: chan_skinny.c:372
struct media_qualifier qualifier
Definition: chan_skinny.c:475
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
struct ast_format * ast_format_alaw
Built-in cached alaw format.
Definition: format_cache.c:91
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:226
#define SOFT_KEY_TEMPLATE_RES_MESSAGE
Definition: chan_skinny.c:682
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel&#39;s bridge peer only if the bridge is two-party.
Definition: channel.c:10765
const char * ast_channel_name(const struct ast_channel *chan)
char text[MAXDISPLAYNOTIFYSTR]
Definition: chan_skinny.c:1144
struct skinny_subchannel::@134 list
static void _transmit_displayprinotify(struct skinny_device *d, const char *text, const char *extratext, int timeout, int priority)
Definition: chan_skinny.c:2847
const int pos
Definition: cli.h:164
int new_msgs
Definition: mwi.h:461
#define VERSION_RES_MESSAGE
Definition: chan_skinny.c:623
static void delete_devices(void)
Definition: chan_skinny.c:8556
unsigned int cos_video
Definition: chan_skinny.c:198
int ast_parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)
Park the bridge and/or callers that this channel is in.
Definition: parking.c:162
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7486
Asterisk MWI API.
#define AST_PTHREADT_STOP
Definition: lock.h:67
int ast_rtp_glue_unregister(struct ast_rtp_glue *glue)
Unregister RTP glue.
Definition: rtp_engine.c:408
#define AST_PRES_ALLOWED
Definition: callerid.h:324
static PGresult * result
Definition: cel_pgsql.c:88
#define SKINNY_RINGOUT
Definition: chan_skinny.c:1288
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
Execute the PBX in the current thread.
Definition: pbx.c:4759
struct start_media_transmission_message_ip4 startmedia_ip4
Definition: chan_skinny.c:1190
static const uint8_t soft_key_default_offhook[]
Definition: chan_skinny.c:952
static int skinnysock
Definition: chan_skinny.c:1237
struct stasis_forward * sub
Definition: res_corosync.c:240
Data structure associated with a single frame of data.
#define SKINNY_DEVICE_7914
Definition: chan_skinny.c:1255
static void transmit_closereceivechannel(struct skinny_device *d, struct skinny_subchannel *sub)
Definition: chan_skinny.c:3005
#define KEYDEF_OFFHOOKWITHFEAT
Definition: chan_skinny.c:703
Internal Asterisk hangup causes.
static int total
Definition: res_adsi.c:968
unsigned int tos_audio
Definition: chan_skinny.c:194
static int keep_alive
Definition: chan_skinny.c:201
#define SKINNY_MAX_PACKET
Definition: chan_skinny.c:188
char type[10]
Definition: chan_skinny.c:1556
#define SOFTKEY_REDIAL
Definition: chan_skinny.c:710
Abstract JSON element (object, array, string, int, ...).
#define SKINNY_SDCONTAINER
Definition: chan_skinny.c:1547
#define ONHOOK_MESSAGE
Definition: chan_skinny.c:330
static int handle_ip_port_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:6192
static void handle_callforward_button(struct skinny_line *l, struct skinny_subchannel *sub, int cfwdtype)
Definition: chan_skinny.c:6160
char lnname[AST_MAX_EXTENSION]
Definition: chan_skinny.c:1510
static void transmit_stop_tone(struct skinny_device *d, int instance, int reference)
Definition: chan_skinny.c:2692
uint32_t callReference
Definition: chan_skinny.c:1067
struct ast_ha * ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error)
Add a new rule to a list of HAs.
Definition: acl.c:713
const char * ast_channel_context(const struct ast_channel *chan)
uint32_t instance
Definition: chan_skinny.c:690
#define SKINNY_SUBLINECONTAINER
Definition: chan_skinny.c:1546
#define SKINNY_DEVICE_7942
Definition: chan_skinny.c:1265
static int unload_module(void)
Definition: chan_skinny.c:8748
void ast_rtp_instance_set_prop(struct ast_rtp_instance *instance, enum ast_rtp_property property, int value)
Set the value of an RTP instance property.
Definition: rtp_engine.c:705
#define ast_sockaddr_to_sin(addr, sin)
Converts a struct ast_sockaddr to a struct sockaddr_in.
Definition: netsock2.h:769
enum queue_result id
Definition: app_queue.c:1507
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
#define SOFT_KEY_TEMPLATE_REQ_MESSAGE
Definition: chan_skinny.c:401
enum ast_frame_type frametype
#define SET_LAMP_MESSAGE
Definition: chan_skinny.c:442
static void unregister_exten(struct skinny_line *l)
Definition: chan_skinny.c:2234
#define KEYDEF_CONNWITHTRANS
Definition: chan_skinny.c:699
static void transmit_callstate(struct skinny_device *d, int buttonInstance, unsigned callid, int state)
Definition: chan_skinny.c:3087
#define ast_mutex_init(pmutex)
Definition: lock.h:184
int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, enum ast_media_type type)
Append the formats of provided type in src to dst.
Definition: format_cap.c:269
#define AST_CLI_YESNO(x)
Return Yes or No depending on the argument.
Definition: cli.h:71
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:280
#define STIMULUS_FORWARDNOANSWER
Definition: chan_skinny.c:579
struct ast_namedgroups * ast_unref_namedgroups(struct ast_namedgroups *groups)
Definition: channel.c:7832
static const uint8_t soft_key_default_offhookwithfeat[]
Definition: chan_skinny.c:994
struct ast_format * ast_format_g729
Built-in cached g729 format.
Definition: format_cache.c:156
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
static int handle_hold_button(struct skinny_subchannel *sub)
Definition: chan_skinny.c:6092
struct ast_format * ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
Get the format at a specific index.
Definition: format_cap.c:400
static int skinny_register(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:2258
#define CAPABILITIES_REQ_MESSAGE
Definition: chan_skinny.c:639
#define ast_mutex_destroy(a)
Definition: lock.h:186
static char version_id[16]
Definition: chan_skinny.c:210
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition: pbx.c:6198
struct ast_format * format
#define SKINNY_CX_SENDRECV
Definition: chan_skinny.c:1334
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
Definition: pbx.c:3825
static void skinny_transfer_blind(struct skinny_subchannel *sub)
Definition: chan_skinny.c:5277
static struct ast_variable * add_var(const char *buf, struct ast_variable *list)
Definition: chan_skinny.c:1993
#define SKINNY_DEVICE_7945
Definition: chan_skinny.c:1266
uint8_t softKeyTemplateIndex[16]
Definition: chan_skinny.c:1043
#define STIMULUS_CALLPARK
Definition: chan_skinny.c:587
uint32_t res
Definition: chan_skinny.c:1214
struct set_ringer_message setringer
Definition: chan_skinny.c:1179
static const uint8_t soft_key_default_onhook[]
Definition: chan_skinny.c:918
struct ast_rtp_instance * ast_rtp_instance_new(const char *engine_name, struct ast_sched_context *sched, const struct ast_sockaddr *sa, void *data)
Create a new RTP instance.
Definition: rtp_engine.c:465
The structure that contains MWI state.
Definition: mwi.h:457
static void transmit_microphone_mode(struct skinny_device *d, int mode)
Definition: chan_skinny.c:2451
static char url[512]
#define REGISTER_MESSAGE
Definition: chan_skinny.c:288
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:186
uint32_t instance
Definition: chan_skinny.c:292
Say numbers and dates (maybe words one day too)
void ast_endpoint_shutdown(struct ast_endpoint *endpoint)
Shutsdown an ast_endpoint.
struct server_res_message serverres
Definition: chan_skinny.c:1176
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
direction
void ast_channel_priority_set(struct ast_channel *chan, int value)
Pluggable RTP Architecture.
Bridging API.
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1259
struct onhook_message onhook
Definition: chan_skinny.c:1186
void ast_rtp_instance_update_source(struct ast_rtp_instance *instance)
Indicate that the RTP marker bit should be set on an RTP stream.
Definition: rtp_engine.c:2151
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
Asterisk module definitions.
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
static struct hostent * hp
Definition: chan_skinny.c:1236
#define OCTAL_JOIN
Definition: chan_skinny.c:774
char * ast_print_namedgroups(struct ast_str **buf, struct ast_namedgroups *groups)
Print named call groups and named pickup groups.
Definition: channel.c:8158
struct ast_mwi_subscriber * ast_mwi_subscribe_pool(const char *mailbox, stasis_subscription_cb callback, void *data)
Add an MWI state subscriber, and stasis subscription to the mailbox.
Definition: mwi.c:230
struct capabilities_res_message caps
Definition: chan_skinny.c:1161
static struct skinny_device * skinny_device_destroy(struct skinny_device *d)
Definition: chan_skinny.c:1722
int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
Find the compatible formats between two capabilities structures.
Definition: format_cap.c:630
#define STIMULUS_MESSAGE
Definition: chan_skinny.c:317
static snd_pcm_format_t format
Definition: chan_alsa.c:102
#define KEYDEF_RINGIN
Definition: chan_skinny.c:697
static int skinny_dialer_cb(const void *data)
Definition: chan_skinny.c:4888
#define SKINNY_LAMP_WINK
Definition: chan_skinny.c:1318
#define CAPABILITIES_RES_MESSAGE
Definition: chan_skinny.c:336
struct ast_format * ast_format_h263
Built-in cached h263 format.
Definition: format_cache.c:171
long max_size
Max size of the jitterbuffer implementation.
Definition: abstract_jb.h:74
struct display_notify_message displaynotify
Definition: chan_skinny.c:1197
Persistant data storage (akin to *doze registry)
#define ast_rtp_instance_get_remote_address(instance, address)
Get the address of the remote endpoint that we are sending RTP to.
Definition: rtp_engine.h:1192
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define DIALTYPE_CFWD
Definition: chan_skinny.c:1385
struct display_prinotify_message_variable displayprinotifyvar
Definition: chan_skinny.c:1208
struct reset_message reset
Definition: chan_skinny.c:1177
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
Endpoint abstractions.
#define TYPE_DEVICE
Definition: chan_skinny.c:7762
uint16_t softKeyInfoIndex[16]
Definition: chan_skinny.c:1044
General jitterbuffer configuration.
Definition: abstract_jb.h:69
static char * _skinny_show_devices(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *const *argv)
Definition: chan_skinny.c:4088
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:269
#define SOFTKEY_JOIN
Definition: chan_skinny.c:724
#define SKINNY_OUTGOING
Definition: chan_skinny.c:1302
static void * skinny_session(void *data)
Definition: chan_skinny.c:7520
#define SOFT_KEY_SET_REQ_MESSAGE
Definition: chan_skinny.c:391
#define REGISTER_ACK_MESSAGE
Definition: chan_skinny.c:410
#define DISPLAY_NOTIFY_MESSAGE
Definition: chan_skinny.c:1086
#define BT_DISPLAY
Definition: chan_skinny.c:599
#define SKINNY_DEVICE_7910
Definition: chan_skinny.c:1248
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:518
#define SKINNY_DEVICE_7940
Definition: chan_skinny.c:1250
int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type)
Find out if the capabilities structure has any formats of a specific type.
Definition: format_cap.c:615
static char * handle_skinny_message_set(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Handle sending messages to devices.
Definition: chan_skinny.c:4686
#define SKINNY_DEVICE_7906
Definition: chan_skinny.c:1262
#define CALL_INFO_MESSAGE
Definition: chan_skinny.c:499
int tm_min
Definition: localtime.h:37
Structure for mutex and tracking information.
Definition: lock.h:135
#define OCTAL_CFWDNOAN
Definition: chan_skinny.c:766
#define SERVICEURL_STAT_MESSAGE
Definition: chan_skinny.c:1105
#define SOFTKEY_IDIVERT
Definition: chan_skinny.c:729
#define SUBSTATE_UNSET
Definition: chan_skinny.c:1371
#define MAXCALLINFOSTR
Definition: chan_skinny.c:1112
static void send_displayprinotify(struct skinny_device *d, const char *text, const char *extratext, int timeout, int priority)
Definition: chan_skinny.c:2902
uint32_t stimulusInstance
Definition: chan_skinny.c:445
static struct skinny_req * req_alloc(size_t size, int response_message)
Definition: chan_skinny.c:1869
#define BT_LINE
Definition: chan_skinny.c:600
jack_status_t status
Definition: app_jack.c:146
struct ast_frame * ast_rtp_instance_read(struct ast_rtp_instance *instance, int rtcp)
Receive a frame over RTP.
Definition: rtp_engine.c:578
struct sockaddr_in addr
Definition: chan_skinny.c:1583
static char vmexten[AST_MAX_EXTENSION]
Definition: chan_skinny.c:206
#define OPEN_RECEIVE_CHANNEL_ACK_MESSAGE
Definition: chan_skinny.c:376
Media Format Cache API.
short word
#define ast_mutex_unlock(a)
Definition: lock.h:188
const uint8_t * defaults
Definition: chan_skinny.c:914
#define DEVICE2STR_BUFSIZE
Definition: chan_skinny.c:270
#define MAX_SERVICEURL
Definition: chan_skinny.c:1104
#define OCTAL_PARK
Definition: chan_skinny.c:773
static struct ast_channel * skinny_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest, int *cause)
Definition: chan_skinny.c:7717
struct server_identifier server[5]
Definition: chan_skinny.c:652
static void transmit_registerack(struct skinny_device *d)
Definition: chan_skinny.c:3336
static void transmit_softkeytemplateres(struct skinny_device *d)
Definition: chan_skinny.c:3284
static void destroy_rtp(struct skinny_subchannel *sub)
Definition: chan_skinny.c:4807
static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:6609
Channels have this property if they can create jitter; i.e. most VoIP channels.
Definition: channel.h:966
#define KEYDEF_RINGOUTWITHTRANS
Definition: chan_skinny.c:707
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3201
#define OCTAL_BKSPC
Definition: chan_skinny.c:767
#define RESET_MESSAGE
Definition: chan_skinny.c:657
static struct test_val a
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343
uint8_t buttonDefinition
Definition: chan_skinny.c:564
static int handle_keypad_button_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:6220
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443
static void transmit_ringer_mode(struct skinny_device *d, int mode)
Definition: chan_skinny.c:2762
static void dialandactivatesub(struct skinny_subchannel *sub, char exten[AST_MAX_EXTENSION])
Definition: chan_skinny.c:6071