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