00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <unistd.h>
00032 #include <sys/socket.h>
00033 #include <netinet/in.h>
00034 #include <netinet/tcp.h>
00035 #include <sys/ioctl.h>
00036 #include <net/if.h>
00037 #include <errno.h>
00038 #include <fcntl.h>
00039 #include <netdb.h>
00040 #include <arpa/inet.h>
00041 #include <sys/signal.h>
00042 #include <signal.h>
00043 #include <ctype.h>
00044
00045 #include "asterisk.h"
00046
00047 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 36725 $")
00048
00049 #include "asterisk/lock.h"
00050 #include "asterisk/channel.h"
00051 #include "asterisk/config.h"
00052 #include "asterisk/logger.h"
00053 #include "asterisk/module.h"
00054 #include "asterisk/pbx.h"
00055 #include "asterisk/options.h"
00056 #include "asterisk/lock.h"
00057 #include "asterisk/sched.h"
00058 #include "asterisk/io.h"
00059 #include "asterisk/rtp.h"
00060 #include "asterisk/acl.h"
00061 #include "asterisk/callerid.h"
00062 #include "asterisk/cli.h"
00063 #include "asterisk/say.h"
00064 #include "asterisk/cdr.h"
00065 #include "asterisk/astdb.h"
00066 #include "asterisk/features.h"
00067 #include "asterisk/app.h"
00068 #include "asterisk/musiconhold.h"
00069 #include "asterisk/utils.h"
00070 #include "asterisk/dsp.h"
00071
00072
00073
00074
00075 static const char desc[] = "Skinny Client Control Protocol (Skinny)";
00076 static const char tdesc[] = "Skinny Client Control Protocol (Skinny)";
00077 static const char type[] = "Skinny";
00078 static const char config[] = "skinny.conf";
00079
00080
00081 static int capability = AST_FORMAT_ULAW;
00082
00083 #define DEFAULT_SKINNY_PORT 2000
00084 #define DEFAULT_SKINNY_BACKLOG 2
00085 #define SKINNY_MAX_PACKET 1000
00086
00087 static int keep_alive = 120;
00088 static char date_format[6] = "D-M-Y";
00089 static char version_id[16] = "P002F202";
00090
00091
00092 typedef unsigned char UINT8;
00093 typedef unsigned short UINT16;
00094 typedef unsigned int UINT32;
00095
00096 #if __BYTE_ORDER == __LITTLE_ENDIAN
00097 #define letohl(x) (x)
00098 #define letohs(x) (x)
00099 #define htolel(x) (x)
00100 #define htoles(x) (x)
00101 #else
00102 #if defined(SOLARIS) || defined(__Darwin__) || defined(__NetBSD__)
00103 #define __bswap_16(x) \
00104 ((((x) & 0xff00) >> 8) | \
00105 (((x) & 0x00ff) << 8))
00106 #define __bswap_32(x) \
00107 ((((x) & 0xff000000) >> 24) | \
00108 (((x) & 0x00ff0000) >> 8) | \
00109 (((x) & 0x0000ff00) << 8) | \
00110 (((x) & 0x000000ff) << 24))
00111 #else
00112 #include <bits/byteswap.h>
00113 #endif
00114 #define letohl(x) __bswap_32(x)
00115 #define letohs(x) __bswap_16(x)
00116 #define htolel(x) __bswap_32(x)
00117 #define htoles(x) __bswap_16(x)
00118 #endif
00119
00120
00121
00122
00123
00124
00125 #define KEEP_ALIVE_MESSAGE 0x0000
00126
00127
00128 #define REGISTER_MESSAGE 0x0001
00129 typedef struct register_message {
00130 char name[16];
00131 int userId;
00132 int instance;
00133 char ip[4];
00134 int type;
00135 int maxStreams;
00136 } register_message;
00137
00138 #define IP_PORT_MESSAGE 0x0002
00139
00140 #define KEYPAD_BUTTON_MESSAGE 0x0003
00141 typedef struct keypad_button_message {
00142 int button;
00143 } keypad_button_message;
00144
00145 #define STIMULUS_MESSAGE 0x0005
00146 typedef struct stimulus_message {
00147 int stimulus;
00148 int stimulusInstance;
00149 } stimulus_message;
00150
00151 #define OFFHOOK_MESSAGE 0x0006
00152 #define ONHOOK_MESSAGE 0x0007
00153
00154 #define CAPABILITIES_RES_MESSAGE 0x0010
00155 typedef struct station_capabilities {
00156 int codec;
00157 int frames;
00158 union {
00159 char res[8];
00160 long rate;
00161 } payloads;
00162 } station_capabilities;
00163
00164 typedef struct capabilities_res_message {
00165 int count;
00166 struct station_capabilities caps[18];
00167 } capabilities_res_message;
00168
00169 #define SPEED_DIAL_STAT_REQ_MESSAGE 0x000A
00170 typedef struct speed_dial_stat_req_message {
00171 int speedDialNumber;
00172 } speed_dial_stat_req_message;
00173
00174 #define LINE_STATE_REQ_MESSAGE 0x000B
00175 typedef struct line_state_req_message {
00176 int lineNumber;
00177 } line_state_req_message;
00178
00179 #define TIME_DATE_REQ_MESSAGE 0x000D
00180 #define VERSION_REQ_MESSAGE 0x000F
00181 #define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
00182 #define SERVER_REQUEST_MESSAGE 0x0012
00183 #define ALARM_MESSAGE 0x0020
00184
00185 #define OPEN_RECIEVE_CHANNEL_ACK_MESSAGE 0x0022
00186 typedef struct open_recieve_channel_ack_message {
00187 int status;
00188 char ipAddr[4];
00189 int port;
00190 int passThruId;
00191 } open_recieve_channel_ack_message;
00192
00193 #define SOFT_KEY_SET_REQ_MESSAGE 0x0025
00194 #define UNREGISTER_MESSAGE 0x0027
00195 #define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028
00196
00197 #define REGISTER_ACK_MESSAGE 0x0081
00198 typedef struct register_ack_message {
00199 int keepAlive;
00200 char dateTemplate[6];
00201 char res[2];
00202 int secondaryKeepAlive;
00203 char res2[4];
00204 } register_ack_message;
00205
00206 #define START_TONE_MESSAGE 0x0082
00207 typedef struct start_tone_message {
00208 int tone;
00209 } start_tone_message;
00210
00211 #define STOP_TONE_MESSAGE 0x0083
00212
00213 #define SET_RINGER_MESSAGE 0x0085
00214 typedef struct set_ringer_message {
00215 int ringerMode;
00216 } set_ringer_message;
00217
00218 #define SET_LAMP_MESSAGE 0x0086
00219 typedef struct set_lamp_message {
00220 int stimulus;
00221 int stimulusInstance;
00222 int deviceStimulus;
00223 } set_lamp_message;
00224
00225 #define SET_SPEAKER_MESSAGE 0x0088
00226 typedef struct set_speaker_message {
00227 int mode;
00228 } set_speaker_message;
00229
00230 #define START_MEDIA_TRANSMISSION_MESSAGE 0x008A
00231 typedef struct media_qualifier {
00232 int precedence;
00233 int vad;
00234 int packets;
00235 int bitRate;
00236 } media_qualifier;
00237
00238 typedef struct start_media_transmission_message {
00239 int conferenceId;
00240 int passThruPartyId;
00241 char remoteIp[4];
00242 int remotePort;
00243 int packetSize;
00244 int payloadType;
00245 media_qualifier qualifier;
00246 } start_media_transmission_message;
00247
00248 #define STOP_MEDIA_TRANSMISSION_MESSAGE 0x008B
00249 typedef struct stop_media_transmission_message {
00250 int conferenceId;
00251 int passThruPartyId;
00252 } stop_media_transmission_message;
00253
00254 #define CALL_INFO_MESSAGE 0x008F
00255 typedef struct call_info_message {
00256 char callingPartyName[40];
00257 char callingParty[24];
00258 char calledPartyName[40];
00259 char calledParty[24];
00260 int instance;
00261 int reference;
00262 int type;
00263 char originalCalledPartyName[40];
00264 char originalCalledParty[24];
00265 } call_info_message;
00266
00267 #define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
00268 typedef struct speed_dial_stat_res_message {
00269 int speedDialNumber;
00270 char speedDialDirNumber[24];
00271 char speedDialDisplayName[40];
00272 } speed_dial_stat_res_message;
00273
00274 #define LINE_STAT_RES_MESSAGE 0x0092
00275 typedef struct line_stat_res_message {
00276 int linenumber;
00277 char lineDirNumber[24];
00278 char lineDisplayName[42];
00279 int space;
00280 } line_stat_res_message;
00281
00282 #define DEFINETIMEDATE_MESSAGE 0x0094
00283 typedef struct definetimedate_message {
00284 int year;
00285 int month;
00286 int dayofweek;
00287 int day;
00288 int hour;
00289 int minute;
00290 int seconds;
00291 int milliseconds;
00292 int timestamp;
00293 } definetimedate_message;
00294
00295 #define DISPLAYTEXT_MESSAGE 0x0099
00296 typedef struct displaytext_message {
00297 char text[40];
00298 } displaytext_message;
00299
00300 #define CLEAR_DISPLAY_MESSAGE 0x009A
00301
00302 #define REGISTER_REJ_MESSAGE 0x009D
00303 typedef struct register_rej_message {
00304 char errMsg[33];
00305 } register_rej_message;
00306
00307 #define CAPABILITIES_REQ_MESSAGE 0x009B
00308
00309 #define SERVER_RES_MESSAGE 0x009E
00310 typedef struct server_identifier {
00311 char serverName[48];
00312 } server_identifier;
00313
00314 typedef struct server_res_message {
00315 server_identifier server[5];
00316 int serverListenPort[5];
00317 int serverIpAddr[5];
00318 } server_res_message;
00319
00320 #define BUTTON_TEMPLATE_RES_MESSAGE 0x0097
00321
00322 typedef struct buttondefinition {
00323 UINT8 instanceNumber;
00324 UINT8 buttonDefinition;
00325 } button_definition;
00326
00327 #define STIMULUS_REDIAL 0x01
00328 #define STIMULUS_SPEEDDIAL 0x02
00329 #define STIMULUS_HOLD 0x03
00330 #define STIMULUS_TRANSFER 0x04
00331 #define STIMULUS_FORWARDALL 0x05
00332 #define STIMULUS_FORWARDBUSY 0x06
00333 #define STIMULUS_FORWARDNOANSWER 0x07
00334 #define STIMULUS_DISPLAY 0x08
00335 #define STIMULUS_LINE 0x09
00336 #define STIMULUS_VOICEMAIL 0x0F
00337 #define STIMULUS_AUTOANSWER 0x11
00338 #define STIMULUS_CONFERENCE 0x7D
00339 #define STIMULUS_CALLPARK 0x7E
00340 #define STIMULUS_CALLPICKUP 0x7F
00341 #define STIMULUS_NONE 0xFF
00342
00343 button_definition button_def_30vip[] = {
00344 { 1, STIMULUS_LINE },
00345 { 2, STIMULUS_LINE },
00346 { 3, STIMULUS_LINE },
00347 { 4, STIMULUS_LINE },
00348 { 1, STIMULUS_CALLPARK },
00349 { 0, STIMULUS_NONE },
00350 { 1, STIMULUS_SPEEDDIAL },
00351 { 2, STIMULUS_SPEEDDIAL },
00352 { 3, STIMULUS_SPEEDDIAL },
00353 { 4, STIMULUS_SPEEDDIAL },
00354 { 5, STIMULUS_SPEEDDIAL },
00355 { 6, STIMULUS_SPEEDDIAL },
00356 { 1, STIMULUS_VOICEMAIL },
00357 { 1, STIMULUS_FORWARDALL },
00358 { 1, STIMULUS_CONFERENCE },
00359 { 0, STIMULUS_NONE },
00360 { 0, STIMULUS_NONE },
00361 { 0, STIMULUS_NONE },
00362 { 0, STIMULUS_NONE },
00363 { 0, STIMULUS_NONE },
00364 { 7, STIMULUS_SPEEDDIAL },
00365 { 8, STIMULUS_SPEEDDIAL },
00366 { 9, STIMULUS_SPEEDDIAL },
00367 { 10, STIMULUS_SPEEDDIAL }
00368 };
00369
00370 button_definition button_def_12sp[] = {
00371 { 1, STIMULUS_LINE },
00372 { 1, STIMULUS_LINE },
00373 { 1, STIMULUS_SPEEDDIAL },
00374 { 2, STIMULUS_SPEEDDIAL },
00375 { 3, STIMULUS_SPEEDDIAL },
00376 { 4, STIMULUS_SPEEDDIAL },
00377 { 1, STIMULUS_VOICEMAIL },
00378 { 5, STIMULUS_SPEEDDIAL },
00379 { 6, STIMULUS_SPEEDDIAL },
00380 { 7, STIMULUS_SPEEDDIAL },
00381 { 8, STIMULUS_SPEEDDIAL },
00382 { 9, STIMULUS_SPEEDDIAL }
00383 };
00384
00385 button_definition button_def_7902[] = {
00386 { 1, STIMULUS_LINE },
00387 { 1, STIMULUS_HOLD },
00388 { 1, STIMULUS_TRANSFER },
00389 { 1, STIMULUS_DISPLAY },
00390 { 1, STIMULUS_VOICEMAIL },
00391 { 1, STIMULUS_CONFERENCE },
00392 { 1, STIMULUS_FORWARDALL },
00393 { 1, STIMULUS_SPEEDDIAL },
00394 { 2, STIMULUS_SPEEDDIAL },
00395 { 3, STIMULUS_SPEEDDIAL },
00396 { 4, STIMULUS_SPEEDDIAL },
00397 { 1, STIMULUS_REDIAL }
00398 };
00399
00400 button_definition button_def_7910[] = {
00401 { 1, STIMULUS_LINE },
00402 { 1, STIMULUS_HOLD },
00403 { 1, STIMULUS_TRANSFER },
00404 { 1, STIMULUS_DISPLAY },
00405 { 1, STIMULUS_VOICEMAIL },
00406 { 1, STIMULUS_CONFERENCE },
00407 { 1, STIMULUS_FORWARDALL },
00408 { 1, STIMULUS_SPEEDDIAL },
00409 { 2, STIMULUS_SPEEDDIAL },
00410 { 1, STIMULUS_REDIAL }
00411 };
00412
00413 button_definition button_def_7920[] = {
00414 { 1, STIMULUS_LINE },
00415 { 2, STIMULUS_LINE },
00416 { 1, STIMULUS_SPEEDDIAL },
00417 { 2, STIMULUS_SPEEDDIAL },
00418 { 3, STIMULUS_SPEEDDIAL },
00419 { 4, STIMULUS_SPEEDDIAL }
00420 };
00421
00422 button_definition button_def_7935[] = {
00423 { 1, STIMULUS_LINE },
00424 { 2, STIMULUS_LINE }
00425 };
00426
00427 button_definition button_def_7940[] = {
00428 { 1, STIMULUS_LINE },
00429 { 2, STIMULUS_LINE }
00430 };
00431
00432 button_definition button_def_7960[] = {
00433 { 1, STIMULUS_LINE },
00434 { 2, STIMULUS_LINE },
00435 { 3, STIMULUS_LINE },
00436 { 1, STIMULUS_SPEEDDIAL },
00437 { 2, STIMULUS_SPEEDDIAL },
00438 { 3, STIMULUS_SPEEDDIAL }
00439 };
00440
00441 button_definition button_def_7970[] = {
00442 { 1, STIMULUS_LINE },
00443 { 2, STIMULUS_LINE },
00444 { 3, STIMULUS_LINE },
00445 { 1, STIMULUS_SPEEDDIAL },
00446 { 2, STIMULUS_SPEEDDIAL },
00447 { 3, STIMULUS_SPEEDDIAL },
00448 { 4, STIMULUS_SPEEDDIAL },
00449 { 5, STIMULUS_SPEEDDIAL }
00450 };
00451
00452 button_definition button_def_none = { 0, STIMULUS_NONE };
00453
00454 typedef struct button_defs {
00455 char *type;
00456 int num_buttons;
00457 button_definition *button_def;
00458 } button_defs_t;
00459
00460 button_defs_t button_defs[] = {
00461 { "12SP", 12, button_def_12sp },
00462
00463 { "30VIP", 26, button_def_30vip },
00464 { "7902", 12, button_def_7902 },
00465 { "7910", 10, button_def_7910 },
00466 { "7920", 6, button_def_7920 },
00467 { "7935", 2, button_def_7935 },
00468 { "7940", 2, button_def_7940 },
00469 { "7960", 6, button_def_7960 },
00470 { "7970", 8, button_def_7970 },
00471 { NULL, 0, NULL }
00472 };
00473
00474 typedef struct button_template_res_message {
00475 UINT32 buttonOffset;
00476 UINT32 buttonCount;
00477 UINT32 totalButtonCount;
00478 button_definition definition[42];
00479 } button_template_res_message;
00480
00481 #define VERSION_RES_MESSAGE 0x0098
00482 typedef struct version_res_message {
00483 char version[16];
00484 } version_res_message;
00485
00486 #define KEEP_ALIVE_ACK_MESSAGE 0x0100
00487
00488 #define OPEN_RECIEVE_CHANNEL_MESSAGE 0x0105
00489 typedef struct open_recieve_channel_message {
00490 int conferenceId;
00491 int partyId;
00492 int packets;
00493 int capability;
00494 int echo;
00495 int bitrate;
00496 } open_recieve_channel_message;
00497
00498 #define CLOSE_RECIEVE_CHANNEL_MESSAGE 0x0106
00499 typedef struct close_recieve_channel_message {
00500 int conferenceId;
00501 int partyId;
00502 } close_recieve_channel_message;
00503
00504 #define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108
00505
00506 typedef struct soft_key_template_definition {
00507 char softKeyLabel[16];
00508 int softKeyEvent;
00509 } soft_key_template_definition;
00510
00511 soft_key_template_definition soft_key_template_default[] = {
00512 { "Redial", 1 },
00513 { "NewCall", 2 },
00514 { "Hold", 3 },
00515 { "Trnsfer", 4 },
00516 { "CFwdAll", 5 },
00517 { "CFwdBusy", 6 },
00518 { "CFwdNoAnswer", 7 },
00519 { "<<", 8 },
00520 { "EndCall", 9 },
00521 { "Resume", 10 },
00522 { "Answer", 11 },
00523 { "Info", 12 },
00524 { "Confrn", 13 },
00525 { "Park", 14 },
00526 { "Join", 15 },
00527 { "MeetMe", 16 },
00528 { "PickUp", 17 },
00529 { "GPickUp", 18 },
00530 };
00531
00532 typedef struct soft_key_template {
00533 int softKeyOffset;
00534 int softKeyCount;
00535 int totalSoftKeyCount;
00536 soft_key_template_definition softKeyTemplateDefinition[32];
00537 } soft_key_template;
00538
00539 #define SOFT_KEY_SET_RES_MESSAGE 0x0109
00540 static const char *soft_key_set_hack = {
00541 "\x01\x02\x05\x03\x09\x0a\x0b\x10\x11\x12\x04\x0e\x0d\x00\x00\x00"
00542 "\x2d\x01\x2e\x01\x31\x01\x2f\x01\x35\x01\x36\x01\x37\x01\x3c\x01"
00543 "\x3d\x01\x3e\x01\x30\x01\x3a\x01\x39\x01\x00\x00\x00\x00\x00\x00"
00544 "\x03\x09\x04\x0e\x0d\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00545 "\x2f\x01\x35\x01\x30\x01\x3a\x01\x39\x01\x3f\x01\x00\x00\x00\x00"
00546 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00547 "\x0a\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00548 "\x36\x01\x2e\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00549 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00550 "\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00551 "\x37\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00552 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00553 "\x01\x09\x05\x10\x11\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00554 "\x2d\x01\x35\x01\x31\x01\x3c\x01\x3d\x01\x3e\x01\x00\x00\x00\x00"
00555 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00556 "\x00\x09\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00557 "\x00\x00\x35\x01\x30\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00558 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00559 "\x08\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00560 "\x34\x01\x35\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00561 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00562 "\x00\x09\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00563 "\x00\x00\x35\x01\x39\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00564 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00565 "\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00566 "\x00\x00\x35\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00567 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00568 "\x01\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00569 "\x2d\x01\x35\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00570 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00571 "\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00572 "\x41\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00573 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
00574 };
00575
00576 typedef struct soft_key_set_definition {
00577 UINT8 softKeyTemplateIndex[16];
00578 UINT16 softKeyInfoIndex[16];
00579 } soft_key_set_definition;
00580
00581 typedef struct soft_key_sets {
00582 UINT32 softKeySetOffset;
00583 UINT32 softKeySetCount;
00584 UINT32 totalSoftKeySetCount;
00585 soft_key_set_definition softKeySetDefinition[16];
00586 UINT32 res;
00587 } soft_key_sets;
00588
00589 #define SELECT_SOFT_KEYS_MESSAGE 0x0110
00590 typedef struct select_soft_keys_message {
00591 int instance;
00592 int reference;
00593 int softKeySetIndex;
00594 int validKeyMask;
00595 } select_soft_keys_message;
00596
00597 #define CALL_STATE_MESSAGE 0x0111
00598 typedef struct call_state_message {
00599 int callState;
00600 int lineInstance;
00601 int callReference;
00602 } call_state_message;
00603
00604 #define DISPLAY_PROMPT_STATUS_MESSAGE 0x0112
00605 typedef struct display_prompt_status_message {
00606 int messageTimeout;
00607 char promptMessage[32];
00608 int lineInstance;
00609 int callReference;
00610 } display_prompt_status_message;
00611
00612 #define DISPLAY_NOTIFY_MESSAGE 0x0114
00613 typedef struct display_notify_message {
00614 int displayTimeout;
00615 char displayMessage[100];
00616 } display_notify_message;
00617
00618 #define ACTIVATE_CALL_PLANE_MESSAGE 0x0116
00619 typedef struct activate_call_plane_message {
00620 int lineInstance;
00621 } activate_call_plane_message;
00622
00623 #define DIALLED_NUMBER_MESSAGE 0x011D
00624 typedef struct dialled_number_message {
00625 char dialledNumber[24];
00626 int lineInstance;
00627 int callReference;
00628 } dialled_number_message;
00629
00630
00631 typedef struct {
00632 int len;
00633 int res;
00634 int e;
00635 union {
00636 speed_dial_stat_req_message speeddialreq;
00637 register_message reg;
00638 register_ack_message regack;
00639 register_rej_message regrej;
00640 capabilities_res_message caps;
00641 version_res_message version;
00642 button_template_res_message buttontemplate;
00643 displaytext_message displaytext;
00644 display_prompt_status_message displaypromptstatus;
00645 definetimedate_message definetimedate;
00646 start_tone_message starttone;
00647 speed_dial_stat_res_message speeddial;
00648 line_state_req_message line;
00649 line_stat_res_message linestat;
00650 soft_key_sets softkeysets;
00651 soft_key_template softkeytemplate;
00652 server_res_message serverres;
00653 set_lamp_message setlamp;
00654 set_ringer_message setringer;
00655 call_state_message callstate;
00656 keypad_button_message keypad;
00657 select_soft_keys_message selectsoftkey;
00658 activate_call_plane_message activatecallplane;
00659 stimulus_message stimulus;
00660 set_speaker_message setspeaker;
00661 call_info_message callinfo;
00662 start_media_transmission_message startmedia;
00663 stop_media_transmission_message stopmedia;
00664 open_recieve_channel_message openrecievechannel;
00665 open_recieve_channel_ack_message openrecievechannelack;
00666 close_recieve_channel_message closerecievechannel;
00667 display_notify_message displaynotify;
00668 dialled_number_message diallednumber;
00669 } data;
00670 } skinny_req;
00671
00672
00673
00674
00675
00676 static int skinnydebug = 1;
00677
00678
00679 static struct sockaddr_in bindaddr;
00680 static char ourhost[256];
00681 static int ourport;
00682 static struct in_addr __ourip;
00683 struct ast_hostent ahp; struct hostent *hp;
00684 static int skinnysock = -1;
00685 static pthread_t tcp_thread;
00686 static pthread_t accept_t;
00687 static char context[AST_MAX_CONTEXT] = "default";
00688 static char language[MAX_LANGUAGE] = "";
00689 static char musicclass[MAX_MUSICCLASS] = "";
00690 static char cid_num[AST_MAX_EXTENSION] = "";
00691 static char cid_name[AST_MAX_EXTENSION] = "";
00692 static char linelabel[AST_MAX_EXTENSION] ="";
00693 static int nat = 0;
00694 static ast_group_t cur_callergroup = 0;
00695 static ast_group_t cur_pickupgroup = 0;
00696 static int immediate = 0;
00697 static int callwaiting = 0;
00698 static int callreturn = 0;
00699 static int threewaycalling = 0;
00700 static int mwiblink = 0;
00701
00702 static int transfer = 0;
00703 static int cancallforward = 0;
00704
00705 static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
00706 static char mailbox[AST_MAX_EXTENSION];
00707 static int amaflags = 0;
00708 static int callnums = 1;
00709
00710 #define SUB_REAL 0
00711 #define SUB_ALT 1
00712 #define MAX_SUBS 2
00713
00714 #define SKINNY_SPEAKERON 1
00715 #define SKINNY_SPEAKEROFF 2
00716
00717 #define SKINNY_OFFHOOK 1
00718 #define SKINNY_ONHOOK 2
00719 #define SKINNY_RINGOUT 3
00720 #define SKINNY_RINGIN 4
00721 #define SKINNY_CONNECTED 5
00722 #define SKINNY_BUSY 6
00723 #define SKINNY_CONGESTION 7
00724 #define SKINNY_HOLD 8
00725 #define SKINNY_CALLWAIT 9
00726 #define SKINNY_TRANSFER 10
00727 #define SKINNY_PARK 11
00728 #define SKINNY_PROGRESS 12
00729 #define SKINNY_INVALID 14
00730
00731 #define SKINNY_SILENCE 0x00
00732 #define SKINNY_DIALTONE 0x21
00733 #define SKINNY_BUSYTONE 0x23
00734 #define SKINNY_ALERT 0x24
00735 #define SKINNY_REORDER 0x25
00736 #define SKINNY_CALLWAITTONE 0x2D
00737 #define SKINNY_NOTONE 0x7F
00738
00739 #define SKINNY_LAMP_OFF 1
00740 #define SKINNY_LAMP_ON 2
00741 #define SKINNY_LAMP_WINK 3
00742 #define SKINNY_LAMP_FLASH 4
00743 #define SKINNY_LAMP_BLINK 5
00744
00745 #define SKINNY_RING_OFF 1
00746 #define SKINNY_RING_INSIDE 2
00747 #define SKINNY_RING_OUTSIDE 3
00748 #define SKINNY_RING_FEATURE 4
00749
00750 #define TYPE_TRUNK 1
00751 #define TYPE_LINE 2
00752
00753
00754 #define SKINNY_CX_SENDONLY 0
00755 #define SKINNY_CX_RECVONLY 1
00756 #define SKINNY_CX_SENDRECV 2
00757 #define SKINNY_CX_CONF 3
00758 #define SKINNY_CX_CONFERENCE 3
00759 #define SKINNY_CX_MUTE 4
00760 #define SKINNY_CX_INACTIVE 4
00761
00762 #if 0
00763 static char *skinny_cxmodes[] = {
00764 "sendonly",
00765 "recvonly",
00766 "sendrecv",
00767 "confrnce",
00768 "inactive"
00769 };
00770 #endif
00771
00772
00773 static struct sched_context *sched;
00774 static struct io_context *io;
00775
00776
00777 static int usecnt = 0;
00778 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
00779
00780
00781
00782 AST_MUTEX_DEFINE_STATIC(monlock);
00783
00784 AST_MUTEX_DEFINE_STATIC(netlock);
00785
00786 AST_MUTEX_DEFINE_STATIC(sessionlock);
00787
00788 AST_MUTEX_DEFINE_STATIC(devicelock);
00789 #if 0
00790
00791 AST_MUTEX_DEFINE_STATIC(pagingdevicelock);
00792 #endif
00793
00794
00795
00796 static pthread_t monitor_thread = AST_PTHREADT_NULL;
00797
00798
00799 static int firstdigittimeout = 16000;
00800
00801
00802 static int gendigittimeout = 8000;
00803
00804
00805 static int matchdigittimeout = 3000;
00806
00807 struct skinny_subchannel {
00808 ast_mutex_t lock;
00809 unsigned int callid;
00810 struct ast_channel *owner;
00811 struct skinny_line *parent;
00812 struct ast_rtp *rtp;
00813 time_t lastouttime;
00814 int progress;
00815 int ringing;
00816 int lastout;
00817 int cxmode;
00818 int nat;
00819 int outgoing;
00820 int alreadygone;
00821 struct skinny_subchannel *next;
00822 };
00823
00824 struct skinny_line {
00825 ast_mutex_t lock;
00826 char name[80];
00827 char label[42];
00828 struct skinny_subchannel *sub;
00829 char accountcode[AST_MAX_ACCOUNT_CODE];
00830 char exten[AST_MAX_EXTENSION];
00831 char context[AST_MAX_CONTEXT];
00832 char language[MAX_LANGUAGE];
00833 char cid_num[AST_MAX_EXTENSION];
00834 char cid_name[AST_MAX_EXTENSION];
00835 char lastcallerid[AST_MAX_EXTENSION];
00836 char call_forward[AST_MAX_EXTENSION];
00837 char mailbox[AST_MAX_EXTENSION];
00838 char musicclass[MAX_MUSICCLASS];
00839 int curtone;
00840 ast_group_t callgroup;
00841 ast_group_t pickupgroup;
00842 int callwaiting;
00843 int transfer;
00844 int threewaycalling;
00845 int mwiblink;
00846 int cancallforward;
00847 int callreturn;
00848 int dnd;
00849 int hascallerid;
00850 int hidecallerid;
00851 int amaflags;
00852 int type;
00853 int instance;
00854 int group;
00855 int needdestroy;
00856 int capability;
00857 int nonCodecCapability;
00858 int onhooktime;
00859 int msgstate;
00860 int immediate;
00861 int hookstate;
00862 int progress;
00863 struct skinny_line *next;
00864 struct skinny_device *parent;
00865 };
00866
00867 static struct skinny_device {
00868
00869 char name[80];
00870 char id[16];
00871 char version_id[16];
00872 int type;
00873 int registered;
00874 char model[6];
00875 struct sockaddr_in addr;
00876 struct in_addr ourip;
00877 struct skinny_line *lines;
00878 struct ast_ha *ha;
00879 struct skinnysession *session;
00880 struct skinny_device *next;
00881 } *devices = NULL;
00882
00883 struct skinny_paging_device {
00884 char name[80];
00885 char id[16];
00886 struct skinny_device ** devices;
00887 struct skinny_paging_device *next;
00888 };
00889
00890 static struct skinnysession {
00891 pthread_t t;
00892 ast_mutex_t lock;
00893 struct sockaddr_in sin;
00894 int fd;
00895 char inbuf[SKINNY_MAX_PACKET];
00896 struct skinny_device *device;
00897 struct skinnysession *next;
00898 } *sessions = NULL;
00899
00900 static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause);
00901 static int skinny_call(struct ast_channel *ast, char *dest, int timeout);
00902 static int skinny_hangup(struct ast_channel *ast);
00903 static int skinny_answer(struct ast_channel *ast);
00904 static struct ast_frame *skinny_read(struct ast_channel *ast);
00905 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame);
00906 static int skinny_indicate(struct ast_channel *ast, int ind);
00907 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00908 static int skinny_senddigit(struct ast_channel *ast, char digit);
00909
00910 static const struct ast_channel_tech skinny_tech = {
00911 .type = type,
00912 .description = tdesc,
00913 .capabilities = AST_FORMAT_ULAW,
00914 .properties = AST_CHAN_TP_WANTSJITTER,
00915 .requester = skinny_request,
00916 .call = skinny_call,
00917 .hangup = skinny_hangup,
00918 .answer = skinny_answer,
00919 .read = skinny_read,
00920 .write = skinny_write,
00921 .indicate = skinny_indicate,
00922 .fixup = skinny_fixup,
00923 .send_digit = skinny_senddigit,
00924
00925 };
00926
00927 static skinny_req *req_alloc(size_t size)
00928 {
00929 skinny_req *req;
00930 req = malloc(size+12);
00931 if (!req) {
00932 return NULL;
00933 }
00934 memset(req, 0, size+12);
00935 return req;
00936 }
00937
00938 static struct skinny_subchannel *find_subchannel_by_line(struct skinny_line *l)
00939 {
00940
00941 struct skinny_subchannel *sub = l->sub;
00942 return sub;
00943 }
00944
00945 static struct skinny_subchannel *find_subchannel_by_name(char *dest)
00946 {
00947 struct skinny_line *l;
00948 struct skinny_device *d;
00949 char line[256];
00950 char *at;
00951 char *device;
00952
00953 strncpy(line, dest, sizeof(line) - 1);
00954 at = strchr(line, '@');
00955 if (!at) {
00956 ast_log(LOG_NOTICE, "Device '%s' has no @ (at) sign!\n", dest);
00957 return NULL;
00958 }
00959 *at = '\0';
00960 at++;
00961 device = at;
00962 ast_mutex_lock(&devicelock);
00963 d = devices;
00964 while(d) {
00965 if (!strcasecmp(d->name, device)) {
00966 if (skinnydebug) {
00967 ast_verbose("Found device: %s\n", d->name);
00968 }
00969
00970 l = d->lines;
00971 while (l) {
00972
00973 if (!strcasecmp(l->name, line)) {
00974 ast_mutex_unlock(&devicelock);
00975 return l->sub;
00976 }
00977 l = l->next;
00978 }
00979 }
00980 d = d->next;
00981 }
00982
00983 ast_mutex_unlock(&devicelock);
00984 return NULL;
00985 }
00986
00987 static int transmit_response(struct skinnysession *s, skinny_req *req)
00988 {
00989 int res = 0;
00990 ast_mutex_lock(&s->lock);
00991
00992 #if 0
00993 if (skinnydebug) {
00994 ast_verbose("writing packet type %04X (%d bytes) to socket %d\n", letohl(req->e), letohl(req->len)+8, s->fd);
00995 }
00996 #endif
00997
00998 res = write(s->fd, req, letohl(req->len)+8);
00999 if (res != letohl(req->len)+8) {
01000 ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, letohl(req->len)+8, strerror(errno));
01001 }
01002 ast_mutex_unlock(&s->lock);
01003 return 1;
01004 }
01005
01006
01007 static int convert_cap(int capability)
01008 {
01009 return 4;
01010
01011 }
01012
01013 static void transmit_speaker_mode(struct skinnysession *s, int mode)
01014 {
01015 skinny_req *req;
01016
01017 req = req_alloc(sizeof(struct set_speaker_message));
01018 if (!req) {
01019 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
01020 return;
01021 }
01022 req->len = htolel(sizeof(set_speaker_message)+4);
01023 req->e = htolel(SET_SPEAKER_MESSAGE);
01024 req->data.setspeaker.mode = htolel(mode);
01025 transmit_response(s, req);
01026 }
01027
01028 static void transmit_callstate(struct skinnysession *s, int instance, int state, unsigned callid)
01029 {
01030 skinny_req *req;
01031 int memsize = sizeof(struct call_state_message);
01032
01033 req = req_alloc(memsize);
01034 if (!req) {
01035 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
01036 return;
01037 }
01038 if (state == SKINNY_ONHOOK) {
01039 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
01040 }
01041 req->len = htolel(sizeof(call_state_message)+4);
01042 req->e = htolel(CALL_STATE_MESSAGE);
01043 req->data.callstate.callState = htolel(state);
01044 req->data.callstate.lineInstance = htolel(instance);
01045 req->data.callstate.callReference = htolel(callid);
01046 transmit_response(s, req);
01047 if (state == SKINNY_OFFHOOK) {
01048 memset(req, 0, memsize);
01049 req->len = htolel(sizeof(activate_call_plane_message)+4);
01050 req->e = htolel(ACTIVATE_CALL_PLANE_MESSAGE);
01051 req->data.activatecallplane.lineInstance = htolel(instance);
01052 transmit_response(s, req);
01053 } else if (state == SKINNY_ONHOOK) {
01054 memset(req, 0, memsize);
01055 req->len = htolel(sizeof(activate_call_plane_message)+4);
01056 req->e = htolel(ACTIVATE_CALL_PLANE_MESSAGE);
01057 req->data.activatecallplane.lineInstance = 0;
01058 transmit_response(s, req);
01059 memset(req, 0, memsize);
01060 req->len = htolel(sizeof(close_recieve_channel_message)+4);
01061 req->e = htolel(CLOSE_RECIEVE_CHANNEL_MESSAGE);
01062 req->data.closerecievechannel.conferenceId = 0;
01063 req->data.closerecievechannel.partyId = 0;
01064 transmit_response(s, req);
01065 memset(req, 0, memsize);
01066 req->len = htolel(sizeof(stop_media_transmission_message)+4);
01067 req->e = htolel(STOP_MEDIA_TRANSMISSION_MESSAGE);
01068 req->data.stopmedia.conferenceId = 0;
01069 req->data.stopmedia.passThruPartyId = 0;
01070 transmit_response(s, req);
01071 }
01072 }
01073
01074 static void transmit_callinfo(struct skinnysession *s, char *fromname, char *fromnum, char *toname, char *tonum, int instance, int callid, int calltype)
01075 {
01076 skinny_req *req;
01077
01078 req = req_alloc(sizeof(struct call_info_message));
01079 if (!req) {
01080 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
01081 return;
01082 }
01083
01084 req->len = htolel(sizeof(struct call_info_message));
01085 req->e = htolel(CALL_INFO_MESSAGE);
01086
01087 if (fromname) {
01088 ast_copy_string(req->data.callinfo.callingPartyName, fromname, sizeof(req->data.callinfo.callingPartyName));
01089 }
01090 if (fromnum) {
01091 ast_copy_string(req->data.callinfo.callingParty, fromnum, sizeof(req->data.callinfo.callingParty));
01092 }
01093 if (toname) {
01094 ast_copy_string(req->data.callinfo.calledPartyName, toname, sizeof(req->data.callinfo.calledPartyName));
01095 }
01096 if (tonum) {
01097 ast_copy_string(req->data.callinfo.calledParty, tonum, sizeof(req->data.callinfo.calledParty));
01098 }
01099 req->data.callinfo.instance = htolel(instance);
01100 req->data.callinfo.reference = htolel(callid);
01101 req->data.callinfo.type = htolel(calltype);
01102 transmit_response(s, req);
01103 }
01104
01105 static void transmit_connect(struct skinnysession *s)
01106 {
01107 skinny_req *req;
01108 struct skinny_line *l = s->device->lines;
01109
01110 req = req_alloc(sizeof(struct open_recieve_channel_message));
01111 if (!req) {
01112 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
01113 return;
01114 }
01115 req->len = htolel(sizeof(struct open_recieve_channel_message));
01116 req->e = htolel(OPEN_RECIEVE_CHANNEL_MESSAGE);
01117 req->data.openrecievechannel.conferenceId = 0;
01118 req->data.openrecievechannel.partyId = 0;
01119 req->data.openrecievechannel.packets = htolel(20);
01120 req->data.openrecievechannel.capability = htolel(convert_cap(l->capability));
01121 req->data.openrecievechannel.echo = 0;
01122 req->data.openrecievechannel.bitrate = 0;
01123 transmit_response(s, req);
01124 }
01125
01126 static void transmit_tone(struct skinnysession *s, int tone)
01127 {
01128 skinny_req *req;
01129
01130 if (tone > 0) {
01131 req = req_alloc(sizeof(struct start_tone_message));
01132 } else {
01133 req = req_alloc(4);
01134 }
01135 if (!req) {
01136 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
01137 return;
01138 }
01139 if (tone > 0) {
01140 req->len = htolel(sizeof(start_tone_message)+4);
01141 req->e = htolel(START_TONE_MESSAGE);
01142 req->data.starttone.tone = htolel(tone);
01143 } else {
01144 req->len = htolel(4);
01145 req->e = htolel(STOP_TONE_MESSAGE);
01146 }
01147 transmit_response(s, req);
01148 }
01149
01150 #if 0
01151
01152 static void transmit_selectsoftkeys(struct skinnysession *s, int instance, int callid, int softkey)
01153 {
01154 skinny_req *req;
01155 int memsize = sizeof(struct select_soft_keys_message);
01156
01157 req = req_alloc(memsize);
01158 if (!req) {
01159 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
01160 return;
01161 }
01162 memset(req, 0, memsize);
01163 req->len = htolel(sizeof(select_soft_keys_message)+4);
01164 req->e = htolel(SELECT_SOFT_KEYS_MESSAGE);
01165 req->data.selectsoftkey.instance = htolel(instance);
01166 req->data.selectsoftkey.reference = htolel(callid);
01167 req->data.selectsoftkey.softKeySetIndex = htolel(softkey);
01168 transmit_response(s, req);
01169 }
01170 #endif
01171
01172 static void transmit_lamp_indication(struct skinnysession *s, int stimulus, int instance, int indication)
01173 {
01174 skinny_req *req;
01175
01176 req = req_alloc(sizeof(struct set_lamp_message));
01177 if (!req) {
01178 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
01179 return;
01180 }
01181 req->len = htolel(sizeof(set_lamp_message)+4);
01182 req->e = htolel(SET_LAMP_MESSAGE);
01183 req->data.setlamp.stimulus = htolel(stimulus);
01184 req->data.setlamp.stimulusInstance = htolel(instance);
01185 req->data.setlamp.deviceStimulus = htolel(indication);
01186 transmit_response(s, req);
01187 }
01188
01189 static void transmit_ringer_mode(struct skinnysession *s, int mode)
01190 {
01191 skinny_req *req;
01192
01193 req = req_alloc(sizeof(struct set_ringer_message));
01194 if (!req) {
01195 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
01196 return;
01197 }
01198 req->len = htolel(sizeof(set_ringer_message)+4);
01199 req->e = htolel(SET_RINGER_MESSAGE);
01200 req->data.setringer.ringerMode = htolel(mode);
01201 transmit_response(s, req);
01202 }
01203
01204 static void transmit_displaymessage(struct skinnysession *s, char *text)
01205 {
01206 skinny_req *req;
01207
01208 if (text == 0) {
01209 req = req_alloc(4);
01210 req->len = htolel(4);
01211 req->e = htolel(CLEAR_DISPLAY_MESSAGE);
01212 } else {
01213 req = req_alloc(sizeof(struct displaytext_message));
01214
01215 strncpy(req->data.displaytext.text, text, sizeof(req->data.displaytext.text)-1);
01216 req->len = htolel(sizeof(displaytext_message) + 4);
01217 req->e = htolel(DISPLAYTEXT_MESSAGE);
01218 if (skinnydebug) {
01219 ast_verbose("Displaying message '%s'\n", req->data.displaytext.text);
01220 }
01221 }
01222
01223 if (!req) {
01224 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
01225 return;
01226 }
01227 transmit_response(s, req);
01228 }
01229
01230 static void transmit_displaynotify(struct skinnysession *s, char *text, int t)
01231 {
01232 skinny_req *req;
01233
01234 req = req_alloc(sizeof(struct display_notify_message));
01235
01236 if (!req) {
01237 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
01238 return;
01239 }
01240
01241 req->e = htolel(DISPLAY_NOTIFY_MESSAGE);
01242 req->len = htolel(sizeof(display_notify_message) + 4);
01243 strncpy(req->data.displaynotify.displayMessage, text, sizeof(req->data.displaynotify.displayMessage)-1);
01244 req->data.displaynotify.displayTimeout = htolel(t);
01245
01246 if (skinnydebug) {
01247 ast_verbose("Displaying notify '%s'\n", text);
01248 }
01249
01250 transmit_response(s, req);
01251 }
01252
01253 static void transmit_displaypromptstatus(struct skinnysession *s, char *text, int t, int instance, int callid)
01254 {
01255 skinny_req *req;
01256
01257 req = req_alloc(sizeof(struct display_prompt_status_message));
01258
01259 if (!req) {
01260 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
01261 return;
01262 }
01263
01264 req->e = htolel(DISPLAY_PROMPT_STATUS_MESSAGE);
01265 req->len = htolel(sizeof(display_prompt_status_message) + 4);
01266 strncpy(req->data.displaypromptstatus.promptMessage, text, sizeof(req->data.displaypromptstatus.promptMessage)-1);
01267 req->data.displaypromptstatus.messageTimeout = htolel(t);
01268 req->data.displaypromptstatus.lineInstance = htolel(instance);
01269 req->data.displaypromptstatus.callReference = htolel(callid);
01270
01271 if (skinnydebug) {
01272 ast_verbose("Displaying Prompt Status '%s'\n", text);
01273 }
01274
01275 transmit_response(s, req);
01276 }
01277
01278 static void transmit_diallednumber(struct skinnysession *s, char *text, int instance, int callid)
01279 {
01280 skinny_req *req;
01281
01282 req = req_alloc(sizeof(struct dialled_number_message));
01283
01284 if (!req) {
01285 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
01286 return;
01287 }
01288
01289 req->e = htolel(DIALLED_NUMBER_MESSAGE);
01290 req->len = htolel(sizeof(dialled_number_message) + 4);
01291 strncpy(req->data.diallednumber.dialledNumber, text, sizeof(req->data.diallednumber.dialledNumber)-1);
01292 req->data.diallednumber.lineInstance = htolel(instance);
01293 req->data.diallednumber.callReference = htolel(callid);
01294
01295 transmit_response(s, req);
01296 }
01297
01298 static int has_voicemail(struct skinny_line *l)
01299 {
01300 return ast_app_has_voicemail(l->mailbox, NULL);
01301 }
01302
01303
01304 static void do_housekeeping(struct skinnysession *s)
01305 {
01306 int new;
01307 int old;
01308 struct skinny_subchannel *sub;
01309 struct skinny_line *l = s->device->lines;
01310
01311 sub = find_subchannel_by_line(l);
01312 transmit_displaymessage(s, NULL);
01313
01314 if (has_voicemail(sub->parent)) {
01315 if (skinnydebug) {
01316 ast_verbose("Checking for voicemail Skinny %s@%s\n", sub->parent->name, sub->parent->parent->name);
01317 }
01318 ast_app_messagecount(sub->parent->mailbox, &new, &old);
01319 if (skinnydebug) {
01320 ast_verbose("Skinny %s@%s has voicemail!\n", sub->parent->name, sub->parent->parent->name);
01321 }
01322 transmit_lamp_indication(s, STIMULUS_VOICEMAIL, l->instance, l->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON);
01323 } else {
01324 transmit_lamp_indication(s, STIMULUS_VOICEMAIL, l->instance, SKINNY_LAMP_OFF);
01325 }
01326
01327 }
01328
01329
01330
01331 static struct ast_rtp *skinny_get_vrtp_peer(struct ast_channel *chan)
01332 {
01333 return NULL;
01334 }
01335
01336 static struct ast_rtp *skinny_get_rtp_peer(struct ast_channel *chan)
01337 {
01338 struct skinny_subchannel *sub;
01339 sub = chan->tech_pvt;
01340 if (sub && sub->rtp) {
01341 return sub->rtp;
01342 }
01343 return NULL;
01344 }
01345
01346 static int skinny_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
01347 {
01348 struct skinny_subchannel *sub;
01349 sub = chan->tech_pvt;
01350 if (sub) {
01351
01352 return 0;
01353 }
01354 return -1;
01355 }
01356
01357 static struct ast_rtp_protocol skinny_rtp = {
01358 .type = type,
01359 .get_rtp_info = skinny_get_rtp_peer,
01360 .get_vrtp_info = skinny_get_vrtp_peer,
01361 .set_rtp_peer = skinny_set_rtp_peer,
01362 };
01363
01364 static int skinny_do_debug(int fd, int argc, char *argv[])
01365 {
01366 if (argc != 2) {
01367 return RESULT_SHOWUSAGE;
01368 }
01369 skinnydebug = 1;
01370 ast_cli(fd, "Skinny Debugging Enabled\n");
01371 return RESULT_SUCCESS;
01372 }
01373
01374 static int skinny_no_debug(int fd, int argc, char *argv[])
01375 {
01376 if (argc != 3) {
01377 return RESULT_SHOWUSAGE;
01378 }
01379 skinnydebug = 0;
01380 ast_cli(fd, "Skinny Debugging Disabled\n");
01381 return RESULT_SUCCESS;
01382 }
01383
01384 static int skinny_show_devices(int fd, int argc, char *argv[])
01385 {
01386 struct skinny_device *d;
01387 struct skinny_line *l;
01388 int numlines = 0;
01389 char iabuf[INET_ADDRSTRLEN];
01390
01391 if (argc != 3) {
01392 return RESULT_SHOWUSAGE;
01393 }
01394 ast_mutex_lock(&devicelock);
01395 d = devices;
01396
01397 ast_cli(fd, "Name DeviceId IP TypeId R Model NL\n");
01398 ast_cli(fd, "-------------------- ---------------- --------------- ------ - ------ --\n");
01399 while(d) {
01400 l = d->lines;
01401 numlines = 0;
01402 while(l) { numlines++; l = l->next; }
01403
01404 ast_cli(fd, "%-20s %-16s %-16s %6X %c %-6s %2d\n",
01405 d->name,
01406 d->id,
01407 ast_inet_ntoa(iabuf, sizeof(iabuf), d->addr.sin_addr),
01408 d->type,
01409 d->registered?'Y':'N',
01410 d->model,
01411 numlines);
01412
01413 d = d->next;
01414 }
01415 ast_mutex_unlock(&devicelock);
01416 return RESULT_SUCCESS;
01417 }
01418
01419 static int skinny_show_lines(int fd, int argc, char *argv[])
01420 {
01421 struct skinny_device *d;
01422 struct skinny_line *l;
01423
01424 if (argc != 3) {
01425 return RESULT_SHOWUSAGE;
01426 }
01427 ast_mutex_lock(&devicelock);
01428 d = devices;
01429 while(d) {
01430 l = d->lines;
01431 while (l) {
01432 ast_cli(fd, "%-20s %2d %-20s %-20s %c %c\n",
01433 l->parent->name,
01434 l->instance,
01435 l->name,
01436 l->label,
01437 l->sub->owner?'Y':'N',
01438 l->sub->rtp?'Y':'N');
01439 l = l->next;
01440 }
01441 d = d->next;
01442 }
01443 ast_mutex_unlock(&devicelock);
01444 return RESULT_SUCCESS;
01445 }
01446
01447 static char show_devices_usage[] =
01448 "Usage: skinny show devices\n"
01449 " Lists all devices known to the Skinny subsystem.\n";
01450
01451 static char show_lines_usage[] =
01452 "Usage: skinny show lines\n"
01453 " Lists all lines known to the Skinny subsystem.\n";
01454
01455 static char debug_usage[] =
01456 "Usage: skinny debug\n"
01457 " Enables dumping of Skinny packets for debugging purposes\n";
01458
01459 static char no_debug_usage[] =
01460 "Usage: skinny no debug\n"
01461 " Disables dumping of Skinny packets for debugging purposes\n";
01462
01463 static struct ast_cli_entry cli_show_devices =
01464 { { "skinny", "show", "devices", NULL }, skinny_show_devices, "Show defined Skinny devices", show_devices_usage };
01465
01466 static struct ast_cli_entry cli_show_lines =
01467 { { "skinny", "show", "lines", NULL }, skinny_show_lines, "Show defined Skinny lines per device", show_lines_usage };
01468
01469 static struct ast_cli_entry cli_debug =
01470 { { "skinny", "debug", NULL }, skinny_do_debug, "Enable Skinny debugging", debug_usage };
01471
01472 static struct ast_cli_entry cli_no_debug =
01473 { { "skinny", "no", "debug", NULL }, skinny_no_debug, "Disable Skinny debugging", no_debug_usage };
01474
01475 #if 0
01476 static struct skinny_paging_device *build_paging_device(char *cat, struct ast_variable *v)
01477 {
01478 return NULL;
01479 }
01480 #endif
01481
01482 static struct skinny_device *build_device(char *cat, struct ast_variable *v)
01483 {
01484 struct skinny_device *d;
01485 struct skinny_line *l;
01486 struct skinny_subchannel *sub;
01487 int i=0, y=0;
01488
01489 d = malloc(sizeof(struct skinny_device));
01490 if (d) {
01491 memset(d, 0, sizeof(struct skinny_device));
01492 strncpy(d->name, cat, sizeof(d->name) - 1);
01493 while(v) {
01494 if (!strcasecmp(v->name, "host")) {
01495 if (ast_get_ip(&d->addr, v->value)) {
01496 free(d);
01497 return NULL;
01498 }
01499 } else if (!strcasecmp(v->name, "port")) {
01500 d->addr.sin_port = htons(atoi(v->value));
01501 } else if (!strcasecmp(v->name, "device")) {
01502 strncpy(d->id, v->value, sizeof(d->id)-1);
01503 } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
01504 d->ha = ast_append_ha(v->name, v->value, d->ha);
01505 } else if (!strcasecmp(v->name, "context")) {
01506 strncpy(context, v->value, sizeof(context) - 1);
01507 } else if (!strcasecmp(v->name, "version")) {
01508 strncpy(d->version_id, v->value, sizeof(d->version_id) -1);
01509 } else if (!strcasecmp(v->name, "nat")) {
01510 nat = ast_true(v->value);
01511 } else if (!strcasecmp(v->name, "model")) {
01512 strncpy(d->model, v->value, sizeof(d->model) - 1);
01513 } else if (!strcasecmp(v->name, "callerid")) {
01514 if (!strcasecmp(v->value, "asreceived")) {
01515 cid_num[0] = '\0';
01516 cid_name[0] = '\0';
01517 } else {
01518 ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
01519 }
01520 } else if (!strcasecmp(v->name, "language")) {
01521 strncpy(language, v->value, sizeof(language)-1);
01522 } else if (!strcasecmp(v->name, "accountcode")) {
01523 strncpy(accountcode, v->value, sizeof(accountcode)-1);
01524 } else if (!strcasecmp(v->name, "amaflags")) {
01525 y = ast_cdr_amaflags2int(v->value);
01526 if (y < 0) {
01527 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
01528 } else {
01529 amaflags = y;
01530 }
01531 } else if (!strcasecmp(v->name, "musiconhold")) {
01532 strncpy(musicclass, v->value, sizeof(musicclass)-1);
01533 } else if (!strcasecmp(v->name, "callgroup")) {
01534 cur_callergroup = ast_get_group(v->value);
01535 } else if (!strcasecmp(v->name, "pickupgroup")) {
01536 cur_pickupgroup = ast_get_group(v->value);
01537 } else if (!strcasecmp(v->name, "immediate")) {
01538 immediate = ast_true(v->value);
01539 } else if (!strcasecmp(v->name, "cancallforward")) {
01540 cancallforward = ast_true(v->value);
01541 } else if (!strcasecmp(v->name, "mailbox")) {
01542 strncpy(mailbox, v->value, sizeof(mailbox) -1);
01543 } else if (!strcasecmp(v->name, "callreturn")) {
01544 callreturn = ast_true(v->value);
01545 } else if (!strcasecmp(v->name, "callwaiting")) {
01546 callwaiting = ast_true(v->value);
01547 } else if (!strcasecmp(v->name, "transfer")) {
01548 transfer = ast_true(v->value);
01549 } else if (!strcasecmp(v->name, "threewaycalling")) {
01550 threewaycalling = ast_true(v->value);
01551 } else if (!strcasecmp(v->name, "mwiblink")) {
01552 mwiblink = ast_true(v->value);
01553 } else if (!strcasecmp(v->name, "linelabel")) {
01554 strncpy(linelabel, v->value, sizeof(linelabel)-1);
01555 } else if (!strcasecmp(v->name, "trunk") || !strcasecmp(v->name, "line")) {
01556 l = malloc(sizeof(struct skinny_line));;
01557 if (l) {
01558 memset(l, 0, sizeof(struct skinny_line));
01559 ast_mutex_init(&l->lock);
01560 strncpy(l->name, v->value, sizeof(l->name) - 1);
01561
01562
01563 strncpy(l->context, context, sizeof(l->context) - 1);
01564 strncpy(l->cid_num, cid_num, sizeof(l->cid_num) - 1);
01565 strncpy(l->cid_name, cid_name, sizeof(l->cid_name) - 1);
01566 strncpy(l->label, linelabel, sizeof(l->label) - 1);
01567 strncpy(l->language, language, sizeof(l->language) - 1);
01568 strncpy(l->musicclass, musicclass, sizeof(l->musicclass)-1);
01569 strncpy(l->mailbox, mailbox, sizeof(l->mailbox)-1);
01570 strncpy(l->mailbox, mailbox, sizeof(l->mailbox)-1);
01571 if (!ast_strlen_zero(mailbox)) {
01572 ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, d->name, l->name);
01573 }
01574 l->msgstate = -1;
01575 l->capability = capability;
01576 l->parent = d;
01577 if (!strcasecmp(v->name, "trunk")) {
01578 l->type = TYPE_TRUNK;
01579 } else {
01580 l->type = TYPE_LINE;
01581 }
01582 l->immediate = immediate;
01583 l->callgroup = cur_callergroup;
01584 l->pickupgroup = cur_pickupgroup;
01585 l->callreturn = callreturn;
01586 l->cancallforward = cancallforward;
01587 l->callwaiting = callwaiting;
01588 l->transfer = transfer;
01589 l->threewaycalling = threewaycalling;
01590 l->mwiblink = mwiblink;
01591 l->onhooktime = time(NULL);
01592 l->instance = 1;
01593
01594 l->hookstate = SKINNY_ONHOOK;
01595
01596 for (i = 0; i < MAX_SUBS; i++) {
01597 sub = malloc(sizeof(struct skinny_subchannel));
01598 if (sub) {
01599 ast_verbose(VERBOSE_PREFIX_3 "Allocating Skinny subchannel '%d' on %s@%s\n", i, l->name, d->name);
01600 memset(sub, 0, sizeof(struct skinny_subchannel));
01601 ast_mutex_init(&sub->lock);
01602 sub->parent = l;
01603
01604 sub->callid = callnums;
01605 callnums++;
01606 sub->cxmode = SKINNY_CX_INACTIVE;
01607 sub->nat = nat;
01608 sub->next = l->sub;
01609 l->sub = sub;
01610 } else {
01611
01612 ast_log(LOG_WARNING, "Out of memory allocating subchannel");
01613 return NULL;
01614 }
01615 }
01616 l->next = d->lines;
01617 d->lines = l;
01618 } else {
01619
01620 ast_log(LOG_WARNING, "Out of memory allocating line");
01621 return NULL;
01622 }
01623 } else {
01624 ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
01625 }
01626 v = v->next;
01627 }
01628
01629 if (!d->lines) {
01630 ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n");
01631 return NULL;
01632 }
01633 if (d->addr.sin_addr.s_addr && !ntohs(d->addr.sin_port)) {
01634 d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
01635 }
01636 if (d->addr.sin_addr.s_addr) {
01637 if (ast_ouraddrfor(&d->addr.sin_addr, &d->ourip)) {
01638 memcpy(&d->ourip, &__ourip, sizeof(d->ourip));
01639 }
01640 } else {
01641 memcpy(&d->ourip, &__ourip, sizeof(d->ourip));
01642 }
01643 }
01644 return d;
01645 }
01646
01647 static int skinny_register(skinny_req *req, struct skinnysession *s)
01648 {
01649 struct skinny_device *d;
01650
01651 ast_mutex_lock(&devicelock);
01652 d = devices;
01653 while (d) {
01654 if (!strcasecmp(req->data.reg.name, d->id)
01655 && ast_apply_ha(d->ha, &(s->sin))) {
01656 s->device = d;
01657 d->type = letohl(req->data.reg.type);
01658 if (ast_strlen_zero(d->version_id)) {
01659 strncpy(d->version_id, version_id, sizeof(d->version_id) - 1);
01660 }
01661 d->registered = 1;
01662 d->session = s;
01663 break;
01664 }
01665 d = d->next;
01666 }
01667 ast_mutex_unlock(&devicelock);
01668 if (!d) {
01669 return 0;
01670 }
01671 return 1;
01672 }
01673
01674 static void start_rtp(struct skinny_subchannel *sub)
01675 {
01676 ast_mutex_lock(&sub->lock);
01677
01678 sub->rtp = ast_rtp_new(sched, io, 1, 0);
01679 if (sub->rtp && sub->owner) {
01680 sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
01681 }
01682 if (sub->rtp) {
01683 ast_rtp_setnat(sub->rtp, sub->nat);
01684 }
01685
01686 transmit_connect(sub->parent->parent->session);
01687 ast_mutex_unlock(&sub->lock);
01688 }
01689
01690 static void *skinny_ss(void *data)
01691 {
01692 struct ast_channel *chan = data;
01693 struct skinny_subchannel *sub = chan->tech_pvt;
01694 struct skinny_line *l = sub->parent;
01695 struct skinnysession *s = l->parent->session;
01696 char exten[AST_MAX_EXTENSION] = "";
01697 int len = 0;
01698 int timeout = firstdigittimeout;
01699 int res;
01700 int getforward=0;
01701
01702 if (option_verbose > 2) {
01703 ast_verbose( VERBOSE_PREFIX_3 "Starting simple switch on '%s@%s'\n", l->name, l->parent->name);
01704 }
01705 while(len < AST_MAX_EXTENSION-1) {
01706 res = ast_waitfordigit(chan, timeout);
01707 timeout = 0;
01708 if (res < 0) {
01709 if (skinnydebug) {
01710 ast_verbose("Skinny(%s@%s): waitfordigit returned < 0\n", l->name, l->parent->name);
01711 }
01712 ast_indicate(chan, -1);
01713 ast_hangup(chan);
01714 return NULL;
01715 } else if (res) {
01716 exten[len++]=res;
01717 exten[len] = '\0';
01718 }
01719 if (!ast_ignore_pattern(chan->context, exten)) {
01720 transmit_tone(s, SKINNY_SILENCE);
01721 }
01722 if (ast_exists_extension(chan, chan->context, exten, 1, l->cid_num)) {
01723 if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, l->cid_num)) {
01724 if (getforward) {
01725
01726 strncpy(l->call_forward, exten, sizeof(l->call_forward) - 1);
01727 if (option_verbose > 2) {
01728 ast_verbose(VERBOSE_PREFIX_3 "Setting call forward to '%s' on channel %s\n",
01729 l->call_forward, chan->name);
01730 }
01731 transmit_tone(s, SKINNY_DIALTONE);
01732 if (res) {
01733 break;
01734 }
01735 ast_safe_sleep(chan, 500);
01736 ast_indicate(chan, -1);
01737 ast_safe_sleep(chan, 1000);
01738 memset(exten, 0, sizeof(exten));
01739 transmit_tone(s, SKINNY_DIALTONE);
01740 len = 0;
01741 getforward = 0;
01742 } else {
01743 strncpy(chan->exten, exten, sizeof(chan->exten)-1);
01744
01745 if (!ast_strlen_zero(l->cid_num)) {
01746 ast_set_callerid(chan,
01747 l->hidecallerid ? "" : l->cid_num,
01748 l->hidecallerid ? "" : l->cid_name,
01749 chan->cid.cid_ani ? NULL : l->cid_num);
01750 ast_setstate(chan, AST_STATE_RING);
01751 res = ast_pbx_run(chan);
01752 if (res) {
01753 ast_log(LOG_WARNING, "PBX exited non-zero\n");
01754 transmit_tone(s, SKINNY_REORDER);
01755 }
01756 return NULL;
01757 }
01758 }
01759 } else {
01760
01761
01762 timeout = matchdigittimeout;
01763 }
01764 } else if (res == 0) {
01765 ast_log(LOG_DEBUG, "Not enough digits (and no ambiguous match)...\n");
01766 transmit_tone(s, SKINNY_REORDER);
01767 ast_hangup(chan);
01768 return NULL;
01769 } else if (l->callwaiting && !strcmp(exten, "*70")) {
01770 if (option_verbose > 2) {
01771 ast_verbose(VERBOSE_PREFIX_3 "Disabling call waiting on %s\n", chan->name);
01772 }
01773
01774 l->callwaiting = 0;
01775 transmit_tone(s, SKINNY_DIALTONE);
01776 len = 0;
01777 memset(exten, 0, sizeof(exten));\
01778 timeout = firstdigittimeout;
01779 } else if (!strcmp(exten,ast_pickup_ext())) {
01780
01781
01782
01783
01784 if (ast_pickup_call(chan)) {
01785 ast_log(LOG_WARNING, "No call pickup possible...\n");
01786 transmit_tone(s, SKINNY_REORDER);
01787 }
01788 ast_hangup(chan);
01789 return NULL;
01790 } else if (!l->hidecallerid && !strcmp(exten, "*67")) {
01791 if (option_verbose > 2) {
01792 ast_verbose(VERBOSE_PREFIX_3 "Disabling Caller*ID on %s\n", chan->name);
01793 }
01794
01795 l->hidecallerid = 1;
01796 ast_set_callerid(chan, "", "", NULL);
01797 transmit_tone(s, SKINNY_DIALTONE);
01798 len = 0;
01799 memset(exten, 0, sizeof(exten));
01800 timeout = firstdigittimeout;
01801 } else if (l->callreturn && !strcmp(exten, "*69")) {
01802 res = 0;
01803 if (!ast_strlen_zero(l->lastcallerid)) {
01804 res = ast_say_digit_str(chan, l->lastcallerid, "", chan->language);
01805 }
01806 if (!res) {
01807 transmit_tone(s, SKINNY_DIALTONE);
01808 }
01809 break;
01810 } else if (!strcmp(exten, "*78")) {
01811
01812 if (option_verbose > 2) {
01813 ast_verbose(VERBOSE_PREFIX_3 "Enabled DND on channel %s\n", chan->name);
01814 }
01815 transmit_tone(s, SKINNY_DIALTONE);
01816 l->dnd = 1;
01817 getforward = 0;
01818 memset(exten, 0, sizeof(exten));
01819 len = 0;
01820 } else if (!strcmp(exten, "*79")) {
01821
01822 if (option_verbose > 2) {
01823 ast_verbose(VERBOSE_PREFIX_3 "Disabled DND on channel %s\n", chan->name);
01824 }
01825 transmit_tone(s, SKINNY_DIALTONE);
01826 l->dnd = 0;
01827 getforward = 0;
01828 memset(exten, 0, sizeof(exten));
01829 len = 0;
01830 } else if (l->cancallforward && !strcmp(exten, "*72")) {
01831 transmit_tone(s, SKINNY_DIALTONE);
01832 getforward = 1;
01833 memset(exten, 0, sizeof(exten));
01834 len = 0;
01835 } else if (l->cancallforward && !strcmp(exten, "*73")) {
01836 if (option_verbose > 2) {
01837 ast_verbose(VERBOSE_PREFIX_3 "Cancelling call forwarding on channel %s\n", chan->name);
01838 }
01839 transmit_tone(s, SKINNY_DIALTONE);
01840 memset(l->call_forward, 0, sizeof(l->call_forward));
01841 getforward = 0;
01842 memset(exten, 0, sizeof(exten));
01843 len = 0;
01844 } else if (!strcmp(exten, ast_parking_ext()) &&
01845 sub->next->owner &&
01846 ast_bridged_channel(sub->next->owner)) {
01847
01848
01849 ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
01850 if (option_verbose > 2) {
01851 ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
01852 }
01853 break;
01854 } else if (!ast_strlen_zero(l->lastcallerid) && !strcmp(exten, "*60")) {
01855 if (option_verbose > 2) {
01856 ast_verbose(VERBOSE_PREFIX_3 "Blacklisting number %s\n", l->lastcallerid);
01857 }
01858 res = ast_db_put("blacklist", l->lastcallerid, "1");
01859 if (!res) {
01860 transmit_tone(s, SKINNY_DIALTONE);
01861 memset(exten, 0, sizeof(exten));
01862 len = 0;
01863 }
01864 } else if (l->hidecallerid && !strcmp(exten, "*82")) {
01865 if (option_verbose > 2) {
01866 ast_verbose(VERBOSE_PREFIX_3 "Enabling Caller*ID on %s\n", chan->name);
01867 }
01868
01869 l->hidecallerid = 0;
01870 ast_set_callerid(chan, l->cid_num, l->cid_name, NULL);
01871 transmit_tone(s, SKINNY_DIALTONE);
01872 len = 0;
01873 memset(exten, 0, sizeof(exten));
01874 timeout = firstdigittimeout;
01875 } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) &&
01876 ((exten[0] != '*') || (!ast_strlen_zero(exten) > 2))) {
01877 ast_log(LOG_WARNING, "Can't match [%s] from '%s' in context %s\n", exten, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
01878 transmit_tone(s, SKINNY_REORDER);
01879
01880 ast_safe_sleep(chan, 3000);
01881 break;
01882 }
01883 if (!timeout) {
01884 timeout = gendigittimeout;
01885 }
01886 if (len && !ast_ignore_pattern(chan->context, exten)) {
01887 ast_indicate(chan, -1);
01888 }
01889 }
01890 ast_hangup(chan);
01891 return NULL;
01892 }
01893
01894
01895
01896 static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
01897 {
01898 int res = 0;
01899 int tone = 0;
01900 struct skinny_line *l;
01901 struct skinny_subchannel *sub;
01902 struct skinnysession *session;
01903
01904 sub = ast->tech_pvt;
01905 l = sub->parent;
01906 session = l->parent->session;
01907
01908 if (!l->parent->registered) {
01909 ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
01910 return -1;
01911 }
01912
01913 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
01914 ast_log(LOG_WARNING, "skinny_call called on %s, neither down nor reserved\n", ast->name);
01915 return -1;
01916 }
01917
01918 if (skinnydebug) {
01919 ast_verbose(VERBOSE_PREFIX_3 "skinny_call(%s)\n", ast->name);
01920 }
01921
01922 if (l->dnd) {
01923 ast_queue_control(ast, AST_CONTROL_BUSY);
01924 return -1;
01925 }
01926
01927 switch (l->hookstate) {
01928 case SKINNY_OFFHOOK:
01929 tone = SKINNY_CALLWAITTONE;
01930 break;
01931 case SKINNY_ONHOOK:
01932 tone = SKINNY_ALERT;
01933 break;
01934 default:
01935 ast_log(LOG_ERROR, "Don't know how to deal with hookstate %d\n", l->hookstate);
01936 break;
01937 }
01938
01939 transmit_lamp_indication(session, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
01940 transmit_ringer_mode(session, SKINNY_RING_INSIDE);
01941
01942 if (ast->cid.cid_num) {
01943 char ciddisplay[41];
01944 char *work;
01945 size_t size = sizeof(ciddisplay);
01946
01947
01948 if (strlen(ast->cid.cid_num) == 10) {
01949 ast_build_string(&work, &size, "(xxx)xxx-xxxx %s",
01950 ast->cid.cid_name ? ast->cid.cid_name : "");
01951 memcpy(&ciddisplay[1], ast->cid.cid_num, 3);
01952 memcpy(&ciddisplay[5], &ast->cid.cid_num[3], 3);
01953 memcpy(&ciddisplay[9], &ast->cid.cid_num[6], 4);
01954 } else {
01955 if (strlen(ast->cid.cid_num) < 41) {
01956 ast_build_string(&work, &size, "%s -- %s", ast->cid.cid_num,
01957 ast->cid.cid_name ? ast->cid.cid_name : "");
01958 } else {
01959 strncpy(ciddisplay, "Number too long!", 15);
01960 }
01961 }
01962 if (skinnydebug) {
01963 ast_verbose("Trying to send: '%s'\n",ciddisplay);
01964 }
01965 transmit_displaymessage(session, ciddisplay);
01966 } else {
01967 transmit_displaymessage(session, "Unknown Name");
01968 }
01969 transmit_tone(session, tone);
01970 transmit_callstate(session, l->instance, SKINNY_RINGIN, sub->callid);
01971 transmit_displaypromptstatus(session, "Ring-In", 0, l->instance, sub->callid);
01972 transmit_callinfo(session, ast->cid.cid_name, ast->cid.cid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1);
01973
01974
01975
01976 ast_setstate(ast, AST_STATE_RINGING);
01977 ast_queue_control(ast, AST_CONTROL_RINGING);
01978 sub->outgoing = 1;
01979 return res;
01980 }
01981
01982 static int skinny_hangup(struct ast_channel *ast)
01983 {
01984 struct skinny_subchannel *sub = ast->tech_pvt;
01985 struct skinny_line *l = sub->parent;
01986 struct skinnysession *s = l->parent->session;
01987
01988 if (skinnydebug) {
01989 ast_verbose("skinny_hangup(%s) on %s@%s\n", ast->name, l->name, l->parent->name);
01990 }
01991 if (!ast->tech_pvt) {
01992 ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
01993 return 0;
01994 }
01995
01996 if (l->parent->registered) {
01997 if ((sub->parent->type = TYPE_LINE) && (sub->parent->hookstate == SKINNY_OFFHOOK)) {
01998 sub->parent->hookstate = SKINNY_ONHOOK;
01999 transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
02000 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
02001 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
02002 } else if ((sub->parent->type = TYPE_LINE) && (sub->parent->hookstate == SKINNY_ONHOOK)) {
02003 transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
02004 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
02005 transmit_ringer_mode(s, SKINNY_RING_OFF);
02006 transmit_tone(s, SKINNY_SILENCE);
02007 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
02008 do_housekeeping(s);
02009 }
02010 }
02011 ast_mutex_lock(&sub->lock);
02012 sub->owner = NULL;
02013 ast->tech_pvt = NULL;
02014 sub->alreadygone = 0;
02015 sub->outgoing = 0;
02016 if (sub->rtp) {
02017 ast_rtp_destroy(sub->rtp);
02018 sub->rtp = NULL;
02019 }
02020 ast_mutex_unlock(&sub->lock);
02021 return 0;
02022 }
02023
02024 static int skinny_answer(struct ast_channel *ast)
02025 {
02026 int res = 0;
02027 struct skinny_subchannel *sub = ast->tech_pvt;
02028 struct skinny_line *l = sub->parent;
02029 struct skinnysession *s = l->parent->session;
02030
02031 sub->cxmode = SKINNY_CX_SENDRECV;
02032 if (!sub->rtp) {
02033 start_rtp(sub);
02034 }
02035 ast_verbose("skinny_answer(%s) on %s@%s-%d\n", ast->name, l->name, l->parent->name, sub->callid);
02036 if (ast->_state != AST_STATE_UP) {
02037 ast_setstate(ast, AST_STATE_UP);
02038 }
02039 transmit_tone(s, SKINNY_NOTONE);
02040 transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
02041 transmit_displaypromptstatus(s, "Connected", 0, l->instance, sub->callid);
02042 return res;
02043 }
02044
02045 static struct ast_frame *skinny_rtp_read(struct skinny_subchannel *sub)
02046 {
02047
02048 struct ast_frame *f;
02049 f = ast_rtp_read(sub->rtp);
02050 if (sub->owner) {
02051
02052 if (f->frametype == AST_FRAME_VOICE) {
02053 if (f->subclass != sub->owner->nativeformats) {
02054 ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
02055 sub->owner->nativeformats = f->subclass;
02056 ast_set_read_format(sub->owner, sub->owner->readformat);
02057 ast_set_write_format(sub->owner, sub->owner->writeformat);
02058 }
02059 }
02060 }
02061 return f;
02062 }
02063
02064 static struct ast_frame *skinny_read(struct ast_channel *ast)
02065 {
02066 struct ast_frame *fr;
02067 struct skinny_subchannel *sub = ast->tech_pvt;
02068 ast_mutex_lock(&sub->lock);
02069 fr = skinny_rtp_read(sub);
02070 ast_mutex_unlock(&sub->lock);
02071 return fr;
02072 }
02073
02074 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
02075 {
02076 struct skinny_subchannel *sub = ast->tech_pvt;
02077 int res = 0;
02078 if (frame->frametype != AST_FRAME_VOICE) {
02079 if (frame->frametype == AST_FRAME_IMAGE) {
02080 return 0;
02081 } else {
02082 ast_log(LOG_WARNING, "Can't send %d type frames with skinny_write\n", frame->frametype);
02083 return 0;
02084 }
02085 } else {
02086 if (!(frame->subclass & ast->nativeformats)) {
02087 ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
02088 frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
02089 return -1;
02090 }
02091 }
02092 if (sub) {
02093 ast_mutex_lock(&sub->lock);
02094 if (sub->rtp) {
02095 res = ast_rtp_write(sub->rtp, frame);
02096 }
02097 ast_mutex_unlock(&sub->lock);
02098 }
02099 return res;
02100 }
02101
02102 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
02103 {
02104 struct skinny_subchannel *sub = newchan->tech_pvt;
02105 ast_log(LOG_NOTICE, "skinny_fixup(%s, %s)\n", oldchan->name, newchan->name);
02106 if (sub->owner != oldchan) {
02107 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
02108 return -1;
02109 }
02110 sub->owner = newchan;
02111 return 0;
02112 }
02113
02114 static int skinny_senddigit(struct ast_channel *ast, char digit)
02115 {
02116 #if 0
02117 struct skinny_subchannel *sub = ast->tech_pvt;
02118 int tmp;
02119
02120 sprintf(tmp, "%d", digit);
02121 transmit_tone(sub->parent->parent->session, digit);
02122 #endif
02123 return -1;
02124 }
02125
02126 static char *control2str(int ind) {
02127 static char tmp[100];
02128
02129 switch (ind) {
02130 case AST_CONTROL_HANGUP:
02131 return "Other end has hungup";
02132 case AST_CONTROL_RING:
02133 return "Local ring";
02134 case AST_CONTROL_RINGING:
02135 return "Remote end is ringing";
02136 case AST_CONTROL_ANSWER:
02137 return "Remote end has answered";
02138 case AST_CONTROL_BUSY:
02139 return "Remote end is busy";
02140 case AST_CONTROL_TAKEOFFHOOK:
02141 return "Make it go off hook";
02142 case AST_CONTROL_OFFHOOK:
02143 return "Line is off hook";
02144 case AST_CONTROL_CONGESTION:
02145 return "Congestion (circuits busy)";
02146 case AST_CONTROL_FLASH:
02147 return "Flash hook";
02148 case AST_CONTROL_WINK:
02149 return "Wink";
02150 case AST_CONTROL_OPTION:
02151 return "Set a low-level option";
02152 case AST_CONTROL_RADIO_KEY:
02153 return "Key Radio";
02154 case AST_CONTROL_RADIO_UNKEY:
02155 return "Un-Key Radio";
02156 case AST_CONTROL_PROGRESS:
02157 return "Remote end is making Progress";
02158 case AST_CONTROL_PROCEEDING:
02159 return "Remote end is proceeding";
02160 case AST_CONTROL_HOLD:
02161 return "Hold";
02162 case AST_CONTROL_UNHOLD:
02163 return "Unhold";
02164 case -1:
02165 return "Stop tone";
02166 }
02167 snprintf(tmp, 100, "UNKNOWN-%d", ind);
02168 return tmp;
02169 }
02170
02171
02172 static int skinny_indicate(struct ast_channel *ast, int ind)
02173 {
02174 struct skinny_subchannel *sub = ast->tech_pvt;
02175 struct skinny_line *l = sub->parent;
02176 struct skinnysession *s = l->parent->session;
02177
02178 if (skinnydebug) {
02179 ast_verbose(VERBOSE_PREFIX_3 "Asked to indicate '%s' condition on channel %s\n", control2str(ind), ast->name);
02180 }
02181 switch(ind) {
02182 case AST_CONTROL_RINGING:
02183 if (ast->_state != AST_STATE_UP) {
02184 if (!sub->progress) {
02185 transmit_tone(s, SKINNY_ALERT);
02186 transmit_callstate(s, l->instance, SKINNY_RINGOUT, sub->callid);
02187 transmit_diallednumber(s, ast->exten, l->instance, sub->callid);
02188 transmit_displaypromptstatus(s, "Ring Out", 0, l->instance, sub->callid);
02189 transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, ast->exten, ast->exten, l->instance, sub->callid, 2);
02190 sub->ringing = 1;
02191 break;
02192 }
02193 }
02194 return -1;
02195 case AST_CONTROL_BUSY:
02196 if (ast->_state != AST_STATE_UP) {
02197 transmit_tone(s, SKINNY_BUSYTONE);
02198 transmit_callstate(s, l->instance, SKINNY_BUSY, sub->callid);
02199 sub->alreadygone = 1;
02200 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
02201 break;
02202 }
02203 return -1;
02204 case AST_CONTROL_CONGESTION:
02205 if (ast->_state != AST_STATE_UP) {
02206 transmit_tone(s, SKINNY_REORDER);
02207 transmit_callstate(s, l->instance, SKINNY_CONGESTION, sub->callid);
02208 sub->alreadygone = 1;
02209 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
02210 break;
02211 }
02212 return -1;
02213 case AST_CONTROL_PROGRESS:
02214 if ((ast->_state != AST_STATE_UP) && !sub->progress && !sub->outgoing) {
02215 transmit_tone(s, SKINNY_ALERT);
02216 transmit_callstate(s, l->instance, SKINNY_PROGRESS, sub->callid);
02217 transmit_displaypromptstatus(s, "Call Progress", 0, l->instance, sub->callid);
02218 transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, ast->exten, ast->exten, l->instance, sub->callid, 2);
02219 sub->progress = 1;
02220 break;
02221 }
02222 return -1;
02223 case -1:
02224 transmit_tone(s, SKINNY_SILENCE);
02225 break;
02226 case AST_CONTROL_PROCEEDING:
02227 break;
02228 default:
02229 ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
02230 return -1;
02231 }
02232 return 0;
02233 }
02234
02235 static struct ast_channel *skinny_new(struct skinny_subchannel *sub, int state)
02236 {
02237 struct ast_channel *tmp;
02238 struct skinny_line *l = sub->parent;
02239 int fmt;
02240 l = sub->parent;
02241 tmp = ast_channel_alloc(1);
02242 if (tmp) {
02243 tmp->tech = &skinny_tech;
02244 tmp->nativeformats = l->capability;
02245 if (!tmp->nativeformats)
02246 tmp->nativeformats = capability;
02247 fmt = ast_best_codec(tmp->nativeformats);
02248 ast_verbose("skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp->nativeformats, fmt);
02249 snprintf(tmp->name, sizeof(tmp->name), "Skinny/%s@%s-%d", l->name, l->parent->name, sub->callid);
02250 if (sub->rtp) {
02251 tmp->fds[0] = ast_rtp_fd(sub->rtp);
02252 }
02253 tmp->type = type;
02254 ast_setstate(tmp, state);
02255 if (state == AST_STATE_RING) {
02256 tmp->rings = 1;
02257 }
02258 tmp->writeformat = fmt;
02259 tmp->rawwriteformat = fmt;
02260 tmp->readformat = fmt;
02261 tmp->rawreadformat = fmt;
02262 tmp->tech_pvt = sub;
02263 if (!ast_strlen_zero(l->language)) {
02264 strncpy(tmp->language, l->language, sizeof(tmp->language)-1);
02265 }
02266 if (!ast_strlen_zero(l->accountcode)) {
02267 strncpy(tmp->accountcode, l->accountcode, sizeof(tmp->accountcode)-1);
02268 }
02269 if (l->amaflags) {
02270 tmp->amaflags = l->amaflags;
02271 }
02272 sub->owner = tmp;
02273 ast_mutex_lock(&usecnt_lock);
02274 usecnt++;
02275 ast_mutex_unlock(&usecnt_lock);
02276 ast_update_use_count();
02277 tmp->callgroup = l->callgroup;
02278 tmp->pickupgroup = l->pickupgroup;
02279 strncpy(tmp->call_forward, l->call_forward, sizeof(tmp->call_forward) - 1);
02280 strncpy(tmp->context, l->context, sizeof(tmp->context)-1);
02281 strncpy(tmp->exten,l->exten, sizeof(tmp->exten)-1);
02282 ast_set_callerid(tmp, l->cid_num, l->cid_name, l->cid_num);
02283 tmp->priority = 1;
02284 tmp->adsicpe = AST_ADSI_UNAVAILABLE;
02285
02286 if (state != AST_STATE_DOWN) {
02287 if (ast_pbx_start(tmp)) {
02288 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
02289 ast_hangup(tmp);
02290 tmp = NULL;
02291 }
02292 }
02293 } else {
02294 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
02295 }
02296 return tmp;
02297 }
02298
02299 static int handle_message(skinny_req *req, struct skinnysession *s)
02300 {
02301 struct skinny_subchannel *sub;
02302 struct ast_channel *c;
02303 struct ast_frame f = { 0, };
02304 struct sockaddr_in sin;
02305 struct sockaddr_in us;
02306 struct skinny_line *lines;
02307 char name[16];
02308 char addr[4];
02309 char d;
02310 char iabuf[INET_ADDRSTRLEN];
02311 int digit;
02312 int res=0;
02313 int speedDialNum;
02314 int lineNumber;
02315 int stimulus;
02316 int stimulusInstance;
02317 int status;
02318 int port;
02319 int i;
02320 time_t timer;
02321 struct tm *cmtime;
02322 pthread_t t;
02323 button_defs_t *b, *buse;
02324
02325 if ((!s->device) && (letohl(req->e) != REGISTER_MESSAGE && letohl(req->e) != ALARM_MESSAGE)) {
02326 ast_log(LOG_WARNING, "Client sent message #%d without first registering.\n", req->e);
02327 free(req);
02328 return 0;
02329 }
02330
02331 switch(letohl(req->e)) {
02332 case ALARM_MESSAGE:
02333
02334 break;
02335 case REGISTER_MESSAGE:
02336 if (skinnydebug) {
02337 ast_verbose("Device %s is attempting to register\n", req->data.reg.name);
02338 }
02339 res = skinny_register(req, s);
02340 if (!res) {
02341 ast_log(LOG_ERROR, "Rejecting Device %s: Device not found\n", req->data.reg.name);
02342 memcpy(&name, req->data.reg.name, sizeof(req->data.reg.name));
02343 memset(req, 0, sizeof(skinny_req));
02344 req->len = htolel(sizeof(register_rej_message)+4);
02345 req->e = htolel(REGISTER_REJ_MESSAGE);
02346 snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name);
02347 transmit_response(s, req);
02348 break;
02349 }
02350 if (option_verbose > 2) {
02351 ast_verbose(VERBOSE_PREFIX_3 "Device '%s' successfuly registered\n", s->device->name);
02352 }
02353 memset(req, 0, SKINNY_MAX_PACKET);
02354 req->len = htolel(sizeof(register_ack_message)+4);
02355 req->e = htolel(REGISTER_ACK_MESSAGE);
02356 req->data.regack.res[0] = '0';
02357 req->data.regack.res[1] = '\0';
02358 req->data.regack.keepAlive = htolel(keep_alive);
02359 strncpy(req->data.regack.dateTemplate, date_format, sizeof(req->data.regack.dateTemplate) - 1);
02360 req->data.regack.res2[0] = '0';
02361 req->data.regack.res2[1] = '\0';
02362 req->data.regack.secondaryKeepAlive = htolel(keep_alive);
02363 transmit_response(s, req);
02364 if (skinnydebug) {
02365 ast_verbose("Requesting capabilities\n");
02366 }
02367 memset(req, 0, SKINNY_MAX_PACKET);
02368 req->len = htolel(4);
02369 req->e = htolel(CAPABILITIES_REQ_MESSAGE);
02370 transmit_response(s, req);
02371 break;
02372 case UNREGISTER_MESSAGE:
02373
02374 break;
02375 case IP_PORT_MESSAGE:
02376
02377 break;
02378 case STIMULUS_MESSAGE:
02379 stimulus = letohl(req->data.stimulus.stimulus);
02380 stimulusInstance = letohl(req->data.stimulus.stimulusInstance);
02381
02382 switch(stimulus) {
02383 case STIMULUS_REDIAL:
02384
02385
02386
02387 if (skinnydebug) {
02388 ast_verbose("Recieved Stimulus: Redial(%d)\n", stimulusInstance);
02389 }
02390 break;
02391 case STIMULUS_SPEEDDIAL:
02392 if (skinnydebug) {
02393 ast_verbose("Recieved Stimulus: SpeedDial(%d)\n", stimulusInstance);
02394 }
02395 break;
02396 case STIMULUS_HOLD:
02397
02398 if (skinnydebug) {
02399 ast_verbose("Recieved Stimulus: Hold(%d)\n", stimulusInstance);
02400 }
02401 break;
02402 case STIMULUS_TRANSFER:
02403 if (skinnydebug) {
02404 ast_verbose("Recieved Stimulus: Transfer(%d)\n", stimulusInstance);
02405 }
02406 transmit_tone(s, SKINNY_DIALTONE);
02407
02408 break;
02409 case STIMULUS_CONFERENCE:
02410 if (skinnydebug) {
02411 ast_verbose("Recieved Stimulus: Transfer(%d)\n", stimulusInstance);
02412 }
02413 transmit_tone(s, SKINNY_DIALTONE);
02414
02415 break;
02416 case STIMULUS_VOICEMAIL:
02417 if (skinnydebug) {
02418 ast_verbose("Recieved Stimulus: Voicemail(%d)\n", stimulusInstance);
02419 }
02420
02421 break;
02422 case STIMULUS_CALLPARK:
02423 if (skinnydebug) {
02424 ast_verbose("Recieved Stimulus: Park Call(%d)\n", stimulusInstance);
02425 }
02426
02427 break;
02428 case STIMULUS_FORWARDALL:
02429
02430
02431
02432 transmit_tone(s, SKINNY_DIALTONE);
02433 if (s->device->lines->dnd != 0){
02434 if (option_verbose > 2) {
02435 ast_verbose(VERBOSE_PREFIX_3 "Disabling DND on %s@%s\n",find_subchannel_by_line(s->device->lines)->parent->name,find_subchannel_by_line(s->device->lines)->parent->name);
02436 }
02437 s->device->lines->dnd = 0;
02438 transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
02439 transmit_displaynotify(s, "DnD disabled",10);
02440 } else {
02441 if (option_verbose > 2) {
02442 ast_verbose(VERBOSE_PREFIX_3 "Enabling DND on %s@%s\n",find_subchannel_by_line(s->device->lines)->parent->name,find_subchannel_by_line(s->device->lines)->parent->name);
02443 }
02444 s->device->lines->dnd = 1;
02445 transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF);
02446 transmit_displaynotify(s, "DnD enabled",10);
02447 }
02448 break;
02449 case STIMULUS_FORWARDBUSY:
02450 case STIMULUS_FORWARDNOANSWER:
02451
02452 if (skinnydebug) {
02453 ast_verbose("Recieved Stimulus: Forward (%d)\n", stimulusInstance);
02454 }
02455 break;
02456 case STIMULUS_DISPLAY:
02457
02458 if (skinnydebug) {
02459 ast_verbose("Recieved Stimulus: Display(%d)\n", stimulusInstance);
02460 }
02461 break;
02462 case STIMULUS_LINE:
02463 if (skinnydebug) {
02464 ast_verbose("Recieved Stimulus: Line(%d)\n", stimulusInstance);
02465 }
02466 sub = find_subchannel_by_line(s->device->lines);
02467
02468 transmit_speaker_mode(s, 1);
02469 break;
02470 default:
02471 ast_verbose("RECEIVED UNKNOWN STIMULUS: %d(%d)\n", stimulus, stimulusInstance);
02472 break;
02473 }
02474 break;
02475 case VERSION_REQ_MESSAGE:
02476 if (skinnydebug) {
02477 ast_verbose("Version Request\n");
02478 }
02479 memset(req, 0, SKINNY_MAX_PACKET);
02480 req->len = htolel(sizeof(version_res_message)+4);
02481 req->e = htolel(VERSION_RES_MESSAGE);
02482 snprintf(req->data.version.version, sizeof(req->data.version.version), s->device->version_id);
02483 transmit_response(s, req);
02484 break;
02485 case SERVER_REQUEST_MESSAGE:
02486 if (skinnydebug) {
02487 ast_verbose("Recieved Server Request\n");
02488 }
02489 memset(req, 0, SKINNY_MAX_PACKET);
02490 req->len = htolel(sizeof(server_res_message)+4);
02491 req->e = htolel(SERVER_RES_MESSAGE);
02492 memcpy(req->data.serverres.server[0].serverName, ourhost,
02493 sizeof(req->data.serverres.server[0].serverName));
02494 req->data.serverres.serverListenPort[0] = htolel(ourport);
02495 req->data.serverres.serverIpAddr[0] = htolel(__ourip.s_addr);
02496 transmit_response(s, req);
02497 break;
02498 case BUTTON_TEMPLATE_REQ_MESSAGE:
02499 if (skinnydebug) {
02500 ast_verbose("Buttontemplate requested\n");
02501 }
02502 sub = find_subchannel_by_line(s->device->lines);
02503 memset(req, 0, SKINNY_MAX_PACKET);
02504 req->e = htolel(BUTTON_TEMPLATE_RES_MESSAGE);
02505 req->len = htolel(sizeof(button_template_res_message)+4);
02506
02507
02508
02509 buse = button_defs;
02510 for(b=button_defs; b->type; b++) {
02511 if (!strcmp(s->device->model, b->type)) {
02512 buse = b;
02513 }
02514 }
02515 req->data.buttontemplate.buttonOffset = 0;
02516 req->data.buttontemplate.buttonCount = htolel(buse->num_buttons);
02517 req->data.buttontemplate.totalButtonCount = htolel(buse->num_buttons);
02518 for (i=0; i<42; i++) {
02519 if (i < buse->num_buttons) {
02520 memcpy(&(req->data.buttontemplate.definition[i]),
02521 &(buse->button_def[i]),
02522 sizeof(button_definition));
02523 } else {
02524 memcpy(&(req->data.buttontemplate.definition[i]),
02525 &(button_def_none),
02526 sizeof(button_definition));
02527 }
02528 }
02529
02530 if (skinnydebug) {
02531 ast_verbose("Sending %s template to %s@%s (%s)\n",
02532 buse->type,
02533 sub->parent->name,
02534 sub->parent->parent->name,
02535 s->device->model);
02536 }
02537 transmit_response(s, req);
02538 break;
02539 case SOFT_KEY_SET_REQ_MESSAGE:
02540 if (skinnydebug) {
02541 ast_verbose("Received SoftKeySetReq\n");
02542 }
02543 memset(req, 0, SKINNY_MAX_PACKET);
02544 req->len = htolel(sizeof(soft_key_sets)+4);
02545 req->e = htolel(SOFT_KEY_SET_RES_MESSAGE);
02546 req->data.softkeysets.softKeySetOffset = 0;
02547 req->data.softkeysets.softKeySetCount = htolel(11);
02548 req->data.softkeysets.totalSoftKeySetCount = htolel(11);
02549
02550 memcpy(req->data.softkeysets.softKeySetDefinition,
02551 soft_key_set_hack,
02552 sizeof(req->data.softkeysets.softKeySetDefinition));
02553 transmit_response(s,req);
02554 break;
02555 case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
02556 if (skinnydebug) {
02557 ast_verbose("Recieved SoftKey Template Request\n");
02558 }
02559 memset(req, 0, SKINNY_MAX_PACKET);
02560 req->len = htolel(sizeof(soft_key_template)+4);
02561 req->e = htolel(SOFT_KEY_TEMPLATE_RES_MESSAGE);
02562 req->data.softkeytemplate.softKeyOffset = 0;
02563 req->data.softkeytemplate.softKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(soft_key_template_definition));
02564 req->data.softkeytemplate.totalSoftKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(soft_key_template_definition));
02565 memcpy(req->data.softkeytemplate.softKeyTemplateDefinition,
02566 soft_key_template_default,
02567 sizeof(soft_key_template_default));
02568 transmit_response(s,req);
02569 break;
02570 case TIME_DATE_REQ_MESSAGE:
02571 if (skinnydebug) {
02572 ast_verbose("Received Time/Date Request\n");
02573 }
02574 memset(req, 0, SKINNY_MAX_PACKET);
02575 req->len = htolel(sizeof(definetimedate_message)+4);
02576 req->e = htolel(DEFINETIMEDATE_MESSAGE);
02577 timer=time(NULL);
02578 cmtime = localtime(&timer);
02579 req->data.definetimedate.year = htolel(cmtime->tm_year+1900);
02580 req->data.definetimedate.month = htolel(cmtime->tm_mon+1);
02581 req->data.definetimedate.dayofweek = htolel(cmtime->tm_wday);
02582 req->data.definetimedate.day = htolel(cmtime->tm_mday);
02583 req->data.definetimedate.hour = htolel(cmtime->tm_hour);
02584 req->data.definetimedate.minute = htolel(cmtime->tm_min);
02585 req->data.definetimedate.seconds = htolel(cmtime->tm_sec);
02586 transmit_response(s, req);
02587 break;
02588 case SPEED_DIAL_STAT_REQ_MESSAGE:
02589
02590
02591 speedDialNum = letohl(req->data.speeddialreq.speedDialNumber);
02592 memset(req, 0, SKINNY_MAX_PACKET);
02593 req->len = htolel(sizeof(speed_dial_stat_res_message)+4);
02594 req->e = htolel(SPEED_DIAL_STAT_RES_MESSAGE);
02595 #if 0
02596
02597
02598
02599 req->data.speeddialreq.speedDialNumber = speedDialNum;
02600 snprintf(req->data.speeddial.speedDialDirNumber, sizeof(req->data.speeddial.speedDialDirNumber), "31337");
02601 snprintf(req->data.speeddial.speedDialDisplayName, sizeof(req->data.speeddial.speedDialDisplayName),"Asterisk Rules!");
02602 #endif
02603 transmit_response(s, req);
02604 break;
02605 case LINE_STATE_REQ_MESSAGE:
02606 lineNumber = letohl(req->data.line.lineNumber);
02607 if (skinnydebug) {
02608 ast_verbose("Received LineStateReq\n");
02609 }
02610 memset(req, 0, SKINNY_MAX_PACKET);
02611 req->len = htolel(sizeof(line_stat_res_message)+4);
02612 req->e = htolel(LINE_STAT_RES_MESSAGE);
02613 sub = find_subchannel_by_line(s->device->lines);
02614 if (!sub) {
02615 ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
02616 return 0;
02617 }
02618 lines = sub->parent;
02619 ast_mutex_lock(&devicelock);
02620 for (i=1; i < lineNumber; i++) {
02621 lines = lines->next;
02622 }
02623 ast_mutex_unlock(&devicelock);
02624 req->data.linestat.linenumber = letohl(lineNumber);
02625 memcpy(req->data.linestat.lineDirNumber, lines->name,
02626 sizeof(req->data.linestat.lineDirNumber));
02627 memcpy(req->data.linestat.lineDisplayName, lines->label,
02628 sizeof(req->data.linestat.lineDisplayName));
02629 transmit_response(s,req);
02630 break;
02631 case CAPABILITIES_RES_MESSAGE:
02632 if (skinnydebug) {
02633 ast_verbose("Received CapabilitiesRes\n");
02634 }
02635
02636 break;
02637 case KEEP_ALIVE_MESSAGE:
02638 memset(req, 0, SKINNY_MAX_PACKET);
02639 req->len = htolel(4);
02640 req->e = htolel(KEEP_ALIVE_ACK_MESSAGE);
02641 transmit_response(s, req);
02642 do_housekeeping(s);
02643 break;
02644 case OFFHOOK_MESSAGE:
02645 transmit_ringer_mode(s,SKINNY_RING_OFF);
02646 transmit_lamp_indication(s, STIMULUS_LINE, s->device->lines->instance, SKINNY_LAMP_ON);
02647 sub = find_subchannel_by_line(s->device->lines);
02648 if (!sub) {
02649 ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
02650 return 0;
02651 }
02652 sub->parent->hookstate = SKINNY_OFFHOOK;
02653
02654 if (sub->outgoing) {
02655
02656 ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
02657 transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, sub->callid);
02658 transmit_tone(s, SKINNY_SILENCE);
02659 transmit_callstate(s, s->device->lines->instance, SKINNY_CONNECTED, sub->callid);
02660 start_rtp(sub);
02661 ast_setstate(sub->owner, AST_STATE_UP);
02662
02663 } else {
02664 if (!sub->owner) {
02665 transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, sub->callid);
02666 if (skinnydebug) {
02667 ast_verbose("Attempting to Clear display on Skinny %s@%s\n",sub->parent->name, sub->parent->parent->name);
02668 }
02669 transmit_displaymessage(s, NULL);
02670 transmit_tone(s, SKINNY_DIALTONE);
02671 c = skinny_new(sub, AST_STATE_DOWN);
02672 if(c) {
02673
02674 if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
02675 ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
02676 ast_hangup(c);
02677 }
02678 } else {
02679 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name, s->device->name);
02680 }
02681 } else {
02682 ast_log(LOG_DEBUG, "Current sub [%s] already has owner\n", sub->owner->name);
02683 }
02684 }
02685 break;
02686 case ONHOOK_MESSAGE:
02687 sub = find_subchannel_by_line(s->device->lines);
02688 if (sub->parent->hookstate == SKINNY_ONHOOK) {
02689
02690 break;
02691 }
02692 sub->cxmode = SKINNY_CX_RECVONLY;
02693 sub->parent->hookstate = SKINNY_ONHOOK;
02694 transmit_callstate(s, s->device->lines->instance, sub->parent->hookstate,sub->callid);
02695 if (skinnydebug) {
02696 ast_verbose("Skinny %s@%s went on hook\n",sub->parent->name, sub->parent->parent->name);
02697 }
02698 if (sub->parent->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
02699
02700
02701
02702 #if 0
02703 if ((res = attempt_transfer(p)) < 0) {
02704 if (p->sub->next->owner) {
02705 sub->next->alreadygone = 1;
02706 ast_queue_hangup(sub->next->owner,1);
02707 }
02708 } else if (res) {
02709 ast_log(LOG_WARNING, "Transfer attempt failed\n");
02710 return -1;
02711 }
02712 #endif
02713 } else {
02714
02715
02716 if (sub->owner) {
02717 sub->alreadygone = 1;
02718 ast_queue_hangup(sub->owner);
02719 } else {
02720 ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n",
02721 sub->parent->name, sub->parent->parent->name, sub->callid);
02722 }
02723 }
02724 if ((sub->parent->hookstate == SKINNY_ONHOOK) && (!sub->next->rtp)) {
02725 do_housekeeping(s);
02726 }
02727 break;
02728 case KEYPAD_BUTTON_MESSAGE:
02729 digit = letohl(req->data.keypad.button);
02730 if (skinnydebug) {
02731 ast_verbose("Collected digit: [%d]\n", digit);
02732 }
02733 f.frametype = AST_FRAME_DTMF;
02734 if (digit == 14) {
02735 d = '*';
02736 } else if (digit == 15) {
02737 d = '#';
02738 } else if (digit >=0 && digit <= 9) {
02739 d = '0' + digit;
02740 } else {
02741
02742
02743
02744
02745
02746
02747
02748 d = '0' + digit;
02749 ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
02750 }
02751 f.subclass = d;
02752 f.src = "skinny";
02753 sub = find_subchannel_by_line(s->device->lines);
02754 if (sub->owner) {
02755
02756 ast_queue_frame(sub->owner, &f);
02757 if (sub->next->owner) {
02758 ast_queue_frame(sub->next->owner, &f);
02759 }
02760 } else {
02761 ast_verbose("No owner: %s\n", s->device->lines->name);
02762 }
02763 break;
02764 case OPEN_RECIEVE_CHANNEL_ACK_MESSAGE:
02765 ast_verbose("Recieved Open Recieve Channel Ack\n");
02766 status = letohl(req->data.openrecievechannelack.status);
02767 if (status) {
02768 ast_log(LOG_ERROR, "Open Recieve Channel Failure\n");
02769 break;
02770 }
02771
02772 memcpy(addr, req->data.openrecievechannelack.ipAddr, sizeof(addr));
02773 port = htolel(req->data.openrecievechannelack.port);
02774 sin.sin_family = AF_INET;
02775
02776 memcpy(&sin.sin_addr, addr, sizeof(sin.sin_addr));
02777 sin.sin_port = htons(port);
02778 if (skinnydebug) {
02779 ast_verbose("ipaddr = %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
02780 }
02781 sub = find_subchannel_by_line(s->device->lines);
02782 if (sub->rtp) {
02783 ast_rtp_set_peer(sub->rtp, &sin);
02784 ast_rtp_get_us(sub->rtp, &us);
02785 } else {
02786 ast_log(LOG_ERROR, "No RTP structure, this is very bad\n");
02787 break;
02788 }
02789 memset(req, 0, SKINNY_MAX_PACKET);
02790 req->len = htolel(sizeof(start_media_transmission_message)+4);
02791 req->e = htolel(START_MEDIA_TRANSMISSION_MESSAGE);
02792 req->data.startmedia.conferenceId = 0;
02793 req->data.startmedia.passThruPartyId = 0;
02794 memcpy(req->data.startmedia.remoteIp, &s->device->ourip, 4);
02795 req->data.startmedia.remotePort = htolel(ntohs(us.sin_port));
02796 req->data.startmedia.packetSize = htolel(20);
02797 req->data.startmedia.payloadType = htolel(convert_cap(s->device->lines->capability));
02798 req->data.startmedia.qualifier.precedence = htolel(127);
02799 req->data.startmedia.qualifier.vad = 0;
02800 req->data.startmedia.qualifier.packets = 0;
02801 req->data.startmedia.qualifier.bitRate = 0;
02802 transmit_response(s, req);
02803 break;
02804 default:
02805 ast_verbose("RECEIVED UNKNOWN MESSAGE TYPE: %x\n", letohl(req->e));
02806 break;
02807 }
02808 free(req);
02809 return 1;
02810 }
02811
02812 static void destroy_session(struct skinnysession *s)
02813 {
02814 struct skinnysession *cur, *prev = NULL;
02815 ast_mutex_lock(&sessionlock);
02816 cur = sessions;
02817 while(cur) {
02818 if (cur == s) {
02819 break;
02820 }
02821 prev = cur;
02822 cur = cur->next;
02823 }
02824 if (cur) {
02825 if (prev) {
02826 prev->next = cur->next;
02827 } else {
02828 sessions = cur->next;
02829 }
02830 if (s->fd > -1) {
02831 close(s->fd);
02832 }
02833 ast_mutex_destroy(&s->lock);
02834 free(s);
02835 } else {
02836 ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
02837 }
02838 ast_mutex_unlock(&sessionlock);
02839 }
02840
02841 static int get_input(struct skinnysession *s)
02842 {
02843 int res;
02844 int dlen = 0;
02845 struct pollfd fds[1];
02846
02847 fds[0].fd = s->fd;
02848 fds[0].events = POLLIN;
02849 res = poll(fds, 1, -1);
02850
02851 if (res < 0) {
02852 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
02853 } else if (res > 0) {
02854 memset(s->inbuf,0,sizeof(s->inbuf));
02855 res = read(s->fd, s->inbuf, 4);
02856 if (res != 4) {
02857 ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
02858 return -1;
02859 }
02860 dlen = letohl(*(int *)s->inbuf);
02861 if (dlen+8 > sizeof(s->inbuf)) {
02862 dlen = sizeof(s->inbuf) - 8;
02863 }
02864 *(int *)s->inbuf = htolel(dlen);
02865 res = read(s->fd, s->inbuf+4, dlen+4);
02866 ast_mutex_unlock(&s->lock);
02867 if (res != (dlen+4)) {
02868 ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
02869 return -1;
02870 }
02871 }
02872 return res;
02873 }
02874
02875 static skinny_req *skinny_req_parse(struct skinnysession *s)
02876 {
02877 skinny_req *req;
02878
02879 req = malloc(SKINNY_MAX_PACKET);
02880 if (!req) {
02881 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
02882 return NULL;
02883 }
02884 memset(req, 0, sizeof(skinny_req));
02885
02886 memcpy(req, s->inbuf, letohl(*(int*)(s->inbuf))+8);
02887 if (letohl(req->e) < 0) {
02888 ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
02889 free(req);
02890 return NULL;
02891 }
02892 return req;
02893 }
02894
02895 static void *skinny_session(void *data)
02896 {
02897 int res;
02898 skinny_req *req;
02899 struct skinnysession *s = data;
02900 char iabuf[INET_ADDRSTRLEN];
02901
02902 ast_verbose(VERBOSE_PREFIX_3 "Starting Skinny session from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
02903 for (;;) {
02904 res = 0;
02905 res = get_input(s);
02906 if (res < 0) {
02907 break;
02908 }
02909 req = skinny_req_parse(s);
02910 if (!req) {
02911 return NULL;
02912 }
02913 res = handle_message(req, s);
02914 if (res < 0) {
02915 destroy_session(s);
02916 return NULL;
02917 }
02918 }
02919 ast_log(LOG_NOTICE, "Skinny Session returned: %s\n", strerror(errno));
02920 destroy_session(s);
02921 return 0;
02922 }
02923
02924 static void *accept_thread(void *ignore)
02925 {
02926 int as;
02927 struct sockaddr_in sin;
02928 socklen_t sinlen;
02929 struct skinnysession *s;
02930 struct protoent *p;
02931 int arg = 1;
02932 pthread_attr_t attr;
02933
02934 pthread_attr_init(&attr);
02935 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02936
02937 for (;;) {
02938 sinlen = sizeof(sin);
02939 as = accept(skinnysock, (struct sockaddr *)&sin, &sinlen);
02940 if (as < 0) {
02941 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
02942 continue;
02943 }
02944 p = getprotobyname("tcp");
02945 if(p) {
02946 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
02947 ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
02948 }
02949 }
02950 s = malloc(sizeof(struct skinnysession));
02951 if (!s) {
02952 ast_log(LOG_WARNING, "Failed to allocate Skinny session: %s\n", strerror(errno));
02953 continue;
02954 }
02955 memset(s, 0, sizeof(struct skinnysession));
02956 memcpy(&s->sin, &sin, sizeof(sin));
02957 ast_mutex_init(&s->lock);
02958 s->fd = as;
02959 ast_mutex_lock(&sessionlock);
02960 s->next = sessions;
02961 sessions = s;
02962 ast_mutex_unlock(&sessionlock);
02963
02964 if (ast_pthread_create(&tcp_thread, NULL, skinny_session, s)) {
02965 destroy_session(s);
02966 }
02967 }
02968 if (skinnydebug) {
02969 ast_verbose("killing accept thread\n");
02970 }
02971 close(as);
02972 return 0;
02973 }
02974
02975 static void *do_monitor(void *data)
02976 {
02977 int res;
02978
02979
02980
02981
02982 for(;;) {
02983 pthread_testcancel();
02984
02985 res = ast_sched_wait(sched);
02986 if ((res < 0) || (res > 1000)) {
02987 res = 1000;
02988 }
02989 res = ast_io_wait(io, res);
02990 ast_mutex_lock(&monlock);
02991 if (res >= 0) {
02992 ast_sched_runq(sched);
02993 }
02994 ast_mutex_unlock(&monlock);
02995 }
02996
02997 return NULL;
02998
02999 }
03000
03001 static int restart_monitor(void)
03002 {
03003
03004 if (monitor_thread == AST_PTHREADT_STOP)
03005 return 0;
03006 if (ast_mutex_lock(&monlock)) {
03007 ast_log(LOG_WARNING, "Unable to lock monitor\n");
03008 return -1;
03009 }
03010 if (monitor_thread == pthread_self()) {
03011 ast_mutex_unlock(&monlock);
03012 ast_log(LOG_WARNING, "Cannot kill myself\n");
03013 return -1;
03014 }
03015 if (monitor_thread != AST_PTHREADT_NULL) {
03016
03017 pthread_kill(monitor_thread, SIGURG);
03018 } else {
03019
03020 if (ast_pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) {
03021 ast_mutex_unlock(&monlock);
03022 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
03023 return -1;
03024 }
03025 }
03026 ast_mutex_unlock(&monlock);
03027 return 0;
03028 }
03029
03030 static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause)
03031 {
03032 int oldformat;
03033 struct skinny_subchannel *sub;
03034 struct ast_channel *tmpc = NULL;
03035 char tmp[256];
03036 char *dest = data;
03037
03038 oldformat = format;
03039 format &= capability;
03040 if (!format) {
03041 ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
03042 return NULL;
03043 }
03044 strncpy(tmp, dest, sizeof(tmp) - 1);
03045 if (ast_strlen_zero(tmp)) {
03046 ast_log(LOG_NOTICE, "Skinny channels require a device\n");
03047 return NULL;
03048 }
03049 sub = find_subchannel_by_name(tmp);
03050 if (!sub) {
03051 ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
03052 return NULL;
03053 }
03054 if (option_verbose > 2) {
03055 ast_verbose(VERBOSE_PREFIX_3 "skinny_request(%s)\n", tmp);
03056 ast_verbose(VERBOSE_PREFIX_3 "Skinny cw: %d, dnd: %d, so: %d, sno: %d\n",
03057 sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
03058 }
03059 tmpc = skinny_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
03060 if (!tmpc) {
03061 ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
03062 }
03063 restart_monitor();
03064 return tmpc;
03065 }
03066
03067 static int reload_config(void)
03068 {
03069 int on = 1;
03070 struct ast_config *cfg;
03071 struct ast_variable *v;
03072 int format;
03073 char *cat;
03074 char iabuf[INET_ADDRSTRLEN];
03075 struct skinny_device *d;
03076 int oldport = ntohs(bindaddr.sin_port);
03077
03078 if (gethostname(ourhost, sizeof(ourhost))) {
03079 ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled\n");
03080 return 0;
03081 }
03082 cfg = ast_config_load(config);
03083
03084
03085 if (!cfg) {
03086 ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled\n", config);
03087 return 0;
03088 }
03089
03090 memset(&bindaddr, 0, sizeof(bindaddr));
03091 v = ast_variable_browse(cfg, "general");
03092 while(v) {
03093
03094 if (!strcasecmp(v->name, "bindaddr")) {
03095 if (!(hp = ast_gethostbyname(v->value, &ahp))) {
03096 ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
03097 } else {
03098 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
03099 }
03100 } else if (!strcasecmp(v->name, "keepAlive")) {
03101 keep_alive = atoi(v->value);
03102 } else if (!strcasecmp(v->name, "dateFormat")) {
03103 strncpy(date_format, v->value, sizeof(date_format) - 1);
03104 } else if (!strcasecmp(v->name, "allow")) {
03105 format = ast_getformatbyname(v->value);
03106 if (format < 1) {
03107 ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
03108 } else {
03109 capability |= format;
03110 }
03111 } else if (!strcasecmp(v->name, "disallow")) {
03112 format = ast_getformatbyname(v->value);
03113 if (format < 1) {
03114 ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
03115 } else {
03116 capability &= ~format;
03117 }
03118 } else if (!strcasecmp(v->name, "port")) {
03119 if (sscanf(v->value, "%d", &ourport) == 1) {
03120 bindaddr.sin_port = htons(ourport);
03121 } else {
03122 ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
03123 }
03124 }
03125 v = v->next;
03126 }
03127 if (ntohl(bindaddr.sin_addr.s_addr)) {
03128 memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
03129 } else {
03130 hp = ast_gethostbyname(ourhost, &ahp);
03131 if (!hp) {
03132 ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
03133 ast_config_destroy(cfg);
03134 return 0;
03135 }
03136 memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
03137 }
03138 if (!ntohs(bindaddr.sin_port)) {
03139 bindaddr.sin_port = ntohs(DEFAULT_SKINNY_PORT);
03140 }
03141 bindaddr.sin_family = AF_INET;
03142
03143
03144 cat = ast_category_browse(cfg, NULL);
03145 while(cat) {
03146 if (!strcasecmp(cat, "general")) {
03147
03148 #if 0
03149 } else if (!strncasecmp(cat, "paging-", 7)) {
03150 p = build_paging_device(cat, ast_variable_browse(cfg, cat));
03151 if (p) {
03152 }
03153 #endif
03154 } else {
03155 d = build_device(cat, ast_variable_browse(cfg, cat));
03156 if (d) {
03157 if (option_verbose > 2) {
03158 ast_verbose(VERBOSE_PREFIX_3 "Added device '%s'\n", d->name);
03159 }
03160 ast_mutex_lock(&devicelock);
03161 d->next = devices;
03162 devices = d;
03163 ast_mutex_unlock(&devicelock);
03164 }
03165 }
03166 cat = ast_category_browse(cfg, cat);
03167 }
03168 ast_mutex_lock(&netlock);
03169 if ((skinnysock > -1) && (ntohs(bindaddr.sin_port) != oldport)) {
03170 close(skinnysock);
03171 skinnysock = -1;
03172 }
03173 if (skinnysock < 0) {
03174 skinnysock = socket(AF_INET, SOCK_STREAM, 0);
03175 if(setsockopt(skinnysock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
03176 ast_log(LOG_ERROR, "Set Socket Options failed: errno %d, %s", errno, strerror(errno));
03177 ast_config_destroy(cfg);
03178 return 0;
03179 }
03180 if (skinnysock < 0) {
03181 ast_log(LOG_WARNING, "Unable to create Skinny socket: %s\n", strerror(errno));
03182 } else {
03183 if (bind(skinnysock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
03184 ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
03185 ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port),
03186 strerror(errno));
03187 close(skinnysock);
03188 skinnysock = -1;
03189 ast_config_destroy(cfg);
03190 return 0;
03191 }
03192 if (listen(skinnysock,DEFAULT_SKINNY_BACKLOG)) {
03193 ast_log(LOG_WARNING, "Failed to start listening to %s:%d: %s\n",
03194 ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port),
03195 strerror(errno));
03196 close(skinnysock);
03197 skinnysock = -1;
03198 ast_config_destroy(cfg);
03199 return 0;
03200 }
03201 if (option_verbose > 1) {
03202 ast_verbose(VERBOSE_PREFIX_2 "Skinny listening on %s:%d\n",
03203 ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port));
03204 }
03205 ast_pthread_create(&accept_t,NULL, accept_thread, NULL);
03206 }
03207 }
03208 ast_mutex_unlock(&netlock);
03209 ast_config_destroy(cfg);
03210 return 0;
03211 }
03212
03213 void delete_devices(void)
03214 {
03215 struct skinny_device *d, *dlast;
03216 struct skinny_line *l, *llast;
03217 struct skinny_subchannel *sub, *slast;
03218
03219 ast_mutex_lock(&devicelock);
03220
03221
03222 for (d=devices;d;) {
03223
03224 for (l=d->lines;l;) {
03225
03226 for (sub=l->sub;sub;) {
03227 slast = sub;
03228 sub = sub->next;
03229 ast_mutex_destroy(&slast->lock);
03230 free(slast);
03231 }
03232 llast = l;
03233 l = l->next;
03234 ast_mutex_destroy(&llast->lock);
03235 free(llast);
03236 }
03237 dlast = d;
03238 d = d->next;
03239 free(dlast);
03240 }
03241 devices=NULL;
03242 ast_mutex_unlock(&devicelock);
03243 }
03244
03245 int reload(void)
03246 {
03247 delete_devices();
03248 reload_config();
03249 restart_monitor();
03250 return 0;
03251 }
03252
03253
03254 int load_module()
03255 {
03256 int res = 0;
03257
03258 for (; res < (sizeof(soft_key_template_default) / sizeof(soft_key_template_default[0])); res++) {
03259 soft_key_template_default[res].softKeyEvent = htolel(soft_key_template_default[res].softKeyEvent);
03260 }
03261
03262 res = reload_config();
03263
03264 ast_rtp_proto_register(&skinny_rtp);
03265 ast_cli_register(&cli_show_devices);
03266 ast_cli_register(&cli_show_lines);
03267 ast_cli_register(&cli_debug);
03268 ast_cli_register(&cli_no_debug);
03269 sched = sched_context_create();
03270 if (!sched) {
03271 ast_log(LOG_WARNING, "Unable to create schedule context\n");
03272 }
03273 io = io_context_create();
03274 if (!io) {
03275 ast_log(LOG_WARNING, "Unable to create I/O context\n");
03276 }
03277
03278 restart_monitor();
03279
03280
03281 if (!res) {
03282
03283 if (ast_channel_register(&skinny_tech)) {
03284 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
03285 return -1;
03286 }
03287 }
03288 return res;
03289 }
03290
03291 int unload_module()
03292 {
03293 #if 0
03294 struct skinny_session *session, s;
03295 struct skinny_subchannel *sub;
03296 struct skinny_line *line = session;
03297
03298
03299 if (!ast_mutex_lock(&devicelock)) {
03300
03301 } else {
03302 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
03303 return -1;
03304 }
03305 if (!ast_mutex_lock(&monlock)) {
03306 if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
03307 pthread_cancel(monitor_thread);
03308 pthread_kill(monitor_thread, SIGURG);
03309 pthread_join(monitor_thread, NULL);
03310 }
03311 monitor_thread = AST_PTHREADT_STOP;
03312 ast_mutex_unlock(&monlock);
03313 } else {
03314 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
03315 return -1;
03316 }
03317 if (!ast_mutex_lock(&iflock)) {
03318
03319 p = iflist;
03320 while(p) {
03321 pl = p;
03322 p = p->next;
03323
03324 ast_mutex_destroy(&pl->lock);
03325 free(pl);
03326 }
03327 iflist = NULL;
03328 ast_mutex_unlock(&iflock);
03329 } else {
03330 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
03331 return -1;
03332 }
03333
03334 ast_rtp_proto_register(&skinny_rtp);
03335 ast_channel_unregister(&skinny_tech);
03336 ast_cli_register(&cli_show_devices);
03337 ast_cli_register(&cli_show_lines);
03338 ast_cli_register(&cli_debug);
03339 ast_cli_register(&cli_no_debug);
03340
03341 return 0;
03342 #endif
03343 return -1;
03344 }
03345
03346 int usecount()
03347 {
03348 return usecnt;
03349 }
03350
03351 char *key()
03352 {
03353 return ASTERISK_GPL_KEY;
03354 }
03355
03356 char *description()
03357 {
03358 return (char *) desc;
03359 }