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