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
00029 #include "asterisk.h"
00030
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00032
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <unistd.h>
00037 #include <sys/socket.h>
00038 #include <netinet/in.h>
00039 #include <netinet/tcp.h>
00040 #include <sys/ioctl.h>
00041 #include <net/if.h>
00042 #include <errno.h>
00043 #include <fcntl.h>
00044 #include <netdb.h>
00045 #include <arpa/inet.h>
00046 #include <sys/signal.h>
00047 #include <signal.h>
00048 #include <ctype.h>
00049
00050 #include "asterisk/lock.h"
00051 #include "asterisk/channel.h"
00052 #include "asterisk/config.h"
00053 #include "asterisk/logger.h"
00054 #include "asterisk/module.h"
00055 #include "asterisk/pbx.h"
00056 #include "asterisk/options.h"
00057 #include "asterisk/lock.h"
00058 #include "asterisk/sched.h"
00059 #include "asterisk/io.h"
00060 #include "asterisk/rtp.h"
00061 #include "asterisk/acl.h"
00062 #include "asterisk/callerid.h"
00063 #include "asterisk/cli.h"
00064 #include "asterisk/say.h"
00065 #include "asterisk/cdr.h"
00066 #include "asterisk/astdb.h"
00067 #include "asterisk/features.h"
00068 #include "asterisk/app.h"
00069 #include "asterisk/musiconhold.h"
00070 #include "asterisk/utils.h"
00071 #include "asterisk/dsp.h"
00072 #include "asterisk/stringfields.h"
00073 #include "asterisk/astobj.h"
00074 #include "asterisk/abstract_jb.h"
00075 #include "asterisk/threadstorage.h"
00076
00077
00078
00079
00080 static const char tdesc[] = "Skinny Client Control Protocol (Skinny)";
00081 static const char config[] = "skinny.conf";
00082
00083 static int default_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW;
00084 static struct ast_codec_pref default_prefs;
00085
00086 enum skinny_codecs {
00087 SKINNY_CODEC_ALAW = 2,
00088 SKINNY_CODEC_ULAW = 4,
00089 SKINNY_CODEC_G723_1 = 9,
00090 SKINNY_CODEC_G729A = 12,
00091 SKINNY_CODEC_G726_32 = 82,
00092 SKINNY_CODEC_H261 = 100,
00093 SKINNY_CODEC_H263 = 101
00094 };
00095
00096 #define DEFAULT_SKINNY_PORT 2000
00097 #define DEFAULT_SKINNY_BACKLOG 2
00098 #define SKINNY_MAX_PACKET 1000
00099
00100 static int keep_alive = 120;
00101 static char date_format[6] = "D-M-Y";
00102 static char version_id[16] = "P002F202";
00103
00104 #if __BYTE_ORDER == __LITTLE_ENDIAN
00105 #define letohl(x) (x)
00106 #define letohs(x) (x)
00107 #define htolel(x) (x)
00108 #define htoles(x) (x)
00109 #else
00110 #if defined(SOLARIS) || defined(__Darwin__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
00111 #define __bswap_16(x) \
00112 ((((x) & 0xff00) >> 8) | \
00113 (((x) & 0x00ff) << 8))
00114 #define __bswap_32(x) \
00115 ((((x) & 0xff000000) >> 24) | \
00116 (((x) & 0x00ff0000) >> 8) | \
00117 (((x) & 0x0000ff00) << 8) | \
00118 (((x) & 0x000000ff) << 24))
00119 #else
00120 #include <bits/byteswap.h>
00121 #endif
00122 #define letohl(x) __bswap_32(x)
00123 #define letohs(x) __bswap_16(x)
00124 #define htolel(x) __bswap_32(x)
00125 #define htoles(x) __bswap_16(x)
00126 #endif
00127
00128
00129 static struct ast_jb_conf default_jbconf =
00130 {
00131 .flags = 0,
00132 .max_size = -1,
00133 .resync_threshold = -1,
00134 .impl = ""
00135 };
00136 static struct ast_jb_conf global_jbconf;
00137
00138 AST_THREADSTORAGE(device2str_threadbuf, device2str_threadbuf_init);
00139 #define DEVICE2STR_BUFSIZE 15
00140
00141 AST_THREADSTORAGE(control2str_threadbuf, control2str_threadbuf_init);
00142 #define CONTROL2STR_BUFSIZE 100
00143
00144
00145
00146
00147
00148 #define KEEP_ALIVE_MESSAGE 0x0000
00149
00150
00151 #define REGISTER_MESSAGE 0x0001
00152 struct register_message {
00153 char name[16];
00154 uint32_t userId;
00155 uint32_t instance;
00156 uint32_t ip;
00157 uint32_t type;
00158 uint32_t maxStreams;
00159 };
00160
00161 #define IP_PORT_MESSAGE 0x0002
00162
00163 #define KEYPAD_BUTTON_MESSAGE 0x0003
00164 struct keypad_button_message {
00165 uint32_t button;
00166 uint32_t lineInstance;
00167 uint32_t callReference;
00168 };
00169
00170
00171 #define ENBLOC_CALL_MESSAGE 0x0004
00172 struct enbloc_call_message {
00173 char calledParty[24];
00174 };
00175
00176 #define STIMULUS_MESSAGE 0x0005
00177 struct stimulus_message {
00178 uint32_t stimulus;
00179 uint32_t stimulusInstance;
00180 uint32_t callreference;
00181 };
00182
00183 #define OFFHOOK_MESSAGE 0x0006
00184 struct offhook_message {
00185 uint32_t unknown1;
00186 uint32_t unknown2;
00187 };
00188
00189 #define ONHOOK_MESSAGE 0x0007
00190 struct onhook_message {
00191 uint32_t unknown1;
00192 uint32_t unknown2;
00193 };
00194
00195 #define CAPABILITIES_RES_MESSAGE 0x0010
00196 struct station_capabilities {
00197 uint32_t codec;
00198 uint32_t frames;
00199 union {
00200 char res[8];
00201 uint32_t rate;
00202 } payloads;
00203 };
00204
00205 #define SKINNY_MAX_CAPABILITIES 18
00206
00207 struct capabilities_res_message {
00208 uint32_t count;
00209 struct station_capabilities caps[SKINNY_MAX_CAPABILITIES];
00210 };
00211
00212 #define SPEED_DIAL_STAT_REQ_MESSAGE 0x000A
00213 struct speed_dial_stat_req_message {
00214 uint32_t speedDialNumber;
00215 };
00216
00217 #define LINE_STATE_REQ_MESSAGE 0x000B
00218 struct line_state_req_message {
00219 uint32_t lineNumber;
00220 };
00221
00222 #define TIME_DATE_REQ_MESSAGE 0x000D
00223 #define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
00224 #define VERSION_REQ_MESSAGE 0x000F
00225 #define SERVER_REQUEST_MESSAGE 0x0012
00226
00227 #define ALARM_MESSAGE 0x0020
00228 struct alarm_message {
00229 uint32_t alarmSeverity;
00230 char displayMessage[80];
00231 uint32_t alarmParam1;
00232 uint32_t alarmParam2;
00233 };
00234
00235 #define OPEN_RECEIVE_CHANNEL_ACK_MESSAGE 0x0022
00236 struct open_receive_channel_ack_message {
00237 uint32_t status;
00238 uint32_t ipAddr;
00239 uint32_t port;
00240 uint32_t passThruId;
00241 };
00242
00243 #define SOFT_KEY_SET_REQ_MESSAGE 0x0025
00244
00245 #define SOFT_KEY_EVENT_MESSAGE 0x0026
00246 struct soft_key_event_message {
00247 uint32_t softKeyEvent;
00248 uint32_t instance;
00249 uint32_t callreference;
00250 };
00251
00252 #define UNREGISTER_MESSAGE 0x0027
00253 #define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028
00254 #define HEADSET_STATUS_MESSAGE 0x002B
00255 #define REGISTER_AVAILABLE_LINES_MESSAGE 0x002D
00256
00257 #define REGISTER_ACK_MESSAGE 0x0081
00258 struct register_ack_message {
00259 uint32_t keepAlive;
00260 char dateTemplate[6];
00261 char res[2];
00262 uint32_t secondaryKeepAlive;
00263 char res2[4];
00264 };
00265
00266 #define START_TONE_MESSAGE 0x0082
00267 struct start_tone_message {
00268 uint32_t tone;
00269 uint32_t space;
00270 uint32_t instance;
00271 uint32_t reference;
00272 };
00273
00274 #define STOP_TONE_MESSAGE 0x0083
00275 struct stop_tone_message {
00276 uint32_t instance;
00277 uint32_t reference;
00278 };
00279
00280 #define SET_RINGER_MESSAGE 0x0085
00281 struct set_ringer_message {
00282 uint32_t ringerMode;
00283 uint32_t unknown1;
00284 uint32_t unknown2;
00285 uint32_t space[2];
00286 };
00287
00288 #define SET_LAMP_MESSAGE 0x0086
00289 struct set_lamp_message {
00290 uint32_t stimulus;
00291 uint32_t stimulusInstance;
00292 uint32_t deviceStimulus;
00293 };
00294
00295 #define SET_SPEAKER_MESSAGE 0x0088
00296 struct set_speaker_message {
00297 uint32_t mode;
00298 };
00299
00300
00301 #define SET_MICROPHONE_MESSAGE 0x0089
00302 struct set_microphone_message {
00303 uint32_t mode;
00304 };
00305
00306 #define START_MEDIA_TRANSMISSION_MESSAGE 0x008A
00307 struct media_qualifier {
00308 uint32_t precedence;
00309 uint32_t vad;
00310 uint16_t packets;
00311 uint32_t bitRate;
00312 };
00313
00314 struct start_media_transmission_message {
00315 uint32_t conferenceId;
00316 uint32_t passThruPartyId;
00317 uint32_t remoteIp;
00318 uint32_t remotePort;
00319 uint32_t packetSize;
00320 uint32_t payloadType;
00321 struct media_qualifier qualifier;
00322 uint32_t space[16];
00323 };
00324
00325 #define STOP_MEDIA_TRANSMISSION_MESSAGE 0x008B
00326 struct stop_media_transmission_message {
00327 uint32_t conferenceId;
00328 uint32_t passThruPartyId;
00329 uint32_t space[3];
00330 };
00331
00332 #define CALL_INFO_MESSAGE 0x008F
00333 struct call_info_message {
00334 char callingPartyName[40];
00335 char callingParty[24];
00336 char calledPartyName[40];
00337 char calledParty[24];
00338 uint32_t instance;
00339 uint32_t reference;
00340 uint32_t type;
00341 char originalCalledPartyName[40];
00342 char originalCalledParty[24];
00343 char lastRedirectingPartyName[40];
00344 char lastRedirectingParty[24];
00345 uint32_t originalCalledPartyRedirectReason;
00346 uint32_t lastRedirectingReason;
00347 char callingPartyVoiceMailbox[24];
00348 char calledPartyVoiceMailbox[24];
00349 char originalCalledPartyVoiceMailbox[24];
00350 char lastRedirectingVoiceMailbox[24];
00351 uint32_t space[3];
00352 };
00353
00354 #define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
00355 struct speed_dial_stat_res_message {
00356 uint32_t speedDialNumber;
00357 char speedDialDirNumber[24];
00358 char speedDialDisplayName[40];
00359 };
00360
00361 #define LINE_STAT_RES_MESSAGE 0x0092
00362 struct line_stat_res_message {
00363 uint32_t lineNumber;
00364 char lineDirNumber[24];
00365 char lineDisplayName[24];
00366 uint32_t space[15];
00367 };
00368
00369 #define DEFINETIMEDATE_MESSAGE 0x0094
00370 struct definetimedate_message {
00371 uint32_t year;
00372 uint32_t month;
00373 uint32_t dayofweek;
00374 uint32_t day;
00375 uint32_t hour;
00376 uint32_t minute;
00377 uint32_t seconds;
00378 uint32_t milliseconds;
00379 uint32_t timestamp;
00380 };
00381
00382 #define BUTTON_TEMPLATE_RES_MESSAGE 0x0097
00383 struct button_definition {
00384 uint8_t instanceNumber;
00385 uint8_t buttonDefinition;
00386 };
00387
00388 struct button_definition_template {
00389 uint8_t buttonDefinition;
00390
00391
00392 };
00393
00394 #define STIMULUS_REDIAL 0x01
00395 #define STIMULUS_SPEEDDIAL 0x02
00396 #define STIMULUS_HOLD 0x03
00397 #define STIMULUS_TRANSFER 0x04
00398 #define STIMULUS_FORWARDALL 0x05
00399 #define STIMULUS_FORWARDBUSY 0x06
00400 #define STIMULUS_FORWARDNOANSWER 0x07
00401 #define STIMULUS_DISPLAY 0x08
00402 #define STIMULUS_LINE 0x09
00403 #define STIMULUS_VOICEMAIL 0x0F
00404 #define STIMULUS_AUTOANSWER 0x11
00405 #define STIMULUS_CONFERENCE 0x7D
00406 #define STIMULUS_CALLPARK 0x7E
00407 #define STIMULUS_CALLPICKUP 0x7F
00408 #define STIMULUS_NONE 0xFF
00409
00410
00411 #define BT_REDIAL STIMULUS_REDIAL
00412 #define BT_SPEEDDIAL STIMULUS_SPEEDDIAL
00413 #define BT_HOLD STIMULUS_HOLD
00414 #define BT_TRANSFER STIMULUS_TRANSFER
00415 #define BT_FORWARDALL STIMULUS_FORWARDALL
00416 #define BT_FORWARDBUSY STIMULUS_FORWARDBUSY
00417 #define BT_FORWARDNOANSWER STIMULUS_FORWARDNOANSWER
00418 #define BT_DISPLAY STIMULUS_DISPLAY
00419 #define BT_LINE STIMULUS_LINE
00420 #define BT_VOICEMAIL STIMULUS_VOICEMAIL
00421 #define BT_AUTOANSWER STIMULUS_AUTOANSWER
00422 #define BT_CONFERENCE STIMULUS_CONFERENCE
00423 #define BT_CALLPARK STIMULUS_CALLPARK
00424 #define BT_CALLPICKUP STIMULUS_CALLPICKUP
00425 #define BT_NONE 0x00
00426
00427
00428
00429
00430 #define BT_CUST_LINESPEEDDIAL 0xB0
00431 #define BT_CUST_HINT 0xB1
00432
00433 struct button_template_res_message {
00434 uint32_t buttonOffset;
00435 uint32_t buttonCount;
00436 uint32_t totalButtonCount;
00437 struct button_definition definition[42];
00438 };
00439
00440 #define VERSION_RES_MESSAGE 0x0098
00441 struct version_res_message {
00442 char version[16];
00443 };
00444
00445 #define DISPLAYTEXT_MESSAGE 0x0099
00446 struct displaytext_message {
00447 char text[40];
00448 };
00449
00450 #define CLEAR_NOTIFY_MESSAGE 0x0115
00451 #define CLEAR_DISPLAY_MESSAGE 0x009A
00452
00453 #define CAPABILITIES_REQ_MESSAGE 0x009B
00454
00455 #define REGISTER_REJ_MESSAGE 0x009D
00456 struct register_rej_message {
00457 char errMsg[33];
00458 };
00459
00460 #define SERVER_RES_MESSAGE 0x009E
00461 struct server_identifier {
00462 char serverName[48];
00463 };
00464
00465 struct server_res_message {
00466 struct server_identifier server[5];
00467 uint32_t serverListenPort[5];
00468 uint32_t serverIpAddr[5];
00469 };
00470
00471 #define RESET_MESSAGE 0x009F
00472 struct reset_message {
00473 uint32_t resetType;
00474 };
00475
00476 #define KEEP_ALIVE_ACK_MESSAGE 0x0100
00477
00478 #define OPEN_RECEIVE_CHANNEL_MESSAGE 0x0105
00479 struct open_receive_channel_message {
00480 uint32_t conferenceId;
00481 uint32_t partyId;
00482 uint32_t packets;
00483 uint32_t capability;
00484 uint32_t echo;
00485 uint32_t bitrate;
00486 uint32_t space[16];
00487 };
00488
00489 #define CLOSE_RECEIVE_CHANNEL_MESSAGE 0x0106
00490 struct close_receive_channel_message {
00491 uint32_t conferenceId;
00492 uint32_t partyId;
00493 uint32_t space[2];
00494 };
00495
00496 #define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108
00497
00498 struct soft_key_template_definition {
00499 char softKeyLabel[16];
00500 uint32_t softKeyEvent;
00501 };
00502
00503 #define KEYDEF_ONHOOK 0
00504 #define KEYDEF_CONNECTED 1
00505 #define KEYDEF_ONHOLD 2
00506 #define KEYDEF_RINGIN 3
00507 #define KEYDEF_OFFHOOK 4
00508 #define KEYDEF_CONNWITHTRANS 5
00509 #define KEYDEF_DADFD 6
00510 #define KEYDEF_CONNWITHCONF 7
00511 #define KEYDEF_RINGOUT 8
00512 #define KEYDEF_OFFHOOKWITHFEAT 9
00513 #define KEYDEF_UNKNOWN 10
00514
00515 #define SOFTKEY_NONE 0x00
00516 #define SOFTKEY_REDIAL 0x01
00517 #define SOFTKEY_NEWCALL 0x02
00518 #define SOFTKEY_HOLD 0x03
00519 #define SOFTKEY_TRNSFER 0x04
00520 #define SOFTKEY_CFWDALL 0x05
00521 #define SOFTKEY_CFWDBUSY 0x06
00522 #define SOFTKEY_CFWDNOANSWER 0x07
00523 #define SOFTKEY_BKSPC 0x08
00524 #define SOFTKEY_ENDCALL 0x09
00525 #define SOFTKEY_RESUME 0x0A
00526 #define SOFTKEY_ANSWER 0x0B
00527 #define SOFTKEY_INFO 0x0C
00528 #define SOFTKEY_CONFRN 0x0D
00529 #define SOFTKEY_PARK 0x0E
00530 #define SOFTKEY_JOIN 0x0F
00531 #define SOFTKEY_MEETME 0x10
00532 #define SOFTKEY_PICKUP 0x11
00533 #define SOFTKEY_GPICKUP 0x12
00534
00535 struct soft_key_template_definition soft_key_template_default[] = {
00536 { "Redial", 0x01 },
00537 { "NewCall", 0x02 },
00538 { "Hold", 0x03 },
00539 { "Trnsfer", 0x04 },
00540 { "CFwdAll", 0x05 },
00541 { "CFwdBusy", 0x06 },
00542 { "CFwdNoAnswer", 0x07 },
00543 { "<<", 0x08 },
00544 { "EndCall", 0x09 },
00545 { "Resume", 0x0A },
00546 { "Answer", 0x0B },
00547 { "Info", 0x0C },
00548 { "Confrn", 0x0D },
00549 { "Park", 0x0E },
00550 { "Join", 0x0F },
00551 { "MeetMe", 0x10 },
00552 { "PickUp", 0x11 },
00553 { "GPickUp", 0x12 },
00554 };
00555
00556 struct soft_key_definitions {
00557 const uint8_t mode;
00558 const uint8_t *defaults;
00559 const int count;
00560 };
00561
00562 static const uint8_t soft_key_default_onhook[] = {
00563 SOFTKEY_REDIAL,
00564 SOFTKEY_NEWCALL,
00565 SOFTKEY_CFWDALL,
00566 SOFTKEY_CFWDBUSY,
00567
00568
00569 };
00570
00571 static const uint8_t soft_key_default_connected[] = {
00572 SOFTKEY_HOLD,
00573 SOFTKEY_ENDCALL,
00574 SOFTKEY_TRNSFER,
00575 SOFTKEY_PARK,
00576 SOFTKEY_CFWDALL,
00577 SOFTKEY_CFWDBUSY,
00578 };
00579
00580 static const uint8_t soft_key_default_onhold[] = {
00581 SOFTKEY_RESUME,
00582 SOFTKEY_NEWCALL,
00583 SOFTKEY_ENDCALL,
00584 SOFTKEY_TRNSFER,
00585 };
00586
00587 static const uint8_t soft_key_default_ringin[] = {
00588 SOFTKEY_ANSWER,
00589 SOFTKEY_ENDCALL,
00590 SOFTKEY_TRNSFER,
00591 };
00592
00593 static const uint8_t soft_key_default_offhook[] = {
00594 SOFTKEY_REDIAL,
00595 SOFTKEY_ENDCALL,
00596 SOFTKEY_CFWDALL,
00597 SOFTKEY_CFWDBUSY,
00598
00599 };
00600
00601 static const uint8_t soft_key_default_connwithtrans[] = {
00602 SOFTKEY_HOLD,
00603 SOFTKEY_ENDCALL,
00604 SOFTKEY_TRNSFER,
00605 SOFTKEY_PARK,
00606 SOFTKEY_CFWDALL,
00607 SOFTKEY_CFWDBUSY,
00608 };
00609
00610 static const uint8_t soft_key_default_dadfd[] = {
00611 SOFTKEY_BKSPC,
00612 SOFTKEY_ENDCALL,
00613 };
00614
00615 static const uint8_t soft_key_default_connwithconf[] = {
00616 SOFTKEY_NONE,
00617 };
00618
00619 static const uint8_t soft_key_default_ringout[] = {
00620 SOFTKEY_NONE,
00621 SOFTKEY_ENDCALL,
00622 };
00623
00624 static const uint8_t soft_key_default_offhookwithfeat[] = {
00625 SOFTKEY_REDIAL,
00626 SOFTKEY_ENDCALL,
00627 };
00628
00629 static const uint8_t soft_key_default_unknown[] = {
00630 SOFTKEY_NONE,
00631 };
00632
00633 static const struct soft_key_definitions soft_key_default_definitions[] = {
00634 {KEYDEF_ONHOOK, soft_key_default_onhook, sizeof(soft_key_default_onhook) / sizeof(uint8_t)},
00635 {KEYDEF_CONNECTED, soft_key_default_connected, sizeof(soft_key_default_connected) / sizeof(uint8_t)},
00636 {KEYDEF_ONHOLD, soft_key_default_onhold, sizeof(soft_key_default_onhold) / sizeof(uint8_t)},
00637 {KEYDEF_RINGIN, soft_key_default_ringin, sizeof(soft_key_default_ringin) / sizeof(uint8_t)},
00638 {KEYDEF_OFFHOOK, soft_key_default_offhook, sizeof(soft_key_default_offhook) / sizeof(uint8_t)},
00639 {KEYDEF_CONNWITHTRANS, soft_key_default_connwithtrans, sizeof(soft_key_default_connwithtrans) / sizeof(uint8_t)},
00640 {KEYDEF_DADFD, soft_key_default_dadfd, sizeof(soft_key_default_dadfd) / sizeof(uint8_t)},
00641 {KEYDEF_CONNWITHCONF, soft_key_default_connwithconf, sizeof(soft_key_default_connwithconf) / sizeof(uint8_t)},
00642 {KEYDEF_RINGOUT, soft_key_default_ringout, sizeof(soft_key_default_ringout) / sizeof(uint8_t)},
00643 {KEYDEF_OFFHOOKWITHFEAT, soft_key_default_offhookwithfeat, sizeof(soft_key_default_offhookwithfeat) / sizeof(uint8_t)},
00644 {KEYDEF_UNKNOWN, soft_key_default_unknown, sizeof(soft_key_default_unknown) / sizeof(uint8_t)}
00645 };
00646
00647 struct soft_key_template_res_message {
00648 uint32_t softKeyOffset;
00649 uint32_t softKeyCount;
00650 uint32_t totalSoftKeyCount;
00651 struct soft_key_template_definition softKeyTemplateDefinition[32];
00652 };
00653
00654 #define SOFT_KEY_SET_RES_MESSAGE 0x0109
00655
00656 struct soft_key_set_definition {
00657 uint8_t softKeyTemplateIndex[16];
00658 uint16_t softKeyInfoIndex[16];
00659 };
00660
00661 struct soft_key_set_res_message {
00662 uint32_t softKeySetOffset;
00663 uint32_t softKeySetCount;
00664 uint32_t totalSoftKeySetCount;
00665 struct soft_key_set_definition softKeySetDefinition[16];
00666 uint32_t res;
00667 };
00668
00669 #define SELECT_SOFT_KEYS_MESSAGE 0x0110
00670 struct select_soft_keys_message {
00671 uint32_t instance;
00672 uint32_t reference;
00673 uint32_t softKeySetIndex;
00674 uint32_t validKeyMask;
00675 };
00676
00677 #define CALL_STATE_MESSAGE 0x0111
00678 struct call_state_message {
00679 uint32_t callState;
00680 uint32_t lineInstance;
00681 uint32_t callReference;
00682 uint32_t space[3];
00683 };
00684
00685 #define DISPLAY_PROMPT_STATUS_MESSAGE 0x0112
00686 struct display_prompt_status_message {
00687 uint32_t messageTimeout;
00688 char promptMessage[32];
00689 uint32_t lineInstance;
00690 uint32_t callReference;
00691 };
00692
00693 #define CLEAR_PROMPT_MESSAGE 0x0113
00694 struct clear_prompt_message {
00695 uint32_t lineInstance;
00696 uint32_t callReference;
00697 };
00698
00699 #define DISPLAY_NOTIFY_MESSAGE 0x0114
00700 struct display_notify_message {
00701 uint32_t displayTimeout;
00702 char displayMessage[100];
00703 };
00704
00705 #define ACTIVATE_CALL_PLANE_MESSAGE 0x0116
00706 struct activate_call_plane_message {
00707 uint32_t lineInstance;
00708 };
00709
00710 #define DIALED_NUMBER_MESSAGE 0x011D
00711 struct dialed_number_message {
00712 char dialedNumber[24];
00713 uint32_t lineInstance;
00714 uint32_t callReference;
00715 };
00716
00717 union skinny_data {
00718 struct alarm_message alarm;
00719 struct speed_dial_stat_req_message speeddialreq;
00720 struct register_message reg;
00721 struct register_ack_message regack;
00722 struct register_rej_message regrej;
00723 struct capabilities_res_message caps;
00724 struct version_res_message version;
00725 struct button_template_res_message buttontemplate;
00726 struct displaytext_message displaytext;
00727 struct display_prompt_status_message displaypromptstatus;
00728 struct clear_prompt_message clearpromptstatus;
00729 struct definetimedate_message definetimedate;
00730 struct start_tone_message starttone;
00731 struct stop_tone_message stoptone;
00732 struct speed_dial_stat_res_message speeddial;
00733 struct line_state_req_message line;
00734 struct line_stat_res_message linestat;
00735 struct soft_key_set_res_message softkeysets;
00736 struct soft_key_template_res_message softkeytemplate;
00737 struct server_res_message serverres;
00738 struct reset_message reset;
00739 struct set_lamp_message setlamp;
00740 struct set_ringer_message setringer;
00741 struct call_state_message callstate;
00742 struct keypad_button_message keypad;
00743 struct select_soft_keys_message selectsoftkey;
00744 struct activate_call_plane_message activatecallplane;
00745 struct stimulus_message stimulus;
00746 struct offhook_message offhook;
00747 struct onhook_message onhook;
00748 struct set_speaker_message setspeaker;
00749 struct set_microphone_message setmicrophone;
00750 struct call_info_message callinfo;
00751 struct start_media_transmission_message startmedia;
00752 struct stop_media_transmission_message stopmedia;
00753 struct open_receive_channel_message openreceivechannel;
00754 struct open_receive_channel_ack_message openreceivechannelack;
00755 struct close_receive_channel_message closereceivechannel;
00756 struct display_notify_message displaynotify;
00757 struct dialed_number_message dialednumber;
00758 struct soft_key_event_message softkeyeventmessage;
00759 struct enbloc_call_message enbloccallmessage;
00760 };
00761
00762
00763 struct skinny_req {
00764 int len;
00765 int res;
00766 int e;
00767 union skinny_data data;
00768 };
00769
00770
00771
00772
00773 int skinny_header_size = 12;
00774
00775
00776
00777
00778
00779 static int skinnydebug = 0;
00780
00781
00782 static struct sockaddr_in bindaddr;
00783 static char ourhost[256];
00784 static int ourport;
00785 static struct in_addr __ourip;
00786 struct ast_hostent ahp;
00787 struct hostent *hp;
00788 static int skinnysock = -1;
00789 static pthread_t accept_t;
00790 static char context[AST_MAX_CONTEXT] = "default";
00791 static char language[MAX_LANGUAGE] = "";
00792 static char mohinterpret[MAX_MUSICCLASS] = "default";
00793 static char mohsuggest[MAX_MUSICCLASS] = "";
00794 static char cid_num[AST_MAX_EXTENSION] = "";
00795 static char cid_name[AST_MAX_EXTENSION] = "";
00796 static char linelabel[AST_MAX_EXTENSION] ="";
00797 static int nat = 0;
00798 static ast_group_t cur_callergroup = 0;
00799 static ast_group_t cur_pickupgroup = 0;
00800 static int immediate = 0;
00801 static int callwaiting = 0;
00802 static int callreturn = 0;
00803 static int threewaycalling = 0;
00804 static int mwiblink = 0;
00805
00806 static int transfer = 0;
00807 static int cancallforward = 0;
00808
00809 static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
00810 static char mailbox[AST_MAX_EXTENSION];
00811 static int amaflags = 0;
00812 static int callnums = 1;
00813
00814 #define SKINNY_DEVICE_UNKNOWN -1
00815 #define SKINNY_DEVICE_NONE 0
00816 #define SKINNY_DEVICE_30SPPLUS 1
00817 #define SKINNY_DEVICE_12SPPLUS 2
00818 #define SKINNY_DEVICE_12SP 3
00819 #define SKINNY_DEVICE_12 4
00820 #define SKINNY_DEVICE_30VIP 5
00821 #define SKINNY_DEVICE_7910 6
00822 #define SKINNY_DEVICE_7960 7
00823 #define SKINNY_DEVICE_7940 8
00824 #define SKINNY_DEVICE_7935 9
00825 #define SKINNY_DEVICE_ATA186 12
00826 #define SKINNY_DEVICE_7941 115
00827 #define SKINNY_DEVICE_7971 119
00828 #define SKINNY_DEVICE_7985 302
00829 #define SKINNY_DEVICE_7911 307
00830 #define SKINNY_DEVICE_7961GE 308
00831 #define SKINNY_DEVICE_7941GE 309
00832 #define SKINNY_DEVICE_7921 365
00833 #define SKINNY_DEVICE_7905 20000
00834 #define SKINNY_DEVICE_7920 30002
00835 #define SKINNY_DEVICE_7970 30006
00836 #define SKINNY_DEVICE_7912 30007
00837 #define SKINNY_DEVICE_7902 30008
00838 #define SKINNY_DEVICE_CIPC 30016
00839 #define SKINNY_DEVICE_7961 30018
00840 #define SKINNY_DEVICE_7936 30019
00841 #define SKINNY_DEVICE_SCCPGATEWAY_AN 30027
00842 #define SKINNY_DEVICE_SCCPGATEWAY_BRI 30028
00843
00844 #define SKINNY_SPEAKERON 1
00845 #define SKINNY_SPEAKEROFF 2
00846
00847 #define SKINNY_MICON 1
00848 #define SKINNY_MICOFF 2
00849
00850 #define SKINNY_OFFHOOK 1
00851 #define SKINNY_ONHOOK 2
00852 #define SKINNY_RINGOUT 3
00853 #define SKINNY_RINGIN 4
00854 #define SKINNY_CONNECTED 5
00855 #define SKINNY_BUSY 6
00856 #define SKINNY_CONGESTION 7
00857 #define SKINNY_HOLD 8
00858 #define SKINNY_CALLWAIT 9
00859 #define SKINNY_TRANSFER 10
00860 #define SKINNY_PARK 11
00861 #define SKINNY_PROGRESS 12
00862 #define SKINNY_INVALID 14
00863
00864 #define SKINNY_SILENCE 0x00
00865 #define SKINNY_DIALTONE 0x21
00866 #define SKINNY_BUSYTONE 0x23
00867 #define SKINNY_ALERT 0x24
00868 #define SKINNY_REORDER 0x25
00869 #define SKINNY_CALLWAITTONE 0x2D
00870 #define SKINNY_NOTONE 0x7F
00871
00872 #define SKINNY_LAMP_OFF 1
00873 #define SKINNY_LAMP_ON 2
00874 #define SKINNY_LAMP_WINK 3
00875 #define SKINNY_LAMP_FLASH 4
00876 #define SKINNY_LAMP_BLINK 5
00877
00878 #define SKINNY_RING_OFF 1
00879 #define SKINNY_RING_INSIDE 2
00880 #define SKINNY_RING_OUTSIDE 3
00881 #define SKINNY_RING_FEATURE 4
00882
00883 #define TYPE_TRUNK 1
00884 #define TYPE_LINE 2
00885
00886
00887 #define SKINNY_CX_SENDONLY 0
00888 #define SKINNY_CX_RECVONLY 1
00889 #define SKINNY_CX_SENDRECV 2
00890 #define SKINNY_CX_CONF 3
00891 #define SKINNY_CX_CONFERENCE 3
00892 #define SKINNY_CX_MUTE 4
00893 #define SKINNY_CX_INACTIVE 4
00894
00895 #if 0
00896 static char *skinny_cxmodes[] = {
00897 "sendonly",
00898 "recvonly",
00899 "sendrecv",
00900 "confrnce",
00901 "inactive"
00902 };
00903 #endif
00904
00905
00906 static struct sched_context *sched = NULL;
00907 static struct io_context *io;
00908
00909
00910
00911 AST_MUTEX_DEFINE_STATIC(monlock);
00912
00913 AST_MUTEX_DEFINE_STATIC(netlock);
00914
00915 AST_MUTEX_DEFINE_STATIC(sessionlock);
00916
00917 AST_MUTEX_DEFINE_STATIC(devicelock);
00918 #if 0
00919
00920 AST_MUTEX_DEFINE_STATIC(pagingdevicelock);
00921 #endif
00922
00923
00924
00925 static pthread_t monitor_thread = AST_PTHREADT_NULL;
00926
00927
00928 static int firstdigittimeout = 16000;
00929
00930
00931 static int gendigittimeout = 8000;
00932
00933
00934 static int matchdigittimeout = 3000;
00935
00936 struct skinny_subchannel {
00937 ast_mutex_t lock;
00938 struct ast_channel *owner;
00939 struct ast_rtp *rtp;
00940 struct ast_rtp *vrtp;
00941 unsigned int callid;
00942
00943 int progress;
00944 int ringing;
00945 int onhold;
00946
00947 int cxmode;
00948 int nat;
00949 int outgoing;
00950 int alreadygone;
00951
00952 struct skinny_subchannel *next;
00953 struct skinny_line *parent;
00954 };
00955
00956 struct skinny_line {
00957 ast_mutex_t lock;
00958 char name[80];
00959 char label[24];
00960 char accountcode[AST_MAX_ACCOUNT_CODE];
00961 char exten[AST_MAX_EXTENSION];
00962 char context[AST_MAX_CONTEXT];
00963 char language[MAX_LANGUAGE];
00964 char cid_num[AST_MAX_EXTENSION];
00965 char cid_name[AST_MAX_EXTENSION];
00966 char lastcallerid[AST_MAX_EXTENSION];
00967 char call_forward[AST_MAX_EXTENSION];
00968 char mailbox[AST_MAX_EXTENSION];
00969 char mohinterpret[MAX_MUSICCLASS];
00970 char mohsuggest[MAX_MUSICCLASS];
00971 char lastnumberdialed[AST_MAX_EXTENSION];
00972 int curtone;
00973 ast_group_t callgroup;
00974 ast_group_t pickupgroup;
00975 int callwaiting;
00976 int transfer;
00977 int threewaycalling;
00978 int mwiblink;
00979 int cancallforward;
00980 int callreturn;
00981 int dnd;
00982 int hascallerid;
00983 int hidecallerid;
00984 int amaflags;
00985 int type;
00986 int instance;
00987 int group;
00988 int needdestroy;
00989 int capability;
00990 int nonCodecCapability;
00991 int onhooktime;
00992 int msgstate;
00993 int immediate;
00994 int hookstate;
00995 int nat;
00996
00997 struct ast_codec_pref prefs;
00998 struct skinny_subchannel *sub;
00999 struct skinny_line *next;
01000 struct skinny_device *parent;
01001 };
01002
01003 struct skinny_speeddial {
01004 ast_mutex_t lock;
01005 char label[42];
01006 char exten[AST_MAX_EXTENSION];
01007 int instance;
01008
01009 struct skinny_speeddial *next;
01010 struct skinny_device *parent;
01011 };
01012
01013 struct skinny_addon {
01014 ast_mutex_t lock;
01015 char type[10];
01016
01017 struct skinny_addon *next;
01018 struct skinny_device *parent;
01019 };
01020
01021 static struct skinny_device {
01022
01023 char name[80];
01024 char id[16];
01025 char version_id[16];
01026 int type;
01027 int registered;
01028 int lastlineinstance;
01029 int lastcallreference;
01030 int capability;
01031 char exten[AST_MAX_EXTENSION];
01032 struct sockaddr_in addr;
01033 struct in_addr ourip;
01034 struct skinny_line *lines;
01035 struct skinny_speeddial *speeddials;
01036 struct skinny_addon *addons;
01037 struct ast_codec_pref prefs;
01038 struct ast_ha *ha;
01039 struct skinnysession *session;
01040 struct skinny_device *next;
01041 } *devices = NULL;
01042
01043 struct skinny_paging_device {
01044 char name[80];
01045 char id[16];
01046 struct skinny_device ** devices;
01047 struct skinny_paging_device *next;
01048 };
01049
01050 static struct skinnysession {
01051 pthread_t t;
01052 ast_mutex_t lock;
01053 struct sockaddr_in sin;
01054 int fd;
01055 char inbuf[SKINNY_MAX_PACKET];
01056 char outbuf[SKINNY_MAX_PACKET];
01057 struct skinny_device *device;
01058 struct skinnysession *next;
01059 } *sessions = NULL;
01060
01061 static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause);
01062 static int skinny_call(struct ast_channel *ast, char *dest, int timeout);
01063 static int skinny_hangup(struct ast_channel *ast);
01064 static int skinny_answer(struct ast_channel *ast);
01065 static struct ast_frame *skinny_read(struct ast_channel *ast);
01066 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame);
01067 static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
01068 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
01069 static int skinny_senddigit_begin(struct ast_channel *ast, char digit);
01070 static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
01071 static int handle_time_date_req_message(struct skinny_req *req, struct skinnysession *s);
01072
01073 static const struct ast_channel_tech skinny_tech = {
01074 .type = "Skinny",
01075 .description = tdesc,
01076 .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
01077 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
01078 .requester = skinny_request,
01079 .call = skinny_call,
01080 .hangup = skinny_hangup,
01081 .answer = skinny_answer,
01082 .read = skinny_read,
01083 .write = skinny_write,
01084 .indicate = skinny_indicate,
01085 .fixup = skinny_fixup,
01086 .send_digit_begin = skinny_senddigit_begin,
01087 .send_digit_end = skinny_senddigit_end,
01088
01089 };
01090
01091 static void *get_button_template(struct skinnysession *s, struct button_definition_template *btn)
01092 {
01093 struct skinny_device *d = s->device;
01094 struct skinny_addon *a = d->addons;
01095 int i;
01096
01097 switch (d->type) {
01098 case SKINNY_DEVICE_30SPPLUS:
01099 case SKINNY_DEVICE_30VIP:
01100
01101 for (i = 0; i < 4; i++)
01102 (btn++)->buttonDefinition = BT_LINE;
01103 (btn++)->buttonDefinition = BT_REDIAL;
01104 (btn++)->buttonDefinition = BT_VOICEMAIL;
01105 (btn++)->buttonDefinition = BT_CALLPARK;
01106 (btn++)->buttonDefinition = BT_FORWARDALL;
01107 (btn++)->buttonDefinition = BT_CONFERENCE;
01108 for (i = 0; i < 4; i++)
01109 (btn++)->buttonDefinition = BT_NONE;
01110 for (i = 0; i < 13; i++)
01111 (btn++)->buttonDefinition = BT_SPEEDDIAL;
01112
01113 break;
01114 case SKINNY_DEVICE_12SPPLUS:
01115 case SKINNY_DEVICE_12SP:
01116 case SKINNY_DEVICE_12:
01117
01118 for (i = 0; i < 2; i++)
01119 (btn++)->buttonDefinition = BT_LINE;
01120 (btn++)->buttonDefinition = BT_REDIAL;
01121 for (i = 0; i < 3; i++)
01122 (btn++)->buttonDefinition = BT_SPEEDDIAL;
01123 (btn++)->buttonDefinition = BT_HOLD;
01124 (btn++)->buttonDefinition = BT_TRANSFER;
01125 (btn++)->buttonDefinition = BT_FORWARDALL;
01126 (btn++)->buttonDefinition = BT_CALLPARK;
01127 (btn++)->buttonDefinition = BT_VOICEMAIL;
01128 (btn++)->buttonDefinition = BT_CONFERENCE;
01129 break;
01130 case SKINNY_DEVICE_7910:
01131 (btn++)->buttonDefinition = BT_LINE;
01132 (btn++)->buttonDefinition = BT_HOLD;
01133 (btn++)->buttonDefinition = BT_TRANSFER;
01134 (btn++)->buttonDefinition = BT_DISPLAY;
01135 (btn++)->buttonDefinition = BT_VOICEMAIL;
01136 (btn++)->buttonDefinition = BT_CONFERENCE;
01137 (btn++)->buttonDefinition = BT_FORWARDALL;
01138 for (i = 0; i < 2; i++)
01139 (btn++)->buttonDefinition = BT_SPEEDDIAL;
01140 (btn++)->buttonDefinition = BT_REDIAL;
01141 break;
01142 case SKINNY_DEVICE_7960:
01143 case SKINNY_DEVICE_7961:
01144 case SKINNY_DEVICE_7961GE:
01145 for (i = 0; i < 6; i++)
01146 (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
01147 break;
01148 case SKINNY_DEVICE_7940:
01149 case SKINNY_DEVICE_7941:
01150 case SKINNY_DEVICE_7941GE:
01151 for (i = 0; i < 2; i++)
01152 (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
01153 break;
01154 case SKINNY_DEVICE_7935:
01155 case SKINNY_DEVICE_7936:
01156 for (i = 0; i < 2; i++)
01157 (btn++)->buttonDefinition = BT_LINE;
01158 break;
01159 case SKINNY_DEVICE_ATA186:
01160 (btn++)->buttonDefinition = BT_LINE;
01161 break;
01162 case SKINNY_DEVICE_7970:
01163 case SKINNY_DEVICE_7971:
01164 case SKINNY_DEVICE_CIPC:
01165 for (i = 0; i < 8; i++)
01166 (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
01167 break;
01168 case SKINNY_DEVICE_7985:
01169
01170 ast_log(LOG_WARNING, "Unsupported device type '%d (7985)' found.\n", d->type);
01171 break;
01172 case SKINNY_DEVICE_7912:
01173 case SKINNY_DEVICE_7911:
01174 case SKINNY_DEVICE_7905:
01175 (btn++)->buttonDefinition = BT_LINE;
01176 (btn++)->buttonDefinition = BT_HOLD;
01177 break;
01178 case SKINNY_DEVICE_7920:
01179
01180 for (i = 0; i < 4; i++)
01181 (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
01182 break;
01183 case SKINNY_DEVICE_7921:
01184 for (i = 0; i < 6; i++)
01185 (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
01186 break;
01187 case SKINNY_DEVICE_7902:
01188 ast_log(LOG_WARNING, "Unsupported device type '%d (7902)' found.\n", d->type);
01189 break;
01190 case SKINNY_DEVICE_SCCPGATEWAY_AN:
01191 case SKINNY_DEVICE_SCCPGATEWAY_BRI:
01192 ast_log(LOG_WARNING, "Unsupported device type '%d (SCCP gateway)' found.\n", d->type);
01193 break;
01194 default:
01195 ast_log(LOG_WARNING, "Unknown device type '%d' found.\n", d->type);
01196 break;
01197 }
01198
01199 for (a = d->addons; a; a = a->next) {
01200 if (!strcasecmp(a->type, "7914")) {
01201 for (i = 0; i < 14; i++)
01202 (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
01203 } else {
01204 ast_log(LOG_WARNING, "Unknown addon type '%s' found. Skipping.\n", a->type);
01205 }
01206 }
01207
01208 return btn;
01209 }
01210
01211 static struct skinny_req *req_alloc(size_t size, int response_message)
01212 {
01213 struct skinny_req *req;
01214
01215 if (!(req = ast_calloc(1, skinny_header_size + size + 4)))
01216 return NULL;
01217
01218 req->len = htolel(size+4);
01219 req->e = htolel(response_message);
01220
01221 return req;
01222 }
01223
01224 static struct skinny_line *find_line_by_instance(struct skinny_device *d, int instance)
01225 {
01226 struct skinny_line *l;
01227
01228 if (!instance)
01229 instance = 1;
01230
01231 for (l = d->lines; l; l = l->next) {
01232 if (l->instance == instance)
01233 break;
01234 }
01235
01236 if (!l) {
01237 ast_log(LOG_WARNING, "Could not find line with instance '%d' on device '%s'\n", instance, d->name);
01238 }
01239 return l;
01240 }
01241
01242 static struct skinny_line *find_line_by_name(const char *dest)
01243 {
01244 struct skinny_line *l;
01245 struct skinny_device *d;
01246 char line[256];
01247 char *at;
01248 char *device;
01249
01250 ast_copy_string(line, dest, sizeof(line));
01251 at = strchr(line, '@');
01252 if (!at) {
01253 ast_log(LOG_NOTICE, "Device '%s' has no @ (at) sign!\n", dest);
01254 return NULL;
01255 }
01256 *at++ = '\0';
01257 device = at;
01258 ast_mutex_lock(&devicelock);
01259 for (d = devices; d; d = d->next) {
01260 if (!strcasecmp(d->name, device)) {
01261 if (skinnydebug)
01262 ast_verbose("Found device: %s\n", d->name);
01263
01264 for (l = d->lines; l; l = l->next) {
01265
01266 if (!strcasecmp(l->name, line)) {
01267 ast_mutex_unlock(&devicelock);
01268 return l;
01269 }
01270 }
01271 }
01272 }
01273
01274 ast_mutex_unlock(&devicelock);
01275 return NULL;
01276 }
01277
01278
01279 static struct skinny_subchannel *find_subchannel_by_instance_reference(struct skinny_device *d, int instance, int reference)
01280 {
01281 struct skinny_line *l = find_line_by_instance(d, instance);
01282 struct skinny_subchannel *sub;
01283
01284 if (!l) {
01285 return NULL;
01286 }
01287
01288 if (!reference)
01289 sub = l->sub;
01290 else {
01291 for (sub = l->sub; sub; sub = sub->next) {
01292 if (sub->callid == reference)
01293 break;
01294 }
01295 }
01296
01297 if (!sub) {
01298 ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s'\n", reference, d->name);
01299 }
01300 return sub;
01301 }
01302
01303
01304 static struct skinny_subchannel *find_subchannel_by_reference(struct skinny_device *d, int reference)
01305 {
01306 struct skinny_line *l;
01307 struct skinny_subchannel *sub = NULL;
01308
01309 for (l = d->lines; l; l = l->next) {
01310 for (sub = l->sub; sub; sub = sub->next) {
01311 if (sub->callid == reference)
01312 break;
01313 }
01314 if (sub)
01315 break;
01316 }
01317
01318 if (!l) {
01319 ast_log(LOG_WARNING, "Could not find any lines that contained a subchannel with reference '%d' on device '%s'\n", reference, d->name);
01320 } else {
01321 if (!sub) {
01322 ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s@%s'\n", reference, l->name, d->name);
01323 }
01324 }
01325 return sub;
01326 }
01327
01328 static struct skinny_speeddial *find_speeddial_by_instance(struct skinny_device *d, int instance)
01329 {
01330 struct skinny_speeddial *sd;
01331
01332 for (sd = d->speeddials; sd; sd = sd->next) {
01333 if (sd->instance == instance)
01334 break;
01335 }
01336
01337 if (!sd) {
01338 ast_log(LOG_WARNING, "Could not find speeddial with instance '%d' on device '%s'\n", instance, d->name);
01339 }
01340 return sd;
01341 }
01342
01343 static int codec_skinny2ast(enum skinny_codecs skinnycodec)
01344 {
01345 switch (skinnycodec) {
01346 case SKINNY_CODEC_ALAW:
01347 return AST_FORMAT_ALAW;
01348 case SKINNY_CODEC_ULAW:
01349 return AST_FORMAT_ULAW;
01350 case SKINNY_CODEC_G723_1:
01351 return AST_FORMAT_G723_1;
01352 case SKINNY_CODEC_G729A:
01353 return AST_FORMAT_G729A;
01354 case SKINNY_CODEC_G726_32:
01355 return AST_FORMAT_G726_AAL2;
01356 case SKINNY_CODEC_H261:
01357 return AST_FORMAT_H261;
01358 case SKINNY_CODEC_H263:
01359 return AST_FORMAT_H263;
01360 default:
01361 return 0;
01362 }
01363 }
01364
01365 static int codec_ast2skinny(int astcodec)
01366 {
01367 switch (astcodec) {
01368 case AST_FORMAT_ALAW:
01369 return SKINNY_CODEC_ALAW;
01370 case AST_FORMAT_ULAW:
01371 return SKINNY_CODEC_ULAW;
01372 case AST_FORMAT_G723_1:
01373 return SKINNY_CODEC_G723_1;
01374 case AST_FORMAT_G729A:
01375 return SKINNY_CODEC_G729A;
01376 case AST_FORMAT_G726_AAL2:
01377 return SKINNY_CODEC_G726_32;
01378 case AST_FORMAT_H261:
01379 return SKINNY_CODEC_H261;
01380 case AST_FORMAT_H263:
01381 return SKINNY_CODEC_H263;
01382 default:
01383 return 0;
01384 }
01385 }
01386
01387
01388 static int skinny_register(struct skinny_req *req, struct skinnysession *s)
01389 {
01390 struct skinny_device *d;
01391 struct sockaddr_in sin;
01392 socklen_t slen;
01393
01394 ast_mutex_lock(&devicelock);
01395 for (d = devices; d; d = d->next) {
01396 if (!strcasecmp(req->data.reg.name, d->id)
01397 && ast_apply_ha(d->ha, &(s->sin))) {
01398 s->device = d;
01399 d->type = letohl(req->data.reg.type);
01400 if (ast_strlen_zero(d->version_id)) {
01401 ast_copy_string(d->version_id, version_id, sizeof(d->version_id));
01402 }
01403 d->registered = 1;
01404 d->session = s;
01405
01406 slen = sizeof(sin);
01407 if (getsockname(s->fd, (struct sockaddr *)&sin, &slen)) {
01408 ast_log(LOG_WARNING, "Cannot get socket name\n");
01409 sin.sin_addr = __ourip;
01410 }
01411 d->ourip = sin.sin_addr;
01412 break;
01413 }
01414 }
01415 ast_mutex_unlock(&devicelock);
01416 if (!d) {
01417 return 0;
01418 }
01419 return 1;
01420 }
01421
01422 static int skinny_unregister(struct skinny_req *req, struct skinnysession *s)
01423 {
01424 struct skinny_device *d;
01425
01426 d = s->device;
01427
01428 if (d) {
01429 d->session = NULL;
01430 d->registered = 0;
01431 }
01432
01433 return -1;
01434 }
01435
01436 static int transmit_response(struct skinnysession *s, struct skinny_req *req)
01437 {
01438 int res = 0;
01439
01440 if (!s) {
01441 ast_log(LOG_WARNING, "Asked to transmit to a non-existant session!\n");
01442 return -1;
01443 }
01444
01445 ast_mutex_lock(&s->lock);
01446
01447 if (skinnydebug)
01448 ast_log(LOG_VERBOSE, "writing packet type %04X (%d bytes) to socket %d\n", letohl(req->e), letohl(req->len)+8, s->fd);
01449
01450 if (letohl(req->len > SKINNY_MAX_PACKET) || letohl(req->len < 0)) {
01451 ast_log(LOG_WARNING, "transmit_response: the length of the request is out of bounds\n");
01452 return -1;
01453 }
01454
01455 memset(s->outbuf,0,sizeof(s->outbuf));
01456 memcpy(s->outbuf, req, skinny_header_size);
01457 memcpy(s->outbuf+skinny_header_size, &req->data, letohl(req->len));
01458
01459 res = write(s->fd, s->outbuf, letohl(req->len)+8);
01460
01461 if (res != letohl(req->len)+8) {
01462 ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, letohl(req->len)+8, strerror(errno));
01463 if (res == -1) {
01464 if (skinnydebug)
01465 ast_log(LOG_WARNING, "Transmit: Skinny Client was lost, unregistering\n");
01466 skinny_unregister(NULL, s);
01467 }
01468
01469 }
01470
01471 ast_mutex_unlock(&s->lock);
01472 return 1;
01473 }
01474
01475 static void transmit_speaker_mode(struct skinnysession *s, int mode)
01476 {
01477 struct skinny_req *req;
01478
01479 if (!(req = req_alloc(sizeof(struct set_speaker_message), SET_SPEAKER_MESSAGE)))
01480 return;
01481
01482 req->data.setspeaker.mode = htolel(mode);
01483 transmit_response(s, req);
01484 }
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498 static void transmit_callinfo(struct skinnysession *s, const char *fromname, const char *fromnum, const char *toname, const char *tonum, int instance, int callid, int calltype)
01499 {
01500 struct skinny_req *req;
01501
01502 if (!(req = req_alloc(sizeof(struct call_info_message), CALL_INFO_MESSAGE)))
01503 return;
01504
01505 if (skinnydebug)
01506 ast_verbose("Setting Callinfo to %s(%s) from %s(%s) on %s(%d)\n", fromname, fromnum, toname, tonum, s->device->name, instance);
01507
01508 if (fromname) {
01509 ast_copy_string(req->data.callinfo.callingPartyName, fromname, sizeof(req->data.callinfo.callingPartyName));
01510 }
01511 if (fromnum) {
01512 ast_copy_string(req->data.callinfo.callingParty, fromnum, sizeof(req->data.callinfo.callingParty));
01513 }
01514 if (toname) {
01515 ast_copy_string(req->data.callinfo.calledPartyName, toname, sizeof(req->data.callinfo.calledPartyName));
01516 }
01517 if (tonum) {
01518 ast_copy_string(req->data.callinfo.calledParty, tonum, sizeof(req->data.callinfo.calledParty));
01519 }
01520 req->data.callinfo.instance = htolel(instance);
01521 req->data.callinfo.reference = htolel(callid);
01522 req->data.callinfo.type = htolel(calltype);
01523 transmit_response(s, req);
01524 }
01525
01526 static void transmit_connect(struct skinnysession *s, struct skinny_subchannel *sub)
01527 {
01528 struct skinny_req *req;
01529 struct skinny_line *l = sub->parent;
01530 struct ast_format_list fmt;
01531
01532 if (!(req = req_alloc(sizeof(struct open_receive_channel_message), OPEN_RECEIVE_CHANNEL_MESSAGE)))
01533 return;
01534
01535 fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability));
01536
01537 req->data.openreceivechannel.conferenceId = htolel(sub->callid);
01538 req->data.openreceivechannel.partyId = htolel(sub->callid);
01539 req->data.openreceivechannel.packets = htolel(fmt.cur_ms);
01540 req->data.openreceivechannel.capability = htolel(codec_ast2skinny(fmt.bits));
01541 req->data.openreceivechannel.echo = htolel(0);
01542 req->data.openreceivechannel.bitrate = htolel(0);
01543 transmit_response(s, req);
01544 }
01545
01546 static void transmit_tone(struct skinnysession *s, int tone, int instance, int reference)
01547 {
01548 struct skinny_req *req;
01549
01550 if (tone == SKINNY_NOTONE) {
01551
01552 return;
01553 }
01554
01555 if (tone > 0) {
01556 if (!(req = req_alloc(sizeof(struct start_tone_message), START_TONE_MESSAGE)))
01557 return;
01558 req->data.starttone.tone = htolel(tone);
01559 req->data.starttone.instance = htolel(instance);
01560 req->data.starttone.reference = htolel(reference);
01561 } else {
01562 if (!(req = req_alloc(sizeof(struct stop_tone_message), STOP_TONE_MESSAGE)))
01563 return;
01564 req->data.stoptone.instance = htolel(instance);
01565 req->data.stoptone.reference = htolel(reference);
01566 }
01567
01568 if (tone > 0) {
01569 req->data.starttone.tone = htolel(tone);
01570 }
01571 transmit_response(s, req);
01572 }
01573
01574 static void transmit_selectsoftkeys(struct skinnysession *s, int instance, int callid, int softkey)
01575 {
01576 struct skinny_req *req;
01577
01578 if (!(req = req_alloc(sizeof(struct select_soft_keys_message), SELECT_SOFT_KEYS_MESSAGE)))
01579 return;
01580
01581 req->data.selectsoftkey.instance = htolel(instance);
01582 req->data.selectsoftkey.reference = htolel(callid);
01583 req->data.selectsoftkey.softKeySetIndex = htolel(softkey);
01584 req->data.selectsoftkey.validKeyMask = htolel(0xFFFFFFFF);
01585 transmit_response(s, req);
01586 }
01587
01588 static void transmit_lamp_indication(struct skinnysession *s, int stimulus, int instance, int indication)
01589 {
01590 struct skinny_req *req;
01591
01592 if (!(req = req_alloc(sizeof(struct set_lamp_message), SET_LAMP_MESSAGE)))
01593 return;
01594
01595 req->data.setlamp.stimulus = htolel(stimulus);
01596 req->data.setlamp.stimulusInstance = htolel(instance);
01597 req->data.setlamp.deviceStimulus = htolel(indication);
01598 transmit_response(s, req);
01599 }
01600
01601 static void transmit_ringer_mode(struct skinnysession *s, int mode)
01602 {
01603 struct skinny_req *req;
01604
01605 if (skinnydebug)
01606 ast_verbose("Setting ringer mode to '%d'.\n", mode);
01607
01608 if (!(req = req_alloc(sizeof(struct set_ringer_message), SET_RINGER_MESSAGE)))
01609 return;
01610
01611 req->data.setringer.ringerMode = htolel(mode);
01612
01613
01614
01615
01616
01617
01618
01619 req->data.setringer.unknown1 = htolel(1);
01620
01621
01622 req->data.setringer.unknown2 = htolel(1);
01623 transmit_response(s, req);
01624 }
01625
01626 static void transmit_displaymessage(struct skinnysession *s, const char *text, int instance, int reference)
01627 {
01628 struct skinny_req *req;
01629
01630 if (text == 0) {
01631 if (!(req = req_alloc(0, CLEAR_DISPLAY_MESSAGE)))
01632 return;
01633
01634 req->data.clearpromptstatus.lineInstance = instance;
01635 req->data.clearpromptstatus.callReference = reference;
01636
01637 if (skinnydebug)
01638 ast_verbose("Clearing Display\n");
01639 } else {
01640 if (!(req = req_alloc(sizeof(struct displaytext_message), DISPLAYTEXT_MESSAGE)))
01641 return;
01642
01643 ast_copy_string(req->data.displaytext.text, text, sizeof(req->data.displaytext.text));
01644 if (skinnydebug)
01645 ast_verbose("Displaying message '%s'\n", req->data.displaytext.text);
01646 }
01647
01648 transmit_response(s, req);
01649 }
01650
01651 static void transmit_displaynotify(struct skinnysession *s, const char *text, int t)
01652 {
01653 struct skinny_req *req;
01654
01655 if (!(req = req_alloc(sizeof(struct display_notify_message), DISPLAY_NOTIFY_MESSAGE)))
01656 return;
01657
01658 ast_copy_string(req->data.displaynotify.displayMessage, text, sizeof(req->data.displaynotify.displayMessage));
01659 req->data.displaynotify.displayTimeout = htolel(t);
01660
01661 if (skinnydebug)
01662 ast_verbose("Displaying notify '%s'\n", text);
01663
01664 transmit_response(s, req);
01665 }
01666
01667 static void transmit_displaypromptstatus(struct skinnysession *s, const char *text, int t, int instance, int callid)
01668 {
01669 struct skinny_req *req;
01670
01671 if (text == 0) {
01672 if (!(req = req_alloc(sizeof(struct clear_prompt_message), CLEAR_PROMPT_MESSAGE)))
01673 return;
01674
01675 req->data.clearpromptstatus.lineInstance = htolel(instance);
01676 req->data.clearpromptstatus.callReference = htolel(callid);
01677
01678 if (skinnydebug)
01679 ast_verbose("Clearing Prompt\n");
01680 } else {
01681 if (!(req = req_alloc(sizeof(struct display_prompt_status_message), DISPLAY_PROMPT_STATUS_MESSAGE)))
01682 return;
01683
01684 ast_copy_string(req->data.displaypromptstatus.promptMessage, text, sizeof(req->data.displaypromptstatus.promptMessage));
01685 req->data.displaypromptstatus.messageTimeout = htolel(t);
01686 req->data.displaypromptstatus.lineInstance = htolel(instance);
01687 req->data.displaypromptstatus.callReference = htolel(callid);
01688
01689 if (skinnydebug)
01690 ast_verbose("Displaying Prompt Status '%s'\n", text);
01691 }
01692
01693 transmit_response(s, req);
01694 }
01695
01696 static void transmit_dialednumber(struct skinnysession *s, const char *text, int instance, int callid)
01697 {
01698 struct skinny_req *req;
01699
01700 if (!(req = req_alloc(sizeof(struct dialed_number_message), DIALED_NUMBER_MESSAGE)))
01701 return;
01702
01703 ast_copy_string(req->data.dialednumber.dialedNumber, text, sizeof(req->data.dialednumber.dialedNumber));
01704 req->data.dialednumber.lineInstance = htolel(instance);
01705 req->data.dialednumber.callReference = htolel(callid);
01706
01707 transmit_response(s, req);
01708 }
01709
01710 static void transmit_callstate(struct skinnysession *s, int instance, int state, unsigned callid)
01711 {
01712 struct skinny_req *req;
01713
01714 if (state == SKINNY_ONHOOK) {
01715 if (!(req = req_alloc(sizeof(struct close_receive_channel_message), CLOSE_RECEIVE_CHANNEL_MESSAGE)))
01716 return;
01717
01718 req->data.closereceivechannel.conferenceId = htolel(callid);
01719 req->data.closereceivechannel.partyId = htolel(callid);
01720 transmit_response(s, req);
01721
01722 if (!(req = req_alloc(sizeof(struct stop_media_transmission_message), STOP_MEDIA_TRANSMISSION_MESSAGE)))
01723 return;
01724
01725 req->data.stopmedia.conferenceId = htolel(callid);
01726 req->data.stopmedia.passThruPartyId = htolel(callid);
01727 transmit_response(s, req);
01728
01729 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
01730
01731 transmit_displaypromptstatus(s, NULL, 0, instance, callid);
01732 }
01733
01734 if (!(req = req_alloc(sizeof(struct call_state_message), CALL_STATE_MESSAGE)))
01735 return;
01736
01737 req->data.callstate.callState = htolel(state);
01738 req->data.callstate.lineInstance = htolel(instance);
01739 req->data.callstate.callReference = htolel(callid);
01740 transmit_response(s, req);
01741
01742 if (state == SKINNY_ONHOOK) {
01743 transmit_selectsoftkeys(s, 0, 0, KEYDEF_ONHOOK);
01744 }
01745
01746 if (state == SKINNY_OFFHOOK || state == SKINNY_ONHOOK) {
01747 if (!(req = req_alloc(sizeof(struct activate_call_plane_message), ACTIVATE_CALL_PLANE_MESSAGE)))
01748 return;
01749
01750 req->data.activatecallplane.lineInstance = htolel(instance);
01751 transmit_response(s, req);
01752 }
01753 }
01754
01755
01756
01757
01758
01759
01760
01761
01762 static void do_housekeeping(struct skinnysession *s)
01763 {
01764
01765
01766
01767
01768
01769
01770
01771
01772 handle_time_date_req_message(NULL, s);
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788 }
01789
01790
01791
01792
01793 static enum ast_rtp_get_result skinny_get_vrtp_peer(struct ast_channel *c, struct ast_rtp **rtp)
01794 {
01795 struct skinny_subchannel *sub = NULL;
01796
01797 if (!(sub = c->tech_pvt) || !(sub->vrtp))
01798 return AST_RTP_GET_FAILED;
01799
01800 *rtp = sub->vrtp;
01801
01802 return AST_RTP_TRY_NATIVE;
01803 }
01804
01805 static enum ast_rtp_get_result skinny_get_rtp_peer(struct ast_channel *c, struct ast_rtp **rtp)
01806 {
01807 struct skinny_subchannel *sub = NULL;
01808
01809 if (!(sub = c->tech_pvt) || !(sub->rtp))
01810 return AST_RTP_GET_FAILED;
01811
01812 *rtp = sub->rtp;
01813
01814 return AST_RTP_TRY_NATIVE;
01815 }
01816
01817 static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
01818 {
01819 struct skinny_subchannel *sub;
01820 sub = c->tech_pvt;
01821 if (sub) {
01822
01823 return 0;
01824 }
01825 return -1;
01826 }
01827
01828 static struct ast_rtp_protocol skinny_rtp = {
01829 .type = "Skinny",
01830 .get_rtp_info = skinny_get_rtp_peer,
01831 .get_vrtp_info = skinny_get_vrtp_peer,
01832 .set_rtp_peer = skinny_set_rtp_peer,
01833 };
01834
01835 static int skinny_do_debug(int fd, int argc, char *argv[])
01836 {
01837 if (argc != 3) {
01838 return RESULT_SHOWUSAGE;
01839 }
01840 skinnydebug = 1;
01841 ast_cli(fd, "Skinny Debugging Enabled\n");
01842 return RESULT_SUCCESS;
01843 }
01844
01845 static int skinny_no_debug(int fd, int argc, char *argv[])
01846 {
01847 if (argc != 4) {
01848 return RESULT_SHOWUSAGE;
01849 }
01850 skinnydebug = 0;
01851 ast_cli(fd, "Skinny Debugging Disabled\n");
01852 return RESULT_SUCCESS;
01853 }
01854
01855 static char *complete_skinny_reset(const char *line, const char *word, int pos, int state)
01856 {
01857 struct skinny_device *d;
01858
01859 char *result = NULL;
01860 int wordlen = strlen(word);
01861 int which = 0;
01862
01863 if (pos == 2) {
01864 for (d = devices; d && !result; d = d->next) {
01865 if (!strncasecmp(word, d->id, wordlen) && ++which > state)
01866 result = ast_strdup(d->id);
01867 }
01868 }
01869
01870 return result;
01871 }
01872
01873 static int skinny_reset_device(int fd, int argc, char *argv[])
01874 {
01875 struct skinny_device *d;
01876 struct skinny_req *req;
01877
01878 if (argc < 3 || argc > 4) {
01879 return RESULT_SHOWUSAGE;
01880 }
01881 ast_mutex_lock(&devicelock);
01882
01883 for (d = devices; d; d = d->next) {
01884 int fullrestart = 0;
01885 if (!strcasecmp(argv[2], d->id) || !strcasecmp(argv[2], "all")) {
01886 if (!(d->session))
01887 continue;
01888
01889 if (!(req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE)))
01890 continue;
01891
01892 if (argc == 4 && !strcasecmp(argv[3], "restart"))
01893 fullrestart = 1;
01894
01895 if (fullrestart)
01896 req->data.reset.resetType = 2;
01897 else
01898 req->data.reset.resetType = 1;
01899
01900 if (option_verbose > 2)
01901 ast_verbose(VERBOSE_PREFIX_3 "%s device %s.\n", (fullrestart) ? "Restarting" : "Resetting", d->id);
01902 transmit_response(d->session, req);
01903 }
01904 }
01905 ast_mutex_unlock(&devicelock);
01906 return RESULT_SUCCESS;
01907 }
01908
01909 static char *device2str(int type)
01910 {
01911 char *tmp;
01912
01913 switch (type) {
01914 case SKINNY_DEVICE_NONE:
01915 return "No Device";
01916 case SKINNY_DEVICE_30SPPLUS:
01917 return "30SP Plus";
01918 case SKINNY_DEVICE_12SPPLUS:
01919 return "12SP Plus";
01920 case SKINNY_DEVICE_12SP:
01921 return "12SP";
01922 case SKINNY_DEVICE_12:
01923 return "12";
01924 case SKINNY_DEVICE_30VIP:
01925 return "30VIP";
01926 case SKINNY_DEVICE_7910:
01927 return "7910";
01928 case SKINNY_DEVICE_7960:
01929 return "7960";
01930 case SKINNY_DEVICE_7940:
01931 return "7940";
01932 case SKINNY_DEVICE_7935:
01933 return "7935";
01934 case SKINNY_DEVICE_ATA186:
01935 return "ATA186";
01936 case SKINNY_DEVICE_7941:
01937 return "7941";
01938 case SKINNY_DEVICE_7971:
01939 return "7971";
01940 case SKINNY_DEVICE_7985:
01941 return "7985";
01942 case SKINNY_DEVICE_7911:
01943 return "7911";
01944 case SKINNY_DEVICE_7961GE:
01945 return "7961GE";
01946 case SKINNY_DEVICE_7941GE:
01947 return "7941GE";
01948 case SKINNY_DEVICE_7921:
01949 return "7921";
01950 case SKINNY_DEVICE_7905:
01951 return "7905";
01952 case SKINNY_DEVICE_7920:
01953 return "7920";
01954 case SKINNY_DEVICE_7970:
01955 return "7970";
01956 case SKINNY_DEVICE_7912:
01957 return "7912";
01958 case SKINNY_DEVICE_7902:
01959 return "7902";
01960 case SKINNY_DEVICE_CIPC:
01961 return "IP Communicator";
01962 case SKINNY_DEVICE_7961:
01963 return "7961";
01964 case SKINNY_DEVICE_7936:
01965 return "7936";
01966 case SKINNY_DEVICE_SCCPGATEWAY_AN:
01967 return "SCCPGATEWAY_AN";
01968 case SKINNY_DEVICE_SCCPGATEWAY_BRI:
01969 return "SCCPGATEWAY_BRI";
01970 case SKINNY_DEVICE_UNKNOWN:
01971 return "Unknown";
01972 default:
01973 if (!(tmp = ast_threadstorage_get(&device2str_threadbuf, DEVICE2STR_BUFSIZE)))
01974 return "Unknown";
01975 snprintf(tmp, DEVICE2STR_BUFSIZE, "UNKNOWN-%d", type);
01976 return tmp;
01977 }
01978 }
01979
01980 static int skinny_show_devices(int fd, int argc, char *argv[])
01981 {
01982 struct skinny_device *d;
01983 struct skinny_line *l;
01984 int numlines = 0;
01985
01986 if (argc != 3) {
01987 return RESULT_SHOWUSAGE;
01988 }
01989 ast_mutex_lock(&devicelock);
01990
01991 ast_cli(fd, "Name DeviceId IP Type R NL\n");
01992 ast_cli(fd, "-------------------- ---------------- --------------- --------------- - --\n");
01993 for (d = devices; d; d = d->next) {
01994 numlines = 0;
01995 for (l = d->lines; l; l = l->next) {
01996 numlines++;
01997 }
01998
01999 ast_cli(fd, "%-20s %-16s %-15s %-15s %c %2d\n",
02000 d->name,
02001 d->id,
02002 d->session?ast_inet_ntoa(d->session->sin.sin_addr):"",
02003 device2str(d->type),
02004 d->registered?'Y':'N',
02005 numlines);
02006 }
02007 ast_mutex_unlock(&devicelock);
02008 return RESULT_SUCCESS;
02009 }
02010
02011 static int skinny_show_lines(int fd, int argc, char *argv[])
02012 {
02013 struct skinny_device *d;
02014 struct skinny_line *l;
02015
02016 if (argc != 3) {
02017 return RESULT_SHOWUSAGE;
02018 }
02019 ast_mutex_lock(&devicelock);
02020
02021 ast_cli(fd, "Device Name Instance Name Label \n");
02022 ast_cli(fd, "-------------------- -------- -------------------- --------------------\n");
02023 for (d = devices; d; d = d->next) {
02024 for (l = d->lines; l; l = l->next) {
02025 ast_cli(fd, "%-20s %8d %-20s %-20s\n",
02026 d->name,
02027 l->instance,
02028 l->name,
02029 l->label);
02030 }
02031 }
02032
02033 ast_mutex_unlock(&devicelock);
02034 return RESULT_SUCCESS;
02035 }
02036
02037 static char show_devices_usage[] =
02038 "Usage: skinny show devices\n"
02039 " Lists all devices known to the Skinny subsystem.\n";
02040
02041 static char show_lines_usage[] =
02042 "Usage: skinny show lines\n"
02043 " Lists all lines known to the Skinny subsystem.\n";
02044
02045 static char debug_usage[] =
02046 "Usage: skinny set debug\n"
02047 " Enables dumping of Skinny packets for debugging purposes\n";
02048
02049 static char no_debug_usage[] =
02050 "Usage: skinny set debug off\n"
02051 " Disables dumping of Skinny packets for debugging purposes\n";
02052
02053 static char reset_usage[] =
02054 "Usage: skinny reset <DeviceId|all> [restart]\n"
02055 " Causes a Skinny device to reset itself, optionally with a full restart\n";
02056
02057 static struct ast_cli_entry cli_skinny[] = {
02058 { { "skinny", "show", "devices", NULL },
02059 skinny_show_devices, "List defined Skinny devices",
02060 show_devices_usage },
02061
02062 { { "skinny", "show", "lines", NULL },
02063 skinny_show_lines, "List defined Skinny lines per device",
02064 show_lines_usage },
02065
02066 { { "skinny", "set", "debug", NULL },
02067 skinny_do_debug, "Enable Skinny debugging",
02068 debug_usage },
02069
02070 { { "skinny", "set", "debug", "off", NULL },
02071 skinny_no_debug, "Disable Skinny debugging",
02072 no_debug_usage },
02073
02074 { { "skinny", "reset", NULL },
02075 skinny_reset_device, "Reset Skinny device(s)",
02076 reset_usage, complete_skinny_reset },
02077 };
02078
02079 #if 0
02080 static struct skinny_paging_device *build_paging_device(const char *cat, struct ast_variable *v)
02081 {
02082 return NULL;
02083 }
02084 #endif
02085
02086 static struct skinny_device *build_device(const char *cat, struct ast_variable *v)
02087 {
02088 struct skinny_device *d;
02089 struct skinny_line *l;
02090 struct skinny_speeddial *sd;
02091 struct skinny_addon *a;
02092 int lineInstance = 1;
02093 int speeddialInstance = 1;
02094 int y = 0;
02095
02096 if (!(d = ast_calloc(1, sizeof(struct skinny_device)))) {
02097 return NULL;
02098 } else {
02099 ast_copy_string(d->name, cat, sizeof(d->name));
02100 d->lastlineinstance = 1;
02101 d->capability = default_capability;
02102 d->prefs = default_prefs;
02103 while(v) {
02104 if (!strcasecmp(v->name, "host")) {
02105 if (ast_get_ip(&d->addr, v->value)) {
02106 free(d);
02107 return NULL;
02108 }
02109 } else if (!strcasecmp(v->name, "port")) {
02110 d->addr.sin_port = htons(atoi(v->value));
02111 } else if (!strcasecmp(v->name, "device")) {
02112 ast_copy_string(d->id, v->value, sizeof(d->id));
02113 } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
02114 d->ha = ast_append_ha(v->name, v->value, d->ha);
02115 } else if (!strcasecmp(v->name, "context")) {
02116 ast_copy_string(context, v->value, sizeof(context));
02117 } else if (!strcasecmp(v->name, "allow")) {
02118 ast_parse_allow_disallow(&d->prefs, &d->capability, v->value, 1);
02119 } else if (!strcasecmp(v->name, "disallow")) {
02120 ast_parse_allow_disallow(&d->prefs, &d->capability, v->value, 0);
02121 } else if (!strcasecmp(v->name, "version")) {
02122 ast_copy_string(d->version_id, v->value, sizeof(d->version_id));
02123 } else if (!strcasecmp(v->name, "nat")) {
02124 nat = ast_true(v->value);
02125 } else if (!strcasecmp(v->name, "callerid")) {
02126 if (!strcasecmp(v->value, "asreceived")) {
02127 cid_num[0] = '\0';
02128 cid_name[0] = '\0';
02129 } else {
02130 ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
02131 }
02132 } else if (!strcasecmp(v->name, "language")) {
02133 ast_copy_string(language, v->value, sizeof(language));
02134 } else if (!strcasecmp(v->name, "accountcode")) {
02135 ast_copy_string(accountcode, v->value, sizeof(accountcode));
02136 } else if (!strcasecmp(v->name, "amaflags")) {
02137 y = ast_cdr_amaflags2int(v->value);
02138 if (y < 0) {
02139 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
02140 } else {
02141 amaflags = y;
02142 }
02143 } else if (!strcasecmp(v->name, "mohinterpret") || !strcasecmp(v->name, "musiconhold")) {
02144 ast_copy_string(mohinterpret, v->value, sizeof(mohinterpret));
02145 } else if (!strcasecmp(v->name, "mohsuggest")) {
02146 ast_copy_string(mohsuggest, v->value, sizeof(mohsuggest));
02147 } else if (!strcasecmp(v->name, "callgroup")) {
02148 cur_callergroup = ast_get_group(v->value);
02149 } else if (!strcasecmp(v->name, "pickupgroup")) {
02150 cur_pickupgroup = ast_get_group(v->value);
02151 } else if (!strcasecmp(v->name, "immediate")) {
02152 immediate = ast_true(v->value);
02153 } else if (!strcasecmp(v->name, "cancallforward")) {
02154 cancallforward = ast_true(v->value);
02155 } else if (!strcasecmp(v->name, "mailbox")) {
02156 ast_copy_string(mailbox, v->value, sizeof(mailbox));
02157 } else if (!strcasecmp(v->name, "callreturn")) {
02158 callreturn = ast_true(v->value);
02159 } else if (!strcasecmp(v->name, "callwaiting")) {
02160 callwaiting = ast_true(v->value);
02161 } else if (!strcasecmp(v->name, "transfer")) {
02162 transfer = ast_true(v->value);
02163 } else if (!strcasecmp(v->name, "threewaycalling")) {
02164 threewaycalling = ast_true(v->value);
02165 } else if (!strcasecmp(v->name, "mwiblink")) {
02166 mwiblink = ast_true(v->value);
02167 } else if (!strcasecmp(v->name, "linelabel")) {
02168 ast_copy_string(linelabel, v->value, sizeof(linelabel));
02169 } else if (!strcasecmp(v->name, "speeddial")) {
02170 if (!(sd = ast_calloc(1, sizeof(struct skinny_speeddial)))) {
02171 return NULL;
02172 } else {
02173 char *stringp, *exten, *label;
02174 stringp = v->value;
02175 exten = strsep(&stringp, ",");
02176 label = strsep(&stringp, ",");
02177 ast_mutex_init(&sd->lock);
02178 ast_copy_string(sd->exten, exten, sizeof(sd->exten));
02179 if (label)
02180 ast_copy_string(sd->label, label, sizeof(sd->label));
02181 else
02182 ast_copy_string(sd->label, exten, sizeof(sd->label));
02183 sd->instance = speeddialInstance++;
02184
02185 sd->parent = d;
02186
02187 sd->next = d->speeddials;
02188 d->speeddials = sd;
02189 }
02190 } else if (!strcasecmp(v->name, "addon")) {
02191 if (!(a = ast_calloc(1, sizeof(struct skinny_addon)))) {
02192 return NULL;
02193 } else {
02194 ast_mutex_init(&a->lock);
02195 ast_copy_string(a->type, v->value, sizeof(a->type));
02196
02197 a->next = d->addons;
02198 d->addons = a;
02199 }
02200 } else if (!strcasecmp(v->name, "trunk") || !strcasecmp(v->name, "line")) {
02201 if (!(l = ast_calloc(1, sizeof(struct skinny_line)))) {
02202 return NULL;
02203 } else {
02204 ast_mutex_init(&l->lock);
02205 ast_copy_string(l->name, v->value, sizeof(l->name));
02206
02207
02208 ast_copy_string(l->context, context, sizeof(l->context));
02209 ast_copy_string(l->cid_num, cid_num, sizeof(l->cid_num));
02210 ast_copy_string(l->cid_name, cid_name, sizeof(l->cid_name));
02211 ast_copy_string(l->label, linelabel, sizeof(l->label));
02212 ast_copy_string(l->language, language, sizeof(l->language));
02213 ast_copy_string(l->mohinterpret, mohinterpret, sizeof(l->mohinterpret));
02214 ast_copy_string(l->mohsuggest, mohsuggest, sizeof(l->mohsuggest));
02215 ast_copy_string(l->mailbox, mailbox, sizeof(l->mailbox));
02216 if (!ast_strlen_zero(mailbox)) {
02217 if (option_verbose > 2)
02218 ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, d->name, l->name);
02219 }
02220 l->msgstate = -1;
02221 l->capability = d->capability;
02222 l->prefs = d->prefs;
02223 l->parent = d;
02224 if (!strcasecmp(v->name, "trunk")) {
02225 l->type = TYPE_TRUNK;
02226 } else {
02227 l->type = TYPE_LINE;
02228 }
02229 l->immediate = immediate;
02230 l->callgroup = cur_callergroup;
02231 l->pickupgroup = cur_pickupgroup;
02232 l->callreturn = callreturn;
02233 l->cancallforward = cancallforward;
02234 l->callwaiting = callwaiting;
02235 l->transfer = transfer;
02236 l->threewaycalling = threewaycalling;
02237 l->mwiblink = mwiblink;
02238 l->onhooktime = time(NULL);
02239 l->instance = lineInstance++;
02240
02241 l->hookstate = SKINNY_ONHOOK;
02242 l->nat = nat;
02243
02244 l->next = d->lines;
02245 d->lines = l;
02246 }
02247 } else {
02248 ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
02249 }
02250 v = v->next;
02251 }
02252
02253 if (!d->lines) {
02254 ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n");
02255 return NULL;
02256 }
02257 if (!ntohs(d->addr.sin_port)) {
02258 d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
02259 }
02260 #if 0
02261
02262 if (d->addr.sin_addr.s_addr) {
02263
02264 if (ast_ouraddrfor(&d->addr.sin_addr, &d->ourip)) {
02265 d->ourip = __ourip;
02266 }
02267 } else {
02268 d->ourip = __ourip;
02269 }
02270 #endif
02271 }
02272 return d;
02273 }
02274
02275 static void start_rtp(struct skinny_subchannel *sub)
02276 {
02277 struct skinny_line *l = sub->parent;
02278 struct skinny_device *d = l->parent;
02279 int hasvideo = 0;
02280
02281 ast_mutex_lock(&sub->lock);
02282
02283 sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
02284 if (hasvideo)
02285 sub->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
02286
02287 if (sub->rtp && sub->owner) {
02288 sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
02289 sub->owner->fds[1] = ast_rtcp_fd(sub->rtp);
02290 }
02291 if (hasvideo && sub->vrtp && sub->owner) {
02292 sub->owner->fds[2] = ast_rtp_fd(sub->vrtp);
02293 sub->owner->fds[3] = ast_rtcp_fd(sub->vrtp);
02294 }
02295 if (sub->rtp) {
02296 ast_rtp_setnat(sub->rtp, l->nat);
02297 }
02298 if (sub->vrtp) {
02299 ast_rtp_setnat(sub->vrtp, l->nat);
02300 }
02301
02302 if (sub->rtp)
02303 ast_rtp_codec_setpref(sub->rtp, &l->prefs);
02304
02305
02306 transmit_connect(d->session, sub);
02307 ast_mutex_unlock(&sub->lock);
02308 }
02309
02310 static void *skinny_newcall(void *data)
02311 {
02312 struct ast_channel *c = data;
02313 struct skinny_subchannel *sub = c->tech_pvt;
02314 struct skinny_line *l = sub->parent;
02315 struct skinny_device *d = l->parent;
02316 struct skinnysession *s = d->session;
02317 int res = 0;
02318
02319 ast_copy_string(l->lastnumberdialed, c->exten, sizeof(l->lastnumberdialed));
02320 ast_set_callerid(c,
02321 l->hidecallerid ? "" : l->cid_num,
02322 l->hidecallerid ? "" : l->cid_name,
02323 c->cid.cid_ani ? NULL : l->cid_num);
02324 ast_setstate(c, AST_STATE_RING);
02325 res = ast_pbx_run(c);
02326 if (res) {
02327 ast_log(LOG_WARNING, "PBX exited non-zero\n");
02328 transmit_tone(s, SKINNY_REORDER, l->instance, sub->callid);
02329 }
02330 return NULL;
02331 }
02332
02333 static void *skinny_ss(void *data)
02334 {
02335 struct ast_channel *c = data;
02336 struct skinny_subchannel *sub = c->tech_pvt;
02337 struct skinny_line *l = sub->parent;
02338 struct skinny_device *d = l->parent;
02339 struct skinnysession *s = d->session;
02340 int len = 0;
02341 int timeout = firstdigittimeout;
02342 int res = 0;
02343 int getforward=0;
02344 int loop_pause = 100;
02345
02346 if (option_verbose > 2)
02347 ast_verbose( VERBOSE_PREFIX_3 "Starting simple switch on '%s@%s'\n", l->name, d->name);
02348 len = strlen(d->exten);
02349
02350 while (len < AST_MAX_EXTENSION-1) {
02351
02352 res = 1;
02353 while (strlen(d->exten) == len) {
02354 ast_safe_sleep(c, loop_pause);
02355 timeout -= loop_pause;
02356 if (timeout <= 0){
02357 res = 0;
02358 break;
02359 }
02360 }
02361
02362 len = strlen(d->exten);
02363
02364 if (!ast_ignore_pattern(c->context, d->exten)) {
02365 transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
02366 }
02367
02368 if (ast_exists_extension(c, c->context, d->exten, 1, l->cid_num)) {
02369 if (!res || !ast_matchmore_extension(c, c->context, d->exten, 1, l->cid_num)) {
02370 if (getforward) {
02371
02372 ast_copy_string(l->call_forward, d->exten, sizeof(l->call_forward));
02373 if (option_verbose > 2)
02374 ast_verbose(VERBOSE_PREFIX_3 "Setting call forward to '%s' on channel %s\n",
02375 l->call_forward, c->name);
02376 transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
02377 if (res) {
02378 break;
02379 }
02380 ast_safe_sleep(c, 500);
02381 ast_indicate(c, -1);
02382 ast_safe_sleep(c, 1000);
02383 memset(d->exten, 0, sizeof(d->exten));
02384 transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
02385 len = 0;
02386 getforward = 0;
02387 } else {
02388 ast_copy_string(c->exten, d->exten, sizeof(c->exten));
02389 ast_copy_string(l->lastnumberdialed, d->exten, sizeof(l->lastnumberdialed));
02390 memset (d->exten, 0, sizeof(d->exten));
02391 skinny_newcall(c);
02392 return NULL;
02393 }
02394 } else {
02395
02396
02397 timeout = matchdigittimeout;
02398 }
02399 } else if (res == 0) {
02400 ast_log(LOG_DEBUG, "Not enough digits (and no ambiguous match)...\n");
02401 memset(d->exten, 0, sizeof(d->exten));
02402 transmit_tone(s, SKINNY_REORDER, l->instance, sub->callid);
02403 if (sub->owner && sub->owner->_state != AST_STATE_UP) {
02404 ast_indicate(c, -1);
02405 ast_hangup(c);
02406 }
02407 return NULL;
02408 } else if (!ast_canmatch_extension(c, c->context, d->exten, 1, c->cid.cid_num) &&
02409 ((d->exten[0] != '*') || (!ast_strlen_zero(d->exten) > 2))) {
02410 ast_log(LOG_WARNING, "Can't match [%s] from '%s' in context %s\n", d->exten, c->cid.cid_num ? c->cid.cid_num : "<Unknown Caller>", c->context);
02411 memset(d->exten, 0, sizeof(d->exten));
02412 transmit_tone(s, SKINNY_REORDER, l->instance, sub->callid);
02413
02414 ast_safe_sleep(c, 3000);
02415 break;
02416 }
02417 if (!timeout) {
02418 timeout = gendigittimeout;
02419 }
02420 if (len && !ast_ignore_pattern(c->context, d->exten)) {
02421 ast_indicate(c, -1);
02422 }
02423 }
02424 if (c)
02425 ast_hangup(c);
02426
02427 memset(d->exten, 0, sizeof(d->exten));
02428 return NULL;
02429 }
02430
02431
02432
02433 static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
02434 {
02435 int res = 0;
02436 int tone = 0;
02437 struct skinny_subchannel *sub = ast->tech_pvt;
02438 struct skinny_line *l = sub->parent;
02439 struct skinny_device *d = l->parent;
02440 struct skinnysession *s = d->session;
02441
02442 if (!d->registered) {
02443 ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
02444 return -1;
02445 }
02446
02447 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
02448 ast_log(LOG_WARNING, "skinny_call called on %s, neither down nor reserved\n", ast->name);
02449 return -1;
02450 }
02451
02452 if (skinnydebug)
02453 ast_verbose(VERBOSE_PREFIX_3 "skinny_call(%s)\n", ast->name);
02454
02455 if (l->dnd) {
02456 ast_queue_control(ast, AST_CONTROL_BUSY);
02457 return -1;
02458 }
02459
02460 switch (l->hookstate) {
02461 case SKINNY_OFFHOOK:
02462 tone = SKINNY_CALLWAITTONE;
02463 break;
02464 case SKINNY_ONHOOK:
02465 tone = SKINNY_ALERT;
02466 break;
02467 default:
02468 ast_log(LOG_ERROR, "Don't know how to deal with hookstate %d\n", l->hookstate);
02469 break;
02470 }
02471
02472 transmit_callstate(s, l->instance, SKINNY_RINGIN, sub->callid);
02473 transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_RINGIN);
02474 transmit_displaypromptstatus(s, "Ring-In", 0, l->instance, sub->callid);
02475 transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1);
02476 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
02477 transmit_ringer_mode(s, SKINNY_RING_INSIDE);
02478
02479 ast_setstate(ast, AST_STATE_RINGING);
02480 ast_queue_control(ast, AST_CONTROL_RINGING);
02481 sub->outgoing = 1;
02482 return res;
02483 }
02484
02485 static int skinny_hangup(struct ast_channel *ast)
02486 {
02487 struct skinny_subchannel *sub = ast->tech_pvt;
02488 struct skinny_line *l;
02489 struct skinny_device *d;
02490 struct skinnysession *s;
02491
02492 if (!sub) {
02493 ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
02494 return 0;
02495 }
02496 l = sub->parent;
02497 d = l->parent;
02498 s = d->session;
02499 if (skinnydebug)
02500 ast_verbose("skinny_hangup(%s) on %s@%s\n", ast->name, l->name, d->name);
02501
02502 if (d->registered) {
02503 if ((l->type = TYPE_LINE) && (l->hookstate == SKINNY_OFFHOOK)) {
02504 l->hookstate = SKINNY_ONHOOK;
02505 transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
02506 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
02507 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
02508 } else if ((l->type = TYPE_LINE) && (l->hookstate == SKINNY_ONHOOK)) {
02509 transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
02510 transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
02511 transmit_ringer_mode(s, SKINNY_RING_OFF);
02512 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
02513 do_housekeeping(s);
02514 }
02515 }
02516 ast_mutex_lock(&sub->lock);
02517 sub->owner = NULL;
02518 ast->tech_pvt = NULL;
02519 sub->alreadygone = 0;
02520 sub->outgoing = 0;
02521 if (sub->rtp) {
02522 ast_rtp_destroy(sub->rtp);
02523 sub->rtp = NULL;
02524 }
02525 ast_mutex_unlock(&sub->lock);
02526 return 0;
02527 }
02528
02529 static int skinny_answer(struct ast_channel *ast)
02530 {
02531 int res = 0;
02532 struct skinny_subchannel *sub = ast->tech_pvt;
02533 struct skinny_line *l = sub->parent;
02534 struct skinny_device *d = l->parent;
02535 struct skinnysession *s = d->session;
02536 char exten[AST_MAX_EXTENSION] = "";
02537
02538 ast_copy_string(exten, S_OR(ast->macroexten, ast->exten), sizeof(exten));
02539
02540 sub->cxmode = SKINNY_CX_SENDRECV;
02541 if (!sub->rtp) {
02542 start_rtp(sub);
02543 }
02544 if (skinnydebug)
02545 ast_verbose("skinny_answer(%s) on %s@%s-%d\n", ast->name, l->name, d->name, sub->callid);
02546 if (ast->_state != AST_STATE_UP) {
02547 ast_setstate(ast, AST_STATE_UP);
02548 }
02549
02550 transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
02551
02552
02553
02554 transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, exten, exten, l->instance, sub->callid, 2);
02555 transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
02556 transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_CONNECTED);
02557 transmit_dialednumber(s, exten, l->instance, sub->callid);
02558 transmit_displaypromptstatus(s, "Connected", 0, l->instance, sub->callid);
02559 return res;
02560 }
02561
02562
02563 static struct ast_frame *skinny_rtp_read(struct skinny_subchannel *sub)
02564 {
02565 struct ast_channel *ast = sub->owner;
02566 struct ast_frame *f;
02567
02568 if (!sub->rtp) {
02569
02570 return &ast_null_frame;
02571 }
02572
02573 switch(ast->fdno) {
02574 case 0:
02575 f = ast_rtp_read(sub->rtp);
02576 break;
02577 case 1:
02578 f = ast_rtcp_read(sub->rtp);
02579 break;
02580 case 2:
02581 f = ast_rtp_read(sub->vrtp);
02582 break;
02583 case 3:
02584 f = ast_rtcp_read(sub->vrtp);
02585 break;
02586 #if 0
02587 case 5:
02588
02589 f = ast_udptl_read(sub->udptl);
02590 break;
02591 #endif
02592 default:
02593 f = &ast_null_frame;
02594 }
02595
02596 if (ast) {
02597
02598 if (f->frametype == AST_FRAME_VOICE) {
02599 if (f->subclass != ast->nativeformats) {
02600 ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
02601 ast->nativeformats = f->subclass;
02602 ast_set_read_format(ast, ast->readformat);
02603 ast_set_write_format(ast, ast->writeformat);
02604 }
02605 }
02606 }
02607 return f;
02608 }
02609
02610 static struct ast_frame *skinny_read(struct ast_channel *ast)
02611 {
02612 struct ast_frame *fr;
02613 struct skinny_subchannel *sub = ast->tech_pvt;
02614 ast_mutex_lock(&sub->lock);
02615 fr = skinny_rtp_read(sub);
02616 ast_mutex_unlock(&sub->lock);
02617 return fr;
02618 }
02619
02620 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
02621 {
02622 struct skinny_subchannel *sub = ast->tech_pvt;
02623 int res = 0;
02624 if (frame->frametype != AST_FRAME_VOICE) {
02625 if (frame->frametype == AST_FRAME_IMAGE) {
02626 return 0;
02627 } else {
02628 ast_log(LOG_WARNING, "Can't send %d type frames with skinny_write\n", frame->frametype);
02629 return 0;
02630 }
02631 } else {
02632 if (!(frame->subclass & ast->nativeformats)) {
02633 ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
02634 frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
02635 return -1;
02636 }
02637 }
02638 if (sub) {
02639 ast_mutex_lock(&sub->lock);
02640 if (sub->rtp) {
02641 res = ast_rtp_write(sub->rtp, frame);
02642 }
02643 ast_mutex_unlock(&sub->lock);
02644 }
02645 return res;
02646 }
02647
02648 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
02649 {
02650 struct skinny_subchannel *sub = newchan->tech_pvt;
02651 ast_log(LOG_NOTICE, "skinny_fixup(%s, %s)\n", oldchan->name, newchan->name);
02652 if (sub->owner != oldchan) {
02653 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
02654 return -1;
02655 }
02656 sub->owner = newchan;
02657 return 0;
02658 }
02659
02660 static int skinny_senddigit_begin(struct ast_channel *ast, char digit)
02661 {
02662 return -1;
02663 }
02664
02665 static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
02666 {
02667 #if 0
02668 struct skinny_subchannel *sub = ast->tech_pvt;
02669 struct skinny_line *l = sub->parent;
02670 struct skinny_device *d = l->parent;
02671 int tmp;
02672
02673 sprintf(tmp, "%d", digit);
02674 transmit_tone(d->session, digit, l->instance, sub->callid);
02675 #endif
02676 return -1;
02677 }
02678
02679 static char *control2str(int ind) {
02680 char *tmp;
02681
02682 switch (ind) {
02683 case AST_CONTROL_HANGUP:
02684 return "Other end has hungup";
02685 case AST_CONTROL_RING:
02686 return "Local ring";
02687 case AST_CONTROL_RINGING:
02688 return "Remote end is ringing";
02689 case AST_CONTROL_ANSWER:
02690 return "Remote end has answered";
02691 case AST_CONTROL_BUSY:
02692 return "Remote end is busy";
02693 case AST_CONTROL_TAKEOFFHOOK:
02694 return "Make it go off hook";
02695 case AST_CONTROL_OFFHOOK:
02696 return "Line is off hook";
02697 case AST_CONTROL_CONGESTION:
02698 return "Congestion (circuits busy)";
02699 case AST_CONTROL_FLASH:
02700 return "Flash hook";
02701 case AST_CONTROL_WINK:
02702 return "Wink";
02703 case AST_CONTROL_OPTION:
02704 return "Set a low-level option";
02705 case AST_CONTROL_RADIO_KEY:
02706 return "Key Radio";
02707 case AST_CONTROL_RADIO_UNKEY:
02708 return "Un-Key Radio";
02709 case AST_CONTROL_PROGRESS:
02710 return "Remote end is making Progress";
02711 case AST_CONTROL_PROCEEDING:
02712 return "Remote end is proceeding";
02713 case AST_CONTROL_HOLD:
02714 return "Hold";
02715 case AST_CONTROL_UNHOLD:
02716 return "Unhold";
02717 case -1:
02718 return "Stop tone";
02719 default:
02720 if (!(tmp = ast_threadstorage_get(&control2str_threadbuf, CONTROL2STR_BUFSIZE)))
02721 return "Unknown";
02722 snprintf(tmp, CONTROL2STR_BUFSIZE, "UNKNOWN-%d", ind);
02723 return tmp;
02724 }
02725 }
02726
02727
02728 static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
02729 {
02730 struct skinny_subchannel *sub = ast->tech_pvt;
02731 struct skinny_line *l = sub->parent;
02732 struct skinny_device *d = l->parent;
02733 struct skinnysession *s = d->session;
02734 char exten[AST_MAX_EXTENSION] = "";
02735
02736 if (!s) {
02737 ast_log(LOG_NOTICE, "Asked to indicate '%s' condition on channel %s, but session does not exist.\n", control2str(ind), ast->name);
02738 return -1;
02739 }
02740
02741 ast_copy_string(exten, S_OR(ast->macroexten, ast->exten), sizeof(exten));
02742
02743 if (skinnydebug)
02744 ast_verbose(VERBOSE_PREFIX_3 "Asked to indicate '%s' condition on channel %s\n", control2str(ind), ast->name);
02745 switch(ind) {
02746 case AST_CONTROL_RINGING:
02747 if (ast->_state != AST_STATE_UP) {
02748 if (!sub->progress) {
02749 transmit_tone(s, SKINNY_ALERT, l->instance, sub->callid);
02750 transmit_callstate(s, l->instance, SKINNY_RINGOUT, sub->callid);
02751 transmit_dialednumber(s, exten, l->instance, sub->callid);
02752 transmit_displaypromptstatus(s, "Ring Out", 0, l->instance, sub->callid);
02753 transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, exten, exten, l->instance, sub->callid, 2);
02754 sub->ringing = 1;
02755 break;
02756 }
02757 }
02758 return -1;
02759 case AST_CONTROL_BUSY:
02760 if (ast->_state != AST_STATE_UP) {
02761 transmit_tone(s, SKINNY_BUSYTONE, l->instance, sub->callid);
02762 transmit_callstate(s, l->instance, SKINNY_BUSY, sub->callid);
02763 sub->alreadygone = 1;
02764 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
02765 break;
02766 }
02767 return -1;
02768 case AST_CONTROL_CONGESTION:
02769 if (ast->_state != AST_STATE_UP) {
02770 transmit_tone(s, SKINNY_REORDER, l->instance, sub->callid);
02771 transmit_callstate(s, l->instance, SKINNY_CONGESTION, sub->callid);
02772 sub->alreadygone = 1;
02773 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
02774 break;
02775 }
02776 return -1;
02777 case AST_CONTROL_PROGRESS:
02778 if ((ast->_state != AST_STATE_UP) && !sub->progress && !sub->outgoing) {
02779 transmit_tone(s, SKINNY_ALERT, l->instance, sub->callid);
02780 transmit_callstate(s, l->instance, SKINNY_PROGRESS, sub->callid);
02781 transmit_displaypromptstatus(s, "Call Progress", 0, l->instance, sub->callid);
02782 transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, exten, exten, l->instance, sub->callid, 2);
02783 sub->progress = 1;
02784 break;
02785 }
02786 return -1;
02787 case -1:
02788 transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
02789 break;
02790 case AST_CONTROL_HOLD:
02791 ast_moh_start(ast, data, l->mohinterpret);
02792 break;
02793 case AST_CONTROL_UNHOLD:
02794 ast_moh_stop(ast);
02795 break;
02796 case AST_CONTROL_PROCEEDING:
02797 break;
02798 case AST_CONTROL_SRCUPDATE:
02799 ast_rtp_new_source(sub->rtp);
02800 break;
02801 default:
02802 ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
02803 return -1;
02804 }
02805 return 0;
02806 }
02807
02808 static struct ast_channel *skinny_new(struct skinny_line *l, int state)
02809 {
02810 struct ast_channel *tmp;
02811 struct skinny_subchannel *sub;
02812 struct skinny_device *d = l->parent;
02813 int fmt;
02814
02815 tmp = ast_channel_alloc(1, state, l->cid_num, l->cid_name, l->accountcode, l->exten, l->context, l->amaflags, "Skinny/%s@%s-%d", l->name, d->name, callnums);
02816 if (!tmp) {
02817 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
02818 return NULL;
02819 } else {
02820 sub = ast_calloc(1, sizeof(struct skinny_subchannel));
02821 if (!sub) {
02822 ast_log(LOG_WARNING, "Unable to allocate Skinny subchannel\n");
02823 return NULL;
02824 } else {
02825 ast_mutex_init(&sub->lock);
02826
02827 sub->owner = tmp;
02828 sub->callid = callnums++;
02829 d->lastlineinstance = l->instance;
02830 d->lastcallreference = sub->callid;
02831 sub->cxmode = SKINNY_CX_INACTIVE;
02832 sub->nat = l->nat;
02833 sub->parent = l;
02834 sub->onhold = 0;
02835
02836 sub->next = l->sub;
02837 l->sub = sub;
02838 }
02839 tmp->tech = &skinny_tech;
02840 tmp->tech_pvt = sub;
02841 tmp->nativeformats = l->capability;
02842 if (!tmp->nativeformats)
02843 tmp->nativeformats = default_capability;
02844 fmt = ast_best_codec(tmp->nativeformats);
02845 if (skinnydebug)
02846 ast_verbose("skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp->nativeformats, fmt);
02847 if (sub->rtp) {
02848 tmp->fds[0] = ast_rtp_fd(sub->rtp);
02849 }
02850 if (state == AST_STATE_RING) {
02851 tmp->rings = 1;
02852 }
02853 tmp->writeformat = fmt;
02854 tmp->rawwriteformat = fmt;
02855 tmp->readformat = fmt;
02856 tmp->rawreadformat = fmt;
02857 if (!ast_strlen_zero(l->language))
02858 ast_string_field_set(tmp, language, l->language);
02859 if (!ast_strlen_zero(l->accountcode))
02860 ast_string_field_set(tmp, accountcode, l->accountcode);
02861 if (l->amaflags)
02862 tmp->amaflags = l->amaflags;
02863
02864 ast_module_ref(ast_module_info->self);
02865 tmp->callgroup = l->callgroup;
02866 tmp->pickupgroup = l->pickupgroup;
02867 ast_string_field_set(tmp, call_forward, l->call_forward);
02868 ast_copy_string(tmp->context, l->context, sizeof(tmp->context));
02869 ast_copy_string(tmp->exten, l->exten, sizeof(tmp->exten));
02870
02871
02872
02873 tmp->cid.cid_ani = ast_strdup(l->cid_num);
02874
02875 tmp->priority = 1;
02876 tmp->adsicpe = AST_ADSI_UNAVAILABLE;
02877
02878 if (sub->rtp)
02879 ast_jb_configure(tmp, &global_jbconf);
02880
02881 if (state != AST_STATE_DOWN) {
02882 if (ast_pbx_start(tmp)) {
02883 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
02884 ast_hangup(tmp);
02885 tmp = NULL;
02886 }
02887 }
02888 }
02889 return tmp;
02890 }
02891
02892 static int skinny_hold(struct skinny_subchannel *sub)
02893 {
02894 struct skinny_line *l = sub->parent;
02895 struct skinny_device *d = l->parent;
02896 struct skinnysession *s = d->session;
02897 struct skinny_req *req;
02898
02899
02900 if (!sub || !sub->owner)
02901 return 0;
02902
02903
02904 if (skinnydebug)
02905 ast_verbose("Putting on Hold(%d)\n", l->instance);
02906
02907 ast_queue_control_data(sub->owner, AST_CONTROL_HOLD,
02908 S_OR(l->mohsuggest, NULL),
02909 !ast_strlen_zero(l->mohsuggest) ? strlen(l->mohsuggest) + 1 : 0);
02910
02911 if (!(req = req_alloc(sizeof(struct activate_call_plane_message), ACTIVATE_CALL_PLANE_MESSAGE)))
02912 return 0;
02913
02914 req->data.activatecallplane.lineInstance = htolel(l->instance);
02915 transmit_response(s, req);
02916
02917 if (!(req = req_alloc(sizeof(struct close_receive_channel_message), CLOSE_RECEIVE_CHANNEL_MESSAGE)))
02918 return 0;
02919
02920 req->data.closereceivechannel.conferenceId = htolel(sub->callid);
02921 req->data.closereceivechannel.partyId = htolel(sub->callid);
02922 transmit_response(s, req);
02923
02924 if (!(req = req_alloc(sizeof(struct stop_media_transmission_message), STOP_MEDIA_TRANSMISSION_MESSAGE)))
02925 return 0;
02926
02927 req->data.stopmedia.conferenceId = htolel(sub->callid);
02928 req->data.stopmedia.passThruPartyId = htolel(sub->callid);
02929 transmit_response(s, req);
02930
02931 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
02932 sub->onhold = 1;
02933 return 1;
02934 }
02935
02936 static int skinny_unhold(struct skinny_subchannel *sub)
02937 {
02938 struct skinny_line *l = sub->parent;
02939 struct skinny_device *d = l->parent;
02940 struct skinnysession *s = d->session;
02941 struct skinny_req *req;
02942
02943
02944 if (!sub || !sub->owner)
02945 return 0;
02946
02947
02948 if (skinnydebug)
02949 ast_verbose("Taking off Hold(%d)\n", l->instance);
02950
02951 ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
02952
02953 if (!(req = req_alloc(sizeof(struct activate_call_plane_message), ACTIVATE_CALL_PLANE_MESSAGE)))
02954 return 0;
02955
02956 req->data.activatecallplane.lineInstance = htolel(l->instance);
02957 transmit_response(s, req);
02958
02959 transmit_connect(s, sub);
02960 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
02961 sub->onhold = 0;
02962 return 1;
02963 }
02964
02965 static int handle_keep_alive_message(struct skinny_req *req, struct skinnysession *s)
02966 {
02967 if (!(req = req_alloc(0, KEEP_ALIVE_ACK_MESSAGE)))
02968 return -1;
02969
02970 transmit_response(s, req);
02971 do_housekeeping(s);
02972 return 1;
02973 }
02974
02975 static int handle_register_message(struct skinny_req *req, struct skinnysession *s)
02976 {
02977 char name[16];
02978 int res;
02979
02980 memcpy(&name, req->data.reg.name, sizeof(name));
02981
02982 res = skinny_register(req, s);
02983 if (!res) {
02984 ast_log(LOG_ERROR, "Rejecting Device %s: Device not found\n", name);
02985 if (!(req = req_alloc(sizeof(struct register_rej_message), REGISTER_REJ_MESSAGE)))
02986 return -1;
02987
02988 snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name);
02989 transmit_response(s, req);
02990 return 0;
02991 }
02992 if (option_verbose > 2)
02993 ast_verbose(VERBOSE_PREFIX_3 "Device '%s' successfully registered\n", name);
02994
02995 if (!(req = req_alloc(sizeof(struct register_ack_message), REGISTER_ACK_MESSAGE)))
02996 return -1;
02997
02998 req->data.regack.res[0] = '0';
02999 req->data.regack.res[1] = '\0';
03000 req->data.regack.keepAlive = htolel(keep_alive);
03001 memcpy(req->data.regack.dateTemplate, date_format, sizeof(req->data.regack.dateTemplate));
03002 req->data.regack.res2[0] = '0';
03003 req->data.regack.res2[1] = '\0';
03004 req->data.regack.secondaryKeepAlive = htolel(keep_alive);
03005 transmit_response(s, req);
03006 if (skinnydebug)
03007 ast_verbose("Requesting capabilities\n");
03008
03009 if (!(req = req_alloc(0, CAPABILITIES_REQ_MESSAGE)))
03010 return -1;
03011
03012 transmit_response(s, req);
03013
03014 return res;
03015 }
03016
03017 static int handle_ip_port_message(struct skinny_req *req, struct skinnysession *s)
03018 {
03019
03020 return 1;
03021 }
03022
03023 static int handle_keypad_button_message(struct skinny_req *req, struct skinnysession *s)
03024 {
03025 struct skinny_subchannel *sub = NULL;
03026 struct skinny_line *l;
03027 struct skinny_device *d = s->device;
03028 struct ast_frame f = { 0, };
03029 char dgt;
03030 int digit;
03031 int lineInstance;
03032 int callReference;
03033
03034 digit = letohl(req->data.keypad.button);
03035 lineInstance = letohl(req->data.keypad.lineInstance);
03036 callReference = letohl(req->data.keypad.callReference);
03037
03038 if (digit == 14) {
03039 dgt = '*';
03040 } else if (digit == 15) {
03041 dgt = '#';
03042 } else if (digit >= 0 && digit <= 9) {
03043 dgt = '0' + digit;
03044 } else {
03045
03046
03047
03048
03049
03050
03051
03052 dgt = '0' + digit;
03053 ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
03054 }
03055
03056 f.subclass = dgt;
03057
03058 f.src = "skinny";
03059
03060 if (lineInstance && callReference)
03061 sub = find_subchannel_by_instance_reference(d, lineInstance, callReference);
03062 else
03063 sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
03064
03065 if (!sub)
03066 return 0;
03067
03068 l = sub->parent;
03069 if (sub->owner) {
03070 if (sub->owner->_state == 0) {
03071 f.frametype = AST_FRAME_DTMF_BEGIN;
03072 ast_queue_frame(sub->owner, &f);
03073 }
03074
03075 f.frametype = AST_FRAME_DTMF_END;
03076 ast_queue_frame(sub->owner, &f);
03077
03078 if (sub->next && sub->next->owner) {
03079 if (sub->owner->_state == 0) {
03080 f.frametype = AST_FRAME_DTMF_BEGIN;
03081 ast_queue_frame(sub->next->owner, &f);
03082 }
03083 f.frametype = AST_FRAME_DTMF_END;
03084 ast_queue_frame(sub->next->owner, &f);
03085 }
03086 } else {
03087 if (skinnydebug)
03088 ast_verbose("No owner: %s\n", l->name);
03089 }
03090 return 1;
03091 }
03092
03093 static int handle_stimulus_message(struct skinny_req *req, struct skinnysession *s)
03094 {
03095 struct skinny_device *d = s->device;
03096 struct skinny_line *l;
03097 struct skinny_subchannel *sub;
03098
03099 struct ast_channel *c;
03100 pthread_t t;
03101 int event;
03102 int instance;
03103 int callreference;
03104
03105
03106 event = letohl(req->data.stimulus.stimulus);
03107 instance = letohl(req->data.stimulus.stimulusInstance);
03108 callreference = letohl(req->data.stimulus.callreference);
03109 if (skinnydebug)
03110 ast_verbose("callreference in handle_stimulus_message is '%d'\n", callreference);
03111
03112
03113 sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
03114
03115 if (!sub) {
03116 l = find_line_by_instance(d, d->lastlineinstance);
03117 if (!l) {
03118 return 0;
03119 }
03120 } else {
03121 l = sub->parent;
03122 }
03123
03124 switch(event) {
03125 case STIMULUS_REDIAL:
03126 if (skinnydebug)
03127 ast_verbose("Received Stimulus: Redial(%d/%d)\n", instance, callreference);
03128
03129 #if 0
03130 if (ast_strlen_zero(l->lastnumberdialed)) {
03131 ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found.\n");
03132 l->hookstate = SKINNY_ONHOOK;
03133 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
03134 transmit_callstate(s, l->instance, SKINNY_ONHOOK, instance);
03135 break;
03136 }
03137
03138 c = skinny_new(l, AST_STATE_DOWN);
03139 if(!c) {
03140 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
03141 } else {
03142 sub = c->tech_pvt;
03143 transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
03144 if (skinnydebug)
03145 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
03146 transmit_displaymessage(s, NULL, l->instance, sub->callid);
03147 transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
03148 transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_RINGOUT);
03149
03150 if (!ast_ignore_pattern(c->context, l->lastnumberdialed)) {
03151 transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
03152 }
03153 ast_copy_string(c->exten, l->lastnumberdialed, sizeof(c->exten));
03154 if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
03155 ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
03156 ast_hangup(c);
03157 }
03158 }
03159 #endif
03160 break;
03161 case STIMULUS_SPEEDDIAL:
03162 if (skinnydebug)
03163 ast_verbose("Received Stimulus: SpeedDial(%d/%d)\n", instance, callreference);
03164
03165 #if 0
03166 if (!(sd = find_speeddial_by_instance(d, instance))) {
03167 return 0;
03168 }
03169
03170 if (ast_strlen_zero(l->lastnumberdialed)) {
03171 ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found.\n");
03172 l->hookstate = SKINNY_ONHOOK;
03173 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
03174 transmit_callstate(s, l->instance, SKINNY_ONHOOK, instance);
03175 break;
03176 }
03177
03178 c = skinny_new(l, AST_STATE_DOWN);
03179 if(c) {
03180 sub = c->tech_pvt;
03181 l = sub->parent;
03182 transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
03183 if (skinnydebug)
03184 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
03185 transmit_displaymessage(s, NULL, l->instance, sub->callid);
03186 transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
03187 transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_RINGOUT);
03188
03189 if (!ast_ignore_pattern(c->context, sd->exten)) {
03190 transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
03191 }
03192 if (ast_exists_extension(c, c->context, sd->exten, 1, l->cid_num)) {
03193 if (!ast_matchmore_extension(c, c->context, sd->exten, 1, l->cid_num)) {
03194 ast_copy_string(c->exten, sd->exten, sizeof(c->exten));
03195 ast_copy_string(l->lastnumberdialed, sd->exten, sizeof(l->lastnumberdialed));
03196 skinny_newcall(c);
03197 break;
03198 }
03199 }
03200 } else {
03201 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
03202 }
03203 #endif
03204 break;
03205 case STIMULUS_HOLD:
03206 if (skinnydebug)
03207 ast_verbose("Received Stimulus: Hold(%d/%d)\n", instance, callreference);
03208
03209 if (!sub)
03210 break;
03211
03212 if (sub->onhold) {
03213 skinny_unhold(sub);
03214 } else {
03215 skinny_hold(sub);
03216 }
03217 break;
03218 case STIMULUS_TRANSFER:
03219 if (skinnydebug)
03220 ast_verbose("Received Stimulus: Transfer(%d/%d)\n", instance, callreference);
03221
03222 break;
03223 case STIMULUS_CONFERENCE:
03224 if (skinnydebug)
03225 ast_verbose("Received Stimulus: Conference(%d/%d)\n", instance, callreference);
03226
03227 break;
03228 case STIMULUS_VOICEMAIL:
03229 if (skinnydebug)
03230 ast_verbose("Received Stimulus: Voicemail(%d/%d)\n", instance, callreference);
03231
03232 break;
03233 case STIMULUS_CALLPARK:
03234 if (skinnydebug)
03235 ast_verbose("Received Stimulus: Park Call(%d/%d)\n", instance, callreference);
03236
03237 break;
03238 case STIMULUS_FORWARDALL:
03239 if (skinnydebug)
03240 ast_verbose("Received Stimulus: Forward All(%d/%d)\n", instance, callreference);
03241
03242
03243
03244
03245 if (l->dnd != 0){
03246 if (option_verbose > 2)
03247 ast_verbose(VERBOSE_PREFIX_3 "Disabling DND on %s@%s\n", l->name, d->name);
03248 l->dnd = 0;
03249 transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
03250 transmit_displaynotify(s, "DnD disabled", 10);
03251 } else {
03252 if (option_verbose > 2)
03253 ast_verbose(VERBOSE_PREFIX_3 "Enabling DND on %s@%s\n", l->name, d->name);
03254 l->dnd = 1;
03255 transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF);
03256 transmit_displaynotify(s, "DnD enabled", 10);
03257 }
03258 break;
03259 case STIMULUS_FORWARDBUSY:
03260 if (skinnydebug)
03261 ast_verbose("Received Stimulus: Forward Busy (%d/%d)\n", instance, callreference);
03262 break;
03263 case STIMULUS_FORWARDNOANSWER:
03264 if (skinnydebug)
03265 ast_verbose("Received Stimulus: Forward No Answer (%d/%d)\n", instance, callreference);
03266 break;
03267 case STIMULUS_DISPLAY:
03268
03269 if (skinnydebug)
03270 ast_verbose("Received Stimulus: Display(%d/%d)\n", instance, callreference);
03271 break;
03272 case STIMULUS_LINE:
03273 if (skinnydebug)
03274 ast_verbose("Received Stimulus: Line(%d/%d)\n", instance, callreference);
03275
03276 l = find_line_by_instance(s->device, instance);
03277
03278 if (!l) {
03279 return 0;
03280 }
03281
03282
03283 transmit_speaker_mode(s, SKINNY_SPEAKERON);
03284 transmit_ringer_mode(s, SKINNY_RING_OFF);
03285 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
03286
03287 l->hookstate = SKINNY_OFFHOOK;
03288
03289 if (sub && sub->outgoing) {
03290
03291 ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
03292 transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
03293 transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
03294 transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
03295 transmit_displaypromptstatus(s, "Connected", 0, l->instance, sub->callid);
03296 transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_CONNECTED);
03297 start_rtp(sub);
03298 ast_setstate(sub->owner, AST_STATE_UP);
03299 } else {
03300 if (sub && sub->owner) {
03301 ast_log(LOG_DEBUG, "Current subchannel [%s] already has owner\n", sub->owner->name);
03302 } else {
03303 c = skinny_new(l, AST_STATE_DOWN);
03304 if(c) {
03305 sub = c->tech_pvt;
03306 transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
03307 if (skinnydebug)
03308 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
03309 transmit_displaymessage(s, NULL, l->instance, sub->callid);
03310 transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
03311 transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_OFFHOOK);
03312
03313
03314 if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
03315 ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
03316 ast_hangup(c);
03317 }
03318 } else {
03319 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
03320 }
03321 }
03322 }
03323 break;
03324 default:
03325 if (skinnydebug)
03326 ast_verbose("RECEIVED UNKNOWN STIMULUS: %d(%d/%d)\n", event, instance, callreference);
03327 break;
03328 }
03329 return 1;
03330 }
03331
03332 static int handle_offhook_message(struct skinny_req *req, struct skinnysession *s)
03333 {
03334 struct skinny_device *d = s->device;
03335 struct skinny_line *l;
03336 struct skinny_subchannel *sub;
03337 struct ast_channel *c;
03338 pthread_t t;
03339 int unknown1;
03340 int unknown2;
03341
03342 unknown1 = letohl(req->data.offhook.unknown1);
03343 unknown2 = letohl(req->data.offhook.unknown2);
03344
03345 sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
03346
03347 if (!sub) {
03348 l = find_line_by_instance(d, d->lastlineinstance);
03349 if (!l) {
03350 return 0;
03351 }
03352 } else {
03353 l = sub->parent;
03354 }
03355
03356 transmit_ringer_mode(s, SKINNY_RING_OFF);
03357 l->hookstate = SKINNY_OFFHOOK;
03358
03359 if (sub && sub->onhold) {
03360 return 1;
03361 }
03362
03363 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
03364
03365 if (sub && sub->outgoing) {
03366
03367 ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
03368 transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
03369 transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
03370 transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
03371 transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_CONNECTED);
03372 start_rtp(sub);
03373 ast_setstate(sub->owner, AST_STATE_UP);
03374 } else {
03375 if (sub && sub->owner) {
03376 ast_log(LOG_DEBUG, "Current sub [%s] already has owner\n", sub->owner->name);
03377 } else {
03378 c = skinny_new(l, AST_STATE_DOWN);
03379 if(c) {
03380 sub = c->tech_pvt;
03381 transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
03382 if (skinnydebug)
03383 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
03384 transmit_displaymessage(s, NULL, l->instance, sub->callid);
03385 transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
03386 transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_OFFHOOK);
03387
03388
03389 if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
03390 ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
03391 ast_hangup(c);
03392 }
03393 } else {
03394 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
03395 }
03396 }
03397 }
03398 return 1;
03399 }
03400
03401 static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s)
03402 {
03403 struct skinny_device *d = s->device;
03404 struct skinny_line *l;
03405 struct skinny_subchannel *sub;
03406 int unknown1;
03407 int unknown2;
03408
03409 unknown1 = letohl(req->data.onhook.unknown1);
03410 unknown2 = letohl(req->data.onhook.unknown2);
03411
03412 sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
03413
03414 if (!sub) {
03415 return 0;
03416 }
03417 l = sub->parent;
03418
03419 if (l->hookstate == SKINNY_ONHOOK) {
03420
03421 return 0;
03422 }
03423 l->hookstate = SKINNY_ONHOOK;
03424
03425 if (sub->onhold) {
03426 return 0;
03427 }
03428
03429 sub->cxmode = SKINNY_CX_RECVONLY;
03430 transmit_callstate(s, l->instance, l->hookstate, sub->callid);
03431 if (skinnydebug)
03432 ast_verbose("Skinny %s@%s went on hook\n", l->name, d->name);
03433 if (l->transfer && (sub->owner && sub->next && sub->next->owner) && ((!sub->outgoing) || (sub->next && !sub->next->outgoing))) {
03434
03435
03436
03437 #if 0
03438 if ((res = attempt_transfer(p)) < 0) {
03439 if (sub->next && sub->next->owner) {
03440 sub->next->alreadygone = 1;
03441 ast_queue_hangup(sub->next->owner,1);
03442 }
03443 } else if (res) {
03444 ast_log(LOG_WARNING, "Transfer attempt failed\n");
03445 return 0;
03446 }
03447 #endif
03448 } else {
03449
03450
03451 if (sub->owner) {
03452 sub->alreadygone = 1;
03453 ast_queue_hangup(sub->owner);
03454 } else {
03455 ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n",
03456 l->name, d->name, sub->callid);
03457 }
03458 }
03459 if ((l->hookstate == SKINNY_ONHOOK) && (sub->next && !sub->next->rtp)) {
03460 do_housekeeping(s);
03461 }
03462 return 1;
03463 }
03464
03465 static int handle_capabilities_res_message(struct skinny_req *req, struct skinnysession *s)
03466 {
03467 struct skinny_device *d = s->device;
03468 struct skinny_line *l;
03469 uint32_t count = 0;
03470 int codecs = 0;
03471 int i;
03472
03473 count = letohl(req->data.caps.count);
03474 if (count > SKINNY_MAX_CAPABILITIES) {
03475 count = SKINNY_MAX_CAPABILITIES;
03476 ast_log(LOG_WARNING, "Received more capabilities than we can handle (%d). Ignoring the rest.\n", SKINNY_MAX_CAPABILITIES);
03477 }
03478
03479 for (i = 0; i < count; i++) {
03480 int acodec = 0;
03481 int scodec = 0;
03482 scodec = letohl(req->data.caps.caps[i].codec);
03483 acodec = codec_skinny2ast(scodec);
03484 if (skinnydebug)
03485 ast_verbose("Adding codec capability '%d (%d)'\n", acodec, scodec);
03486 codecs |= acodec;
03487 }
03488
03489 d->capability &= codecs;
03490 ast_verbose("Device capability set to '%d'\n", d->capability);
03491 for (l = d->lines; l; l = l->next) {
03492 ast_mutex_lock(&l->lock);
03493 l->capability = d->capability;
03494 ast_mutex_unlock(&l->lock);
03495 }
03496
03497 return 1;
03498 }
03499
03500 static int handle_speed_dial_stat_req_message(struct skinny_req *req, struct skinnysession *s)
03501 {
03502 struct skinny_device *d = s->device;
03503 struct skinny_speeddial *sd;
03504 int instance;
03505
03506 instance = letohl(req->data.speeddialreq.speedDialNumber);
03507
03508 sd = find_speeddial_by_instance(d, instance);
03509
03510 if (!sd) {
03511 return 0;
03512 }
03513
03514 if (!(req = req_alloc(sizeof(struct speed_dial_stat_res_message), SPEED_DIAL_STAT_RES_MESSAGE)))
03515 return -1;
03516
03517 req->data.speeddialreq.speedDialNumber = htolel(instance);
03518 snprintf(req->data.speeddial.speedDialDirNumber, sizeof(req->data.speeddial.speedDialDirNumber), sd->exten);
03519 snprintf(req->data.speeddial.speedDialDisplayName, sizeof(req->data.speeddial.speedDialDisplayName), sd->label);
03520
03521 transmit_response(s, req);
03522 return 1;
03523 }
03524
03525 static int handle_line_state_req_message(struct skinny_req *req, struct skinnysession *s)
03526 {
03527 struct skinny_device *d = s->device;
03528 struct skinny_line *l;
03529 int instance;
03530
03531 instance = letohl(req->data.line.lineNumber);
03532
03533 ast_mutex_lock(&devicelock);
03534
03535 l = find_line_by_instance(d, instance);
03536
03537 if (!l) {
03538 return 0;
03539 }
03540
03541 ast_mutex_unlock(&devicelock);
03542
03543 if (!(req = req_alloc(sizeof(struct line_stat_res_message), LINE_STAT_RES_MESSAGE)))
03544 return -1;
03545
03546 req->data.linestat.lineNumber = letohl(instance);
03547 memcpy(req->data.linestat.lineDirNumber, l->name,
03548 sizeof(req->data.linestat.lineDirNumber));
03549 memcpy(req->data.linestat.lineDisplayName, l->label,
03550 sizeof(req->data.linestat.lineDisplayName));
03551 transmit_response(s,req);
03552 return 1;
03553 }
03554
03555 static int handle_time_date_req_message(struct skinny_req *req, struct skinnysession *s)
03556 {
03557 time_t timer;
03558 struct tm *cmtime;
03559
03560 if (!(req = req_alloc(sizeof(struct definetimedate_message), DEFINETIMEDATE_MESSAGE)))
03561 return -1;
03562
03563 timer = time(NULL);
03564 cmtime = localtime(&timer);
03565 req->data.definetimedate.year = htolel(cmtime->tm_year+1900);
03566 req->data.definetimedate.month = htolel(cmtime->tm_mon+1);
03567 req->data.definetimedate.dayofweek = htolel(cmtime->tm_wday);
03568 req->data.definetimedate.day = htolel(cmtime->tm_mday);
03569 req->data.definetimedate.hour = htolel(cmtime->tm_hour);
03570 req->data.definetimedate.minute = htolel(cmtime->tm_min);
03571 req->data.definetimedate.seconds = htolel(cmtime->tm_sec);
03572 req->data.definetimedate.milliseconds = htolel(0);
03573 req->data.definetimedate.timestamp = htolel(timer);
03574 transmit_response(s, req);
03575 return 1;
03576 }
03577
03578 static int handle_button_template_req_message(struct skinny_req *req, struct skinnysession *s)
03579 {
03580 struct skinny_device *d = s->device;
03581 struct skinny_line *l;
03582 int i;
03583
03584 struct skinny_speeddial *sd;
03585 struct button_definition_template btn[42];
03586 int lineInstance = 1;
03587 int speeddialInstance = 1;
03588 int buttonCount = 0;
03589
03590 if (!(req = req_alloc(sizeof(struct button_template_res_message), BUTTON_TEMPLATE_RES_MESSAGE)))
03591 return -1;
03592
03593 memset(&btn, 0, sizeof(btn));
03594
03595 get_button_template(s, btn);
03596
03597 for (i=0; i<42; i++) {
03598 int btnSet = 0;
03599 switch (btn[i].buttonDefinition) {
03600 case BT_CUST_LINESPEEDDIAL:
03601
03602 req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE;
03603 req->data.buttontemplate.definition[i].instanceNumber = htolel(0);
03604
03605 for (l = d->lines; l; l = l->next) {
03606 if (l->instance == lineInstance) {
03607 ast_verbose("Adding button: %d, %d\n", BT_LINE, lineInstance);
03608 req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE;
03609 req->data.buttontemplate.definition[i].instanceNumber = htolel(lineInstance);
03610 lineInstance++;
03611 buttonCount++;
03612 btnSet = 1;
03613 break;
03614 }
03615 }
03616
03617 if (!btnSet) {
03618 for (sd = d->speeddials; sd; sd = sd->next) {
03619 if (sd->instance == speeddialInstance) {
03620 ast_verbose("Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
03621 req->data.buttontemplate.definition[i].buttonDefinition = BT_SPEEDDIAL;
03622 req->data.buttontemplate.definition[i].instanceNumber = htolel(speeddialInstance);
03623 speeddialInstance++;
03624 buttonCount++;
03625 btnSet = 1;
03626 break;
03627 }
03628 }
03629 }
03630 break;
03631 case BT_LINE:
03632 req->data.buttontemplate.definition[i].buttonDefinition = htolel(BT_NONE);
03633 req->data.buttontemplate.definition[i].instanceNumber = htolel(0);
03634
03635 for (l = d->lines; l; l = l->next) {
03636 if (l->instance == lineInstance) {
03637 ast_verbose("Adding button: %d, %d\n", BT_LINE, lineInstance);
03638 req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE;
03639 req->data.buttontemplate.definition[i].instanceNumber = htolel(lineInstance);
03640 lineInstance++;
03641 buttonCount++;
03642 btnSet = 1;
03643 break;
03644 }
03645 }
03646 break;
03647 case BT_SPEEDDIAL:
03648 req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE;
03649 req->data.buttontemplate.definition[i].instanceNumber = 0;
03650
03651 for (sd = d->speeddials; sd; sd = sd->next) {
03652 if (sd->instance == speeddialInstance) {
03653 ast_verbose("Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
03654 req->data.buttontemplate.definition[i].buttonDefinition = BT_SPEEDDIAL;
03655 req->data.buttontemplate.definition[i].instanceNumber = htolel(speeddialInstance);
03656 speeddialInstance++;
03657 buttonCount++;
03658 btnSet = 1;
03659 break;
03660 }
03661 }
03662 break;
03663 case BT_CUST_HINT:
03664 break;
03665 case BT_NONE:
03666 break;
03667 default:
03668 ast_verbose("Adding button: %d, %d\n", btn[i].buttonDefinition, 0);
03669 req->data.buttontemplate.definition[i].buttonDefinition = htolel(btn[i].buttonDefinition);
03670 req->data.buttontemplate.definition[i].instanceNumber = htolel(0);
03671 buttonCount++;
03672 btnSet = 1;
03673 break;
03674 }
03675 }
03676
03677 req->data.buttontemplate.buttonOffset = htolel(0);
03678 req->data.buttontemplate.buttonCount = htolel(buttonCount);
03679 req->data.buttontemplate.totalButtonCount = htolel(buttonCount);
03680
03681 if (skinnydebug)
03682 ast_verbose("Sending %d template to %s\n",
03683 d->type,
03684 d->name);
03685 transmit_response(s, req);
03686 return 1;
03687 }
03688
03689 static int handle_version_req_message(struct skinny_req *req, struct skinnysession *s)
03690 {
03691 struct skinny_device *d = s->device;
03692 if (!(req = req_alloc(sizeof(struct version_res_message), VERSION_RES_MESSAGE)))
03693 return -1;
03694
03695 snprintf(req->data.version.version, sizeof(req->data.version.version), d->version_id);
03696 transmit_response(s, req);
03697 return 1;
03698 }
03699
03700 static int handle_server_request_message(struct skinny_req *req, struct skinnysession *s)
03701 {
03702 struct skinny_device *d = s->device;
03703 if (!(req = req_alloc(sizeof(struct server_res_message), SERVER_RES_MESSAGE)))
03704 return -1;
03705
03706 memcpy(req->data.serverres.server[0].serverName, ourhost,
03707 sizeof(req->data.serverres.server[0].serverName));
03708 req->data.serverres.serverListenPort[0] = htolel(ourport);
03709 req->data.serverres.serverIpAddr[0] = htolel(d->ourip.s_addr);
03710 transmit_response(s, req);
03711 return 1;
03712 }
03713
03714 static int handle_alarm_message(struct skinny_req *req, struct skinnysession *s)
03715 {
03716
03717 if (skinnydebug)
03718 ast_verbose("Received Alarm Message: %s\n", req->data.alarm.displayMessage);
03719
03720 return 1;
03721 }
03722
03723 static int handle_open_receive_channel_ack_message(struct skinny_req *req, struct skinnysession *s)
03724 {
03725 struct skinny_device *d = s->device;
03726 struct skinny_line *l;
03727 struct skinny_subchannel *sub;
03728 struct ast_format_list fmt;
03729 struct sockaddr_in sin;
03730 struct sockaddr_in us;
03731 uint32_t addr;
03732 int port;
03733 int status;
03734 int passthruid;
03735
03736 status = letohl(req->data.openreceivechannelack.status);
03737 if (status) {
03738 ast_log(LOG_ERROR, "Open Receive Channel Failure\n");
03739 return 0;
03740 }
03741 addr = letohl(req->data.openreceivechannelack.ipAddr);
03742 port = letohl(req->data.openreceivechannelack.port);
03743 passthruid = letohl(req->data.openreceivechannelack.passThruId);
03744
03745 sin.sin_family = AF_INET;
03746 sin.sin_addr.s_addr = addr;
03747 sin.sin_port = htons(port);
03748
03749 sub = find_subchannel_by_reference(d, passthruid);
03750
03751 if (!sub)
03752 return 0;
03753
03754 l = sub->parent;
03755
03756 if (sub->rtp) {
03757 ast_rtp_set_peer(sub->rtp, &sin);
03758 ast_rtp_get_us(sub->rtp, &us);
03759 } else {
03760 ast_log(LOG_ERROR, "No RTP structure, this is very bad\n");
03761 return 0;
03762 }
03763
03764 if (skinnydebug) {
03765 ast_verbose("ipaddr = %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
03766 ast_verbose("ourip = %s:%d\n", ast_inet_ntoa(d->ourip), ntohs(us.sin_port));
03767 }
03768
03769 if (!(req = req_alloc(sizeof(struct start_media_transmission_message), START_MEDIA_TRANSMISSION_MESSAGE)))
03770 return -1;
03771
03772 fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability));
03773
03774 if (skinnydebug)
03775 ast_verbose("Setting payloadType to '%d' (%d ms)\n", fmt.bits, fmt.cur_ms);
03776
03777 req->data.startmedia.conferenceId = htolel(sub->callid);
03778 req->data.startmedia.passThruPartyId = htolel(sub->callid);
03779 req->data.startmedia.remoteIp = htolel(d->ourip.s_addr);
03780 req->data.startmedia.remotePort = htolel(ntohs(us.sin_port));
03781 req->data.startmedia.packetSize = htolel(fmt.cur_ms);
03782 req->data.startmedia.payloadType = htolel(codec_ast2skinny(fmt.bits));
03783 req->data.startmedia.qualifier.precedence = htolel(127);
03784 req->data.startmedia.qualifier.vad = htolel(0);
03785 req->data.startmedia.qualifier.packets = htolel(0);
03786 req->data.startmedia.qualifier.bitRate = htolel(0);
03787 transmit_response(s, req);
03788
03789 return 1;
03790 }
03791
03792 static int handle_enbloc_call_message(struct skinny_req *req, struct skinnysession *s)
03793 {
03794 struct skinny_device *d = s->device;
03795 struct skinny_line *l;
03796 struct skinny_subchannel *sub = NULL;
03797 struct ast_channel *c;
03798 pthread_t t;
03799
03800 if (skinnydebug)
03801 ast_verbose("Received Enbloc Call: %s\n", req->data.enbloccallmessage.calledParty);
03802
03803 sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
03804
03805 if (!sub) {
03806 l = find_line_by_instance(d, d->lastlineinstance);
03807 if (!l) {
03808 return 0;
03809 }
03810 } else {
03811 l = sub->parent;
03812 }
03813
03814 c = skinny_new(l, AST_STATE_DOWN);
03815
03816 if(!c) {
03817 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
03818 } else {
03819 l->hookstate = SKINNY_OFFHOOK;
03820
03821 sub = c->tech_pvt;
03822 transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
03823 if (skinnydebug)
03824 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
03825 transmit_displaymessage(s, NULL, l->instance, sub->callid);
03826 transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
03827
03828 if (!ast_ignore_pattern(c->context, req->data.enbloccallmessage.calledParty)) {
03829 transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
03830 }
03831 ast_copy_string(c->exten, req->data.enbloccallmessage.calledParty, sizeof(c->exten));
03832 if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
03833 ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
03834 ast_hangup(c);
03835 }
03836 }
03837
03838 return 1;
03839 }
03840
03841
03842 static int handle_soft_key_set_req_message(struct skinny_req *req, struct skinnysession *s)
03843 {
03844 int i;
03845 int x;
03846 int y;
03847 const struct soft_key_definitions *softkeymode = soft_key_default_definitions;
03848
03849 if (!(req = req_alloc(sizeof(struct soft_key_set_res_message), SOFT_KEY_SET_RES_MESSAGE)))
03850 return -1;
03851
03852 req->data.softkeysets.softKeySetOffset = htolel(0);
03853 req->data.softkeysets.softKeySetCount = htolel(11);
03854 req->data.softkeysets.totalSoftKeySetCount = htolel(11);
03855 for (x = 0; x < sizeof(soft_key_default_definitions) / sizeof(struct soft_key_definitions); x++) {
03856 const uint8_t *defaults = softkeymode->defaults;
03857
03858
03859 for (y = 0; y < softkeymode->count; y++) {
03860 for (i = 0; i < (sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition)); i++) {
03861 if (defaults[y] == i+1) {
03862 req->data.softkeysets.softKeySetDefinition[softkeymode->mode].softKeyTemplateIndex[y] = htolel(i+1);
03863 req->data.softkeysets.softKeySetDefinition[softkeymode->mode].softKeyInfoIndex[y] = htolel(i+301);
03864 }
03865 }
03866 }
03867 softkeymode++;
03868 }
03869 transmit_response(s,req);
03870 transmit_selectsoftkeys(s, 0, 0, KEYDEF_ONHOOK);
03871 return 1;
03872 }
03873
03874 static int handle_soft_key_event_message(struct skinny_req *req, struct skinnysession *s)
03875 {
03876 struct skinny_device *d = s->device;
03877 struct skinny_line *l;
03878 struct skinny_subchannel *sub = NULL;
03879 struct ast_channel *c;
03880 pthread_t t;
03881 int event;
03882 int instance;
03883 int callreference;
03884
03885 event = letohl(req->data.softkeyeventmessage.softKeyEvent);
03886 instance = letohl(req->data.softkeyeventmessage.instance);
03887 callreference = letohl(req->data.softkeyeventmessage.callreference);
03888
03889 if (instance) {
03890 l = find_line_by_instance(d, instance);
03891 if (callreference) {
03892 sub = find_subchannel_by_instance_reference(d, instance, callreference);
03893 } else {
03894 sub = find_subchannel_by_instance_reference(d, instance, d->lastcallreference);
03895 }
03896 } else {
03897 l = find_line_by_instance(d, d->lastlineinstance);
03898 }
03899
03900 if (!l) {
03901 if (skinnydebug)
03902 ast_verbose("Received Softkey Event: %d(%d/%d)\n", event, instance, callreference);
03903 return 0;
03904 }
03905
03906 switch(event) {
03907 case SOFTKEY_NONE:
03908 if (skinnydebug)
03909 ast_verbose("Received Softkey Event: None(%d/%d)\n", instance, callreference);
03910 break;
03911 case SOFTKEY_REDIAL:
03912 if (skinnydebug)
03913 ast_verbose("Received Softkey Event: Redial(%d/%d)\n", instance, callreference);
03914
03915 #if 0
03916 if (!sub || !sub->owner) {
03917 c = skinny_new(l, AST_STATE_DOWN);
03918 } else {
03919 c = sub->owner;
03920 }
03921
03922 if(!c) {
03923 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
03924 } else {
03925 sub = c->tech_pvt;
03926 transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
03927 if (skinnydebug)
03928 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
03929 transmit_displaymessage(s, NULL, l->instance, sub->callid);
03930 transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
03931 transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_RINGOUT);
03932
03933 if (!ast_ignore_pattern(c->context, l->lastnumberdialed)) {
03934 transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
03935 }
03936 ast_copy_string(c->exten, l->lastnumberdialed, sizeof(c->exten));
03937 if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
03938 ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
03939 ast_hangup(c);
03940 }
03941 }
03942 #endif
03943 break;
03944 case SOFTKEY_NEWCALL:
03945 if (skinnydebug)
03946 ast_verbose("Received Softkey Event: New Call(%d/%d)\n", instance, callreference);
03947
03948 if (!sub || !sub->owner) {
03949 c = skinny_new(l, AST_STATE_DOWN);
03950 } else {
03951 c = sub->owner;
03952 }
03953
03954 if (!c) {
03955 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
03956 } else {
03957 sub = c->tech_pvt;
03958 if (l->hookstate == SKINNY_ONHOOK) {
03959 l->hookstate = SKINNY_OFFHOOK;
03960 transmit_speaker_mode(s, SKINNY_SPEAKERON);
03961 transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
03962 }
03963
03964 if (skinnydebug)
03965 ast_verbose("Attempting to Clear display on Skinny %s@%s\n", l->name, d->name);
03966 transmit_displaymessage(s, NULL, l->instance, sub->callid);
03967 transmit_tone(s, SKINNY_DIALTONE, l->instance, sub->callid);
03968 transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_OFFHOOK);
03969
03970
03971 if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
03972 ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
03973 ast_hangup(c);
03974 }
03975 }
03976 break;
03977 case SOFTKEY_HOLD:
03978 if (skinnydebug)
03979 ast_verbose("Received Softkey Event: Hold(%d/%d)\n", instance, callreference);
03980
03981 if (sub) {
03982 if (sub->onhold) {
03983 skinny_unhold(sub);
03984 } else {
03985 skinny_hold(sub);
03986 }
03987 }
03988
03989 break;
03990 case SOFTKEY_TRNSFER:
03991 if (skinnydebug)
03992 ast_verbose("Received Softkey Event: Transfer(%d/%d)\n", instance, callreference);
03993
03994 break;
03995 case SOFTKEY_CFWDALL:
03996 if (skinnydebug)
03997 ast_verbose("Received Softkey Event: Forward All(%d/%d)\n", instance, callreference);
03998
03999
04000 if (l->dnd != 0){
04001 if (option_verbose > 2)
04002 ast_verbose(VERBOSE_PREFIX_3 "Disabling DND on %s@%s\n", l->name, d->name);
04003 l->dnd = 0;
04004 transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
04005 transmit_displaynotify(s, "DnD disabled", 10);
04006 } else {
04007 if (option_verbose > 2)
04008 ast_verbose(VERBOSE_PREFIX_3 "Enabling DND on %s@%s\n", l->name, d->name);
04009 l->dnd = 1;
04010 transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF);
04011 transmit_displaynotify(s, "DnD enabled", 10);
04012 }
04013 break;
04014 case SOFTKEY_CFWDBUSY:
04015 if (skinnydebug)
04016 ast_verbose("Received Softkey Event: Forward Busy (%d/%d)\n", instance, callreference);
04017 break;
04018 case SOFTKEY_CFWDNOANSWER:
04019 if (skinnydebug)
04020 ast_verbose("Received Softkey Event: Forward No Answer (%d/%d)\n", instance, callreference);
04021 break;
04022 case SOFTKEY_BKSPC:
04023 if (skinnydebug)
04024 ast_verbose("Received Softkey Event: Backspace(%d/%d)\n", instance, callreference);
04025 break;
04026 case SOFTKEY_ENDCALL:
04027 if (skinnydebug)
04028 ast_verbose("Received Softkey Event: End Call(%d/%d)\n", instance, callreference);
04029
04030 if (l->hookstate == SKINNY_ONHOOK) {
04031
04032 break;
04033 }
04034 if (sub) {
04035 sub->cxmode = SKINNY_CX_RECVONLY;
04036 l->hookstate = SKINNY_ONHOOK;
04037 transmit_callstate(s, l->instance, l->hookstate, sub->callid);
04038 if (skinnydebug)
04039 ast_verbose("Skinny %s@%s went on hook\n", l->name, d->name);
04040 if (l->transfer && (sub->owner && sub->next && sub->next->owner) && ((!sub->outgoing) || (sub->next && !sub->next->outgoing))) {
04041
04042
04043
04044 #if 0
04045 if ((res = attempt_transfer(p)) < 0) {
04046 if (sub->next && sub->next->owner) {
04047 sub->next->alreadygone = 1;
04048 ast_queue_hangup(sub->next->owner, 1);
04049 }
04050 } else if (res) {
04051 ast_log(LOG_WARNING, "Transfer attempt failed\n");
04052 break;
04053 }
04054 #endif
04055 } else {
04056
04057
04058 if (sub->owner) {
04059 sub->alreadygone = 1;
04060 ast_queue_hangup(sub->owner);
04061 } else {
04062 ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n",
04063 l->name, d->name, sub->callid);
04064 }
04065 }
04066 if ((l->hookstate == SKINNY_ONHOOK) && (sub->next && !sub->next->rtp)) {
04067 do_housekeeping(s);
04068 }
04069 }
04070 break;
04071 case SOFTKEY_RESUME:
04072 if (skinnydebug)
04073 ast_verbose("Received Softkey Event: Resume(%d/%d)\n", instance, callreference);
04074 break;
04075 case SOFTKEY_ANSWER:
04076 if (skinnydebug)
04077 ast_verbose("Received Softkey Event: Answer(%d/%d)\n", instance, callreference);
04078
04079 transmit_ringer_mode(s,SKINNY_RING_OFF);
04080 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
04081
04082 l->hookstate = SKINNY_OFFHOOK;
04083
04084 if (sub && sub->outgoing) {
04085
04086 ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
04087 transmit_callstate(s, l->instance, SKINNY_OFFHOOK, sub->callid);
04088 transmit_tone(s, SKINNY_SILENCE, l->instance, sub->callid);
04089 transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
04090 transmit_selectsoftkeys(s, l->instance, sub->callid, KEYDEF_CONNECTED);
04091 start_rtp(sub);
04092 ast_setstate(sub->owner, AST_STATE_UP);
04093 }
04094 break;
04095 case SOFTKEY_INFO:
04096 if (skinnydebug)
04097 ast_verbose("Received Softkey Event: Info(%d/%d)\n", instance, callreference);
04098 break;
04099 case SOFTKEY_CONFRN:
04100 if (skinnydebug)
04101 ast_verbose("Received Softkey Event: Conference(%d/%d)\n", instance, callreference);
04102
04103 break;
04104 case SOFTKEY_PARK:
04105 if (skinnydebug)
04106 ast_verbose("Received Softkey Event: Park Call(%d/%d)\n", instance, callreference);
04107
04108 break;
04109 case SOFTKEY_JOIN:
04110 if (skinnydebug)
04111 ast_verbose("Received Softkey Event: Join(%d/%d)\n", instance, callreference);
04112 break;
04113 case SOFTKEY_MEETME:
04114
04115 if (skinnydebug)
04116 ast_verbose("Received Softkey Event: Meetme(%d/%d)\n", instance, callreference);
04117 break;
04118 case SOFTKEY_PICKUP:
04119 if (skinnydebug)
04120 ast_verbose("Received Softkey Event: Pickup(%d/%d)\n", instance, callreference);
04121 break;
04122 case SOFTKEY_GPICKUP:
04123 if (skinnydebug)
04124 ast_verbose("Received Softkey Event: Group Pickup(%d/%d)\n", instance, callreference);
04125 break;
04126 default:
04127 if (skinnydebug)
04128 ast_verbose("Received unknown Softkey Event: %d(%d/%d)\n", event, instance, callreference);
04129 break;
04130 }
04131 return 1;
04132 }
04133
04134 static int handle_unregister_message(struct skinny_req *req, struct skinnysession *s)
04135 {
04136 return skinny_unregister(req, s);
04137 }
04138
04139 static int handle_soft_key_template_req_message(struct skinny_req *req, struct skinnysession *s)
04140 {
04141 if (!(req = req_alloc(sizeof(struct soft_key_template_res_message), SOFT_KEY_TEMPLATE_RES_MESSAGE)))
04142 return -1;
04143
04144 req->data.softkeytemplate.softKeyOffset = htolel(0);
04145 req->data.softkeytemplate.softKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition));
04146 req->data.softkeytemplate.totalSoftKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition));
04147 memcpy(req->data.softkeytemplate.softKeyTemplateDefinition,
04148 soft_key_template_default,
04149 sizeof(soft_key_template_default));
04150 transmit_response(s,req);
04151 return 1;
04152 }
04153
04154 static int handle_headset_status_message(struct skinny_req *req, struct skinnysession *s)
04155 {
04156
04157 return 1;
04158 }
04159
04160 static int handle_register_available_lines_message(struct skinny_req *req, struct skinnysession *s)
04161 {
04162
04163 return 1;
04164 }
04165
04166 static int handle_message(struct skinny_req *req, struct skinnysession *s)
04167 {
04168 int res = 0;
04169 struct skinny_device *d = s->device;
04170 struct skinny_subchannel *sub;
04171 int lineInstance;
04172 int callReference;
04173
04174 if ((!s->device) && (letohl(req->e) != REGISTER_MESSAGE && letohl(req->e) != ALARM_MESSAGE)) {
04175 ast_log(LOG_WARNING, "Client sent message #%d without first registering.\n", req->e);
04176 free(req);
04177 return 0;
04178 }
04179
04180 switch(letohl(req->e)) {
04181 case KEEP_ALIVE_MESSAGE:
04182 res = handle_keep_alive_message(req, s);
04183 break;
04184 case REGISTER_MESSAGE:
04185 if (skinnydebug)
04186 ast_verbose("Device %s is attempting to register\n", req->data.reg.name);
04187
04188 res = handle_register_message(req, s);
04189 break;
04190 case IP_PORT_MESSAGE:
04191 res = handle_ip_port_message(req, s);
04192 break;
04193 case KEYPAD_BUTTON_MESSAGE:
04194 if (skinnydebug)
04195 ast_verbose("Collected digit: [%d]\n", letohl(req->data.keypad.button));
04196
04197 lineInstance = letohl(req->data.keypad.lineInstance);
04198 callReference = letohl(req->data.keypad.callReference);
04199
04200 sub = find_subchannel_by_instance_reference(d, lineInstance, callReference);
04201
04202 if (sub && (sub->owner && sub->owner->_state < AST_STATE_UP)) {
04203 char dgt;
04204 int digit = letohl(req->data.keypad.button);
04205 size_t len;
04206
04207 if (digit == 14) {
04208 dgt = '*';
04209 } else if (digit == 15) {
04210 dgt = '#';
04211 } else if (digit >= 0 && digit <= 9) {
04212 dgt = '0' + digit;
04213 } else {
04214
04215
04216
04217
04218
04219
04220
04221 dgt = '0' + digit;
04222 ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
04223 }
04224
04225 len = strlen(d->exten);
04226 if (len < sizeof(d->exten) - 1) {
04227 d->exten[len] = dgt;
04228 d->exten[len+1] = '\0';
04229 } else {
04230 ast_log(LOG_WARNING, "Dropping digit with value %d because digit queue is full\n", dgt);
04231 }
04232 } else
04233 res = handle_keypad_button_message(req, s);
04234 break;
04235 case ENBLOC_CALL_MESSAGE:
04236 res = handle_enbloc_call_message(req, s);
04237 break;
04238 case STIMULUS_MESSAGE:
04239 res = handle_stimulus_message(req, s);
04240 break;
04241 case OFFHOOK_MESSAGE:
04242 res = handle_offhook_message(req, s);
04243 break;
04244 case ONHOOK_MESSAGE:
04245 res = handle_onhook_message(req, s);
04246 break;
04247 case CAPABILITIES_RES_MESSAGE:
04248 if (skinnydebug)
04249 ast_verbose("Received CapabilitiesRes\n");
04250
04251 res = handle_capabilities_res_message(req, s);
04252 break;
04253 case SPEED_DIAL_STAT_REQ_MESSAGE:
04254 if (skinnydebug)
04255 ast_verbose("Received SpeedDialStatRequest\n");
04256
04257 res = handle_speed_dial_stat_req_message(req, s);
04258 break;
04259 case LINE_STATE_REQ_MESSAGE:
04260 if (skinnydebug)
04261 ast_verbose("Received LineStatRequest\n");
04262 res = handle_line_state_req_message(req, s);
04263 break;
04264 case TIME_DATE_REQ_MESSAGE:
04265 if (skinnydebug)
04266 ast_verbose("Received Time/Date Request\n");
04267
04268 res = handle_time_date_req_message(req, s);
04269 break;
04270 case BUTTON_TEMPLATE_REQ_MESSAGE:
04271 if (skinnydebug)
04272 ast_verbose("Buttontemplate requested\n");
04273
04274 res = handle_button_template_req_message(req, s);
04275 break;
04276 case VERSION_REQ_MESSAGE:
04277 if (skinnydebug)
04278 ast_verbose("Version Request\n");
04279
04280 res = handle_version_req_message(req, s);
04281 break;
04282 case SERVER_REQUEST_MESSAGE:
04283 if (skinnydebug)
04284 ast_verbose("Received Server Request\n");
04285
04286 res = handle_server_request_message(req, s);
04287 break;
04288 case ALARM_MESSAGE:
04289 res = handle_alarm_message(req, s);
04290 break;
04291 case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE:
04292 if (skinnydebug)
04293 ast_verbose("Received Open Receive Channel Ack\n");
04294
04295 res = handle_open_receive_channel_ack_message(req, s);
04296 break;
04297 case SOFT_KEY_SET_REQ_MESSAGE:
04298 if (skinnydebug)
04299 ast_verbose("Received SoftKeySetReq\n");
04300
04301 res = handle_soft_key_set_req_message(req, s);
04302 break;
04303 case SOFT_KEY_EVENT_MESSAGE:
04304 res = handle_soft_key_event_message(req, s);
04305 break;
04306 case UNREGISTER_MESSAGE:
04307 if (skinnydebug)
04308 ast_verbose("Received Unregister Request\n");
04309
04310 res = handle_unregister_message(req, s);
04311 break;
04312 case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
04313 if (skinnydebug)
04314 ast_verbose("Received SoftKey Template Request\n");
04315
04316 res = handle_soft_key_template_req_message(req, s);
04317 break;
04318 case HEADSET_STATUS_MESSAGE:
04319 res = handle_headset_status_message(req, s);
04320 break;
04321 case REGISTER_AVAILABLE_LINES_MESSAGE:
04322 res = handle_register_available_lines_message(req, s);
04323 break;
04324 default:
04325 if (skinnydebug)
04326 ast_verbose("RECEIVED UNKNOWN MESSAGE TYPE: %x\n", letohl(req->e));
04327 break;
04328 }
04329 if (res >= 0 && req)
04330 free(req);
04331 return res;
04332 }
04333
04334 static void destroy_session(struct skinnysession *s)
04335 {
04336 struct skinnysession *cur, *prev = NULL;
04337 ast_mutex_lock(&sessionlock);
04338 cur = sessions;
04339 while(cur) {
04340 if (cur == s) {
04341 break;
04342 }
04343 prev = cur;
04344 cur = cur->next;
04345 }
04346 if (cur) {
04347 if (prev) {
04348 prev->next = cur->next;
04349 } else {
04350 sessions = cur->next;
04351 }
04352 if (s->fd > -1) {
04353 close(s->fd);
04354 }
04355 ast_mutex_destroy(&s->lock);
04356 free(s);
04357 } else {
04358 ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
04359 }
04360 ast_mutex_unlock(&sessionlock);
04361 }
04362
04363 static int get_input(struct skinnysession *s)
04364 {
04365 int res;
04366 int dlen = 0;
04367 struct pollfd fds[1];
04368
04369 fds[0].fd = s->fd;
04370 fds[0].events = POLLIN;
04371 fds[0].revents = 0;
04372 res = poll(fds, 1, (keep_alive * 1100));
04373
04374
04375 if (res < 0) {
04376 if (errno != EINTR) {
04377 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
04378 return res;
04379 }
04380 } else if (res == 0) {
04381 if (skinnydebug)
04382 ast_verbose("Skinny Client was lost, unregistering\n");
04383 skinny_unregister(NULL, s);
04384 return -1;
04385 }
04386
04387 if (fds[0].revents) {
04388 ast_mutex_lock(&s->lock);
04389 memset(s->inbuf,0,sizeof(s->inbuf));
04390 res = read(s->fd, s->inbuf, 4);
04391 if (res < 0) {
04392 ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
04393
04394 if (skinnydebug)
04395 ast_verbose("Skinny Client was lost, unregistering\n");
04396
04397 skinny_unregister(NULL,s);
04398 ast_mutex_unlock(&s->lock);
04399 return res;
04400 } else if (res != 4) {
04401 ast_log(LOG_WARNING, "Skinny Client sent less data than expected. Expected 4 but got %d.\n", res);
04402 ast_mutex_unlock(&s->lock);
04403
04404 if (res == 0) {
04405 if (skinnydebug)
04406 ast_verbose("Skinny Client was lost, unregistering\n");
04407 skinny_unregister(NULL, s);
04408 }
04409
04410 return -1;
04411 }
04412
04413 dlen = letohl(*(int *)s->inbuf);
04414 if (dlen < 4) {
04415 ast_log(LOG_WARNING, "Skinny Client sent invalid data.\n");
04416 ast_mutex_unlock(&s->lock);
04417 return -1;
04418 }
04419 if (dlen+8 > sizeof(s->inbuf)) {
04420 dlen = sizeof(s->inbuf) - 8;
04421 }
04422 *(int *)s->inbuf = htolel(dlen);
04423
04424 res = read(s->fd, s->inbuf+4, dlen+4);
04425 ast_mutex_unlock(&s->lock);
04426 if (res < 0) {
04427 ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
04428 return res;
04429 } else if (res != (dlen+4)) {
04430 ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
04431 return -1;
04432 }
04433 return res;
04434 }
04435 return 0;
04436 }
04437
04438 static struct skinny_req *skinny_req_parse(struct skinnysession *s)
04439 {
04440 struct skinny_req *req;
04441
04442 if (!(req = ast_calloc(1, SKINNY_MAX_PACKET)))
04443 return NULL;
04444
04445 ast_mutex_lock(&s->lock);
04446 memcpy(req, s->inbuf, skinny_header_size);
04447 memcpy(&req->data, s->inbuf+skinny_header_size, letohl(*(int*)(s->inbuf))-4);
04448
04449 ast_mutex_unlock(&s->lock);
04450
04451 if (letohl(req->e) < 0) {
04452 ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
04453 free(req);
04454 return NULL;
04455 }
04456
04457 return req;
04458 }
04459
04460 static void *skinny_session(void *data)
04461 {
04462 int res;
04463 struct skinny_req *req;
04464 struct skinnysession *s = data;
04465
04466 if (option_verbose > 2)
04467 ast_verbose(VERBOSE_PREFIX_3 "Starting Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));
04468
04469 for (;;) {
04470 res = get_input(s);
04471 if (res < 0) {
04472 break;
04473 }
04474
04475 if (res > 0)
04476 {
04477 if (!(req = skinny_req_parse(s))) {
04478 destroy_session(s);
04479 return NULL;
04480 }
04481
04482 res = handle_message(req, s);
04483 if (res < 0) {
04484 destroy_session(s);
04485 return NULL;
04486 }
04487 }
04488 }
04489 ast_log(LOG_NOTICE, "Skinny Session returned: %s\n", strerror(errno));
04490
04491 if (s)
04492 destroy_session(s);
04493
04494 return 0;
04495 }
04496
04497 static void *accept_thread(void *ignore)
04498 {
04499 int as;
04500 struct sockaddr_in sin;
04501 socklen_t sinlen;
04502 struct skinnysession *s;
04503 struct protoent *p;
04504 int arg = 1;
04505 pthread_attr_t attr;
04506 pthread_t tcp_thread;
04507
04508 pthread_attr_init(&attr);
04509 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04510
04511 for (;;) {
04512 sinlen = sizeof(sin);
04513 as = accept(skinnysock, (struct sockaddr *)&sin, &sinlen);
04514 if (as < 0) {
04515 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
04516 continue;
04517 }
04518 p = getprotobyname("tcp");
04519 if(p) {
04520 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
04521 ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
04522 }
04523 }
04524 if (!(s = ast_calloc(1, sizeof(struct skinnysession))))
04525 continue;
04526
04527 memcpy(&s->sin, &sin, sizeof(sin));
04528 ast_mutex_init(&s->lock);
04529 s->fd = as;
04530 ast_mutex_lock(&sessionlock);
04531 s->next = sessions;
04532 sessions = s;
04533 ast_mutex_unlock(&sessionlock);
04534
04535 if (ast_pthread_create(&tcp_thread, &attr, skinny_session, s)) {
04536 destroy_session(s);
04537 }
04538 }
04539 if (skinnydebug)
04540 ast_verbose("killing accept thread\n");
04541 close(as);
04542 pthread_attr_destroy(&attr);
04543 return 0;
04544 }
04545
04546 static void *do_monitor(void *data)
04547 {
04548 int res;
04549
04550
04551
04552
04553 for(;;) {
04554 pthread_testcancel();
04555
04556 res = ast_sched_wait(sched);
04557 if ((res < 0) || (res > 1000)) {
04558 res = 1000;
04559 }
04560 res = ast_io_wait(io, res);
04561 ast_mutex_lock(&monlock);
04562 if (res >= 0) {
04563 ast_sched_runq(sched);
04564 }
04565 ast_mutex_unlock(&monlock);
04566 }
04567
04568 return NULL;
04569
04570 }
04571
04572 static int restart_monitor(void)
04573 {
04574
04575 if (monitor_thread == AST_PTHREADT_STOP)
04576 return 0;
04577
04578 ast_mutex_lock(&monlock);
04579 if (monitor_thread == pthread_self()) {
04580 ast_mutex_unlock(&monlock);
04581 ast_log(LOG_WARNING, "Cannot kill myself\n");
04582 return -1;
04583 }
04584 if (monitor_thread != AST_PTHREADT_NULL) {
04585
04586 pthread_kill(monitor_thread, SIGURG);
04587 } else {
04588
04589 if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
04590 ast_mutex_unlock(&monlock);
04591 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
04592 return -1;
04593 }
04594 }
04595 ast_mutex_unlock(&monlock);
04596 return 0;
04597 }
04598
04599 static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause)
04600 {
04601 int oldformat;
04602
04603 struct skinny_line *l;
04604 struct ast_channel *tmpc = NULL;
04605 char tmp[256];
04606 char *dest = data;
04607
04608 oldformat = format;
04609
04610 if (!(format &= ((AST_FORMAT_MAX_AUDIO << 1) - 1))) {
04611 ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
04612 return NULL;
04613 }
04614
04615 ast_copy_string(tmp, dest, sizeof(tmp));
04616 if (ast_strlen_zero(tmp)) {
04617 ast_log(LOG_NOTICE, "Skinny channels require a device\n");
04618 return NULL;
04619 }
04620 l = find_line_by_name(tmp);
04621 if (!l) {
04622 ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
04623 return NULL;
04624 }
04625 if (option_verbose > 2) {
04626 ast_verbose(VERBOSE_PREFIX_3 "skinny_request(%s)\n", tmp);
04627 }
04628 tmpc = skinny_new(l, AST_STATE_DOWN);
04629 if (!tmpc) {
04630 ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
04631 }
04632 restart_monitor();
04633 return tmpc;
04634 }
04635
04636 static int reload_config(void)
04637 {
04638 int on = 1;
04639 struct ast_config *cfg;
04640 struct ast_variable *v;
04641 char *cat;
04642 struct skinny_device *d;
04643 int oldport = ntohs(bindaddr.sin_port);
04644
04645 if (gethostname(ourhost, sizeof(ourhost))) {
04646 ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled\n");
04647 return 0;
04648 }
04649 cfg = ast_config_load(config);
04650
04651
04652 if (!cfg) {
04653 ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled\n", config);
04654 return -1;
04655 }
04656 memset(&bindaddr, 0, sizeof(bindaddr));
04657 memset(&default_prefs, 0, sizeof(default_prefs));
04658
04659
04660 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
04661
04662
04663 v = ast_variable_browse(cfg, "general");
04664 while (v) {
04665
04666 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
04667 v = v->next;
04668 continue;
04669 }
04670
04671
04672 if (!strcasecmp(v->name, "bindaddr")) {
04673 if (!(hp = ast_gethostbyname(v->value, &ahp))) {
04674 ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
04675 } else {
04676 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
04677 }
04678 } else if (!strcasecmp(v->name, "keepalive")) {
04679 keep_alive = atoi(v->value);
04680 } else if (!strcasecmp(v->name, "dateformat")) {
04681 memcpy(date_format, v->value, sizeof(date_format));
04682 } else if (!strcasecmp(v->name, "allow")) {
04683 ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 1);
04684 } else if (!strcasecmp(v->name, "disallow")) {
04685 ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 0);
04686 } else if (!strcasecmp(v->name, "bindport") || !strcasecmp(v->name, "port")) {
04687 if (sscanf(v->value, "%d", &ourport) == 1) {
04688 bindaddr.sin_port = htons(ourport);
04689 } else {
04690 ast_log(LOG_WARNING, "Invalid bindport '%s' at line %d of %s\n", v->value, v->lineno, config);
04691 }
04692 if (!strcasecmp(v->name, "port")) {
04693 ast_log(LOG_WARNING, "Option 'port' at line %d of %s has been deprecated. Please use 'bindport' instead.\n", v->lineno, config);
04694 }
04695 }
04696 v = v->next;
04697 }
04698
04699 if (ntohl(bindaddr.sin_addr.s_addr)) {
04700 __ourip = bindaddr.sin_addr;
04701 } else {
04702 hp = ast_gethostbyname(ourhost, &ahp);
04703 if (!hp) {
04704 ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
04705 ast_config_destroy(cfg);
04706 return 0;
04707 }
04708 memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
04709 }
04710 if (!ntohs(bindaddr.sin_port)) {
04711 bindaddr.sin_port = ntohs(DEFAULT_SKINNY_PORT);
04712 }
04713 bindaddr.sin_family = AF_INET;
04714
04715
04716 cat = ast_category_browse(cfg, NULL);
04717 while(cat) {
04718 if (!strcasecmp(cat, "general")) {
04719
04720 #if 0
04721 } else if (!strncasecmp(cat, "paging-", 7)) {
04722 p = build_paging_device(cat, ast_variable_browse(cfg, cat));
04723 if (p) {
04724 }
04725 #endif
04726 } else {
04727 d = build_device(cat, ast_variable_browse(cfg, cat));
04728 if (d) {
04729 if (option_verbose > 2)
04730 ast_verbose(VERBOSE_PREFIX_3 "Added device '%s'\n", d->name);
04731 ast_mutex_lock(&devicelock);
04732 d->next = devices;
04733 devices = d;
04734 ast_mutex_unlock(&devicelock);
04735 }
04736 }
04737 cat = ast_category_browse(cfg, cat);
04738 }
04739 ast_mutex_lock(&netlock);
04740 if ((skinnysock > -1) && (ntohs(bindaddr.sin_port) != oldport)) {
04741 close(skinnysock);
04742 skinnysock = -1;
04743 }
04744 if (skinnysock < 0) {
04745 skinnysock = socket(AF_INET, SOCK_STREAM, 0);
04746 if(setsockopt(skinnysock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
04747 ast_log(LOG_ERROR, "Set Socket Options failed: errno %d, %s\n", errno, strerror(errno));
04748 ast_config_destroy(cfg);
04749 return 0;
04750 }
04751 if (skinnysock < 0) {
04752 ast_log(LOG_WARNING, "Unable to create Skinny socket: %s\n", strerror(errno));
04753 } else {
04754 if (bind(skinnysock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
04755 ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
04756 ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
04757 strerror(errno));
04758 close(skinnysock);
04759 skinnysock = -1;
04760 ast_config_destroy(cfg);
04761 return 0;
04762 }
04763 if (listen(skinnysock,DEFAULT_SKINNY_BACKLOG)) {
04764 ast_log(LOG_WARNING, "Failed to start listening to %s:%d: %s\n",
04765 ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
04766 strerror(errno));
04767 close(skinnysock);
04768 skinnysock = -1;
04769 ast_config_destroy(cfg);
04770 return 0;
04771 }
04772 if (option_verbose > 1)
04773 ast_verbose(VERBOSE_PREFIX_2 "Skinny listening on %s:%d\n",
04774 ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
04775 ast_pthread_create_background(&accept_t,NULL, accept_thread, NULL);
04776 }
04777 }
04778 ast_mutex_unlock(&netlock);
04779 ast_config_destroy(cfg);
04780 return 1;
04781 }
04782
04783 static void delete_devices(void)
04784 {
04785 struct skinny_device *d, *dlast;
04786 struct skinny_line *l, *llast;
04787 struct skinny_speeddial *sd, *sdlast;
04788 struct skinny_addon *a, *alast;
04789
04790 ast_mutex_lock(&devicelock);
04791
04792
04793 for (d=devices;d;) {
04794
04795 for (l=d->lines;l;) {
04796 llast = l;
04797 l = l->next;
04798 ast_mutex_destroy(&llast->lock);
04799 free(llast);
04800 }
04801
04802 for (sd=d->speeddials;sd;) {
04803 sdlast = sd;
04804 sd = sd->next;
04805 ast_mutex_destroy(&sdlast->lock);
04806 free(sdlast);
04807 }
04808
04809 for (a=d->addons;a;) {
04810 alast = a;
04811 a = a->next;
04812 ast_mutex_destroy(&alast->lock);
04813 free(alast);
04814 }
04815 dlast = d;
04816 d = d->next;
04817 free(dlast);
04818 }
04819 devices=NULL;
04820 ast_mutex_unlock(&devicelock);
04821 }
04822
04823 #if 0
04824
04825
04826
04827
04828 static int reload(void)
04829 {
04830 delete_devices();
04831 reload_config();
04832 restart_monitor();
04833 return 0;
04834 }
04835 #endif
04836
04837 static int load_module(void)
04838 {
04839 int res = 0;
04840
04841 for (; res < (sizeof(soft_key_template_default) / sizeof(soft_key_template_default[0])); res++) {
04842 soft_key_template_default[res].softKeyEvent = htolel(soft_key_template_default[res].softKeyEvent);
04843 }
04844
04845 res = reload_config();
04846 if (res == -1) {
04847 return AST_MODULE_LOAD_DECLINE;
04848 }
04849
04850
04851 if (ast_channel_register(&skinny_tech)) {
04852 ast_log(LOG_ERROR, "Unable to register channel class 'Skinny'\n");
04853 return -1;
04854 }
04855
04856 ast_rtp_proto_register(&skinny_rtp);
04857 ast_cli_register_multiple(cli_skinny, sizeof(cli_skinny) / sizeof(struct ast_cli_entry));
04858 sched = sched_context_create();
04859 if (!sched) {
04860 ast_log(LOG_WARNING, "Unable to create schedule context\n");
04861 }
04862 io = io_context_create();
04863 if (!io) {
04864 ast_log(LOG_WARNING, "Unable to create I/O context\n");
04865 }
04866
04867 restart_monitor();
04868
04869 return res;
04870 }
04871
04872 static int unload_module(void)
04873 {
04874 struct skinnysession *s, *slast;
04875 struct skinny_device *d;
04876 struct skinny_line *l;
04877 struct skinny_subchannel *sub;
04878
04879 ast_mutex_lock(&sessionlock);
04880
04881 s = sessions;
04882 while(s) {
04883 slast = s;
04884 s = s->next;
04885 for (d = slast->device; d; d = d->next) {
04886 for (l = d->lines; l; l = l->next) {
04887 ast_mutex_lock(&l->lock);
04888 for (sub = l->sub; sub; sub = sub->next) {
04889 ast_mutex_lock(&sub->lock);
04890 if (sub->owner) {
04891 sub->alreadygone = 1;
04892 ast_softhangup(sub->owner, AST_SOFTHANGUP_APPUNLOAD);
04893 }
04894 ast_mutex_unlock(&sub->lock);
04895 }
04896 ast_mutex_unlock(&l->lock);
04897 }
04898 }
04899 if (slast->fd > -1)
04900 close(slast->fd);
04901 ast_mutex_destroy(&slast->lock);
04902 free(slast);
04903 }
04904 sessions = NULL;
04905 ast_mutex_unlock(&sessionlock);
04906
04907 delete_devices();
04908
04909 ast_mutex_lock(&monlock);
04910 if ((monitor_thread != AST_PTHREADT_NULL) && (monitor_thread != AST_PTHREADT_STOP)) {
04911 pthread_cancel(monitor_thread);
04912 pthread_kill(monitor_thread, SIGURG);
04913 pthread_join(monitor_thread, NULL);
04914 }
04915 monitor_thread = AST_PTHREADT_STOP;
04916 ast_mutex_unlock(&monlock);
04917
04918 ast_mutex_lock(&netlock);
04919 if (accept_t && (accept_t != AST_PTHREADT_STOP)) {
04920 pthread_cancel(accept_t);
04921 pthread_kill(accept_t, SIGURG);
04922 pthread_join(accept_t, NULL);
04923 }
04924 accept_t = AST_PTHREADT_STOP;
04925 ast_mutex_unlock(&netlock);
04926
04927 ast_rtp_proto_unregister(&skinny_rtp);
04928 ast_channel_unregister(&skinny_tech);
04929 ast_cli_unregister_multiple(cli_skinny, sizeof(cli_skinny) / sizeof(struct ast_cli_entry));
04930
04931 close(skinnysock);
04932 if (sched)
04933 sched_context_destroy(sched);
04934
04935 return 0;
04936 }
04937
04938 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Skinny Client Control Protocol (Skinny)",
04939 .load = load_module,
04940 .unload = unload_module,
04941 );