Rework channel structure to eliminate "pvt" portion of channel (bug #3573)
[asterisk/asterisk.git] / channels / chan_skinny.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Implementation of the Skinny protocol
5  * 
6  * Copyright (C) 1999 - 2005 Digium, inc
7  *
8  * chan_skinny was developed by Jeremy McNamara & Florian Overkamp
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  *
13  */
14
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <asterisk/lock.h>
20 #include <asterisk/channel.h>
21 #include <asterisk/config.h>
22 #include <asterisk/logger.h>
23 #include <asterisk/module.h>
24 #include <asterisk/pbx.h>
25 #include <asterisk/options.h>
26 #include <asterisk/lock.h>
27 #include <asterisk/sched.h>
28 #include <asterisk/io.h>
29 #include <asterisk/rtp.h>
30 #include <asterisk/acl.h>
31 #include <asterisk/callerid.h>
32 #include <asterisk/cli.h>
33 #include <asterisk/say.h>
34 #include <asterisk/cdr.h>
35 #include <asterisk/astdb.h>
36 #include <asterisk/features.h>
37 #include <asterisk/app.h>
38 #include <asterisk/musiconhold.h>
39 #include <asterisk/utils.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <netinet/tcp.h>
43 #include <sys/ioctl.h>
44 #include <net/if.h>
45 #include <errno.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <netdb.h>
49 #include <arpa/inet.h>
50 #include <sys/signal.h>
51 #include <signal.h>
52 #include <asterisk/dsp.h>
53 #include <ctype.h>
54
55 /************************************************************************************/
56 /*                         Skinny/Asterisk Protocol Settings                        */
57 /************************************************************************************/
58 static const char desc[] = "Skinny Client Control Protocol (Skinny)";
59 static const char tdesc[] = "Skinny Client Control Protocol (Skinny)";
60 static const char type[] = "Skinny";
61 static const char config[] = "skinny.conf";
62
63 /* Just about everybody seems to support ulaw, so make it a nice default */
64 static int capability = AST_FORMAT_ULAW;
65
66 #define DEFAULT_SKINNY_PORT     2000
67 #define DEFAULT_SKINNY_BACKLOG  2
68 #define SKINNY_MAX_PACKET       1000
69
70 static int  keep_alive = 120;
71 static char date_format[6] = "D-M-Y";
72 static char version_id[16] = "P002F202";
73
74 /* these should be in an include file, but dunno what to include */
75 typedef unsigned char  UINT8;
76 typedef unsigned short UINT16;
77 typedef unsigned int   UINT32;
78
79 /************************************************************************************/
80 /*                                Protocol Messages                                 */
81 /************************************************************************************/
82 /* message types */
83 #define KEEP_ALIVE_MESSAGE 0x0000
84 /* no additional struct */
85
86 #define REGISTER_MESSAGE 0x0001
87 typedef struct register_message {
88         char name[16];
89         int userId;
90         int instance;
91         char ip[4];
92         int type;
93         int maxStreams;
94 } register_message;
95
96 #define IP_PORT_MESSAGE 0x0002
97
98 #define KEYPAD_BUTTON_MESSAGE 0x0003
99 typedef struct keypad_button_message {
100         int button;
101 } keypad_button_message;
102
103 #define STIMULUS_MESSAGE 0x0005
104 typedef struct stimulus_message {
105         int stimulus;
106         int stimulusInstance;
107 } stimulus_message;
108                 
109 #define OFFHOOK_MESSAGE 0x0006
110 #define ONHOOK_MESSAGE 0x0007
111
112 #define CAPABILITIES_RES_MESSAGE 0x0010
113 typedef struct station_capabilities {   
114         int codec;
115         int frames;
116         union {
117                 char res[8];
118                 long rate;
119         } payloads;     
120 } station_capabilities;
121
122 typedef struct capabilities_res_message {
123         int count;
124         struct station_capabilities caps[18];
125 } capabilities_res_message;
126
127 #define SPEED_DIAL_STAT_REQ_MESSAGE 0x000A
128 typedef struct speed_dial_stat_req_message {
129         int speedDialNumber;
130 } speed_dial_stat_req_message;
131
132 #define LINE_STATE_REQ_MESSAGE 0x000B
133 typedef struct line_state_req_message {
134         int lineNumber;
135 } line_state_req_message;
136
137 #define TIME_DATE_REQ_MESSAGE 0x000D
138 #define VERSION_REQ_MESSAGE 0x000F
139 #define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
140 #define SERVER_REQUEST_MESSAGE 0x0012
141 #define ALARM_MESSAGE 0x0020
142
143 #define OPEN_RECIEVE_CHANNEL_ACK_MESSAGE 0x0022 
144 typedef struct open_recieve_channel_ack_message {
145         int status;
146         char ipAddr[4];
147         int port;
148         int passThruId;
149 } open_recieve_channel_ack_message;
150
151 #define SOFT_KEY_SET_REQ_MESSAGE 0x0025
152 #define UNREGISTER_MESSAGE 0x0027
153 #define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028
154
155 #define REGISTER_ACK_MESSAGE 0x0081
156 typedef struct register_ack_message {
157         int keepAlive;
158         char dateTemplate[6];
159         char res[2];
160         int secondaryKeepAlive;
161         char res2[4];
162 } register_ack_message;
163
164 #define START_TONE_MESSAGE 0x0082
165 typedef struct start_tone_message {
166         int tone;
167 } start_tone_message;
168
169 #define STOP_TONE_MESSAGE 0x0083
170
171 #define SET_RINGER_MESSAGE 0x0085
172 typedef struct set_ringer_message {
173         int ringerMode;
174 } set_ringer_message;
175
176 #define SET_LAMP_MESSAGE 0x0086
177 typedef struct set_lamp_message {
178         int stimulus;
179         int stimulusInstance;
180         int deviceStimulus;
181 } set_lamp_message;
182
183 #define SET_SPEAKER_MESSAGE 0x0088 
184 typedef struct set_speaker_message {
185         int mode;
186 } set_speaker_message;
187
188 #define START_MEDIA_TRANSMISSION_MESSAGE 0x008A
189 typedef struct media_qualifier {
190         int precedence;
191         int vad;
192         int packets;
193         int bitRate;
194 } media_qualifier;
195
196 typedef struct start_media_transmission_message {
197         int conferenceId;
198         int passThruPartyId;
199         char remoteIp[4];
200         int remotePort;
201         int packetSize;
202         int payloadType;
203         media_qualifier qualifier;
204 } start_media_transmission_message;
205
206 #define STOP_MEDIA_TRANSMISSION_MESSAGE 0x008B
207 typedef struct stop_media_transmission_message {
208         int conferenceId;
209         int passThruPartyId;
210 } stop_media_transmission_message;
211
212 #define CALL_INFO_MESSAGE 0x008F
213 typedef struct call_info_message {
214         char callingPartyName[40];
215         char callingParty[24];
216         char calledPartyName[40];
217         char calledParty[24];
218         int  instance;
219         int  reference;
220         int  type;
221         char originalCalledPartyName[40];
222         char originalCalledParty[24];
223 } call_info_message;
224
225 #define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
226 typedef struct speed_dial_stat_res_message {
227         int speedDialNumber;
228         char speedDialDirNumber[24];
229         char speedDialDisplayName[40];
230 } speed_dial_stat_res_message;
231
232 #define LINE_STAT_RES_MESSAGE 0x0092
233 typedef struct line_stat_res_message {
234         int  linenumber;
235         char lineDirNumber[24];
236         char lineDisplayName[42];
237         int  space;
238 } line_stat_res_message;
239
240 #define DEFINETIMEDATE_MESSAGE 0x0094
241 typedef struct definetimedate_message {
242         int year;       /* since 1900 */
243         int month;
244         int dayofweek;  /* monday = 1 */
245         int day;
246         int hour;
247         int minute;
248         int seconds;
249         int milliseconds;
250         int timestamp;
251 } definetimedate_message;
252  
253 #define DISPLAYTEXT_MESSAGE 0x0099
254 typedef struct displaytext_message {
255         char text[40];
256 } displaytext_message;
257
258 #define CLEAR_DISPLAY_MESSAGE 0x009A
259
260 #define REGISTER_REJ_MESSAGE 0x009D
261 typedef struct register_rej_message {
262         char errMsg[33];
263 } register_rej_message;
264
265 #define CAPABILITIES_REQ_MESSAGE 0x009B
266
267 #define SERVER_RES_MESSAGE 0x009E
268 typedef struct server_identifier {
269         char serverName[48];
270 } server_identifier;
271
272 typedef struct server_res_message {
273         server_identifier server[5];
274         int serverListenPort[5];
275         int serverIpAddr[5];
276 } server_res_message;
277
278 #define BUTTON_TEMPLATE_RES_MESSAGE 0x0097
279 /* 
280    Define the template for a 30VIP phone, this is the older Selsius systems
281    model that has 30 buttons for your button-pushing enjoyment. Each 
282    softbutton defition goes by a 'index' of a button followed by that buttons
283    assignment for example "\x01\x09" means Line 1, while "\x02\x09" means Line 2
284    comments on what each assignment means is below 
285 */
286 static const char *thirtyvip_button_definition_hack = {
287         "\x01\x09"      /* Line 1 */
288         "\x02\x09"      /* Line 2 */
289         "\x03\x09"      /* Line 3 */
290         "\x04\x09"      /* Line 4 */
291         "\x01\x7e"
292         "\x01\x01"      /* Redial */
293         "\x00\xff"      
294         "\x01\x02"      /* Speeddial 1 */
295         "\x02\x02"      /* Speeddial 2 */
296         "\x03\x02"      /* Speeddial 3 */
297         "\x04\x02"      /* Speeddial 4 */
298         "\x05\x02"      /* Speeddial 5 */
299         "\x06\x02"      /* Speeddial 6 */
300         "\x01\x0f"      /* Voicemail */
301         "\x01\x05"      /* Forward all */
302         "\x01\x7d"      /* Conference */
303         "\x00\xff"
304         "\x00\xff"
305         "\x00\xff"
306         "\x00\xff"
307         "\x00\xff"
308         "\x07\x02"      /* Speeddial 7 */
309         "\x08\x02"      /* Speeddial 8 */
310         "\x09\x02"      /* Speeddial 9 */
311         "\x0A\x02"      /* Speeddial 10 */
312         "\x00\xff"
313         "\x00\xff"
314         "\x00\xff"
315         "\x00\xff"
316         "\x00\xff"
317         "\x00\xff"
318         "\x00\xff"
319         "\x00\xff"
320         "\x00\xff"
321         "\x00\xff"
322         "\x00\xff"
323         "\x00\xff"
324         "\x00\xff"
325         "\x00\xff"
326         "\x00\xff"
327         "\x00\xff"
328         "\x00\xff"
329 };
330
331 /* 
332    Now, define the buttons on the 12SP, you 79XX series folks, you get this 
333    too, as I don't know how the buttons are laid out, and I don't care as I 
334    don't have one. Code your own damn buttons or send me a 7960
335 */
336
337 static const char *twelvesp_button_definition_hack = {
338         "\x01\x09"      /* Line 1 */
339         "\x01\x09"      /* Line 2 */    
340         "\x01\x02"      /* Speeddial 1 */
341         "\x02\x02"      /* Speeddial 2 */
342         "\x03\x02"      /* Speeddial 3 */
343         "\x04\x02"      /* Speeddial 4 */
344         "\x01\x0f"      /* Voicemail */
345         "\x05\x02"      /* Speeddial 5 */
346         "\x06\x02"      /* Speeddial 6 */
347         "\x07\x02"      /* Speeddial 7 */
348         "\x08\x02"      /* Speeddial 8 */
349         "\x09\x02"      /* Speeddial 9 */
350         "\x00\xff"
351         "\x00\xff"
352         "\x00\xff"
353         "\x00\xff"
354         "\x00\xff"
355         "\x00\xff"
356         "\x00\xff"
357         "\x00\xff"
358         "\x00\xff"
359         "\x00\xff"
360         "\x00\xff"
361         "\x00\xff"
362         "\x00\xff"
363         "\x00\xff"
364         "\x00\xff"
365         "\x00\xff"
366         "\x00\xff"
367         "\x00\xff"
368         "\x00\xff"
369         "\x00\xff"
370         "\x00\xff"
371         "\x00\xff"
372         "\x00\xff"
373         "\x00\xff"
374         "\x00\xff"
375         "\x00\xff"
376         "\x00\xff"
377         "\x00\xff"
378         "\x00\xff"
379         "\x00\xff"
380 };
381
382 typedef struct buttondefinition {
383         UINT8 instanceNumber;
384         UINT8 buttonDefinition;
385 } button_definition;
386
387 typedef struct button_template_res_message {
388         UINT32 buttonOffset;
389         UINT32 buttonCount;
390         UINT32 totalButtonCount;
391         button_definition definition[42];
392 } button_template_res_message;
393
394 #define VERSION_RES_MESSAGE 0x0098
395 typedef struct version_res_message {
396         char version[16];
397 } version_res_message;
398
399 #define KEEP_ALIVE_ACK_MESSAGE 0x0100
400
401 #define OPEN_RECIEVE_CHANNEL_MESSAGE 0x0105
402 typedef struct open_recieve_channel_message {
403         int conferenceId;
404         int partyId;
405         int packets;
406         int capability;
407         int echo;
408         int bitrate;
409 } open_recieve_channel_message;
410
411 #define CLOSE_RECIEVE_CHANNEL_MESSAGE 0x0106
412 typedef struct close_recieve_channel_message {
413         int conferenceId;
414         int partyId;
415 } close_recieve_channel_message;
416
417 #define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108
418 static const char *soft_key_template_hack = {
419         "\x52\x65\x64\x69\x61\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
420         "\x01\x00\x00\x00\x4e\x65\x77\x43\x61\x6c\6c\\x00\x00\x00\x00\x00"
421         "\x00\x00\x00\x00\x02\x00\x00\x00\x48\x6f\x6c\x64\x00\x00\x00\x00"
422         "\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x54\x72\x6e\x73"
423         "\x66\x65\x72\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00"
424         "\x43\x46\x77\x64\x41\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05"
425         "\x00\x00\x00\x43\x46\x77\x64\x20\x42\x75\x73\x79\x00\x00\x00\x00"
426         "\x00\x00\x00\x06\x00\x00\x00\x43\x46\x77\x64\x4e\x6f\x41\x6e\x73"
427         "\x77\x65\x72\x00\x00\x00\x00\x07\x00\x00\x00\x3c\x3c\x00\x00\x00"
428         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x45"
429         "\x6e\x64\x43\x61\x6c\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09"
430         "\x00\x00\x00\x52\x65\x73\x75\x6d\x65\x00\x00\x00\x00\x00\x00\x00"
431         "\x00\x00\x0a\x00\x00\x00\x41\x6e\x73\x77\x65\x72\x00\x00\x00\x00"
432         "\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x49\x6e\x66\x6f\x00\x00"
433         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x43\x6f"
434         "\x6e\x66\x72\x6e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00"
435         "\x00\x50\x61\x72\x6b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
436         "\x00\x0e\x00\x00\x00\x4a\x6f\x69\x6e\x00\x00\x00\x00\x00\x00\x00"
437         "\x00\x00\x00\x00\x0f\x00\x00\x00\x4d\x65\x65\x74\x4d\x65\x00\x00"
438         "\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x50\x69\x63\x6b"
439         "\x55\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00"
440         "\x47\x50\x69\x63\x6b\x55\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00"
441         "\x12\x00\x00\x00\x52\x6d\x4c\x73\x43\x00\x00\x00\x00\x00\x00\x00"
442         "\x00\x00\x00\x13\x00\x00\x00\x42\x61\x72\x67\x65\x00\x00\x00\x00"
443         "\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x42\x61\x72\x67\x65"
444         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00"
445 };
446
447 typedef struct soft_key_template_definition {
448         char softKeyLabel[16];
449         int softKeyEvent;
450 } soft_key_template_definition;
451
452 typedef struct soft_key_template {
453         int softKeyOffset;
454         int softKeyCount;
455         int totalSoftKeyCount;
456     soft_key_template_definition softKeyTemplateDefinition[32];
457 } soft_key_template;
458
459 #define SOFT_KEY_SET_RES_MESSAGE 0x0109
460 static const char *soft_key_set_hack = {
461         "\x01\x02\x05\x03\x09\x0a\x0b\x10\x11\x12\x04\x0e\x0d\x00\x00\x00"
462         "\x2d\x01\x2e\x01\x31\x01\x2f\x01\x35\x01\x36\x01\x37\x01\x3c\x01"
463         "\x3d\x01\x3e\x01\x30\x01\x3a\x01\x39\x01\x00\x00\x00\x00\x00\x00"
464         "\x03\x09\x04\x0e\x0d\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
465         "\x2f\x01\x35\x01\x30\x01\x3a\x01\x39\x01\x3f\x01\x00\x00\x00\x00"
466         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
467         "\x0a\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
468         "\x36\x01\x2e\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
469         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
470         "\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
471         "\x37\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
472         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
473         "\x01\x09\x05\x10\x11\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
474         "\x2d\x01\x35\x01\x31\x01\x3c\x01\x3d\x01\x3e\x01\x00\x00\x00\x00"
475         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
476         "\x00\x09\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
477         "\x00\x00\x35\x01\x30\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
478         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
479         "\x08\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
480         "\x34\x01\x35\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
481         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
482         "\x00\x09\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
483         "\x00\x00\x35\x01\x39\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
484         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
485         "\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
486         "\x00\x00\x35\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
487         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
488         "\x01\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
489         "\x2d\x01\x35\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
490         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
491         "\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
492         "\x41\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
493         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
494 };
495
496 typedef struct soft_key_set_definition {
497         UINT8  softKeyTemplateIndex[16];
498         UINT16 softKeyInfoIndex[16];
499 } soft_key_set_definition;
500
501 typedef struct soft_key_sets {
502         UINT32 softKeySetOffset;
503         UINT32 softKeySetCount;
504         UINT32 totalSoftKeySetCount;
505         soft_key_set_definition softKeySetDefinition[16];
506         UINT32 res;
507 } soft_key_sets;
508
509 #define SELECT_SOFT_KEYS_MESSAGE 0x0110
510 typedef struct select_soft_keys_message {
511         int instance;
512         int reference;
513         int softKeySetIndex;
514         int validKeyMask;
515 } select_soft_keys_message;
516
517 #define CALL_STATE_MESSAGE 0x0111
518 typedef struct call_state_message {
519         int callState;
520         int lineInstance;
521         int callReference;
522 } call_state_message;
523
524 #define ACTIVATE_CALL_PLANE_MESSAGE 0x0116
525 typedef struct activate_call_plane_message {
526         int lineInstance;
527 } activate_call_plane_message;
528
529 /* packet composition */
530 typedef struct {
531         int len;
532         int res;
533         int e;
534         union {
535                 speed_dial_stat_req_message speeddialreq;
536                 register_message reg;
537                 register_ack_message regack;
538                 register_rej_message regrej;
539                 capabilities_res_message caps;
540                 version_res_message version;
541                 button_template_res_message buttontemplate;
542                 displaytext_message displaytext;
543                 definetimedate_message definetimedate;
544                 start_tone_message starttone;
545                 speed_dial_stat_res_message speeddial;
546                 line_state_req_message line;
547                 line_stat_res_message linestat;
548                 soft_key_sets softkeysets;
549                 soft_key_template softkeytemplate;
550                 server_res_message serverres;
551                 set_lamp_message setlamp;
552                 set_ringer_message setringer;
553                 call_state_message callstate;
554                 keypad_button_message keypad;
555                 select_soft_keys_message selectsoftkey;
556                 activate_call_plane_message activatecallplane;
557                 stimulus_message stimulus;
558                 set_speaker_message setspeaker;
559                 call_info_message callinfo;
560                 start_media_transmission_message startmedia;
561                 stop_media_transmission_message stopmedia;
562                 open_recieve_channel_message openrecievechannel;
563                 open_recieve_channel_ack_message openrecievechannelack;
564                 close_recieve_channel_message closerecievechannel;
565         } data;
566 } skinny_req;
567
568 /************************************************************************************/
569 /*                            Asterisk specific globals                             */
570 /************************************************************************************/
571
572 static int skinnydebug = 1;     /* XXX for now, enable debugging default */
573
574 /* a hostname, portnumber, socket and such is usefull for VoIP protocols */
575 static struct sockaddr_in bindaddr;
576 static char ourhost[256];
577 static int ourport;
578 static struct in_addr __ourip;
579 struct ast_hostent ahp; struct hostent *hp;
580 static int skinnysock  = -1;
581 static pthread_t tcp_thread;
582 static pthread_t accept_t;
583 static char context[AST_MAX_EXTENSION] = "default";
584 static char language[MAX_LANGUAGE] = "";
585 static char musicclass[MAX_LANGUAGE] = "";
586 static char cid_num[AST_MAX_EXTENSION] = "";
587 static char cid_name[AST_MAX_EXTENSION] = "";
588 static char linelabel[AST_MAX_EXTENSION] ="";
589 static int nat = 0;
590 static ast_group_t cur_callergroup = 0;
591 static ast_group_t cur_pickupgroup = 0;
592 static int immediate = 0;
593 static int callwaiting = 0;
594 static int callreturn = 0;
595 static int threewaycalling = 0;
596 /* This is for flashhook transfers */
597 static int transfer = 0;
598 static int cancallforward = 0;
599 /* static int busycount = 3;*/
600 static char accountcode[20] = "";
601 static char mailbox[AST_MAX_EXTENSION];
602 static int amaflags = 0;
603 static int callnums = 1;
604
605 #define SUB_REAL 0
606 #define SUB_ALT  1
607 #define MAX_SUBS 2
608
609 #define SKINNY_SPEAKERON 1
610 #define SKINNY_SPEAKEROFF 2
611
612 #define SKINNY_OFFHOOK 1
613 #define SKINNY_ONHOOK 2
614 #define SKINNY_RINGOUT 3
615 #define SKINNY_RINGIN 4
616 #define SKINNY_CONNECTED 5
617 #define SKINNY_BUSY 6
618 #define SKINNY_CONGESTION 7
619 #define SKINNY_HOLD 8
620 #define SKINNY_CALLWAIT 9
621 #define SKINNY_TRANSFER 10
622 #define SKINNY_PARK 11
623 #define SKINNY_PROGRESS 12
624 #define SKINNY_INVALID 14
625
626 #define SKINNY_SILENCE 0
627 #define SKINNY_DIALTONE 33
628 #define SKINNY_BUSYTONE 35
629 #define SKINNY_ALERT 36
630 #define SKINNY_REORDER 37
631 #define SKINNY_CALLWAITTONE 45
632
633 #define SKINNY_LAMP_OFF 1
634 #define SKINNY_LAMP_ON  2
635 #define SKINNY_LAMP_WINK 3
636 #define SKINNY_LAMP_FLASH 4
637 #define SKINNY_LAMP_BLINK 5
638
639 #define SKINNY_RING_OFF 1
640 #define SKINNY_RING_INSIDE 2
641 #define SKINNY_RING_OUTSIDE 3
642 #define SKINNY_RING_FEATURE 4
643
644 #define TYPE_TRUNK 1
645 #define TYPE_LINE 2
646
647 #define STIMULUS_REDIAL 1
648 #define STIMULUS_SPEEDDIAL 2
649 #define STIMULUS_HOLD 3
650 #define STIMULUS_TRANSFER 4
651 #define STIMULUS_FORWARDALL 5
652 #define STIMULUS_FORWARDBUSY 6
653 #define STIMULUS_FORWARDNOANSWER 7
654 #define STIMULUS_DISPLAY 8
655 #define STIMULUS_LINE 9
656 #define STIMULUS_VOICEMAIL 15
657 #define STIMULUS_AUTOANSWER 17
658 #define STIMULUS_CONFERENCE 125
659 #define STIMULUS_CALLPARK 126
660 #define STIMULUS_CALLPICKUP 127
661
662
663 /* Skinny rtp stream modes. Do we really need this? */
664 #define SKINNY_CX_SENDONLY 0
665 #define SKINNY_CX_RECVONLY 1
666 #define SKINNY_CX_SENDRECV 2
667 #define SKINNY_CX_CONF     3
668 #define SKINNY_CX_CONFERENCE 3
669 #define SKINNY_CX_MUTE     4
670 #define SKINNY_CX_INACTIVE 4
671
672 #if 0
673 static char *skinny_cxmodes[] = {
674     "sendonly",
675     "recvonly",
676     "sendrecv",
677     "confrnce",
678     "inactive"
679 };
680 #endif
681
682 /* driver scheduler */
683 static struct sched_context *sched;
684 static struct io_context *io;
685
686 /* usage count and locking */
687 static int usecnt = 0;
688 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
689
690 /* Protect the monitoring thread, so only one process can kill or start it, and not
691    when it's doing something critical. */
692 AST_MUTEX_DEFINE_STATIC(monlock);
693 /* Protect the network socket */
694 AST_MUTEX_DEFINE_STATIC(netlock);
695 /* Protect the session list */
696 AST_MUTEX_DEFINE_STATIC(sessionlock);
697 /* Protect the device list */
698 AST_MUTEX_DEFINE_STATIC(devicelock);
699
700 /* This is the thread for the monitor which checks for input on the channels
701    which are not currently in use.  */
702 static pthread_t monitor_thread = AST_PTHREADT_NULL;
703
704 /* Wait up to 16 seconds for first digit */
705 static int firstdigittimeout = 16000;
706
707 /* How long to wait for following digits */
708 static int gendigittimeout = 8000;
709
710 /* How long to wait for an extra digit, if there is an ambiguous match */
711 static int matchdigittimeout = 3000;
712
713 struct skinny_subchannel {
714         ast_mutex_t lock;
715         unsigned int callid;
716         struct ast_channel *owner;
717         struct skinny_line *parent;
718         struct ast_rtp *rtp;
719         time_t lastouttime;
720         int progress;
721         int ringing;
722         int lastout;
723         int cxmode;
724         int nat;
725         int outgoing;
726         int alreadygone;
727         struct skinny_subchannel *next; 
728 };
729
730 struct skinny_line {
731         ast_mutex_t lock;
732         char name[80];
733         char label[42];                                 /* Label that shows next to the line buttons */
734         struct skinny_subchannel *sub;                  /* pointer to our current connection, channel and stuff */
735         char accountcode[80];
736         char exten[AST_MAX_EXTENSION];                  /* Extention where to start */
737         char context[AST_MAX_EXTENSION];
738         char language[MAX_LANGUAGE];
739         char cid_num[AST_MAX_EXTENSION];                /* Caller*ID */
740         char cid_name[AST_MAX_EXTENSION];               /* Caller*ID */
741         char lastcallerid[AST_MAX_EXTENSION];           /* Last Caller*ID */
742         char call_forward[AST_MAX_EXTENSION];   
743         char mailbox[AST_MAX_EXTENSION];
744         char musicclass[MAX_LANGUAGE];
745         int curtone;                                    /* Current tone being played */
746         ast_group_t callgroup;
747         ast_group_t pickupgroup;
748         int callwaiting;
749         int transfer;
750         int threewaycalling;
751         int cancallforward;
752         int callreturn;
753         int dnd; /* How does this affect callwait?  Do we just deny a skinny_request if we're dnd? */
754         int hascallerid;
755         int hidecallerid;
756         int amaflags;
757         int type;
758         int instance;
759         int group;
760         int needdestroy;
761         int capability;
762         int nonCodecCapability;
763         int onhooktime;
764         int msgstate;           /* voicemail message state */
765         int immediate;
766         int hookstate;
767         int progress;
768         struct skinny_line *next;
769         struct skinny_device *parent;
770 };
771
772 static struct skinny_device {
773         /* A device containing one or more lines */
774         char name[80];
775         char id[16];
776         char version_id[16];    
777         int type;
778         int registered;
779         char model[6];
780         struct sockaddr_in addr;
781         struct in_addr ourip;
782         struct skinny_line *lines;
783         struct ast_ha *ha;
784         struct skinnysession *session;
785         struct skinny_device *next;
786 } *devices = NULL;
787
788 static struct skinnysession {
789         pthread_t t;
790         ast_mutex_t lock;
791         struct sockaddr_in sin;
792         int fd;
793         char inbuf[SKINNY_MAX_PACKET];
794         struct skinny_device *device;
795         struct skinnysession *next;
796 } *sessions = NULL;
797
798 static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause);
799 static int skinny_call(struct ast_channel *ast, char *dest, int timeout);
800 static int skinny_hangup(struct ast_channel *ast);
801 static int skinny_answer(struct ast_channel *ast);
802 static struct ast_frame *skinny_read(struct ast_channel *ast);
803 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame);
804 static int skinny_indicate(struct ast_channel *ast, int ind);
805 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
806 static int skinny_senddigit(struct ast_channel *ast, char digit);
807
808 static const struct ast_channel_tech skinny_tech = {
809         .type = type,
810         .description = tdesc,
811         .capabilities = AST_FORMAT_ULAW,
812         .requester = skinny_request,
813         .call = skinny_call,
814         .hangup = skinny_hangup,
815         .answer = skinny_answer,
816         .read = skinny_read,
817         .write = skinny_write,
818         .indicate = skinny_indicate,
819         .fixup = skinny_fixup,
820         .send_digit = skinny_senddigit,
821 /*      .bridge = ast_rtp_bridge, */
822 };
823
824 static skinny_req *req_alloc(size_t size)
825 {
826         skinny_req *req;
827         req = malloc(size+12);
828         if (!req) {
829                 return NULL;
830         }       
831         memset(req, 0, size+12);
832         return req;
833 }
834
835 static struct skinny_subchannel *find_subchannel_by_line(struct skinny_line *l)
836 {
837         /* XXX Need to figure out how to determine which sub we want */
838         struct skinny_subchannel *sub = l->sub;
839         return sub;
840 }
841
842 static struct skinny_subchannel *find_subchannel_by_name(char *dest)
843 {
844         struct skinny_line *l;
845         struct skinny_device *d;
846         char line[256];
847         char *at;
848         char *device;
849         
850         strncpy(line, dest, sizeof(line) - 1);
851         at = strchr(line, '@');
852         if (!at) {
853                 ast_log(LOG_NOTICE, "Device '%s' has no @ (at) sign!\n", dest);
854                 return NULL;
855         }
856         *at = '\0';
857         at++;
858         device = at;
859         ast_mutex_lock(&devicelock);
860         d = devices;
861         while(d) {
862                 if (!strcasecmp(d->name, device)) {
863                         if (skinnydebug) {
864                                 ast_verbose("Found device: %s\n", d->name);
865                         }
866                         /* Found the device */
867                         l = d->lines;
868                         while (l) {
869                                 /* Search for the right line */
870                                 if (!strcasecmp(l->name, line)) {
871                                         ast_mutex_unlock(&devicelock);
872                                         return l->sub;
873                                 }
874                                 l = l->next;
875                         }
876                 }
877                 d = d->next;
878         }
879         /* Device not found*/
880         ast_mutex_unlock(&devicelock);
881         return NULL;
882 }
883
884 static int transmit_response(struct skinnysession *s, skinny_req *req)
885 {
886         int res = 0;
887         ast_mutex_lock(&s->lock);
888 #if 0
889         ast_verbose("writing packet type %d (%d bytes) to socket %d\n", req->e, req->len+8, s->fd);
890 #endif
891         res = write(s->fd, req, req->len+8);
892         if (res != req->len+8) {
893                 ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, req->len+8, strerror(errno));
894         }
895         ast_mutex_unlock(&s->lock);
896         return 1;
897 }
898
899 /* XXX Do this right */
900 static int convert_cap(int capability)
901 {
902         return 4; /* ulaw (this is not the same as asterisk's '4'  */
903
904 }
905
906 static void transmit_speaker_mode(struct skinnysession *s, int mode)
907 {
908         skinny_req *req;
909
910         req = req_alloc(sizeof(struct set_speaker_message));
911         if (!req) {
912                 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
913                 return;
914         }
915         req->len = sizeof(set_speaker_message)+4;
916         req->e = SET_SPEAKER_MESSAGE;
917         req->data.setspeaker.mode = mode; 
918         transmit_response(s, req);
919 }
920
921 static void transmit_callstate(struct skinnysession *s, int instance, int state, unsigned callid)
922
923         skinny_req *req;
924         int memsize = sizeof(struct call_state_message);
925
926         req = req_alloc(memsize);
927         if (!req) {
928                 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
929                 return;
930         }       
931         if (state == SKINNY_ONHOOK) {
932                 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
933         }
934         req->len = sizeof(call_state_message)+4;
935         req->e = CALL_STATE_MESSAGE;
936         req->data.callstate.callState = state;
937         req->data.callstate.lineInstance = instance;
938         req->data.callstate.callReference = callid;
939         transmit_response(s, req);
940         if (state == SKINNY_OFFHOOK) {
941                 memset(req, 0, memsize);
942                 req->len = sizeof(activate_call_plane_message)+4;
943                 req->e = ACTIVATE_CALL_PLANE_MESSAGE;
944                 req->data.activatecallplane.lineInstance = instance;
945                 transmit_response(s, req);
946         } else if (state == SKINNY_ONHOOK) {
947                 memset(req, 0, memsize);
948                 req->len = sizeof(activate_call_plane_message)+4;
949                 req->e = ACTIVATE_CALL_PLANE_MESSAGE;
950                 req->data.activatecallplane.lineInstance = 0;
951                 transmit_response(s, req);
952                 memset(req, 0, memsize);
953                 req->len = sizeof(close_recieve_channel_message)+4;
954                 req->e = CLOSE_RECIEVE_CHANNEL_MESSAGE;
955                 req->data.closerecievechannel.conferenceId = 0;
956                 req->data.closerecievechannel.partyId = 0;
957                 transmit_response(s, req);
958                 memset(req, 0, memsize);
959                 req->len = sizeof(stop_media_transmission_message)+4;
960                 req->e = STOP_MEDIA_TRANSMISSION_MESSAGE;
961                 req->data.stopmedia.conferenceId = 0;   
962                 req->data.stopmedia.passThruPartyId = 0;
963                 transmit_response(s, req);      
964         }
965 }       
966
967 static void transmit_connect(struct skinnysession *s)
968 {
969         skinny_req *req;
970         struct skinny_line *l = s->device->lines;
971
972         req = req_alloc(sizeof(struct open_recieve_channel_message));
973         if (!req) {
974                 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
975                 return;
976         }       
977         req->len = sizeof(struct call_info_message);
978         req->e = OPEN_RECIEVE_CHANNEL_MESSAGE;
979         req->data.openrecievechannel.conferenceId = 0;
980         req->data.openrecievechannel.partyId = 0;
981         req->data.openrecievechannel.packets = 20;
982         req->data.openrecievechannel.capability = convert_cap(l->capability); 
983         req->data.openrecievechannel.echo = 0;
984         req->data.openrecievechannel.bitrate = 0;
985         transmit_response(s, req);
986 }       
987
988 static void transmit_tone(struct skinnysession *s, int tone)
989 {
990         skinny_req *req;
991
992         if (tone > 0)
993                 req = req_alloc(sizeof(struct start_tone_message));
994         else 
995                 req = req_alloc(4);
996         if (!req) {
997                 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
998                 return;
999         }       
1000         if (tone > 0) {
1001                 req->len = sizeof(start_tone_message)+4;
1002                 req->e = START_TONE_MESSAGE;
1003                 req->data.starttone.tone = tone; 
1004         } else {
1005                 req->len = 4;
1006                 req->e = STOP_TONE_MESSAGE;
1007         }
1008         transmit_response(s, req);
1009 }
1010
1011 #if 0
1012 /* XXX need to properly deal with softkeys */
1013 static void transmit_selectsoftkeys(struct skinnysession *s, int instance, int callid, int softkey)
1014 {
1015         skinny_req *req;
1016         int memsize = sizeof(struct select_soft_keys_message);
1017
1018         req = req_alloc(memsize);
1019         if (!req) {
1020                 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1021                 return;
1022         }       
1023         memset(req, 0, memsize);
1024         req->len = sizeof(select_soft_keys_message)+4;
1025         req->e = SELECT_SOFT_KEYS_MESSAGE;
1026         req->data.selectsoftkey.instance = instance;
1027         req->data.selectsoftkey.reference = callid;
1028         req->data.selectsoftkey.softKeySetIndex = softkey;
1029         transmit_response(s, req);
1030 }
1031 #endif
1032
1033 static void transmit_lamp_indication(struct skinnysession *s, int stimulus, int instance, int indication)
1034 {
1035         skinny_req *req;
1036
1037         req = req_alloc(sizeof(struct set_lamp_message));
1038         if (!req) {
1039                 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1040                 return;
1041         }       
1042         req->len = sizeof(set_lamp_message)+4;
1043         req->e = SET_LAMP_MESSAGE;
1044         req->data.setlamp.stimulus = stimulus;
1045         req->data.setlamp.stimulusInstance = instance;
1046         req->data.setlamp.deviceStimulus = indication;
1047         transmit_response(s, req);
1048 }
1049
1050 static void transmit_ringer_mode(struct skinnysession *s, int mode)
1051 {
1052         skinny_req *req;
1053
1054         req = req_alloc(sizeof(struct set_ringer_message));
1055         if (!req) {
1056                 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1057                 return;
1058         }
1059         req->len = sizeof(set_ringer_message)+4;
1060         req->e = SET_RINGER_MESSAGE; 
1061         req->data.setringer.ringerMode = mode; 
1062         transmit_response(s, req);
1063 }
1064
1065 static void transmit_displaymessage(struct skinnysession *s, char *text)
1066 {
1067         skinny_req *req;
1068
1069         if (text == 0) {
1070                 req = req_alloc(4);
1071                 req->len = 4;
1072                 req->e = CLEAR_DISPLAY_MESSAGE;
1073         } else {
1074                 req = req_alloc(sizeof(struct displaytext_message));
1075
1076                 strncpy(req->data.displaytext.text, text, sizeof(req->data.displaytext.text)-1);
1077                 req->len = sizeof(displaytext_message) + 4;
1078                 req->e = DISPLAYTEXT_MESSAGE;
1079                 if (skinnydebug) {
1080                         ast_verbose("Displaying message '%s'\n", req->data.displaytext.text);
1081                 }
1082         }
1083
1084         if (!req) {
1085                 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1086                 return;
1087         }
1088         transmit_response(s, req);
1089 }
1090
1091 static int has_voicemail(struct skinny_line *l)
1092 {
1093         return ast_app_has_voicemail(l->mailbox, NULL);
1094 }
1095
1096
1097 static void do_housekeeping(struct skinnysession *s)
1098 {
1099         struct skinny_subchannel *sub;
1100
1101         sub = find_subchannel_by_line(s->device->lines);
1102         transmit_displaymessage(s, 0);
1103
1104         if (skinnydebug) {
1105                 ast_verbose("Checking for voicemail Skinny %s@%s\n", sub->parent->name, sub->parent->parent->name);
1106         }
1107         if (has_voicemail(sub->parent)) {
1108                 int new;
1109                 int old;
1110                 ast_app_messagecount(sub->parent->mailbox, &new, &old);
1111                 if (skinnydebug) {
1112                         ast_verbose("Skinny %s@%s has voicemail! Yay!\n", sub->parent->name, sub->parent->parent->name);
1113                 }
1114                 transmit_lamp_indication(s, STIMULUS_VOICEMAIL, s->device->lines->instance, SKINNY_LAMP_BLINK);
1115         } else {
1116                 transmit_lamp_indication(s, STIMULUS_VOICEMAIL, s->device->lines->instance, SKINNY_LAMP_OFF);
1117         }
1118
1119 }
1120
1121 /* I do not believe skinny can deal with video. 
1122    Anyone know differently? */
1123 static struct ast_rtp *skinny_get_vrtp_peer(struct ast_channel *chan)
1124 {
1125         return NULL;
1126 }
1127
1128 static struct ast_rtp *skinny_get_rtp_peer(struct ast_channel *chan)
1129 {
1130         struct skinny_subchannel *sub;
1131         sub = chan->tech_pvt;
1132         if (sub && sub->rtp)
1133                 return sub->rtp;
1134         return NULL;
1135 }
1136
1137 static int skinny_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs)
1138 {
1139         struct skinny_subchannel *sub;
1140         sub = chan->tech_pvt;
1141         if (sub) {
1142                 /* transmit_modify_with_sdp(sub, rtp); @@FIXME@@ if needed */
1143                 return 0;
1144         }
1145         return -1;
1146 }
1147
1148 static struct ast_rtp_protocol skinny_rtp = {
1149         .type = type,
1150         .get_rtp_info = skinny_get_rtp_peer,
1151         .get_vrtp_info =  skinny_get_vrtp_peer,
1152         .set_rtp_peer = skinny_set_rtp_peer,
1153 };
1154
1155 static int skinny_do_debug(int fd, int argc, char *argv[])
1156 {
1157         if (argc != 2)
1158                 return RESULT_SHOWUSAGE;
1159         skinnydebug = 1;
1160         ast_cli(fd, "Skinny Debugging Enabled\n");
1161         return RESULT_SUCCESS;
1162 }
1163
1164 static int skinny_no_debug(int fd, int argc, char *argv[])
1165 {
1166         if (argc != 3)
1167                 return RESULT_SHOWUSAGE;
1168         skinnydebug = 0;
1169         ast_cli(fd, "Skinny Debugging Disabled\n");
1170         return RESULT_SUCCESS;
1171 }
1172
1173 static int skinny_show_lines(int fd, int argc, char *argv[])
1174 {
1175         struct skinny_device  *d;
1176         struct skinny_line *l;
1177         int haslines = 0;
1178         char iabuf[INET_ADDRSTRLEN];
1179         if (argc != 3) 
1180                 return RESULT_SHOWUSAGE;
1181         ast_mutex_lock(&devicelock);
1182         d = devices;
1183         while(d) {
1184                 l = d->lines;
1185                 ast_cli(fd, "Device '%s' at %s\n", d->name, ast_inet_ntoa(iabuf, sizeof(iabuf), d->addr.sin_addr));
1186                 while(l) {
1187                         ast_cli(fd, "   -- '%s@%s in '%s' is %s\n", l->name, d->name, l->context, l->sub->owner ? "active" : "idle");
1188                         haslines = 1;
1189                         l = l->next;
1190                 }
1191                 if (!haslines) {
1192                         ast_cli(fd, "   << No Lines Defined >>     ");
1193                 }
1194                 d = d->next;
1195         }
1196         ast_mutex_unlock(&devicelock);
1197         return RESULT_SUCCESS;
1198 }
1199
1200 static char show_lines_usage[] = 
1201 "Usage: skinny show lines\n"
1202 "       Lists all lines known to the Skinny subsystem.\n";
1203
1204 static char debug_usage[] = 
1205 "Usage: skinny debug\n"
1206 "       Enables dumping of Skinny packets for debugging purposes\n";
1207
1208 static char no_debug_usage[] = 
1209 "Usage: skinny no debug\n"
1210 "       Disables dumping of Skinny packets for debugging purposes\n";
1211
1212 static struct ast_cli_entry  cli_show_lines =
1213         { { "skinny", "show", "lines", NULL }, skinny_show_lines, "Show defined Skinny lines per device", show_lines_usage };
1214 static struct ast_cli_entry  cli_debug =
1215         { { "skinny", "debug", NULL }, skinny_do_debug, "Enable Skinny debugging", debug_usage };
1216 static struct ast_cli_entry  cli_no_debug =
1217         { { "skinny", "no", "debug", NULL }, skinny_no_debug, "Disable Skinny debugging", no_debug_usage };
1218
1219 static struct skinny_device *build_device(char *cat, struct ast_variable *v)
1220 {
1221         struct skinny_device *d;
1222         struct skinny_line *l;
1223         struct skinny_subchannel *sub;
1224         int i=0, y=0;
1225         
1226         d = malloc(sizeof(struct skinny_device));
1227         if (d) {
1228                 memset(d, 0, sizeof(struct skinny_device));
1229                 strncpy(d->name, cat, sizeof(d->name) - 1);
1230                 while(v) {
1231                         if (!strcasecmp(v->name, "host")) {
1232                                         if (ast_get_ip(&d->addr, v->value)) {
1233                                                 free(d);
1234                                                 return NULL;
1235                                         }                               
1236                         } else if (!strcasecmp(v->name, "port")) {
1237                                 d->addr.sin_port = htons(atoi(v->value));
1238                         } else if (!strcasecmp(v->name, "device")) {
1239                         strncpy(d->id, v->value, sizeof(d->id)-1);
1240                         } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
1241                                 d->ha = ast_append_ha(v->name, v->value, d->ha);
1242                         } else if (!strcasecmp(v->name, "context")) {
1243                                 strncpy(context, v->value, sizeof(context) - 1);
1244                         } else if (!strcasecmp(v->name, "version")) {
1245                                 strncpy(d->version_id, v->value, sizeof(d->version_id) -1); 
1246                         } else if (!strcasecmp(v->name, "nat")) {
1247                                 nat = ast_true(v->value);
1248                 } else if (!strcasecmp(v->name, "model")) {
1249                                 strncpy(d->model, v->value, sizeof(d->model) - 1);
1250                         } else if (!strcasecmp(v->name, "callerid")) {
1251                                 if (!strcasecmp(v->value, "asreceived")) {
1252                                         cid_num[0] = '\0';
1253                                         cid_name[0] = '\0';
1254                                 } else {
1255                                         ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
1256                                 }
1257                         } else if (!strcasecmp(v->name, "language")) {
1258                                 strncpy(language, v->value, sizeof(language)-1);
1259                         } else if (!strcasecmp(v->name, "accountcode")) {
1260                                 strncpy(accountcode, v->value, sizeof(accountcode)-1);
1261                         } else if (!strcasecmp(v->name, "amaflags")) {
1262                                 y = ast_cdr_amaflags2int(v->value);
1263                                 if (y < 0) {
1264                                         ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
1265                                 } else {
1266                                 amaflags = y;
1267                                 }
1268                         } else if (!strcasecmp(v->name, "musiconhold")) {
1269                                 strncpy(musicclass, v->value, sizeof(musicclass)-1);
1270                         } else if (!strcasecmp(v->name, "callgroup")) {
1271                                 cur_callergroup = ast_get_group(v->value);
1272                         } else if (!strcasecmp(v->name, "pickupgroup")) {
1273                                 cur_pickupgroup = ast_get_group(v->value);
1274                         } else if (!strcasecmp(v->name, "immediate")) {
1275                                 immediate = ast_true(v->value);
1276                         } else if (!strcasecmp(v->name, "cancallforward")) {
1277                                 cancallforward = ast_true(v->value);
1278                         } else if (!strcasecmp(v->name, "mailbox")) {
1279                                 strncpy(mailbox, v->value, sizeof(mailbox) -1);
1280                         } else if (!strcasecmp(v->name, "callreturn")) {
1281                                 callreturn = ast_true(v->value);
1282                         } else if (!strcasecmp(v->name, "immediate")) {
1283                                 immediate = ast_true(v->value);
1284                         } else if (!strcasecmp(v->name, "callwaiting")) {
1285                                 callwaiting = ast_true(v->value);
1286                         } else if (!strcasecmp(v->name, "transfer")) {
1287                                 transfer = ast_true(v->value);
1288                         } else if (!strcasecmp(v->name, "threewaycalling")) {
1289                                 threewaycalling = ast_true(v->value);
1290                         } else if (!strcasecmp(v->name, "linelabel")) {
1291                                 strncpy(linelabel, v->value, sizeof(linelabel)-1);
1292                         } else if (!strcasecmp(v->name, "trunk") || !strcasecmp(v->name, "line")) {
1293                                 l = malloc(sizeof(struct skinny_line));;
1294                                 if (l) {
1295                                         memset(l, 0, sizeof(struct skinny_line));
1296                                         ast_mutex_init(&l->lock);
1297                                         strncpy(l->name, v->value, sizeof(l->name) - 1);
1298                                         
1299                                         /* XXX Should we check for uniqueness?? XXX */
1300
1301                                         strncpy(l->context, context, sizeof(l->context) - 1);
1302                                         strncpy(l->cid_num, cid_num, sizeof(l->cid_num) - 1);
1303                                         strncpy(l->cid_name, cid_name, sizeof(l->cid_name) - 1);
1304                                         strncpy(l->label, linelabel, sizeof(l->label) - 1);
1305                                         strncpy(l->language, language, sizeof(l->language) - 1);
1306                                         strncpy(l->musicclass, musicclass, sizeof(l->musicclass)-1);
1307                                         strncpy(l->mailbox, mailbox, sizeof(l->mailbox)-1);
1308                                         strncpy(l->mailbox, mailbox, sizeof(l->mailbox)-1);
1309                                         if (!ast_strlen_zero(mailbox)) {
1310                                                 ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, d->name, l->name);
1311                                         }
1312                                 
1313                                         l->msgstate = -1;
1314                                         l->capability = capability;
1315                                         l->parent = d;
1316                                         if (!strcasecmp(v->name, "trunk")) {
1317                                                 l->type = TYPE_TRUNK;
1318                                         } else {
1319                                                 l->type = TYPE_LINE;
1320                                         }
1321                                         l->immediate = immediate;
1322                                         l->callgroup = cur_callergroup;
1323                                         l->pickupgroup = cur_pickupgroup;
1324                                         l->callreturn = callreturn;
1325                                         l->cancallforward = cancallforward;
1326                                         l->callwaiting = callwaiting;
1327                                         l->transfer = transfer; 
1328                                         l->threewaycalling = threewaycalling;
1329                                         l->onhooktime = time(NULL);
1330                                         l->instance = 1;
1331                                         /* ASSUME we're onhook at this point*/
1332                                         l->hookstate = SKINNY_ONHOOK;
1333
1334                                         for (i = 0; i < MAX_SUBS; i++) {
1335                                                 sub = malloc(sizeof(struct skinny_subchannel));
1336                                                 if (sub) {
1337                                                         ast_verbose(VERBOSE_PREFIX_3 "Allocating Skinny subchannel '%d' on %s@%s\n", i, l->name, d->name);
1338                                                         memset(sub, 0, sizeof(struct skinny_subchannel));
1339                                                         ast_mutex_init(&sub->lock);
1340                                                         sub->parent = l;
1341                                                         /* Make a call*ID */
1342                                                         sub->callid = callnums;
1343                                                         callnums++;
1344                                                         sub->cxmode = SKINNY_CX_INACTIVE;
1345                                                         sub->nat = nat;
1346                                                         sub->next = l->sub;
1347                                                         l->sub = sub;
1348                                                 } else {
1349                                                         /* XXX Should find a way to clean up our memory */
1350                                                         ast_log(LOG_WARNING, "Out of memory allocating subchannel");
1351                                                         return NULL;
1352                                                 }
1353                                         }
1354                                         l->next = d->lines;
1355                                         d->lines = l;                   
1356                                 } else {
1357                                         /* XXX Should find a way to clean up our memory */
1358                                         ast_log(LOG_WARNING, "Out of memory allocating line");
1359                                         return NULL;
1360                                 }
1361                         } else {
1362                                 ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
1363                         }
1364                         v = v->next;
1365                 }
1366         
1367                 if (!d->lines) {
1368                         ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n");
1369                         return NULL;
1370                 }
1371
1372                 if (d->addr.sin_addr.s_addr && !ntohs(d->addr.sin_port))
1373                         d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
1374                 if (d->addr.sin_addr.s_addr) {
1375                         if (ast_ouraddrfor(&d->addr.sin_addr, &d->ourip)) {
1376                                 memcpy(&d->ourip, &__ourip, sizeof(d->ourip));
1377                         }
1378                 } else {
1379                         memcpy(&d->ourip, &__ourip, sizeof(d->ourip));
1380                 }
1381         }
1382         return d;
1383 }
1384
1385 static int skinny_register(skinny_req *req, struct skinnysession *s)
1386 {
1387         struct skinny_device *d;
1388         
1389         ast_mutex_lock(&devicelock);
1390         d = devices;
1391         while (d) {
1392                 if (!strcasecmp(req->data.reg.name, d->id)) {
1393                         /* XXX Deal with IP authentication */
1394                         s->device = d;
1395                         d->type = req->data.reg.type;
1396                         if (ast_strlen_zero(d->version_id)) {
1397                                 strncpy(d->version_id, version_id, sizeof(d->version_id) - 1);
1398                         }
1399                         d->registered = 1;
1400                         d->session = s;
1401                         break;
1402                 }
1403                 d = d->next;
1404         }
1405         ast_mutex_unlock(&devicelock);
1406
1407         if (!d)
1408                 return 0;
1409         
1410         return 1;
1411 }               
1412
1413 static void start_rtp(struct skinny_subchannel *sub)
1414 {
1415                 ast_mutex_lock(&sub->lock);
1416                 /* Allocate the RTP */
1417                 sub->rtp = ast_rtp_new(sched, io, 1, 0);
1418                 if (sub->rtp && sub->owner)
1419                         sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
1420                 if (sub->rtp)
1421                         ast_rtp_setnat(sub->rtp, sub->nat);
1422                 
1423                 /* Create the RTP connection */
1424                 transmit_connect(sub->parent->parent->session);
1425                 ast_mutex_unlock(&sub->lock);
1426 }
1427
1428
1429 static void *skinny_ss(void *data)
1430 {
1431         struct ast_channel *chan = data;
1432         struct skinny_subchannel *sub = chan->tech_pvt;
1433         struct skinny_line *l = sub->parent;
1434         struct skinnysession *s = l->parent->session;
1435         char exten[AST_MAX_EXTENSION] = "";
1436         int len = 0;
1437         int timeout = firstdigittimeout;
1438         int res;
1439         int getforward=0;
1440     
1441         if (option_verbose > 2) {
1442                 ast_verbose( VERBOSE_PREFIX_3 "Starting simple switch on '%s@%s'\n", l->name, l->parent->name);
1443         }
1444         while(len < AST_MAX_EXTENSION-1) {
1445         res = ast_waitfordigit(chan, timeout);
1446         timeout = 0;
1447         if (res < 0) {
1448                 if (skinnydebug) {
1449                         ast_verbose("Skinny(%s@%s): waitfordigit returned < 0\n", l->name, l->parent->name);
1450                 }
1451                 ast_indicate(chan, -1);
1452                 ast_hangup(chan);
1453                 return NULL;
1454         } else if (res)  {
1455             exten[len++]=res;
1456             exten[len] = '\0';
1457         }
1458         if (!ast_ignore_pattern(chan->context, exten)) {
1459                         transmit_tone(s, SKINNY_SILENCE);
1460         } 
1461         if (ast_exists_extension(chan, chan->context, exten, 1, l->cid_num)) {
1462             if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, l->cid_num)) {
1463                 if (getforward) {
1464                     /* Record this as the forwarding extension */
1465                     strncpy(l->call_forward, exten, sizeof(l->call_forward) - 1); 
1466                     if (option_verbose > 2) {
1467                         ast_verbose(VERBOSE_PREFIX_3 "Setting call forward to '%s' on channel %s\n", 
1468                                 l->call_forward, chan->name);
1469                     }
1470                     transmit_tone(s, SKINNY_DIALTONE); 
1471                     if (res) {
1472                             break;
1473                     }
1474                     usleep(500000);
1475                     ast_indicate(chan, -1);
1476                     sleep(1);
1477                     memset(exten, 0, sizeof(exten));
1478                     transmit_tone(s, SKINNY_DIALTONE); 
1479                     len = 0;
1480                     getforward = 0;
1481                 } else  {
1482                     strncpy(chan->exten, exten, sizeof(chan->exten)-1);
1483                     if (!ast_strlen_zero(l->cid_num)) {
1484                         if (!l->hidecallerid)
1485                             chan->cid.cid_num = strdup(l->cid_num);
1486                         chan->cid.cid_ani = strdup(l->cid_num);
1487                     }
1488                     ast_setstate(chan, AST_STATE_RING);
1489                     res = ast_pbx_run(chan);
1490                     if (res) {
1491                         ast_log(LOG_WARNING, "PBX exited non-zero\n");
1492                                                 transmit_tone(s, SKINNY_REORDER); 
1493                     }
1494                     return NULL;
1495                 }
1496             } else {
1497                 /* It's a match, but they just typed a digit, and there is an ambiguous match,
1498                    so just set the timeout to matchdigittimeout and wait some more */
1499                 timeout = matchdigittimeout;
1500             }
1501         } else if (res == 0) {
1502             ast_log(LOG_DEBUG, "Not enough digits (and no ambiguous match)...\n");
1503                 transmit_tone(s, SKINNY_REORDER); 
1504             ast_hangup(chan);
1505             return NULL;
1506         } else if (l->callwaiting && !strcmp(exten, "*70")) {
1507             if (option_verbose > 2) {
1508                 ast_verbose(VERBOSE_PREFIX_3 "Disabling call waiting on %s\n", chan->name);
1509             }
1510             /* Disable call waiting if enabled */
1511             l->callwaiting = 0;
1512             transmit_tone(s, SKINNY_DIALTONE);
1513                         len = 0;
1514             memset(exten, 0, sizeof(exten));
1515             timeout = firstdigittimeout;
1516                 
1517         } else if (!strcmp(exten,ast_pickup_ext())) {
1518             /* Scan all channels and see if any there
1519              * ringing channqels with that have call groups
1520              * that equal this channels pickup group  
1521              */
1522             if (ast_pickup_call(chan)) {
1523                 ast_log(LOG_WARNING, "No call pickup possible...\n");
1524                                 transmit_tone(s, SKINNY_REORDER);
1525             }
1526             ast_hangup(chan);
1527             return NULL;
1528             
1529         } else if (!l->hidecallerid && !strcmp(exten, "*67")) {
1530             if (option_verbose > 2) {
1531                 ast_verbose(VERBOSE_PREFIX_3 "Disabling Caller*ID on %s\n", chan->name);
1532             }
1533             /* Disable Caller*ID if enabled */
1534             l->hidecallerid = 1;
1535             if (chan->cid.cid_num)
1536                 free(chan->cid.cid_num);
1537             chan->cid.cid_num = NULL;
1538             
1539                         if (chan->cid.cid_name)
1540                 free(chan->cid.cid_name);
1541             chan->cid.cid_name = NULL;
1542                         
1543             transmit_tone(s, SKINNY_DIALTONE);
1544             len = 0;
1545             memset(exten, 0, sizeof(exten));
1546             timeout = firstdigittimeout;
1547         } else if (l->callreturn && !strcmp(exten, "*69")) {
1548             res = 0;
1549             if (!ast_strlen_zero(l->lastcallerid)) {
1550                 res = ast_say_digit_str(chan, l->lastcallerid, "", chan->language);
1551             }
1552             if (!res) {
1553                 transmit_tone(s, SKINNY_DIALTONE);
1554                         }
1555             break;
1556         } else if (!strcmp(exten, "*78")) {
1557             /* Do not disturb */
1558             if (option_verbose > 2) {
1559                 ast_verbose(VERBOSE_PREFIX_3 "Enabled DND on channel %s\n", chan->name);
1560             }
1561             transmit_tone(s, SKINNY_DIALTONE);
1562             l->dnd = 1;
1563             getforward = 0;
1564             memset(exten, 0, sizeof(exten));
1565             len = 0;
1566         } else if (!strcmp(exten, "*79")) {
1567             /* Do not disturb */
1568             if (option_verbose > 2) {
1569                 ast_verbose(VERBOSE_PREFIX_3 "Disabled DND on channel %s\n", chan->name);
1570             }
1571                         transmit_tone(s, SKINNY_DIALTONE);
1572             l->dnd = 0;
1573             getforward = 0;
1574             memset(exten, 0, sizeof(exten));
1575             len = 0;
1576         } else if (l->cancallforward && !strcmp(exten, "*72")) {
1577             transmit_tone(s, SKINNY_DIALTONE);
1578             getforward = 1;
1579             memset(exten, 0, sizeof(exten));
1580             len = 0;
1581         } else if (l->cancallforward && !strcmp(exten, "*73")) {
1582             if (option_verbose > 2) {
1583                 ast_verbose(VERBOSE_PREFIX_3 "Cancelling call forwarding on channel %s\n", chan->name);
1584             }
1585             transmit_tone(s, SKINNY_DIALTONE); 
1586             memset(l->call_forward, 0, sizeof(l->call_forward));
1587             getforward = 0;
1588             memset(exten, 0, sizeof(exten));
1589             len = 0;
1590         } else if (!strcmp(exten, ast_parking_ext()) && 
1591                     sub->next->owner &&
1592                     ast_bridged_channel(sub->next->owner)) {
1593             /* This is a three way call, the main call being a real channel, 
1594                 and we're parking the first call. */
1595             ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
1596             if (option_verbose > 2) {
1597                 ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
1598             }
1599             break;
1600         } else if (!ast_strlen_zero(l->lastcallerid) && !strcmp(exten, "*60")) {
1601             if (option_verbose > 2) {
1602                 ast_verbose(VERBOSE_PREFIX_3 "Blacklisting number %s\n", l->lastcallerid);
1603             }
1604             res = ast_db_put("blacklist", l->lastcallerid, "1");
1605             if (!res) {
1606                 transmit_tone(s, SKINNY_DIALTONE);              
1607                 memset(exten, 0, sizeof(exten));
1608                 len = 0;
1609             }
1610         } else if (l->hidecallerid && !strcmp(exten, "*82")) {
1611             if (option_verbose > 2) {
1612                 ast_verbose(VERBOSE_PREFIX_3 "Enabling Caller*ID on %s\n", chan->name);
1613             }
1614             /* Enable Caller*ID if enabled */
1615             l->hidecallerid = 0;
1616             if (chan->cid.cid_num)
1617                 free(chan->cid.cid_num);
1618             if (!ast_strlen_zero(l->cid_num))
1619                 chan->cid.cid_num = strdup(l->cid_num);
1620
1621             if (chan->cid.cid_name)
1622                 free(chan->cid.cid_name);
1623             if (!ast_strlen_zero(l->cid_name))
1624                 chan->cid.cid_name = strdup(l->cid_name);
1625
1626             transmit_tone(s, SKINNY_DIALTONE);
1627             len = 0;
1628             memset(exten, 0, sizeof(exten));
1629             timeout = firstdigittimeout;
1630         } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) &&
1631                         ((exten[0] != '*') || (!ast_strlen_zero(exten) > 2))) {
1632             ast_log(LOG_WARNING, "Can't match [%s] from '%s' in context %s\n", exten, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
1633             transmit_tone(s, SKINNY_REORDER); 
1634                         sleep(3); /* hang out for 3 seconds to let congestion play */
1635                         break;
1636         }
1637         if (!timeout)
1638             timeout = gendigittimeout;
1639         if (len && !ast_ignore_pattern(chan->context, exten))
1640                         ast_indicate(chan, -1);
1641     }
1642         ast_hangup(chan);
1643         return NULL;
1644 }
1645
1646
1647
1648 static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
1649 {
1650         int res = 0;
1651         int tone = 0;
1652         struct skinny_line *l;
1653         struct skinny_subchannel *sub;
1654         struct skinnysession *session;
1655         
1656         sub = ast->tech_pvt;
1657         l = sub->parent;
1658         session = l->parent->session;
1659
1660         if (!l->parent->registered) {
1661                 ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
1662                 return -1;
1663         }
1664         
1665         if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
1666                 ast_log(LOG_WARNING, "skinny_call called on %s, neither down nor reserved\n", ast->name);
1667                 return -1;
1668         }
1669
1670         if (skinnydebug) {
1671                 ast_verbose(VERBOSE_PREFIX_3 "skinny_call(%s)\n", ast->name);
1672         }
1673
1674         if (l->dnd) {
1675                 ast_queue_control(ast, AST_CONTROL_BUSY);
1676                 return -1;
1677         }
1678    
1679         switch (l->hookstate) {
1680         case SKINNY_OFFHOOK:
1681             tone = SKINNY_CALLWAITTONE;
1682             break;
1683         case SKINNY_ONHOOK:
1684                         tone = SKINNY_ALERT;
1685                         break;
1686         default:
1687             ast_log(LOG_ERROR, "Don't know how to deal with hookstate %d\n", l->hookstate);
1688             break;
1689         }
1690
1691         transmit_lamp_indication(session, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
1692         transmit_ringer_mode(session, SKINNY_RING_INSIDE);
1693         
1694         if (ast->cid.cid_num){ 
1695
1696                 char ciddisplay[41] = "";
1697
1698                 /* We'll assume that if it is 10 numbers, it is a standard NANPA number
1699                    Why? Because I am bloody American, and I'm bigoted that way. */
1700
1701                 if (strlen(ast->cid.cid_num) == 10) {
1702
1703                         strcat (ciddisplay, "(");
1704                         strncat (ciddisplay, ast->cid.cid_num,3);
1705                         strcat (ciddisplay, ") ");
1706
1707                         strncat (ciddisplay, &ast->cid.cid_num[3],3);
1708                         strcat (ciddisplay,"-");
1709                         strncat (ciddisplay, &ast->cid.cid_num[6],4);
1710
1711                         strncat (ciddisplay, "      ", 6);
1712
1713                         strncat (ciddisplay, ast->cid.cid_name,17);
1714                 } else {
1715                         if (strlen(ast->cid.cid_num) < 40) {
1716                                 strncpy(ciddisplay,ast->cid.cid_num,strlen(ast->cid.cid_num));
1717                                 strcat (ciddisplay," -- ");
1718                                 
1719                                 if (sizeof(ast->cid.cid_name) > (40 - (strlen(ast->cid.cid_num) + 4))) {
1720                                         strncat (ciddisplay, ast->cid.cid_name, (40 - (strlen(ast->cid.cid_num) + 4)));
1721                                 } else {
1722                                         strncat (ciddisplay, ast->cid.cid_name, strlen(ast->cid.cid_name));
1723                                 }
1724                         } else {
1725                                 strncpy(ciddisplay, "Number too long!", 15);
1726                         }
1727                 }
1728
1729                 if (skinnydebug) {
1730                         ast_verbose("Trying to send: '%s'\n",ciddisplay);
1731                 }
1732
1733                 transmit_displaymessage(session, ciddisplay);
1734         }else{
1735                 transmit_displaymessage(session, "Unknown Name");
1736         }
1737
1738         transmit_tone(session, tone);
1739         transmit_callstate(session, l->instance, SKINNY_RINGIN, sub->callid);
1740
1741         /* XXX need to set the prompt */
1742         /* XXX need to deal with softkeys */
1743
1744         ast_setstate(ast, AST_STATE_RINGING);
1745         ast_queue_control(ast, AST_CONTROL_RINGING);
1746
1747         sub->outgoing = 1;
1748         if (l->type == TYPE_LINE) {
1749         if (!sub->rtp) {
1750             start_rtp(sub);
1751         } else {
1752                 /* do/should we need to anything if there already is an RTP allocated? */
1753         }
1754
1755         } else {
1756                 ast_log(LOG_ERROR, "I don't know how to dial on trunks, yet\n");
1757                 res = -1;
1758         }
1759         return res;
1760 }
1761
1762
1763 static int skinny_hangup(struct ast_channel *ast)
1764 {
1765     struct skinny_subchannel *sub = ast->tech_pvt;
1766     struct skinny_line *l = sub->parent;
1767     struct skinnysession *s = l->parent->session;
1768
1769     if (skinnydebug) {
1770         ast_verbose("skinny_hangup(%s) on %s@%s\n", ast->name, l->name, l->parent->name);
1771     }
1772     if (!ast->tech_pvt) {
1773         ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
1774         return 0;
1775     }
1776
1777     if (l->parent->registered) {
1778         if ((sub->parent->type = TYPE_LINE) && (sub->parent->hookstate == SKINNY_OFFHOOK)) {
1779                         sub->parent->hookstate = SKINNY_ONHOOK;
1780                         transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
1781                         transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
1782                         transmit_speaker_mode(s, SKINNY_SPEAKEROFF); 
1783                 } else if ((sub->parent->type = TYPE_LINE) && (sub->parent->hookstate == SKINNY_ONHOOK)) {
1784                         transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
1785                         transmit_speaker_mode(s, SKINNY_SPEAKEROFF); 
1786                         transmit_ringer_mode(s, SKINNY_RING_OFF);
1787                         transmit_tone(s, SKINNY_SILENCE);
1788                         transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
1789                         do_housekeeping(s);
1790                 } 
1791     }
1792     ast_mutex_lock(&sub->lock);
1793     sub->owner = NULL;
1794     ast->tech_pvt = NULL;
1795     sub->alreadygone = 0;
1796     sub->outgoing = 0;
1797     if (sub->rtp) {
1798         ast_rtp_destroy(sub->rtp);
1799         sub->rtp = NULL;
1800     }
1801     ast_mutex_unlock(&sub->lock);
1802     return 0;
1803 }
1804
1805 static int skinny_answer(struct ast_channel *ast)
1806 {
1807     int res = 0;
1808     struct skinny_subchannel *sub = ast->tech_pvt;
1809     struct skinny_line *l = sub->parent;
1810     sub->cxmode = SKINNY_CX_SENDRECV;
1811     if (!sub->rtp) {
1812                 start_rtp(sub);
1813     } 
1814     ast_verbose("skinny_answer(%s) on %s@%s-%d\n", ast->name, l->name, l->parent->name, sub->callid);
1815     if (ast->_state != AST_STATE_UP) {
1816         ast_setstate(ast, AST_STATE_UP);
1817     }
1818     return res;
1819 }
1820
1821 static struct ast_frame *skinny_rtp_read(struct skinny_subchannel *sub)
1822 {
1823         /* Retrieve audio/etc from channel.  Assumes sub->lock is already held. */
1824         struct ast_frame *f;
1825         f = ast_rtp_read(sub->rtp);
1826         if (sub->owner) {
1827                 /* We already hold the channel lock */
1828                 if (f->frametype == AST_FRAME_VOICE) {
1829                         if (f->subclass != sub->owner->nativeformats) {
1830                                 ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
1831                                 sub->owner->nativeformats = f->subclass;
1832                                 ast_set_read_format(sub->owner, sub->owner->readformat);
1833                                 ast_set_write_format(sub->owner, sub->owner->writeformat);
1834                         }
1835                 }
1836         }
1837         return f;
1838 }
1839
1840 static struct ast_frame  *skinny_read(struct ast_channel *ast)
1841 {
1842         struct ast_frame *fr;
1843         struct skinny_subchannel *sub = ast->tech_pvt;
1844         ast_mutex_lock(&sub->lock);
1845         fr = skinny_rtp_read(sub);
1846         ast_mutex_unlock(&sub->lock);
1847         return fr;
1848 }
1849
1850 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
1851 {
1852         struct skinny_subchannel *sub = ast->tech_pvt;
1853         int res = 0;
1854         if (frame->frametype != AST_FRAME_VOICE) {
1855                 if (frame->frametype == AST_FRAME_IMAGE)
1856                         return 0;
1857                 else {
1858                         ast_log(LOG_WARNING, "Can't send %d type frames with skinny_write\n", frame->frametype);
1859                         return 0;
1860                 }
1861         } else {
1862                 if (!(frame->subclass & ast->nativeformats)) {
1863                         ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
1864                                 frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
1865                         return -1;
1866                 }
1867         }
1868         if (sub) {
1869                 ast_mutex_lock(&sub->lock);
1870                 if (sub->rtp) {
1871                         res =  ast_rtp_write(sub->rtp, frame);
1872                 }
1873                 ast_mutex_unlock(&sub->lock);
1874         }
1875         return res;
1876 }
1877
1878 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1879 {
1880         struct skinny_subchannel *sub = newchan->tech_pvt;
1881         ast_log(LOG_NOTICE, "skinny_fixup(%s, %s)\n", oldchan->name, newchan->name);
1882         if (sub->owner != oldchan) {
1883                 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
1884                 return -1;
1885         }
1886         sub->owner = newchan;
1887         return 0;
1888 }
1889
1890 static int skinny_senddigit(struct ast_channel *ast, char digit)
1891 {
1892 #if 0
1893         struct skinny_subchannel *sub = ast->tech_pvt;
1894         int tmp;
1895         /* not right */
1896         sprintf(tmp, "%d", digit);  
1897         transmit_tone(sub->parent->parent->session, digit);
1898 #endif
1899         return -1;
1900 }
1901
1902 static char *control2str(int ind) {
1903     switch (ind) {
1904         case AST_CONTROL_HANGUP:
1905             return "Other end has hungup";
1906         case AST_CONTROL_RING:
1907             return "Local ring";
1908         case AST_CONTROL_RINGING:
1909             return "Remote end is ringing";
1910         case AST_CONTROL_ANSWER:
1911             return "Remote end has answered";
1912         case AST_CONTROL_BUSY:
1913             return "Remote end is busy";
1914         case AST_CONTROL_TAKEOFFHOOK:
1915             return "Make it go off hook";
1916         case AST_CONTROL_OFFHOOK:
1917             return "Line is off hook";
1918         case AST_CONTROL_CONGESTION:
1919             return "Congestion (circuits busy)";
1920         case AST_CONTROL_FLASH:
1921             return "Flash hook";
1922         case AST_CONTROL_WINK:
1923             return "Wink";
1924         case AST_CONTROL_OPTION:
1925             return "Set a low-level option";
1926         case AST_CONTROL_RADIO_KEY:
1927             return "Key Radio";
1928         case AST_CONTROL_RADIO_UNKEY:
1929             return "Un-Key Radio";
1930                 case -1:
1931                         return "Stop tone";
1932     }
1933     return "UNKNOWN";
1934 }
1935
1936
1937 static int skinny_indicate(struct ast_channel *ast, int ind)
1938 {
1939         struct skinny_subchannel *sub = ast->tech_pvt;
1940         struct skinny_line *l = sub->parent;
1941         struct skinnysession *s = l->parent->session;
1942
1943         if (skinnydebug) {
1944                 ast_verbose(VERBOSE_PREFIX_3 "Asked to indicate '%s' condition on channel %s\n", control2str(ind), ast->name);
1945         }
1946         switch(ind) {
1947         case AST_CONTROL_RINGING:
1948                 if (ast->_state != AST_STATE_UP) {
1949                         if (!sub->progress) {           
1950                                 transmit_tone(s, SKINNY_ALERT);
1951                                 transmit_callstate(s, l->instance, SKINNY_RINGOUT, sub->callid);
1952                                 sub->ringing = 1;
1953                                 break;
1954                         }
1955                 }
1956                 return -1;
1957         case AST_CONTROL_BUSY:
1958                 if (ast->_state != AST_STATE_UP) {              
1959                         transmit_tone(s, SKINNY_BUSYTONE);
1960                         transmit_callstate(s, l->instance, SKINNY_BUSY, sub->callid);
1961                         sub->alreadygone = 1;
1962                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1963                         break;
1964                 }
1965                 return -1;
1966         case AST_CONTROL_CONGESTION:
1967                 if (ast->_state != AST_STATE_UP) {              
1968                         transmit_tone(s, SKINNY_REORDER);
1969                         transmit_callstate(s, l->instance, SKINNY_CONGESTION, sub->callid);
1970                         sub->alreadygone = 1;
1971                         ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1972                         break;
1973                 }
1974                 return -1;
1975         case AST_CONTROL_PROGRESS:
1976                 if ((ast->_state != AST_STATE_UP) && !sub->progress && !sub->outgoing) {
1977                         transmit_callstate(s, l->instance, SKINNY_PROGRESS, sub->callid);
1978                         sub->progress = 1;
1979                         break;
1980                 }
1981                 return -1;  
1982         case -1:
1983                 transmit_tone(s, SKINNY_SILENCE);
1984                 break;          
1985         case AST_CONTROL_PROCEEDING:
1986                 break;
1987         default:
1988                 ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
1989                 return -1;
1990         }
1991         return 0;
1992 }
1993         
1994 static struct ast_channel *skinny_new(struct skinny_subchannel *sub, int state)
1995 {
1996         struct ast_channel *tmp;
1997         struct skinny_line *l = sub->parent;
1998         int fmt;
1999         l = sub->parent;
2000         tmp = ast_channel_alloc(1);
2001         if (tmp) {
2002                 tmp->tech = &skinny_tech;
2003                 tmp->nativeformats = l->capability;
2004                 if (!tmp->nativeformats)
2005                         tmp->nativeformats = capability;
2006                 fmt = ast_best_codec(tmp->nativeformats);
2007                 snprintf(tmp->name, sizeof(tmp->name), "Skinny/%s@%s-%d", l->name, l->parent->name, sub->callid);
2008                 if (sub->rtp)
2009                         tmp->fds[0] = ast_rtp_fd(sub->rtp);
2010                 tmp->type = type;
2011                 ast_setstate(tmp, state);
2012                 if (state == AST_STATE_RING)
2013                         tmp->rings = 1;
2014                 tmp->writeformat = fmt;
2015                 tmp->rawwriteformat = fmt;
2016                 tmp->readformat = fmt;
2017                 tmp->rawreadformat = fmt;
2018                 tmp->tech_pvt = sub;
2019                 if (!ast_strlen_zero(l->language))
2020                         strncpy(tmp->language, l->language, sizeof(tmp->language)-1);
2021                 if (!ast_strlen_zero(l->accountcode))
2022                         strncpy(tmp->accountcode, l->accountcode, sizeof(tmp->accountcode)-1);
2023                 if (l->amaflags)
2024                         tmp->amaflags = l->amaflags;
2025                 sub->owner = tmp;
2026                 ast_mutex_lock(&usecnt_lock);
2027                 usecnt++;
2028                 ast_mutex_unlock(&usecnt_lock);
2029                 ast_update_use_count();
2030                 tmp->callgroup = l->callgroup;
2031                 tmp->pickupgroup = l->pickupgroup;
2032                 strncpy(tmp->call_forward, l->call_forward, sizeof(tmp->call_forward) - 1);
2033                 strncpy(tmp->context, l->context, sizeof(tmp->context)-1);
2034                 strncpy(tmp->exten,l->exten, sizeof(tmp->exten)-1);
2035                 if (!ast_strlen_zero(l->cid_num)) {
2036                         tmp->cid.cid_num = strdup(l->cid_num);
2037                 }
2038                 if (!ast_strlen_zero(l->cid_name)) {
2039                         tmp->cid.cid_name = strdup(l->cid_name);
2040                 }
2041                 tmp->priority = 1;
2042                 if (state != AST_STATE_DOWN) {
2043                         if (ast_pbx_start(tmp)) {
2044                                 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
2045                                 ast_hangup(tmp);
2046                                 tmp = NULL;
2047                         }
2048                 }
2049         } else {
2050                 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
2051     }
2052
2053         return tmp;
2054 }
2055
2056 static int handle_message(skinny_req *req, struct skinnysession *s)
2057 {
2058         struct skinny_subchannel *sub;
2059         struct ast_channel *c;
2060         struct ast_frame f = { 0, };    
2061         struct sockaddr_in sin;
2062         struct sockaddr_in us;
2063         struct skinny_line *lines;
2064         char name[16];
2065         char addr[4];
2066         char d;
2067         int digit;
2068         int res=0;
2069         int speedDialNum;
2070         int lineNumber;
2071         int stimulus;
2072         int stimulusInstance;
2073         int status;
2074         int port;
2075         int i;
2076         time_t timer;
2077         struct tm *cmtime;
2078         pthread_t t;
2079         
2080         if ( (!s->device) && (req->e != REGISTER_MESSAGE && req->e != ALARM_MESSAGE)) {
2081                 ast_log(LOG_WARNING, "Client sent message #%d without first registering.\n", req->e);
2082                 free(req);
2083                 return 0;
2084         }
2085
2086         switch(req->e)  {
2087         case ALARM_MESSAGE:
2088                 /* no response necessary */
2089                 break;
2090         case REGISTER_MESSAGE:
2091                 if (skinnydebug) {
2092                         ast_verbose("Device %s is attempting to register\n", req->data.reg.name);
2093                 }
2094                 res = skinny_register(req, s);  
2095                 if (!res) {
2096                         ast_log(LOG_ERROR, "Rejecting Device %s: Device not found\n", req->data.reg.name);
2097                         memcpy(&name, req->data.reg.name, sizeof(req->data.reg.name));
2098                         memset(req, 0, sizeof(skinny_req));
2099                         req->len = sizeof(register_rej_message)+4;
2100                         req->e = REGISTER_REJ_MESSAGE;
2101                         snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name);
2102                         transmit_response(s, req);
2103                         break;
2104                 }
2105                 if (option_verbose > 2) {
2106                         ast_verbose(VERBOSE_PREFIX_3 "Device '%s' successfuly registered\n", s->device->name); 
2107                 }
2108                 memset(req, 0, SKINNY_MAX_PACKET);
2109                 req->len = sizeof(register_ack_message)+4;
2110                 req->e = REGISTER_ACK_MESSAGE;
2111                 req->data.regack.res[0] = '0';
2112                 req->data.regack.res[1] = '\0';
2113                 req->data.regack.keepAlive = keep_alive;
2114                 strncpy(req->data.regack.dateTemplate, date_format, sizeof(req->data.regack.dateTemplate) - 1); 
2115                 req->data.regack.res2[0] = '0';
2116                 req->data.regack.res2[1] = '\0';
2117                 req->data.regack.secondaryKeepAlive = keep_alive;
2118                 transmit_response(s, req);
2119                 if (skinnydebug) {
2120                         ast_verbose("Requesting capabilities\n");
2121                 }
2122                 memset(req, 0, SKINNY_MAX_PACKET);
2123                 req->len = 4;
2124                 req->e = CAPABILITIES_REQ_MESSAGE;
2125                 transmit_response(s, req);
2126                 break;
2127         case UNREGISTER_MESSAGE:
2128                 /* XXX Acutally unregister the device */
2129                 break;
2130         case IP_PORT_MESSAGE:
2131                 /* no response necessary */
2132                 break;
2133         case STIMULUS_MESSAGE:
2134                 stimulus = req->data.stimulus.stimulus;
2135                 stimulusInstance = req->data.stimulus.stimulusInstance;
2136                 
2137                 switch(stimulus) {
2138                 case STIMULUS_REDIAL:
2139                         /* If we can keep an array of dialed frames we can implement a quick 
2140                            and dirty redial, feeding the frames we last got into the queue
2141                            function */
2142
2143                         if (skinnydebug) {
2144                                 ast_verbose("Recieved Stimulus: Redial(%d)\n", stimulusInstance);
2145                         }
2146
2147
2148                         break;
2149                 case STIMULUS_SPEEDDIAL:
2150                         if (skinnydebug) {
2151                                 ast_verbose("Recieved Stimulus: SpeedDial(%d)\n", stimulusInstance);
2152                         }
2153                         break;
2154                 case STIMULUS_HOLD:
2155                         /* start moh? set RTP to 0.0.0.0? */
2156                         if (skinnydebug) {
2157                                 ast_verbose("Recieved Stimulus: Hold(%d)\n", stimulusInstance);
2158                         }
2159                         break;
2160                 case STIMULUS_TRANSFER:
2161                         if (skinnydebug) {
2162                                 ast_verbose("Recieved Stimulus: Transfer(%d)\n", stimulusInstance);
2163                         }
2164                         transmit_tone(s, SKINNY_DIALTONE);
2165                                 
2166                         /* figure out how to transfer */
2167
2168                         break;
2169                 case STIMULUS_CONFERENCE:
2170                         if (skinnydebug) {
2171                                 ast_verbose("Recieved Stimulus: Transfer(%d)\n", stimulusInstance);
2172                         }
2173                         transmit_tone(s, SKINNY_DIALTONE);
2174
2175                         /* figure out how to bridge n' stuff */
2176                                 
2177
2178                         break;
2179                 case STIMULUS_VOICEMAIL:
2180                         if (skinnydebug) {
2181                                 ast_verbose("Recieved Stimulus: Voicemail(%d)\n", stimulusInstance);
2182                         }
2183                                 
2184                         /* Dial Voicemail */
2185
2186                         break;
2187                 case STIMULUS_CALLPARK:
2188                         if (skinnydebug) {
2189                                 ast_verbose("Recieved Stimulus: Park Call(%d)\n", stimulusInstance);
2190                         }
2191
2192                         break;
2193                 case STIMULUS_FORWARDALL:
2194                         /* Do not disturb */
2195                         transmit_tone(s, SKINNY_DIALTONE);
2196                         if(s->device->lines->dnd != 0){
2197                                 if (option_verbose > 2) {
2198                                         ast_verbose(VERBOSE_PREFIX_3 "Disabling DND on %s@%s\n",find_subchannel_by_line(s->device->lines)->parent->name,find_subchannel_by_line(s->device->lines)->parent->name);
2199                                 }
2200                                 s->device->lines->dnd = 0;
2201                                 transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
2202                         }else{
2203                                 if (option_verbose > 2) {
2204                                         ast_verbose(VERBOSE_PREFIX_3 "Enabling DND on %s@%s\n",find_subchannel_by_line(s->device->lines)->parent->name,find_subchannel_by_line(s->device->lines)->parent->name);
2205                                 }
2206                                 s->device->lines->dnd = 1;
2207                                 transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF);
2208                         }
2209                         break;
2210                 case STIMULUS_FORWARDBUSY:
2211                 case STIMULUS_FORWARDNOANSWER:
2212                         /* Gonna be fun, not */
2213                         if (skinnydebug) {
2214                                 ast_verbose("Recieved Stimulus: Forward (%d)\n", stimulusInstance);
2215                         }
2216                         break;
2217                 case STIMULUS_DISPLAY:
2218                         /* Not sure what this is */
2219                         if (skinnydebug) {
2220                                 ast_verbose("Recieved Stimulus: Display(%d)\n", stimulusInstance);
2221                         }
2222                         break;
2223                 case STIMULUS_LINE:
2224                         if (skinnydebug) {
2225                                 ast_verbose("Recieved Stimulus: Line(%d)\n", stimulusInstance);
2226                         }               
2227                         sub = find_subchannel_by_line(s->device->lines);
2228                         /* turn the speaker on */
2229                         transmit_speaker_mode(s, 1);  
2230                 break;
2231                 default:
2232                         ast_verbose("RECEIVED UNKNOWN STIMULUS:  %d(%d)\n", stimulus, stimulusInstance);                        
2233                         break;
2234                 }
2235                 break;
2236         case VERSION_REQ_MESSAGE:
2237                 if (skinnydebug) {
2238                         ast_verbose("Version Request\n");
2239                 }
2240                 memset(req, 0, SKINNY_MAX_PACKET);
2241                 req->len = sizeof(version_res_message)+4;
2242                 req->e = VERSION_RES_MESSAGE;
2243                 snprintf(req->data.version.version, sizeof(req->data.version.version), s->device->version_id);
2244                 transmit_response(s, req);
2245                 break;
2246         case SERVER_REQUEST_MESSAGE:
2247                 if (skinnydebug) {
2248                         ast_verbose("Recieved Server Request\n");
2249                 }
2250                 memset(req, 0, SKINNY_MAX_PACKET);
2251                 req->len = sizeof(server_res_message)+4;
2252                 req->e = SERVER_RES_MESSAGE;
2253                 memcpy(req->data.serverres.server[0].serverName, ourhost, 
2254                                 sizeof(req->data.serverres.server[0].serverName));
2255                 req->data.serverres.serverListenPort[0] = ourport;
2256                 req->data.serverres.serverIpAddr[0] = __ourip.s_addr;
2257                 transmit_response(s, req);      
2258                 break;
2259         case BUTTON_TEMPLATE_REQ_MESSAGE:
2260                 if (skinnydebug) {
2261                         ast_verbose("Buttontemplate requested\n");
2262                 }
2263                 memset(req, 0, SKINNY_MAX_PACKET);
2264                 req->e = BUTTON_TEMPLATE_RES_MESSAGE;   
2265                 /* XXX Less of a hack, more of a kludge now */
2266                 sub = find_subchannel_by_line(s->device->lines);
2267                 req->len = sizeof(button_template_res_message)+4;
2268                 if (!strcmp(s->device->model,"30VIP")){
2269                         req->data.buttontemplate.buttonOffset = 0;
2270                         req->data.buttontemplate.buttonCount  = 30;
2271                         req->data.buttontemplate.totalButtonCount = 30;
2272                         memcpy(req->data.buttontemplate.definition,
2273                                 thirtyvip_button_definition_hack, 
2274                                 sizeof(req->data.buttontemplate.definition));
2275                         if(skinnydebug){                        
2276                                 ast_verbose("Sending 30VIP template to %s@%s (%s)\n",sub->parent->name, sub->parent->parent->name, s->device->model);
2277                         }
2278                 }else if(!strcmp(s->device->model,"12SP")){
2279                         req->data.buttontemplate.buttonOffset = 0;
2280                         req->data.buttontemplate.buttonCount  = 12;
2281                         req->data.buttontemplate.totalButtonCount = 12;
2282                         memcpy(req->data.buttontemplate.definition,
2283                                 twelvesp_button_definition_hack, 
2284                                 sizeof(req->data.buttontemplate.definition));
2285                         if(skinnydebug){                        
2286                                 ast_verbose("Sending 12SP template to %s@%s (%s)\n",sub->parent->name, sub->parent->parent->name, s->device->model);
2287                         }               
2288                 }else{
2289                         req->data.buttontemplate.buttonOffset = 0;
2290                         req->data.buttontemplate.buttonCount  = 12;
2291                         req->data.buttontemplate.totalButtonCount = 12;
2292                         memcpy(req->data.buttontemplate.definition,
2293                                 twelvesp_button_definition_hack, 
2294                                 sizeof(req->data.buttontemplate.definition));
2295                         if(skinnydebug){                        
2296                                 ast_verbose("Sending default template to %s@%s (%s)\n",sub->parent->name, sub->parent->parent->name, s->device->model);
2297                         }
2298
2299                 }
2300                 
2301                 transmit_response(s, req);
2302                 break;
2303         case SOFT_KEY_SET_REQ_MESSAGE:
2304                 if (skinnydebug)  {
2305                         ast_verbose("Received SoftKeySetReq\n");
2306                 }
2307                 memset(req, 0, SKINNY_MAX_PACKET);
2308                 req->len = sizeof(soft_key_sets)+4;
2309                 req->e = SOFT_KEY_SET_RES_MESSAGE;
2310                 req->data.softkeysets.softKeySetOffset          = 0;
2311                 req->data.softkeysets.softKeySetCount           = 11;
2312                 req->data.softkeysets.totalSoftKeySetCount  = 11;       
2313                 /* XXX Wicked hack XXX */
2314                 memcpy(req->data.softkeysets.softKeySetDefinition, 
2315                            soft_key_set_hack, 
2316                            sizeof(req->data.softkeysets.softKeySetDefinition));
2317                 transmit_response(s,req);
2318                 break;
2319         case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
2320                 if (skinnydebug) {
2321                         ast_verbose("Recieved SoftKey Template Request\n");
2322                 }
2323                 memset(req, 0, SKINNY_MAX_PACKET);
2324                 req->len = sizeof(soft_key_template)+4;
2325                 req->e = SOFT_KEY_TEMPLATE_RES_MESSAGE;
2326                 req->data.softkeytemplate.softKeyOffset         = 0;
2327                 req->data.softkeytemplate.softKeyCount          = 21;
2328                 req->data.softkeytemplate.totalSoftKeyCount = 21; 
2329                 /* XXX Another wicked hack XXX */
2330                 memcpy(req->data.softkeytemplate.softKeyTemplateDefinition,
2331                            soft_key_template_hack,
2332                            sizeof(req->data.softkeytemplate.softKeyTemplateDefinition));
2333                 transmit_response(s,req);
2334                 break;
2335         case TIME_DATE_REQ_MESSAGE:
2336                 if (skinnydebug) {
2337                         ast_verbose("Received Time/Date Request\n");
2338                 }
2339                 memset(req, 0, SKINNY_MAX_PACKET);
2340                 req->len = sizeof(definetimedate_message)+4;
2341                 req->e = DEFINETIMEDATE_MESSAGE;
2342                 timer=time(NULL);
2343                 cmtime = localtime(&timer);
2344                 req->data.definetimedate.year = cmtime->tm_year+1900;
2345                 req->data.definetimedate.month = cmtime->tm_mon+1;
2346                 req->data.definetimedate.dayofweek = cmtime->tm_wday;
2347                 req->data.definetimedate.day = cmtime->tm_mday;
2348                 req->data.definetimedate.hour = cmtime->tm_hour;
2349                 req->data.definetimedate.minute = cmtime->tm_min;
2350                 req->data.definetimedate.seconds = cmtime->tm_sec;
2351                 transmit_response(s, req);
2352                 break;
2353         case SPEED_DIAL_STAT_REQ_MESSAGE:
2354                 /* Not really sure how Speed Dial's are different than the 
2355                    Softkey templates */
2356                 speedDialNum = req->data.speeddialreq.speedDialNumber;
2357                 memset(req, 0, SKINNY_MAX_PACKET);
2358                 req->len = sizeof(speed_dial_stat_res_message)+4;
2359                 req->e = SPEED_DIAL_STAT_RES_MESSAGE;
2360 #if 0
2361                 /* XXX Do this right XXX */     
2362                 /* If the redial function works the way I think it will, a modification of it
2363                    can work here was well. Yikes. */
2364                 req->data.speeddialreq.speedDialNumber = speedDialNum;
2365                 snprintf(req->data.speeddial.speedDialDirNumber, sizeof(req->data.speeddial.speedDialDirNumber), "31337");
2366                 snprintf(req->data.speeddial.speedDialDisplayName,  sizeof(req->data.speeddial.speedDialDisplayName),"Asterisk Rules!");
2367 #endif  
2368                 transmit_response(s, req);
2369                 break;
2370         case LINE_STATE_REQ_MESSAGE:
2371                 lineNumber = req->data.line.lineNumber;
2372                 if (skinnydebug) {
2373                         ast_verbose("Received LineStateReq\n");
2374                 }
2375                 memset(req, 0, SKINNY_MAX_PACKET);
2376                 req->len = sizeof(line_stat_res_message)+4;
2377                 req->e = LINE_STAT_RES_MESSAGE; 
2378                 sub = find_subchannel_by_line(s->device->lines);
2379                 if (!sub) {
2380                         ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
2381                         return 0;
2382                 }
2383                 lines = sub->parent;
2384                 ast_mutex_lock(&devicelock);
2385                 for (i=1; i < lineNumber; i++) {
2386                         lines = lines->next;
2387                 }
2388                 ast_mutex_unlock(&devicelock);
2389                 req->data.linestat.linenumber = lineNumber;             
2390                 memcpy(req->data.linestat.lineDirNumber, lines->name,
2391                                 sizeof(req->data.linestat.lineDirNumber));
2392                 memcpy(req->data.linestat.lineDisplayName, lines->label,
2393                                 sizeof(req->data.linestat.lineDisplayName)); 
2394                 transmit_response(s,req);
2395                 break;
2396         case CAPABILITIES_RES_MESSAGE:
2397                 if (skinnydebug) {
2398                         ast_verbose("Received CapabilitiesRes\n");      
2399                 }
2400                 /* XXX process the capabilites  */
2401                 break;
2402         case KEEP_ALIVE_MESSAGE:
2403                 memset(req, 0, SKINNY_MAX_PACKET);
2404                 req->len = 4;
2405                 req->e = KEEP_ALIVE_ACK_MESSAGE;
2406                 transmit_response(s, req);
2407                 do_housekeeping(s);
2408
2409                 break;
2410         case OFFHOOK_MESSAGE:
2411                 transmit_ringer_mode(s,SKINNY_RING_OFF);
2412                 transmit_lamp_indication(s, STIMULUS_LINE, s->device->lines->instance, SKINNY_LAMP_ON); 
2413                 
2414                 sub = find_subchannel_by_line(s->device->lines);
2415                 if (!sub) {
2416                         ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
2417                         return 0;
2418                 }
2419                 sub->parent->hookstate = SKINNY_OFFHOOK;
2420                 
2421                 if (sub->outgoing) {
2422                         transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, sub->callid);
2423                         transmit_tone(s, SKINNY_SILENCE);
2424                         ast_setstate(sub->owner, AST_STATE_UP);
2425                         /* XXX select the appropriate soft key here */
2426                 } else {        
2427                         if (!sub->owner) {      
2428                                 transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, sub->callid);
2429                                 if (skinnydebug) {
2430                                         ast_verbose("Attempting to Clear display on Skinny %s@%s\n",sub->parent->name, sub->parent->parent->name);
2431                                 }
2432                                 transmit_displaymessage(s, 0); /* clear display */ 
2433                                 transmit_tone(s, SKINNY_DIALTONE);
2434                                 c = skinny_new(sub, AST_STATE_DOWN);                    
2435                                 if(c) {
2436                                         /* start switch */
2437                                         if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
2438                                                 ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
2439                                                 ast_hangup(c);
2440                                         }
2441                                 } else {
2442                                         ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name, s->device->name);
2443                                 }
2444                                 
2445                         } else {
2446                                 ast_log(LOG_DEBUG, "Current sub [%s] already has owner\n", sub->owner->name);
2447                         }
2448                 }
2449                 break;
2450         case ONHOOK_MESSAGE:
2451                 sub = find_subchannel_by_line(s->device->lines);
2452                 if (sub->parent->hookstate == SKINNY_ONHOOK) {
2453                         /* Somthing else already put us back on hook */ 
2454                         break;
2455                 }
2456                 sub->cxmode = SKINNY_CX_RECVONLY;
2457                 sub->parent->hookstate = SKINNY_ONHOOK;
2458                 transmit_callstate(s, s->device->lines->instance, sub->parent->hookstate,sub->callid);
2459             if (skinnydebug) {
2460                         ast_verbose("Skinny %s@%s went on hook\n",sub->parent->name, sub->parent->parent->name);
2461             }
2462             if (sub->parent->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
2463                         /* We're allowed to transfer, we have two active calls and */
2464                         /* we made at least one of the calls.  Let's try and transfer */
2465 #if 0
2466              if ((res = attempt_transfer(p)) < 0) {
2467                                  if (p->sub->next->owner) {
2468                                         sub->next->alreadygone = 1;
2469                                         ast_queue_hangup(sub->next->owner,1);
2470                                 }
2471                          } else if (res) {
2472                                     ast_log(LOG_WARNING, "Transfer attempt failed\n");
2473                                         return -1;
2474              }
2475 #endif
2476         } else {
2477            /* Hangup the current call */
2478            /* If there is another active call, skinny_hangup will ring the phone with the other call */
2479            if (sub->owner) {
2480                sub->alreadygone = 1;
2481                ast_queue_hangup(sub->owner);
2482            } else {
2483                ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n", 
2484                            sub->parent->name, sub->parent->parent->name, sub->callid);
2485            }
2486         }
2487
2488         if ((sub->parent->hookstate == SKINNY_ONHOOK) && (!sub->next->rtp)) {
2489                         do_housekeeping(s);
2490         }
2491
2492         break;
2493         case KEYPAD_BUTTON_MESSAGE:
2494                 digit = req->data.keypad.button;
2495                 if (skinnydebug) {
2496                         ast_verbose("Collected digit: [%d]\n", digit);
2497                 }
2498                 f.frametype = AST_FRAME_DTMF;
2499                 if (digit == 14) {
2500                         d = '*';
2501                 } else if (digit == 15) {
2502                         d = '#';
2503                 } else if (digit >=0 && digit <= 9) {
2504                         d = '0' + digit;
2505                 } else {
2506                         /* digit=10-13 (A,B,C,D ?), or
2507                          * digit is bad value
2508                          * 
2509                          * probably should not end up here, but set
2510                          * value for backward compatibility, and log
2511                          * a warning.
2512                          */
2513                         d = '0' + digit;
2514                         ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
2515                 }
2516                 f.subclass  = d;  
2517                 f.src = "skinny";
2518
2519                 sub = find_subchannel_by_line(s->device->lines);                
2520
2521                 if (sub->owner) {
2522                         /* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
2523                         ast_queue_frame(sub->owner, &f);
2524                         if (sub->next->owner) {
2525                                 ast_queue_frame(sub->next->owner, &f);
2526                         }
2527                 } else {
2528                         ast_verbose("No owner: %s\n", s->device->lines->name);
2529                 }
2530                 break;
2531         case OPEN_RECIEVE_CHANNEL_ACK_MESSAGE:
2532                 ast_verbose("Recieved Open Recieve Channel Ack\n");
2533                 status = req->data.openrecievechannelack.status;
2534                 if (status) {
2535                         ast_log(LOG_ERROR, "Open Recieve Channel Failure\n");
2536                         break;
2537                 }
2538                 memcpy(addr, req->data.openrecievechannelack.ipAddr, sizeof(addr));
2539                 port = req->data.openrecievechannelack.port;
2540                                 
2541                 sin.sin_family = AF_INET;
2542                 /* I smell endian problems */
2543                 memcpy(&sin.sin_addr, addr, sizeof(sin.sin_addr));  
2544                 sin.sin_port = htons(port);
2545         
2546                 sub = find_subchannel_by_line(s->device->lines);
2547                 if (sub->rtp) {
2548                         ast_rtp_set_peer(sub->rtp, &sin);
2549                         ast_rtp_get_us(sub->rtp, &us);  
2550                 } else {
2551                         ast_log(LOG_ERROR, "No RTP structure, this is very bad\n");
2552                         break;
2553                 }
2554                 memset(req, 0, SKINNY_MAX_PACKET);
2555                 req->len = sizeof(start_media_transmission_message)+4;
2556                 req->e = START_MEDIA_TRANSMISSION_MESSAGE;
2557                 req->data.startmedia.conferenceId = 0;
2558                 req->data.startmedia.passThruPartyId = 0;
2559                 memcpy(req->data.startmedia.remoteIp, &s->device->ourip, 4); /* Endian? */
2560                 req->data.startmedia.remotePort = ntohs(us.sin_port);
2561                 req->data.startmedia.packetSize = 20;
2562                 req->data.startmedia.payloadType = convert_cap(s->device->lines->capability);
2563                 req->data.startmedia.qualifier.precedence = 127;
2564                 req->data.startmedia.qualifier.vad = 0;
2565                 req->data.startmedia.qualifier.packets = 0;
2566                 req->data.startmedia.qualifier.bitRate = 0;
2567                 transmit_response(s, req);
2568                 break;  
2569         default:
2570                 ast_verbose("RECEIVED UNKNOWN MESSAGE TYPE:  %x\n", req->e);
2571                 break;
2572         }
2573
2574         free(req);
2575         return 1;
2576
2577 }
2578
2579 static void destroy_session(struct skinnysession *s)
2580 {
2581         struct skinnysession *cur, *prev = NULL;
2582         ast_mutex_lock(&sessionlock);
2583         cur = sessions;
2584         while(cur) {
2585                 if (cur == s)
2586                         break;
2587                 prev = cur;
2588                 cur = cur->next;
2589         }
2590         if (cur) {
2591                 if (prev)
2592                         prev->next = cur->next;
2593                 else
2594                         sessions = cur->next;
2595                 if (s->fd > -1)
2596                         close(s->fd);
2597                 ast_mutex_destroy(&s->lock);
2598                 free(s);
2599         } else
2600                 ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s);
2601         ast_mutex_unlock(&sessionlock);
2602 }
2603
2604 static int get_input(struct skinnysession *s)  
2605 {  
2606         int res;  
2607         int dlen = 0;
2608         struct pollfd fds[1];  
2609  
2610         fds[0].fd = s->fd;
2611         fds[0].events = POLLIN;
2612         res = poll(fds, 1, -1);
2613  
2614         if (res < 0) {
2615                 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
2616         } else if (res > 0) {
2617                 memset(s->inbuf,0,sizeof(s->inbuf));
2618                 res = read(s->fd, s->inbuf, 4);
2619                 if (res != 4) {
2620                         ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
2621                         return -1;
2622                 }
2623                 dlen = *(int *)s->inbuf;
2624                 if (dlen+8 > sizeof(s->inbuf))
2625                         dlen = sizeof(s->inbuf) - 8;
2626                 res = read(s->fd, s->inbuf+4, dlen+4);
2627                 ast_mutex_unlock(&s->lock);
2628                 if (res != (dlen+4)) {
2629                         ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
2630                         return -1;
2631                 } 
2632         }  
2633         return res;  
2634 }   
2635
2636 static skinny_req *skinny_req_parse(struct skinnysession *s)
2637 {
2638         skinny_req *req;
2639         
2640         req = malloc(SKINNY_MAX_PACKET);
2641         if (!req) {
2642                 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
2643                 return NULL;
2644         }
2645         memset(req, 0, sizeof(skinny_req));
2646         /* +8 to account for reserved and length fields */
2647         memcpy(req, s->inbuf, *(int*)(s->inbuf)+8); 
2648         if (req->e < 0) {
2649                 ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
2650                 free(req);
2651                 return NULL;
2652         }
2653         return req;
2654 }
2655
2656 static void *skinny_session(void *data)
2657 {
2658         int res;
2659         skinny_req *req;
2660         struct skinnysession *s = data;
2661         char iabuf[INET_ADDRSTRLEN];
2662         
2663         ast_verbose(VERBOSE_PREFIX_3 "Starting Skinny session from %s\n",  ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
2664
2665         for (;;) {
2666                 res = 0;
2667                 res = get_input(s);
2668                 if (res < 0)
2669                         break;
2670                 req = skinny_req_parse(s);
2671                 if (!req) {
2672                         return NULL;
2673                 }
2674                 res = handle_message(req, s);
2675                 if (res < 0) {
2676                         destroy_session(s);
2677                         return NULL;
2678                 } 
2679         }
2680         ast_log(LOG_NOTICE, "Skinny Session returned: %s\n", strerror(errno));
2681         destroy_session(s);
2682         return 0;
2683 }
2684
2685 static void *accept_thread(void *ignore)
2686 {
2687         int as;
2688         struct sockaddr_in sin;
2689         int sinlen;
2690         struct skinnysession *s;
2691         struct protoent *p;
2692         int arg = 1;
2693         pthread_attr_t attr;
2694
2695         pthread_attr_init(&attr);
2696         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2697
2698         for (;;) {
2699                 sinlen = sizeof(sin);
2700                 as = accept(skinnysock, (struct sockaddr *)&sin, &sinlen);
2701                 if (as < 0) {
2702                         ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
2703                         continue;
2704                 }
2705                 p = getprotobyname("tcp");
2706                 if(p) {
2707                         if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
2708                                 ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
2709                         }
2710                 }
2711                 s = malloc(sizeof(struct skinnysession));
2712                 if (!s) {
2713                         ast_log(LOG_WARNING, "Failed to allocate Skinny session: %s\n", strerror(errno));
2714                         continue;
2715                 } 
2716                 memset(s, 0, sizeof(struct skinnysession));
2717                 memcpy(&s->sin, &sin, sizeof(sin));
2718                 ast_mutex_init(&s->lock);
2719                 s->fd = as;
2720                 ast_mutex_lock(&sessionlock);
2721                 s->next = sessions;
2722                 sessions = s;
2723                 ast_mutex_unlock(&sessionlock);
2724                 
2725                 if (ast_pthread_create(&tcp_thread, NULL, skinny_session, s)) {
2726                         destroy_session(s);
2727                 }
2728         }
2729         
2730         
2731         if (skinnydebug) {
2732                 ast_verbose("killing accept thread\n");
2733         }
2734         close(as);
2735         return 0;
2736 }
2737
2738 static void *do_monitor(void *data)
2739 {
2740         int res;
2741
2742         /* This thread monitors all the interfaces which are not yet in use
2743            (and thus do not have a separate thread) indefinitely */
2744         /* From here on out, we die whenever asked */
2745         for(;;) {
2746                 pthread_testcancel();
2747                 /* Wait for sched or io */
2748                 res = ast_sched_wait(sched);
2749                 if ((res < 0) || (res > 1000)) {
2750                         res = 1000;
2751                 }
2752                 res = ast_io_wait(io, res);
2753                 ast_mutex_lock(&monlock);
2754                 if (res >= 0) {
2755                         ast_sched_runq(sched);
2756                 }
2757                 ast_mutex_unlock(&monlock);
2758         }
2759         /* Never reached */
2760         return NULL;
2761         
2762 }
2763
2764 static int restart_monitor(void)
2765 {
2766         /* If we're supposed to be stopped -- stay stopped */
2767         if (monitor_thread == AST_PTHREADT_STOP)
2768                 return 0;
2769         if (ast_mutex_lock(&monlock)) {
2770                 ast_log(LOG_WARNING, "Unable to lock monitor\n");
2771                 return -1;
2772         }
2773         if (monitor_thread == pthread_self()) {
2774                 ast_mutex_unlock(&monlock);
2775                 ast_log(LOG_WARNING, "Cannot kill myself\n");
2776                 return -1;
2777         }
2778         if (monitor_thread != AST_PTHREADT_NULL) {
2779                 /* Wake up the thread */
2780                 pthread_kill(monitor_thread, SIGURG);
2781         } else {
2782                 /* Start a new monitor */
2783                 if (ast_pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) {
2784                         ast_mutex_unlock(&monlock);
2785                         ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
2786                         return -1;
2787                 }
2788         }
2789         ast_mutex_unlock(&monlock);
2790         return 0;
2791 }
2792
2793 static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause)
2794 {
2795         int oldformat;
2796         struct skinny_subchannel *sub;
2797         struct ast_channel *tmpc = NULL;
2798         char tmp[256];
2799         char *dest = data;
2800
2801         oldformat = format;
2802         format &= capability;
2803         if (!format) {
2804                 ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
2805                 return NULL;
2806         }
2807         
2808         strncpy(tmp, dest, sizeof(tmp) - 1);
2809         if (ast_strlen_zero(tmp)) {
2810                 ast_log(LOG_NOTICE, "Skinny channels require a device\n");
2811                 return NULL;
2812         }
2813         
2814         sub = find_subchannel_by_name(tmp);  
2815         if (!sub) {
2816                 ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
2817                 return NULL;
2818         }
2819         
2820         if (option_verbose > 2) {
2821                 ast_verbose(VERBOSE_PREFIX_3 "skinny_request(%s)\n", tmp);
2822                 ast_verbose(VERBOSE_PREFIX_3 "Skinny cw: %d, dnd: %d, so: %d, sno: %d\n", 
2823                         sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
2824         }
2825         tmpc = skinny_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
2826         if (!tmpc) {
2827                 ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
2828         }
2829         restart_monitor();
2830
2831         /* and finish */        
2832         return tmpc;
2833 }
2834
2835 static int reload_config(void)
2836 {
2837         int on=1;
2838         struct ast_config *cfg;
2839         struct ast_variable *v;
2840         int format;
2841         char *cat;
2842         char iabuf[INET_ADDRSTRLEN];
2843         struct skinny_device *d;
2844         int oldport = ntohs(bindaddr.sin_port);
2845
2846 #if 0           
2847         hp = ast_gethostbyname(ourhost, &ahp);
2848         if (!hp) {
2849                 ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled\n");
2850                 return 0;
2851         }
2852 #endif
2853         cfg = ast_config_load(config);
2854
2855         /* We *must* have a config file otherwise stop immediately */
2856         if (!cfg) {
2857                 ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled\n", config);
2858                 return 0;
2859         }
2860
2861         /* load the general section */
2862         memset(&bindaddr, 0, sizeof(bindaddr));
2863         v = ast_variable_browse(cfg, "general");
2864         while(v) {
2865                 /* Create the interface list */
2866                 if (!strcasecmp(v->name, "bindaddr")) {
2867                         if (!(hp = ast_gethostbyname(v->value, &ahp))) {
2868                                 ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
2869                         } else {
2870                                 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
2871                         }
2872                 } else if (!strcasecmp(v->name, "keepAlive")) {
2873                         keep_alive = atoi(v->value);            
2874                 } else if (!strcasecmp(v->name, "dateFormat")) {
2875                         strncpy(date_format, v->value, sizeof(date_format) - 1);        
2876                 } else if (!strcasecmp(v->name, "allow")) {
2877                         format = ast_getformatbyname(v->value);
2878                         if (format < 1) 
2879                                 ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
2880                         else
2881                                 capability |= format;
2882                 } else if (!strcasecmp(v->name, "disallow")) {
2883                         format = ast_getformatbyname(v->value);
2884                         if (format < 1) 
2885                                 ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
2886                         else
2887                                 capability &= ~format;
2888                 } else if (!strcasecmp(v->name, "port")) {
2889                         if (sscanf(v->value, "%i", &ourport) == 1) {
2890                                 bindaddr.sin_port = htons(ourport);
2891                         } else {
2892                                 ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
2893                         }
2894                 }
2895                 v = v->next;
2896         }
2897
2898         if (ntohl(bindaddr.sin_addr.s_addr)) {
2899                 memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
2900         } else {
2901                 hp = ast_gethostbyname(ourhost, &ahp);
2902                 if (!hp) {
2903                         ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
2904                         ast_config_destroy(cfg);
2905                         return 0;
2906                 }
2907                 memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
2908         }
2909         if (!ntohs(bindaddr.sin_port)) {
2910                 bindaddr.sin_port = ntohs(DEFAULT_SKINNY_PORT);
2911         }
2912         bindaddr.sin_family = AF_INET;
2913         
2914         /* load the device sections */
2915         cat = ast_category_browse(cfg, NULL);
2916         while(cat) {
2917                 if (strcasecmp(cat, "general")) {
2918                         d = build_device(cat, ast_variable_browse(cfg, cat));
2919                         if (d) {
2920                                 if (option_verbose > 2) {
2921                                         ast_verbose(VERBOSE_PREFIX_3 "Added device '%s'\n", d->name);
2922                 }
2923                                 ast_mutex_lock(&devicelock);
2924                                 d->next = devices;
2925                                 devices = d;
2926                                 ast_mutex_unlock(&devicelock);
2927                         }
2928                 }
2929                 cat = ast_category_browse(cfg, cat);
2930         }
2931         ast_mutex_lock(&netlock);
2932         if ((skinnysock > -1) && (ntohs(bindaddr.sin_port) != oldport)) {
2933                 close(skinnysock);
2934                 skinnysock = -1;
2935         }
2936         if (skinnysock < 0) {
2937                 skinnysock = socket(AF_INET, SOCK_STREAM, 0);
2938                 if(setsockopt(skinnysock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
2939                         ast_log(LOG_ERROR, "Set Socket Options failed: errno %d, %s", errno, strerror(errno));
2940                         ast_config_destroy(cfg);
2941                         return 0;
2942                 }
2943
2944                 if (skinnysock < 0) {
2945                         ast_log(LOG_WARNING, "Unable to create Skinny socket: %s\n", strerror(errno));
2946                 } else {
2947                         if (bind(skinnysock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
2948                                 ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
2949                                                 ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port),
2950                                                         strerror(errno));
2951                                 close(skinnysock);
2952                                 skinnysock = -1;
2953                                 ast_config_destroy(cfg);
2954                                 return 0;
2955                         } 
2956
2957                         if (listen(skinnysock,DEFAULT_SKINNY_BACKLOG)) {
2958                                         ast_log(LOG_WARNING, "Failed to start listening to %s:%d: %s\n",
2959                                                 ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port),
2960                                                         strerror(errno));
2961                                         close(skinnysock);
2962                                         skinnysock = -1;
2963                                         ast_config_destroy(cfg);
2964                                         return 0;
2965                         }
2966                 
2967                         if (option_verbose > 1)
2968                                 ast_verbose(VERBOSE_PREFIX_2 "Skinny listening on %s:%d\n", 
2969                                         ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port));
2970
2971                         ast_pthread_create(&accept_t,NULL, accept_thread, NULL);
2972                 }
2973         }
2974         ast_mutex_unlock(&netlock);
2975
2976         /* and unload the configuration when were done */
2977         ast_config_destroy(cfg);
2978
2979         return 0;
2980 }
2981
2982 #if 0
2983 void delete_devices(void)
2984 {
2985         struct skinny_device *d, *dlast;
2986         struct skinny_line *l, *llast;
2987         struct skinny_subchannel *sub, *slast;
2988         
2989         ast_mutex_lock(&devicelock);
2990         
2991         /* Delete all devices */
2992         for (d=devices;d;) {
2993                 
2994                 /* Delete all lines for this device */
2995                 for (l=d->lines;l;) {
2996                         /* Delete all subchannels for this line */
2997                         for (sub=l->sub;sub;) {
2998                                 slast = sub;
2999                                 sub = sub->next;
3000                                 ast_mutex_destroy(&slast->lock);
3001                                 free(slast);
3002                         }
3003                         llast = l;
3004                         l = l->next;
3005                         ast_mutex_destroy(&llast->lock);
3006                         free(llast);
3007                 }
3008                 dlast = d;
3009                 d = d->next;
3010                 free(dlast);
3011         }
3012         devices=NULL;
3013         ast_mutex_unlock(&devicelock);
3014 }
3015 #endif
3016
3017 int reload(void)
3018 {
3019 #if 0
3020 /* XXX Causes Seg - needs to be fixed, or? */
3021
3022         delete_devices();
3023         reload_config();
3024         restart_monitor();
3025 #endif
3026         return 0;
3027 }
3028
3029
3030 int load_module()
3031 {
3032         int res = 0;
3033
3034         /* load and parse config */
3035         res = reload_config();
3036         
3037         /* Announce our presence to Asterisk */ 
3038         if (!res) {
3039                 /* Make sure we can register our skinny channel type */
3040                 if (ast_channel_register(&skinny_tech)) {
3041                         ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
3042                         return -1;
3043                 }
3044         }
3045         ast_rtp_proto_register(&skinny_rtp);
3046         ast_cli_register(&cli_show_lines);
3047         ast_cli_register(&cli_debug);
3048         ast_cli_register(&cli_no_debug);
3049         sched = sched_context_create();
3050         if (!sched) {
3051                 ast_log(LOG_WARNING, "Unable to create schedule context\n");
3052         }
3053         io = io_context_create();
3054         if (!io) {
3055                 ast_log(LOG_WARNING, "Unable to create I/O context\n");
3056         }
3057         /* And start the monitor for the first time */
3058         restart_monitor();
3059         return res;
3060 }
3061
3062 int unload_module()
3063 {
3064 #if 0
3065         struct skinny_session *session, s;
3066         struct skinny_subchannel *sub;
3067         struct skinny_line *line = session;
3068
3069         /* close all IP connections */
3070         if (!ast_mutex_lock(&devicelock)) {
3071                 /* Terminate tcp listener thread */
3072                 
3073
3074         } else {
3075                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
3076                 return -1;
3077         }
3078         if (!ast_mutex_lock(&monlock)) {
3079                 if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
3080                         pthread_cancel(monitor_thread);
3081                         pthread_kill(monitor_thread, SIGURG);
3082                         pthread_join(monitor_thread, NULL);
3083                 }
3084                 monitor_thread = AST_PTHREADT_STOP;
3085                 ast_mutex_unlock(&monlock);