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: 7221 $")
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 if (!ast_strlen_zero(l->cid_num)) {
01745 if (!l->hidecallerid) {
01746 chan->cid.cid_num = strdup(l->cid_num);
01747 chan->cid.cid_ani = strdup(l->cid_num);
01748 }
01749 ast_setstate(chan, AST_STATE_RING);
01750 res = ast_pbx_run(chan);
01751 if (res) {
01752 ast_log(LOG_WARNING, "PBX exited non-zero\n");
01753 transmit_tone(s, SKINNY_REORDER);
01754 }
01755 return NULL;
01756 }
01757 }
01758 } else {
01759
01760
01761 timeout = matchdigittimeout;
01762 }
01763 } else if (res == 0) {
01764 ast_log(LOG_DEBUG, "Not enough digits (and no ambiguous match)...\n");
01765 transmit_tone(s, SKINNY_REORDER);
01766 ast_hangup(chan);
01767 return NULL;
01768 } else if (l->callwaiting && !strcmp(exten, "*70")) {
01769 if (option_verbose > 2) {
01770 ast_verbose(VERBOSE_PREFIX_3 "Disabling call waiting on %s\n", chan->name);
01771 }
01772
01773 l->callwaiting = 0;
01774 transmit_tone(s, SKINNY_DIALTONE);
01775 len = 0;
01776 memset(exten, 0, sizeof(exten));\
01777 timeout = firstdigittimeout;
01778 } else if (!strcmp(exten,ast_pickup_ext())) {
01779
01780
01781
01782
01783 if (ast_pickup_call(chan)) {
01784 ast_log(LOG_WARNING, "No call pickup possible...\n");
01785 transmit_tone(s, SKINNY_REORDER);
01786 }
01787 ast_hangup(chan);
01788 return NULL;
01789 } else if (!l->hidecallerid && !strcmp(exten, "*67")) {
01790 if (option_verbose > 2) {
01791 ast_verbose(VERBOSE_PREFIX_3 "Disabling Caller*ID on %s\n", chan->name);
01792 }
01793
01794 l->hidecallerid = 1;
01795 if (chan->cid.cid_num) {
01796 free(chan->cid.cid_num);
01797 }
01798 chan->cid.cid_num = NULL;
01799 if (chan->cid.cid_name) {
01800 free(chan->cid.cid_name);
01801 }
01802 chan->cid.cid_name = NULL;
01803 transmit_tone(s, SKINNY_DIALTONE);
01804 len = 0;
01805 memset(exten, 0, sizeof(exten));
01806 timeout = firstdigittimeout;
01807 } else if (l->callreturn && !strcmp(exten, "*69")) {
01808 res = 0;
01809 if (!ast_strlen_zero(l->lastcallerid)) {
01810 res = ast_say_digit_str(chan, l->lastcallerid, "", chan->language);
01811 }
01812 if (!res) {
01813 transmit_tone(s, SKINNY_DIALTONE);
01814 }
01815 break;
01816 } else if (!strcmp(exten, "*78")) {
01817
01818 if (option_verbose > 2) {
01819 ast_verbose(VERBOSE_PREFIX_3 "Enabled DND on channel %s\n", chan->name);
01820 }
01821 transmit_tone(s, SKINNY_DIALTONE);
01822 l->dnd = 1;
01823 getforward = 0;
01824 memset(exten, 0, sizeof(exten));
01825 len = 0;
01826 } else if (!strcmp(exten, "*79")) {
01827
01828 if (option_verbose > 2) {
01829 ast_verbose(VERBOSE_PREFIX_3 "Disabled DND on channel %s\n", chan->name);
01830 }
01831 transmit_tone(s, SKINNY_DIALTONE);
01832 l->dnd = 0;
01833 getforward = 0;
01834 memset(exten, 0, sizeof(exten));
01835 len = 0;
01836 } else if (l->cancallforward && !strcmp(exten, "*72")) {
01837 transmit_tone(s, SKINNY_DIALTONE);
01838 getforward = 1;
01839 memset(exten, 0, sizeof(exten));
01840 len = 0;
01841 } else if (l->cancallforward && !strcmp(exten, "*73")) {
01842 if (option_verbose > 2) {
01843 ast_verbose(VERBOSE_PREFIX_3 "Cancelling call forwarding on channel %s\n", chan->name);
01844 }
01845 transmit_tone(s, SKINNY_DIALTONE);
01846 memset(l->call_forward, 0, sizeof(l->call_forward));
01847 getforward = 0;
01848 memset(exten, 0, sizeof(exten));
01849 len = 0;
01850 } else if (!strcmp(exten, ast_parking_ext()) &&
01851 sub->next->owner &&
01852 ast_bridged_channel(sub->next->owner)) {
01853
01854
01855 ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
01856 if (option_verbose > 2) {
01857 ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
01858 }
01859 break;
01860 } else if (!ast_strlen_zero(l->lastcallerid) && !strcmp(exten, "*60")) {
01861 if (option_verbose > 2) {
01862 ast_verbose(VERBOSE_PREFIX_3 "Blacklisting number %s\n", l->lastcallerid);
01863 }
01864 res = ast_db_put("blacklist", l->lastcallerid, "1");
01865 if (!res) {
01866 transmit_tone(s, SKINNY_DIALTONE);
01867 memset(exten, 0, sizeof(exten));
01868 len = 0;
01869 }
01870 } else if (l->hidecallerid && !strcmp(exten, "*82")) {
01871 if (option_verbose > 2) {
01872 ast_verbose(VERBOSE_PREFIX_3 "Enabling Caller*ID on %s\n", chan->name);
01873 }
01874
01875 l->hidecallerid = 0;
01876 if (chan->cid.cid_num) {
01877 free(chan->cid.cid_num);
01878 }
01879 if (!ast_strlen_zero(l->cid_num)) {
01880 chan->cid.cid_num = strdup(l->cid_num);
01881 }
01882 if (chan->cid.cid_name) {
01883 free(chan->cid.cid_name);
01884 }
01885 if (!ast_strlen_zero(l->cid_name)) {
01886 chan->cid.cid_name = strdup(l->cid_name);
01887 }
01888 transmit_tone(s, SKINNY_DIALTONE);
01889 len = 0;
01890 memset(exten, 0, sizeof(exten));
01891 timeout = firstdigittimeout;
01892 } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) &&
01893 ((exten[0] != '*') || (!ast_strlen_zero(exten) > 2))) {
01894 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);
01895 transmit_tone(s, SKINNY_REORDER);
01896
01897 ast_safe_sleep(chan, 3000);
01898 break;
01899 }
01900 if (!timeout) {
01901 timeout = gendigittimeout;
01902 }
01903 if (len && !ast_ignore_pattern(chan->context, exten)) {
01904 ast_indicate(chan, -1);
01905 }
01906 }
01907 ast_hangup(chan);
01908 return NULL;
01909 }
01910
01911
01912
01913 static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
01914 {
01915 int res = 0;
01916 int tone = 0;
01917 struct skinny_line *l;
01918 struct skinny_subchannel *sub;
01919 struct skinnysession *session;
01920
01921 sub = ast->tech_pvt;
01922 l = sub->parent;
01923 session = l->parent->session;
01924
01925 if (!l->parent->registered) {
01926 ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
01927 return -1;
01928 }
01929
01930 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
01931 ast_log(LOG_WARNING, "skinny_call called on %s, neither down nor reserved\n", ast->name);
01932 return -1;
01933 }
01934
01935 if (skinnydebug) {
01936 ast_verbose(VERBOSE_PREFIX_3 "skinny_call(%s)\n", ast->name);
01937 }
01938
01939 if (l->dnd) {
01940 ast_queue_control(ast, AST_CONTROL_BUSY);
01941 return -1;
01942 }
01943
01944 switch (l->hookstate) {
01945 case SKINNY_OFFHOOK:
01946 tone = SKINNY_CALLWAITTONE;
01947 break;
01948 case SKINNY_ONHOOK:
01949 tone = SKINNY_ALERT;
01950 break;
01951 default:
01952 ast_log(LOG_ERROR, "Don't know how to deal with hookstate %d\n", l->hookstate);
01953 break;
01954 }
01955
01956 transmit_lamp_indication(session, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
01957 transmit_ringer_mode(session, SKINNY_RING_INSIDE);
01958
01959 if (ast->cid.cid_num) {
01960 char ciddisplay[41];
01961 char *work;
01962 size_t size = sizeof(ciddisplay);
01963
01964
01965 if (strlen(ast->cid.cid_num) == 10) {
01966 ast_build_string(&work, &size, "(xxx)xxx-xxxx %s",
01967 ast->cid.cid_name ? ast->cid.cid_name : "");
01968 memcpy(&ciddisplay[1], ast->cid.cid_num, 3);
01969 memcpy(&ciddisplay[5], &ast->cid.cid_num[3], 3);
01970 memcpy(&ciddisplay[9], &ast->cid.cid_num[6], 4);
01971 } else {
01972 if (strlen(ast->cid.cid_num) < 41) {
01973 ast_build_string(&work, &size, "%s -- %s", ast->cid.cid_num,
01974 ast->cid.cid_name ? ast->cid.cid_name : "");
01975 } else {
01976 strncpy(ciddisplay, "Number too long!", 15);
01977 }
01978 }
01979 if (skinnydebug) {
01980 ast_verbose("Trying to send: '%s'\n",ciddisplay);
01981 }
01982 transmit_displaymessage(session, ciddisplay);
01983 } else {
01984 transmit_displaymessage(session, "Unknown Name");
01985 }
01986 transmit_tone(session, tone);
01987 transmit_callstate(session, l->instance, SKINNY_RINGIN, sub->callid);
01988 transmit_displaypromptstatus(session, "Ring-In", 0, l->instance, sub->callid);
01989 transmit_callinfo(session, ast->cid.cid_name, ast->cid.cid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1);
01990
01991
01992
01993 ast_setstate(ast, AST_STATE_RINGING);
01994 ast_queue_control(ast, AST_CONTROL_RINGING);
01995 sub->outgoing = 1;
01996 return res;
01997 }
01998
01999 static int skinny_hangup(struct ast_channel *ast)
02000 {
02001 struct skinny_subchannel *sub = ast->tech_pvt;
02002 struct skinny_line *l = sub->parent;
02003 struct skinnysession *s = l->parent->session;
02004
02005 if (skinnydebug) {
02006 ast_verbose("skinny_hangup(%s) on %s@%s\n", ast->name, l->name, l->parent->name);
02007 }
02008 if (!ast->tech_pvt) {
02009 ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
02010 return 0;
02011 }
02012
02013 if (l->parent->registered) {
02014 if ((sub->parent->type = TYPE_LINE) && (sub->parent->hookstate == SKINNY_OFFHOOK)) {
02015 sub->parent->hookstate = SKINNY_ONHOOK;
02016 transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
02017 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
02018 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
02019 } else if ((sub->parent->type = TYPE_LINE) && (sub->parent->hookstate == SKINNY_ONHOOK)) {
02020 transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
02021 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
02022 transmit_ringer_mode(s, SKINNY_RING_OFF);
02023 transmit_tone(s, SKINNY_SILENCE);
02024 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
02025 do_housekeeping(s);
02026 }
02027 }
02028 ast_mutex_lock(&sub->lock);
02029 sub->owner = NULL;
02030 ast->tech_pvt = NULL;
02031 sub->alreadygone = 0;
02032 sub->outgoing = 0;
02033 if (sub->rtp) {
02034 ast_rtp_destroy(sub->rtp);
02035 sub->rtp = NULL;
02036 }
02037 ast_mutex_unlock(&sub->lock);
02038 return 0;
02039 }
02040
02041 static int skinny_answer(struct ast_channel *ast)
02042 {
02043 int res = 0;
02044 struct skinny_subchannel *sub = ast->tech_pvt;
02045 struct skinny_line *l = sub->parent;
02046 struct skinnysession *s = l->parent->session;
02047
02048 sub->cxmode = SKINNY_CX_SENDRECV;
02049 if (!sub->rtp) {
02050 start_rtp(sub);
02051 }
02052 ast_verbose("skinny_answer(%s) on %s@%s-%d\n", ast->name, l->name, l->parent->name, sub->callid);
02053 if (ast->_state != AST_STATE_UP) {
02054 ast_setstate(ast, AST_STATE_UP);
02055 }
02056 transmit_tone(s, SKINNY_NOTONE);
02057 transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
02058 transmit_displaypromptstatus(s, "Connected", 0, l->instance, sub->callid);
02059 return res;
02060 }
02061
02062 static struct ast_frame *skinny_rtp_read(struct skinny_subchannel *sub)
02063 {
02064
02065 struct ast_frame *f;
02066 f = ast_rtp_read(sub->rtp);
02067 if (sub->owner) {
02068
02069 if (f->frametype == AST_FRAME_VOICE) {
02070 if (f->subclass != sub->owner->nativeformats) {
02071 ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
02072 sub->owner->nativeformats = f->subclass;
02073 ast_set_read_format(sub->owner, sub->owner->readformat);
02074 ast_set_write_format(sub->owner, sub->owner->writeformat);
02075 }
02076 }
02077 }
02078 return f;
02079 }
02080
02081 static struct ast_frame *skinny_read(struct ast_channel *ast)
02082 {
02083 struct ast_frame *fr;
02084 struct skinny_subchannel *sub = ast->tech_pvt;
02085 ast_mutex_lock(&sub->lock);
02086 fr = skinny_rtp_read(sub);
02087 ast_mutex_unlock(&sub->lock);
02088 return fr;
02089 }
02090
02091 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
02092 {
02093 struct skinny_subchannel *sub = ast->tech_pvt;
02094 int res = 0;
02095 if (frame->frametype != AST_FRAME_VOICE) {
02096 if (frame->frametype == AST_FRAME_IMAGE) {
02097 return 0;
02098 } else {
02099 ast_log(LOG_WARNING, "Can't send %d type frames with skinny_write\n", frame->frametype);
02100 return 0;
02101 }
02102 } else {
02103 if (!(frame->subclass & ast->nativeformats)) {
02104 ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
02105 frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
02106 return -1;
02107 }
02108 }
02109 if (sub) {
02110 ast_mutex_lock(&sub->lock);
02111 if (sub->rtp) {
02112 res = ast_rtp_write(sub->rtp, frame);
02113 }
02114 ast_mutex_unlock(&sub->lock);
02115 }
02116 return res;
02117 }
02118
02119 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
02120 {
02121 struct skinny_subchannel *sub = newchan->tech_pvt;
02122 ast_log(LOG_NOTICE, "skinny_fixup(%s, %s)\n", oldchan->name, newchan->name);
02123 if (sub->owner != oldchan) {
02124 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
02125 return -1;
02126 }
02127 sub->owner = newchan;
02128 return 0;
02129 }
02130
02131 static int skinny_senddigit(struct ast_channel *ast, char digit)
02132 {
02133 #if 0
02134 struct skinny_subchannel *sub = ast->tech_pvt;
02135 int tmp;
02136
02137 sprintf(tmp, "%d", digit);
02138 transmit_tone(sub->parent->parent->session, digit);
02139 #endif
02140 return -1;
02141 }
02142
02143 static char *control2str(int ind) {
02144 static char tmp[100];
02145
02146 switch (ind) {
02147 case AST_CONTROL_HANGUP:
02148 return "Other end has hungup";
02149 case AST_CONTROL_RING:
02150 return "Local ring";
02151 case AST_CONTROL_RINGING:
02152 return "Remote end is ringing";
02153 case AST_CONTROL_ANSWER:
02154 return "Remote end has answered";
02155 case AST_CONTROL_BUSY:
02156 return "Remote end is busy";
02157 case AST_CONTROL_TAKEOFFHOOK:
02158 return "Make it go off hook";
02159 case AST_CONTROL_OFFHOOK:
02160 return "Line is off hook";
02161 case AST_CONTROL_CONGESTION:
02162 return "Congestion (circuits busy)";
02163 case AST_CONTROL_FLASH:
02164 return "Flash hook";
02165 case AST_CONTROL_WINK:
02166 return "Wink";
02167 case AST_CONTROL_OPTION:
02168 return "Set a low-level option";
02169 case AST_CONTROL_RADIO_KEY:
02170 return "Key Radio";
02171 case AST_CONTROL_RADIO_UNKEY:
02172 return "Un-Key Radio";
02173 case AST_CONTROL_PROGRESS:
02174 return "Remote end is making Progress";
02175 case AST_CONTROL_PROCEEDING:
02176 return "Remote end is proceeding";
02177 case AST_CONTROL_HOLD:
02178 return "Hold";
02179 case AST_CONTROL_UNHOLD:
02180 return "Unhold";
02181 case -1:
02182 return "Stop tone";
02183 }
02184 snprintf(tmp, 100, "UNKNOWN-%d", ind);
02185 return tmp;
02186 }
02187
02188
02189 static int skinny_indicate(struct ast_channel *ast, int ind)
02190 {
02191 struct skinny_subchannel *sub = ast->tech_pvt;
02192 struct skinny_line *l = sub->parent;
02193 struct skinnysession *s = l->parent->session;
02194
02195 if (skinnydebug) {
02196 ast_verbose(VERBOSE_PREFIX_3 "Asked to indicate '%s' condition on channel %s\n", control2str(ind), ast->name);
02197 }
02198 switch(ind) {
02199 case AST_CONTROL_RINGING:
02200 if (ast->_state != AST_STATE_UP) {
02201 if (!sub->progress) {
02202 transmit_tone(s, SKINNY_ALERT);
02203 transmit_callstate(s, l->instance, SKINNY_RINGOUT, sub->callid);
02204 transmit_diallednumber(s, ast->exten, l->instance, sub->callid);
02205 transmit_displaypromptstatus(s, "Ring Out", 0, l->instance, sub->callid);
02206 transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, ast->exten, ast->exten, l->instance, sub->callid, 2);
02207 sub->ringing = 1;
02208 break;
02209 }
02210 }
02211 return -1;
02212 case AST_CONTROL_BUSY:
02213 if (ast->_state != AST_STATE_UP) {
02214 transmit_tone(s, SKINNY_BUSYTONE);
02215 transmit_callstate(s, l->instance, SKINNY_BUSY, sub->callid);
02216 sub->alreadygone = 1;
02217 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
02218 break;
02219 }
02220 return -1;
02221 case AST_CONTROL_CONGESTION:
02222 if (ast->_state != AST_STATE_UP) {
02223 transmit_tone(s, SKINNY_REORDER);
02224 transmit_callstate(s, l->instance, SKINNY_CONGESTION, sub->callid);
02225 sub->alreadygone = 1;
02226 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
02227 break;
02228 }
02229 return -1;
02230 case AST_CONTROL_PROGRESS:
02231 if ((ast->_state != AST_STATE_UP) && !sub->progress && !sub->outgoing) {
02232 transmit_tone(s, SKINNY_ALERT);
02233 transmit_callstate(s, l->instance, SKINNY_PROGRESS, sub->callid);
02234 transmit_displaypromptstatus(s, "Call Progress", 0, l->instance, sub->callid);
02235 transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, ast->exten, ast->exten, l->instance, sub->callid, 2);
02236 sub->progress = 1;
02237 break;
02238 }
02239 return -1;
02240 case -1:
02241 transmit_tone(s, SKINNY_SILENCE);
02242 break;
02243 case AST_CONTROL_PROCEEDING:
02244 break;
02245 default:
02246 ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
02247 return -1;
02248 }
02249 return 0;
02250 }
02251
02252 static struct ast_channel *skinny_new(struct skinny_subchannel *sub, int state)
02253 {
02254 struct ast_channel *tmp;
02255 struct skinny_line *l = sub->parent;
02256 int fmt;
02257 l = sub->parent;
02258 tmp = ast_channel_alloc(1);
02259 if (tmp) {
02260 tmp->tech = &skinny_tech;
02261 tmp->nativeformats = l->capability;
02262 if (!tmp->nativeformats)
02263 tmp->nativeformats = capability;
02264 fmt = ast_best_codec(tmp->nativeformats);
02265 ast_verbose("skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp->nativeformats, fmt);
02266 snprintf(tmp->name, sizeof(tmp->name), "Skinny/%s@%s-%d", l->name, l->parent->name, sub->callid);
02267 if (sub->rtp) {
02268 tmp->fds[0] = ast_rtp_fd(sub->rtp);
02269 }
02270 tmp->type = type;
02271 ast_setstate(tmp, state);
02272 if (state == AST_STATE_RING) {
02273 tmp->rings = 1;
02274 }
02275 tmp->writeformat = fmt;
02276 tmp->rawwriteformat = fmt;
02277 tmp->readformat = fmt;
02278 tmp->rawreadformat = fmt;
02279 tmp->tech_pvt = sub;
02280 if (!ast_strlen_zero(l->language)) {
02281 strncpy(tmp->language, l->language, sizeof(tmp->language)-1);
02282 }
02283 if (!ast_strlen_zero(l->accountcode)) {
02284 strncpy(tmp->accountcode, l->accountcode, sizeof(tmp->accountcode)-1);
02285 }
02286 if (l->amaflags) {
02287 tmp->amaflags = l->amaflags;
02288 }
02289 sub->owner = tmp;
02290 ast_mutex_lock(&usecnt_lock);
02291 usecnt++;
02292 ast_mutex_unlock(&usecnt_lock);
02293 ast_update_use_count();
02294 tmp->callgroup = l->callgroup;
02295 tmp->pickupgroup = l->pickupgroup;
02296 strncpy(tmp->call_forward, l->call_forward, sizeof(tmp->call_forward) - 1);
02297 strncpy(tmp->context, l->context, sizeof(tmp->context)-1);
02298 strncpy(tmp->exten,l->exten, sizeof(tmp->exten)-1);
02299 if (!ast_strlen_zero(l->cid_num)) {
02300 tmp->cid.cid_num = strdup(l->cid_num);
02301 }
02302 if (!ast_strlen_zero(l->cid_name)) {
02303 tmp->cid.cid_name = strdup(l->cid_name);
02304 }
02305 tmp->priority = 1;
02306 tmp->adsicpe = AST_ADSI_UNAVAILABLE;
02307
02308 if (state != AST_STATE_DOWN) {
02309 if (ast_pbx_start(tmp)) {
02310 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
02311 ast_hangup(tmp);
02312 tmp = NULL;
02313 }
02314 }
02315 } else {
02316 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
02317 }
02318 return tmp;
02319 }
02320
02321 static int handle_message(skinny_req *req, struct skinnysession *s)
02322 {
02323 struct skinny_subchannel *sub;
02324 struct ast_channel *c;
02325 struct ast_frame f = { 0, };
02326 struct sockaddr_in sin;
02327 struct sockaddr_in us;
02328 struct skinny_line *lines;
02329 char name[16];
02330 char addr[4];
02331 char d;
02332 char iabuf[INET_ADDRSTRLEN];
02333 int digit;
02334 int res=0;
02335 int speedDialNum;
02336 int lineNumber;
02337 int stimulus;
02338 int stimulusInstance;
02339 int status;
02340 int port;
02341 int i;
02342 time_t timer;
02343 struct tm *cmtime;
02344 pthread_t t;
02345 button_defs_t *b, *buse;
02346
02347 if ((!s->device) && (letohl(req->e) != REGISTER_MESSAGE && letohl(req->e) != ALARM_MESSAGE)) {
02348 ast_log(LOG_WARNING, "Client sent message #%d without first registering.\n", req->e);
02349 free(req);
02350 return 0;
02351 }
02352
02353 switch(letohl(req->e)) {
02354 case ALARM_MESSAGE:
02355
02356 break;
02357 case REGISTER_MESSAGE:
02358 if (skinnydebug) {
02359 ast_verbose("Device %s is attempting to register\n", req->data.reg.name);
02360 }
02361 res = skinny_register(req, s);
02362 if (!res) {
02363 ast_log(LOG_ERROR, "Rejecting Device %s: Device not found\n", req->data.reg.name);
02364 memcpy(&name, req->data.reg.name, sizeof(req->data.reg.name));
02365 memset(req, 0, sizeof(skinny_req));
02366 req->len = htolel(sizeof(register_rej_message)+4);
02367 req->e = htolel(REGISTER_REJ_MESSAGE);
02368 snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name);
02369 transmit_response(s, req);
02370 break;
02371 }
02372 if (option_verbose > 2) {
02373 ast_verbose(VERBOSE_PREFIX_3 "Device '%s' successfuly registered\n", s->device->name);
02374 }
02375 memset(req, 0, SKINNY_MAX_PACKET);
02376 req->len = htolel(sizeof(register_ack_message)+4);
02377 req->e = htolel(REGISTER_ACK_MESSAGE);
02378 req->data.regack.res[0] = '0';
02379 req->data.regack.res[1] = '\0';
02380 req->data.regack.keepAlive = htolel(keep_alive);
02381 strncpy(req->data.regack.dateTemplate, date_format, sizeof(req->data.regack.dateTemplate) - 1);
02382 req->data.regack.res2[0] = '0';
02383 req->data.regack.res2[1] = '\0';
02384 req->data.regack.secondaryKeepAlive = htolel(keep_alive);
02385 transmit_response(s, req);
02386 if (skinnydebug) {
02387 ast_verbose("Requesting capabilities\n");
02388 }
02389 memset(req, 0, SKINNY_MAX_PACKET);
02390 req->len = htolel(4);
02391 req->e = htolel(CAPABILITIES_REQ_MESSAGE);
02392 transmit_response(s, req);
02393 break;
02394 case UNREGISTER_MESSAGE:
02395
02396 break;
02397 case IP_PORT_MESSAGE:
02398
02399 break;
02400 case STIMULUS_MESSAGE:
02401 stimulus = letohl(req->data.stimulus.stimulus);
02402 stimulusInstance = letohl(req->data.stimulus.stimulusInstance);
02403
02404 switch(stimulus) {
02405 case STIMULUS_REDIAL:
02406
02407
02408
02409 if (skinnydebug) {
02410 ast_verbose("Recieved Stimulus: Redial(%d)\n", stimulusInstance);
02411 }
02412 break;
02413 case STIMULUS_SPEEDDIAL:
02414 if (skinnydebug) {
02415 ast_verbose("Recieved Stimulus: SpeedDial(%d)\n", stimulusInstance);
02416 }
02417 break;
02418 case STIMULUS_HOLD:
02419
02420 if (skinnydebug) {
02421 ast_verbose("Recieved Stimulus: Hold(%d)\n", stimulusInstance);
02422 }
02423 break;
02424 case STIMULUS_TRANSFER:
02425 if (skinnydebug) {
02426 ast_verbose("Recieved Stimulus: Transfer(%d)\n", stimulusInstance);
02427 }
02428 transmit_tone(s, SKINNY_DIALTONE);
02429
02430 break;
02431 case STIMULUS_CONFERENCE:
02432 if (skinnydebug) {
02433 ast_verbose("Recieved Stimulus: Transfer(%d)\n", stimulusInstance);
02434 }
02435 transmit_tone(s, SKINNY_DIALTONE);
02436
02437 break;
02438 case STIMULUS_VOICEMAIL:
02439 if (skinnydebug) {
02440 ast_verbose("Recieved Stimulus: Voicemail(%d)\n", stimulusInstance);
02441 }
02442
02443 break;
02444 case STIMULUS_CALLPARK:
02445 if (skinnydebug) {
02446 ast_verbose("Recieved Stimulus: Park Call(%d)\n", stimulusInstance);
02447 }
02448
02449 break;
02450 case STIMULUS_FORWARDALL:
02451
02452
02453
02454 transmit_tone(s, SKINNY_DIALTONE);
02455 if (s->device->lines->dnd != 0){
02456 if (option_verbose > 2) {
02457 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);
02458 }
02459 s->device->lines->dnd = 0;
02460 transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
02461 transmit_displaynotify(s, "DnD disabled",10);
02462 } else {
02463 if (option_verbose > 2) {
02464 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);
02465 }
02466 s->device->lines->dnd = 1;
02467 transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF);
02468 transmit_displaynotify(s, "DnD enabled",10);
02469 }
02470 break;
02471 case STIMULUS_FORWARDBUSY:
02472 case STIMULUS_FORWARDNOANSWER:
02473
02474 if (skinnydebug) {
02475 ast_verbose("Recieved Stimulus: Forward (%d)\n", stimulusInstance);
02476 }
02477 break;
02478 case STIMULUS_DISPLAY:
02479
02480 if (skinnydebug) {
02481 ast_verbose("Recieved Stimulus: Display(%d)\n", stimulusInstance);
02482 }
02483 break;
02484 case STIMULUS_LINE:
02485 if (skinnydebug) {
02486 ast_verbose("Recieved Stimulus: Line(%d)\n", stimulusInstance);
02487 }
02488 sub = find_subchannel_by_line(s->device->lines);
02489
02490 transmit_speaker_mode(s, 1);
02491 break;
02492 default:
02493 ast_verbose("RECEIVED UNKNOWN STIMULUS: %d(%d)\n", stimulus, stimulusInstance);
02494 break;
02495 }
02496 break;
02497 case VERSION_REQ_MESSAGE:
02498 if (skinnydebug) {
02499 ast_verbose("Version Request\n");
02500 }
02501 memset(req, 0, SKINNY_MAX_PACKET);
02502 req->len = htolel(sizeof(version_res_message)+4);
02503 req->e = htolel(VERSION_RES_MESSAGE);
02504 snprintf(req->data.version.version, sizeof(req->data.version.version), s->device->version_id);
02505 transmit_response(s, req);
02506 break;
02507 case SERVER_REQUEST_MESSAGE:
02508 if (skinnydebug) {
02509 ast_verbose("Recieved Server Request\n");
02510 }
02511 memset(req, 0, SKINNY_MAX_PACKET);
02512 req->len = htolel(sizeof(server_res_message)+4);
02513 req->e = htolel(SERVER_RES_MESSAGE);
02514 memcpy(req->data.serverres.server[0].serverName, ourhost,
02515 sizeof(req->data.serverres.server[0].serverName));
02516 req->data.serverres.serverListenPort[0] = htolel(ourport);
02517 req->data.serverres.serverIpAddr[0] = htolel(__ourip.s_addr);
02518 transmit_response(s, req);
02519 break;
02520 case BUTTON_TEMPLATE_REQ_MESSAGE:
02521 if (skinnydebug) {
02522 ast_verbose("Buttontemplate requested\n");
02523 }
02524 sub = find_subchannel_by_line(s->device->lines);
02525 memset(req, 0, SKINNY_MAX_PACKET);
02526 req->e = htolel(BUTTON_TEMPLATE_RES_MESSAGE);
02527 req->len = htolel(sizeof(button_template_res_message)+4);
02528
02529
02530
02531 buse = button_defs;
02532 for(b=button_defs; b->type; b++) {
02533 if (!strcmp(s->device->model, b->type)) {
02534 buse = b;
02535 }
02536 }
02537 req->data.buttontemplate.buttonOffset = 0;
02538 req->data.buttontemplate.buttonCount = htolel(buse->num_buttons);
02539 req->data.buttontemplate.totalButtonCount = htolel(buse->num_buttons);
02540 for (i=0; i<42; i++) {
02541 if (i < buse->num_buttons) {
02542 memcpy(&(req->data.buttontemplate.definition[i]),
02543 &(buse->button_def[i]),
02544 sizeof(button_definition));
02545 } else {
02546 memcpy(&(req->data.buttontemplate.definition[i]),
02547 &(button_def_none),
02548 sizeof(button_definition));
02549 }
02550 }
02551
02552 if (skinnydebug) {
02553 ast_verbose("Sending %s template to %s@%s (%s)\n",
02554 buse->type,
02555 sub->parent->name,
02556 sub->parent->parent->name,
02557 s->device->model);
02558 }
02559 transmit_response(s, req);
02560 break;
02561 case SOFT_KEY_SET_REQ_MESSAGE:
02562 if (skinnydebug) {
02563 ast_verbose("Received SoftKeySetReq\n");
02564 }
02565 memset(req, 0, SKINNY_MAX_PACKET);
02566 req->len = htolel(sizeof(soft_key_sets)+4);
02567 req->e = htolel(SOFT_KEY_SET_RES_MESSAGE);
02568 req->data.softkeysets.softKeySetOffset = 0;
02569 req->data.softkeysets.softKeySetCount = htolel(11);
02570 req->data.softkeysets.totalSoftKeySetCount = htolel(11);
02571
02572 memcpy(req->data.softkeysets.softKeySetDefinition,
02573 soft_key_set_hack,
02574 sizeof(req->data.softkeysets.softKeySetDefinition));
02575 transmit_response(s,req);
02576 break;
02577 case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
02578 if (skinnydebug) {
02579 ast_verbose("Recieved SoftKey Template Request\n");
02580 }
02581 memset(req, 0, SKINNY_MAX_PACKET);
02582 req->len = htolel(sizeof(soft_key_template)+4);
02583 req->e = htolel(SOFT_KEY_TEMPLATE_RES_MESSAGE);
02584 req->data.softkeytemplate.softKeyOffset = 0;
02585 req->data.softkeytemplate.softKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(soft_key_template_definition));
02586 req->data.softkeytemplate.totalSoftKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(soft_key_template_definition));
02587 memcpy(req->data.softkeytemplate.softKeyTemplateDefinition,
02588 soft_key_template_default,
02589 sizeof(soft_key_template_default));
02590 transmit_response(s,req);
02591 break;
02592 case TIME_DATE_REQ_MESSAGE:
02593 if (skinnydebug) {
02594 ast_verbose("Received Time/Date Request\n");
02595 }
02596 memset(req, 0, SKINNY_MAX_PACKET);
02597 req->len = htolel(sizeof(definetimedate_message)+4);
02598 req->e = htolel(DEFINETIMEDATE_MESSAGE);
02599 timer=time(NULL);
02600 cmtime = localtime(&timer);
02601 req->data.definetimedate.year = htolel(cmtime->tm_year+1900);
02602 req->data.definetimedate.month = htolel(cmtime->tm_mon+1);
02603 req->data.definetimedate.dayofweek = htolel(cmtime->tm_wday);
02604 req->data.definetimedate.day = htolel(cmtime->tm_mday);
02605 req->data.definetimedate.hour = htolel(cmtime->tm_hour);
02606 req->data.definetimedate.minute = htolel(cmtime->tm_min);
02607 req->data.definetimedate.seconds = htolel(cmtime->tm_sec);
02608 transmit_response(s, req);
02609 break;
02610 case SPEED_DIAL_STAT_REQ_MESSAGE:
02611
02612
02613 speedDialNum = letohl(req->data.speeddialreq.speedDialNumber);
02614 memset(req, 0, SKINNY_MAX_PACKET);
02615 req->len = htolel(sizeof(speed_dial_stat_res_message)+4);
02616 req->e = htolel(SPEED_DIAL_STAT_RES_MESSAGE);
02617 #if 0
02618
02619
02620
02621 req->data.speeddialreq.speedDialNumber = speedDialNum;
02622 snprintf(req->data.speeddial.speedDialDirNumber, sizeof(req->data.speeddial.speedDialDirNumber), "31337");
02623 snprintf(req->data.speeddial.speedDialDisplayName, sizeof(req->data.speeddial.speedDialDisplayName),"Asterisk Rules!");
02624 #endif
02625 transmit_response(s, req);
02626 break;
02627 case LINE_STATE_REQ_MESSAGE:
02628 lineNumber = letohl(req->data.line.lineNumber);
02629 if (skinnydebug) {
02630 ast_verbose("Received LineStateReq\n");
02631 }
02632 memset(req, 0, SKINNY_MAX_PACKET);
02633 req->len = htolel(sizeof(line_stat_res_message)+4);
02634 req->e = htolel(LINE_STAT_RES_MESSAGE);
02635 sub = find_subchannel_by_line(s->device->lines);
02636 if (!sub) {
02637 ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
02638 return 0;
02639 }
02640 lines = sub->parent;
02641 ast_mutex_lock(&devicelock);
02642 for (i=1; i < lineNumber; i++) {
02643 lines = lines->next;
02644 }
02645 ast_mutex_unlock(&devicelock);
02646 req->data.linestat.linenumber = letohl(lineNumber);
02647 memcpy(req->data.linestat.lineDirNumber, lines->name,
02648 sizeof(req->data.linestat.lineDirNumber));
02649 memcpy(req->data.linestat.lineDisplayName, lines->label,
02650 sizeof(req->data.linestat.lineDisplayName));
02651 transmit_response(s,req);
02652 break;
02653 case CAPABILITIES_RES_MESSAGE:
02654 if (skinnydebug) {
02655 ast_verbose("Received CapabilitiesRes\n");
02656 }
02657
02658 break;
02659 case KEEP_ALIVE_MESSAGE:
02660 memset(req, 0, SKINNY_MAX_PACKET);
02661 req->len = htolel(4);
02662 req->e = htolel(KEEP_ALIVE_ACK_MESSAGE);
02663 transmit_response(s, req);
02664 do_housekeeping(s);
02665 break;
02666 case OFFHOOK_MESSAGE:
02667 transmit_ringer_mode(s,SKINNY_RING_OFF);
02668 transmit_lamp_indication(s, STIMULUS_LINE, s->device->lines->instance, SKINNY_LAMP_ON);
02669 sub = find_subchannel_by_line(s->device->lines);
02670 if (!sub) {
02671 ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
02672 return 0;
02673 }
02674 sub->parent->hookstate = SKINNY_OFFHOOK;
02675
02676 if (sub->outgoing) {
02677
02678 ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
02679 transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, sub->callid);
02680 transmit_tone(s, SKINNY_SILENCE);
02681 transmit_callstate(s, s->device->lines->instance, SKINNY_CONNECTED, sub->callid);
02682 start_rtp(sub);
02683 ast_setstate(sub->owner, AST_STATE_UP);
02684
02685 } else {
02686 if (!sub->owner) {
02687 transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, sub->callid);
02688 if (skinnydebug) {
02689 ast_verbose("Attempting to Clear display on Skinny %s@%s\n",sub->parent->name, sub->parent->parent->name);
02690 }
02691 transmit_displaymessage(s, NULL);
02692 transmit_tone(s, SKINNY_DIALTONE);
02693 c = skinny_new(sub, AST_STATE_DOWN);
02694 if(c) {
02695
02696 if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
02697 ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
02698 ast_hangup(c);
02699 }
02700 } else {
02701 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name, s->device->name);
02702 }
02703 } else {
02704 ast_log(LOG_DEBUG, "Current sub [%s] already has owner\n", sub->owner->name);
02705 }
02706 }
02707 break;
02708 case ONHOOK_MESSAGE:
02709 sub = find_subchannel_by_line(s->device->lines);
02710 if (sub->parent->hookstate == SKINNY_ONHOOK) {
02711
02712 break;
02713 }
02714 sub->cxmode = SKINNY_CX_RECVONLY;
02715 sub->parent->hookstate = SKINNY_ONHOOK;
02716 transmit_callstate(s, s->device->lines->instance, sub->parent->hookstate,sub->callid);
02717 if (skinnydebug) {
02718 ast_verbose("Skinny %s@%s went on hook\n",sub->parent->name, sub->parent->parent->name);
02719 }
02720 if (sub->parent->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
02721
02722
02723
02724 #if 0
02725 if ((res = attempt_transfer(p)) < 0) {
02726 if (p->sub->next->owner) {
02727 sub->next->alreadygone = 1;
02728 ast_queue_hangup(sub->next->owner,1);
02729 }
02730 } else if (res) {
02731 ast_log(LOG_WARNING, "Transfer attempt failed\n");
02732 return -1;
02733 }
02734 #endif
02735 } else {
02736
02737
02738 if (sub->owner) {
02739 sub->alreadygone = 1;
02740 ast_queue_hangup(sub->owner);
02741 } else {
02742 ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n",
02743 sub->parent->name, sub->parent->parent->name, sub->callid);
02744 }
02745 }
02746 if ((sub->parent->hookstate == SKINNY_ONHOOK) && (!sub->next->rtp)) {
02747 do_housekeeping(s);
02748 }
02749 break;
02750 case KEYPAD_BUTTON_MESSAGE:
02751 digit = letohl(req->data.keypad.button);
02752 if (skinnydebug) {
02753 ast_verbose("Collected digit: [%d]\n", digit);
02754 }
02755 f.frametype = AST_FRAME_DTMF;
02756 if (digit == 14) {
02757 d = '*';
02758 } else if (digit == 15) {
02759 d = '#';
02760 } else if (digit >=0 && digit <= 9) {
02761 d = '0' + digit;
02762 } else {
02763
02764
02765
02766
02767
02768
02769
02770 d = '0' + digit;
02771 ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
02772 }
02773 f.subclass = d;
02774 f.src = "skinny";
02775 sub = find_subchannel_by_line(s->device->lines);
02776 if (sub->owner) {
02777
02778 ast_queue_frame(sub->owner, &f);
02779 if (sub->next->owner) {
02780 ast_queue_frame(sub->next->owner, &f);
02781 }
02782 } else {
02783 ast_verbose("No owner: %s\n", s->device->lines->name);
02784 }
02785 break;
02786 case OPEN_RECIEVE_CHANNEL_ACK_MESSAGE:
02787 ast_verbose("Recieved Open Recieve Channel Ack\n");
02788 status = letohl(req->data.openrecievechannelack.status);
02789 if (status) {
02790 ast_log(LOG_ERROR, "Open Recieve Channel Failure\n");
02791 break;
02792 }
02793
02794 memcpy(addr, req->data.openrecievechannelack.ipAddr, sizeof(addr));
02795 port = htolel(req->data.openrecievechannelack.port);
02796 sin.sin_family = AF_INET;
02797
02798 memcpy(&sin.sin_addr, addr, sizeof(sin.sin_addr));
02799 sin.sin_port = htons(port);
02800 if (skinnydebug) {
02801 ast_verbose("ipaddr = %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
02802 }
02803 sub = find_subchannel_by_line(s->device->lines);
02804 if (sub->rtp) {
02805 ast_rtp_set_peer(sub->rtp, &sin);
02806 ast_rtp_get_us(sub->rtp, &us);
02807 } else {
02808 ast_log(LOG_ERROR, "No RTP structure, this is very bad\n");
02809 break;
02810 }
02811 memset(req, 0, SKINNY_MAX_PACKET);
02812 req->len = htolel(sizeof(start_media_transmission_message)+4);
02813 req->e = htolel(START_MEDIA_TRANSMISSION_MESSAGE);
02814 req->data.startmedia.conferenceId = 0;
02815 req->data.startmedia.passThruPartyId = 0;
02816 memcpy(req->data.startmedia.remoteIp, &s->device->ourip, 4);
02817 req->data.startmedia.remotePort = htolel(ntohs(us.sin_port));
02818 req->data.startmedia.packetSize = htolel(20);
02819 req->data.startmedia.payloadType = htolel(convert_cap(s->device->lines->capability));
02820 req->data.startmedia.qualifier.precedence = htolel(127);
02821 req->data.startmedia.qualifier.vad = 0;
02822 req->data.startmedia.qualifier.packets = 0;
02823 req->data.startmedia.qualifier.bitRate = 0;
02824 transmit_response(s, req);
02825 break;
02826 default:
02827 ast_verbose("RECEIVED UNKNOWN MESSAGE TYPE: %x\n", letohl(req->e));
02828 break;
02829 }
02830 free(req);
02831 return 1;
02832 }
02833
02834 static void destroy_session(struct skinnysession *s)
02835 {
02836 struct skinnysession *cur, *prev = NULL;
02837 ast_mutex_lock(&sessionlock);
02838 cur = sessions;
02839 while(cur) {
02840 if (cur == s) {
02841 break;
02842 }
02843 prev = cur;
02844 cur = cur->next;
02845 }
02846 if (cur) {
02847 if (prev) {
02848 prev->next = cur->next;
02849 } else {
02850 sessions = cur->next;
02851 }
02852 if (s->fd > -1) {
02853 close(s->fd);
02854 }
02855 ast_mutex_destroy(&s->lock);
02856 free(s);
02857 } else {
02858 ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
02859 }
02860 ast_mutex_unlock(&sessionlock);
02861 }
02862
02863 static int get_input(struct skinnysession *s)
02864 {
02865 int res;
02866 int dlen = 0;
02867 struct pollfd fds[1];
02868
02869 fds[0].fd = s->fd;
02870 fds[0].events = POLLIN;
02871 res = poll(fds, 1, -1);
02872
02873 if (res < 0) {
02874 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
02875 } else if (res > 0) {
02876 memset(s->inbuf,0,sizeof(s->inbuf));
02877 res = read(s->fd, s->inbuf, 4);
02878 if (res != 4) {
02879 ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
02880 return -1;
02881 }
02882 dlen = letohl(*(int *)s->inbuf);
02883 if (dlen+8 > sizeof(s->inbuf)) {
02884 dlen = sizeof(s->inbuf) - 8;
02885 }
02886 *(int *)s->inbuf = htolel(dlen);
02887 res = read(s->fd, s->inbuf+4, dlen+4);
02888 ast_mutex_unlock(&s->lock);
02889 if (res != (dlen+4)) {
02890 ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
02891 return -1;
02892 }
02893 }
02894 return res;
02895 }
02896
02897 static skinny_req *skinny_req_parse(struct skinnysession *s)
02898 {
02899 skinny_req *req;
02900
02901 req = malloc(SKINNY_MAX_PACKET);
02902 if (!req) {
02903 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
02904 return NULL;
02905 }
02906 memset(req, 0, sizeof(skinny_req));
02907
02908 memcpy(req, s->inbuf, letohl(*(int*)(s->inbuf))+8);
02909 if (letohl(req->e) < 0) {
02910 ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
02911 free(req);
02912 return NULL;
02913 }
02914 return req;
02915 }
02916
02917 static void *skinny_session(void *data)
02918 {
02919 int res;
02920 skinny_req *req;
02921 struct skinnysession *s = data;
02922 char iabuf[INET_ADDRSTRLEN];
02923
02924 ast_verbose(VERBOSE_PREFIX_3 "Starting Skinny session from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
02925 for (;;) {
02926 res = 0;
02927 res = get_input(s);
02928 if (res < 0) {
02929 break;
02930 }
02931 req = skinny_req_parse(s);
02932 if (!req) {
02933 return NULL;
02934 }
02935 res = handle_message(req, s);
02936 if (res < 0) {
02937 destroy_session(s);
02938 return NULL;
02939 }
02940 }
02941 ast_log(LOG_NOTICE, "Skinny Session returned: %s\n", strerror(errno));
02942 destroy_session(s);
02943 return 0;
02944 }
02945
02946 static void *accept_thread(void *ignore)
02947 {
02948 int as;
02949 struct sockaddr_in sin;
02950 socklen_t sinlen;
02951 struct skinnysession *s;
02952 struct protoent *p;
02953 int arg = 1;
02954 pthread_attr_t attr;
02955
02956 pthread_attr_init(&attr);
02957 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02958
02959 for (;;) {
02960 sinlen = sizeof(sin);
02961 as = accept(skinnysock, (struct sockaddr *)&sin, &sinlen);
02962 if (as < 0) {
02963 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
02964 continue;
02965 }
02966 p = getprotobyname("tcp");
02967 if(p) {
02968 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
02969 ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
02970 }
02971 }
02972 s = malloc(sizeof(struct skinnysession));
02973 if (!s) {
02974 ast_log(LOG_WARNING, "Failed to allocate Skinny session: %s\n", strerror(errno));
02975 continue;
02976 }
02977 memset(s, 0, sizeof(struct skinnysession));
02978 memcpy(&s->sin, &sin, sizeof(sin));
02979 ast_mutex_init(&s->lock);
02980 s->fd = as;
02981 ast_mutex_lock(&sessionlock);
02982 s->next = sessions;
02983 sessions = s;
02984 ast_mutex_unlock(&sessionlock);
02985
02986 if (ast_pthread_create(&tcp_thread, NULL, skinny_session, s)) {
02987 destroy_session(s);
02988 }
02989 }
02990 if (skinnydebug) {
02991 ast_verbose("killing accept thread\n");
02992 }
02993 close(as);
02994 return 0;
02995 }
02996
02997 static void *do_monitor(void *data)
02998 {
02999 int res;
03000
03001
03002
03003
03004 for(;;) {
03005 pthread_testcancel();
03006
03007 res = ast_sched_wait(sched);
03008 if ((res < 0) || (res > 1000)) {
03009 res = 1000;
03010 }
03011 res = ast_io_wait(io, res);
03012 ast_mutex_lock(&monlock);
03013 if (res >= 0) {
03014 ast_sched_runq(sched);
03015 }
03016 ast_mutex_unlock(&monlock);
03017 }
03018
03019 return NULL;
03020
03021 }
03022
03023 static int restart_monitor(void)
03024 {
03025
03026 if (monitor_thread == AST_PTHREADT_STOP)
03027 return 0;
03028 if (ast_mutex_lock(&monlock)) {
03029 ast_log(LOG_WARNING, "Unable to lock monitor\n");
03030 return -1;
03031 }
03032 if (monitor_thread == pthread_self()) {
03033 ast_mutex_unlock(&monlock);
03034 ast_log(LOG_WARNING, "Cannot kill myself\n");
03035 return -1;
03036 }
03037 if (monitor_thread != AST_PTHREADT_NULL) {
03038
03039 pthread_kill(monitor_thread, SIGURG);
03040 } else {
03041
03042 if (ast_pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) {
03043 ast_mutex_unlock(&monlock);
03044 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
03045 return -1;
03046 }
03047 }
03048 ast_mutex_unlock(&monlock);
03049 return 0;
03050 }
03051
03052 static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause)
03053 {
03054 int oldformat;
03055 struct skinny_subchannel *sub;
03056 struct ast_channel *tmpc = NULL;
03057 char tmp[256];
03058 char *dest = data;
03059
03060 oldformat = format;
03061 format &= capability;
03062 if (!format) {
03063 ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
03064 return NULL;
03065 }
03066 strncpy(tmp, dest, sizeof(tmp) - 1);
03067 if (ast_strlen_zero(tmp)) {
03068 ast_log(LOG_NOTICE, "Skinny channels require a device\n");
03069 return NULL;
03070 }
03071 sub = find_subchannel_by_name(tmp);
03072 if (!sub) {
03073 ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
03074 return NULL;
03075 }
03076 if (option_verbose > 2) {
03077 ast_verbose(VERBOSE_PREFIX_3 "skinny_request(%s)\n", tmp);
03078 ast_verbose(VERBOSE_PREFIX_3 "Skinny cw: %d, dnd: %d, so: %d, sno: %d\n",
03079 sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
03080 }
03081 tmpc = skinny_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
03082 if (!tmpc) {
03083 ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
03084 }
03085 restart_monitor();
03086 return tmpc;
03087 }
03088
03089 static int reload_config(void)
03090 {
03091 int on = 1;
03092 struct ast_config *cfg;
03093 struct ast_variable *v;
03094 int format;
03095 char *cat;
03096 char iabuf[INET_ADDRSTRLEN];
03097 struct skinny_device *d;
03098 int oldport = ntohs(bindaddr.sin_port);
03099
03100 if (gethostname(ourhost, sizeof(ourhost))) {
03101 ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled\n");
03102 return 0;
03103 }
03104 cfg = ast_config_load(config);
03105
03106
03107 if (!cfg) {
03108 ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled\n", config);
03109 return 0;
03110 }
03111
03112 memset(&bindaddr, 0, sizeof(bindaddr));
03113 v = ast_variable_browse(cfg, "general");
03114 while(v) {
03115
03116 if (!strcasecmp(v->name, "bindaddr")) {
03117 if (!(hp = ast_gethostbyname(v->value, &ahp))) {
03118 ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
03119 } else {
03120 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
03121 }
03122 } else if (!strcasecmp(v->name, "keepAlive")) {
03123 keep_alive = atoi(v->value);
03124 } else if (!strcasecmp(v->name, "dateFormat")) {
03125 strncpy(date_format, v->value, sizeof(date_format) - 1);
03126 } else if (!strcasecmp(v->name, "allow")) {
03127 format = ast_getformatbyname(v->value);
03128 if (format < 1) {
03129 ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
03130 } else {
03131 capability |= format;
03132 }
03133 } else if (!strcasecmp(v->name, "disallow")) {
03134 format = ast_getformatbyname(v->value);
03135 if (format < 1) {
03136 ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
03137 } else {
03138 capability &= ~format;
03139 }
03140 } else if (!strcasecmp(v->name, "port")) {
03141 if (sscanf(v->value, "%d", &ourport) == 1) {
03142 bindaddr.sin_port = htons(ourport);
03143 } else {
03144 ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
03145 }
03146 }
03147 v = v->next;
03148 }
03149 if (ntohl(bindaddr.sin_addr.s_addr)) {
03150 memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
03151 } else {
03152 hp = ast_gethostbyname(ourhost, &ahp);
03153 if (!hp) {
03154 ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
03155 ast_config_destroy(cfg);
03156 return 0;
03157 }
03158 memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
03159 }
03160 if (!ntohs(bindaddr.sin_port)) {
03161 bindaddr.sin_port = ntohs(DEFAULT_SKINNY_PORT);
03162 }
03163 bindaddr.sin_family = AF_INET;
03164
03165
03166 cat = ast_category_browse(cfg, NULL);
03167 while(cat) {
03168 if (!strcasecmp(cat, "general")) {
03169
03170 #if 0
03171 } else if (!strncasecmp(cat, "paging-", 7)) {
03172 p = build_paging_device(cat, ast_variable_browse(cfg, cat));
03173 if (p) {
03174 }
03175 #endif
03176 } else {
03177 d = build_device(cat, ast_variable_browse(cfg, cat));
03178 if (d) {
03179 if (option_verbose > 2) {
03180 ast_verbose(VERBOSE_PREFIX_3 "Added device '%s'\n", d->name);
03181 }
03182 ast_mutex_lock(&devicelock);
03183 d->next = devices;
03184 devices = d;
03185 ast_mutex_unlock(&devicelock);
03186 }
03187 }
03188 cat = ast_category_browse(cfg, cat);
03189 }
03190 ast_mutex_lock(&netlock);
03191 if ((skinnysock > -1) && (ntohs(bindaddr.sin_port) != oldport)) {
03192 close(skinnysock);
03193 skinnysock = -1;
03194 }
03195 if (skinnysock < 0) {
03196 skinnysock = socket(AF_INET, SOCK_STREAM, 0);
03197 if(setsockopt(skinnysock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
03198 ast_log(LOG_ERROR, "Set Socket Options failed: errno %d, %s", errno, strerror(errno));
03199 ast_config_destroy(cfg);
03200 return 0;
03201 }
03202 if (skinnysock < 0) {
03203 ast_log(LOG_WARNING, "Unable to create Skinny socket: %s\n", strerror(errno));
03204 } else {
03205 if (bind(skinnysock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
03206 ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
03207 ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port),
03208 strerror(errno));
03209 close(skinnysock);
03210 skinnysock = -1;
03211 ast_config_destroy(cfg);
03212 return 0;
03213 }
03214 if (listen(skinnysock,DEFAULT_SKINNY_BACKLOG)) {
03215 ast_log(LOG_WARNING, "Failed to start listening to %s:%d: %s\n",
03216 ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port),
03217 strerror(errno));
03218 close(skinnysock);
03219 skinnysock = -1;
03220 ast_config_destroy(cfg);
03221 return 0;
03222 }
03223 if (option_verbose > 1) {
03224 ast_verbose(VERBOSE_PREFIX_2 "Skinny listening on %s:%d\n",
03225 ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port));
03226 }
03227 ast_pthread_create(&accept_t,NULL, accept_thread, NULL);
03228 }
03229 }
03230 ast_mutex_unlock(&netlock);
03231 ast_config_destroy(cfg);
03232 return 0;
03233 }
03234
03235 void delete_devices(void)
03236 {
03237 struct skinny_device *d, *dlast;
03238 struct skinny_line *l, *llast;
03239 struct skinny_subchannel *sub, *slast;
03240
03241 ast_mutex_lock(&devicelock);
03242
03243
03244 for (d=devices;d;) {
03245
03246 for (l=d->lines;l;) {
03247
03248 for (sub=l->sub;sub;) {
03249 slast = sub;
03250 sub = sub->next;
03251 ast_mutex_destroy(&slast->lock);
03252 free(slast);
03253 }
03254 llast = l;
03255 l = l->next;
03256 ast_mutex_destroy(&llast->lock);
03257 free(llast);
03258 }
03259 dlast = d;
03260 d = d->next;
03261 free(dlast);
03262 }
03263 devices=NULL;
03264 ast_mutex_unlock(&devicelock);
03265 }
03266
03267 int reload(void)
03268 {
03269 delete_devices();
03270 reload_config();
03271 restart_monitor();
03272 return 0;
03273 }
03274
03275
03276 int load_module()
03277 {
03278 int res = 0;
03279
03280 for (; res < (sizeof(soft_key_template_default) / sizeof(soft_key_template_default[0])); res++) {
03281 soft_key_template_default[res].softKeyEvent = htolel(soft_key_template_default[res].softKeyEvent);
03282 }
03283
03284 res = reload_config();
03285
03286 ast_rtp_proto_register(&skinny_rtp);
03287 ast_cli_register(&cli_show_devices);
03288 ast_cli_register(&cli_show_lines);
03289 ast_cli_register(&cli_debug);
03290 ast_cli_register(&cli_no_debug);
03291 sched = sched_context_create();
03292 if (!sched) {
03293 ast_log(LOG_WARNING, "Unable to create schedule context\n");
03294 }
03295 io = io_context_create();
03296 if (!io) {
03297 ast_log(LOG_WARNING, "Unable to create I/O context\n");
03298 }
03299
03300 restart_monitor();
03301
03302
03303 if (!res) {
03304
03305 if (ast_channel_register(&skinny_tech)) {
03306 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
03307 return -1;
03308 }
03309 }
03310 return res;
03311 }
03312
03313 int unload_module()
03314 {
03315 #if 0
03316 struct skinny_session *session, s;
03317 struct skinny_subchannel *sub;
03318 struct skinny_line *line = session;
03319
03320
03321 if (!ast_mutex_lock(&devicelock)) {
03322
03323 } else {
03324 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
03325 return -1;
03326 }
03327 if (!ast_mutex_lock(&monlock)) {
03328 if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
03329 pthread_cancel(monitor_thread);
03330 pthread_kill(monitor_thread, SIGURG);
03331 pthread_join(monitor_thread, NULL);
03332 }
03333 monitor_thread = AST_PTHREADT_STOP;
03334 ast_mutex_unlock(&monlock);
03335 } else {
03336 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
03337 return -1;
03338 }
03339 if (!ast_mutex_lock(&iflock)) {
03340
03341 p = iflist;
03342 while(p) {
03343 pl = p;
03344 p = p->next;
03345
03346 ast_mutex_destroy(&pl->lock);
03347 free(pl);
03348 }
03349 iflist = NULL;
03350 ast_mutex_unlock(&iflock);
03351 } else {
03352 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
03353 return -1;
03354 }
03355
03356 ast_rtp_proto_register(&skinny_rtp);
03357 ast_channel_unregister(&skinny_tech);
03358 ast_cli_register(&cli_show_devices);
03359 ast_cli_register(&cli_show_lines);
03360 ast_cli_register(&cli_debug);
03361 ast_cli_register(&cli_no_debug);
03362
03363 return 0;
03364 #endif
03365 return -1;
03366 }
03367
03368 int usecount()
03369 {
03370 return usecnt;
03371 }
03372
03373 char *key()
03374 {
03375 return ASTERISK_GPL_KEY;
03376 }
03377
03378 char *description()
03379 {
03380 return (char *) desc;
03381 }