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