Wed Jan 8 2020 09:49:45

Asterisk developer's documentation


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 /*** MODULEINFO
29  <support_level>extended</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 413586 $")
35 
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <netinet/tcp.h>
39 #include <sys/ioctl.h>
40 #include <net/if.h>
41 #include <fcntl.h>
42 #include <netdb.h>
43 #include <arpa/inet.h>
44 #include <sys/signal.h>
45 #include <signal.h>
46 #include <ctype.h>
47 
48 #include "asterisk/lock.h"
49 #include "asterisk/channel.h"
50 #include "asterisk/config.h"
51 #include "asterisk/module.h"
52 #include "asterisk/pbx.h"
53 #include "asterisk/sched.h"
54 #include "asterisk/io.h"
55 #include "asterisk/rtp_engine.h"
56 #include "asterisk/netsock.h"
57 #include "asterisk/acl.h"
58 #include "asterisk/callerid.h"
59 #include "asterisk/cli.h"
60 #include "asterisk/manager.h"
61 #include "asterisk/say.h"
62 #include "asterisk/cdr.h"
63 #include "asterisk/astdb.h"
64 #include "asterisk/features.h"
65 #include "asterisk/app.h"
66 #include "asterisk/musiconhold.h"
67 #include "asterisk/utils.h"
68 #include "asterisk/dsp.h"
69 #include "asterisk/stringfields.h"
70 #include "asterisk/abstract_jb.h"
71 #include "asterisk/threadstorage.h"
72 #include "asterisk/devicestate.h"
73 #include "asterisk/event.h"
74 #include "asterisk/indications.h"
75 #include "asterisk/linkedlists.h"
76 
77 /*** DOCUMENTATION
78  <manager name="SKINNYdevices" language="en_US">
79  <synopsis>
80  List SKINNY devices (text format).
81  </synopsis>
82  <syntax>
83  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
84  </syntax>
85  <description>
86  <para>Lists Skinny devices in text format with details on current status.
87  Devicelist will follow as separate events, followed by a final event called
88  DevicelistComplete.</para>
89  </description>
90  </manager>
91  <manager name="SKINNYshowdevice" language="en_US">
92  <synopsis>
93  Show SKINNY device (text format).
94  </synopsis>
95  <syntax>
96  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
97  <parameter name="Device" required="true">
98  <para>The device name you want to check.</para>
99  </parameter>
100  </syntax>
101  <description>
102  <para>Show one SKINNY device with details on current status.</para>
103  </description>
104  </manager>
105  <manager name="SKINNYlines" language="en_US">
106  <synopsis>
107  List SKINNY lines (text format).
108  </synopsis>
109  <syntax>
110  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
111  </syntax>
112  <description>
113  <para>Lists Skinny lines in text format with details on current status.
114  Linelist will follow as separate events, followed by a final event called
115  LinelistComplete.</para>
116  </description>
117  </manager>
118  <manager name="SKINNYshowline" language="en_US">
119  <synopsis>
120  Show SKINNY line (text format).
121  </synopsis>
122  <syntax>
123  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
124  <parameter name="Line" required="true">
125  <para>The line name you want to check.</para>
126  </parameter>
127  </syntax>
128  <description>
129  <para>Show one SKINNY line with details on current status.</para>
130  </description>
131  </manager>
132  ***/
133 
134 #ifdef SKINNY_DEVMODE
135 #define SKINNY_DEVONLY(code) \
136  code
137 #else
138 #define SKINNY_DEVONLY(code)
139 #endif
140 
141 /*************************************
142  * Skinny/Asterisk Protocol Settings *
143  *************************************/
144 static const char tdesc[] = "Skinny Client Control Protocol (Skinny)";
145 static const char config[] = "skinny.conf";
146 
149 
155  SKINNY_CODEC_G726_32 = 82, /* XXX Which packing order does this translate to? */
158 };
159 
160 #define DEFAULT_SKINNY_PORT 2000
161 #define DEFAULT_SKINNY_BACKLOG 2
162 #define SKINNY_MAX_PACKET 1000
163 #define DEFAULT_AUTH_TIMEOUT 30
164 #define DEFAULT_AUTH_LIMIT 50
165 
166 static struct {
167  unsigned int tos;
168  unsigned int tos_audio;
169  unsigned int tos_video;
170  unsigned int cos;
171  unsigned int cos_audio;
172  unsigned int cos_video;
173 } qos = { 0, 0, 0, 0, 0, 0 };
174 
175 static int keep_alive = 120;
178 static int unauth_sessions = 0;
179 static char global_vmexten[AST_MAX_EXTENSION]; /* Voicemail pilot number */
180 static char used_context[AST_MAX_EXTENSION]; /* placeholder to check if context are already used in regcontext */
181 static char regcontext[AST_MAX_CONTEXT]; /* Context for auto-extension */
182 static char date_format[6] = "D-M-Y";
183 static char version_id[16] = "P002F202";
184 
185 #if __BYTE_ORDER == __LITTLE_ENDIAN
186 #define letohl(x) (x)
187 #define letohs(x) (x)
188 #define htolel(x) (x)
189 #define htoles(x) (x)
190 #else
191 #if defined(HAVE_BYTESWAP_H)
192 #include <byteswap.h>
193 #define letohl(x) bswap_32(x)
194 #define letohs(x) bswap_16(x)
195 #define htolel(x) bswap_32(x)
196 #define htoles(x) bswap_16(x)
197 #elif defined(HAVE_SYS_ENDIAN_SWAP16)
198 #include <sys/endian.h>
199 #define letohl(x) __swap32(x)
200 #define letohs(x) __swap16(x)
201 #define htolel(x) __swap32(x)
202 #define htoles(x) __swap16(x)
203 #elif defined(HAVE_SYS_ENDIAN_BSWAP16)
204 #include <sys/endian.h>
205 #define letohl(x) bswap32(x)
206 #define letohs(x) bswap16(x)
207 #define htolel(x) bswap32(x)
208 #define htoles(x) bswap16(x)
209 #else
210 #define __bswap_16(x) \
211  ((((x) & 0xff00) >> 8) | \
212  (((x) & 0x00ff) << 8))
213 #define __bswap_32(x) \
214  ((((x) & 0xff000000) >> 24) | \
215  (((x) & 0x00ff0000) >> 8) | \
216  (((x) & 0x0000ff00) << 8) | \
217  (((x) & 0x000000ff) << 24))
218 #define letohl(x) __bswap_32(x)
219 #define letohs(x) __bswap_16(x)
220 #define htolel(x) __bswap_32(x)
221 #define htoles(x) __bswap_16(x)
222 #endif
223 #endif
224 
225 /*! Global jitterbuffer configuration - by default, jb is disabled
226  * \note Values shown here match the defaults shown in skinny.conf.sample */
228 {
229  .flags = 0,
230  .max_size = 200,
231  .resync_threshold = 1000,
232  .impl = "fixed",
233  .target_extra = 40,
234 };
236 
237 #ifdef SKINNY_DEVMODE
238 AST_THREADSTORAGE(message2str_threadbuf);
239 #define MESSAGE2STR_BUFSIZE 35
240 #endif
241 
243 #define DEVICE2STR_BUFSIZE 15
244 
246 #define CONTROL2STR_BUFSIZE 100
247 
248 /*********************
249  * Protocol Messages *
250  *********************/
251 /* message types */
252 #define KEEP_ALIVE_MESSAGE 0x0000
253 /* no additional struct */
254 
255 #define REGISTER_MESSAGE 0x0001
257  char name[16];
258  uint32_t userId;
259  uint32_t instance;
260  uint32_t ip;
261  uint32_t type;
262  uint32_t maxStreams;
263 };
264 
265 #define IP_PORT_MESSAGE 0x0002
266 
267 #define KEYPAD_BUTTON_MESSAGE 0x0003
269  uint32_t button;
270  uint32_t lineInstance;
271  uint32_t callReference;
272 };
273 
274 
275 #define ENBLOC_CALL_MESSAGE 0x0004
277  char calledParty[24];
278 };
279 
280 #define STIMULUS_MESSAGE 0x0005
282  uint32_t stimulus;
284  uint32_t callreference;
285 };
286 
287 #define OFFHOOK_MESSAGE 0x0006
289  uint32_t instance;
290  uint32_t reference;
291 };
292 
293 #define ONHOOK_MESSAGE 0x0007
295  uint32_t instance;
296  uint32_t reference;
297 };
298 
299 #define CAPABILITIES_RES_MESSAGE 0x0010
301  uint32_t codec;
302  uint32_t frames;
303  union {
304  char res[8];
305  uint32_t rate;
306  } payloads;
307 };
308 
309 #define SKINNY_MAX_CAPABILITIES 18
310 
312  uint32_t count;
314 };
315 
316 #define SPEED_DIAL_STAT_REQ_MESSAGE 0x000A
318  uint32_t speedDialNumber;
319 };
320 
321 #define LINE_STATE_REQ_MESSAGE 0x000B
323  uint32_t lineNumber;
324 };
325 
326 #define TIME_DATE_REQ_MESSAGE 0x000D
327 #define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
328 #define VERSION_REQ_MESSAGE 0x000F
329 #define SERVER_REQUEST_MESSAGE 0x0012
330 
331 #define ALARM_MESSAGE 0x0020
333  uint32_t alarmSeverity;
334  char displayMessage[80];
335  uint32_t alarmParam1;
336  uint32_t alarmParam2;
337 };
338 
339 #define OPEN_RECEIVE_CHANNEL_ACK_MESSAGE 0x0022
341  uint32_t status;
342  uint32_t ipAddr;
343  uint32_t port;
344  uint32_t passThruId;
345 };
346 
347 #define SOFT_KEY_SET_REQ_MESSAGE 0x0025
348 
349 #define SOFT_KEY_EVENT_MESSAGE 0x0026
351  uint32_t softKeyEvent;
352  uint32_t instance;
353  uint32_t callreference;
354 };
355 
356 #define UNREGISTER_MESSAGE 0x0027
357 #define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028
358 #define HEADSET_STATUS_MESSAGE 0x002B
359 #define REGISTER_AVAILABLE_LINES_MESSAGE 0x002D
360 
361 #define REGISTER_ACK_MESSAGE 0x0081
363  uint32_t keepAlive;
364  char dateTemplate[6];
365  char res[2];
367  char res2[4];
368 };
369 
370 #define START_TONE_MESSAGE 0x0082
372  uint32_t tone;
373  uint32_t space;
374  uint32_t instance;
375  uint32_t reference;
376 };
377 
378 #define STOP_TONE_MESSAGE 0x0083
380  uint32_t instance;
381  uint32_t reference;
382 };
383 
384 #define SET_RINGER_MESSAGE 0x0085
386  uint32_t ringerMode;
387  uint32_t unknown1; /* See notes in transmit_ringer_mode */
388  uint32_t unknown2;
389  uint32_t space[2];
390 };
391 
392 #define SET_LAMP_MESSAGE 0x0086
394  uint32_t stimulus;
396  uint32_t deviceStimulus;
397 };
398 
399 #define SET_SPEAKER_MESSAGE 0x0088
401  uint32_t mode;
402 };
403 
404 /* XXX When do we need to use this? */
405 #define SET_MICROPHONE_MESSAGE 0x0089
407  uint32_t mode;
408 };
409 
410 #define START_MEDIA_TRANSMISSION_MESSAGE 0x008A
412  uint32_t precedence;
413  uint32_t vad;
414  uint16_t packets;
415  uint32_t bitRate;
416 };
417 
419  uint32_t conferenceId;
420  uint32_t passThruPartyId;
421  uint32_t remoteIp;
422  uint32_t remotePort;
423  uint32_t packetSize;
424  uint32_t payloadType;
426  uint32_t space[16];
427 };
428 
429 #define STOP_MEDIA_TRANSMISSION_MESSAGE 0x008B
431  uint32_t conferenceId;
432  uint32_t passThruPartyId;
433  uint32_t space[3];
434 };
435 
436 #define CALL_INFO_MESSAGE 0x008F
439  char callingParty[24];
440  char calledPartyName[40];
441  char calledParty[24];
442  uint32_t instance;
443  uint32_t reference;
444  uint32_t type;
455  uint32_t space[3];
456 };
457 
458 #define FORWARD_STAT_MESSAGE 0x0090
460  uint32_t activeforward;
461  uint32_t lineNumber;
462  uint32_t fwdall;
463  char fwdallnum[24];
464  uint32_t fwdbusy;
465  char fwdbusynum[24];
466  uint32_t fwdnoanswer;
467  char fwdnoanswernum[24];
468 };
469 
470 #define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
472  uint32_t speedDialNumber;
475 };
476 
477 #define LINE_STAT_RES_MESSAGE 0x0092
479  uint32_t lineNumber;
480  char lineDirNumber[24];
481  char lineDisplayName[24];
482  uint32_t space[15];
483 };
484 
485 #define DEFINETIMEDATE_MESSAGE 0x0094
487  uint32_t year; /* since 1900 */
488  uint32_t month;
489  uint32_t dayofweek; /* monday = 1 */
490  uint32_t day;
491  uint32_t hour;
492  uint32_t minute;
493  uint32_t seconds;
494  uint32_t milliseconds;
495  uint32_t timestamp;
496 };
497 
498 #define BUTTON_TEMPLATE_RES_MESSAGE 0x0097
500  uint8_t instanceNumber;
502 };
503 
506  /* for now, anything between 0xB0 and 0xCF is custom */
507  /*int custom;*/
508 };
509 
510 #define STIMULUS_REDIAL 0x01
511 #define STIMULUS_SPEEDDIAL 0x02
512 #define STIMULUS_HOLD 0x03
513 #define STIMULUS_TRANSFER 0x04
514 #define STIMULUS_FORWARDALL 0x05
515 #define STIMULUS_FORWARDBUSY 0x06
516 #define STIMULUS_FORWARDNOANSWER 0x07
517 #define STIMULUS_DISPLAY 0x08
518 #define STIMULUS_LINE 0x09
519 #define STIMULUS_VOICEMAIL 0x0F
520 #define STIMULUS_AUTOANSWER 0x11
521 #define STIMULUS_DND 0x3F
522 #define STIMULUS_CONFERENCE 0x7D
523 #define STIMULUS_CALLPARK 0x7E
524 #define STIMULUS_CALLPICKUP 0x7F
525 #define STIMULUS_NONE 0xFF
526 
527 /* Button types */
528 #define BT_REDIAL STIMULUS_REDIAL
529 #define BT_SPEEDDIAL STIMULUS_SPEEDDIAL
530 #define BT_HOLD STIMULUS_HOLD
531 #define BT_TRANSFER STIMULUS_TRANSFER
532 #define BT_FORWARDALL STIMULUS_FORWARDALL
533 #define BT_FORWARDBUSY STIMULUS_FORWARDBUSY
534 #define BT_FORWARDNOANSWER STIMULUS_FORWARDNOANSWER
535 #define BT_DISPLAY STIMULUS_DISPLAY
536 #define BT_LINE STIMULUS_LINE
537 #define BT_VOICEMAIL STIMULUS_VOICEMAIL
538 #define BT_AUTOANSWER STIMULUS_AUTOANSWER
539 #define BT_DND STIMULUS_DND
540 #define BT_CONFERENCE STIMULUS_CONFERENCE
541 #define BT_CALLPARK STIMULUS_CALLPARK
542 #define BT_CALLPICKUP STIMULUS_CALLPICKUP
543 #define BT_NONE 0x00
544 
545 /* Custom button types - add our own between 0xB0 and 0xCF.
546  This may need to be revised in the future,
547  if stimuluses are ever added in this range. */
548 #define BT_CUST_LINESPEEDDIAL 0xB0 /* line or speeddial with/without hint */
549 #define BT_CUST_LINE 0xB1 /* line or speeddial with hint only */
550 
552  uint32_t buttonOffset;
553  uint32_t buttonCount;
556 };
557 
558 #define VERSION_RES_MESSAGE 0x0098
560  char version[16];
561 };
562 
563 #define DISPLAYTEXT_MESSAGE 0x0099
565  char text[40];
566 };
567 
568 #define CLEAR_NOTIFY_MESSAGE 0x0115
569 #define CLEAR_DISPLAY_MESSAGE 0x009A
570 
571 #define CAPABILITIES_REQ_MESSAGE 0x009B
572 
573 #define REGISTER_REJ_MESSAGE 0x009D
575  char errMsg[33];
576 };
577 
578 #define SERVER_RES_MESSAGE 0x009E
580  char serverName[48];
581 };
582 
585  uint32_t serverListenPort[5];
586  uint32_t serverIpAddr[5];
587 };
588 
589 #define RESET_MESSAGE 0x009F
591  uint32_t resetType;
592 };
593 
594 #define KEEP_ALIVE_ACK_MESSAGE 0x0100
595 
596 #define OPEN_RECEIVE_CHANNEL_MESSAGE 0x0105
598  uint32_t conferenceId;
599  uint32_t partyId;
600  uint32_t packets;
601  uint32_t capability;
602  uint32_t echo;
603  uint32_t bitrate;
604  uint32_t space[16];
605 };
606 
607 #define CLOSE_RECEIVE_CHANNEL_MESSAGE 0x0106
609  uint32_t conferenceId;
610  uint32_t partyId;
611  uint32_t space[2];
612 };
613 
614 #define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108
615 
617  char softKeyLabel[16];
618  uint32_t softKeyEvent;
619 };
620 
621 #define KEYDEF_ONHOOK 0
622 #define KEYDEF_CONNECTED 1
623 #define KEYDEF_ONHOLD 2
624 #define KEYDEF_RINGIN 3
625 #define KEYDEF_OFFHOOK 4
626 #define KEYDEF_CONNWITHTRANS 5
627 #define KEYDEF_DADFD 6 /* Digits After Dialing First Digit */
628 #define KEYDEF_CONNWITHCONF 7
629 #define KEYDEF_RINGOUT 8
630 #define KEYDEF_OFFHOOKWITHFEAT 9
631 #define KEYDEF_UNKNOWN 10
632 
633 #define SOFTKEY_NONE 0x00
634 #define SOFTKEY_REDIAL 0x01
635 #define SOFTKEY_NEWCALL 0x02
636 #define SOFTKEY_HOLD 0x03
637 #define SOFTKEY_TRNSFER 0x04
638 #define SOFTKEY_CFWDALL 0x05
639 #define SOFTKEY_CFWDBUSY 0x06
640 #define SOFTKEY_CFWDNOANSWER 0x07
641 #define SOFTKEY_BKSPC 0x08
642 #define SOFTKEY_ENDCALL 0x09
643 #define SOFTKEY_RESUME 0x0A
644 #define SOFTKEY_ANSWER 0x0B
645 #define SOFTKEY_INFO 0x0C
646 #define SOFTKEY_CONFRN 0x0D
647 #define SOFTKEY_PARK 0x0E
648 #define SOFTKEY_JOIN 0x0F
649 #define SOFTKEY_MEETME 0x10
650 #define SOFTKEY_PICKUP 0x11
651 #define SOFTKEY_GPICKUP 0x12
652 #define SOFTKEY_DND 0x13
653 #define SOFTKEY_IDIVERT 0x14
654 
656  { "\200\001", SOFTKEY_REDIAL },
657  { "\200\002", SOFTKEY_NEWCALL },
658  { "\200\003", SOFTKEY_HOLD },
659  { "\200\004", SOFTKEY_TRNSFER },
660  { "\200\005", SOFTKEY_CFWDALL },
661  { "\200\006", SOFTKEY_CFWDBUSY },
662  { "\200\007", SOFTKEY_CFWDNOANSWER },
663  { "\200\010", SOFTKEY_BKSPC },
664  { "\200\011", SOFTKEY_ENDCALL },
665  { "\200\012", SOFTKEY_RESUME },
666  { "\200\013", SOFTKEY_ANSWER },
667  { "\200\014", SOFTKEY_INFO },
668  { "\200\015", SOFTKEY_CONFRN },
669  { "\200\016", SOFTKEY_PARK },
670  { "\200\017", SOFTKEY_JOIN },
671  { "\200\020", SOFTKEY_MEETME },
672  { "\200\021", SOFTKEY_PICKUP },
673  { "\200\022", SOFTKEY_GPICKUP },
674  { "\200\077", SOFTKEY_DND },
675  { "\200\120", SOFTKEY_IDIVERT },
676 };
677 
678 /* Localized message "codes" (in octal)
679  Below is en_US (taken from a 7970)
680 
681  \200\xxx
682  \000: ???
683  \001: Redial
684  \002: New Call
685  \003: Hold
686  \004: Transfer
687  \005: CFwdALL
688  \006: CFwdBusy
689  \007: CFwdNoAnswer
690  \010: <<
691  \011: EndCall
692  \012: Resume
693  \013: Answer
694  \014: Info
695  \015: Confrn
696  \016: Park
697  \017: Join
698  \020: MeetMe
699  \021: PickUp
700  \022: GPickUp
701  \023: Your current options
702  \024: Off Hook
703  \025: On Hook
704  \026: Ring out
705  \027: From
706  \030: Connected
707  \031: Busy
708  \032: Line In Use
709  \033: Call Waiting
710  \034: Call Transfer
711  \035: Call Park
712  \036: Call Proceed
713  \037: In Use Remote
714  \040: Enter number
715  \041: Call park At
716  \042: Primary Only
717  \043: Temp Fail
718  \044: You Have VoiceMail
719  \045: Forwarded to
720  \046: Can Not Complete Conference
721  \047: No Conference Bridge
722  \050: Can Not Hold Primary Control
723  \051: Invalid Conference Participant
724  \052: In Conference Already
725  \053: No Participant Info
726  \054: Exceed Maximum Parties
727  \055: Key Is Not Active
728  \056: Error No License
729  \057: Error DBConfig
730  \060: Error Database
731  \061: Error Pass Limit
732  \062: Error Unknown
733  \063: Error Mismatch
734  \064: Conference
735  \065: Park Number
736  \066: Private
737  \067: Not Enough Bandwidth
738  \070: Unknown Number
739  \071: RmLstC
740  \072: Voicemail
741  \073: ImmDiv
742  \074: Intrcpt
743  \075: SetWtch
744  \076: TrnsfVM
745  \077: DND
746  \100: DivAll
747  \101: CallBack
748  \102: Network congestion,rerouting
749  \103: Barge
750  \104: Failed to setup Barge
751  \105: Another Barge exists
752  \106: Incompatible device type
753  \107: No Park Number Available
754  \110: CallPark Reversion
755  \111: Service is not Active
756  \112: High Traffic Try Again Later
757  \113: QRT
758  \114: MCID
759  \115: DirTrfr
760  \116: Select
761  \117: ConfList
762  \120: iDivert
763  \121: cBarge
764  \122: Can Not Complete Transfer
765  \123: Can Not Join Calls
766  \124: Mcid Successful
767  \125: Number Not Configured
768  \126: Security Error
769  \127: Video Bandwidth Unavailable
770  \130: VidMode
771  \131: Max Call Duration Timeout
772  \132: Max Hold Duration Timeout
773  \133: OPickUp
774  \134: ???
775  \135: ???
776  \136: ???
777  \137: ???
778  \140: ???
779  \141: External Transfer Restricted
780  \142: ???
781  \143: ???
782  \144: ???
783  \145: Mac Address
784  \146: Host Name
785  \147: Domain Name
786  \150: IP Address
787  \151: Subnet Mask
788  \152: TFTP Server 1
789  \153: Default Router 1
790  \154: Default Router 2
791  \155: Default Router 3
792  \156: Default Router 4
793  \157: Default Router 5
794  \160: DNS Server 1
795  \161: DNS Server 2
796  \162: DNS Server 3
797  \163: DNS Server 4
798  \164: DNS Server 5
799  \165: Operational VLAN Id
800  \166: Admin. VLAN Id
801  \167: CallManager 1
802  \170: CallManager 2
803  \171: CallManager 3
804  \172: CallManager 4
805  \173: CallManager 5
806  \174: Information URL
807  \175: Directories URL
808  \176: Messages URL
809  \177: Services URL
810  */
811 
813  const uint8_t mode;
814  const uint8_t *defaults;
815  const int count;
816 };
817 
818 static const uint8_t soft_key_default_onhook[] = {
823  SOFTKEY_DND,
824  /*SOFTKEY_GPICKUP,
825  SOFTKEY_CONFRN,*/
826 };
827 
828 static const uint8_t soft_key_default_connected[] = {
829  SOFTKEY_HOLD,
832  SOFTKEY_PARK,
835 };
836 
837 static const uint8_t soft_key_default_onhold[] = {
842 };
843 
844 static const uint8_t soft_key_default_ringin[] = {
848 };
849 
850 static const uint8_t soft_key_default_offhook[] = {
855  /*SOFTKEY_GPICKUP,*/
856 };
857 
858 static const uint8_t soft_key_default_connwithtrans[] = {
859  SOFTKEY_HOLD,
862  SOFTKEY_PARK,
865 };
866 
867 static const uint8_t soft_key_default_dadfd[] = {
870 };
871 
872 static const uint8_t soft_key_default_connwithconf[] = {
873  SOFTKEY_NONE,
874 };
875 
876 static const uint8_t soft_key_default_ringout[] = {
877  SOFTKEY_NONE,
879 };
880 
881 static const uint8_t soft_key_default_offhookwithfeat[] = {
885 };
886 
887 static const uint8_t soft_key_default_unknown[] = {
888  SOFTKEY_NONE,
889 };
890 
892  {KEYDEF_ONHOOK, soft_key_default_onhook, sizeof(soft_key_default_onhook) / sizeof(uint8_t)},
894  {KEYDEF_ONHOLD, soft_key_default_onhold, sizeof(soft_key_default_onhold) / sizeof(uint8_t)},
895  {KEYDEF_RINGIN, soft_key_default_ringin, sizeof(soft_key_default_ringin) / sizeof(uint8_t)},
898  {KEYDEF_DADFD, soft_key_default_dadfd, sizeof(soft_key_default_dadfd) / sizeof(uint8_t)},
903 };
904 
906  uint32_t softKeyOffset;
907  uint32_t softKeyCount;
910 };
911 
912 #define SOFT_KEY_SET_RES_MESSAGE 0x0109
913 
915  uint8_t softKeyTemplateIndex[16];
916  uint16_t softKeyInfoIndex[16];
917 };
918 
921  uint32_t softKeySetCount;
924  uint32_t res;
925 };
926 
927 #define SELECT_SOFT_KEYS_MESSAGE 0x0110
929  uint32_t instance;
930  uint32_t reference;
931  uint32_t softKeySetIndex;
932  uint32_t validKeyMask;
933 };
934 
935 #define CALL_STATE_MESSAGE 0x0111
937  uint32_t callState;
938  uint32_t lineInstance;
939  uint32_t callReference;
940  uint32_t space[3];
941 };
942 
943 #define DISPLAY_PROMPT_STATUS_MESSAGE 0x0112
945  uint32_t messageTimeout;
946  char promptMessage[32];
947  uint32_t lineInstance;
948  uint32_t callReference;
949  uint32_t space[3];
950 };
951 
952 #define CLEAR_PROMPT_MESSAGE 0x0113
954  uint32_t lineInstance;
955  uint32_t callReference;
956 };
957 
958 #define DISPLAY_NOTIFY_MESSAGE 0x0114
960  uint32_t displayTimeout;
961  char displayMessage[100];
962 };
963 
964 #define ACTIVATE_CALL_PLANE_MESSAGE 0x0116
966  uint32_t lineInstance;
967 };
968 
969 #define DIALED_NUMBER_MESSAGE 0x011D
971  char dialedNumber[24];
972  uint32_t lineInstance;
973  uint32_t callReference;
974 };
975 
976 union skinny_data {
1020 };
1021 
1022 /* packet composition */
1023 struct skinny_req {
1024  int len;
1025  int res;
1026  int e;
1028 };
1029 
1030 /* XXX This is the combined size of the variables above. (len, res, e)
1031  If more are added, this MUST change.
1032  (sizeof(skinny_req) - sizeof(skinny_data)) DOES NOT WORK on all systems (amd64?). */
1033 static int skinny_header_size = 12;
1034 
1035 /*****************************
1036  * Asterisk specific globals *
1037  *****************************/
1038 
1039 static int skinnydebug = 0;
1040 static int skinnyreload = 0;
1041 
1042 /* a hostname, portnumber, socket and such is usefull for VoIP protocols */
1043 static struct sockaddr_in bindaddr;
1044 static char ourhost[256];
1045 static int ourport;
1046 static struct in_addr __ourip;
1047 static struct ast_hostent ahp;
1048 static struct hostent *hp;
1049 static int skinnysock = -1;
1050 static pthread_t accept_t;
1051 static int callnums = 1;
1052 
1053 #define SKINNY_DEVICE_UNKNOWN -1
1054 #define SKINNY_DEVICE_NONE 0
1055 #define SKINNY_DEVICE_30SPPLUS 1
1056 #define SKINNY_DEVICE_12SPPLUS 2
1057 #define SKINNY_DEVICE_12SP 3
1058 #define SKINNY_DEVICE_12 4
1059 #define SKINNY_DEVICE_30VIP 5
1060 #define SKINNY_DEVICE_7910 6
1061 #define SKINNY_DEVICE_7960 7
1062 #define SKINNY_DEVICE_7940 8
1063 #define SKINNY_DEVICE_7935 9
1064 #define SKINNY_DEVICE_ATA186 12 /* Cisco ATA-186 */
1065 #define SKINNY_DEVICE_7941 115
1066 #define SKINNY_DEVICE_7971 119
1067 #define SKINNY_DEVICE_7914 124 /* Expansion module */
1068 #define SKINNY_DEVICE_7985 302
1069 #define SKINNY_DEVICE_7911 307
1070 #define SKINNY_DEVICE_7961GE 308
1071 #define SKINNY_DEVICE_7941GE 309
1072 #define SKINNY_DEVICE_7931 348
1073 #define SKINNY_DEVICE_7921 365
1074 #define SKINNY_DEVICE_7906 369
1075 #define SKINNY_DEVICE_7962 404 /* Not found */
1076 #define SKINNY_DEVICE_7937 431
1077 #define SKINNY_DEVICE_7942 434
1078 #define SKINNY_DEVICE_7945 435
1079 #define SKINNY_DEVICE_7965 436
1080 #define SKINNY_DEVICE_7975 437
1081 #define SKINNY_DEVICE_7905 20000
1082 #define SKINNY_DEVICE_7920 30002
1083 #define SKINNY_DEVICE_7970 30006
1084 #define SKINNY_DEVICE_7912 30007
1085 #define SKINNY_DEVICE_7902 30008
1086 #define SKINNY_DEVICE_CIPC 30016 /* Cisco IP Communicator */
1087 #define SKINNY_DEVICE_7961 30018
1088 #define SKINNY_DEVICE_7936 30019
1089 #define SKINNY_DEVICE_SCCPGATEWAY_AN 30027 /* Analog gateway */
1090 #define SKINNY_DEVICE_SCCPGATEWAY_BRI 30028 /* BRI gateway */
1091 
1092 #define SKINNY_SPEAKERON 1
1093 #define SKINNY_SPEAKEROFF 2
1094 
1095 #define SKINNY_MICON 1
1096 #define SKINNY_MICOFF 2
1097 
1098 #define SKINNY_OFFHOOK 1
1099 #define SKINNY_ONHOOK 2
1100 #define SKINNY_RINGOUT 3
1101 #define SKINNY_RINGIN 4
1102 #define SKINNY_CONNECTED 5
1103 #define SKINNY_BUSY 6
1104 #define SKINNY_CONGESTION 7
1105 #define SKINNY_HOLD 8
1106 #define SKINNY_CALLWAIT 9
1107 #define SKINNY_TRANSFER 10
1108 #define SKINNY_PARK 11
1109 #define SKINNY_PROGRESS 12
1110 #define SKINNY_CALLREMOTEMULTILINE 13
1111 #define SKINNY_INVALID 14
1112 
1113 #define SKINNY_SILENCE 0x00 /* Note sure this is part of the protocol, remove? */
1114 #define SKINNY_DIALTONE 0x21
1115 #define SKINNY_BUSYTONE 0x23
1116 #define SKINNY_ALERT 0x24
1117 #define SKINNY_REORDER 0x25
1118 #define SKINNY_CALLWAITTONE 0x2D
1119 #define SKINNY_NOTONE 0x7F
1120 
1121 #define SKINNY_LAMP_OFF 1
1122 #define SKINNY_LAMP_ON 2
1123 #define SKINNY_LAMP_WINK 3
1124 #define SKINNY_LAMP_FLASH 4
1125 #define SKINNY_LAMP_BLINK 5
1126 
1127 #define SKINNY_RING_OFF 1
1128 #define SKINNY_RING_INSIDE 2
1129 #define SKINNY_RING_OUTSIDE 3
1130 #define SKINNY_RING_FEATURE 4
1131 
1132 #define SKINNY_CFWD_ALL (1 << 0)
1133 #define SKINNY_CFWD_BUSY (1 << 1)
1134 #define SKINNY_CFWD_NOANSWER (1 << 2)
1135 
1136 /* Skinny rtp stream modes. Do we really need this? */
1137 #define SKINNY_CX_SENDONLY 0
1138 #define SKINNY_CX_RECVONLY 1
1139 #define SKINNY_CX_SENDRECV 2
1140 #define SKINNY_CX_CONF 3
1141 #define SKINNY_CX_CONFERENCE 3
1142 #define SKINNY_CX_MUTE 4
1143 #define SKINNY_CX_INACTIVE 4
1144 
1145 #if 0
1146 static const char * const skinny_cxmodes[] = {
1147  "sendonly",
1148  "recvonly",
1149  "sendrecv",
1150  "confrnce",
1151  "inactive"
1152 };
1153 #endif
1154 
1155 /* driver scheduler */
1156 static struct sched_context *sched = NULL;
1157 static struct io_context *io;
1158 
1159 /* Protect the monitoring thread, so only one process can kill or start it, and not
1160  when it's doing something critical. */
1162 /* Protect the network socket */
1164 
1165 /* This is the thread for the monitor which checks for input on the channels
1166  which are not currently in use. */
1168 
1169 /* Wait up to 16 seconds for first digit */
1170 static int firstdigittimeout = 16000;
1171 
1172 /* How long to wait for following digits */
1173 static int gendigittimeout = 8000;
1174 
1175 /* How long to wait for an extra digit, if there is an ambiguous match */
1176 static int matchdigittimeout = 3000;
1177 
1183  unsigned int callid;
1184  /* time_t lastouttime; */ /* Unused */
1186  int ringing;
1187  int onhold;
1188  /* int lastout; */ /* Unused */
1189  int cxmode;
1190  int nat;
1194  int xferor;
1195 
1196 
1200 };
1201 
1202 #define SKINNY_LINE_OPTIONS \
1203  char name[80]; \
1204  char label[24]; \
1205  char accountcode[AST_MAX_ACCOUNT_CODE]; \
1206  char exten[AST_MAX_EXTENSION]; \
1207  char context[AST_MAX_CONTEXT]; \
1208  char language[MAX_LANGUAGE]; \
1209  char cid_num[AST_MAX_EXTENSION]; \
1210  char cid_name[AST_MAX_EXTENSION]; \
1211  char lastcallerid[AST_MAX_EXTENSION]; \
1212  int cfwdtype; \
1213  char call_forward_all[AST_MAX_EXTENSION]; \
1214  char call_forward_busy[AST_MAX_EXTENSION]; \
1215  char call_forward_noanswer[AST_MAX_EXTENSION]; \
1216  char mailbox[AST_MAX_EXTENSION]; \
1217  char vmexten[AST_MAX_EXTENSION]; \
1218  char regexten[AST_MAX_EXTENSION]; \
1219  char regcontext[AST_MAX_CONTEXT]; \
1220  char parkinglot[AST_MAX_CONTEXT]; \
1221  char mohinterpret[MAX_MUSICCLASS]; \
1222  char mohsuggest[MAX_MUSICCLASS]; \
1223  char lastnumberdialed[AST_MAX_EXTENSION]; \
1224  int curtone; \
1225  ast_group_t callgroup; \
1226  ast_group_t pickupgroup; \
1227  int callwaiting; \
1228  int transfer; \
1229  int threewaycalling; \
1230  int mwiblink; \
1231  int cancallforward; \
1232  int getforward; \
1233  int callreturn; \
1234  int dnd; \
1235  int hascallerid; \
1236  int hidecallerid; \
1237  int amaflags; \
1238  int type; \
1239  int instance; \
1240  int group; \
1241  int needdestroy; \
1242  format_t confcapability; \
1243  struct ast_codec_pref confprefs; \
1244  format_t capability; \
1245  struct ast_codec_pref prefs; \
1246  int nonCodecCapability; \
1247  int onhooktime; \
1248  int msgstate; \
1249  int immediate; \
1250  int hookstate; \
1251  int nat; \
1252  int directmedia; \
1253  int prune;
1254 
1255 struct skinny_line {
1258  struct ast_event_sub *mwi_event_sub; /* Event based MWI */
1263  struct skinny_device *device;
1264  struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
1265  int newmsgs;
1266 };
1267 
1268 static struct skinny_line_options{
1270 } default_line_struct = {
1271  .callwaiting = 1,
1272  .transfer = 1,
1273  .mwiblink = 0,
1274  .dnd = 0,
1275  .hidecallerid = 0,
1276  .amaflags = 0,
1277  .instance = 0,
1278  .directmedia = 0,
1279  .nat = 0,
1280  .confcapability = AST_FORMAT_ULAW | AST_FORMAT_ALAW,
1281  .capability = 0,
1282  .getforward = 0,
1283  .needdestroy = 0,
1284  .prune = 0,
1285  .hookstate = SKINNY_ONHOOK,
1286 };
1288 
1290 
1293  char label[42];
1297  int stateid;
1299  int isHint;
1300 
1302  struct skinny_device *parent;
1303 };
1304 
1307  char type[10];
1308  AST_LIST_ENTRY(skinny_addon) list;
1309  struct skinny_device *parent;
1310 };
1311 
1312 #define SKINNY_DEVICE_OPTIONS \
1313  char name[80]; \
1314  char id[16]; \
1315  char version_id[16]; \
1316  char exten[AST_MAX_EXTENSION]; \
1317  char vmexten[AST_MAX_EXTENSION]; \
1318  int type; \
1319  int registered; \
1320  int lastlineinstance; \
1321  int lastcallreference; \
1322  format_t confcapability; \
1323  struct ast_codec_pref confprefs; \
1324  format_t capability; \
1325  int earlyrtp; \
1326  int transfer; \
1327  int callwaiting; \
1328  int mwiblink; \
1329  int dnd; \
1330  int prune;
1331 
1334  struct type *first;
1335  struct type *last;
1337  struct sockaddr_in addr;
1338  struct in_addr ourip;
1339  struct ast_ha *ha;
1344  AST_LIST_HEAD(, skinny_addon) addons;
1346 };
1347 
1348 static struct skinny_device_options {
1351  .transfer = 1,
1352  .earlyrtp = 1,
1353  .callwaiting = 1,
1354  .mwiblink = 0,
1355  .dnd = 0,
1356  .confcapability = AST_FORMAT_ULAW | AST_FORMAT_ALAW,
1357  .capability = 0,
1358  .prune = 0,
1359 };
1361 
1363 
1365  pthread_t t;
1367  time_t start;
1368  struct sockaddr_in sin;
1369  int fd;
1371  char outbuf[SKINNY_MAX_PACKET];
1374 };
1375 
1376 static struct ast_channel *skinny_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause);
1378 
1379 static int skinny_devicestate(void *data);
1380 static int skinny_call(struct ast_channel *ast, char *dest, int timeout);
1381 static int skinny_hangup(struct ast_channel *ast);
1382 static int skinny_answer(struct ast_channel *ast);
1383 static struct ast_frame *skinny_read(struct ast_channel *ast);
1384 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame);
1385 static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
1386 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
1387 static int skinny_senddigit_begin(struct ast_channel *ast, char digit);
1388 static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
1389 static void mwi_event_cb(const struct ast_event *event, void *userdata);
1390 static int skinny_reload(void);
1391 
1392 static const struct ast_channel_tech skinny_tech = {
1393  .type = "Skinny",
1394  .description = tdesc,
1395  .capabilities = AST_FORMAT_AUDIO_MASK,
1397  .requester = skinny_request,
1398  .devicestate = skinny_devicestate,
1399  .call = skinny_call,
1400  .hangup = skinny_hangup,
1401  .answer = skinny_answer,
1402  .read = skinny_read,
1403  .write = skinny_write,
1404  .indicate = skinny_indicate,
1405  .fixup = skinny_fixup,
1406  .send_digit_begin = skinny_senddigit_begin,
1407  .send_digit_end = skinny_senddigit_end,
1408  .bridge = ast_rtp_instance_bridge,
1409 };
1410 
1411 static int skinny_extensionstate_cb(char *context, char* exten, int state, void *data);
1412 static int skinny_transfer(struct skinny_subchannel *sub);
1413 
1415 {
1416  struct skinny_device *d = s->device;
1417  struct skinny_addon *a;
1418  int i;
1419 
1420  switch (d->type) {
1422  case SKINNY_DEVICE_30VIP:
1423  /* 13 rows, 2 columns */
1424  for (i = 0; i < 4; i++)
1425  (btn++)->buttonDefinition = BT_CUST_LINE;
1426  (btn++)->buttonDefinition = BT_REDIAL;
1427  (btn++)->buttonDefinition = BT_VOICEMAIL;
1428  (btn++)->buttonDefinition = BT_CALLPARK;
1429  (btn++)->buttonDefinition = BT_FORWARDALL;
1430  (btn++)->buttonDefinition = BT_CONFERENCE;
1431  for (i = 0; i < 4; i++)
1432  (btn++)->buttonDefinition = BT_NONE;
1433  for (i = 0; i < 13; i++)
1434  (btn++)->buttonDefinition = BT_SPEEDDIAL;
1435 
1436  break;
1438  case SKINNY_DEVICE_12SP:
1439  case SKINNY_DEVICE_12:
1440  /* 6 rows, 2 columns */
1441  for (i = 0; i < 2; i++)
1442  (btn++)->buttonDefinition = BT_CUST_LINE;
1443  for (i = 0; i < 4; i++)
1444  (btn++)->buttonDefinition = BT_SPEEDDIAL;
1445  (btn++)->buttonDefinition = BT_HOLD;
1446  (btn++)->buttonDefinition = BT_REDIAL;
1447  (btn++)->buttonDefinition = BT_TRANSFER;
1448  (btn++)->buttonDefinition = BT_FORWARDALL;
1449  (btn++)->buttonDefinition = BT_CALLPARK;
1450  (btn++)->buttonDefinition = BT_VOICEMAIL;
1451  break;
1452  case SKINNY_DEVICE_7910:
1453  (btn++)->buttonDefinition = BT_LINE;
1454  (btn++)->buttonDefinition = BT_HOLD;
1455  (btn++)->buttonDefinition = BT_TRANSFER;
1456  (btn++)->buttonDefinition = BT_DISPLAY;
1457  (btn++)->buttonDefinition = BT_VOICEMAIL;
1458  (btn++)->buttonDefinition = BT_CONFERENCE;
1459  (btn++)->buttonDefinition = BT_FORWARDALL;
1460  for (i = 0; i < 2; i++)
1461  (btn++)->buttonDefinition = BT_SPEEDDIAL;
1462  (btn++)->buttonDefinition = BT_REDIAL;
1463  break;
1464  case SKINNY_DEVICE_7960:
1465  case SKINNY_DEVICE_7961:
1466  case SKINNY_DEVICE_7961GE:
1467  case SKINNY_DEVICE_7962:
1468  case SKINNY_DEVICE_7965:
1469  for (i = 0; i < 6; i++)
1470  (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
1471  break;
1472  case SKINNY_DEVICE_7940:
1473  case SKINNY_DEVICE_7941:
1474  case SKINNY_DEVICE_7941GE:
1475  case SKINNY_DEVICE_7942:
1476  case SKINNY_DEVICE_7945:
1477  for (i = 0; i < 2; i++)
1478  (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
1479  break;
1480  case SKINNY_DEVICE_7935:
1481  case SKINNY_DEVICE_7936:
1482  for (i = 0; i < 2; i++)
1483  (btn++)->buttonDefinition = BT_LINE;
1484  break;
1485  case SKINNY_DEVICE_ATA186:
1486  (btn++)->buttonDefinition = BT_LINE;
1487  break;
1488  case SKINNY_DEVICE_7970:
1489  case SKINNY_DEVICE_7971:
1490  case SKINNY_DEVICE_7975:
1491  case SKINNY_DEVICE_CIPC:
1492  for (i = 0; i < 8; i++)
1493  (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
1494  break;
1495  case SKINNY_DEVICE_7985:
1496  /* XXX I have no idea what the buttons look like on these. */
1497  ast_log(LOG_WARNING, "Unsupported device type '%d (7985)' found.\n", d->type);
1498  break;
1499  case SKINNY_DEVICE_7912:
1500  case SKINNY_DEVICE_7911:
1501  case SKINNY_DEVICE_7905:
1502  (btn++)->buttonDefinition = BT_LINE;
1503  (btn++)->buttonDefinition = BT_HOLD;
1504  break;
1505  case SKINNY_DEVICE_7920:
1506  /* XXX I don't know if this is right. */
1507  for (i = 0; i < 4; i++)
1508  (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
1509  break;
1510  case SKINNY_DEVICE_7921:
1511  for (i = 0; i < 6; i++)
1512  (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
1513  break;
1514  case SKINNY_DEVICE_7902:
1515  ast_log(LOG_WARNING, "Unsupported device type '%d (7902)' found.\n", d->type);
1516  break;
1517  case SKINNY_DEVICE_7906:
1518  ast_log(LOG_WARNING, "Unsupported device type '%d (7906)' found.\n", d->type);
1519  break;
1520  case SKINNY_DEVICE_7931:
1521  ast_log(LOG_WARNING, "Unsupported device type '%d (7931)' found.\n", d->type);
1522  break;
1523  case SKINNY_DEVICE_7937:
1524  ast_log(LOG_WARNING, "Unsupported device type '%d (7937)' found.\n", d->type);
1525  break;
1526  case SKINNY_DEVICE_7914:
1527  ast_log(LOG_WARNING, "Unsupported device type '%d (7914)' found. Expansion module registered by itself?\n", d->type);
1528  break;
1531  ast_log(LOG_WARNING, "Unsupported device type '%d (SCCP gateway)' found.\n", d->type);
1532  break;
1533  default:
1534  ast_log(LOG_WARNING, "Unknown device type '%d' found.\n", d->type);
1535  break;
1536  }
1537 
1538  AST_LIST_LOCK(&d->addons);
1539  AST_LIST_TRAVERSE(&d->addons, a, list) {
1540  if (!strcasecmp(a->type, "7914")) {
1541  for (i = 0; i < 14; i++)
1542  (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
1543  } else {
1544  ast_log(LOG_WARNING, "Unknown addon type '%s' found. Skipping.\n", a->type);
1545  }
1546  }
1547  AST_LIST_UNLOCK(&d->addons);
1548 
1549  return btn;
1550 }
1551 
1552 static struct skinny_req *req_alloc(size_t size, int response_message)
1553 {
1554  struct skinny_req *req;
1555 
1556  if (!(req = ast_calloc(1, skinny_header_size + size + 4)))
1557  return NULL;
1558 
1559  req->len = htolel(size+4);
1560  req->e = htolel(response_message);
1561 
1562  return req;
1563 }
1564 
1565 static struct skinny_line *find_line_by_instance(struct skinny_device *d, int instance)
1566 {
1567  struct skinny_line *l;
1568 
1569  /*Dialing from on hook or on a 7920 uses instance 0 in requests
1570  but we need to start looking at instance 1 */
1571 
1572  if (!instance)
1573  instance = 1;
1574 
1575  AST_LIST_TRAVERSE(&d->lines, l, list){
1576  if (l->instance == instance)
1577  break;
1578  }
1579 
1580  if (!l) {
1581  ast_log(LOG_WARNING, "Could not find line with instance '%d' on device '%s'\n", instance, d->name);
1582  }
1583  return l;
1584 }
1585 
1586 static struct skinny_line *find_line_by_name(const char *dest)
1587 {
1588  struct skinny_line *l;
1589  struct skinny_line *tmpl = NULL;
1590  struct skinny_device *d;
1591  char line[256];
1592  char *at;
1593  char *device;
1594  int checkdevice = 0;
1595 
1596  ast_copy_string(line, dest, sizeof(line));
1597  at = strchr(line, '@');
1598  if (at)
1599  *at++ = '\0';
1600  device = at;
1601 
1602  if (!ast_strlen_zero(device))
1603  checkdevice = 1;
1604 
1606  AST_LIST_TRAVERSE(&devices, d, list){
1607  if (checkdevice && tmpl)
1608  break;
1609  else if (!checkdevice) {
1610  /* This is a match, since we're checking for line on every device. */
1611  } else if (!strcasecmp(d->name, device)) {
1612  if (skinnydebug)
1613  ast_verb(2, "Found device: %s\n", d->name);
1614  } else
1615  continue;
1616 
1617  /* Found the device (or we don't care which device) */
1618  AST_LIST_TRAVERSE(&d->lines, l, list){
1619  /* Search for the right line */
1620  if (!strcasecmp(l->name, line)) {
1621  if (tmpl) {
1622  ast_verb(2, "Ambiguous line name: %s\n", line);
1624  return NULL;
1625  } else
1626  tmpl = l;
1627  }
1628  }
1629  }
1631  return tmpl;
1632 }
1633 
1634 /*!
1635  * implement the setvar config line
1636  */
1637 static struct ast_variable *add_var(const char *buf, struct ast_variable *list)
1638 {
1639  struct ast_variable *tmpvar = NULL;
1640  char *varname = ast_strdupa(buf), *varval = NULL;
1641 
1642  if ((varval = strchr(varname,'='))) {
1643  *varval++ = '\0';
1644  if ((tmpvar = ast_variable_new(varname, varval, ""))) {
1645  tmpvar->next = list;
1646  list = tmpvar;
1647  }
1648  }
1649  return list;
1650 }
1651 
1652 /* It's quicker/easier to find the subchannel when we know the instance number too */
1653 static struct skinny_subchannel *find_subchannel_by_instance_reference(struct skinny_device *d, int instance, int reference)
1654 {
1655  struct skinny_line *l = find_line_by_instance(d, instance);
1656  struct skinny_subchannel *sub;
1657 
1658  if (!l) {
1659  return NULL;
1660  }
1661 
1662  /* 7920 phones set call reference to 0, so use the first
1663  sub-channel on the list.
1664  This MIGHT need more love to be right */
1665  if (!reference)
1666  sub = AST_LIST_FIRST(&l->sub);
1667  else {
1668  AST_LIST_TRAVERSE(&l->sub, sub, list) {
1669  if (sub->callid == reference)
1670  break;
1671  }
1672  }
1673  if (!sub) {
1674  ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s'\n", reference, d->name);
1675  }
1676  return sub;
1677 }
1678 
1679 /* Find the subchannel when we only have the callid - this shouldn't happen often */
1680 static struct skinny_subchannel *find_subchannel_by_reference(struct skinny_device *d, int reference)
1681 {
1682  struct skinny_line *l;
1683  struct skinny_subchannel *sub = NULL;
1684 
1685  AST_LIST_TRAVERSE(&d->lines, l, list){
1686  AST_LIST_TRAVERSE(&l->sub, sub, list){
1687  if (sub->callid == reference)
1688  break;
1689  }
1690  if (sub)
1691  break;
1692  }
1693 
1694  if (!l) {
1695  ast_log(LOG_WARNING, "Could not find any lines that contained a subchannel with reference '%d' on device '%s'\n", reference, d->name);
1696  } else {
1697  if (!sub) {
1698  ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s@%s'\n", reference, l->name, d->name);
1699  }
1700  }
1701  return sub;
1702 }
1703 
1705 {
1706  struct skinny_speeddial *sd;
1707 
1708  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
1709  if (sd->isHint == isHint && sd->instance == instance)
1710  break;
1711  }
1712 
1713  if (!sd) {
1714  ast_log(LOG_WARNING, "Could not find speeddial with instance '%d' on device '%s'\n", instance, d->name);
1715  }
1716  return sd;
1717 }
1718 
1719 static format_t codec_skinny2ast(enum skinny_codecs skinnycodec)
1720 {
1721  switch (skinnycodec) {
1722  case SKINNY_CODEC_ALAW:
1723  return AST_FORMAT_ALAW;
1724  case SKINNY_CODEC_ULAW:
1725  return AST_FORMAT_ULAW;
1726  case SKINNY_CODEC_G723_1:
1727  return AST_FORMAT_G723_1;
1728  case SKINNY_CODEC_G729A:
1729  return AST_FORMAT_G729A;
1730  case SKINNY_CODEC_G726_32:
1731  return AST_FORMAT_G726_AAL2; /* XXX Is this right? */
1732  case SKINNY_CODEC_H261:
1733  return AST_FORMAT_H261;
1734  case SKINNY_CODEC_H263:
1735  return AST_FORMAT_H263;
1736  default:
1737  return 0;
1738  }
1739 }
1740 
1741 static int codec_ast2skinny(format_t astcodec)
1742 {
1743  switch (astcodec) {
1744  case AST_FORMAT_ALAW:
1745  return SKINNY_CODEC_ALAW;
1746  case AST_FORMAT_ULAW:
1747  return SKINNY_CODEC_ULAW;
1748  case AST_FORMAT_G723_1:
1749  return SKINNY_CODEC_G723_1;
1750  case AST_FORMAT_G729A:
1751  return SKINNY_CODEC_G729A;
1752  case AST_FORMAT_G726_AAL2: /* XXX Is this right? */
1753  return SKINNY_CODEC_G726_32;
1754  case AST_FORMAT_H261:
1755  return SKINNY_CODEC_H261;
1756  case AST_FORMAT_H263:
1757  return SKINNY_CODEC_H263;
1758  default:
1759  return 0;
1760  }
1761 }
1762 
1763 static int set_callforwards(struct skinny_line *l, const char *cfwd, int cfwdtype)
1764 {
1765  if (!l)
1766  return 0;
1767 
1768  if (!ast_strlen_zero(cfwd)) {
1769  if (cfwdtype & SKINNY_CFWD_ALL) {
1770  l->cfwdtype |= SKINNY_CFWD_ALL;
1771  ast_copy_string(l->call_forward_all, cfwd, sizeof(l->call_forward_all));
1772  }
1773  if (cfwdtype & SKINNY_CFWD_BUSY) {
1774  l->cfwdtype |= SKINNY_CFWD_BUSY;
1775  ast_copy_string(l->call_forward_busy, cfwd, sizeof(l->call_forward_busy));
1776  }
1777  if (cfwdtype & SKINNY_CFWD_NOANSWER) {
1778  l->cfwdtype |= SKINNY_CFWD_NOANSWER;
1779  ast_copy_string(l->call_forward_noanswer, cfwd, sizeof(l->call_forward_noanswer));
1780  }
1781  } else {
1782  if (cfwdtype & SKINNY_CFWD_ALL) {
1783  l->cfwdtype &= ~SKINNY_CFWD_ALL;
1784  memset(l->call_forward_all, 0, sizeof(l->call_forward_all));
1785  }
1786  if (cfwdtype & SKINNY_CFWD_BUSY) {
1787  l->cfwdtype &= ~SKINNY_CFWD_BUSY;
1788  memset(l->call_forward_busy, 0, sizeof(l->call_forward_busy));
1789  }
1790  if (cfwdtype & SKINNY_CFWD_NOANSWER) {
1791  l->cfwdtype &= ~SKINNY_CFWD_NOANSWER;
1792  memset(l->call_forward_noanswer, 0, sizeof(l->call_forward_noanswer));
1793  }
1794  }
1795  return l->cfwdtype;
1796 }
1797 
1798 static void cleanup_stale_contexts(char *new, char *old)
1799 {
1800  char *oldcontext, *newcontext, *stalecontext, *stringp, newlist[AST_MAX_CONTEXT];
1801 
1802  while ((oldcontext = strsep(&old, "&"))) {
1803  stalecontext = '\0';
1804  ast_copy_string(newlist, new, sizeof(newlist));
1805  stringp = newlist;
1806  while ((newcontext = strsep(&stringp, "&"))) {
1807  if (strcmp(newcontext, oldcontext) == 0) {
1808  /* This is not the context you're looking for */
1809  stalecontext = '\0';
1810  break;
1811  } else if (strcmp(newcontext, oldcontext)) {
1812  stalecontext = oldcontext;
1813  }
1814 
1815  }
1816  if (stalecontext)
1817  ast_context_destroy(ast_context_find(stalecontext), "Skinny");
1818  }
1819 }
1820 
1821 static void register_exten(struct skinny_line *l)
1822 {
1823  char multi[256];
1824  char *stringp, *ext, *context;
1825 
1826  if (ast_strlen_zero(regcontext))
1827  return;
1828 
1829  ast_copy_string(multi, S_OR(l->regexten, l->name), sizeof(multi));
1830  stringp = multi;
1831  while ((ext = strsep(&stringp, "&"))) {
1832  if ((context = strchr(ext, '@'))) {
1833  *context++ = '\0'; /* split ext@context */
1834  if (!ast_context_find(context)) {
1835  ast_log(LOG_WARNING, "Context %s must exist in regcontext= in skinny.conf!\n", context);
1836  continue;
1837  }
1838  } else {
1839  context = regcontext;
1840  }
1841  ast_add_extension(context, 1, ext, 1, NULL, NULL, "Noop",
1842  ast_strdup(l->name), ast_free_ptr, "Skinny");
1843  }
1844 }
1845 
1846 static void unregister_exten(struct skinny_line *l)
1847 {
1848  char multi[256];
1849  char *stringp, *ext, *context;
1850 
1851  if (ast_strlen_zero(regcontext))
1852  return;
1853 
1854  ast_copy_string(multi, S_OR(l->regexten, l->name), sizeof(multi));
1855  stringp = multi;
1856  while ((ext = strsep(&stringp, "&"))) {
1857  if ((context = strchr(ext, '@'))) {
1858  *context++ = '\0'; /* split ext@context */
1859  if (!ast_context_find(context)) {
1860  ast_log(LOG_WARNING, "Context %s must exist in regcontext= in skinny.conf!\n", context);
1861  continue;
1862  }
1863  } else {
1864  context = regcontext;
1865  }
1866  ast_context_remove_extension(context, ext, 1, NULL);
1867  }
1868 }
1869 
1870 static int skinny_register(struct skinny_req *req, struct skinnysession *s)
1871 {
1872  struct skinny_device *d;
1873  struct skinny_line *l;
1874  struct skinny_speeddial *sd;
1875  struct sockaddr_in sin;
1876  socklen_t slen;
1877  int instance;
1878 
1880  AST_LIST_TRAVERSE(&devices, d, list){
1881  struct ast_sockaddr addr;
1882  ast_sockaddr_from_sin(&addr, &s->sin);
1883  if (!strcasecmp(req->data.reg.name, d->id)
1884  && ast_apply_ha(d->ha, &addr)) {
1885  s->device = d;
1886  d->type = letohl(req->data.reg.type);
1887  if (ast_strlen_zero(d->version_id)) {
1888  ast_copy_string(d->version_id, version_id, sizeof(d->version_id));
1889  }
1890  d->registered = 1;
1891  d->session = s;
1892 
1893  slen = sizeof(sin);
1894  if (getsockname(s->fd, (struct sockaddr *)&sin, &slen)) {
1895  ast_log(LOG_WARNING, "Cannot get socket name\n");
1896  sin.sin_addr = __ourip;
1897  }
1898  d->ourip = sin.sin_addr;
1899 
1900  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
1902  }
1903  instance = 0;
1904  AST_LIST_TRAVERSE(&d->lines, l, list) {
1905  instance++;
1906  }
1907  AST_LIST_TRAVERSE(&d->lines, l, list) {
1908  /* FIXME: All sorts of issues will occur if this line is already connected to a device */
1909  if (l->device) {
1910  manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Rejected\r\nCause: LINE_ALREADY_CONNECTED\r\n", l->name, l->device->name);
1911  ast_verb(1, "Line %s already connected to %s. Not connecting to %s.\n", l->name, l->device->name, d->name);
1912  } else {
1913  l->device = d;
1914  l->capability = l->confcapability & d->capability;
1915  l->prefs = l->confprefs;
1916  if (!l->prefs.order[0]) {
1917  l->prefs = d->confprefs;
1918  }
1919  /* l->capability = d->capability;
1920  l->prefs = d->prefs; */
1921  l->instance = instance;
1922  l->newmsgs = ast_app_has_voicemail(l->mailbox, NULL);
1923  set_callforwards(l, NULL, 0);
1924  manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Registered\r\n", l->name, d->name);
1925  register_exten(l);
1926  /* initialize MWI on line and device */
1927  mwi_event_cb(0, l);
1928  ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
1929  }
1930  --instance;
1931  }
1932  break;
1933  }
1934  }
1936  if (!d) {
1937  return 0;
1938  }
1939  return 1;
1940 }
1941 
1942 static int skinny_unregister(struct skinny_req *req, struct skinnysession *s)
1943 {
1944  struct skinny_device *d;
1945  struct skinny_line *l;
1946  struct skinny_speeddial *sd;
1947 
1948  d = s->device;
1949 
1950  if (d) {
1951  d->session = NULL;
1952  d->registered = 0;
1953 
1954  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
1955  if (sd->stateid > -1)
1956  ast_extension_state_del(sd->stateid, NULL);
1957  }
1958  AST_LIST_TRAVERSE(&d->lines, l, list) {
1959  if (l->device == d) {
1960  l->device = NULL;
1961  l->capability = 0;
1962  ast_parse_allow_disallow(&l->prefs, &l->capability, "all", 0);
1963  l->instance = 0;
1964  manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Unregistered\r\n", l->name, d->name);
1965  unregister_exten(l);
1966  ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
1967  }
1968  }
1969  }
1970 
1971  return -1; /* main loop will destroy the session */
1972 }
1973 
1974 #ifdef SKINNY_DEVMODE
1975 static char *message2str(int type)
1976 {
1977  char *tmp;
1978 
1979  switch (letohl(type)) {
1980  case KEEP_ALIVE_MESSAGE:
1981  return "KEEP_ALIVE_MESSAGE";
1982  case REGISTER_MESSAGE:
1983  return "REGISTER_MESSAGE";
1984  case IP_PORT_MESSAGE:
1985  return "IP_PORT_MESSAGE";
1986  case KEYPAD_BUTTON_MESSAGE:
1987  return "KEYPAD_BUTTON_MESSAGE";
1988  case ENBLOC_CALL_MESSAGE:
1989  return "ENBLOC_CALL_MESSAGE";
1990  case STIMULUS_MESSAGE:
1991  return "STIMULUS_MESSAGE";
1992  case OFFHOOK_MESSAGE:
1993  return "OFFHOOK_MESSAGE";
1994  case ONHOOK_MESSAGE:
1995  return "ONHOOK_MESSAGE";
1997  return "CAPABILITIES_RES_MESSAGE";
1999  return "SPEED_DIAL_STAT_REQ_MESSAGE";
2001  return "LINE_STATE_REQ_MESSAGE";
2002  case TIME_DATE_REQ_MESSAGE:
2003  return "TIME_DATE_REQ_MESSAGE";
2005  return "BUTTON_TEMPLATE_REQ_MESSAGE";
2006  case VERSION_REQ_MESSAGE:
2007  return "VERSION_REQ_MESSAGE";
2009  return "SERVER_REQUEST_MESSAGE";
2010  case ALARM_MESSAGE:
2011  return "ALARM_MESSAGE";
2013  return "OPEN_RECEIVE_CHANNEL_ACK_MESSAGE";
2015  return "SOFT_KEY_SET_REQ_MESSAGE";
2017  return "SOFT_KEY_EVENT_MESSAGE";
2018  case UNREGISTER_MESSAGE:
2019  return "UNREGISTER_MESSAGE";
2021  return "SOFT_KEY_TEMPLATE_REQ_MESSAGE";
2023  return "HEADSET_STATUS_MESSAGE";
2025  return "REGISTER_AVAILABLE_LINES_MESSAGE";
2026  case REGISTER_ACK_MESSAGE:
2027  return "REGISTER_ACK_MESSAGE";
2028  case START_TONE_MESSAGE:
2029  return "START_TONE_MESSAGE";
2030  case STOP_TONE_MESSAGE:
2031  return "STOP_TONE_MESSAGE";
2032  case SET_RINGER_MESSAGE:
2033  return "SET_RINGER_MESSAGE";
2034  case SET_LAMP_MESSAGE:
2035  return "SET_LAMP_MESSAGE";
2036  case SET_SPEAKER_MESSAGE:
2037  return "SET_SPEAKER_MESSAGE";
2039  return "SET_MICROPHONE_MESSAGE";
2041  return "START_MEDIA_TRANSMISSION_MESSAGE";
2043  return "STOP_MEDIA_TRANSMISSION_MESSAGE";
2044  case CALL_INFO_MESSAGE:
2045  return "CALL_INFO_MESSAGE";
2046  case FORWARD_STAT_MESSAGE:
2047  return "FORWARD_STAT_MESSAGE";
2049  return "SPEED_DIAL_STAT_RES_MESSAGE";
2050  case LINE_STAT_RES_MESSAGE:
2051  return "LINE_STAT_RES_MESSAGE";
2053  return "DEFINETIMEDATE_MESSAGE";
2055  return "BUTTON_TEMPLATE_RES_MESSAGE";
2056  case VERSION_RES_MESSAGE:
2057  return "VERSION_RES_MESSAGE";
2058  case DISPLAYTEXT_MESSAGE:
2059  return "DISPLAYTEXT_MESSAGE";
2060  case CLEAR_NOTIFY_MESSAGE:
2061  return "CLEAR_NOTIFY_MESSAGE";
2062  case CLEAR_DISPLAY_MESSAGE:
2063  return "CLEAR_DISPLAY_MESSAGE";
2065  return "CAPABILITIES_REQ_MESSAGE";
2066  case REGISTER_REJ_MESSAGE:
2067  return "REGISTER_REJ_MESSAGE";
2068  case SERVER_RES_MESSAGE:
2069  return "SERVER_RES_MESSAGE";
2070  case RESET_MESSAGE:
2071  return "RESET_MESSAGE";
2073  return "KEEP_ALIVE_ACK_MESSAGE";
2075  return "OPEN_RECEIVE_CHANNEL_MESSAGE";
2077  return "CLOSE_RECEIVE_CHANNEL_MESSAGE";
2079  return "SOFT_KEY_TEMPLATE_RES_MESSAGE";
2081  return "SOFT_KEY_SET_RES_MESSAGE";
2083  return "SELECT_SOFT_KEYS_MESSAGE";
2084  case CALL_STATE_MESSAGE:
2085  return "CALL_STATE_MESSAGE";
2087  return "DISPLAY_PROMPT_STATUS_MESSAGE";
2088  case CLEAR_PROMPT_MESSAGE:
2089  return "CLEAR_PROMPT_MESSAGE";
2091  return "DISPLAY_NOTIFY_MESSAGE";
2093  return "ACTIVATE_CALL_PLANE_MESSAGE";
2094  case DIALED_NUMBER_MESSAGE:
2095  return "DIALED_NUMBER_MESSAGE";
2096  default:
2097  if (!(tmp = ast_threadstorage_get(&message2str_threadbuf, MESSAGE2STR_BUFSIZE)))
2098  return "Unknown";
2099  snprintf(tmp, MESSAGE2STR_BUFSIZE, "UNKNOWN_MESSAGE-%d", type);
2100  return tmp;
2101  }
2102 }
2103 #endif
2104 
2105 static int transmit_response(struct skinny_device *d, struct skinny_req *req)
2106 {
2107  struct skinnysession *s = d->session;
2108  int res = 0;
2109 
2110  if (!s) {
2111  ast_log(LOG_WARNING, "Asked to transmit to a non-existent session!\n");
2112  return -1;
2113  }
2114 
2115  ast_mutex_lock(&s->lock);
2116 
2117  SKINNY_DEVONLY(if (skinnydebug>1) ast_verb(4, "Transmitting %s to %s\n", message2str(req->e), d->name);)
2118 
2119  if ((letohl(req->len) > SKINNY_MAX_PACKET) || (letohl(req->len) < 0)) {
2120  ast_log(LOG_WARNING, "transmit_response: the length of the request (%d) is out of bounds (%d)\n", letohl(req->len), SKINNY_MAX_PACKET);
2121  ast_mutex_unlock(&s->lock);
2122  return -1;
2123  }
2124 
2125  memset(s->outbuf, 0, sizeof(s->outbuf));
2126  memcpy(s->outbuf, req, skinny_header_size);
2127  memcpy(s->outbuf+skinny_header_size, &req->data, letohl(req->len));
2128 
2129  res = write(s->fd, s->outbuf, letohl(req->len)+8);
2130 
2131  if (res != letohl(req->len)+8) {
2132  ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, letohl(req->len)+8, strerror(errno));
2133  if (res == -1) {
2134  if (skinnydebug)
2135  ast_log(LOG_WARNING, "Transmit: Skinny Client was lost, unregistering\n");
2136  skinny_unregister(NULL, s);
2137  }
2138 
2139  }
2140 
2141  ast_free(req);
2142  ast_mutex_unlock(&s->lock);
2143  return 1;
2144 }
2145 
2146 static void transmit_speaker_mode(struct skinny_device *d, int mode)
2147 {
2148  struct skinny_req *req;
2149 
2150  if (!(req = req_alloc(sizeof(struct set_speaker_message), SET_SPEAKER_MESSAGE)))
2151  return;
2152 
2153  req->data.setspeaker.mode = htolel(mode);
2154  transmit_response(d, req);
2155 }
2156 /*
2157 static void transmit_microphone_mode(struct skinny_device *d, int mode)
2158 {
2159  struct skinny_req *req;
2160 
2161  if (!(req = req_alloc(sizeof(struct set_microphone_message), SET_MICROPHONE_MESSAGE)))
2162  return;
2163 
2164  req->data.setmicrophone.mode = htolel(mode);
2165  transmit_response(d, req);
2166 }
2167 */
2168 
2169 static void transmit_callinfo(struct skinny_device *d, const char *fromname, const char *fromnum, const char *toname, const char *tonum, int instance, int callid, int calltype)
2170 {
2171  struct skinny_req *req;
2172 
2173  /* We should not be able to get here without a device */
2174  if (!d)
2175  return;
2176 
2177  if (!(req = req_alloc(sizeof(struct call_info_message), CALL_INFO_MESSAGE)))
2178  return;
2179 
2180  if (skinnydebug)
2181  ast_verb(1, "Setting Callinfo to %s(%s) from %s(%s) on %s(%d)\n", fromname, fromnum, toname, tonum, d->name, instance);
2182 
2183  if (fromname) {
2185  }
2186  if (fromnum) {
2187  ast_copy_string(req->data.callinfo.callingParty, fromnum, sizeof(req->data.callinfo.callingParty));
2188  }
2189  if (toname) {
2191  }
2192  if (tonum) {
2193  ast_copy_string(req->data.callinfo.calledParty, tonum, sizeof(req->data.callinfo.calledParty));
2194  }
2195  req->data.callinfo.instance = htolel(instance);
2196  req->data.callinfo.reference = htolel(callid);
2197  req->data.callinfo.type = htolel(calltype);
2198  transmit_response(d, req);
2199 }
2200 
2201 static void transmit_connect(struct skinny_device *d, struct skinny_subchannel *sub)
2202 {
2203  struct skinny_req *req;
2204  struct skinny_line *l = sub->parent;
2205  struct ast_format_list fmt;
2206 
2208  return;
2209 
2210  fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability));
2211 
2216  req->data.openreceivechannel.echo = htolel(0);
2218  transmit_response(d, req);
2219 }
2220 
2221 static void transmit_start_tone(struct skinny_device *d, int tone, int instance, int reference)
2222 {
2223  struct skinny_req *req;
2224  if (!(req = req_alloc(sizeof(struct start_tone_message), START_TONE_MESSAGE)))
2225  return;
2226  req->data.starttone.tone = htolel(tone);
2227  req->data.starttone.instance = htolel(instance);
2228  req->data.starttone.reference = htolel(reference);
2229  transmit_response(d, req);
2230 }
2231 
2232 static void transmit_stop_tone(struct skinny_device *d, int instance, int reference)
2233 {
2234  struct skinny_req *req;
2235  if (!(req = req_alloc(sizeof(struct stop_tone_message), STOP_TONE_MESSAGE)))
2236  return;
2237  req->data.stoptone.instance = htolel(instance);
2238  req->data.stoptone.reference = htolel(reference);
2239  transmit_response(d, req);
2240 }
2241 
2242 static void transmit_selectsoftkeys(struct skinny_device *d, int instance, int callid, int softkey)
2243 {
2244  struct skinny_req *req;
2245 
2246  if (!(req = req_alloc(sizeof(struct select_soft_keys_message), SELECT_SOFT_KEYS_MESSAGE)))
2247  return;
2248 
2249  req->data.selectsoftkey.instance = htolel(instance);
2250  req->data.selectsoftkey.reference = htolel(callid);
2251  req->data.selectsoftkey.softKeySetIndex = htolel(softkey);
2252  req->data.selectsoftkey.validKeyMask = htolel(0xFFFFFFFF);
2253  transmit_response(d, req);
2254 }
2255 
2256 static void transmit_lamp_indication(struct skinny_device *d, int stimulus, int instance, int indication)
2257 {
2258  struct skinny_req *req;
2259 
2260  if (!(req = req_alloc(sizeof(struct set_lamp_message), SET_LAMP_MESSAGE)))
2261  return;
2262 
2263  req->data.setlamp.stimulus = htolel(stimulus);
2264  req->data.setlamp.stimulusInstance = htolel(instance);
2265  req->data.setlamp.deviceStimulus = htolel(indication);
2266  transmit_response(d, req);
2267 }
2268 
2269 static void transmit_ringer_mode(struct skinny_device *d, int mode)
2270 {
2271  struct skinny_req *req;
2272 
2273  if (skinnydebug)
2274  ast_verb(1, "Setting ringer mode to '%d'.\n", mode);
2275 
2276  if (!(req = req_alloc(sizeof(struct set_ringer_message), SET_RINGER_MESSAGE)))
2277  return;
2278 
2279  req->data.setringer.ringerMode = htolel(mode);
2280  /* XXX okay, I don't quite know what this is, but here's what happens (on a 7960).
2281  Note: The phone will always show as ringing on the display.
2282 
2283  1: phone will audibly ring over and over
2284  2: phone will audibly ring only once
2285  any other value, will NOT cause the phone to audibly ring
2286  */
2287  req->data.setringer.unknown1 = htolel(1);
2288  /* XXX the value here doesn't seem to change anything. Must be higher than 0.
2289  Perhaps a packet capture can shed some light on this. */
2290  req->data.setringer.unknown2 = htolel(1);
2291  transmit_response(d, req);
2292 }
2293 
2294 static void transmit_clear_display_message(struct skinny_device *d, int instance, int reference)
2295 {
2296  struct skinny_req *req;
2297  if (!(req = req_alloc(0, CLEAR_DISPLAY_MESSAGE)))
2298  return;
2299 
2300  //what do we want hear CLEAR_DISPLAY_MESSAGE or CLEAR_PROMPT_STATUS???
2301  //if we are clearing the display, it appears there is no instance and refernece info (size 0)
2302  //req->data.clearpromptstatus.lineInstance = instance;
2303  //req->data.clearpromptstatus.callReference = reference;
2304 
2305  if (skinnydebug)
2306  ast_verb(1, "Clearing Display\n");
2307  transmit_response(d, req);
2308 }
2309 
2310 /* This function is not currently used, but will be (wedhorn)*/
2311 /* static void transmit_display_message(struct skinny_device *d, const char *text, int instance, int reference)
2312 {
2313  struct skinny_req *req;
2314 
2315  if (text == 0) {
2316  ast_verb(1, "Bug, Asked to display empty message\n");
2317  return;
2318  }
2319 
2320  if (!(req = req_alloc(sizeof(struct displaytext_message), DISPLAYTEXT_MESSAGE)))
2321  return;
2322 
2323  ast_copy_string(req->data.displaytext.text, text, sizeof(req->data.displaytext.text));
2324  if (skinnydebug)
2325  ast_verb(1, "Displaying message '%s'\n", req->data.displaytext.text);
2326  transmit_response(d, req);
2327 } */
2328 
2329 static void transmit_displaynotify(struct skinny_device *d, const char *text, int t)
2330 {
2331  struct skinny_req *req;
2332 
2333  if (!(req = req_alloc(sizeof(struct display_notify_message), DISPLAY_NOTIFY_MESSAGE)))
2334  return;
2335 
2338 
2339  if (skinnydebug)
2340  ast_verb(1, "Displaying notify '%s'\n", text);
2341 
2342  transmit_response(d, req);
2343 }
2344 
2345 static void transmit_displaypromptstatus(struct skinny_device *d, const char *text, int t, int instance, int callid)
2346 {
2347  struct skinny_req *req;
2348 
2350  return;
2351 
2354  req->data.displaypromptstatus.lineInstance = htolel(instance);
2356 
2357  if (skinnydebug)
2358  ast_verb(1, "Displaying Prompt Status '%s'\n", text);
2359 
2360  transmit_response(d, req);
2361 }
2362 
2363 static void transmit_clearpromptmessage(struct skinny_device *d, int instance, int callid)
2364 {
2365  struct skinny_req *req;
2366 
2367  if (!(req = req_alloc(sizeof(struct clear_prompt_message), CLEAR_PROMPT_MESSAGE)))
2368  return;
2369 
2370  req->data.clearpromptstatus.lineInstance = htolel(instance);
2371  req->data.clearpromptstatus.callReference = htolel(callid);
2372 
2373  if (skinnydebug)
2374  ast_verb(1, "Clearing Prompt\n");
2375 
2376  transmit_response(d, req);
2377 }
2378 
2379 static void transmit_dialednumber(struct skinny_device *d, const char *text, int instance, int callid)
2380 {
2381  struct skinny_req *req;
2382 
2383  if (!(req = req_alloc(sizeof(struct dialed_number_message), DIALED_NUMBER_MESSAGE)))
2384  return;
2385 
2387  req->data.dialednumber.lineInstance = htolel(instance);
2388  req->data.dialednumber.callReference = htolel(callid);
2389 
2390  transmit_response(d, req);
2391 }
2392 
2394 {
2395  struct skinny_req *req;
2396 
2398  return;
2399 
2402  transmit_response(d, req);
2403 }
2404 
2406 {
2407  struct skinny_req *req;
2408 
2410  return;
2411 
2412  req->data.stopmedia.conferenceId = htolel(0);
2414  transmit_response(d, req);
2415 }
2416 
2417 static void transmit_startmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub, struct sockaddr_in dest, struct ast_format_list fmt)
2418 {
2419  struct skinny_req *req;
2420 
2422  return;
2423 
2424  req->data.startmedia.conferenceId = htolel(sub->callid);
2426  req->data.startmedia.remoteIp = dest.sin_addr.s_addr;
2427  req->data.startmedia.remotePort = htolel(ntohs(dest.sin_port));
2428  req->data.startmedia.packetSize = htolel(fmt.cur_ms);
2431  req->data.startmedia.qualifier.vad = htolel(0);
2434  transmit_response(d, req);
2435 }
2436 
2437 static void transmit_activatecallplane(struct skinny_device *d, struct skinny_line *l)
2438 {
2439  struct skinny_req *req;
2440 
2442  return;
2443 
2444  req->data.activatecallplane.lineInstance = htolel(l->instance);
2445  transmit_response(d, req);
2446 }
2447 
2448 static void transmit_callstate(struct skinny_device *d, int buttonInstance, unsigned callid, int state)
2449 {
2450  struct skinny_req *req;
2451 
2452  if (!(req = req_alloc(sizeof(struct call_state_message), CALL_STATE_MESSAGE)))
2453  return;
2454 
2455  req->data.callstate.callState = htolel(state);
2456  req->data.callstate.lineInstance = htolel(buttonInstance);
2457  req->data.callstate.callReference = htolel(callid);
2458  transmit_response(d, req);
2459 }
2460 
2461 static void transmit_cfwdstate(struct skinny_device *d, struct skinny_line *l)
2462 {
2463  struct skinny_req *req;
2464  int anyon = 0;
2465 
2466  if (!(req = req_alloc(sizeof(struct forward_stat_message), FORWARD_STAT_MESSAGE)))
2467  return;
2468 
2469  if (l->cfwdtype & SKINNY_CFWD_ALL) {
2470  if (!ast_strlen_zero(l->call_forward_all)) {
2471  ast_copy_string(req->data.forwardstat.fwdallnum, l->call_forward_all, sizeof(req->data.forwardstat.fwdallnum));
2472  req->data.forwardstat.fwdall = htolel(1);
2473  anyon++;
2474  } else {
2475  req->data.forwardstat.fwdall = htolel(0);
2476  }
2477  }
2478  if (l->cfwdtype & SKINNY_CFWD_BUSY) {
2479  if (!ast_strlen_zero(l->call_forward_busy)) {
2480  ast_copy_string(req->data.forwardstat.fwdbusynum, l->call_forward_busy, sizeof(req->data.forwardstat.fwdbusynum));
2481  req->data.forwardstat.fwdbusy = htolel(1);
2482  anyon++;
2483  } else {
2484  req->data.forwardstat.fwdbusy = htolel(0);
2485  }
2486  }
2487  if (l->cfwdtype & SKINNY_CFWD_NOANSWER) {
2488  if (!ast_strlen_zero(l->call_forward_noanswer)) {
2489  ast_copy_string(req->data.forwardstat.fwdnoanswernum, l->call_forward_noanswer, sizeof(req->data.forwardstat.fwdnoanswernum));
2490  req->data.forwardstat.fwdnoanswer = htolel(1);
2491  anyon++;
2492  } else {
2493  req->data.forwardstat.fwdnoanswer = htolel(0);
2494  }
2495  }
2496  req->data.forwardstat.lineNumber = htolel(l->instance);
2497  if (anyon)
2499  else
2501 
2502  transmit_response(d, req);
2503 }
2504 
2506 {
2507  struct skinny_req *req;
2508 
2510  return;
2511 
2515 
2516  transmit_response(d, req);
2517 }
2518 
2519 static void transmit_linestatres(struct skinny_device *d, struct skinny_line *l)
2520 {
2521  struct skinny_req *req;
2522 
2523  if (!(req = req_alloc(sizeof(struct line_stat_res_message), LINE_STAT_RES_MESSAGE)))
2524  return;
2525 
2526  req->data.linestat.lineNumber = letohl(l->instance);
2527  memcpy(req->data.linestat.lineDirNumber, l->name, sizeof(req->data.linestat.lineDirNumber));
2528  memcpy(req->data.linestat.lineDisplayName, l->label, sizeof(req->data.linestat.lineDisplayName));
2529  transmit_response(d, req);
2530 }
2531 
2533 {
2534  struct skinny_req *req;
2535  struct timeval now = ast_tvnow();
2536  struct ast_tm cmtime;
2537 
2538  if (!(req = req_alloc(sizeof(struct definetimedate_message), DEFINETIMEDATE_MESSAGE)))
2539  return;
2540 
2541  ast_localtime(&now, &cmtime, NULL);
2542  req->data.definetimedate.year = htolel(cmtime.tm_year+1900);
2543  req->data.definetimedate.month = htolel(cmtime.tm_mon+1);
2544  req->data.definetimedate.dayofweek = htolel(cmtime.tm_wday);
2545  req->data.definetimedate.day = htolel(cmtime.tm_mday);
2546  req->data.definetimedate.hour = htolel(cmtime.tm_hour);
2547  req->data.definetimedate.minute = htolel(cmtime.tm_min);
2548  req->data.definetimedate.seconds = htolel(cmtime.tm_sec);
2549  req->data.definetimedate.milliseconds = htolel(cmtime.tm_usec / 1000);
2550  req->data.definetimedate.timestamp = htolel(now.tv_sec);
2551  transmit_response(d, req);
2552 }
2553 
2554 static void transmit_versionres(struct skinny_device *d)
2555 {
2556  struct skinny_req *req;
2557  if (!(req = req_alloc(sizeof(struct version_res_message), VERSION_RES_MESSAGE)))
2558  return;
2559 
2560  ast_copy_string(req->data.version.version, d->version_id, sizeof(req->data.version.version));
2561  transmit_response(d, req);
2562 }
2563 
2564 static void transmit_serverres(struct skinny_device *d)
2565 {
2566  struct skinny_req *req;
2567  if (!(req = req_alloc(sizeof(struct server_res_message), SERVER_RES_MESSAGE)))
2568  return;
2569 
2570  memcpy(req->data.serverres.server[0].serverName, ourhost,
2571  sizeof(req->data.serverres.server[0].serverName));
2572  req->data.serverres.serverListenPort[0] = htolel(ourport);
2573  req->data.serverres.serverIpAddr[0] = htolel(d->ourip.s_addr);
2574  transmit_response(d, req);
2575 }
2576 
2578 {
2579  struct skinny_req *req;
2580  int i;
2581  int x;
2582  int y;
2583  const struct soft_key_definitions *softkeymode = soft_key_default_definitions;
2584 
2585  if (!(req = req_alloc(sizeof(struct soft_key_set_res_message), SOFT_KEY_SET_RES_MESSAGE)))
2586  return;
2587 
2591  for (x = 0; x < sizeof(soft_key_default_definitions) / sizeof(struct soft_key_definitions); x++) {
2592  const uint8_t *defaults = softkeymode->defaults;
2593  /* XXX I wanted to get the size of the array dynamically, but that wasn't wanting to work.
2594  This will have to do for now. */
2595  for (y = 0; y < softkeymode->count; y++) {
2596  for (i = 0; i < (sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition)); i++) {
2597  if (defaults[y] == i+1) {
2598  req->data.softkeysets.softKeySetDefinition[softkeymode->mode].softKeyTemplateIndex[y] = (i+1);
2599  req->data.softkeysets.softKeySetDefinition[softkeymode->mode].softKeyInfoIndex[y] = htoles(i+301);
2600  if (skinnydebug)
2601  ast_verbose("softKeySetDefinition : softKeyTemplateIndex: %d softKeyInfoIndex: %d\n", i+1, i+301);
2602  }
2603  }
2604  }
2605  softkeymode++;
2606  }
2607  transmit_response(d, req);
2608 }
2609 
2611 {
2612  struct skinny_req *req;
2614  return;
2615 
2617  req->data.softkeytemplate.softKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition));
2618  req->data.softkeytemplate.totalSoftKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition));
2620  soft_key_template_default,
2621  sizeof(soft_key_template_default));
2622  transmit_response(d, req);
2623 }
2624 
2625 
2626 static int skinny_extensionstate_cb(char *context, char *exten, int state, void *data)
2627 {
2628  struct skinny_speeddial *sd = data;
2629  struct skinny_device *d = sd->parent;
2630  char hint[AST_MAX_EXTENSION];
2631 
2632  if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, sd->context, sd->exten)) {
2633  /* If they are not registered, we will override notification and show no availability */
2637  }
2638  } else {
2639  switch (state) {
2640  case AST_EXTENSION_DEACTIVATED: /* Retry after a while */
2641  case AST_EXTENSION_REMOVED: /* Extension is gone */
2642  ast_verb(2, "Extension state: Watcher for hint %s %s. Notify Device %s\n", exten, state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", d->name);
2643  sd->stateid = -1;
2646  break;
2647  case AST_EXTENSION_RINGING:
2651  break;
2652  case AST_EXTENSION_BUSY: /* callstate = SKINNY_BUSY wasn't wanting to work - I'll settle for this */
2653  case AST_EXTENSION_INUSE:
2656  break;
2657  case AST_EXTENSION_ONHOLD:
2660  break;
2662  default:
2665  break;
2666  }
2667  }
2668 
2669  sd->laststate = state;
2670 
2671  return 0;
2672 }
2673 
2674 static void update_connectedline(struct skinny_subchannel *sub, const void *data, size_t datalen)
2675 {
2676  struct ast_channel *c = sub->owner;
2677  struct skinny_line *l = sub->parent;
2678  struct skinny_device *d = l->device;
2679 
2680  if (!d) {
2681  return;
2682  }
2683 
2684  if (!c->caller.id.number.valid
2686  || !c->connected.id.number.valid
2688  return;
2689 
2690  if (sub->owner->_state == AST_STATE_UP) {
2691  transmit_callstate(d, l->instance, sub->callid, SKINNY_CONNECTED);
2692  transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid);
2693  if (sub->outgoing)
2695  S_COR(c->connected.id.name.valid, c->connected.id.name.str, ""),
2696  c->connected.id.number.str,
2697  l->cid_name, l->cid_num, l->instance, sub->callid, 1);
2698  else
2699  transmit_callinfo(d, l->cid_name, l->cid_num,
2700  S_COR(c->connected.id.name.valid, c->connected.id.name.str, ""),
2701  c->connected.id.number.str,
2702  l->instance, sub->callid, 2);
2703  } else {
2704  if (sub->outgoing) {
2705  transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGIN);
2706  transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid);
2708  S_COR(c->connected.id.name.valid, c->connected.id.name.str, ""),
2709  c->connected.id.number.str,
2710  l->cid_name, l->cid_num, l->instance, sub->callid, 1);
2711  } else {
2712  if (!sub->ringing) {
2713  transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGOUT);
2714  transmit_displaypromptstatus(d, "Ring-Out", 0, l->instance, sub->callid);
2715  sub->ringing = 1;
2716  } else {
2717  transmit_callstate(d, l->instance, sub->callid, SKINNY_PROGRESS);
2718  transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid);
2719  sub->progress = 1;
2720  }
2721 
2722  transmit_callinfo(d, l->cid_name, l->cid_num,
2723  S_COR(c->connected.id.name.valid, c->connected.id.name.str, ""),
2724  c->connected.id.number.str,
2725  l->instance, sub->callid, 2);
2726  }
2727  }
2728 }
2729 
2730 static void mwi_event_cb(const struct ast_event *event, void *userdata)
2731 {
2732  struct skinny_line *l = userdata;
2733  struct skinny_device *d = l->device;
2734  if (d) {
2735  struct skinnysession *s = d->session;
2736  struct skinny_line *l2;
2737  int new_msgs = 0;
2738  int dev_msgs = 0;
2739 
2740  if (s) {
2741  if (event) {
2743  }
2744 
2745  if (l->newmsgs) {
2747  } else {
2749  }
2750 
2751  /* find out wether the device lamp should be on or off */
2752  AST_LIST_TRAVERSE(&d->lines, l2, list) {
2753  if (l2->newmsgs) {
2754  dev_msgs++;
2755  }
2756  }
2757 
2758  if (dev_msgs) {
2760  } else {
2762  }
2763  ast_verb(3, "Skinny mwi_event_cb found %d new messages\n", new_msgs);
2764  }
2765  }
2766 }
2767 
2768 /* I do not believe skinny can deal with video.
2769  Anyone know differently? */
2770 /* Yes, it can. Currently 7985 and Cisco VT Advantage do video. */
2772 {
2773  struct skinny_subchannel *sub = NULL;
2774 
2775  if (!(sub = c->tech_pvt) || !(sub->vrtp))
2777 
2778  ao2_ref(sub->vrtp, +1);
2779  *instance = sub->vrtp;
2780 
2782 }
2783 
2784 static enum ast_rtp_glue_result skinny_get_rtp_peer(struct ast_channel *c, struct ast_rtp_instance **instance)
2785 {
2786  struct skinny_subchannel *sub = NULL;
2787  struct skinny_line *l;
2789 
2790  if (skinnydebug)
2791  ast_verb(1, "skinny_get_rtp_peer() Channel = %s\n", c->name);
2792 
2793 
2794  if (!(sub = c->tech_pvt))
2796 
2797  ast_mutex_lock(&sub->lock);
2798 
2799  if (!(sub->rtp)){
2800  ast_mutex_unlock(&sub->lock);
2802  }
2803 
2804  ao2_ref(sub->rtp, +1);
2805  *instance = sub->rtp;
2806 
2807  l = sub->parent;
2808 
2809  if (!l->directmedia || l->nat){
2811  if (skinnydebug)
2812  ast_verb(1, "skinny_get_rtp_peer() Using AST_RTP_GLUE_RESULT_LOCAL \n");
2813  }
2814 
2815  ast_mutex_unlock(&sub->lock);
2816 
2817  return res;
2818 
2819 }
2820 
2821 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, format_t codecs, int nat_active)
2822 {
2823  struct skinny_subchannel *sub;
2824  struct skinny_line *l;
2825  struct skinny_device *d;
2826  struct ast_format_list fmt;
2827  struct sockaddr_in us = { 0, };
2828  struct sockaddr_in them = { 0, };
2829  struct ast_sockaddr them_tmp;
2830  struct ast_sockaddr us_tmp;
2831 
2832  sub = c->tech_pvt;
2833 
2834  if (c->_state != AST_STATE_UP)
2835  return 0;
2836 
2837  if (!sub) {
2838  return -1;
2839  }
2840 
2841  l = sub->parent;
2842  d = l->device;
2843 
2844  if (rtp){
2845  ast_rtp_instance_get_remote_address(rtp, &them_tmp);
2846  ast_sockaddr_to_sin(&them_tmp, &them);
2847 
2848  /* Shutdown any early-media or previous media on re-invite */
2850 
2851  if (skinnydebug)
2852  ast_verb(1, "Peerip = %s:%d\n", ast_inet_ntoa(them.sin_addr), ntohs(them.sin_port));
2853 
2854  fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability));
2855 
2856  if (skinnydebug)
2857  ast_verb(1, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(fmt.bits), fmt.cur_ms);
2858 
2859  if (!(l->directmedia) || (l->nat)){
2860  ast_rtp_instance_get_local_address(rtp, &us_tmp);
2861  ast_sockaddr_to_sin(&us_tmp, &us);
2862  us.sin_addr.s_addr = us.sin_addr.s_addr ? us.sin_addr.s_addr : d->ourip.s_addr;
2863  transmit_startmediatransmission(d, sub, us, fmt);
2864  } else {
2865  transmit_startmediatransmission(d, sub, them, fmt);
2866  }
2867 
2868  return 0;
2869  }
2870  /* Need a return here to break the bridge */
2871  return 0;
2872 }
2873 
2875  .type = "Skinny",
2876  .get_rtp_info = skinny_get_rtp_peer,
2877  .get_vrtp_info = skinny_get_vrtp_peer,
2878  .update_peer = skinny_set_rtp_peer,
2879 };
2880 
2881 static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2882 {
2883  switch (cmd) {
2884  case CLI_INIT:
2885 #ifdef SKINNY_DEVMODE
2886  e->command = "skinny set debug {off|on|packet}";
2887  e->usage =
2888  "Usage: skinny set debug {off|on|packet}\n"
2889  " Enables/Disables dumping of Skinny packets for debugging purposes\n";
2890 #else
2891  e->command = "skinny set debug {off|on}";
2892  e->usage =
2893  "Usage: skinny set debug {off|on}\n"
2894  " Enables/Disables dumping of Skinny packets for debugging purposes\n";
2895 #endif
2896  return NULL;
2897  case CLI_GENERATE:
2898  return NULL;
2899  }
2900 
2901  if (a->argc != e->args)
2902  return CLI_SHOWUSAGE;
2903 
2904  if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
2905  skinnydebug = 1;
2906  ast_cli(a->fd, "Skinny Debugging Enabled\n");
2907  return CLI_SUCCESS;
2908  } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
2909  skinnydebug = 0;
2910  ast_cli(a->fd, "Skinny Debugging Disabled\n");
2911  return CLI_SUCCESS;
2912 #ifdef SKINNY_DEVMODE
2913  } else if (!strncasecmp(a->argv[e->args - 1], "packet", 6)) {
2914  skinnydebug = 2;
2915  ast_cli(a->fd, "Skinny Debugging Enabled including Packets\n");
2916  return CLI_SUCCESS;
2917 #endif
2918  } else {
2919  return CLI_SHOWUSAGE;
2920  }
2921 }
2922 
2923 static char *handle_skinny_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2924 {
2925  switch (cmd) {
2926  case CLI_INIT:
2927  e->command = "skinny reload";
2928  e->usage =
2929  "Usage: skinny reload\n"
2930  " Reloads the chan_skinny configuration\n";
2931  return NULL;
2932  case CLI_GENERATE:
2933  return NULL;
2934  }
2935 
2936  if (a->argc != e->args)
2937  return CLI_SHOWUSAGE;
2938 
2939  skinny_reload();
2940  return CLI_SUCCESS;
2941 
2942 }
2943 
2944 static char *complete_skinny_devices(const char *word, int state)
2945 {
2946  struct skinny_device *d;
2947  char *result = NULL;
2948  int wordlen = strlen(word), which = 0;
2949 
2950  AST_LIST_TRAVERSE(&devices, d, list) {
2951  if (!strncasecmp(word, d->id, wordlen) && ++which > state)
2952  result = ast_strdup(d->id);
2953  }
2954 
2955  return result;
2956 }
2957 
2958 static char *complete_skinny_show_device(const char *line, const char *word, int pos, int state)
2959 {
2960  return (pos == 3 ? ast_strdup(complete_skinny_devices(word, state)) : NULL);
2961 }
2962 
2963 static char *complete_skinny_reset(const char *line, const char *word, int pos, int state)
2964 {
2965  return (pos == 2 ? ast_strdup(complete_skinny_devices(word, state)) : NULL);
2966 }
2967 
2968 static char *complete_skinny_show_line(const char *line, const char *word, int pos, int state)
2969 {
2970  struct skinny_device *d;
2971  struct skinny_line *l;
2972  char *result = NULL;
2973  int wordlen = strlen(word), which = 0;
2974 
2975  if (pos != 3)
2976  return NULL;
2977 
2978  AST_LIST_TRAVERSE(&devices, d, list) {
2979  AST_LIST_TRAVERSE(&d->lines, l, list) {
2980  if (!strncasecmp(word, l->name, wordlen) && ++which > state)
2981  result = ast_strdup(l->name);
2982  }
2983  }
2984 
2985  return result;
2986 }
2987 
2988 static char *handle_skinny_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2989 {
2990  struct skinny_device *d;
2991  struct skinny_req *req;
2992 
2993  switch (cmd) {
2994  case CLI_INIT:
2995  e->command = "skinny reset";
2996  e->usage =
2997  "Usage: skinny reset <DeviceId|DeviceName|all> [restart]\n"
2998  " Causes a Skinny device to reset itself, optionally with a full restart\n";
2999  return NULL;
3000  case CLI_GENERATE:
3001  return complete_skinny_reset(a->line, a->word, a->pos, a->n);
3002  }
3003 
3004  if (a->argc < 3 || a->argc > 4)
3005  return CLI_SHOWUSAGE;
3006 
3008  AST_LIST_TRAVERSE(&devices, d, list) {
3009  int fullrestart = 0;
3010  if (!strcasecmp(a->argv[2], d->id) || !strcasecmp(a->argv[2], d->name) || !strcasecmp(a->argv[2], "all")) {
3011  if (!(d->session))
3012  continue;
3013 
3014  if (!(req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE)))
3015  continue;
3016 
3017  if (a->argc == 4 && !strcasecmp(a->argv[3], "restart"))
3018  fullrestart = 1;
3019 
3020  if (fullrestart)
3021  req->data.reset.resetType = 2;
3022  else
3023  req->data.reset.resetType = 1;
3024 
3025  ast_verb(3, "%s device %s.\n", (fullrestart) ? "Restarting" : "Resetting", d->id);
3026  transmit_response(d, req);
3027  }
3028  }
3030  return CLI_SUCCESS;
3031 }
3032 
3033 static char *device2str(int type)
3034 {
3035  char *tmp;
3036 
3037  switch (type) {
3038  case SKINNY_DEVICE_NONE:
3039  return "No Device";
3041  return "30SP Plus";
3043  return "12SP Plus";
3044  case SKINNY_DEVICE_12SP:
3045  return "12SP";
3046  case SKINNY_DEVICE_12:
3047  return "12";
3048  case SKINNY_DEVICE_30VIP:
3049  return "30VIP";
3050  case SKINNY_DEVICE_7910:
3051  return "7910";
3052  case SKINNY_DEVICE_7960:
3053  return "7960";
3054  case SKINNY_DEVICE_7940:
3055  return "7940";
3056  case SKINNY_DEVICE_7935:
3057  return "7935";
3058  case SKINNY_DEVICE_ATA186:
3059  return "ATA186";
3060  case SKINNY_DEVICE_7941:
3061  return "7941";
3062  case SKINNY_DEVICE_7971:
3063  return "7971";
3064  case SKINNY_DEVICE_7914:
3065  return "7914";
3066  case SKINNY_DEVICE_7985:
3067  return "7985";
3068  case SKINNY_DEVICE_7911:
3069  return "7911";
3070  case SKINNY_DEVICE_7961GE:
3071  return "7961GE";
3072  case SKINNY_DEVICE_7941GE:
3073  return "7941GE";
3074  case SKINNY_DEVICE_7931:
3075  return "7931";
3076  case SKINNY_DEVICE_7921:
3077  return "7921";
3078  case SKINNY_DEVICE_7906:
3079  return "7906";
3080  case SKINNY_DEVICE_7962:
3081  return "7962";
3082  case SKINNY_DEVICE_7937:
3083  return "7937";
3084  case SKINNY_DEVICE_7942:
3085  return "7942";
3086  case SKINNY_DEVICE_7945:
3087  return "7945";
3088  case SKINNY_DEVICE_7965:
3089  return "7965";
3090  case SKINNY_DEVICE_7975:
3091  return "7975";
3092  case SKINNY_DEVICE_7905:
3093  return "7905";
3094  case SKINNY_DEVICE_7920:
3095  return "7920";
3096  case SKINNY_DEVICE_7970:
3097  return "7970";
3098  case SKINNY_DEVICE_7912:
3099  return "7912";
3100  case SKINNY_DEVICE_7902:
3101  return "7902";
3102  case SKINNY_DEVICE_CIPC:
3103  return "IP Communicator";
3104  case SKINNY_DEVICE_7961:
3105  return "7961";
3106  case SKINNY_DEVICE_7936:
3107  return "7936";
3109  return "SCCPGATEWAY_AN";
3111  return "SCCPGATEWAY_BRI";
3112  case SKINNY_DEVICE_UNKNOWN:
3113  return "Unknown";
3114  default:
3116  return "Unknown";
3117  snprintf(tmp, DEVICE2STR_BUFSIZE, "UNKNOWN-%d", type);
3118  return tmp;
3119  }
3120 }
3121 
3122 /*! \brief Print codec list from preference to CLI/manager */
3123 static void print_codec_to_cli(int fd, struct ast_codec_pref *pref)
3124 {
3125  int x, codec;
3126 
3127  for(x = 0; x < 32 ; x++) {
3128  codec = ast_codec_pref_index(pref, x);
3129  if (!codec)
3130  break;
3131  ast_cli(fd, "%s", ast_getformatname(codec));
3132  ast_cli(fd, ":%d", pref->framing[x]);
3133  if (x < 31 && ast_codec_pref_index(pref, x + 1))
3134  ast_cli(fd, ",");
3135  }
3136  if (!x)
3137  ast_cli(fd, "none");
3138 }
3139 
3140 static char *_skinny_show_devices(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[])
3141 {
3142  struct skinny_device *d;
3143  struct skinny_line *l;
3144  const char *id;
3145  char idtext[256] = "";
3146  int total_devices = 0;
3147 
3148  if (s) { /* Manager - get ActionID */
3149  id = astman_get_header(m, "ActionID");
3150  if (!ast_strlen_zero(id))
3151  snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
3152  }
3153 
3154  switch (argc) {
3155  case 3:
3156  break;
3157  default:
3158  return CLI_SHOWUSAGE;
3159  }
3160 
3161  if (!s) {
3162  ast_cli(fd, "Name DeviceId IP Type R NL\n");
3163  ast_cli(fd, "-------------------- ---------------- --------------- --------------- - --\n");
3164  }
3165 
3167  AST_LIST_TRAVERSE(&devices, d, list) {
3168  int numlines = 0;
3169  total_devices++;
3170  AST_LIST_TRAVERSE(&d->lines, l, list) {
3171  numlines++;
3172  }
3173  if (!s) {
3174  ast_cli(fd, "%-20s %-16s %-15s %-15s %c %2d\n",
3175  d->name,
3176  d->id,
3177  d->session?ast_inet_ntoa(d->session->sin.sin_addr):"",
3178  device2str(d->type),
3179  d->registered?'Y':'N',
3180  numlines);
3181  } else {
3182  astman_append(s,
3183  "Event: DeviceEntry\r\n%s"
3184  "Channeltype: SKINNY\r\n"
3185  "ObjectName: %s\r\n"
3186  "ChannelObjectType: device\r\n"
3187  "DeviceId: %s\r\n"
3188  "IPaddress: %s\r\n"
3189  "Type: %s\r\n"
3190  "Devicestatus: %s\r\n"
3191  "NumberOfLines: %d\r\n",
3192  idtext,
3193  d->name,
3194  d->id,
3195  d->session?ast_inet_ntoa(d->session->sin.sin_addr):"-none-",
3196  device2str(d->type),
3197  d->registered?"registered":"unregistered",
3198  numlines);
3199  }
3200  }
3202 
3203  if (total)
3204  *total = total_devices;
3205 
3206  return CLI_SUCCESS;
3207 }
3208 
3209 /*! \brief Show SKINNY devices in the manager API */
3210 /* Inspired from chan_sip */
3211 static int manager_skinny_show_devices(struct mansession *s, const struct message *m)
3212 {
3213  const char *id = astman_get_header(m, "ActionID");
3214  const char *a[] = {"skinny", "show", "devices"};
3215  char idtext[256] = "";
3216  int total = 0;
3217 
3218  if (!ast_strlen_zero(id))
3219  snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
3220 
3221  astman_send_listack(s, m, "Device status list will follow", "start");
3222  /* List the devices in separate manager events */
3223  _skinny_show_devices(-1, &total, s, m, 3, a);
3224  /* Send final confirmation */
3225  astman_append(s,
3226  "Event: DevicelistComplete\r\n"
3227  "EventList: Complete\r\n"
3228  "ListItems: %d\r\n"
3229  "%s"
3230  "\r\n", total, idtext);
3231  return 0;
3232 }
3233 
3234 static char *handle_skinny_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3235 {
3236 
3237  switch (cmd) {
3238  case CLI_INIT:
3239  e->command = "skinny show devices";
3240  e->usage =
3241  "Usage: skinny show devices\n"
3242  " Lists all devices known to the Skinny subsystem.\n";
3243  return NULL;
3244  case CLI_GENERATE:
3245  return NULL;
3246  }
3247 
3248  return _skinny_show_devices(a->fd, NULL, NULL, NULL, a->argc, (const char **) a->argv);
3249 }
3250 
3251 static char *_skinny_show_device(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
3252 {
3253  struct skinny_device *d;
3254  struct skinny_line *l;
3255  struct skinny_speeddial *sd;
3256  struct skinny_addon *sa;
3257  char codec_buf[512];
3258 
3259  if (argc < 4) {
3260  return CLI_SHOWUSAGE;
3261  }
3262 
3264  AST_LIST_TRAVERSE(&devices, d, list) {
3265  if (!strcasecmp(argv[3], d->id) || !strcasecmp(argv[3], d->name)) {
3266  int numlines = 0, numaddons = 0, numspeeddials = 0;
3267 
3268  AST_LIST_TRAVERSE(&d->lines, l, list){
3269  numlines++;
3270  }
3271 
3272  AST_LIST_TRAVERSE(&d->addons, sa, list) {
3273  numaddons++;
3274  }
3275 
3276  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
3277  numspeeddials++;
3278  }
3279 
3280  if (type == 0) { /* CLI */
3281  ast_cli(fd, "Name: %s\n", d->name);
3282  ast_cli(fd, "Id: %s\n", d->id);
3283  ast_cli(fd, "version: %s\n", S_OR(d->version_id, "Unknown"));
3284  ast_cli(fd, "Ip address: %s\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown"));
3285  ast_cli(fd, "Port: %d\n", (d->session ? ntohs(d->session->sin.sin_port) : 0));
3286  ast_cli(fd, "Device Type: %s\n", device2str(d->type));
3287  ast_cli(fd, "Conf Codecs:");
3288  ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, d->confcapability);
3289  ast_cli(fd, "%s\n", codec_buf);
3290  ast_cli(fd, "Neg Codecs: ");
3291  ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, d->capability);
3292  ast_cli(fd, "%s\n", codec_buf);
3293  ast_cli(fd, "Registered: %s\n", (d->registered ? "Yes" : "No"));
3294  ast_cli(fd, "Lines: %d\n", numlines);
3295  AST_LIST_TRAVERSE(&d->lines, l, list) {
3296  ast_cli(fd, " %s (%s)\n", l->name, l->label);
3297  }
3298  AST_LIST_TRAVERSE(&d->addons, sa, list) {
3299  numaddons++;
3300  }
3301  ast_cli(fd, "Addons: %d\n", numaddons);
3302  AST_LIST_TRAVERSE(&d->addons, sa, list) {
3303  ast_cli(fd, " %s\n", sa->type);
3304  }
3305  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
3306  numspeeddials++;
3307  }
3308  ast_cli(fd, "Speeddials: %d\n", numspeeddials);
3309  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
3310  ast_cli(fd, " %s (%s) ishint: %d\n", sd->exten, sd->label, sd->isHint);
3311  }
3312  } else { /* manager */
3313  astman_append(s, "Channeltype: SKINNY\r\n");
3314  astman_append(s, "ObjectName: %s\r\n", d->name);
3315  astman_append(s, "ChannelObjectType: device\r\n");
3316  astman_append(s, "Id: %s\r\n", d->id);
3317  astman_append(s, "version: %s\r\n", S_OR(d->version_id, "Unknown"));
3318  astman_append(s, "Ipaddress: %s\r\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown"));
3319  astman_append(s, "Port: %d\r\n", (d->session ? ntohs(d->session->sin.sin_port) : 0));
3320  astman_append(s, "DeviceType: %s\r\n", device2str(d->type));
3321  astman_append(s, "Codecs: ");
3322  ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, d->confcapability);
3323  astman_append(s, "%s\r\n", codec_buf);
3324  astman_append(s, "CodecOrder: ");
3325  ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, d->capability);
3326  astman_append(s, "%s\r\n", codec_buf);
3327  astman_append(s, "Devicestatus: %s\r\n", (d->registered?"registered":"unregistered"));
3328  astman_append(s, "NumberOfLines: %d\r\n", numlines);
3329  AST_LIST_TRAVERSE(&d->lines, l, list) {
3330  astman_append(s, "Line: %s (%s)\r\n", l->name, l->label);
3331  }
3332  astman_append(s, "NumberOfAddons: %d\r\n", numaddons);
3333  AST_LIST_TRAVERSE(&d->addons, sa, list) {
3334  astman_append(s, "Addon: %s\r\n", sa->type);
3335  }
3336  astman_append(s, "NumberOfSpeeddials: %d\r\n", numspeeddials);
3337  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
3338  astman_append(s, "Speeddial: %s (%s) ishint: %d\r\n", sd->exten, sd->label, sd->isHint);
3339  }
3340  }
3341  }
3342  }
3344  return CLI_SUCCESS;
3345 }
3346 
3347 static int manager_skinny_show_device(struct mansession *s, const struct message *m)
3348 {
3349  const char *a[4];
3350  const char *device;
3351 
3352  device = astman_get_header(m, "Device");
3353  if (ast_strlen_zero(device)) {
3354  astman_send_error(s, m, "Device: <name> missing.");
3355  return 0;
3356  }
3357  a[0] = "skinny";
3358  a[1] = "show";
3359  a[2] = "device";
3360  a[3] = device;
3361 
3362  _skinny_show_device(1, -1, s, m, 4, a);
3363  astman_append(s, "\r\n\r\n" );
3364  return 0;
3365 }
3366 
3367 /*! \brief Show device information */
3368 static char *handle_skinny_show_device(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3369 {
3370  switch (cmd) {
3371  case CLI_INIT:
3372  e->command = "skinny show device";
3373  e->usage =
3374  "Usage: skinny show device <DeviceId|DeviceName>\n"
3375  " Lists all deviceinformation of a specific device known to the Skinny subsystem.\n";
3376  return NULL;
3377  case CLI_GENERATE:
3378  return complete_skinny_show_device(a->line, a->word, a->pos, a->n);
3379  }
3380 
3381  return _skinny_show_device(0, a->fd, NULL, NULL, a->argc, (const char **) a->argv);
3382 }
3383 
3384 static char *_skinny_show_lines(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[])
3385 {
3386  struct skinny_line *l;
3387  struct skinny_subchannel *sub;
3388  int total_lines = 0;
3389  int verbose = 0;
3390  const char *id;
3391  char idtext[256] = "";
3392 
3393  if (s) { /* Manager - get ActionID */
3394  id = astman_get_header(m, "ActionID");
3395  if (!ast_strlen_zero(id))
3396  snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
3397  }
3398 
3399  switch (argc) {
3400  case 4:
3401  verbose = 1;
3402  break;
3403  case 3:
3404  verbose = 0;
3405  break;
3406  default:
3407  return CLI_SHOWUSAGE;
3408  }
3409 
3410  if (!s) {
3411  ast_cli(fd, "Name Device Name Instance Label \n");
3412  ast_cli(fd, "-------------------- -------------------- -------- --------------------\n");
3413  }
3414  AST_LIST_LOCK(&lines);
3415  AST_LIST_TRAVERSE(&lines, l, all) {
3416  total_lines++;
3417  if (!s) {
3418  ast_cli(fd, "%-20s %-20s %8d %-20s\n",
3419  l->name,
3420  (l->device ? l->device->name : "Not connected"),
3421  l->instance,
3422  l->label);
3423  if (verbose) {
3424  AST_LIST_TRAVERSE(&l->sub, sub, list) {
3425  ast_cli(fd, " %s> %s to %s\n",
3426  (sub == l->activesub?"Active ":"Inactive"),
3427  sub->owner->name,
3429  );
3430  }
3431  }
3432  } else {
3433  astman_append(s,
3434  "Event: LineEntry\r\n%s"
3435  "Channeltype: SKINNY\r\n"
3436  "ObjectName: %s\r\n"
3437  "ChannelObjectType: line\r\n"
3438  "Device: %s\r\n"
3439  "Instance: %d\r\n"
3440  "Label: %s\r\n",
3441  idtext,
3442  l->name,
3443  (l->device?l->device->name:"None"),
3444  l->instance,
3445  l->label);
3446  }
3447  }
3449 
3450  if (total) {
3451  *total = total_lines;
3452  }
3453 
3454  return CLI_SUCCESS;
3455 }
3456 
3457 /*! \brief Show Skinny lines in the manager API */
3458 /* Inspired from chan_sip */
3459 static int manager_skinny_show_lines(struct mansession *s, const struct message *m)
3460 {
3461  const char *id = astman_get_header(m, "ActionID");
3462  const char *a[] = {"skinny", "show", "lines"};
3463  char idtext[256] = "";
3464  int total = 0;
3465 
3466  if (!ast_strlen_zero(id))
3467  snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
3468 
3469  astman_send_listack(s, m, "Line status list will follow", "start");
3470  /* List the lines in separate manager events */
3471  _skinny_show_lines(-1, &total, s, m, 3, a);
3472  /* Send final confirmation */
3473  astman_append(s,
3474  "Event: LinelistComplete\r\n"
3475  "EventList: Complete\r\n"
3476  "ListItems: %d\r\n"
3477  "%s"
3478  "\r\n", total, idtext);
3479  return 0;
3480 }
3481 
3482 static char *handle_skinny_show_lines(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3483 {
3484  switch (cmd) {
3485  case CLI_INIT:
3486  e->command = "skinny show lines [verbose]";
3487  e->usage =
3488  "Usage: skinny show lines\n"
3489  " Lists all lines known to the Skinny subsystem.\n"
3490  " If 'verbose' is specified, the output includes\n"
3491  " information about subs for each line.\n";
3492  return NULL;
3493  case CLI_GENERATE:
3494  return NULL;
3495  }
3496 
3497  if (a->argc == e->args) {
3498  if (strcasecmp(a->argv[e->args-1], "verbose")) {
3499  return CLI_SHOWUSAGE;
3500  }
3501  } else if (a->argc != e->args - 1) {
3502  return CLI_SHOWUSAGE;
3503  }
3504 
3505  return _skinny_show_lines(a->fd, NULL, NULL, NULL, a->argc, (const char **) a->argv);
3506 }
3507 
3508 static char *_skinny_show_line(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
3509 {
3510  struct skinny_device *d;
3511  struct skinny_line *l;
3512  struct ast_codec_pref *pref;
3513  int x = 0, codec = 0;
3514  char codec_buf[512];
3515  char group_buf[256];
3516  char cbuf[256];
3517 
3518  switch (argc) {
3519  case 4:
3520  break;
3521  case 6:
3522  break;
3523  default:
3524  return CLI_SHOWUSAGE;
3525  }
3526 
3528 
3529  /* Show all lines matching the one supplied */
3530  AST_LIST_TRAVERSE(&devices, d, list) {
3531  if (argc == 6 && (strcasecmp(argv[5], d->id) && strcasecmp(argv[5], d->name))) {
3532  continue;
3533  }
3534  AST_LIST_TRAVERSE(&d->lines, l, list) {
3535  if (strcasecmp(argv[3], l->name)) {
3536  continue;
3537  }
3538  if (type == 0) { /* CLI */
3539  ast_cli(fd, "Line: %s\n", l->name);
3540  ast_cli(fd, "On Device: %s\n", d->name);
3541  ast_cli(fd, "Line Label: %s\n", l->label);
3542  ast_cli(fd, "Extension: %s\n", S_OR(l->exten, "<not set>"));
3543  ast_cli(fd, "Context: %s\n", l->context);
3544  ast_cli(fd, "CallGroup: %s\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup));
3545  ast_cli(fd, "PickupGroup: %s\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup));
3546  ast_cli(fd, "Language: %s\n", S_OR(l->language, "<not set>"));
3547  ast_cli(fd, "Accountcode: %s\n", S_OR(l->accountcode, "<not set>"));
3548  ast_cli(fd, "AmaFlag: %s\n", ast_cdr_flags2str(l->amaflags));
3549  ast_cli(fd, "CallerId Number: %s\n", S_OR(l->cid_num, "<not set>"));
3550  ast_cli(fd, "CallerId Name: %s\n", S_OR(l->cid_name, "<not set>"));
3551  ast_cli(fd, "Hide CallerId: %s\n", (l->hidecallerid ? "Yes" : "No"));
3552  ast_cli(fd, "CFwdAll: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "<not set>"));
3553  ast_cli(fd, "CFwdBusy: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
3554  ast_cli(fd, "CFwdNoAnswer: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
3555  ast_cli(fd, "VoicemailBox: %s\n", S_OR(l->mailbox, "<not set>"));
3556  ast_cli(fd, "VoicemailNumber: %s\n", S_OR(l->vmexten, "<not set>"));
3557  ast_cli(fd, "MWIblink: %d\n", l->mwiblink);
3558  ast_cli(fd, "Regextension: %s\n", S_OR(l->regexten, "<not set>"));
3559  ast_cli(fd, "Regcontext: %s\n", S_OR(l->regcontext, "<not set>"));
3560  ast_cli(fd, "MoHInterpret: %s\n", S_OR(l->mohinterpret, "<not set>"));
3561  ast_cli(fd, "MoHSuggest: %s\n", S_OR(l->mohsuggest, "<not set>"));
3562  ast_cli(fd, "Last dialed nr: %s\n", S_OR(l->lastnumberdialed, "<no calls made yet>"));
3563  ast_cli(fd, "Last CallerID: %s\n", S_OR(l->lastcallerid, "<not set>"));
3564  ast_cli(fd, "Transfer enabled: %s\n", (l->transfer ? "Yes" : "No"));
3565  ast_cli(fd, "Callwaiting: %s\n", (l->callwaiting ? "Yes" : "No"));
3566  ast_cli(fd, "3Way Calling: %s\n", (l->threewaycalling ? "Yes" : "No"));
3567  ast_cli(fd, "Can forward: %s\n", (l->cancallforward ? "Yes" : "No"));
3568  ast_cli(fd, "Do Not Disturb: %s\n", (l->dnd ? "Yes" : "No"));
3569  ast_cli(fd, "NAT: %s\n", (l->nat ? "Yes" : "No"));
3570  ast_cli(fd, "immediate: %s\n", (l->immediate ? "Yes" : "No"));
3571  ast_cli(fd, "Group: %d\n", l->group);
3572  ast_cli(fd, "Parkinglot: %s\n", S_OR(l->parkinglot, "<not set>"));
3573  ast_cli(fd, "Conf Codecs: ");
3574  ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->confcapability);
3575  ast_cli(fd, "%s\n", codec_buf);
3576  ast_cli(fd, "Neg Codecs: ");
3577  ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->capability);
3578  ast_cli(fd, "%s\n", codec_buf);
3579  ast_cli(fd, "Codec Order: (");
3580  print_codec_to_cli(fd, &l->prefs);
3581  ast_cli(fd, ")\n");
3582  ast_cli(fd, "\n");
3583  } else { /* manager */
3584  astman_append(s, "Channeltype: SKINNY\r\n");
3585  astman_append(s, "ObjectName: %s\r\n", l->name);
3586  astman_append(s, "ChannelObjectType: line\r\n");
3587  astman_append(s, "Device: %s\r\n", d->name);
3588  astman_append(s, "LineLabel: %s\r\n", l->label);
3589  astman_append(s, "Extension: %s\r\n", S_OR(l->exten, "<not set>"));
3590  astman_append(s, "Context: %s\r\n", l->context);
3591  astman_append(s, "CallGroup: %s\r\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup));
3592  astman_append(s, "PickupGroup: %s\r\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup));
3593  astman_append(s, "Language: %s\r\n", S_OR(l->language, "<not set>"));
3594  astman_append(s, "Accountcode: %s\r\n", S_OR(l->accountcode, "<not set>"));
3595  astman_append(s, "AMAflags: %s\r\n", ast_cdr_flags2str(l->amaflags));
3596  astman_append(s, "Callerid: %s\r\n", ast_callerid_merge(cbuf, sizeof(cbuf), l->cid_name, l->cid_num, ""));
3597  astman_append(s, "HideCallerId: %s\r\n", (l->hidecallerid ? "Yes" : "No"));
3598  astman_append(s, "CFwdAll: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "<not set>"));
3599  astman_append(s, "CFwdBusy: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
3600  astman_append(s, "CFwdNoAnswer: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
3601  astman_append(s, "VoicemailBox: %s\r\n", S_OR(l->mailbox, "<not set>"));
3602  astman_append(s, "VoicemailNumber: %s\r\n", S_OR(l->vmexten, "<not set>"));
3603  astman_append(s, "MWIblink: %d\r\n", l->mwiblink);
3604  astman_append(s, "RegExtension: %s\r\n", S_OR(l->regexten, "<not set>"));
3605  astman_append(s, "Regcontext: %s\r\n", S_OR(l->regcontext, "<not set>"));
3606  astman_append(s, "MoHInterpret: %s\r\n", S_OR(l->mohinterpret, "<not set>"));
3607  astman_append(s, "MoHSuggest: %s\r\n", S_OR(l->mohsuggest, "<not set>"));
3608  astman_append(s, "LastDialedNr: %s\r\n", S_OR(l->lastnumberdialed, "<no calls made yet>"));
3609  astman_append(s, "LastCallerID: %s\r\n", S_OR(l->lastcallerid, "<not set>"));
3610  astman_append(s, "Transfer: %s\r\n", (l->transfer ? "Yes" : "No"));
3611  astman_append(s, "Callwaiting: %s\r\n", (l->callwaiting ? "Yes" : "No"));
3612  astman_append(s, "3WayCalling: %s\r\n", (l->threewaycalling ? "Yes" : "No"));
3613  astman_append(s, "CanForward: %s\r\n", (l->cancallforward ? "Yes" : "No"));
3614  astman_append(s, "DoNotDisturb: %s\r\n", (l->dnd ? "Yes" : "No"));
3615  astman_append(s, "NAT: %s\r\n", (l->nat ? "Yes" : "No"));
3616  astman_append(s, "immediate: %s\r\n", (l->immediate ? "Yes" : "No"));
3617  astman_append(s, "Group: %d\r\n", l->group);
3618  astman_append(s, "Parkinglot: %s\r\n", S_OR(l->parkinglot, "<not set>"));
3619  ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->confcapability);
3620  astman_append(s, "Codecs: %s\r\n", codec_buf);
3621  astman_append(s, "CodecOrder: ");
3622  pref = &l->prefs;
3623  for(x = 0; x < 32 ; x++) {
3624  codec = ast_codec_pref_index(pref, x);
3625  if (!codec)
3626  break;
3627  astman_append(s, "%s", ast_getformatname(codec));
3628  if (x < 31 && ast_codec_pref_index(pref, x+1))
3629  astman_append(s, ",");
3630  }
3631  astman_append(s, "\r\n");
3632  }
3633  }
3634  }
3635 
3637  return CLI_SUCCESS;
3638 }
3639 
3640 static int manager_skinny_show_line(struct mansession *s, const struct message *m)
3641 {
3642  const char *a[4];
3643  const char *line;
3644 
3645  line = astman_get_header(m, "Line");
3646  if (ast_strlen_zero(line)) {
3647  astman_send_error(s, m, "Line: <name> missing.");
3648  return 0;
3649  }
3650  a[0] = "skinny";
3651  a[1] = "show";
3652  a[2] = "line";
3653  a[3] = line;
3654 
3655  _skinny_show_line(1, -1, s, m, 4, a);
3656  astman_append(s, "\r\n\r\n" );
3657  return 0;
3658 }
3659 
3660 /*! \brief List line information. */
3661 static char *handle_skinny_show_line(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3662 {
3663  switch (cmd) {
3664  case CLI_INIT:
3665  e->command = "skinny show line";
3666  e->usage =
3667  "Usage: skinny show line <Line> [ on <DeviceID|DeviceName> ]\n"
3668  " List all lineinformation of a specific line known to the Skinny subsystem.\n";
3669  return NULL;
3670  case CLI_GENERATE:
3671  return complete_skinny_show_line(a->line, a->word, a->pos, a->n);
3672  }
3673 
3674  return _skinny_show_line(0, a->fd, NULL, NULL, a->argc, (const char **) a->argv);
3675 }
3676 
3677 /*! \brief List global settings for the Skinny subsystem. */
3678 static char *handle_skinny_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3679 {
3680  switch (cmd) {
3681  case CLI_INIT:
3682  e->command = "skinny show settings";
3683  e->usage =
3684  "Usage: skinny show settings\n"
3685  " Lists all global configuration settings of the Skinny subsystem.\n";
3686  return NULL;
3687  case CLI_GENERATE:
3688  return NULL;
3689  }
3690 
3691  if (a->argc != 3)
3692  return CLI_SHOWUSAGE;
3693 
3694  ast_cli(a->fd, "\nGlobal Settings:\n");
3695  ast_cli(a->fd, " Skinny Port: %d\n", ntohs(bindaddr.sin_port));
3696  ast_cli(a->fd, " Bindaddress: %s\n", ast_inet_ntoa(bindaddr.sin_addr));
3697  ast_cli(a->fd, " KeepAlive: %d\n", keep_alive);
3698  ast_cli(a->fd, " Date Format: %s\n", date_format);
3699  ast_cli(a->fd, " Voice Mail Extension: %s\n", S_OR(global_vmexten, "(not set)"));
3700  ast_cli(a->fd, " Reg. context: %s\n", S_OR(regcontext, "(not set)"));
3701  ast_cli(a->fd, " Jitterbuffer enabled: %s\n", AST_CLI_YESNO(ast_test_flag(&global_jbconf, AST_JB_ENABLED)));
3703  ast_cli(a->fd, " Jitterbuffer forced: %s\n", AST_CLI_YESNO(ast_test_flag(&global_jbconf, AST_JB_FORCED)));
3704  ast_cli(a->fd, " Jitterbuffer max size: %ld\n", global_jbconf.max_size);
3705  ast_cli(a->fd, " Jitterbuffer resync: %ld\n", global_jbconf.resync_threshold);
3706  ast_cli(a->fd, " Jitterbuffer impl: %s\n", global_jbconf.impl);
3707  if (!strcasecmp(global_jbconf.impl, "adaptive")) {
3708  ast_cli(a->fd, " Jitterbuffer tgt extra: %ld\n", global_jbconf.target_extra);
3709  }
3710  ast_cli(a->fd, " Jitterbuffer log: %s\n", AST_CLI_YESNO(ast_test_flag(&global_jbconf, AST_JB_LOG)));
3711  }
3712 
3713  return CLI_SUCCESS;
3714 }
3715 
3716 static struct ast_cli_entry cli_skinny[] = {
3717  AST_CLI_DEFINE(handle_skinny_show_devices, "List defined Skinny devices"),
3718  AST_CLI_DEFINE(handle_skinny_show_device, "List Skinny device information"),
3719  AST_CLI_DEFINE(handle_skinny_show_lines, "List defined Skinny lines per device"),
3720  AST_CLI_DEFINE(handle_skinny_show_line, "List Skinny line information"),
3721  AST_CLI_DEFINE(handle_skinny_show_settings, "List global Skinny settings"),
3722  AST_CLI_DEFINE(handle_skinny_set_debug, "Enable/Disable Skinny debugging"),
3723  AST_CLI_DEFINE(handle_skinny_reset, "Reset Skinny device(s)"),
3724  AST_CLI_DEFINE(handle_skinny_reload, "Reload Skinny config"),
3725 };
3726 
3727 static void start_rtp(struct skinny_subchannel *sub)
3728 {
3729  struct skinny_line *l = sub->parent;
3730  struct skinny_device *d = l->device;
3731  int hasvideo = 0;
3732  struct ast_sockaddr bindaddr_tmp;
3733 
3734  ast_mutex_lock(&sub->lock);
3735  /* Allocate the RTP */
3736  ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
3737  sub->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL);
3738  if (hasvideo)
3739  sub->vrtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL);
3740 
3741  if (sub->rtp) {
3743  }
3744  if (sub->vrtp) {
3746  }
3747 
3748  if (sub->rtp && sub->owner) {
3749  ast_channel_set_fd(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
3750  ast_channel_set_fd(sub->owner, 1, ast_rtp_instance_fd(sub->rtp, 1));
3751  }
3752  if (hasvideo && sub->vrtp && sub->owner) {
3753  ast_channel_set_fd(sub->owner, 2, ast_rtp_instance_fd(sub->vrtp, 0));
3754  ast_channel_set_fd(sub->owner, 3, ast_rtp_instance_fd(sub->vrtp, 1));
3755  }
3756  if (sub->rtp) {
3757  ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "Skinny RTP");
3759  }
3760  if (sub->vrtp) {
3761  ast_rtp_instance_set_qos(sub->vrtp, qos.tos_video, qos.cos_video, "Skinny VRTP");
3763  }
3764  /* Set Frame packetization */
3765  if (sub->rtp)
3767 
3768  /* Create the RTP connection */
3769  transmit_connect(d, sub);
3770  ast_mutex_unlock(&sub->lock);
3771 }
3772 
3773 static void *skinny_newcall(void *data)
3774 {
3775  struct ast_channel *c = data;
3776  struct skinny_subchannel *sub = c->tech_pvt;
3777  struct skinny_line *l = sub->parent;
3778  struct skinny_device *d = l->device;
3779  int res = 0;
3780 
3781  ast_copy_string(l->lastnumberdialed, c->exten, sizeof(l->lastnumberdialed));
3782  ast_set_callerid(c,
3783  l->hidecallerid ? "" : l->cid_num,
3784  l->hidecallerid ? "" : l->cid_name,
3785  c->caller.ani.number.valid ? NULL : l->cid_num);
3786 #if 1 /* XXX This code is probably not necessary */
3789  c->connected.id.number.valid = 1;
3793 #endif
3795  if (!sub->rtp) {
3796  start_rtp(sub);
3797  }
3798  res = ast_pbx_run(c);
3799  if (res) {
3800  ast_log(LOG_WARNING, "PBX exited non-zero\n");
3801  transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
3802  }
3803  return NULL;
3804 }
3805 
3806 static void *skinny_ss(void *data)
3807 {
3808  struct ast_channel *c = data;
3809  struct skinny_subchannel *sub = c->tech_pvt;
3810  struct skinny_line *l = sub->parent;
3811  struct skinny_device *d = l->device;
3812  int len = 0;
3813  int timeout = firstdigittimeout;
3814  int res = 0;
3815  int loop_pause = 100;
3816 
3817  if (!d) {
3818  ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
3819  return NULL;
3820  }
3821 
3822  ast_verb(3, "Starting simple switch on '%s@%s'\n", l->name, d->name);
3823 
3824  len = strlen(d->exten);
3825 
3826  while (len < AST_MAX_EXTENSION-1) {
3827  res = 1; /* Assume that we will get a digit */
3828  while (strlen(d->exten) == len){
3829  ast_safe_sleep(c, loop_pause);
3830  timeout -= loop_pause;
3831  if ( (timeout -= loop_pause) <= 0){
3832  res = 0;
3833  break;
3834  }
3835  res = 1;
3836  }
3837 
3838  timeout = 0;
3839  len = strlen(d->exten);
3840 
3841  if (!ast_ignore_pattern(c->context, d->exten)) {
3842  transmit_stop_tone(d, l->instance, sub->callid);
3843  }
3844  if (ast_exists_extension(c, c->context, d->exten, 1, l->cid_num)) {
3845  if (!res || !ast_matchmore_extension(c, c->context, d->exten, 1, l->cid_num)) {
3846  if (l->getforward) {
3847  /* Record this as the forwarding extension */
3848  set_callforwards(l, d->exten, l->getforward);
3849  ast_verb(3, "Setting call forward (%d) to '%s' on channel %s\n",
3850  l->cfwdtype, d->exten, c->name);
3851  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
3853  transmit_displaynotify(d, "CFwd enabled", 10);
3854  transmit_cfwdstate(d, l);
3855  ast_safe_sleep(c, 500);
3856  ast_indicate(c, -1);
3857  ast_safe_sleep(c, 1000);
3858  memset(d->exten, 0, sizeof(d->exten));
3859  len = 0;
3860  l->getforward = 0;
3861  if (sub->owner && sub->owner->_state != AST_STATE_UP) {
3862  ast_indicate(c, -1);
3863  ast_hangup(c);
3864  }
3865  return NULL;
3866  } else {
3867  ast_copy_string(c->exten, d->exten, sizeof(c->exten));
3868  ast_copy_string(l->lastnumberdialed, d->exten, sizeof(l->lastnumberdialed));
3869  memset(d->exten, 0, sizeof(d->exten));
3870  skinny_newcall(c);
3871  return NULL;
3872  }
3873  } else {
3874  /* It's a match, but they just typed a digit, and there is an ambiguous match,
3875  so just set the timeout to matchdigittimeout and wait some more */
3876  timeout = matchdigittimeout;
3877  }
3878  } else if (res == 0) {
3879  ast_debug(1, "Not enough digits (%s) (and no ambiguous match)...\n", d->exten);
3880  memset(d->exten, 0, sizeof(d->exten));
3881  if (l->hookstate == SKINNY_OFFHOOK) {
3882  transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
3883  }
3884  if (sub->owner && sub->owner->_state != AST_STATE_UP) {
3885  ast_indicate(c, -1);
3886  ast_hangup(c);
3887  }
3888  return NULL;
3889  } else if (!ast_canmatch_extension(c, c->context, d->exten, 1,
3890  S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))
3891  && ((d->exten[0] != '*') || (!ast_strlen_zero(d->exten) > 2))) {
3892  ast_log(LOG_WARNING, "Can't match [%s] from '%s' in context %s\n", d->exten,
3893  S_COR(c->caller.id.number.valid, c->caller.id.number.str, "<Unknown Caller>"),
3894  c->context);
3895  memset(d->exten, 0, sizeof(d->exten));
3896  if (l->hookstate == SKINNY_OFFHOOK) {
3897  transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
3898  /* hang out for 3 seconds to let congestion play */
3899  ast_safe_sleep(c, 3000);
3900  }
3901  break;
3902  }
3903  if (!timeout) {
3904  timeout = gendigittimeout;
3905  }
3906  if (len && !ast_ignore_pattern(c->context, d->exten)) {
3907  ast_indicate(c, -1);
3908  }
3909  }
3910  if (c)
3911  ast_hangup(c);
3912  memset(d->exten, 0, sizeof(d->exten));
3913  return NULL;
3914 }
3915 
3916 
3917 
3918 static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
3919 {
3920  int res = 0;
3921  struct skinny_subchannel *sub = ast->tech_pvt;
3922  struct skinny_line *l = sub->parent;
3923  struct skinny_device *d = l->device;
3924 
3925  if (!d || !d->registered) {
3926  ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
3927  return -1;
3928  }
3929 
3930  if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
3931  ast_log(LOG_WARNING, "skinny_call called on %s, neither down nor reserved\n", ast->name);
3932  return -1;
3933  }
3934 
3935  if (skinnydebug)
3936  ast_verb(3, "skinny_call(%s)\n", ast->name);
3937 
3938  if (l->dnd) {
3940  return -1;
3941  }
3942 
3943  if (AST_LIST_NEXT(sub,list) && !l->callwaiting) {
3945  return -1;
3946  }
3947 
3948  switch (l->hookstate) {
3949  case SKINNY_OFFHOOK:
3950  break;
3951  case SKINNY_ONHOOK:
3952  l->activesub = sub;
3953  break;
3954  default:
3955  ast_log(LOG_ERROR, "Don't know how to deal with hookstate %d\n", l->hookstate);
3956  break;
3957  }
3958 
3959  transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_RINGIN);
3960  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN);
3961  transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid);
3963  S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, ""),
3964  S_COR(ast->connected.id.number.valid, ast->connected.id.number.str, ""),
3965  l->cid_name, l->cid_num, l->instance, sub->callid, 1);
3968 
3971  sub->outgoing = 1;
3972  return res;
3973 }
3974 
3975 static int skinny_hangup(struct ast_channel *ast)
3976 {
3977  struct skinny_subchannel *sub = ast->tech_pvt;
3978  struct skinny_line *l;
3979  struct skinny_device *d;
3980 
3981  if (!sub) {
3982  ast_debug(1, "Asked to hangup channel not connected\n");
3983  return 0;
3984  }
3985 
3986  l = sub->parent;
3987  d = l->device;
3988 
3989  if (!d) {
3990  ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
3991  return 0;
3992  }
3993 
3994  if (skinnydebug)
3995  ast_verb(3,"Hanging up %s/%u\n", d->name, sub->callid);
3996 
3997  AST_LIST_REMOVE(&l->sub, sub, list);
3998 
3999  if (d->registered) {
4000  /* Ignoring l->type, doesn't seem relevant and previous code
4001  assigned rather than tested, ie always true */
4002  if (!AST_LIST_EMPTY(&l->sub)) {
4003  if (sub->related) {
4004  sub->related->related = NULL;
4005 
4006  }
4007  if (sub == l->activesub) { /* we are killing the active sub, but there are other subs on the line*/
4008  ast_verb(4,"Killing active sub %u\n", sub->callid);
4009  if (sub->related) {
4010  l->activesub = sub->related;
4011  } else {
4012  if (AST_LIST_NEXT(sub, list)) {
4013  l->activesub = AST_LIST_NEXT(sub, list);
4014  } else {
4015  l->activesub = AST_LIST_FIRST(&l->sub);
4016  }
4017  }
4018  //transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->callid);
4023  transmit_stop_tone(d, l->instance, sub->callid);
4024  } else { /* we are killing a background sub on the line with other subs*/
4025  ast_verb(4,"Killing inactive sub %u\n", sub->callid);
4026  if (AST_LIST_NEXT(sub, list)) {
4028  } else {
4030  }
4031  }
4032  } else { /* no more subs on line so make idle */
4033  ast_verb(4,"Killing only sub %u\n", sub->callid);
4034  l->hookstate = SKINNY_ONHOOK;
4038  transmit_clearpromptmessage(d, l->instance, sub->callid);
4039  transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
4042  l->activesub = NULL;
4044  if (sub->parent == d->activeline) {
4050  transmit_clear_display_message(d, l->instance, sub->callid);
4051  transmit_stop_tone(d, l->instance, sub->callid);
4052  /* we should check to see if we can start the ringer if another line is ringing */
4053  }
4054  }
4055  }
4056  ast_mutex_lock(&sub->lock);
4057  sub->owner = NULL;
4058  ast->tech_pvt = NULL;
4059  sub->alreadygone = 0;
4060  sub->outgoing = 0;
4061  if (sub->rtp) {
4063  sub->rtp = NULL;
4064  }
4065  ast_mutex_unlock(&sub->lock);
4066  ast_free(sub);
4068  return 0;
4069 }
4070 
4071 static int skinny_answer(struct ast_channel *ast)
4072 {
4073  int res = 0;
4074  struct skinny_subchannel *sub = ast->tech_pvt;
4075  struct skinny_line *l = sub->parent;
4076  struct skinny_device *d = l->device;
4077 
4078  if (sub->blindxfer) {
4079  if (skinnydebug)
4080  ast_debug(1, "skinny_answer(%s) on %s@%s-%u with BlindXFER, transferring\n",
4081  ast->name, l->name, d->name, sub->callid);
4082  ast_setstate(ast, AST_STATE_UP);
4083  skinny_transfer(sub);
4084  return 0;
4085  }
4086 
4087  sub->cxmode = SKINNY_CX_SENDRECV;
4088  if (!sub->rtp) {
4089  start_rtp(sub);
4090  }
4091  if (skinnydebug)
4092  ast_verb(1, "skinny_answer(%s) on %s@%s-%u\n", ast->name, l->name, d->name, sub->callid);
4093  if (ast->_state != AST_STATE_UP) {
4094  ast_setstate(ast, AST_STATE_UP);
4095  }
4096 
4097  transmit_stop_tone(d, l->instance, sub->callid);
4098  /* order matters here...
4099  for some reason, transmit_callinfo must be before transmit_callstate,
4100  or you won't get keypad messages in some situations. */
4102  S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, ""),
4103  S_COR(ast->connected.id.number.valid, ast->connected.id.number.str, ""),
4104  l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2);
4105  transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_CONNECTED);
4106  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
4107  transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
4108  transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid);
4109  l->activesub = sub;
4110  return res;
4111 }
4112 
4113 /* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
4114 static struct ast_frame *skinny_rtp_read(struct skinny_subchannel *sub)
4115 {
4116  struct ast_channel *ast = sub->owner;
4117  struct ast_frame *f;
4118 
4119  if (!sub->rtp) {
4120  /* We have no RTP allocated for this channel */
4121  return &ast_null_frame;
4122  }
4123 
4124  switch(ast->fdno) {
4125  case 0:
4126  f = ast_rtp_instance_read(sub->rtp, 0); /* RTP Audio */
4127  break;
4128  case 1:
4129  f = ast_rtp_instance_read(sub->rtp, 1); /* RTCP Control Channel */
4130  break;
4131  case 2:
4132  f = ast_rtp_instance_read(sub->vrtp, 0); /* RTP Video */
4133  break;
4134  case 3:
4135  f = ast_rtp_instance_read(sub->vrtp, 1); /* RTCP Control Channel for video */
4136  break;
4137 #if 0
4138  case 5:
4139  /* Not yet supported */
4140  f = ast_udptl_read(sub->udptl); /* UDPTL for T.38 */
4141  break;
4142 #endif
4143  default:
4144  f = &ast_null_frame;
4145  }
4146 
4147  if (ast) {
4148  /* We already hold the channel lock */
4149  if (f->frametype == AST_FRAME_VOICE) {
4150  if (f->subclass.codec != ast->nativeformats) {
4151  ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(f->subclass.codec));
4152  ast->nativeformats = f->subclass.codec;
4153  ast_set_read_format(ast, ast->readformat);
4154  ast_set_write_format(ast, ast->writeformat);
4155  }
4156  }
4157  }
4158  return f;
4159 }
4160 
4161 static struct ast_frame *skinny_read(struct ast_channel *ast)
4162 {
4163  struct ast_frame *fr;
4164  struct skinny_subchannel *sub = ast->tech_pvt;
4165  ast_mutex_lock(&sub->lock);
4166  fr = skinny_rtp_read(sub);
4167  ast_mutex_unlock(&sub->lock);
4168  return fr;
4169 }
4170 
4171 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
4172 {
4173  struct skinny_subchannel *sub = ast->tech_pvt;
4174  int res = 0;
4175  if (frame->frametype != AST_FRAME_VOICE) {
4176  if (frame->frametype == AST_FRAME_IMAGE) {
4177  return 0;
4178  } else {
4179  ast_log(LOG_WARNING, "Can't send %u type frames with skinny_write\n", frame->frametype);
4180  return 0;
4181  }
4182  } else {
4183  if (!(frame->subclass.codec & ast->nativeformats)) {
4184  char buf[256];
4185  ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
4187  ast_getformatname_multiple(buf, sizeof(buf), ast->nativeformats),
4190  return -1;
4191  }
4192  }
4193  if (sub) {
4194  ast_mutex_lock(&sub->lock);
4195  if (sub->rtp) {
4196  res = ast_rtp_instance_write(sub->rtp, frame);
4197  }
4198  ast_mutex_unlock(&sub->lock);
4199  }
4200  return res;
4201 }
4202 
4203 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
4204 {
4205  struct skinny_subchannel *sub = newchan->tech_pvt;
4206  ast_log(LOG_NOTICE, "skinny_fixup(%s, %s)\n", oldchan->name, newchan->name);
4207  if (sub->owner != oldchan) {
4208  ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
4209  return -1;
4210  }
4211  sub->owner = newchan;
4212  return 0;
4213 }
4214 
4215 static int skinny_senddigit_begin(struct ast_channel *ast, char digit)
4216 {
4217  return -1; /* Start inband indications */
4218 }
4219 
4220 static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
4221 {
4222 #if 0
4223  struct skinny_subchannel *sub = ast->tech_pvt;
4224  struct skinny_line *l = sub->parent;
4225  struct skinny_device *d = l->device;
4226  int tmp;
4227  /* not right */
4228  sprintf(tmp, "%d", digit);
4229  //transmit_tone(d, digit, l->instance, sub->callid);
4230 #endif
4231  return -1; /* Stop inband indications */
4232 }
4233 
4234 static int get_devicestate(struct skinny_line *l)
4235 {
4236  struct skinny_subchannel *sub;
4237  int res = AST_DEVICE_UNKNOWN;
4238 
4239  if (!l)
4240  res = AST_DEVICE_INVALID;
4241  else if (!l->device)
4242  res = AST_DEVICE_UNAVAILABLE;
4243  else if (l->dnd)
4244  res = AST_DEVICE_BUSY;
4245  else {
4246  if (l->hookstate == SKINNY_ONHOOK) {
4247  res = AST_DEVICE_NOT_INUSE;
4248  } else {
4249  res = AST_DEVICE_INUSE;
4250  }
4251 
4252  AST_LIST_TRAVERSE(&l->sub, sub, list) {
4253  if (sub->onhold) {
4254  res = AST_DEVICE_ONHOLD;
4255  break;
4256  }
4257  }
4258  }
4259 
4260  return res;
4261 }
4262 
4263 static char *control2str(int ind) {
4264  char *tmp;
4265 
4266  switch (ind) {
4267  case AST_CONTROL_HANGUP:
4268  return "Other end has hungup";
4269  case AST_CONTROL_RING:
4270  return "Local ring";
4271  case AST_CONTROL_RINGING:
4272  return "Remote end is ringing";
4273  case AST_CONTROL_ANSWER:
4274  return "Remote end has answered";
4275  case AST_CONTROL_BUSY:
4276  return "Remote end is busy";
4278  return "Make it go off hook";
4279  case AST_CONTROL_OFFHOOK:
4280  return "Line is off hook";
4282  return "Congestion (circuits busy)";
4283  case AST_CONTROL_FLASH:
4284  return "Flash hook";
4285  case AST_CONTROL_WINK:
4286  return "Wink";
4287  case AST_CONTROL_OPTION:
4288  return "Set a low-level option";
4289  case AST_CONTROL_RADIO_KEY:
4290  return "Key Radio";
4292  return "Un-Key Radio";
4293  case AST_CONTROL_PROGRESS:
4294  return "Remote end is making Progress";
4296  return "Remote end is proceeding";
4297  case AST_CONTROL_HOLD:
4298  return "Hold";
4299  case AST_CONTROL_UNHOLD:
4300  return "Unhold";
4301  case AST_CONTROL_SRCUPDATE:
4302  return "Media Source Update";
4304  return "Connected Line";
4306  return "Redirecting";
4308  return "Incomplete";
4309  case -1:
4310  return "Stop tone";
4311  default:
4313  return "Unknown";
4314  snprintf(tmp, CONTROL2STR_BUFSIZE, "UNKNOWN-%d", ind);
4315  return tmp;
4316  }
4317 }
4318 
4319 static int skinny_transfer(struct skinny_subchannel *sub)
4320 {
4321  struct skinny_subchannel *xferor; /* the sub doing the transferring */
4322  struct skinny_subchannel *xferee; /* the sub being transferred */
4323  struct ast_tone_zone_sound *ts = NULL;
4324 
4326  if (sub->xferor) {
4327  xferor = sub;
4328  xferee = sub->related;
4329  } else {
4330  xferor = sub;
4331  xferee = sub->related;
4332  }
4333 
4334  if (skinnydebug) {
4335  ast_debug(1, "Transferee channels (local/remote): %s and %s\n",
4336  xferee->owner->name, ast_bridged_channel(xferee->owner)?ast_bridged_channel(xferee->owner)->name:"");
4337  ast_debug(1, "Transferor channels (local/remote): %s and %s\n",
4338  xferor->owner->name, ast_bridged_channel(xferor->owner)?ast_bridged_channel(xferor->owner)->name:"");
4339  }
4340  if (ast_bridged_channel(xferor->owner)) {
4341  if (ast_bridged_channel(xferee->owner)) {
4343  }
4344  if (xferor->owner->_state == AST_STATE_RING) {
4345  /* play ringing inband */
4346  if ((ts = ast_get_indication_tone(xferor->owner->zone, "ring"))) {
4347  ast_playtones_start(xferor->owner, 0, ts->data, 1);
4348  ts = ast_tone_zone_sound_unref(ts);
4349  }
4350  }
4351  if (skinnydebug)
4352  ast_debug(1, "Transfer Masquerading %s to %s\n",
4353  xferee->owner->name, ast_bridged_channel(xferor->owner)?ast_bridged_channel(xferor->owner)->name:"");
4354  if (ast_channel_masquerade(xferee->owner, ast_bridged_channel(xferor->owner))) {
4355  ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
4356  ast_bridged_channel(xferor->owner)->name, xferee->owner->name);
4357  return -1;
4358  }
4359  } else if (ast_bridged_channel(xferee->owner)) {
4361  if (xferor->owner->_state == AST_STATE_RING) {
4362  /* play ringing inband */
4363  if ((ts = ast_get_indication_tone(xferor->owner->zone, "ring"))) {
4364  ast_playtones_start(xferor->owner, 0, ts->data, 1);
4365  ts = ast_tone_zone_sound_unref(ts);
4366  }
4367  }
4368  if (skinnydebug)
4369  ast_debug(1, "Transfer Masquerading %s to %s\n",
4370  xferor->owner->name, ast_bridged_channel(xferee->owner)?ast_bridged_channel(xferee->owner)->name:"");
4371  if (ast_channel_masquerade(xferor->owner, ast_bridged_channel(xferee->owner))) {
4372  ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
4373  ast_bridged_channel(xferee->owner)->name, xferor->owner->name);
4374  return -1;
4375  }
4376  return 0;
4377  } else {
4378  if (option_debug)
4379  ast_log(LOG_DEBUG, "Neither %s nor %s are in a bridge, nothing to transfer\n",
4380  xferor->owner->name, xferee->owner->name);
4381  }
4382  }
4383  return 0;
4384 }
4385 
4386 static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
4387 {
4388  struct skinny_subchannel *sub = ast->tech_pvt;
4389  struct skinny_line *l = sub->parent;
4390  struct skinny_device *d = l->device;
4391  struct skinnysession *s;
4392 
4393  if (!d) {
4394  ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
4395  return -1;
4396  }
4397  s = d->session;
4398 
4399  if (!s) {
4400  ast_log(LOG_NOTICE, "Asked to indicate '%s' condition on channel %s, but session does not exist.\n", control2str(ind), ast->name);
4401  return -1;
4402  }
4403 
4404  if (skinnydebug)
4405  ast_verb(3, "Asked to indicate '%s' condition on channel %s\n", control2str(ind), ast->name);
4406  switch(ind) {
4407  case AST_CONTROL_RINGING:
4408  if (sub->blindxfer) {
4409  if (skinnydebug)
4410  ast_debug(1, "Channel %s set up for Blind Xfer, so Xfer rather than ring device\n", ast->name);
4411  skinny_transfer(sub);
4412  break;
4413  }
4414  if (ast->_state != AST_STATE_UP) {
4415  if (!sub->progress) {
4416  if (!d->earlyrtp) {
4417  transmit_start_tone(d, SKINNY_ALERT, l->instance, sub->callid);
4418  }
4419  transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_RINGOUT);
4420  transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
4421  transmit_displaypromptstatus(d, "Ring Out", 0, l->instance, sub->callid);
4423  S_COR(ast->caller.id.name.valid, ast->caller.id.name.str, ""),
4424  S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""),
4425  S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, l->lastnumberdialed),
4426  S_COR(ast->connected.id.number.valid, ast->connected.id.number.str, l->lastnumberdialed),
4427  l->instance, sub->callid, 2); /* 2 = outgoing from phone */
4428  sub->ringing = 1;
4429  if (!d->earlyrtp) {
4430  break;
4431  }
4432  }
4433  }
4434  return -1; /* Tell asterisk to provide inband signalling */
4435  case AST_CONTROL_BUSY:
4436  if (ast->_state != AST_STATE_UP) {
4437  if (!d->earlyrtp) {
4438  transmit_start_tone(d, SKINNY_BUSYTONE, l->instance, sub->callid);
4439  }
4440  transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_BUSY);
4441  sub->alreadygone = 1;
4443  if (!d->earlyrtp) {
4444  break;
4445  }
4446  }
4447  return -1; /* Tell asterisk to provide inband signalling */
4449  /* Support for incomplete not supported for chan_skinny; treat as congestion */
4451  if (ast->_state != AST_STATE_UP) {
4452  if (!d->earlyrtp) {
4453  transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
4454  }
4455  transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_CONGESTION);
4456  sub->alreadygone = 1;
4458  if (!d->earlyrtp) {
4459  break;
4460  }
4461  }
4462  return -1; /* Tell asterisk to provide inband signalling */
4463  case AST_CONTROL_PROGRESS:
4464  if ((ast->_state != AST_STATE_UP) && !sub->progress && !sub->outgoing) {
4465  if (!d->earlyrtp) {
4466  transmit_start_tone(d, SKINNY_ALERT, l->instance, sub->callid);
4467  }
4468  transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_PROGRESS);
4469  transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid);
4471  S_COR(ast->caller.id.name.valid, ast->caller.id.name.str, ""),
4472  S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""),
4473  S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, l->lastnumberdialed),
4474  S_COR(ast->connected.id.number.valid, ast->connected.id.number.str, l->lastnumberdialed),
4475  l->instance, sub->callid, 2); /* 2 = outgoing from phone */
4476  sub->progress = 1;
4477  if (!d->earlyrtp) {
4478  break;
4479  }
4480  }
4481  return -1; /* Tell asterisk to provide inband signalling */
4482  case -1: /* STOP_TONE */
4483  transmit_stop_tone(d, l->instance, sub->callid);
4484  break;
4485  case AST_CONTROL_HOLD:
4486  ast_moh_start(ast, data, l->mohinterpret);
4487  break;
4488  case AST_CONTROL_UNHOLD:
4489  ast_moh_stop(ast);
4490  break;
4492  break;
4493  case AST_CONTROL_SRCUPDATE:
4495  break;
4496  case AST_CONTROL_SRCCHANGE:
4498  break;
4500  update_connectedline(sub, data, datalen);
4501  break;
4502  default:
4503  ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
4504  return -1; /* Tell asterisk to provide inband signalling */
4505  }
4506  return 0;
4507 }
4508 
4509 static struct ast_channel *skinny_new(struct skinny_line *l, int state, const char *linkedid)
4510 {
4511  struct ast_channel *tmp;
4512  struct skinny_subchannel *sub;
4513  struct skinny_device *d = l->device;
4514  struct ast_variable *v = NULL;
4515  int fmt;
4516 
4517  if (!l->device) {
4518  ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
4519  return NULL;
4520  }
4521 
4522  tmp = ast_channel_alloc(1, state, l->cid_num, l->cid_name, l->accountcode, l->exten, l->context, linkedid, l->amaflags, "Skinny/%s@%s-%d", l->name, d->name, callnums);
4523  if (!tmp) {
4524  ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
4525  return NULL;
4526  } else {
4527  sub = ast_calloc(1, sizeof(*sub));
4528  if (!sub) {
4529  ast_log(LOG_WARNING, "Unable to allocate Skinny subchannel\n");
4530  return NULL;
4531  } else {
4532  ast_mutex_init(&sub->lock);
4533 
4534  sub->owner = tmp;
4535  sub->callid = callnums++;
4536  d->lastlineinstance = l->instance;
4537  d->lastcallreference = sub->callid;
4538  sub->cxmode = SKINNY_CX_INACTIVE;
4539  sub->nat = l->nat;
4540  sub->parent = l;
4541  sub->onhold = 0;
4542  sub->blindxfer = 0;
4543  sub->xferor = 0;
4544  sub->related = NULL;
4545 
4546  AST_LIST_INSERT_HEAD(&l->sub, sub, list);
4547  //l->activesub = sub;
4548  }
4549  tmp->tech = &skinny_tech;
4550  tmp->tech_pvt = sub;
4551  tmp->nativeformats = l->capability;
4552  if (!tmp->nativeformats)
4553  // Should throw an error
4555  fmt = ast_best_codec(tmp->nativeformats);
4556  if (skinnydebug) {
4557  char buf[256];
4558  ast_verb(1, "skinny_new: tmp->nativeformats=%s fmt=%s\n",
4559  ast_getformatname_multiple(buf, sizeof(buf), tmp->nativeformats),
4560  ast_getformatname(fmt));
4561  }
4562  if (sub->rtp) {
4563  ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
4564  }
4565  if (state == AST_STATE_RING) {
4566  tmp->rings = 1;
4567  }
4568  tmp->writeformat = fmt;
4569  tmp->rawwriteformat = fmt;
4570  tmp->readformat = fmt;
4571  tmp->rawreadformat = fmt;
4572  if (!ast_strlen_zero(l->language))
4573  ast_string_field_set(tmp, language, l->language);
4574  if (!ast_strlen_zero(l->accountcode))
4575  ast_string_field_set(tmp, accountcode, l->accountcode);
4576  if (!ast_strlen_zero(l->parkinglot))
4577  ast_string_field_set(tmp, parkinglot, l->parkinglot);
4578  if (l->amaflags)
4579  tmp->amaflags = l->amaflags;
4580 
4582  tmp->callgroup = l->callgroup;
4583  tmp->pickupgroup = l->pickupgroup;
4584 
4585  /* XXX Need to figure out how to handle CFwdNoAnswer */
4586  if (l->cfwdtype & SKINNY_CFWD_ALL) {
4587  ast_string_field_set(tmp, call_forward, l->call_forward_all);
4588  } else if (l->cfwdtype & SKINNY_CFWD_BUSY) {
4590  ast_string_field_set(tmp, call_forward, l->call_forward_busy);
4591  }
4592  }
4593 
4594  ast_copy_string(tmp->context, l->context, sizeof(tmp->context));
4595  ast_copy_string(tmp->exten, l->exten, sizeof(tmp->exten));
4596 
4597  /* Don't use ast_set_callerid() here because it will
4598  * generate a needless NewCallerID event */
4599  if (!ast_strlen_zero(l->cid_num)) {
4600  tmp->caller.ani.number.valid = 1;
4601  tmp->caller.ani.number.str = ast_strdup(l->cid_num);
4602  }
4603 
4604  tmp->priority = 1;
4606 
4607  if (sub->rtp)
4609 
4610  /* Set channel variables for this call from configuration */
4611  for (v = l->chanvars ; v ; v = v->next)
4612  pbx_builtin_setvar_helper(tmp, v->name, v->value);
4613 
4614  if (state != AST_STATE_DOWN) {
4615  if (ast_pbx_start(tmp)) {
4616  ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
4617  ast_hangup(tmp);
4618  tmp = NULL;
4619  }
4620  }
4621  }
4622  return tmp;
4623 }
4624 
4625 static int skinny_hold(struct skinny_subchannel *sub)
4626 {
4627  struct skinny_line *l = sub->parent;
4628  struct skinny_device *d = l->device;
4629 
4630  /* Don't try to hold a channel that doesn't exist */
4631  if (!sub || !sub->owner) {
4632  return 0;
4633  }
4634  if (!d) {
4635  ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
4636  return 0;
4637  }
4638 
4639  /* Channel needs to be put on hold */
4640  if (skinnydebug)
4641  ast_verb(1, "Putting on Hold(%d)\n", l->instance);
4642 
4644  S_OR(l->mohsuggest, NULL),
4645  !ast_strlen_zero(l->mohsuggest) ? strlen(l->mohsuggest) + 1 : 0);
4646 
4650 
4651  transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_HOLD);
4653  sub->onhold = 1;
4654  return 1;
4655 }
4656 
4657 static int skinny_unhold(struct skinny_subchannel *sub)
4658 {
4659  struct skinny_line *l = sub->parent;
4660  struct skinny_device *d = l->device;
4661 
4662  /* Don't try to unhold a channel that doesn't exist */
4663  if (!sub || !sub->owner) {
4664  return 0;
4665  }
4666  if (!d) {
4667  ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
4668  return 0;
4669  }
4670 
4671  /* Channel is on hold, so we will unhold */
4672  if (skinnydebug)
4673  ast_verb(1, "Taking off Hold(%d)\n", l->instance);
4674 
4676 
4678 
4679  transmit_connect(d, sub);
4680  transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_CONNECTED);
4682  l->hookstate = SKINNY_OFFHOOK;
4683  sub->onhold = 0;
4684  return 1;
4685 }
4686 
4687 static int handle_hold_button(struct skinny_subchannel *sub)
4688 {
4689  if (!sub)
4690  return -1;
4691  if (sub->related) {
4692  skinny_hold(sub);
4693  skinny_unhold(sub->related);
4694  sub->parent->activesub = sub->related;
4695  } else {
4696  if (sub->onhold) {
4697  skinny_unhold(sub);
4698  transmit_selectsoftkeys(sub->parent->device, sub->parent->instance, sub->callid, KEYDEF_CONNECTED);
4699  } else {
4700  skinny_hold(sub);
4701  transmit_selectsoftkeys(sub->parent->device, sub->parent->instance, sub->callid, KEYDEF_ONHOLD);
4702  }
4703  }
4704  return 1;
4705 }
4706 
4708 {
4709  struct skinny_line *l;
4710  struct skinny_device *d;
4711  struct skinny_subchannel *newsub;
4712  struct ast_channel *c;
4713  pthread_t t;
4714 
4715  if (!sub) {
4716  ast_verbose("Transfer: No subchannel to transfer\n");
4717  return -1;
4718  }
4719 
4720  l = sub->parent;
4721  d = l->device;
4722 
4723  if (!d) {
4724  ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
4725  return -1;
4726  }
4727 
4728  if (!sub->related) {
4729  /* Another sub has not been created so this must be first XFER press */
4730  if (!sub->onhold) {
4731  skinny_hold(sub);
4732  }
4733  c = skinny_new(l, AST_STATE_DOWN, NULL);
4734  if (c) {
4735  newsub = c->tech_pvt;
4736  /* point the sub and newsub at each other so we know they are related */
4737  newsub->related = sub;
4738  sub->related = newsub;
4739  newsub->xferor = 1;
4740  l->activesub = newsub;
4741  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
4743  transmit_clear_display_message(d, l->instance, newsub->callid);
4744  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, newsub->callid);
4745  transmit_selectsoftkeys(d, l->instance, newsub->callid, KEYDEF_OFFHOOKWITHFEAT);
4746  /* start the switch thread */
4747  if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
4748  ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
4749  ast_hangup(c);
4750  }
4751  } else {
4752  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
4753  }
4754  } else {
4755  /* We already have a related sub so we can either complete XFER or go into BLINDXFER (or cancel BLINDXFER */
4756  if (sub->blindxfer) {
4757  /* toggle blindxfer off */
4758  sub->blindxfer = 0;
4759  sub->related->blindxfer = 0;
4760  /* we really need some indications */
4761  } else {
4762  /* We were doing attended transfer */
4763  if (sub->owner->_state == AST_STATE_DOWN || sub->related->owner->_state == AST_STATE_DOWN) {
4764  /* one of the subs so we cant transfer yet, toggle blindxfer on */
4765  sub->blindxfer = 1;
4766  sub->related->blindxfer = 1;
4767  } else {
4768  /* big assumption we have two channels, lets transfer */
4769  skinny_transfer(sub);
4770  }
4771  }
4772  }
4773  return 0;
4774 }
4775 
4776 static int handle_keep_alive_message(struct skinny_req *req, struct skinnysession *s)
4777 {
4778  if (!(req = req_alloc(0, KEEP_ALIVE_ACK_MESSAGE)))
4779  return -1;
4780 
4781  transmit_response(s->device, req);
4782  return 1;
4783 }
4784 
4785 static int handle_register_message(struct skinny_req *req, struct skinnysession *s)
4786 {
4787  struct skinny_device *d = NULL;
4788  char name[16];
4789  int res;
4790 
4791  memcpy(&name, req->data.reg.name, sizeof(name));
4792 
4793  res = skinny_register(req, s);
4794  if (!res) {
4795  ast_log(LOG_ERROR, "Rejecting Device %s: Device not found\n", name);
4796  if (!(req = req_alloc(sizeof(struct register_rej_message), REGISTER_REJ_MESSAGE)))
4797  return -1;
4798 
4799  snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name);
4800 
4801  /* transmit_respons in line as we don't have a valid d */
4802  ast_mutex_lock(&s->lock);
4803 
4804  if (letohl(req->len) > SKINNY_MAX_PACKET || letohl(req->len) < 0) {
4805  ast_log(LOG_WARNING, "transmit_response: the length (%d) of the request is out of bounds (%d) \n", letohl(req->len), SKINNY_MAX_PACKET);
4806  ast_mutex_unlock(&s->lock);
4807  return -1;
4808  }
4809 
4810  memset(s->outbuf, 0, sizeof(s->outbuf));
4811  memcpy(s->outbuf, req, skinny_header_size);
4812  memcpy(s->outbuf+skinny_header_size, &req->data, letohl(req->len));
4813 
4814  res = write(s->fd, s->outbuf, letohl(req->len)+8);
4815 
4816  if (res != letohl(req->len)+8) {
4817  ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, letohl(req->len)+8, strerror(errno));
4818  }
4819 
4820  ast_mutex_unlock(&s->lock);
4821 
4822  return 0;
4823  }
4824  ast_atomic_fetchadd_int(&unauth_sessions, -1);
4825 
4826  ast_verb(3, "Device '%s' successfully registered\n", name);
4827 
4828  d = s->device;
4829 
4830  if (!(req = req_alloc(sizeof(struct register_ack_message), REGISTER_ACK_MESSAGE)))
4831  return -1;
4832 
4833  req->data.regack.res[0] = '0';
4834  req->data.regack.res[1] = '\0';
4835  req->data.regack.keepAlive = htolel(keep_alive);
4836  memcpy(req->data.regack.dateTemplate, date_format, sizeof(req->data.regack.dateTemplate));
4837  req->data.regack.res2[0] = '0';
4838  req->data.regack.res2[1] = '\0';
4839  req->data.regack.secondaryKeepAlive = htolel(keep_alive);
4840  transmit_response(d, req);
4841  if (skinnydebug)
4842  ast_verb(1, "Requesting capabilities\n");
4843 
4844  if (!(req = req_alloc(0, CAPABILITIES_REQ_MESSAGE)))
4845  return -1;
4846 
4847  transmit_response(d, req);
4848 
4849  return res;
4850 }
4851 
4852 static int handle_callforward_button(struct skinny_subchannel *sub, int cfwdtype)
4853 {
4854  struct skinny_line *l = sub->parent;
4855  struct skinny_device *d = l->device;
4856  struct ast_channel *c = sub->owner;
4857  pthread_t t;
4858 
4859  if (!d) {
4860  ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
4861  return 0;
4862  }
4863 
4864  if (l->hookstate == SKINNY_ONHOOK) {
4865  l->hookstate = SKINNY_OFFHOOK;
4867  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
4869  }
4870  transmit_clear_display_message(d, l->instance, sub->callid);
4871 
4872  if (l->cfwdtype & cfwdtype) {
4873  set_callforwards(l, NULL, cfwdtype);
4874  ast_safe_sleep(c, 500);
4879  transmit_clearpromptmessage(d, l->instance, sub->callid);
4880  transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
4883  transmit_displaynotify(d, "CFwd disabled", 10);
4884  if (sub->owner && sub->owner->_state != AST_STATE_UP) {
4885  ast_indicate(c, -1);
4886  ast_hangup(c);
4887  }
4888  transmit_cfwdstate(d, l);
4889  } else {
4890  l->getforward = cfwdtype;
4891  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
4892  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
4893  if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
4894  ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
4895  ast_hangup(c);
4896  }
4897  }
4898  return 0;
4899 }
4900 static int handle_ip_port_message(struct skinny_req *req, struct skinnysession *s)
4901 {
4902  /* no response necessary */
4903  return 1;
4904 }
4905 
4906 static int handle_keypad_button_message(struct skinny_req *req, struct skinnysession *s)
4907 {
4908  struct skinny_subchannel *sub = NULL;
4909  struct skinny_line *l;
4910  struct skinny_device *d = s->device;
4911  struct ast_frame f = { 0, };
4912  char dgt;
4913  int digit;
4914  int lineInstance;
4915  int callReference;
4916 
4917  digit = letohl(req->data.keypad.button);
4918  lineInstance = letohl(req->data.keypad.lineInstance);
4919  callReference = letohl(req->data.keypad.callReference);
4920 
4921  if (digit == 14) {
4922  dgt = '*';
4923  } else if (digit == 15) {
4924  dgt = '#';
4925  } else if (digit >= 0 && digit <= 9) {
4926  dgt = '0' + digit;
4927  } else {
4928  /* digit=10-13 (A,B,C,D ?), or
4929  * digit is bad value
4930  *
4931  * probably should not end up here, but set
4932  * value for backward compatibility, and log
4933  * a warning.
4934  */
4935  dgt = '0' + digit;
4936  ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
4937  }
4938 
4939  f.subclass.integer = dgt;
4940 
4941  f.src = "skinny";
4942 
4943  if (lineInstance && callReference)
4944  sub = find_subchannel_by_instance_reference(d, lineInstance, callReference);
4945  else
4946  sub = d->activeline->activesub;
4947  //sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
4948 
4949  if (!sub)
4950  return 0;
4951 
4952  l = sub->parent;
4953  if (sub->owner) {
4954  if (sub->owner->_state == 0) {
4956  ast_queue_frame(sub->owner, &f);
4957  }
4958  /* XXX MUST queue this frame to all lines in threeway call if threeway call is active */
4960  ast_queue_frame(sub->owner, &f);
4961  /* XXX This seriously needs to be fixed */
4962  if (AST_LIST_NEXT(sub, list) && AST_LIST_NEXT(sub, list)->owner) {
4963  if (sub->owner->_state == 0) {
4965  ast_queue_frame(AST_LIST_NEXT(sub, list)->owner, &f);
4966  }
4968  ast_queue_frame(AST_LIST_NEXT(sub, list)->owner, &f);
4969  }
4970  } else {
4971  if (skinnydebug)
4972  ast_verb(1, "No owner: %s\n", l->name);
4973  }
4974  return 1;
4975 }
4976 
4977 static int handle_stimulus_message(struct skinny_req *req, struct skinnysession *s)
4978 {
4979  struct skinny_device *d = s->device;
4980  struct skinny_line *l;
4981  struct skinny_subchannel *sub;
4982  /*struct skinny_speeddial *sd;*/
4983  struct ast_channel *c;
4984  pthread_t t;
4985  int event;
4986  int instance;
4987  int callreference;
4988  /*int res = 0;*/
4989 
4990  event = letohl(req->data.stimulus.stimulus);
4991  instance = letohl(req->data.stimulus.stimulusInstance);
4992  callreference = letohl(req->data.stimulus.callreference);
4993  if (skinnydebug)
4994  ast_verb(1, "callreference in handle_stimulus_message is '%d'\n", callreference);
4995 
4996  /* Note that this call should be using the passed in instance and callreference */
4997  sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
4998 
4999  if (!sub) {
5000  l = find_line_by_instance(d, d->lastlineinstance);
5001  if (!l) {
5002  return 0;
5003  }
5004  sub = l->activesub;
5005  } else {
5006  l = sub->parent;
5007  }
5008 
5009  switch(event) {
5010  case STIMULUS_REDIAL:
5011  if (skinnydebug)
5012  ast_verb(1, "Received Stimulus: Redial(%d/%d)\n", instance, callreference);
5013 
5014  if (ast_strlen_zero(l->lastnumberdialed)) {
5015  ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found.\n");
5016  l->hookstate = SKINNY_ONHOOK;
5021  transmit_clearpromptmessage(d, l->instance, sub->callid);
5022  transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
5025  break;
5026  }
5027 
5028  c = skinny_new(l, AST_STATE_DOWN, NULL);
5029  if (!c) {
5030  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5031  } else {
5032  sub = c->tech_pvt;
5033  l = sub->parent;
5034  l->activesub = sub;
5035  if (l->hookstate == SKINNY_ONHOOK) {
5036  l->hookstate = SKINNY_OFFHOOK;
5037  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5039  }
5040  transmit_clear_display_message(d, l->instance, sub->callid);
5041  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
5042  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
5043 
5044  if (!ast_ignore_pattern(c->context, l->lastnumberdialed)) {
5045  transmit_stop_tone(d, l->instance, sub->callid);
5046  }
5047  ast_copy_string(c->exten, l->lastnumberdialed, sizeof(c->exten));
5048  if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
5049  ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
5050  ast_hangup(c);
5051  }
5052  }
5053  break;
5054  case STIMULUS_SPEEDDIAL:
5055  {
5056  struct skinny_speeddial *sd;
5057 
5058  if (skinnydebug)
5059  ast_verb(1, "Received Stimulus: SpeedDial(%d/%d)\n", instance, callreference);
5060  if (!(sd = find_speeddial_by_instance(d, instance, 0))) {
5061  return 0;
5062  }
5063 
5064  if (!sub || !sub->owner)
5065  c = skinny_new(l, AST_STATE_DOWN, NULL);
5066  else
5067  c = sub->owner;
5068 
5069  if (!c) {
5070  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5071  } else {
5072  sub = c->tech_pvt;
5073  l = sub->parent;
5074  l->activesub = sub;
5075  if (l->hookstate == SKINNY_ONHOOK) {
5076  l->hookstate = SKINNY_OFFHOOK;
5078  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5080  }
5081  transmit_clear_display_message(d, l->instance, sub->callid);
5082  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
5083  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
5084 
5085  if (!ast_ignore_pattern(c->context, sd->exten)) {
5086  transmit_stop_tone(d, l->instance, sub->callid);
5087  }
5088  if (ast_exists_extension(c, c->context, sd->exten, 1, l->cid_num)) {
5089  ast_copy_string(c->exten, sd->exten, sizeof(c->exten));
5090  ast_copy_string(l->lastnumberdialed, sd->exten, sizeof(l->lastnumberdialed));
5091 
5092  if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
5093  ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
5094  ast_hangup(c);
5095  }
5096  break;
5097  }
5098  }
5099  }
5100  break;
5101  case STIMULUS_HOLD:
5102  if (skinnydebug)
5103  ast_verb(1, "Received Stimulus: Hold(%d/%d)\n", instance, callreference);
5104  handle_hold_button(sub);
5105  break;
5106  case STIMULUS_TRANSFER:
5107  if (skinnydebug)
5108  ast_verb(1, "Received Stimulus: Transfer(%d/%d)\n", instance, callreference);
5109  if (l->transfer)
5111  else
5112  transmit_displaynotify(d, "Transfer disabled", 10);
5113  break;
5114  case STIMULUS_CONFERENCE:
5115  if (skinnydebug)
5116  ast_verb(1, "Received Stimulus: Conference(%d/%d)\n", instance, callreference);
5117  /* XXX determine the best way to pull off a conference. Meetme? */
5118  break;
5119  case STIMULUS_VOICEMAIL:
5120  if (skinnydebug)
5121  ast_verb(1, "Received Stimulus: Voicemail(%d/%d)\n", instance, callreference);
5122 
5123  if (!sub || !sub->owner) {
5124  c = skinny_new(l, AST_STATE_DOWN, NULL);
5125  } else {
5126  c = sub->owner;
5127  }
5128  if (!c) {
5129  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5130  } else {
5131  sub = c->tech_pvt;
5132  l = sub->parent;
5133  l->activesub = sub;
5134 
5135  if (ast_strlen_zero(l->vmexten)) /* Exit the call if no VM pilot */
5136  break;
5137 
5138  if (l->hookstate == SKINNY_ONHOOK){
5139  l->hookstate = SKINNY_OFFHOOK;
5141  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5143  }
5144 
5145  transmit_clear_display_message(d, l->instance, sub->callid);
5146  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
5147  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
5148 
5149  if (!ast_ignore_pattern(c->context, l->vmexten)) {
5150  transmit_stop_tone(d, l->instance, sub->callid);
5151  }
5152 
5153  if (ast_exists_extension(c, c->context, l->vmexten, 1, l->cid_num)) {
5154  ast_copy_string(c->exten, l->vmexten, sizeof(c->exten));
5155  ast_copy_string(l->lastnumberdialed, l->vmexten, sizeof(l->lastnumberdialed));
5156  if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
5157  ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
5158  ast_hangup(c);
5159  }
5160  break;
5161  }
5162  }
5163  break;
5164  case STIMULUS_CALLPARK:
5165  {
5166  int extout;
5167  char message[32];
5168 
5169  if (skinnydebug)
5170  ast_verb(1, "Received Stimulus: Park Call(%d/%d)\n", instance, callreference);
5171 
5172  if ((sub && sub->owner) && (sub->owner->_state == AST_STATE_UP)){
5173  c = sub->owner;
5174  if (ast_bridged_channel(c)) {
5175  if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) {
5176  snprintf(message, sizeof(message), "Call Parked at: %d", extout);
5177  transmit_displaynotify(d, message, 10);
5178  } else {
5179  transmit_displaynotify(d, "Call Park failed", 10);
5180  }
5181  } else {
5182  transmit_displaynotify(d, "Call Park not available", 10);
5183  }
5184  } else {
5185  transmit_displaynotify(d, "Call Park not available", 10);
5186  }
5187  break;
5188  }
5189  case STIMULUS_DND:
5190  if (skinnydebug)
5191  ast_verb(1, "Received Stimulus: DND (%d/%d)\n", instance, callreference);
5192 
5193  /* Do not disturb */
5194  if (l->dnd != 0){
5195  ast_verb(3, "Disabling DND on %s@%s\n", l->name, d->name);
5196  l->dnd = 0;
5198  transmit_displaynotify(d, "DnD disabled", 10);
5199  } else {
5200  ast_verb(3, "Enabling DND on %s@%s\n", l->name, d->name);
5201  l->dnd = 1;
5203  transmit_displaynotify(d, "DnD enabled", 10);
5204  }
5205  break;
5206  case STIMULUS_FORWARDALL:
5207  if (skinnydebug)
5208  ast_verb(1, "Received Stimulus: Forward All(%d/%d)\n", instance, callreference);
5209 
5210  if (!sub || !sub->owner) {
5211  c = skinny_new(l, AST_STATE_DOWN, NULL);
5212  } else {
5213  c = sub->owner;
5214  }
5215 
5216  if (!c) {
5217  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5218  } else {
5219  sub = c->tech_pvt;
5221  }
5222  break;
5223  case STIMULUS_FORWARDBUSY:
5224  if (skinnydebug)
5225  ast_verb(1, "Received Stimulus: Forward Busy (%d/%d)\n", instance, callreference);
5226 
5227  if (!sub || !sub->owner) {
5228  c = skinny_new(l, AST_STATE_DOWN, NULL);
5229  } else {
5230  c = sub->owner;
5231  }
5232 
5233  if (!c) {
5234  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5235  } else {
5236  sub = c->tech_pvt;
5238  }
5239  break;
5241  if (skinnydebug)
5242  ast_verb(1, "Received Stimulus: Forward No Answer (%d/%d)\n", instance, callreference);
5243 
5244 #if 0 /* Not sure how to handle this yet */
5245  if (!sub || !sub->owner) {
5246  c = skinny_new(l, AST_STATE_DOWN, NULL);
5247  } else {
5248  c = sub->owner;
5249  }
5250 
5251  if (!c) {
5252  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5253  } else {
5254  sub = c->tech_pvt;
5256  }
5257 #endif
5258  break;
5259  case STIMULUS_DISPLAY:
5260  /* Not sure what this is */
5261  if (skinnydebug)
5262  ast_verb(1, "Received Stimulus: Display(%d/%d)\n", instance, callreference);
5263  break;
5264  case STIMULUS_LINE:
5265  if (skinnydebug)
5266  ast_verb(1, "Received Stimulus: Line(%d/%d)\n", instance, callreference);
5267 
5268  l = find_line_by_instance(d, instance);
5269 
5270  if (!l) {
5271  return 0;
5272  }
5273 
5274  d->activeline = l;
5275 
5276  /* turn the speaker on */
5280 
5281  l->hookstate = SKINNY_OFFHOOK;
5282 
5283  if (sub && sub->outgoing) {
5284  /* We're answering a ringing call */
5286  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5288  transmit_stop_tone(d, l->instance, sub->callid);
5289  transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_CONNECTED);
5290  transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid);
5291  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
5292  start_rtp(sub);
5294  } else {
5295  if (sub && sub->owner) {
5296  ast_debug(1, "Current subchannel [%s] already has owner\n", sub->owner->name);
5297  } else {
5298  c = skinny_new(l, AST_STATE_DOWN, NULL);
5299  if (c) {
5300  sub = c->tech_pvt;
5301  l->activesub = sub;
5302  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5304  transmit_clear_display_message(d, l->instance, sub->callid);
5305  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
5306  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK);
5307 
5308  /* start the switch thread */
5309  if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
5310  ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
5311  ast_hangup(c);
5312  }
5313  } else {
5314  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5315  }
5316  }
5317  }
5318  break;
5319  default:
5320  if (skinnydebug)
5321  ast_verb(1, "RECEIVED UNKNOWN STIMULUS: %d(%d/%d)\n", event, instance, callreference);
5322  break;
5323  }
5324  ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
5325 
5326  return 1;
5327 }
5328 
5329 static int handle_offhook_message(struct skinny_req *req, struct skinnysession *s)
5330 {
5331  struct skinny_device *d = s->device;
5332  struct skinny_line *l;
5333  struct skinny_subchannel *sub;
5334  struct ast_channel *c;
5335  struct skinny_line *tmp;
5336  pthread_t t;
5337  int instance;
5338 
5339  /* if any line on a device is offhook, than the device must be offhook,
5340  unless we have shared lines CCM seems that it would never get here,
5341  but asterisk does, so we may need to do more work. Ugly, we should
5342  probably move hookstate from line to device, afterall, it's actually
5343  a device that changes hookstates */
5344 
5345  AST_LIST_TRAVERSE(&d->lines, tmp, list) {
5346  if (tmp->hookstate == SKINNY_OFFHOOK) {
5347  ast_verbose(VERBOSE_PREFIX_3 "Got offhook message when device (%s@%s) already offhook\n", tmp->name, d->name);
5348  return 0;
5349  }
5350  }
5351 
5352  instance = letohl(req->data.offhook.instance);
5353 
5354  if (instance) {
5355  sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
5356  if (!sub) {
5357  l = find_line_by_instance(d, d->lastlineinstance);
5358  if (!l) {
5359  return 0;
5360  }
5361  } else {
5362  l = sub->parent;
5363  }
5364  } else {
5365  l = d->activeline;
5366  sub = l->activesub;
5367  }
5368 
5369  /* Not ideal, but let's send updated time at onhook and offhook, as it clears the display */
5371 
5373  l->hookstate = SKINNY_OFFHOOK;
5374 
5375  ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
5376 
5377  if (sub && sub->onhold) {
5378  return 1;
5379  }
5380 
5382 
5383  if (sub && sub->outgoing) {
5384  /* We're answering a ringing call */
5386  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5388  transmit_stop_tone(d, l->instance, sub->callid);
5389  transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_CONNECTED);
5390  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
5391  start_rtp(sub);
5393  } else {
5394  if (sub && sub->owner) {
5395  ast_debug(1, "Current sub [%s] already has owner\n", sub->owner->name);
5396  } else {
5397  c = skinny_new(l, AST_STATE_DOWN, NULL);
5398  if (c) {
5399  sub = c->tech_pvt;
5400  l->activesub = sub;
5401  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5403  transmit_clear_display_message(d, l->instance, sub->callid);
5404  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
5405  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK);
5406 
5407  /* start the switch thread */
5408  if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
5409  ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
5410  ast_hangup(c);
5411  }
5412  } else {
5413  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5414  }
5415  }
5416  }
5417  return 1;
5418 }
5419 
5420 static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s)
5421 {
5422  struct skinny_device *d = s->device;
5423  struct skinny_line *l;
5424  struct skinny_subchannel *sub;
5425  int instance;
5426  int reference;
5427  int onlysub = 0;
5428 
5429  instance = letohl(req->data.onhook.instance);
5430  reference = letohl(req->data.onhook.reference);
5431 
5432  if (instance && reference) {
5433  sub = find_subchannel_by_instance_reference(d, instance, reference);
5434  if (!sub) {
5435  return 0;
5436  }
5437  l = sub->parent;
5438  } else {
5439  l = d->activeline;
5440  sub = l->activesub;
5441  if (!sub) {
5442  return 0;
5443  }
5444  }
5445 
5446  if (l->hookstate == SKINNY_ONHOOK) {
5447  /* Something else already put us back on hook */
5448  return 0;
5449  }
5450 
5451  ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
5452 
5453  if (sub->onhold) {
5454  return 0;
5455  }
5456 
5457  if (!AST_LIST_NEXT(sub, list)) {
5458  onlysub = 1;
5459  } else {
5460  AST_LIST_REMOVE(&l->sub, sub, list);
5461  }
5462 
5463  sub->cxmode = SKINNY_CX_RECVONLY;
5464  if (onlysub || sub->xferor){ /* is this the only call to this device? */
5465  l->hookstate = SKINNY_ONHOOK;
5466  if (skinnydebug)
5467  ast_debug(1, "Skinny %s@%s-%d went on hook\n", l->name, d->name, reference);
5468  }
5469 
5470  if (l->hookstate == SKINNY_ONHOOK) {
5474  transmit_clearpromptmessage(d, instance, sub->callid);
5475  transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
5478  } else if (l->hookstate == SKINNY_OFFHOOK) {
5479  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5481  } else {
5482  transmit_callstate(d, l->instance, sub->callid, l->hookstate);
5483  }
5484 
5485  if (l->transfer && sub->xferor && sub->owner->_state >= AST_STATE_RING) {
5486  /* We're allowed to transfer, we have two active calls and
5487  we made at least one of the calls. Let's try and transfer */
5489  } else {
5490  /* Hangup the current call */
5491  /* If there is another active call, skinny_hangup will ring the phone with the other call */
5492  if (sub->xferor && sub->related){
5493  sub->related->related = NULL;
5494  sub->related->blindxfer = 0;
5495  }
5496 
5497  if (sub->owner) {
5498  sub->alreadygone = 1;
5499  ast_queue_hangup(sub->owner);
5500  } else {
5501  ast_log(LOG_WARNING, "Skinny(%s@%s-%u) channel already destroyed\n",
5502  l->name, d->name, sub->callid);
5503  }
5504  /* Not ideal, but let's send updated time at onhook and offhook, as it clears the display */
5506  }
5507  return 1;
5508 }
5509 
5511 {
5512  struct skinny_device *d = s->device;
5513  struct skinny_line *l;
5514  uint32_t count = 0;
5515  format_t codecs = 0;
5516  int i;
5517  char buf[256];
5518 
5519  count = letohl(req->data.caps.count);
5520  if (count > SKINNY_MAX_CAPABILITIES) {
5521  count = SKINNY_MAX_CAPABILITIES;
5522  ast_log(LOG_WARNING, "Received more capabilities than we can handle (%d). Ignoring the rest.\n", SKINNY_MAX_CAPABILITIES);
5523  }
5524 
5525  for (i = 0; i < count; i++) {
5526  format_t acodec = 0;
5527  int scodec = 0;
5528  scodec = letohl(req->data.caps.caps[i].codec);
5529  acodec = codec_skinny2ast(scodec);
5530  if (skinnydebug)
5531  ast_verb(1, "Adding codec capability '%" PRId64 " (%d)'\n", acodec, scodec);
5532  codecs |= acodec;
5533  }
5534 
5535  d->capability = d->confcapability & codecs;
5536  ast_verb(0, "Device capability set to '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), d->capability));
5537  AST_LIST_TRAVERSE(&d->lines, l, list) {
5538  ast_mutex_lock(&l->lock);
5539  l->capability = l->confcapability & d->capability;
5540  ast_mutex_unlock(&l->lock);
5541  }
5542 
5543  return 1;
5544 }
5545 
5547 {
5548  struct skinny_device *d = s->device;
5549  struct skinny_line *l;
5550  int i;
5551 
5552  struct skinny_speeddial *sd;
5553  struct button_definition_template btn[42];
5554  int lineInstance = 1;
5555  int speeddialInstance = 1;
5556  int buttonCount = 0;
5557 
5559  return -1;
5560 
5561  memset(&btn, 0, sizeof(btn));
5562 
5563  get_button_template(s, btn);
5564 
5565  for (i=0; i<42; i++) {
5566  int btnSet = 0;
5567  switch (btn[i].buttonDefinition) {
5568  case BT_CUST_LINE:
5569  /* assume failure */
5572 
5573  AST_LIST_TRAVERSE(&d->lines, l, list) {
5574  if (l->instance == lineInstance) {
5575  ast_verb(0, "Adding button: %d, %d\n", BT_LINE, lineInstance);
5577  req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
5578  lineInstance++;
5579  buttonCount++;
5580  btnSet = 1;
5581  break;
5582  }
5583  }
5584 
5585  if (!btnSet) {
5586  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
5587  if (sd->isHint && sd->instance == lineInstance) {
5588  ast_verb(0, "Adding button: %d, %d\n", BT_LINE, lineInstance);
5590  req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
5591  lineInstance++;
5592  buttonCount++;
5593  btnSet = 1;
5594  break;
5595  }
5596  }
5597  }
5598  break;
5599  case BT_CUST_LINESPEEDDIAL:
5600  /* assume failure */
5603 
5604  AST_LIST_TRAVERSE(&d->lines, l, list) {
5605  if (l->instance == lineInstance) {
5606  ast_verb(0, "Adding button: %d, %d\n", BT_LINE, lineInstance);
5608  req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
5609  lineInstance++;
5610  buttonCount++;
5611  btnSet = 1;
5612  break;
5613  }
5614  }
5615 
5616  if (!btnSet) {
5617  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
5618  if (sd->isHint && sd->instance == lineInstance) {
5619  ast_verb(0, "Adding button: %d, %d\n", BT_LINE, lineInstance);
5621  req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
5622  lineInstance++;
5623  buttonCount++;
5624  btnSet = 1;
5625  break;
5626  } else if (!sd->isHint && sd->instance == speeddialInstance) {
5627  ast_verb(0, "Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
5629  req->data.buttontemplate.definition[i].instanceNumber = speeddialInstance;
5630  speeddialInstance++;
5631  buttonCount++;
5632  btnSet = 1;
5633  break;
5634  }
5635  }
5636  }
5637  break;
5638  case BT_LINE:
5641 
5642  AST_LIST_TRAVERSE(&d->lines, l, list) {
5643  if (l->instance == lineInstance) {
5644  ast_verb(0, "Adding button: %d, %d\n", BT_LINE, lineInstance);
5646  req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
5647  lineInstance++;
5648  buttonCount++;
5649  btnSet = 1;
5650  break;
5651  }
5652  }
5653  break;
5654  case BT_SPEEDDIAL:
5657 
5658  AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
5659  if (!sd->isHint && sd->instance == speeddialInstance) {
5660  ast_verb(0, "Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
5662  req->data.buttontemplate.definition[i].instanceNumber = speeddialInstance - 1;
5663  speeddialInstance++;
5664  buttonCount++;
5665  btnSet = 1;
5666  break;
5667  }
5668  }
5669  break;
5670  case BT_NONE:
5671  break;
5672  default:
5673  ast_verb(0, "Adding button: %d, %d\n", btn[i].buttonDefinition, 0);
5674  req->data.buttontemplate.definition[i].buttonDefinition = htolel(btn[i].buttonDefinition);
5676  buttonCount++;
5677  btnSet = 1;
5678  break;
5679  }
5680  }
5681 
5682  req->data.buttontemplate.buttonOffset = 0;
5683  req->data.buttontemplate.buttonCount = htolel(buttonCount);
5684  req->data.buttontemplate.totalButtonCount = htolel(buttonCount);
5685 
5686  if (skinnydebug)
5687  ast_verb(1, "Sending %d template to %s\n",
5688  d->type,
5689  d->name);
5690  transmit_response(d, req);
5691  return 1;
5692 }
5693 
5695 {
5696  struct skinny_device *d = s->device;
5697  struct skinny_line *l;
5698  struct skinny_subchannel *sub;
5699  struct ast_format_list fmt;
5700  struct sockaddr_in sin = { 0, };
5701  struct sockaddr_in us = { 0, };
5702  struct ast_sockaddr sin_tmp;
5703  struct ast_sockaddr us_tmp;
5704  uint32_t addr;
5705  int port;
5706  int status;
5707  int passthruid;
5708 
5709  status = letohl(req->data.openreceivechannelack.status);
5710  if (status) {
5711  ast_log(LOG_ERROR, "Open Receive Channel Failure\n");
5712  return 0;
5713  }
5714  addr = req->data.openreceivechannelack.ipAddr;
5715  port = letohl(req->data.openreceivechannelack.port);
5716  passthruid = letohl(req->data.openreceivechannelack.passThruId);
5717 
5718  sin.sin_family = AF_INET;
5719  sin.sin_addr.s_addr = addr;
5720  sin.sin_port = htons(port);
5721 
5722  sub = find_subchannel_by_reference(d, passthruid);
5723 
5724  if (!sub)
5725  return 0;
5726 
5727  l = sub->parent;
5728 
5729  if (sub->rtp) {
5730  ast_sockaddr_from_sin(&sin_tmp, &sin);
5731  ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
5732  ast_rtp_instance_get_local_address(sub->rtp, &us_tmp);
5733  ast_sockaddr_to_sin(&us_tmp, &us);
5734  us.sin_addr.s_addr = us.sin_addr.s_addr ? us.sin_addr.s_addr : d->ourip.s_addr;
5735  } else {
5736  ast_log(LOG_ERROR, "No RTP structure, this is very bad\n");
5737  return 0;
5738  }
5739 
5740  if (skinnydebug) {
5741  ast_verb(1, "device ipaddr = %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
5742  ast_verb(1, "asterisk ipaddr = %s:%d\n", ast_inet_ntoa(us.sin_addr), ntohs(us.sin_port));
5743  }
5744 
5745  fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability));
5746 
5747  if (skinnydebug)
5748  ast_verb(1, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(fmt.bits), fmt.cur_ms);
5749 
5750  transmit_startmediatransmission(d, sub, us, fmt);
5751 
5752  return 1;
5753 }
5754 
5755 static int handle_enbloc_call_message(struct skinny_req *req, struct skinnysession *s)
5756 {
5757  struct skinny_device *d = s->device;
5758  struct skinny_line *l;
5759  struct skinny_subchannel *sub = NULL;
5760  struct ast_channel *c;
5761  pthread_t t;
5762 
5763  if (skinnydebug)
5764  ast_verb(1, "Received Enbloc Call: %s\n", req->data.enbloccallmessage.calledParty);
5765 
5766  sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
5767 
5768  if (!sub) {
5769  l = find_line_by_instance(d, d->lastlineinstance);
5770  if (!l) {
5771  return 0;
5772  }
5773  } else {
5774  l = sub->parent;
5775  }
5776 
5777  c = skinny_new(l, AST_STATE_DOWN, NULL);
5778 
5779  if(!c) {
5780  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5781  } else {
5782  l->hookstate = SKINNY_OFFHOOK;
5783 
5784  sub = c->tech_pvt;
5785  l->activesub = sub;
5786  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5788  transmit_clear_display_message(d, l->instance, sub->callid);
5789  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
5790 
5792  transmit_stop_tone(d, l->instance, sub->callid);
5793  }
5795  if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
5796  ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
5797  ast_hangup(c);
5798  }
5799  }
5800 
5801  return 1;
5802 }
5803 
5804 
5805 static int handle_soft_key_event_message(struct skinny_req *req, struct skinnysession *s)
5806 {
5807  struct skinny_device *d = s->device;
5808  struct skinny_line *l;
5809  struct skinny_subchannel *sub = NULL;
5810  struct ast_channel *c;
5811  pthread_t t;
5812  int event;
5813  int instance;
5814  int callreference;
5815 
5817  instance = letohl(req->data.softkeyeventmessage.instance);
5818  callreference = letohl(req->data.softkeyeventmessage.callreference);
5819 
5820  if (instance) {
5821  l = find_line_by_instance(d, instance);
5822  if (callreference) {
5823  sub = find_subchannel_by_instance_reference(d, instance, callreference);
5824  } else {
5825  sub = find_subchannel_by_instance_reference(d, instance, d->lastcallreference);
5826  }
5827  } else {
5828  l = find_line_by_instance(d, d->lastlineinstance);
5829  }
5830 
5831  if (!l) {
5832  if (skinnydebug)
5833  ast_verb(1, "Received Softkey Event: %d(%d/%d)\n", event, instance, callreference);
5834  return 0;
5835  }
5836 
5837  ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
5838 
5839  switch(event) {
5840  case SOFTKEY_NONE:
5841  if (skinnydebug)
5842  ast_verb(1, "Received Softkey Event: None(%d/%d)\n", instance, callreference);
5843  break;
5844  case SOFTKEY_REDIAL:
5845  if (skinnydebug)
5846  ast_verb(1, "Received Softkey Event: Redial(%d/%d)\n", instance, callreference);
5847 
5848  if (ast_strlen_zero(l->lastnumberdialed)) {
5849  ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found. Ignoring button.\n");
5850  break;
5851  }
5852 
5853  if (!sub || !sub->owner) {
5854  c = skinny_new(l, AST_STATE_DOWN, NULL);
5855  } else {
5856  c = sub->owner;
5857  }
5858 
5859  if (!c) {
5860  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5861  } else {
5862  sub = c->tech_pvt;
5863  l->activesub = sub;
5864  if (l->hookstate == SKINNY_ONHOOK) {
5865  l->hookstate = SKINNY_OFFHOOK;
5867  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5869  }
5870  transmit_clear_display_message(d, l->instance, sub->callid);
5871  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
5872  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
5873 
5874  if (!ast_ignore_pattern(c->context, l->lastnumberdialed)) {
5875  transmit_stop_tone(d, l->instance, sub->callid);
5876  }
5877  ast_copy_string(c->exten, l->lastnumberdialed, sizeof(c->exten));
5878  if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
5879  ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
5880  ast_hangup(c);
5881  }
5882  }
5883  break;
5884  case SOFTKEY_NEWCALL: /* Actually the DIAL softkey */
5885  if (skinnydebug)
5886  ast_verb(1, "Received Softkey Event: New Call(%d/%d)\n", instance, callreference);
5887 
5888  /* New Call ALWAYS gets a new sub-channel */
5889  c = skinny_new(l, AST_STATE_DOWN, NULL);
5890  sub = c->tech_pvt;
5891 
5892  /* transmit_ringer_mode(d, SKINNY_RING_OFF);
5893  transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON); */
5894 
5895  /* l->hookstate = SKINNY_OFFHOOK; */
5896 
5897  if (!c) {
5898  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5899  } else {
5900  sub = c->tech_pvt;
5901  l->activesub = sub;
5902  if (l->hookstate == SKINNY_ONHOOK) {
5903  l->hookstate = SKINNY_OFFHOOK;
5905  }
5906  ast_verb(1, "Call-id: %u\n", sub->callid);
5907 
5908  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
5910 
5911  transmit_clear_display_message(d, l->instance, sub->callid);
5912  transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
5913  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK);
5914 
5915  /* start the switch thread */
5916  if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
5917  ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
5918  ast_hangup(c);
5919  }
5920  }
5921  break;
5922  case SOFTKEY_HOLD:
5923  if (skinnydebug)
5924  ast_verb(1, "Received Softkey Event: Hold(%d/%d)\n", instance, callreference);
5925  handle_hold_button(sub);
5926  break;
5927  case SOFTKEY_TRNSFER:
5928  if (skinnydebug)
5929  ast_verb(1, "Received Softkey Event: Transfer(%d/%d)\n", instance, callreference);
5930  if (l->transfer)
5932  else
5933  transmit_displaynotify(d, "Transfer disabled", 10);
5934 
5935  break;
5936  case SOFTKEY_DND:
5937  if (skinnydebug)
5938  ast_verb(1, "Received Softkey Event: DND(%d/%d)\n", instance, callreference);
5939 
5940  /* Do not disturb */
5941  if (l->dnd != 0){
5942  ast_verb(3, "Disabling DND on %s@%s\n", l->name, d->name);
5943  l->dnd = 0;
5945  transmit_displaynotify(d, "DnD disabled", 10);
5946  } else {
5947  ast_verb(3, "Enabling DND on %s@%s\n", l->name, d->name);
5948  l->dnd = 1;
5950  transmit_displaynotify(d, "DnD enabled", 10);
5951  }
5952  break;
5953  case SOFTKEY_CFWDALL:
5954  if (skinnydebug)
5955  ast_verb(1, "Received Softkey Event: Forward All(%d/%d)\n", instance, callreference);
5956 
5957  if (!sub || !sub->owner) {
5958  c = skinny_new(l, AST_STATE_DOWN, NULL);
5959  } else {
5960  c = sub->owner;
5961  }
5962 
5963  if (!c) {
5964  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5965  } else {
5966  sub = c->tech_pvt;
5967  l->activesub = sub;
5969  }
5970  break;
5971  case SOFTKEY_CFWDBUSY:
5972  if (skinnydebug)
5973  ast_verb(1, "Received Softkey Event: Forward Busy (%d/%d)\n", instance, callreference);
5974 
5975  if (!sub || !sub->owner) {
5976  c = skinny_new(l, AST_STATE_DOWN, NULL);
5977  } else {
5978  c = sub->owner;
5979  }
5980 
5981  if (!c) {
5982  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
5983  } else {
5984  sub = c->tech_pvt;
5985  l->activesub = sub;
5987  }
5988  break;
5989  case SOFTKEY_CFWDNOANSWER:
5990  if (skinnydebug)
5991  ast_verb(1, "Received Softkey Event: Forward No Answer (%d/%d)\n", instance, callreference);
5992 
5993 #if 0 /* Not sure how to handle this yet */
5994  if (!sub || !sub->owner) {
5995  c = skinny_new(l, AST_STATE_DOWN, NULL);
5996  } else {
5997  c = sub->owner;
5998  }
5999 
6000  if (!c) {
6001  ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
6002  } else {
6003  sub = c->tech_pvt;
6004  l->activesub = sub;
6006  }
6007 #endif
6008  break;
6009  case SOFTKEY_BKSPC:
6010  if (skinnydebug)
6011  ast_verb(1, "Received Softkey Event: Backspace(%d/%d)\n", instance, callreference);
6012  break;
6013  case SOFTKEY_ENDCALL:
6014  if (skinnydebug)
6015  ast_verb(1, "Received Softkey Event: End Call(%d/%d)\n", instance, callreference);
6016 
6017  if (l->hookstate == SKINNY_ONHOOK) {
6018  /* Something else already put us back on hook */
6019  break;
6020  }
6021  if (sub) {
6022  int onlysub = 0;
6023 
6024  if (!AST_LIST_NEXT(sub, list)) {
6025  onlysub = 1;
6026  } else {
6027  AST_LIST_REMOVE(&l->sub, sub, list);
6028  }
6029 
6030  sub->cxmode = SKINNY_CX_RECVONLY;
6031  if (onlysub || sub->xferor){ /*Are there other calls to this device */
6032  l->hookstate = SKINNY_ONHOOK;
6033  if (skinnydebug)
6034  ast_debug(1, "Skinny %s@%s-%d went on hook\n", l->name, d->name, callreference);
6035  }
6036 
6037  if (l->hookstate == SKINNY_ONHOOK) {
6041  transmit_clearpromptmessage(d, instance, sub->callid);
6042  transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
6045  } else if (l->hookstate == SKINNY_OFFHOOK) {
6046  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
6048  } else {
6049  transmit_callstate(d, l->instance, sub->callid, l->hookstate);
6050  }
6051 
6052  ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
6053  if (skinnydebug)
6054  ast_verb(1, "Skinny %s@%s went on hook\n", l->name, d->name);
6055  if (l->transfer && sub->xferor && sub->owner->_state >= AST_STATE_RING) {
6056  /* We're allowed to transfer, we have two active calls and
6057  we made at least one of the calls. Let's try and transfer */
6059  } else {
6060  /* Hangup the current call */
6061  /* If there is another active call, skinny_hangup will ring the phone with the other call */
6062  if (sub->xferor && sub->related){
6063  sub->related->related = NULL;
6064  sub->related->blindxfer = 0;
6065  }
6066 
6067  if (sub->owner) {
6068  sub->alreadygone = 1;
6069  ast_queue_hangup(sub->owner);
6070  } else {
6071  ast_log(LOG_WARNING, "Skinny(%s@%s-%u) channel already destroyed\n",
6072  l->name, d->name, sub->callid);
6073  }
6074  }
6075  if ((l->hookstate == SKINNY_ONHOOK) && (AST_LIST_NEXT(sub, list) && !AST_LIST_NEXT(sub, list)->rtp)) {
6076  ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name);
6077  }
6078  }
6079  break;
6080  case SOFTKEY_RESUME:
6081  if (skinnydebug)
6082  ast_verb(1, "Received Softkey Event: Resume(%d/%d)\n", instance, callreference);
6083 
6084  if (sub) {
6085  if (sub->onhold) {
6086  skinny_unhold(sub);
6087  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
6088  } else {
6089  skinny_hold(sub);
6090  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_ONHOLD);
6091  }
6092  }
6093 
6094  break;
6095  case SOFTKEY_ANSWER:
6096  if (skinnydebug)
6097  ast_verb(1, "Received Softkey Event: Answer(%d/%d)\n", instance, callreference);
6098 
6101  if (l->hookstate == SKINNY_ONHOOK) {
6103  l->hookstate = SKINNY_OFFHOOK;
6104  }
6105 
6106  if (sub && sub->outgoing) {
6107  /* We're answering a ringing call */
6109  transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
6111  transmit_stop_tone(d, l->instance, sub->callid);
6112  transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_CONNECTED);
6113  transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
6114  start_rtp(sub);
6116  }
6117  break;
6118  case SOFTKEY_INFO:
6119  if (skinnydebug)
6120  ast_verb(1, "Received Softkey Event: Info(%d/%d)\n", instance, callreference);
6121  break;
6122  case SOFTKEY_CONFRN:
6123  if (skinnydebug)
6124  ast_verb(1, "Received Softkey Event: Conference(%d/%d)\n", instance, callreference);
6125  /* XXX determine the best way to pull off a conference. Meetme? */
6126  break;
6127  case SOFTKEY_PARK:
6128  {
6129  int extout;
6130  char message[32];
6131 
6132  if (skinnydebug)
6133  ast_verb(1, "Received Softkey Event: Park Call(%d/%d)\n", instance, callreference);
6134 
6135  if ((sub && sub->owner) && (sub->owner->_state == AST_STATE_UP)){
6136  c = sub->owner;
6137  if (ast_bridged_channel(c)) {
6138  if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) {
6139  snprintf(message, sizeof(message), "Call Parked at: %d", extout);
6140  transmit_displaynotify(d, message, 10);
6141  } else {
6142  transmit_displaynotify(d, "Call Park failed", 10);
6143  }
6144  } else {
6145  transmit_displaynotify(d, "Call Park not available", 10);
6146  }
6147  } else {
6148  transmit_displaynotify(d, "Call Park not available", 10);
6149  }
6150  break;
6151  }
6152  case SOFTKEY_JOIN:
6153  if (skinnydebug)
6154  ast_verb(1, "Received Softkey Event: Join(%d/%d)\n", instance, callreference);
6155  break;
6156  case SOFTKEY_MEETME:
6157  /* XXX How is this different from CONFRN? */
6158  if (skinnydebug)
6159  ast_verb(1, "Received Softkey Event: Meetme(%d/%d)\n", instance, callreference);
6160  break;
6161  case SOFTKEY_PICKUP:
6162  if (skinnydebug)
6163  ast_verb(1, "Received Softkey Event: Pickup(%d/%d)\n", instance, callreference);
6164  break;
6165  case SOFTKEY_GPICKUP:
6166  if (skinnydebug)
6167  ast_verb(1, "Received Softkey Event: Group Pickup(%d/%d)\n", instance, callreference);
6168  break;
6169  default:
6170  if (skinnydebug)
6171  ast_verb(1, "Received unknown Softkey Event: %d(%d/%d)\n", event, instance, callreference);
6172  break;
6173  }
6174 
6175  return 1;
6176 }
6177 
6178 static int handle_message(struct skinny_req *req, struct skinnysession *s)
6179 {
6180  int res = 0;
6181  struct skinny_speeddial *sd;
6182  struct skinny_line *l;
6183  struct skinny_device *d = s->device;
6184  size_t len;
6185 
6186  if ((!s->device) && (letohl(req->e) != REGISTER_MESSAGE && letohl(req->e) != ALARM_MESSAGE)) {
6187  ast_log(LOG_WARNING, "Client sent message #%d without first registering.\n", req->e);
6188  ast_free(req);
6189  return 0;
6190  }
6191 
6192  SKINNY_DEVONLY(if (skinnydebug > 1) {
6193  ast_verb(4, "Received %s from %s\n", message2str(req->e), s->device->name);
6194  })
6195 
6196  switch(letohl(req->e)) {
6197  case KEEP_ALIVE_MESSAGE:
6198  res = handle_keep_alive_message(req, s);
6199  break;
6200  case REGISTER_MESSAGE:
6201  if (skinnydebug)
6202  ast_verb(1, "Device %s is attempting to register\n", req->data.reg.name);
6203 
6204  res = handle_register_message(req, s);
6205  break;
6206  case IP_PORT_MESSAGE:
6207  res = handle_ip_port_message(req, s);
6208  break;
6209  case KEYPAD_BUTTON_MESSAGE:
6210  {
6211  struct skinny_device *d = s->device;
6212  struct skinny_subchannel *sub;
6213  int lineInstance;
6214  int callReference;
6215 
6216  if (skinnydebug)
6217  ast_verb(1, "Collected digit: [%u]\n", letohl(req->data.keypad.button));
6218 
6219  lineInstance = letohl(req->data.keypad.lineInstance);
6220  callReference = letohl(req->data.keypad.callReference);
6221 
6222  if (lineInstance) {
6223  sub = find_subchannel_by_instance_reference(d, lineInstance, callReference);
6224  } else {
6225  sub = d->activeline->activesub;
6226  }
6227 
6228  if (sub && ((sub->owner && sub->owner->_state < AST_STATE_UP) || sub->onhold)) {
6229  char dgt;
6230  int digit = letohl(req->data.keypad.button);
6231 
6232  if (digit == 14) {
6233  dgt = '*';
6234  } else if (digit == 15) {
6235  dgt = '#';
6236  } else if (digit >= 0 && digit <= 9) {
6237  dgt = '0' + digit;
6238  } else {
6239  /* digit=10-13 (A,B,C,D ?), or
6240  * digit is bad value
6241  *
6242  * probably should not end up here, but set
6243  * value for backward compatibility, and log
6244  * a warning.
6245  */
6246  dgt = '0' + digit;
6247  ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
6248  }
6249 
6250  len = strlen(d->exten);
6251  if (len < sizeof(d->exten) - 1) {
6252  d->exten[len] = dgt;
6253  d->exten[len + 1] = '\0';
6254  } else {
6255  ast_log(AST_LOG_WARNING, "Dropping digit with value %d because digit queue is full\n", dgt);
6256  }
6257  } else
6258  res = handle_keypad_button_message(req, s);
6259  }
6260  break;
6261  case ENBLOC_CALL_MESSAGE:
6262  res = handle_enbloc_call_message(req, s);
6263  break;
6264  case STIMULUS_MESSAGE:
6265  res = handle_stimulus_message(req, s);
6266  break;
6267  case OFFHOOK_MESSAGE:
6268  res = handle_offhook_message(req, s);
6269  break;
6270  case ONHOOK_MESSAGE:
6271  res = handle_onhook_message(req, s);
6272  break;
6274  if (skinnydebug)
6275  ast_verb(1, "Received CapabilitiesRes\n");
6276 
6277  res = handle_capabilities_res_message(req, s);
6278  break;
6280  if (skinnydebug)
6281  ast_verb(1, "Received SpeedDialStatRequest\n");
6284  }
6285  break;
6287  if (skinnydebug)
6288  ast_verb(1, "Received LineStatRequest\n");
6289  if ((l = find_line_by_instance(d, letohl(req->data.line.lineNumber)))) {
6290  transmit_linestatres(d, l);
6291  }
6292  break;
6293  case TIME_DATE_REQ_MESSAGE:
6294  if (skinnydebug)
6295  ast_verb(1, "Received Time/Date Request\n");
6296 
6298  break;
6300  if (skinnydebug)
6301  ast_verb(1, "Buttontemplate requested\n");
6302 
6303  res = handle_button_template_req_message(req, s);
6304  break;
6305  case VERSION_REQ_MESSAGE:
6306  if (skinnydebug)
6307  ast_verb(1, "Version Request\n");
6309  break;
6311  if (skinnydebug)
6312  ast_verb(1, "Received Server Request\n");
6313  transmit_serverres(d);
6314  break;
6315  case ALARM_MESSAGE:
6316  /* no response necessary */
6317  if (skinnydebug)
6318  ast_verb(1, "Received Alarm Message: %s\n", req->data.alarm.displayMessage);
6319  break;
6321  if (skinnydebug)
6322  ast_verb(1, "Received Open Receive Channel Ack\n");
6323 
6325  break;
6327  if (skinnydebug)
6328  ast_verb(1, "Received SoftKeySetReq\n");
6331  break;
6333  res = handle_soft_key_event_message(req, s);
6334  break;
6335  case UNREGISTER_MESSAGE:
6336  if (skinnydebug)
6337  ast_verb(1, "Received Unregister Request\n");
6338 
6339  res = skinny_unregister(req, s);
6340  break;
6342  if (skinnydebug)
6343  ast_verb(1, "Received SoftKey Template Request\n");
6345  break;
6347  /* XXX umm...okay? Why do I care? */
6348  break;
6350  /* XXX I have no clue what this is for, but my phone was sending it, so... */
6351  break;
6352  default:
6353  if (skinnydebug)
6354  ast_verb(1, "RECEIVED UNKNOWN MESSAGE TYPE: %x\n", (unsigned)letohl(req->e));
6355  break;
6356  }
6357  if (res >= 0 && req)
6358  ast_free(req);
6359  return res;
6360 }
6361 
6362 static void destroy_session(struct skinnysession *s)
6363 {
6364  struct skinnysession *cur;
6366  AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, cur, list) {
6367  if (cur == s) {
6369  if (s->fd > -1)
6370  close(s->fd);
6371 
6372  if (!s->device)
6373  ast_atomic_fetchadd_int(&unauth_sessions, -1);
6374 
6375  ast_mutex_destroy(&s->lock);
6376 
6377  ast_free(s);
6378  } else {
6379  ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
6380  }
6381  }
6384 }
6385 
6386 static int get_input(struct skinnysession *s)
6387 {
6388  int res;
6389  int dlen = 0;
6390  int timeout = keep_alive * 1100;
6391  time_t now;
6392  int *bufaddr;
6393  struct pollfd fds[1];
6394 
6395  if (!s->device) {
6396  if(time(&now) == -1) {
6397  ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
6398  return -1;
6399  }
6400 
6401  timeout = (auth_timeout - (now - s->start)) * 1000;
6402  if (timeout < 0) {
6403  /* we have timed out */
6404  if (skinnydebug)
6405  ast_verb(1, "Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
6406  return -1;
6407  }
6408  }
6409 
6410  fds[0].fd = s->fd;
6411  fds[0].events = POLLIN;
6412  fds[0].revents = 0;
6413  res = ast_poll(fds, 1, timeout); /* If nothing has happen, client is dead */
6414  /* we add 10% to the keep_alive to deal */
6415  /* with network delays, etc */
6416  if (res < 0) {
6417  if (errno != EINTR) {
6418  ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
6419  return res;
6420  }
6421  } else if (res == 0) {
6422  if (skinnydebug) {
6423  if (s->device) {
6424  ast_verb(1, "Skinny Client was lost, unregistering\n");
6425  } else {
6426  ast_verb(1, "Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
6427  }
6428  }
6429  skinny_unregister(NULL, s);
6430  return -1;
6431  }
6432 
6433  if (fds[0].revents) {
6434  ast_mutex_lock(&s->lock);
6435  memset(s->inbuf, 0, sizeof(s->inbuf));
6436  res = read(s->fd, s->inbuf, 4);
6437  if (res < 0) {
6438  ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
6439 
6440  if (skinnydebug)
6441  ast_verb(1, "Skinny Client was lost, unregistering\n");
6442 
6443  skinny_unregister(NULL, s);
6444  ast_mutex_unlock(&s->lock);
6445  return res;
6446  } else if (res != 4) {
6447  ast_log(LOG_WARNING, "Skinny Client sent less data than expected. Expected 4 but got %d.\n", res);
6448  ast_mutex_unlock(&s->lock);
6449 
6450  if (res == 0) {
6451  if (skinnydebug)
6452  ast_verb(1, "Skinny Client was lost, unregistering\n");
6453  skinny_unregister(NULL, s);
6454  }
6455 
6456  return -1;
6457  }
6458 
6459  bufaddr = (int *)s->inbuf;
6460  dlen = letohl(*bufaddr);
6461  if (dlen < 4) {
6462  ast_debug(1, "Skinny Client sent invalid data.\n");
6463  ast_mutex_unlock(&s->lock);
6464  return -1;
6465  }
6466  if (dlen+8 > sizeof(s->inbuf)) {
6467  dlen = sizeof(s->inbuf) - 8;
6468  }
6469  *bufaddr = htolel(dlen);
6470 
6471  res = read(s->fd, s->inbuf+4, dlen+4);
6472  ast_mutex_unlock(&s->lock);
6473  if (res < 0) {
6474  ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
6475  return res;
6476  } else if (res != (dlen+4)) {
6477  ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
6478  return -1;
6479  }
6480  return res;
6481  }
6482  return 0;
6483 }
6484 
6485 static struct skinny_req *skinny_req_parse(struct skinnysession *s)
6486 {
6487  struct skinny_req *req;
6488  int *bufaddr;
6489 
6490  if (!(req = ast_calloc(1, SKINNY_MAX_PACKET)))
6491  return NULL;
6492 
6493  ast_mutex_lock(&s->lock);
6494  memcpy(req, s->inbuf, skinny_header_size);
6495  bufaddr = (int *)(s->inbuf);
6496  memcpy(&req->data, s->inbuf+skinny_header_size, letohl(*bufaddr)-4);
6497 
6498  ast_mutex_unlock(&s->lock);
6499 
6500  if (letohl(req->e) < 0) {
6501  ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
6502  ast_free(req);
6503  return NULL;
6504  }
6505 
6506  return req;
6507 }
6508 
6509 static void *skinny_session(void *data)
6510 {
6511  int res;
6512  struct skinny_req *req;
6513  struct skinnysession *s = data;
6514 
6515  ast_verb(3, "Starting Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));
6516 
6517  for (;;) {
6518  res = get_input(s);
6519  if (res < 0) {
6520  break;
6521  }
6522 
6523  if (res > 0)
6524  {
6525  if (!(req = skinny_req_parse(s))) {
6526  destroy_session(s);
6527  return NULL;
6528  }
6529 
6530  res = handle_message(req, s);
6531  if (res < 0) {
6532  destroy_session(s);
6533  return NULL;
6534  }
6535  }
6536  }
6537  ast_debug(3, "Skinny Session returned: %s\n", strerror(errno));
6538 
6539  if (s)
6540  destroy_session(s);
6541 
6542  return 0;
6543 }
6544 
6545 static void *accept_thread(void *ignore)
6546 {
6547  int as;
6548  struct sockaddr_in sin;
6549  socklen_t sinlen;
6550  struct skinnysession *s;
6551  struct protoent *p;
6552  int arg = 1;
6553 
6554  for (;;) {
6555  sinlen = sizeof(sin);
6556  as = accept(skinnysock, (struct sockaddr *)&sin, &sinlen);
6557  if (as < 0) {
6558  ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
6559  continue;
6560  }
6561 
6562  if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= auth_limit) {
6563  close(as);
6564  ast_atomic_fetchadd_int(&unauth_sessions, -1);
6565  continue;
6566  }
6567 
6568  p = getprotobyname("tcp");
6569  if(p) {
6570  if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
6571  ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
6572  }
6573  }
6574  if (!(s = ast_calloc(1, sizeof(struct skinnysession)))) {
6575  close(as);
6576  ast_atomic_fetchadd_int(&unauth_sessions, -1);
6577  continue;
6578  }
6579 
6580  memcpy(&s->sin, &sin, sizeof(sin));
6581  ast_mutex_init(&s->lock);
6582  s->fd = as;
6583 
6584  if(time(&s->start) == -1) {
6585  ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
6586  destroy_session(s);
6587  continue;
6588  }
6589 
6591  AST_LIST_INSERT_HEAD(&sessions, s, list);
6593 
6594  if (ast_pthread_create(&s->t, NULL, skinny_session, s)) {
6595  destroy_session(s);
6596  }
6597  }
6598  if (skinnydebug)
6599  ast_verb(1, "killing accept thread\n");
6600  close(as);
6601  return 0;
6602 }
6603 
6604 static void *do_monitor(void *data)
6605 {
6606  int res;
6607 
6608  /* This thread monitors all the interfaces which are not yet in use
6609  (and thus do not have a separate thread) indefinitely */
6610  /* From here on out, we die whenever asked */
6611  for(;;) {
6612  pthread_testcancel();
6613  /* Wait for sched or io */
6614  res = ast_sched_wait(sched);
6615  if ((res < 0) || (res > 1000)) {
6616  res = 1000;
6617  }
6618  res = ast_io_wait(io, res);
6620  if (res >= 0) {
6621  ast_sched_runq(sched);
6622  }
6624  }
6625  /* Never reached */
6626  return NULL;
6627 
6628 }
6629 
6630 static int restart_monitor(void)
6631 {
6632  /* If we're supposed to be stopped -- stay stopped */
6633  if (monitor_thread == AST_PTHREADT_STOP)
6634  return 0;
6635 
6637  if (monitor_thread == pthread_self()) {
6639  ast_log(LOG_WARNING, "Cannot kill myself\n");
6640  return -1;
6641  }
6642  if (monitor_thread != AST_PTHREADT_NULL) {
6643  /* Wake up the thread */
6644  pthread_kill(monitor_thread, SIGURG);
6645  } else {
6646  /* Start a new monitor */
6647  if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
6649  ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
6650  return -1;
6651  }
6652  }
6654  return 0;
6655 }
6656 
6657 static int skinny_devicestate(void *data)
6658 {
6659  struct skinny_line *l;
6660  char *tmp;
6661 
6662  tmp = ast_strdupa(data);
6663 
6664  l = find_line_by_name(tmp);
6665 
6666  return get_devicestate(l);
6667 }
6668 
6669 static struct ast_channel *skinny_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
6670 {
6671  struct skinny_line *l;
6672  struct ast_channel *tmpc = NULL;
6673  char tmp[256];
6674  char *dest = data;
6675 
6676  if (!(format &= AST_FORMAT_AUDIO_MASK)) {
6677  ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), format));
6678  return NULL;
6679  }
6680 
6681  ast_copy_string(tmp, dest, sizeof(tmp));
6682  if (ast_strlen_zero(tmp)) {
6683  ast_log(LOG_NOTICE, "Skinny channels require a device\n");
6684  return NULL;
6685  }
6686  l = find_line_by_name(tmp);
6687  if (!l) {
6688  ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
6689  return NULL;
6690  }
6691  ast_verb(3, "skinny_request(%s)\n", tmp);
6692  tmpc = skinny_new(l, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
6693  if (!tmpc) {
6694  ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
6695  }
6696  restart_monitor();
6697  return tmpc;
6698 }
6699 
6700  #define TYPE_GENERAL 1
6701  #define TYPE_DEF_DEVICE 2
6702  #define TYPE_DEF_LINE 4
6703  #define TYPE_DEVICE 8
6704  #define TYPE_LINE 16
6705 
6706  #define CLINE_OPTS ((struct skinny_line_options *)item)
6707  #define CLINE ((struct skinny_line *)item)
6708  #define CDEV_OPTS ((struct skinny_device_options *)item)
6709  #define CDEV ((struct skinny_device *)item)
6710 
6711  static void config_parse_variables(int type, void *item, struct ast_variable *vptr)
6712  {
6713  struct ast_variable *v;
6714  int lineInstance = 1;
6715  int speeddialInstance = 1;
6716 
6717  while(vptr) {
6718  v = vptr;
6719  vptr = vptr->next;
6720 
6721  if (type & (TYPE_GENERAL)) {
6722  char newcontexts[AST_MAX_CONTEXT];
6723  char oldcontexts[AST_MAX_CONTEXT];
6724  char *stringp, *context, *oldregcontext;
6725  if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
6726  v = v->next;
6727  continue;
6728  }
6729  if (!strcasecmp(v->name, "bindaddr")) {
6730  if (!(hp = ast_gethostbyname(v->value, &ahp))) {
6731  ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
6732  } else {
6733  memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
6734  }
6735  continue;
6736  } else if (!strcasecmp(v->name, "keepalive")) {
6737  keep_alive = atoi(v->value);
6738  continue;
6739  } else if (!strcasecmp(v->name, "authtimeout")) {
6740  int timeout = atoi(v->value);
6741 
6742  if (timeout < 1) {
6743  ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", v->value);
6744  auth_timeout = DEFAULT_AUTH_TIMEOUT;
6745  } else {
6746  auth_timeout = timeout;
6747  }
6748  continue;
6749  } else if (!strcasecmp(v->name, "authlimit")) {
6750  int limit = atoi(v->value);
6751 
6752  if (limit < 1) {
6753  ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", v->value);
6754  auth_limit = DEFAULT_AUTH_LIMIT;
6755  } else {
6756  auth_limit = limit;
6757  }
6758  continue;
6759  } else if (!strcasecmp(v->name, "regcontext")) {
6760  ast_copy_string(newcontexts, v->value, sizeof(newcontexts));
6761  stringp = newcontexts;
6762  /* Initialize copy of current global_regcontext for later use in removing stale contexts */
6763  ast_copy_string(oldcontexts, regcontext, sizeof(oldcontexts));
6764  oldregcontext = oldcontexts;
6765  /* Let's remove any contexts that are no longer defined in regcontext */
6766  cleanup_stale_contexts(stringp, oldregcontext);
6767  /* Create contexts if they don't exist already */
6768  while ((context = strsep(&stringp, "&"))) {
6769  ast_copy_string(used_context, context, sizeof(used_context));
6770  ast_context_find_or_create(NULL, NULL, context, "Skinny");
6771  }
6772  ast_copy_string(regcontext, v->value, sizeof(regcontext));
6773  continue;
6774  } else if (!strcasecmp(v->name, "dateformat")) {
6775  memcpy(date_format, v->value, sizeof(date_format));
6776  continue;
6777  } else if (!strcasecmp(v->name, "tos")) {
6778  if (ast_str2tos(v->value, &qos.tos))
6779  ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
6780  continue;
6781  } else if (!strcasecmp(v->name, "tos_audio")) {
6782  if (ast_str2tos(v->value, &qos.tos_audio))
6783  ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
6784  continue;
6785  } else if (!strcasecmp(v->name, "tos_video")) {
6786  if (ast_str2tos(v->value, &qos.tos_video))
6787  ast_log(LOG_WARNING, "Invalid tos_video value at line %d, refer to QoS documentation\n", v->lineno);
6788  continue;
6789  } else if (!strcasecmp(v->name, "cos")) {
6790  if (ast_str2cos(v->value, &qos.cos))
6791  ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
6792  continue;
6793  } else if (!strcasecmp(v->name, "cos_audio")) {
6794  if (ast_str2cos(v->value, &qos.cos_audio))
6795  ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
6796  continue;
6797  } else if (!strcasecmp(v->name, "cos_video")) {
6798  if (ast_str2cos(v->value, &qos.cos_video))
6799  ast_log(LOG_WARNING, "Invalid cos_video value at line %d, refer to QoS documentation\n", v->lineno);
6800  continue;
6801  } else if (!strcasecmp(v->name, "bindport")) {
6802  if (sscanf(v->value, "%5d", &ourport) == 1) {
6803  bindaddr.sin_port = htons(ourport);
6804  } else {
6805  ast_log(LOG_WARNING, "Invalid bindport '%s' at line %d of %s\n", v->value, v->lineno, config);
6806  }
6807  continue;
6808  } else if (!strcasecmp(v->name, "allow")) {
6809  ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 1);
6810  continue;
6811  } else if (!strcasecmp(v->name, "disallow")) {
6812  ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 0);
6813  continue;
6814  }
6815  }
6816 
6817  if (!strcasecmp(v->name, "transfer")) {
6818  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
6819  CDEV_OPTS->transfer = ast_true(v->value);
6820  continue;
6821  } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6822  CLINE_OPTS->transfer = ast_true(v->value);
6823  continue;
6824  }
6825  } else if (!strcasecmp(v->name, "callwaiting")) {
6826  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
6827  CDEV_OPTS->callwaiting = ast_true(v->value);
6828  continue;
6829  } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6830  CLINE_OPTS->callwaiting = ast_true(v->value);
6831  continue;
6832  }
6833  } else if (!strcasecmp(v->name, "directmedia") || !strcasecmp(v->name, "canreinvite")) {
6834  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6835  CLINE_OPTS->directmedia = ast_true(v->value);
6836  continue;
6837  }
6838  } else if (!strcasecmp(v->name, "nat")) {
6839  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6840  CLINE_OPTS->nat = ast_true(v->value);
6841  continue;
6842  }
6843  } else if (!strcasecmp(v->name, "context")) {
6844  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6845  ast_copy_string(CLINE_OPTS->context, v->value, sizeof(CLINE_OPTS->context));
6846  continue;
6847  }
6848  }else if (!strcasecmp(v->name, "vmexten")) {
6849  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
6850  ast_copy_string(CDEV_OPTS->vmexten, v->value, sizeof(CDEV_OPTS->vmexten));
6851  continue;
6852  } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6853  ast_copy_string(CLINE_OPTS->vmexten, v->value, sizeof(CLINE_OPTS->vmexten));
6854  continue;
6855  }
6856  } else if (!strcasecmp(v->name, "mwiblink")) {
6857  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
6858  CDEV_OPTS->mwiblink = ast_true(v->value);
6859  continue;
6860  } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6861  CLINE_OPTS->mwiblink = ast_true(v->value);
6862  continue;
6863  }
6864  } else if (!strcasecmp(v->name, "linelabel")) {
6865  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6866  ast_copy_string(CLINE_OPTS->label, v->value, sizeof(CLINE_OPTS->label));
6867  continue;
6868  }
6869  } else if (!strcasecmp(v->name, "callerid")) {
6870  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6871  if (!strcasecmp(v->value, "asreceived")) {
6872  CLINE_OPTS->cid_num[0] = '\0';
6873  CLINE_OPTS->cid_name[0] = '\0';
6874  } else {
6875  ast_callerid_split(v->value, CLINE_OPTS->cid_name, sizeof(CLINE_OPTS->cid_name), CLINE_OPTS->cid_num, sizeof(CLINE_OPTS->cid_num));
6876  }
6877  continue;
6878  }
6879  } else if (!strcasecmp(v->name, "amaflags")) {
6880  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6881  int tempamaflags = ast_cdr_amaflags2int(v->value);
6882  if (tempamaflags < 0) {
6883  ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
6884  } else {
6885  CLINE_OPTS->amaflags = tempamaflags;
6886  }
6887  continue;
6888  }
6889  } else if (!strcasecmp(v->name, "regexten")) {
6890  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6891  ast_copy_string(CLINE_OPTS->regexten, v->value, sizeof(CLINE_OPTS->regexten));
6892  continue;
6893  }
6894  } else if (!strcasecmp(v->name, "language")) {
6895  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6896  ast_copy_string(CLINE_OPTS->language, v->value, sizeof(CLINE_OPTS->language));
6897  continue;
6898  }
6899  } else if (!strcasecmp(v->name, "accountcode")) {
6900  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6901  ast_copy_string(CLINE_OPTS->accountcode, v->value, sizeof(CLINE_OPTS->accountcode));
6902  continue;
6903  }
6904  } else if (!strcasecmp(v->name, "mohinterpret") || !strcasecmp(v->name, "musiconhold")) {
6905  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6906  ast_copy_string(CLINE_OPTS->mohinterpret, v->value, sizeof(CLINE_OPTS->mohinterpret));
6907  continue;
6908  }
6909  } else if (!strcasecmp(v->name, "mohsuggest")) {
6910  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6911  ast_copy_string(CLINE_OPTS->mohsuggest, v->value, sizeof(CLINE_OPTS->mohsuggest));
6912  continue;
6913  }
6914  } else if (!strcasecmp(v->name, "callgroup")) {
6915  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6916  CLINE_OPTS->callgroup = ast_get_group(v->value);
6917  continue;
6918  }
6919  } else if (!strcasecmp(v->name, "pickupgroup")) {
6920  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6921  CLINE_OPTS->pickupgroup = ast_get_group(v->value);
6922  continue;
6923  }
6924  } else if (!strcasecmp(v->name, "immediate")) {
6925  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE | TYPE_DEF_LINE | TYPE_LINE)) {
6926  CLINE_OPTS->immediate = ast_true(v->value);
6927  continue;
6928  }
6929  } else if (!strcasecmp(v->name, "cancallforward")) {
6930  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6931  CLINE_OPTS->cancallforward = ast_true(v->value);
6932  continue;
6933  }
6934  } else if (!strcasecmp(v->name, "mailbox")) {
6935  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6936  ast_copy_string(CLINE_OPTS->mailbox, v->value, sizeof(CLINE_OPTS->mailbox));
6937  continue;
6938  }
6939  } else if ( !strcasecmp(v->name, "parkinglot")) {
6940  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6941  ast_copy_string(CLINE_OPTS->parkinglot, v->value, sizeof(CLINE_OPTS->parkinglot));
6942  continue;
6943  }
6944  } else if (!strcasecmp(v->name, "hasvoicemail")) {
6945  if (type & (TYPE_LINE)) {
6946  if (ast_true(v->value) && ast_strlen_zero(CLINE->mailbox)) {
6947  ast_copy_string(CLINE->mailbox, CLINE->name, sizeof(CLINE->mailbox));
6948  }
6949  continue;
6950  }
6951  } else if (!strcasecmp(v->name, "callreturn")) {
6952  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6953  CLINE_OPTS->callreturn = ast_true(v->value);
6954  continue;
6955  }
6956  } else if (!strcasecmp(v->name, "threewaycalling")) {
6957  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
6958  CLINE_OPTS->threewaycalling = ast_true(v->value);
6959  continue;
6960  }
6961  } else if (!strcasecmp(v->name, "setvar")) {
6962  if (type & (TYPE_LINE)) {
6963  CLINE->chanvars = add_var(v->value, CLINE->chanvars);
6964  continue;
6965  }
6966  } else if (!strcasecmp(v->name, "earlyrtp")) {
6967  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
6968  CDEV_OPTS->earlyrtp = ast_true(v->value);
6969  continue;
6970  }
6971  } else if (!strcasecmp(v->name, "host")) {
6972  if (type & (TYPE_DEVICE)) {
6973  struct ast_sockaddr CDEV_addr_tmp;
6974 
6975  CDEV_addr_tmp.ss.ss_family = AF_INET;
6976  if (ast_get_ip(&CDEV_addr_tmp, v->value)) {
6977  ast_log(LOG_WARNING, "Bad IP '%s' at line %d.\n", v->value, v->lineno);
6978  }
6979  ast_sockaddr_to_sin(&CDEV_addr_tmp,
6980  &CDEV->addr);
6981  continue;
6982  }
6983  } else if (!strcasecmp(v->name, "port")) {
6984  if (type & (TYPE_DEF_DEVICE)) {
6985  CDEV->addr.sin_port = htons(atoi(v->value));
6986  continue;
6987  }
6988  } else if (!strcasecmp(v->name, "device")) {
6989  if (type & (TYPE_DEVICE)) {
6990  ast_copy_string(CDEV_OPTS->id, v->value, sizeof(CDEV_OPTS->id));
6991  continue;
6992  }
6993  } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
6994  if (type & (TYPE_DEVICE)) {
6995  CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, NULL);
6996  continue;
6997  }
6998  } else if (!strcasecmp(v->name, "allow")) {
6999  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
7000  ast_parse_allow_disallow(&CDEV_OPTS->confprefs, &CDEV_OPTS->confcapability, v->value, 1);
7001  continue;
7002  }
7003  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7004  ast_parse_allow_disallow(&CLINE_OPTS->confprefs, &CLINE_OPTS->confcapability, v->value, 1);
7005  continue;
7006  }
7007  } else if (!strcasecmp(v->name, "disallow")) {
7008  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
7009  ast_parse_allow_disallow(&CDEV_OPTS->confprefs, &CDEV_OPTS->confcapability, v->value, 0);
7010  continue;
7011  }
7012  if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
7013  ast_parse_allow_disallow(&CLINE_OPTS->confprefs, &CLINE_OPTS->confcapability, v->value, 0);
7014  continue;
7015  }
7016  } else if (!strcasecmp(v->name, "version")) {
7017  if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
7018  ast_copy_string(CDEV_OPTS->version_id, v->value, sizeof(CDEV_OPTS->version_id));
7019  continue;
7020  }
7021  } else if (!strcasecmp(v->name, "line")) {
7022  if (type & (TYPE_DEVICE)) {
7023  struct skinny_line *l;
7024  AST_LIST_TRAVERSE(&lines, l, all) {
7025  if (!strcasecmp(v->value, l->name) && !l->prune) {
7026 
7027  /* FIXME: temp solution about line conflicts */
7028  struct skinny_device *d;
7029  struct skinny_line *l2;
7030  int lineinuse = 0;
7031  AST_LIST_TRAVERSE(&devices, d, list) {
7032  AST_LIST_TRAVERSE(&d->lines, l2, list) {
7033  if (l2 == l && strcasecmp(d->id, CDEV->id)) {
7034  ast_log(LOG_WARNING, "Line %s already used by %s. Not connecting to %s.\n", l->name, d->name, CDEV->name);
7035  lineinuse++;
7036  }
7037  }
7038  }
7039  if (!lineinuse) {
7040  if (!AST_LIST_FIRST(&CDEV->lines)) {
7041  CDEV->activeline = l;
7042  }
7043  lineInstance++;
7044  AST_LIST_INSERT_HEAD(&CDEV->lines, l, list);
7045  }
7046  break;
7047  }
7048  }
7049  continue;
7050  }
7051  } else if (!strcasecmp(v->name, "speeddial")) {
7052  if (type & (TYPE_DEVICE)) {
7053  struct skinny_speeddial *sd;
7054  if (!(sd = ast_calloc(1, sizeof(*sd)))) {
7055  ast_log(LOG_WARNING, "Unable to allocate memory for speeddial %s. Ignoring speeddial.\n", v->name);
7056  continue;
7057  } else {
7058  char buf[256];
7059  char *stringp = buf, *exten, *context, *label;
7060  ast_copy_string(buf, v->value, sizeof(buf));
7061  exten = strsep(&stringp, ",");
7062  if ((context = strchr(exten, '@'))) {
7063  *context++ = '\0';
7064  }
7065  label = stringp;
7066  ast_mutex_init(&sd->lock);
7067  ast_copy_string(sd->exten, exten, sizeof(sd->exten));
7068  if (!ast_strlen_zero(context)) {
7069  sd->isHint = 1;
7070  sd->instance = lineInstance++;
7071  ast_copy_string(sd->context, context, sizeof(sd->context));
7072  } else {
7073  sd->isHint = 0;
7074  sd->instance = speeddialInstance++;
7075  sd->context[0] = '\0';
7076  }
7077  ast_copy_string(sd->label, S_OR(label, exten), sizeof(sd->label));
7078  sd->parent = CDEV;
7079  AST_LIST_INSERT_HEAD(&CDEV->speeddials, sd, list);
7080  }
7081  continue;
7082  }
7083  } else if (!strcasecmp(v->name, "addon")) {
7084  if (type & (TYPE_DEVICE)) {
7085  struct skinny_addon *a;
7086  if (!(a = ast_calloc(1, sizeof(*a)))) {
7087  ast_log(LOG_WARNING, "Unable to allocate memory for addon %s. Ignoring addon.\n", v->name);
7088  continue;
7089  } else {
7090  ast_mutex_init(&a->lock);
7091  ast_copy_string(a->type, v->value, sizeof(a->type));
7092  AST_LIST_INSERT_HEAD(&CDEV->addons, a, list);
7093  }
7094  continue;
7095  }
7096 
7097  } else {
7098  ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
7099  continue;
7100  }
7101  ast_log(LOG_WARNING, "Invalid category used: %s at line %d\n", v->name, v->lineno);
7102  }
7103  }
7104 
7105  static struct skinny_line *config_line(const char *lname, struct ast_variable *v)
7106  {
7107  struct skinny_line *l, *temp;
7108  int update = 0;
7109 
7110  ast_log(LOG_NOTICE, "Configuring skinny line %s.\n", lname);
7111 
7112  /* We find the old line and remove it just before the new
7113  line is created */
7114  AST_LIST_LOCK(&lines);
7115  AST_LIST_TRAVERSE(&lines, temp, all) {
7116  if (!strcasecmp(lname, temp->name) && temp->prune) {
7117  update = 1;
7118  break;
7119  }
7120  }
7121 
7122  if (!(l=ast_calloc(1, sizeof(*l)))) {
7123  ast_verb(1, "Unable to allocate memory for line %s.\n", lname);
7125  return NULL;
7126  }
7127 
7128  memcpy(l, default_line, sizeof(*default_line));
7129  ast_mutex_init(&l->lock);
7130  ast_copy_string(l->name, lname, sizeof(l->name));
7132 
7133  ast_mutex_lock(&l->lock);
7135 
7137 
7138  if (!ast_strlen_zero(l->mailbox)) {
7139  char *cfg_mailbox, *cfg_context;
7140  cfg_context = cfg_mailbox = ast_strdupa(l->mailbox);
7141  ast_verb(3, "Setting mailbox '%s' on line %s\n", cfg_mailbox, l->name);
7142  strsep(&cfg_context, "@");
7143  if (ast_strlen_zero(cfg_context))
7144  cfg_context = "default";
7145  l->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, "skinny MWI subsciption", l,
7150  }
7151 
7152  ast_mutex_unlock(&l->lock);
7153 
7154  /* We do not want to unlink or free the line yet, it needs
7155  to be available to detect a device reconfig when we load the
7156  devices. Old lines will be pruned after the reload completes */
7157 
7158  ast_verb(3, "%s config for line '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), l->name);
7159 
7160  return l;
7161  }
7162 
7163  static struct skinny_device *config_device(const char *dname, struct ast_variable *v)
7164  {
7165  struct skinny_device *d, *temp;
7166  struct skinny_line *l, *ltemp;
7167  struct skinny_subchannel *sub;
7168  int update = 0;
7169 
7170  ast_log(LOG_NOTICE, "Configuring skinny device %s.\n", dname);
7171 
7173  AST_LIST_TRAVERSE(&devices, temp, list) {
7174  if (!strcasecmp(dname, temp->name) && temp->prune) {
7175  update = 1;
7176  break;
7177  }
7178  }
7179 
7180  if (!(d = ast_calloc(1, sizeof(*d)))) {
7181  ast_verb(1, "Unable to allocate memory for device %s.\n", dname);
7183  return NULL;
7184  }
7185  memcpy(d, default_device, sizeof(*default_device));
7186  ast_mutex_init(&d->lock);
7187  ast_copy_string(d->name, dname, sizeof(d->name));
7188  AST_LIST_INSERT_TAIL(&devices, d, list);
7189 
7190  ast_mutex_lock(&d->lock);
7192 
7194 
7195  if (!AST_LIST_FIRST(&d->lines)) {
7196  ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n");
7197  ast_mutex_unlock(&d->lock);
7198  return NULL;
7199  }
7200  if (/*d->addr.sin_addr.s_addr && */!ntohs(d->addr.sin_port)) {
7201  d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
7202  }
7203 
7204  if (skinnyreload){
7206  AST_LIST_TRAVERSE(&devices, temp, list) {
7207  if (strcasecmp(d->id, temp->id) || !temp->prune || !temp->session) {
7208  continue;
7209  }
7210  ast_mutex_lock(&d->lock);
7211  d->session = temp->session;
7212  d->session->device = d;
7213 
7214  AST_LIST_LOCK(&d->lines);
7215  AST_LIST_TRAVERSE(&d->lines, l, list){
7216  l->device = d;
7217 
7218  AST_LIST_LOCK(&temp->lines);
7219  AST_LIST_TRAVERSE(&temp->lines, ltemp, list) {
7220  if (strcasecmp(l->name, ltemp->name)) {
7221  continue;
7222  }
7223  ast_mutex_lock(&ltemp->lock);
7224  l->instance = ltemp->instance;
7225  l->hookstate = ltemp->hookstate;
7226  if (!AST_LIST_EMPTY(&ltemp->sub)) {
7227  ast_mutex_lock(&l->lock);
7228  l->sub = ltemp->sub;
7229  AST_LIST_TRAVERSE(&l->sub, sub, list) {
7230  sub->parent = l;
7231  }
7232  ast_mutex_unlock(&l->lock);
7233  }
7234  ast_mutex_unlock(&ltemp->lock);
7235  }
7236  AST_LIST_UNLOCK(&temp->lines);
7237  }
7238  AST_LIST_UNLOCK(&d->lines);
7239  ast_mutex_unlock(&d->lock);
7240  }
7242  }
7243 
7244  ast_mutex_unlock(&d->lock);
7245 
7246  ast_verb(3, "%s config for device '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), d->name);
7247 
7248  return d;
7249 
7250  }
7251 
7252  static int config_load(void)
7253  {
7254  int on = 1;
7255  struct ast_config *cfg;
7256  char *cat;
7257  int oldport = ntohs(bindaddr.sin_port);
7258  struct ast_flags config_flags = { 0 };
7259 
7260  ast_log(LOG_NOTICE, "Configuring skinny from %s\n", config);
7261 
7262  if (gethostname(ourhost, sizeof(ourhost))) {
7263  ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled.\n");
7264  return 0;
7265  }
7266  cfg = ast_config_load(config, config_flags);
7267 
7268  /* We *must* have a config file otherwise stop immediately */
7269  if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
7270  ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled.\n", config);
7271  return -1;
7272  }
7273  memset(&bindaddr, 0, sizeof(bindaddr));
7274  memset(&default_prefs, 0, sizeof(default_prefs));
7275 
7276  /* Copy the default jb config over global_jbconf */
7277  memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
7278 
7279  /* load the general section */
7280  cat = ast_category_browse(cfg, "general");
7282 
7283  if (ntohl(bindaddr.sin_addr.s_addr)) {
7284  __ourip = bindaddr.sin_addr;
7285  } else {
7286  hp = ast_gethostbyname(ourhost, &ahp);
7287  if (!hp) {
7288  ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
7289  ast_config_destroy(cfg);
7290  return 0;
7291  }
7292  memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
7293  }
7294  if (!ntohs(bindaddr.sin_port)) {
7295  bindaddr.sin_port = htons(DEFAULT_SKINNY_PORT);
7296  }
7297  bindaddr.sin_family = AF_INET;
7298 
7299  /* load the lines sections */
7300  default_line->confcapability = default_capability;
7301  default_line->confprefs = default_prefs;
7303  cat = ast_category_browse(cfg, "lines");
7304  while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "devices")) {
7305  config_line(cat, ast_variable_browse(cfg, cat));
7306  cat = ast_category_browse(cfg, cat);
7307  }
7308 
7309  /* load the devices sections */
7310  default_device->confcapability = default_capability;
7311  default_device->confprefs = default_prefs;
7313  cat = ast_category_browse(cfg, "devices");
7314  while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "lines")) {
7315  config_device(cat, ast_variable_browse(cfg, cat));
7316  cat = ast_category_browse(cfg, cat);
7317  }
7318 
7320  if ((skinnysock > -1) && (ntohs(bindaddr.sin_port) != oldport)) {
7321  close(skinnysock);
7322  skinnysock = -1;
7323  }
7324  if (skinnysock < 0) {
7325  skinnysock = socket(AF_INET, SOCK_STREAM, 0);
7326  if(setsockopt(skinnysock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
7327  ast_log(LOG_ERROR, "Set Socket Options failed: errno %d, %s\n", errno, strerror(errno));
7328  ast_config_destroy(cfg);
7330  return 0;
7331  }
7332  if (skinnysock < 0) {
7333  ast_log(LOG_WARNING, "Unable to create Skinny socket: %s\n", strerror(errno));
7334  } else {
7335  if (bind(skinnysock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
7336  ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
7337  ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
7338  strerror(errno));
7339  close(skinnysock);
7340  skinnysock = -1;
7341  ast_config_destroy(cfg);
7343  return 0;
7344  }
7345  if (listen(skinnysock, DEFAULT_SKINNY_BACKLOG)) {
7346  ast_log(LOG_WARNING, "Failed to start listening to %s:%d: %s\n",
7347  ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
7348  strerror(errno));
7349  close(skinnysock);
7350  skinnysock = -1;
7351  ast_config_destroy(cfg);
7353  return 0;
7354  }
7355  ast_verb(2, "Skinny listening on %s:%d\n",
7356  ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
7357  ast_netsock_set_qos(skinnysock, qos.tos, qos.cos, "Skinny");
7358  ast_pthread_create_background(&accept_t, NULL, accept_thread, NULL);
7359  }
7360  }
7362  ast_config_destroy(cfg);
7363  return 1;
7364 }
7365 
7366 static void delete_devices(void)
7367 {
7368  struct skinny_device *d;
7369  struct skinny_line *l;
7370  struct skinny_speeddial *sd;
7371  struct skinny_addon *a;
7372 
7374  AST_LIST_LOCK(&lines);
7375 
7376  /* Delete all devices */
7377  while ((d = AST_LIST_REMOVE_HEAD(&devices, list))) {
7378  /* Delete all lines for this device */
7379  while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) {
7380  AST_LIST_REMOVE(&lines, l, all);
7381  free(l);
7382  }
7383  /* Delete all speeddials for this device */
7384  while ((sd = AST_LIST_REMOVE_HEAD(&d->speeddials, list))) {
7385  free(sd);
7386  }
7387  /* Delete all addons for this device */
7388  while ((a = AST_LIST_REMOVE_HEAD(&d->addons, list))) {
7389  free(a);
7390  }
7391  free(d);
7392  }
7395 }
7396 
7397 int skinny_reload(void)
7398 {
7399  struct skinny_device *d;
7400  struct skinny_line *l;
7401  struct skinny_speeddial *sd;
7402  struct skinny_addon *a;
7403  struct skinny_req *req;
7404 
7405  if (skinnyreload) {
7406  ast_verb(3, "Chan_skinny is already reloading.\n");
7407  return 0;
7408  }
7409 
7410  skinnyreload = 1;
7411 
7412  /* Mark all devices and lines as candidates to be pruned */
7414  AST_LIST_TRAVERSE(&devices, d, list) {
7415  d->prune = 1;
7416  }
7418 
7419  AST_LIST_LOCK(&lines);
7420  AST_LIST_TRAVERSE(&lines, l, all) {
7421  l->prune = 1;
7422  }
7424 
7425  config_load();
7426 
7427  /* Remove any devices that no longer exist in the config */
7430  if (!d->prune) {
7431  continue;
7432  }
7433  ast_verb(3, "Removing device '%s'\n", d->name);
7434  /* Delete all lines for this device.
7435  We do not want to free the line here, that
7436  will happen below. */
7437  while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) {
7438  }
7439  /* Delete all speeddials for this device */
7440  while ((sd = AST_LIST_REMOVE_HEAD(&d->speeddials, list))) {
7441  free(sd);
7442  }
7443  /* Delete all addons for this device */
7444  while ((a = AST_LIST_REMOVE_HEAD(&d->addons, list))) {
7445  free(a);
7446  }
7448  free(d);
7449  }
7452 
7453  AST_LIST_LOCK(&lines);
7455  if (l->prune) {
7457  free(l);
7458  }
7459  }
7462 
7463  AST_LIST_TRAVERSE(&devices, d, list) {
7464  /* Do a soft reset to re-register the devices after
7465  cleaning up the removed devices and lines */
7466  if (d->session) {
7467  ast_verb(3, "Restarting device '%s'\n", d->name);
7468  if ((req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE))) {
7469  req->data.reset.resetType = 2;
7470  transmit_response(d, req);
7471  }
7472  }
7473  }
7474 
7475  skinnyreload = 0;
7476  return 0;
7477 }
7478 
7479 static int load_module(void)
7480 {
7481  int res = 0;
7482 
7483  for (; res < ARRAY_LEN(soft_key_template_default); res++) {
7484  soft_key_template_default[res].softKeyEvent = htolel(soft_key_template_default[res].softKeyEvent);
7485  }
7486  /* load and parse config */
7487  res = config_load();
7488  if (res == -1) {
7489  return AST_MODULE_LOAD_DECLINE;
7490  }
7491 
7492  /* Make sure we can register our skinny channel type */
7494  ast_log(LOG_ERROR, "Unable to register channel class 'Skinny'\n");
7495  return -1;
7496  }
7497 
7500 
7505 
7506  sched = sched_context_create();
7507  if (!sched) {
7508  ast_log(LOG_WARNING, "Unable to create schedule context\n");
7509  }
7510  io = io_context_create();
7511  if (!io) {
7512  ast_log(LOG_WARNING, "Unable to create I/O context\n");
7513  }
7514  /* And start the monitor for the first time */
7515  restart_monitor();
7516 
7517  return AST_MODULE_LOAD_SUCCESS;
7518 }
7519 
7520 static int unload_module(void)
7521 {
7522  struct skinnysession *s;
7523  struct skinny_device *d;
7524  struct skinny_line *l;
7525  struct skinny_subchannel *sub;
7526  struct ast_context *con;
7527 
7531 
7532  ast_manager_unregister("SKINNYdevices");
7533  ast_manager_unregister("SKINNYshowdevice");
7534  ast_manager_unregister("SKINNYlines");
7535  ast_manager_unregister("SKINNYshowline");
7536 
7538  /* Destroy all the interfaces and free their memory */
7539  while((s = AST_LIST_REMOVE_HEAD(&sessions, list))) {
7540  d = s->device;
7541  AST_LIST_TRAVERSE(&d->lines, l, list){
7542  ast_mutex_lock(&l->lock);
7543  AST_LIST_TRAVERSE(&l->sub, sub, list) {
7544  ast_mutex_lock(&sub->lock);
7545  if (sub->owner) {
7546  sub->alreadygone = 1;
7548  }
7549  ast_mutex_unlock(&sub->lock);
7550  }
7551  if (l->mwi_event_sub)
7553  ast_mutex_unlock(&l->lock);
7554  manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Unregistered\r\n", l->name, d->name);
7555  unregister_exten(l);
7556  }
7557  if (s->fd > -1)
7558  close(s->fd);
7559  pthread_cancel(s->t);
7560  pthread_kill(s->t, SIGURG);
7561  pthread_join(s->t, NULL);
7562  free(s);
7563  }
7565 
7566  delete_devices();
7567 
7569  if ((monitor_thread != AST_PTHREADT_NULL) && (monitor_thread != AST_PTHREADT_STOP)) {
7570  pthread_cancel(monitor_thread);
7571  pthread_kill(monitor_thread, SIGURG);
7572  pthread_join(monitor_thread, NULL);
7573  }
7574  monitor_thread = AST_PTHREADT_STOP;
7576 
7578  if (accept_t && (accept_t != AST_PTHREADT_STOP)) {
7579  pthread_cancel(accept_t);
7580  pthread_kill(accept_t, SIGURG);
7581  pthread_join(accept_t, NULL);
7582  }
7583  accept_t = AST_PTHREADT_STOP;
7585 
7586  close(skinnysock);
7587  if (sched)
7588  sched_context_destroy(sched);
7589 
7590  con = ast_context_find(used_context);
7591  if (con)
7592  ast_context_destroy(con, "Skinny");
7593 
7594  return 0;
7595 }
7596 
7597 static int reload(void)
7598 {
7599  skinny_reload();
7600  return 0;
7601 }
7602 
7603 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Skinny Client Control Protocol (Skinny)",
7604  .load = load_module,
7605  .unload = unload_module,
7606  .reload = reload,
7607  .load_pri = AST_MODPRI_CHANNEL_DRIVER,
7608 );
int ast_io_wait(struct io_context *ioc, int howlong)
Waits for IO.
Definition: io.c:273
#define SKINNY_DEVICE_7931
Definition: chan_skinny.c:1072
static const uint8_t soft_key_default_connwithconf[]
Definition: chan_skinny.c:872
union skinny_data data
Definition: chan_skinny.c:1027
#define START_TONE_MESSAGE
Definition: chan_skinny.c:370
static void transmit_dialednumber(struct skinny_device *d, const char *text, int instance, int callid)
Definition: chan_skinny.c:2379
void ast_rtp_codecs_packetization_set(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_codec_pref *prefs)
Set codec packetization preferences.
Definition: rtp_engine.c:727
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:81
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1916
int ast_queue_hangup(struct ast_channel *chan)
Queue a hangup frame.
Definition: channel.c:1569
union ast_frame_subclass subclass
Definition: frame.h:146
static char * _skinny_show_lines(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[])
Definition: chan_skinny.c:3384
int ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2804
static struct ast_channel * skinny_new(struct skinny_line *l, int state, const char *linkedid)
Definition: chan_skinny.c:4509
static void * get_button_template(struct skinnysession *s, struct button_definition_template *btn)
Definition: chan_skinny.c:1414
struct soft_key_template_res_message softkeytemplate
Definition: chan_skinny.c:995
struct sockaddr_storage ss
Definition: netsock2.h:64
char displayMessage[80]
Definition: chan_skinny.c:334
enum sip_cc_notify_state state
Definition: chan_sip.c:842
Tone Indication Support.
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:383
#define SOFTKEY_TRNSFER
Definition: chan_skinny.c:637
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:5362
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:7051
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:5420
#define SKINNY_HOLD
Definition: chan_skinny.c:1105
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
Main Channel structure associated with a channel.
Definition: channel.h:742
#define SKINNY_DEVICE_7960
Definition: chan_skinny.c:1061
Music on hold handling.
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
static enum ast_rtp_glue_result skinny_get_rtp_peer(struct ast_channel *c, struct ast_rtp_instance **instance)
Definition: chan_skinny.c:2784
ast_device_state
Device States.
Definition: devicestate.h:51
#define DEFAULT_AUTH_LIMIT
Definition: chan_skinny.c:164
uint32_t space[3]
Definition: chan_skinny.c:940
An event.
Definition: event.c:85
char * str
Subscriber phone number (Malloced)
Definition: channel.h:241
ast_mutex_t lock
Definition: chan_skinny.c:1336
static int reload(void)
Definition: chan_skinny.c:7597
struct ast_party_connected_line connected
Channel Connected Line ID information.
Definition: channel.h:811
uint32_t deviceStimulus
Definition: chan_skinny.c:396
#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:2958
#define SKINNY_CX_RECVONLY
Definition: chan_skinny.c:1138
const char *const type
Definition: channel.h:508
static void transmit_cfwdstate(struct skinny_device *d, struct skinny_line *l)
Definition: chan_skinny.c:2461
Asterisk locking-related definitions:
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:2068
Asterisk main include file. File version handling, generic pbx functions.
int rings
Definition: channel.h:840
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
#define SKINNY_DIALTONE
Definition: chan_skinny.c:1114
#define BUTTON_TEMPLATE_REQ_MESSAGE
Definition: chan_skinny.c:327
struct ast_ha * ha
Definition: chan_skinny.c:1339
static struct ast_codec_pref default_prefs
Definition: chan_skinny.c:148
#define TYPE_DEF_DEVICE
Definition: chan_skinny.c:6701
struct button_template_res_message buttontemplate
Definition: chan_skinny.c:984
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:172
static pthread_t monitor_thread
Definition: chan_skinny.c:1167
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
void ast_module_unref(struct ast_module *)
Definition: loader.c:1312
#define SKINNY_RINGIN
Definition: chan_skinny.c:1101
static struct skinny_device * config_device(const char *dname, struct ast_variable *v)
Definition: chan_skinny.c:7163
static char parkinglot[AST_MAX_CONTEXT]
Definition: chan_mgcp.c:156
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame with payload.
Definition: channel.c:1601
struct ast_frame ast_null_frame
Definition: frame.c:131
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
struct ast_tone_zone * zone
Definition: channel.h:767
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
struct register_ack_message regack
Definition: chan_skinny.c:980
struct register_rej_message regrej
Definition: chan_skinny.c:981
char * strsep(char **str, const char *delims)
#define STOP_TONE_MESSAGE
Definition: chan_skinny.c:378
#define START_MEDIA_TRANSMISSION_MESSAGE
Definition: chan_skinny.c:410
int tm_usec
Definition: localtime.h:48
uint32_t alarmSeverity
Definition: chan_skinny.c:333
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
Definition: callerid.c:1093
#define SKINNY_SPEAKERON
Definition: chan_skinny.c:1092
static void * accept_thread(void *ignore)
Definition: chan_skinny.c:6545
#define SOFT_KEY_SET_RES_MESSAGE
Definition: chan_skinny.c:912
int priority
Definition: channel.h:841
char callingParty[24]
Definition: chan_skinny.c:439
#define SKINNY_DEVICE_7921
Definition: chan_skinny.c:1073
static int gendigittimeout
Definition: chan_skinny.c:1173
static void register_exten(struct skinny_line *l)
Definition: chan_skinny.c:1821
static struct skinny_req * skinny_req_parse(struct skinnysession *s)
Definition: chan_skinny.c:6485
struct keypad_button_message keypad
Definition: chan_skinny.c:1001
#define LINE_STAT_RES_MESSAGE
Definition: chan_skinny.c:477
#define SOFTKEY_INFO
Definition: chan_skinny.c:645
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:767
#define ast_strdup(a)
Definition: astmm.h:109
int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone)
Weird function made for call transfers.
Definition: channel.c:6110
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
static int skinny_unhold(struct skinny_subchannel *sub)
Definition: chan_skinny.c:4657
format_t writeformat
Definition: channel.h:854
struct enbloc_call_message enbloccallmessage
Definition: chan_skinny.c:1018
static unsigned int tos
Definition: chan_h323.c:146
static char ourhost[256]
Definition: chan_skinny.c:1044
ast_mutex_t lock
Definition: chan_skinny.c:1366
struct ast_party_id id
Connected party ID.
Definition: channel.h:403
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
#define AST_FORMAT_H261
Definition: frame.h:280
#define SKINNY_LAMP_BLINK
Definition: chan_skinny.c:1125
static struct ast_jb_conf default_jbconf
Definition: chan_skinny.c:227
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define SKINNY_CONGESTION
Definition: chan_skinny.c:1104
int option_debug
Definition: asterisk.c:182
static struct skinny_line * find_line_by_instance(struct skinny_device *d, int instance)
Definition: chan_skinny.c:1565
static int auth_timeout
Definition: chan_skinny.c:176
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:511
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4393
#define KEEP_ALIVE_MESSAGE
Definition: chan_skinny.c:252
#define CLEAR_DISPLAY_MESSAGE
Definition: chan_skinny.c:569
struct skinnysession * session
Definition: chan_skinny.c:1340
struct ast_party_name name
Subscriber name.
Definition: channel.h:290
#define AST_FORMAT_G723_1
Definition: frame.h:242
ast_mutex_t lock
Definition: chan_skinny.c:1179
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:938
#define SKINNY_DEVICE_12
Definition: chan_skinny.c:1058
#define TYPE_DEF_LINE
Definition: chan_skinny.c:6702
static struct in_addr __ourip
Definition: chan_skinny.c:1046
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a registered state change callback by ID.
Definition: pbx.c:5157
void * tech_pvt
Definition: channel.h:744
static int handle_stimulus_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:4977
struct forward_stat_message forwardstat
Definition: chan_skinny.c:1019
#define SELECT_SOFT_KEYS_MESSAGE
Definition: chan_skinny.c:927
Convenient Signal Processing routines.
#define STIMULUS_DISPLAY
Definition: chan_skinny.c:517
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
int 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:518
struct set_speaker_message setspeaker
Definition: chan_skinny.c:1007
struct skinny_device::@110 speeddials
int ast_app_has_voicemail(const char *mailbox, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to &quot;INBOX&quot;. If folder is &quot;INBOX&quot;, includes the number of messages in the &quot;Urgent&quot; folder.
Definition: app.c:421
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:483
#define SOFTKEY_RESUME
Definition: chan_skinny.c:643
static char * handle_skinny_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_skinny.c:3234
#define VERBOSE_PREFIX_3
Definition: logger.h:43
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
#define LOG_WARNING
Definition: logger.h:144
#define DIALED_NUMBER_MESSAGE
Definition: chan_skinny.c:969
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:5879
static void destroy_session(struct skinnysession *s)
Definition: chan_skinny.c:6362
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
struct start_tone_message starttone
Definition: chan_skinny.c:989
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
static void transmit_selectsoftkeys(struct skinny_device *d, int instance, int callid, int softkey)
Definition: chan_skinny.c:2242
struct version_res_message version
Definition: chan_skinny.c:983
static const char tdesc[]
Definition: chan_skinny.c:144
static char * _skinny_show_device(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
Definition: chan_skinny.c:3251
#define CONTROL2STR_BUFSIZE
Definition: chan_skinny.c:246
struct ast_rtp_instance * rtp
Definition: chan_skinny.c:1181
int ast_jb_read_conf(struct ast_jb_conf *conf, const char *varname, const char *value)
Sets jitterbuffer configuration property.
Definition: abstract_jb.c:577
uint32_t callreference
Definition: chan_skinny.c:284
#define REGISTER_AVAILABLE_LINES_MESSAGE
Definition: chan_skinny.c:359
int lineno
Definition: config.h:87
void ast_verbose(const char *fmt,...)
Definition: logger.c:1568
#define SOFTKEY_DND
Definition: chan_skinny.c:652
static const uint8_t soft_key_default_ringin[]
Definition: chan_skinny.c:844
#define CDEV_OPTS
Definition: chan_skinny.c:6708
#define SKINNY_DEVICE_7962
Definition: chan_skinny.c:1075
static void transmit_definetimedate(struct skinny_device *d)
Definition: chan_skinny.c:2532
uint8_t instanceNumber
Definition: chan_skinny.c:500
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:1570
#define SKINNY_DEVICE_SCCPGATEWAY_AN
Definition: chan_skinny.c:1089
#define CLINE_OPTS
Definition: chan_skinny.c:6706
uint32_t resetType
Definition: chan_skinny.c:591
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
struct media_qualifier qualifier
Definition: chan_skinny.c:425
#define AST_LOG_WARNING
Definition: logger.h:149
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:774
static int handle_offhook_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:5329
static int codec_ast2skinny(format_t astcodec)
Definition: chan_skinny.c:1741
#define CLINE
Definition: chan_skinny.c:6707
#define SERVER_RES_MESSAGE
Definition: chan_skinny.c:578
int ast_rtp_instance_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
Send a frame out over RTP.
Definition: rtp_engine.c:374
char calledPartyName[40]
Definition: chan_skinny.c:440
#define SKINNY_ALERT
Definition: chan_skinny.c:1116
#define SOFTKEY_NEWCALL
Definition: chan_skinny.c:635
format_t rawwriteformat
Definition: channel.h:856
static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
Definition: chan_skinny.c:4203
struct register_message reg
Definition: chan_skinny.c:979
static struct ast_threadstorage device2str_threadbuf
Definition: chan_skinny.c:242
#define ast_rtp_glue_register(glue)
Definition: rtp_engine.h:476
format_t ast_codec_pref_index(struct ast_codec_pref *pref, int index)
Codec located at a particular place in the preference index.
Definition: frame.c:1061
ast_mutex_t lock
Definition: chan_skinny.c:1292
#define STIMULUS_LINE
Definition: chan_skinny.c:518
#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:580
static char date_format[6]
Definition: chan_skinny.c:182
struct soft_key_set_res_message softkeysets
Definition: chan_skinny.c:994
#define SKINNY_CONNECTED
Definition: chan_skinny.c:1102
struct call_state_message callstate
Definition: chan_skinny.c:1000
struct close_receive_channel_message closereceivechannel
Definition: chan_skinny.c:1014
static format_t default_capability
Definition: chan_skinny.c:147
uint32_t stimulus
Definition: chan_skinny.c:282
static char * _skinny_show_line(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
Definition: chan_skinny.c:3508
#define BT_CALLPARK
Definition: chan_skinny.c:541
#define SKINNY_CFWD_BUSY
Definition: chan_skinny.c:1133
struct dialed_number_message dialednumber
Definition: chan_skinny.c:1016
char originalCalledParty[24]
Definition: chan_skinny.c:446
Definition: sched.c:57
struct line_stat_res_message linestat
Definition: chan_skinny.c:993
Definition: cli.h:146
char exten[AST_MAX_EXTENSION]
Definition: chan_skinny.c:1295
uint32_t space[15]
Definition: chan_skinny.c:482
int ast_ignore_pattern(const char *context, const char *pattern)
Checks to see if a number should be ignored.
Definition: pbx.c:8650
struct stop_media_transmission_message stopmedia
Definition: chan_skinny.c:1011
Configuration File Parser.
static const uint8_t soft_key_default_unknown[]
Definition: chan_skinny.c:887
#define SOFTKEY_BKSPC
Definition: chan_skinny.c:641
int ast_netsock_set_qos(int netsocket, int tos, int cos, const char *desc)
Definition: netsock.c:158
static int handle_keep_alive_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:4776
char * str
Subscriber name (Malloced)
Definition: channel.h:214
char outbuf[SKINNY_MAX_PACKET]
Definition: chan_skinny.c:1371
static struct skinny_subchannel * find_subchannel_by_instance_reference(struct skinny_device *d, int instance, int reference)
Definition: chan_skinny.c:1653
uint32_t stimulusInstance
Definition: chan_skinny.c:283
#define KEYDEF_CONNWITHCONF
Definition: chan_skinny.c:628
#define DEFAULT_AUTH_TIMEOUT
Definition: chan_skinny.c:163
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, format_t codecs, int nat_active)
Definition: chan_skinny.c:2821
format_t ast_best_codec(format_t fmts)
Pick the best audio codec.
Definition: channel.c:1062
static char * control2str(int ind)
Definition: chan_skinny.c:4263
static int auth_limit
Definition: chan_skinny.c:177
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
#define SOFTKEY_HOLD
Definition: chan_skinny.c:636
Number of new messages Used by: AST_EVENT_MWI Payload type: UINT.
Definition: event_defs.h:71
#define SKINNY_DEVICE_7920
Definition: chan_skinny.c:1082
static int skinny_senddigit_begin(struct ast_channel *ast, char digit)
Definition: chan_skinny.c:4215
uint32_t lastRedirectingReason
Definition: chan_skinny.c:450
uint32_t lineInstance
Definition: chan_skinny.c:938
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
#define ast_mutex_lock(a)
Definition: lock.h:155
struct station_capabilities caps[SKINNY_MAX_CAPABILITIES]
Definition: chan_skinny.c:313
static void * skinny_newcall(void *data)
Definition: chan_skinny.c:3773
#define SKINNY_DEVICE_7975
Definition: chan_skinny.c:1080
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:907
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:374
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:3368
char * text
Definition: app_queue.c:1091
format_t nativeformats
Definition: channel.h:852
struct display_prompt_status_message displaypromptstatus
Definition: chan_skinny.c:986
#define BT_FORWARDALL
Definition: chan_skinny.c:532
struct activate_call_plane_message activatecallplane
Definition: chan_skinny.c:1003
#define htolel(x)
Definition: chan_skinny.c:195
struct skinny_device * device
Definition: chan_skinny.c:1263
static struct soft_key_definitions soft_key_default_definitions[]
Definition: chan_skinny.c:891
static struct soft_key_template_definition soft_key_template_default[]
Definition: chan_skinny.c:655
SKINNY_LINE_OPTIONS ast_mutex_t lock
Definition: chan_skinny.c:1257
int ast_str2tos(const char *value, unsigned int *tos)
Convert a string to the appropriate TOS value.
Definition: acl.c:667
#define SKINNY_DEVICE_7937
Definition: chan_skinny.c:1076
#define SKINNY_LINE_OPTIONS
Definition: chan_skinny.c:1202
format_t codec
Definition: frame.h:137
struct definetimedate_message definetimedate
Definition: chan_skinny.c:988
static int skinny_header_size
Definition: chan_skinny.c:1033
#define SKINNY_PROGRESS
Definition: chan_skinny.c:1109
static void start_rtp(struct skinny_subchannel *sub)
Definition: chan_skinny.c:3727
const char * data
Definition: channel.h:755
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
#define SKINNY_DEVICE_OPTIONS
Definition: chan_skinny.c:1312
static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
Definition: chan_skinny.c:4386
I/O Management (derived from Cheops-NG)
static int config_load(void)
Definition: chan_skinny.c:7252
char * ast_cdr_flags2str(int flags)
Definition: cdr.c:977
Definitions to aid in the use of thread local storage.
#define ALARM_MESSAGE
Definition: chan_skinny.c:331
struct set_microphone_message setmicrophone
Definition: chan_skinny.c:1008
#define UNREGISTER_MESSAGE
Definition: chan_skinny.c:356
Common implementation-independent jitterbuffer stuff.
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
struct soft_key_set_definition softKeySetDefinition[16]
Definition: chan_skinny.c:923
struct ast_event_sub * mwi_event_sub
Definition: chan_skinny.c:1258
#define LINE_STATE_REQ_MESSAGE
Definition: chan_skinny.c:321
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:841
#define BT_SPEEDDIAL
Definition: chan_skinny.c:529
const ast_string_field linkedid
Definition: channel.h:787
#define LOG_DEBUG
Definition: logger.h:122
static void transmit_linestatres(struct skinny_device *d, struct skinny_line *l)
Definition: chan_skinny.c:2519
static void transmit_displaynotify(struct skinny_device *d, const char *text, int t)
Definition: chan_skinny.c:2329
static int restart_monitor(void)
Definition: chan_skinny.c:6630
#define SKINNY_LAMP_FLASH
Definition: chan_skinny.c:1124
#define SKINNY_DEVICE_7905
Definition: chan_skinny.c:1081
#define KEYDEF_DADFD
Definition: chan_skinny.c:627
#define SOFTKEY_CFWDNOANSWER
Definition: chan_skinny.c:640
const char * ext
Definition: http.c:112
enum ast_channel_adsicpe adsicpe
Definition: channel.h:844
format_t rawreadformat
Definition: channel.h:855
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:600
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:8051
void ast_free_ptr(void *ptr)
#define TYPE_LINE
Definition: chan_skinny.c:6704
struct offhook_message offhook
Definition: chan_skinny.c:1005
Socket address structure.
Definition: netsock2.h:63
struct skinny_device::@111 addons
static int skinnydebug
Definition: chan_skinny.c:1039
static int firstdigittimeout
Definition: chan_skinny.c:1170
static format_t codec_skinny2ast(enum skinny_codecs skinnycodec)
Definition: chan_skinny.c:1719
ast_group_t pickupgroup
Definition: channel.h:819
int tm_year
Definition: localtime.h:41
char callingPartyName[40]
Definition: chan_skinny.c:438
struct speed_dial_stat_res_message speeddial
Definition: chan_skinny.c:991
#define ast_verb(level,...)
Definition: logger.h:243
Definition: ael.tab.c:203
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
const char * type
Definition: rtp_engine.h:395
unsigned int callid
Definition: chan_skinny.c:1183
static void cleanup_stale_contexts(char *new, char *old)
Definition: chan_skinny.c:1798
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
Definition: lock.h:603
static int skinnyreload
Definition: chan_skinny.c:1040
const char * line
Definition: cli.h:156
ast_group_t callgroup
Definition: channel.h:818
struct ast_channel * ast_channel_alloc(int needqueue, int state, const char *cid_num, const char *cid_name, const char *acctcode, const char *exten, const char *context, const char *linkedid, const int amaflag, const char *name_fmt,...)
Definition: channel.c:9825
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition: pbx.c:5415
uint32_t secondaryKeepAlive
Definition: chan_skinny.c:366
#define BT_HOLD
Definition: chan_skinny.c:530
#define SOFTKEY_GPICKUP
Definition: chan_skinny.c:651
uint32_t reference
Definition: chan_skinny.c:443
#define AST_FORMAT_G729A
Definition: frame.h:258
#define SOFTKEY_PICKUP
Definition: chan_skinny.c:650
static char * handle_skinny_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_skinny.c:2988
uint32_t alarmParam2
Definition: chan_skinny.c:336
union station_capabilities::@102 payloads
#define SOFTKEY_CFWDBUSY
Definition: chan_skinny.c:639
static char * complete_skinny_devices(const char *word, int state)
Definition: chan_skinny.c:2944
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
Simply remove extension from context.
Definition: pbx.c:6114
static ast_mutex_t monlock
Definition: chan_skinny.c:1161
String fields in structures.
struct skinny_subchannel::@103 list
Utility functions.
#define SOFTKEY_NONE
Definition: chan_skinny.c:633
char * ast_print_group(char *buf, int buflen, ast_group_t group)
print call- and pickup groups into buffer
Definition: channel.c:8236
int args
This gets set in ast_cli_register()
Definition: cli.h:179
static void transmit_stopmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub)
Definition: chan_skinny.c:2405
uint32_t instance
Definition: chan_skinny.c:289
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:1860
struct skinny_device * device
Definition: chan_skinny.c:1372
#define SKINNY_DEVICE_SCCPGATEWAY_BRI
Definition: chan_skinny.c:1090
static int handle_button_template_req_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:5546
static int skinny_unregister(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:1942
char context[AST_MAX_CONTEXT]
Definition: chan_skinny.c:1294
struct soft_key_template_definition softKeyTemplateDefinition[32]
Definition: chan_skinny.c:909
char lastRedirectingPartyName[40]
Definition: chan_skinny.c:447
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:426
#define HEADSET_STATUS_MESSAGE
Definition: chan_skinny.c:358
struct skinny_line * parent
Definition: chan_skinny.c:1199
int ast_masq_park_call(struct ast_channel *park_me, struct ast_channel *parker, int timeout, int *extout)
Park a call via a masqueraded channel.
Definition: features.c:1857
uint32_t reference
Definition: chan_skinny.c:381
static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
Definition: chan_skinny.c:4171
long resync_threshold
Resynchronization threshold of the jitterbuffer implementation.
Definition: abstract_jb.h:62
char lastRedirectingParty[24]
Definition: chan_skinny.c:448
char calledParty[24]
Definition: chan_skinny.c:441
internal representation of acl entries In principle user applications would have no need for this...
Definition: acl.h:48
static int handle_enbloc_call_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:5755
Definition of supported media formats (codecs)
Definition: frame.h:550
#define KEYDEF_ONHOLD
Definition: chan_skinny.c:623
uint32_t serverIpAddr[5]
Definition: chan_skinny.c:586
Call Detail Record API.
struct ast_party_id id
Caller party ID.
Definition: channel.h:370
#define BUTTON_TEMPLATE_RES_MESSAGE
Definition: chan_skinny.c:498
int ast_set_write_format(struct ast_channel *chan, format_t format)
Sets write format on channel chan Set write format for channel to whichever component of &quot;format&quot; is ...
Definition: channel.c:5307
struct skinny_line * activeline
Definition: chan_skinny.c:1341
static char * _skinny_show_devices(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[])
Definition: chan_skinny.c:3140
static int matchdigittimeout
Definition: chan_skinny.c:1176
#define SKINNY_DEVICE_7971
Definition: chan_skinny.c:1066
static char used_context[AST_MAX_EXTENSION]
Definition: chan_skinny.c:180
#define BT_CUST_LINE
Definition: chan_skinny.c:549
struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, format_t format)
Get packet size for codec.
Definition: frame.c:1205
#define STIMULUS_FORWARDALL
Definition: chan_skinny.c:514
static int handle_callforward_button(struct skinny_subchannel *sub, int cfwdtype)
Definition: chan_skinny.c:4852
#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:2963
int ast_set_read_format(struct ast_channel *chan, format_t format)
Sets read format on channel chan Set read format for channel to whichever component of &quot;format&quot; is be...
Definition: channel.c:5301
uint32_t instance
Definition: chan_skinny.c:295
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
ast_mutex_t lock
Definition: chan_skinny.c:1306
static struct skinny_device_options * default_device
Definition: chan_skinny.c:1360
struct skinny_subchannel * activesub
Definition: chan_skinny.c:1259
struct sockaddr_in sin
Definition: chan_skinny.c:1368
#define REGISTER_REJ_MESSAGE
Definition: chan_skinny.c:573
Context IE Used by AST_EVENT_MWI Payload type: str.
Definition: event_defs.h:121
#define KEEP_ALIVE_ACK_MESSAGE
Definition: chan_skinny.c:594
const char * value
Definition: config.h:79
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:516
char originalCalledPartyName[40]
Definition: chan_skinny.c:445
static struct skinny_line_options default_line_struct
struct ast_module * self
Definition: module.h:227
struct ast_rtp_instance * vrtp
Definition: chan_skinny.c:1182
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition: callerid.c:1074
static struct skinny_line_options * default_line
Definition: chan_skinny.c:1287
uint32_t maxStreams
Definition: chan_skinny.c:262
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:377
#define BT_CONFERENCE
Definition: chan_skinny.c:540
SKINNY_DEVICE_OPTIONS struct type * first
Definition: chan_skinny.c:1334
static int skinny_reload(void)
Definition: chan_skinny.c:7397
static char * handle_skinny_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_skinny.c:2923
General Asterisk PBX channel definitions.
static struct ast_rtp_glue skinny_rtp_glue
Definition: chan_skinny.c:2874
#define SKINNY_DEVICE_7961GE
Definition: chan_skinny.c:1070
#define STIMULUS_VOICEMAIL
Definition: chan_skinny.c:519
#define SET_MICROPHONE_MESSAGE
Definition: chan_skinny.c:405
const char * src
Definition: frame.h:158
#define ast_sockaddr_from_sin(addr, sin)
Converts a struct sockaddr_in to a struct ast_sockaddr.
Definition: netsock2.h:642
#define SKINNY_LAMP_ON
Definition: chan_skinny.c:1122
Network socket handling.
static int ourport
Definition: chan_skinny.c:1045
const int fd
Definition: cli.h:153
#define AST_FORMAT_ALAW
Definition: frame.h:248
uint32_t precedence
Definition: chan_skinny.c:412
#define ast_config_load(filename, flags)
Load a config file.
Definition: config.h:170
#define ast_manager_register_xml(a, b, c)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:172
#define AST_PTHREADT_NULL
Definition: lock.h:65
#define letohl(x)
Definition: chan_skinny.c:193
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
const int n
Definition: cli.h:159
static void transmit_clear_display_message(struct skinny_device *d, int instance, int reference)
Definition: chan_skinny.c:2294
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
struct ast_variable * chanvars
Definition: chan_skinny.c:1264
Access Control of various sorts.
#define OPEN_RECEIVE_CHANNEL_MESSAGE
Definition: chan_skinny.c:596
#define htoles(x)
Definition: chan_skinny.c:196
Global IO variables are now in a struct in order to be made threadsafe.
Definition: io.c:66
struct skinny_line::@106 all
static struct ast_frame * skinny_read(struct ast_channel *ast)
Definition: chan_skinny.c:4161
#define AST_MAX_EXTENSION
Definition: channel.h:135
Scheduler Routines (derived from cheops)
static void config_parse_variables(int type, void *item, struct ast_variable *vptr)
Definition: chan_skinny.c:6711
#define SKINNY_DEVICE_7911
Definition: chan_skinny.c:1069
static int skinny_hangup(struct ast_channel *ast)
Definition: chan_skinny.c:3975
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition: channel.c:1981
#define BT_NONE
Definition: chan_skinny.c:543
int tm_mon
Definition: localtime.h:40
static void transmit_callinfo(struct skinny_device *d, const char *fromname, const char *fromnum, const char *toname, const char *tonum, int instance, int callid, int calltype)
Definition: chan_skinny.c:2169
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:554
#define AST_FORMAT_G726_AAL2
Definition: frame.h:250
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
#define ao2_ref(o, delta)
Definition: astobj2.h:472
static void update_connectedline(struct skinny_subchannel *sub, const void *data, size_t datalen)
Definition: chan_skinny.c:2674
#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:83
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2746
struct call_info_message callinfo
Definition: chan_skinny.c:1009
#define DEFAULT_SKINNY_PORT
Definition: chan_skinny.c:160
struct in_addr ourip
Definition: chan_skinny.c:1338
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:3661
static char * device2str(int type)
Definition: chan_skinny.c:3033
static void * skinny_ss(void *data)
Definition: chan_skinny.c:3806
#define CLOSE_RECEIVE_CHANNEL_MESSAGE
Definition: chan_skinny.c:607
static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
Definition: chan_skinny.c:4220
unsigned int cos_audio
Definition: chan_mgcp.c:173
static struct ast_tone_zone_sound * ast_tone_zone_sound_unref(struct ast_tone_zone_sound *ts)
Release a reference to an ast_tone_zone_sound.
Definition: indications.h:226
#define VERSION_REQ_MESSAGE
Definition: chan_skinny.c:328
#define TYPE_GENERAL
Definition: chan_skinny.c:6700
int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, const struct ast_sockaddr *address)
Set the address of the remote endpoint that we are sending RTP to.
Definition: rtp_engine.c:391
struct line_state_req_message line
Definition: chan_skinny.c:992
long target_extra
amount of additional jitterbuffer adjustment
Definition: abstract_jb.h:66
#define SKINNY_DEVICE_30SPPLUS
Definition: chan_skinny.c:1055
static const uint8_t soft_key_default_onhold[]
Definition: chan_skinny.c:837
struct open_receive_channel_ack_message openreceivechannelack
Definition: chan_skinny.c:1013
static void transmit_softkeysetres(struct skinny_device *d)
Definition: chan_skinny.c:2577
A set of macros to manage forward-linked lists.
static char language[MAX_LANGUAGE]
Definition: chan_alsa.c:108
const char * name
Definition: config.h:77
#define SKINNY_RING_OFF
Definition: chan_skinny.c:1127
static const uint8_t soft_key_default_ringout[]
Definition: chan_skinny.c:876
ast_group_t ast_get_group(const char *s)
Definition: channel.c:7987
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
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:5694
struct alarm_message alarm
Definition: chan_skinny.c:977
#define STIMULUS_REDIAL
Definition: chan_skinny.c:510
#define AST_FORMAT_H263
Definition: frame.h:283
#define SOFT_KEY_EVENT_MESSAGE
Definition: chan_skinny.c:349
static const char config[]
Definition: chan_skinny.c:145
#define STIMULUS_DND
Definition: chan_skinny.c:521
#define CLEAR_PROMPT_MESSAGE
Definition: chan_skinny.c:952
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:5400
ast_rtp_glue_result
Definition: rtp_engine.h:125
#define DEFINETIMEDATE_MESSAGE
Definition: chan_skinny.c:485
static char regcontext[AST_MAX_CONTEXT]
Definition: chan_skinny.c:181
#define ENBLOC_CALL_MESSAGE
Definition: chan_skinny.c:275
#define SKINNY_CFWD_NOANSWER
Definition: chan_skinny.c:1134
char impl[AST_JB_IMPL_NAME_SIZE]
Name of the jitterbuffer implementation to be used.
Definition: abstract_jb.h:64
Structure to describe a channel &quot;technology&quot;, ie a channel driver See for examples: ...
Definition: channel.h:507
Core PBX routines and definitions.
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:1558
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition: channel.c:2028
#define SOFTKEY_CFWDALL
Definition: chan_skinny.c:638
static int manager_skinny_show_device(struct mansession *s, const struct message *m)
Definition: chan_skinny.c:3347
static void transmit_start_tone(struct skinny_device *d, int tone, int instance, int reference)
Definition: chan_skinny.c:2221
#define SERVER_REQUEST_MESSAGE
Definition: chan_skinny.c:329
#define SOFTKEY_PARK
Definition: chan_skinny.c:647
struct type * last
Definition: chan_skinny.c:1335
struct ast_channel * owner
Definition: chan_skinny.c:1180
static struct skinny_line * config_line(const char *lname, struct ast_variable *v)
Definition: chan_skinny.c:7105
#define SKINNY_REORDER
Definition: chan_skinny.c:1117
#define SKINNY_CALLREMOTEMULTILINE
Definition: chan_skinny.c:1110
static struct ast_channel * skinny_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
Definition: chan_skinny.c:6669
#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
static struct ast_hostent ahp
Definition: chan_skinny.c:1047
static void transmit_startmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub, struct sockaddr_in dest, struct ast_format_list fmt)
Definition: chan_skinny.c:2417
static int handle_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:6178
const char *const * argv
Definition: cli.h:155
#define DEFAULT_SKINNY_BACKLOG
Definition: chan_skinny.c:161
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
uint32_t reference
Definition: chan_skinny.c:290
uint32_t stimulus
Definition: chan_skinny.c:394
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define SKINNY_DEVONLY(code)
Definition: chan_skinny.c:138
static int skinny_answer(struct ast_channel *ast)
Definition: chan_skinny.c:4071
static int manager_skinny_show_lines(struct mansession *s, const struct message *m)
Show Skinny lines in the manager API.
Definition: chan_skinny.c:3459
#define SET_RINGER_MESSAGE
Definition: chan_skinny.c:384
static enum ast_rtp_glue_result skinny_get_vrtp_peer(struct ast_channel *c, struct ast_rtp_instance **instance)
Definition: chan_skinny.c:2771
static int manager_skinny_show_line(struct mansession *s, const struct message *m)
Definition: chan_skinny.c:3640
char * ast_getformatname(format_t format)
Get the name of a format.
Definition: frame.c:578
#define BT_TRANSFER
Definition: chan_skinny.c:531
static pthread_t accept_t
Definition: chan_skinny.c:1050
static int load_module(void)
Definition: chan_skinny.c:7479
#define LOG_ERROR
Definition: logger.h:155
struct displaytext_message displaytext
Definition: chan_skinny.c:985
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
static struct skinny_line * find_line_by_name(const char *dest)
Definition: chan_skinny.c:1586
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
#define KEYDEF_UNKNOWN
Definition: chan_skinny.c:631
void sched_context_destroy(struct sched_context *c)
destroys a schedule context Destroys (free&#39;s) the given sched_context structure
Definition: sched.c:267
static int handle_transfer_button(struct skinny_subchannel *sub)
Definition: chan_skinny.c:4707
static struct ast_threadstorage control2str_threadbuf
Definition: chan_skinny.c:245
int64_t format_t
Definition: frame_defs.h:32
#define free(a)
Definition: astmm.h:94
static int skinny_transfer(struct skinny_subchannel *sub)
Definition: chan_skinny.c:4319
#define KEYPAD_BUTTON_MESSAGE
Definition: chan_skinny.c:267
#define ACTIVATE_CALL_PLANE_MESSAGE
Definition: chan_skinny.c:964
static int manager_skinny_show_devices(struct mansession *s, const struct message *m)
Show SKINNY devices in the manager API.
Definition: chan_skinny.c:3211
#define CLI_SHOWUSAGE
Definition: cli.h:44
#define SKINNY_SPEAKEROFF
Definition: chan_skinny.c:1093
static char global_vmexten[AST_MAX_EXTENSION]
Definition: chan_skinny.c:179
#define SKINNY_OFFHOOK
Definition: chan_skinny.c:1098
#define SOFTKEY_ENDCALL
Definition: chan_skinny.c:642
static struct ast_channel_tech skinny_tech
Definition: chan_skinny.c:1392
struct open_receive_channel_message openreceivechannel
Definition: chan_skinny.c:1012
static const uint8_t soft_key_default_connected[]
Definition: chan_skinny.c:828
struct stimulus_message stimulus
Definition: chan_skinny.c:1004
static int handle_soft_key_event_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:5805
static ast_mutex_t netlock
Definition: chan_skinny.c:1163
#define SKINNY_DEVICE_7941GE
Definition: chan_skinny.c:1071
#define AST_FORMAT_ULAW
Definition: frame.h:246
uint32_t bitRate
Definition: chan_skinny.c:415
Event subscription.
Definition: event.c:124
void ast_party_name_init(struct ast_party_name *init)
Initialize the given name structure.
Definition: channel.c:1928
char inbuf[SKINNY_MAX_PACKET]
Definition: chan_skinny.c:1370
#define SKINNY_ONHOOK
Definition: chan_skinny.c:1099
static const uint8_t soft_key_default_dadfd[]
Definition: chan_skinny.c:867
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int ast_cdr_amaflags2int(const char *flag)
Convert a string to a detail record AMA flag.
Definition: cdr.c:1105
Description of a tone.
Definition: indications.h:36
enum ast_channel_state _state
Definition: channel.h:839
struct set_lamp_message setlamp
Definition: chan_skinny.c:998
struct ast_tone_zone_sound * ast_get_indication_tone(const struct ast_tone_zone *zone, const char *indication)
Locate a tone zone sound.
Definition: indications.c:473
struct ast_channel * ast_bridged_channel(struct ast_channel *chan)
Find bridged channel.
Definition: channel.c:7160
static int handle_register_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:4785
static void * do_monitor(void *data)
Definition: chan_skinny.c:6604
static int unauth_sessions
Definition: chan_skinny.c:178
const ast_string_field name
Definition: channel.h:787
static struct ast_frame * skinny_rtp_read(struct skinny_subchannel *sub)
Definition: chan_skinny.c:4114
#define SKINNY_DEVICE_NONE
Definition: chan_skinny.c:1054
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:8040
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:3678
#define SKINNY_DEVICE_12SP
Definition: chan_skinny.c:1057
void ast_party_name_free(struct ast_party_name *doomed)
Destroy the party name contents.
Definition: channel.c:1975
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
struct select_soft_keys_message selectsoftkey
Definition: chan_skinny.c:1002
#define SKINNY_DEVICE_7985
Definition: chan_skinny.c:1068
#define SKINNY_CFWD_ALL
Definition: chan_skinny.c:1132
int ast_get_ip(struct ast_sockaddr *addr, const char *hostname)
Get the IP address given a hostname.
Definition: acl.c:700
static char * handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_skinny.c:2881
struct speed_dial_stat_req_message speeddialreq
Definition: chan_skinny.c:978
#define SOFTKEY_CONFRN
Definition: chan_skinny.c:646
#define LOG_NOTICE
Definition: logger.h:133
#define IP_PORT_MESSAGE
Definition: chan_skinny.c:265
#define KEYDEF_CONNECTED
Definition: chan_skinny.c:622
int ast_softhangup_nolock(struct ast_channel *chan, int reason)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2733
uint32_t serverListenPort[5]
Definition: chan_skinny.c:585
#define KEYDEF_ONHOOK
Definition: chan_skinny.c:621
#define SKINNY_LAMP_OFF
Definition: chan_skinny.c:1121
int framing[64]
Definition: frame.h:40
#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:625
int fdno
Definition: channel.h:834
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:696
int tm_wday
Definition: localtime.h:42
int errno
#define SET_SPEAKER_MESSAGE
Definition: chan_skinny.c:399
uint16_t packets
Definition: chan_skinny.c:414
static void transmit_connect(struct skinny_device *d, struct skinny_subchannel *sub)
Definition: chan_skinny.c:2201
#define SKINNY_DEVICE_7970
Definition: chan_skinny.c:1083
static const char name[]
#define AST_MAX_CONTEXT
Definition: channel.h:136
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
Definition: utils.c:564
#define BT_REDIAL
Definition: chan_skinny.c:528
#define CALL_STATE_MESSAGE
Definition: chan_skinny.c:935
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
static void transmit_activatecallplane(struct skinny_device *d, struct skinny_line *l)
Definition: chan_skinny.c:2437
#define ast_pthread_create(a, b, c, d)
Definition: utils.h:418
static int handle_capabilities_res_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:5510
#define SKINNY_MAX_CAPABILITIES
Definition: chan_skinny.c:309
#define STIMULUS_HOLD
Definition: chan_skinny.c:512
static struct ast_cli_entry cli_skinny[]
Definition: chan_skinny.c:3716
#define SKINNY_DEVICE_7912
Definition: chan_skinny.c:1084
#define KEYDEF_RINGOUT
Definition: chan_skinny.c:629
static struct skinny_subchannel * find_subchannel_by_reference(struct skinny_device *d, int reference)
Definition: chan_skinny.c:1680
#define CDEV
Definition: chan_skinny.c:6709
#define TIME_DATE_REQ_MESSAGE
Definition: chan_skinny.c:326
static void transmit_serverres(struct skinny_device *d)
Definition: chan_skinny.c:2564
#define AST_FORMAT_AUDIO_MASK
Definition: frame.h:274
#define SKINNY_DEVICE_7935
Definition: chan_skinny.c:1063
#define SPEED_DIAL_STAT_REQ_MESSAGE
Definition: chan_skinny.c:316
#define SKINNY_BUSYTONE
Definition: chan_skinny.c:1115
void ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address)
Get the address of the remote endpoint that we are sending RTP to.
Definition: rtp_engine.c:447
#define STIMULUS_TRANSFER
Definition: chan_skinny.c:513
int ast_str2cos(const char *value, unsigned int *cos)
Convert a string to the appropriate COS value.
Definition: acl.c:653
struct skinny_device * parent
Definition: chan_skinny.c:1302
static struct ast_format f[]
Definition: format_g726.c:181
#define SKINNY_DEVICE_UNKNOWN
Definition: chan_skinny.c:1053
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:786
const char * word
Definition: cli.h:157
char calledPartyVoiceMailbox[24]
Definition: chan_skinny.c:452
struct ast_rtp_instance * ast_rtp_instance_new(const char *engine_name, struct sched_context *sched, const struct ast_sockaddr *sa, void *data)
Create a new RTP instance.
Definition: rtp_engine.c:308
unsigned int flags
Combination of the AST_JB_ENABLED, AST_JB_FORCED and AST_JB_LOG flags.
Definition: abstract_jb.h:58
#define SKINNY_BUSY
Definition: chan_skinny.c:1103
struct clear_prompt_message clearpromptstatus
Definition: chan_skinny.c:987
int tm_hour
Definition: localtime.h:38
#define SKINNY_DEVICE_12SPPLUS
Definition: chan_skinny.c:1056
char lastRedirectingVoiceMailbox[24]
Definition: chan_skinny.c:454
#define SKINNY_DEVICE_CIPC
Definition: chan_skinny.c:1086
#define BT_VOICEMAIL
Definition: chan_skinny.c:537
#define OFFHOOK_MESSAGE
Definition: chan_skinny.c:287
uint32_t originalCalledPartyRedirectReason
Definition: chan_skinny.c:449
static const char type[]
Definition: chan_nbs.c:57
#define FORWARD_STAT_MESSAGE
Definition: chan_skinny.c:458
#define SKINNY_DEVICE_7961
Definition: chan_skinny.c:1087
format_t bits
Definition: frame.h:551
static void transmit_lamp_indication(struct skinny_device *d, int stimulus, int instance, int indication)
Definition: chan_skinny.c:2256
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:430
Structure used to handle boolean flags.
Definition: utils.h:200
static struct skinny_speeddial * find_speeddial_by_instance(struct skinny_device *d, int instance, int isHint)
Definition: chan_skinny.c:1704
static int get_devicestate(struct skinny_line *l)
Definition: chan_skinny.c:4234
int ast_rtp_instance_destroy(struct ast_rtp_instance *instance)
Destroy an RTP instance.
Definition: rtp_engine.c:301
#define SOFTKEY_MEETME
Definition: chan_skinny.c:649
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2631
#define SKINNY_DEVICE_7965
Definition: chan_skinny.c:1079
#define SKINNY_DEVICE_7902
Definition: chan_skinny.c:1085
void ast_jb_configure(struct ast_channel *chan, const struct ast_jb_conf *conf)
Configures a jitterbuffer on a channel.
Definition: abstract_jb.c:616
#define SKINNY_DEVICE_30VIP
Definition: chan_skinny.c:1059
int ast_sched_runq(struct sched_context *con)
Runs the queue.
Definition: sched.c:600
const char * usage
Definition: cli.h:171
static void transmit_speaker_mode(struct skinny_device *d, int mode)
Definition: chan_skinny.c:2146
static int callnums
Definition: chan_skinny.c:1051
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...
Definition: pbx.c:10546
static struct sockaddr_in bindaddr
Definition: chan_gtalk.c:225
uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
Get the value of an information element that has an integer payload.
Definition: event.c:1075
struct button_definition definition[42]
Definition: chan_skinny.c:555
struct ast_frame * ast_udptl_read(struct ast_udptl *udptl)
Definition: udptl.c:675
unsigned int tos_video
Definition: chan_skinny.c:169
#define STIMULUS_FORWARDBUSY
Definition: chan_skinny.c:515
int tm_sec
Definition: localtime.h:36
static int set_callforwards(struct skinny_line *l, const char *cfwd, int cfwdtype)
Definition: chan_skinny.c:1763
static char * handle_skinny_show_lines(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: chan_skinny.c:3482
static struct @101 qos
#define SKINNY_DEVICE_7941
Definition: chan_skinny.c:1065
#define EVENT_FLAG_REPORTING
Definition: manager.h:80
#define SKINNY_DEVICE_ATA186
Definition: chan_skinny.c:1064
#define CLI_SUCCESS
Definition: cli.h:43
static void transmit_clearpromptmessage(struct skinny_device *d, int instance, int callid)
Definition: chan_skinny.c:2363
static struct ast_jb_conf global_jbconf
Definition: chan_skinny.c:235
struct stop_tone_message stoptone
Definition: chan_skinny.c:990
#define SKINNY_DEVICE_7936
Definition: chan_skinny.c:1088
struct hostent * ast_gethostbyname(const char *host, struct ast_hostent *hp)
Thread-safe gethostbyname function to use in Asterisk.
Definition: utils.c:195
static void transmit_versionres(struct skinny_device *d)
Definition: chan_skinny.c:2554
skinny_codecs
Definition: chan_skinny.c:150
static void transmit_speeddialstatres(struct skinny_device *d, struct skinny_speeddial *sd)
Definition: chan_skinny.c:2505
struct soft_key_event_message softkeyeventmessage
Definition: chan_skinny.c:1017
#define BT_CUST_LINESPEEDDIAL
Definition: chan_skinny.c:548
static void print_codec_to_cli(int fd, struct ast_codec_pref *pref)
Print codec list from preference to CLI/manager.
Definition: chan_skinny.c:3123
#define SKINNY_CX_INACTIVE
Definition: chan_skinny.c:1143
static int skinny_hold(struct skinny_subchannel *sub)
Definition: chan_skinny.c:4625
#define STIMULUS_CONFERENCE
Definition: chan_skinny.c:522
#define SOFTKEY_ANSWER
Definition: chan_skinny.c:644
#define SKINNY_RING_INSIDE
Definition: chan_skinny.c:1128
struct sched_context * sched_context_create(void)
New schedule context.
Definition: sched.c:246
uint32_t space[2]
Definition: chan_skinny.c:389
#define STOP_MEDIA_TRANSMISSION_MESSAGE
Definition: chan_skinny.c:429
const uint8_t mode
Definition: chan_skinny.c:813
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:8691
Channels have this property if they can create jitter; i.e. most VoIP channels.
Definition: channel.h:888
static void mwi_event_cb(const struct ast_event *event, void *userdata)
Definition: chan_skinny.c:2730
unsigned int tos_audio
Definition: chan_mgcp.c:171
struct skinny_subchannel * related
Definition: chan_skinny.c:1198
Standard Command Line Interface.
#define SPEED_DIAL_STAT_RES_MESSAGE
Definition: chan_skinny.c:470
format_t readformat
Definition: channel.h:853
#define DISPLAY_PROMPT_STATUS_MESSAGE
Definition: chan_skinny.c:943
pthread_t t
Definition: chan_skinny.c:1365
uint32_t reference
Definition: chan_skinny.c:296
static int transmit_response(struct skinny_device *d, struct skinny_req *req)
Definition: chan_skinny.c:2105
#define ast_calloc(a, b)
Definition: astmm.h:82
static char * complete_skinny_show_line(const char *line, const char *word, int pos, int state)
Definition: chan_skinny.c:2968
struct ast_event_sub * ast_event_subscribe(enum ast_event_type event_type, ast_event_cb_t cb, const char *description, void *userdata,...)
Subscribe to events.
Definition: event.c:909
static const uint8_t soft_key_default_connwithtrans[]
Definition: chan_skinny.c:858
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
uint32_t alarmParam1
Definition: chan_skinny.c:335
static int get_input(struct skinnysession *s)
Definition: chan_skinny.c:6386
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
#define SOFT_KEY_TEMPLATE_RES_MESSAGE
Definition: chan_skinny.c:614
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
const int pos
Definition: cli.h:158
struct skinny_line::@104 sub
#define VERSION_RES_MESSAGE
Definition: chan_skinny.c:558
static void delete_devices(void)
Definition: chan_skinny.c:7366
unsigned int cos_video
Definition: chan_skinny.c:172
int ast_sched_wait(struct sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place Determine the number of s...
Definition: sched.c:334
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7119
#define AST_PTHREADT_STOP
Definition: lock.h:66
int ast_rtp_glue_unregister(struct ast_rtp_glue *glue)
Unregister RTP glue.
Definition: rtp_engine.c:266
struct start_media_transmission_message startmedia
Definition: chan_skinny.c:1010
int ast_queue_control_data(struct ast_channel *chan, enum ast_control_frame_type control, const void *data, size_t datalen)
Queue a control frame with payload.
Definition: channel.c:1608
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define SKINNY_RINGOUT
Definition: chan_skinny.c:1100
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
Execute the PBX in the current thread.
Definition: pbx.c:5926
char * ast_getformatname_multiple(char *buf, size_t size, format_t format)
Get the names of a set of formats.
Definition: frame.c:591
static const uint8_t soft_key_default_offhook[]
Definition: chan_skinny.c:850
static int skinnysock
Definition: chan_skinny.c:1049
Data structure associated with a single frame of data.
Definition: frame.h:142
#define SKINNY_DEVICE_7914
Definition: chan_skinny.c:1067
static void transmit_closereceivechannel(struct skinny_device *d, struct skinny_subchannel *sub)
Definition: chan_skinny.c:2393
#define KEYDEF_OFFHOOKWITHFEAT
Definition: chan_skinny.c:630
static int total
Definition: res_adsi.c:967
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context (or ANY context if NULL)
Definition: pbx.c:9875
static int keep_alive
Definition: chan_skinny.c:175
#define SKINNY_MAX_PACKET
Definition: chan_skinny.c:162
char type[10]
Definition: chan_skinny.c:1307
static int skinny_extensionstate_cb(char *context, char *exten, int state, void *data)
Definition: chan_skinny.c:2626
#define SOFTKEY_REDIAL
Definition: chan_skinny.c:634
int ast_playtones_start(struct ast_channel *chan, int vol, const char *tonelist, int interruptible)
Start playing a list of tones on a channel.
Definition: indications.c:319
#define ONHOOK_MESSAGE
Definition: chan_skinny.c:293
static int handle_ip_port_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:4900
static void transmit_stop_tone(struct skinny_device *d, int instance, int reference)
Definition: chan_skinny.c:2232
uint32_t callReference
Definition: chan_skinny.c:939
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:399
Channels have this property if they can accept input with jitter; i.e. most VoIP channels.
Definition: channel.h:883
const char * data
Description of a tone.
Definition: indications.h:53
#define SKINNY_DEVICE_7942
Definition: chan_skinny.c:1077
static int unload_module(void)
Definition: chan_skinny.c:7520
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:469
#define ast_sockaddr_to_sin(addr, sin)
Converts a struct ast_sockaddr to a struct sockaddr_in.
Definition: netsock2.h:629
enum queue_result id
Definition: app_queue.c:1090
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
enum ast_frame_type frametype
Definition: frame.h:144
#define SET_LAMP_MESSAGE
Definition: chan_skinny.c:392
#define SOFT_KEY_TEMPLATE_REQ_MESSAGE
Definition: chan_skinny.c:357
struct ast_variable * next
Definition: config.h:82
static void unregister_exten(struct skinny_line *l)
Definition: chan_skinny.c:1846
#define KEYDEF_CONNWITHTRANS
Definition: chan_skinny.c:626
static void transmit_callstate(struct skinny_device *d, int buttonInstance, unsigned callid, int state)
Definition: chan_skinny.c:2448
#define ast_mutex_init(pmutex)
Definition: lock.h:152
static struct io_context * io
Definition: chan_skinny.c:1157
#define AST_CLI_YESNO(x)
return Yes or No depending on the argument. This is used in many places in CLI command, having a function to generate this helps maintaining a consistent output (and possibly emitting the output in other languages, at some point).
Definition: cli.h:65
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:229
#define DISPLAYTEXT_MESSAGE
Definition: chan_skinny.c:563
#define STIMULUS_FORWARDNOANSWER
Definition: chan_skinny.c:516
static const uint8_t soft_key_default_offhookwithfeat[]
Definition: chan_skinny.c:881
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
static int handle_hold_button(struct skinny_subchannel *sub)
Definition: chan_skinny.c:4687
static int skinny_register(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:1870
#define CAPABILITIES_REQ_MESSAGE
Definition: chan_skinny.c:571
#define ast_mutex_destroy(a)
Definition: lock.h:154
static char version_id[16]
Definition: chan_skinny.c:183
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:7726
#define SKINNY_CX_SENDRECV
Definition: chan_skinny.c:1139
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Registers a state change callback.
Definition: pbx.c:5135
static struct ast_variable * add_var(const char *buf, struct ast_variable *list)
Definition: chan_skinny.c:1637
static unsigned int cos
Definition: chan_h323.c:147
#define SKINNY_DEVICE_7945
Definition: chan_skinny.c:1078
uint8_t softKeyTemplateIndex[16]
Definition: chan_skinny.c:915
#define STIMULUS_CALLPARK
Definition: chan_skinny.c:523
char originalCalledPartyVoiceMailbox[24]
Definition: chan_skinny.c:453
struct set_ringer_message setringer
Definition: chan_skinny.c:999
static const uint8_t soft_key_default_onhook[]
Definition: chan_skinny.c:818
#define REGISTER_MESSAGE
Definition: chan_skinny.c:255
uint32_t instance
Definition: chan_skinny.c:259
Say numbers and dates (maybe words one day too)
struct server_res_message serverres
Definition: chan_skinny.c:996
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:219
static int skinny_devicestate(void *data)
Definition: chan_skinny.c:6657
Pluggable RTP Architecture.
char callingPartyVoiceMailbox[24]
Definition: chan_skinny.c:451
struct onhook_message onhook
Definition: chan_skinny.c:1006
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:760
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:2130
Asterisk module definitions.
static struct hostent * hp
Definition: chan_skinny.c:1048
int amaflags
Definition: channel.h:843
struct capabilities_res_message caps
Definition: chan_skinny.c:982
#define STIMULUS_MESSAGE
Definition: chan_skinny.c:280
static snd_pcm_format_t format
Definition: chan_alsa.c:93
#define KEYDEF_RINGIN
Definition: chan_skinny.c:624
struct ast_channel_tech * tech
Definition: channel.h:743
#define SKINNY_LAMP_WINK
Definition: chan_skinny.c:1123
uint32_t space[3]
Definition: chan_skinny.c:455
#define CAPABILITIES_RES_MESSAGE
Definition: chan_skinny.c:299
long max_size
Max size of the jitterbuffer implementation.
Definition: abstract_jb.h:60
struct display_notify_message displaynotify
Definition: chan_skinny.c:1015
Persistant data storage (akin to *doze registry)
struct ast_event_sub * ast_event_unsubscribe(struct ast_event_sub *event_sub)
Un-subscribe from events.
Definition: event.c:987
ast_context: An extension context
Definition: pbx.c:955
struct reset_message reset
Definition: chan_skinny.c:997
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:247
#define TYPE_DEVICE
Definition: chan_skinny.c:6703
struct skinny_device::@109 lines
uint16_t softKeyInfoIndex[16]
Definition: chan_skinny.c:916
#define CLEAR_NOTIFY_MESSAGE
Definition: chan_skinny.c:568
General jitterbuffer configuration.
Definition: abstract_jb.h:55
static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
Definition: chan_skinny.c:3918
#define SOFTKEY_JOIN
Definition: chan_skinny.c:648
static void * skinny_session(void *data)
Definition: chan_skinny.c:6509
#define SOFT_KEY_SET_REQ_MESSAGE
Definition: chan_skinny.c:347
#define REGISTER_ACK_MESSAGE
Definition: chan_skinny.c:361
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: pbx.c:2971
#define DISPLAY_NOTIFY_MESSAGE
Definition: chan_skinny.c:958
#define BT_DISPLAY
Definition: chan_skinny.c:535
#define SKINNY_DEVICE_7910
Definition: chan_skinny.c:1060
char exten[AST_MAX_EXTENSION]
Definition: channel.h:869
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:526
#define SKINNY_DEVICE_7940
Definition: chan_skinny.c:1062
struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
Definition: config.c:278
#define SKINNY_DEVICE_7906
Definition: chan_skinny.c:1074
#define CALL_INFO_MESSAGE
Definition: chan_skinny.c:436
int tm_min
Definition: localtime.h:37
Structure for mutex and tracking information.
Definition: lock.h:121
#define SOFTKEY_IDIVERT
Definition: chan_skinny.c:653
int ast_parse_allow_disallow(struct ast_codec_pref *pref, format_t *mask, const char *list, int allowing)
Parse an &quot;allow&quot; or &quot;deny&quot; line in a channel or device configuration and update the capabilities mask...
Definition: frame.c:1272
uint32_t stimulusInstance
Definition: chan_skinny.c:395
static struct skinny_req * req_alloc(size_t size, int response_message)
Definition: chan_skinny.c:1552
#define BT_LINE
Definition: chan_skinny.c:536
int ast_manager_unregister(char *action)
Unregister a registered manager command.
Definition: manager.c:5355
jack_status_t status
Definition: app_jack.c:143
struct ast_frame * ast_rtp_instance_read(struct ast_rtp_instance *instance, int rtcp)
Receive a frame over RTP.
Definition: rtp_engine.c:379
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
Mailbox name.
Definition: event_defs.h:83
struct sockaddr_in addr
Definition: chan_skinny.c:1337
#define OPEN_RECEIVE_CHANNEL_ACK_MESSAGE
Definition: chan_skinny.c:339
#define ast_mutex_unlock(a)
Definition: lock.h:156
const uint8_t * defaults
Definition: chan_skinny.c:814
static void transmit_displaypromptstatus(struct skinny_device *d, const char *text, int t, int instance, int callid)
Definition: chan_skinny.c:2345
#define DEVICE2STR_BUFSIZE
Definition: chan_skinny.c:243
struct server_identifier server[5]
Definition: chan_skinny.c:584
static void transmit_softkeytemplateres(struct skinny_device *d)
Definition: chan_skinny.c:2610
enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
Bridge two channels that use RTP instances.
Definition: rtp_engine.c:1274
static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:5420
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager list transaction.
Definition: manager.c:2145
struct ast_module * ast_module_ref(struct ast_module *)
Definition: loader.c:1300
#define RESET_MESSAGE
Definition: chan_skinny.c:589
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:292
uint8_t buttonDefinition
Definition: chan_skinny.c:501
static int handle_keypad_button_message(struct skinny_req *req, struct skinnysession *s)
Definition: chan_skinny.c:4906
struct io_context * io_context_create(void)
Creates a context Create a context for I/O operations Basically mallocs an IO structure and sets up s...
Definition: io.c:76
static void transmit_ringer_mode(struct skinny_device *d, int mode)
Definition: chan_skinny.c:2269