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