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
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "asterisk.h"
00040
00041 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 366408 $")
00042
00043 #include <sys/stat.h>
00044 #include <signal.h>
00045
00046 #if defined(__CYGWIN__)
00047
00048
00049
00050
00051
00052
00053
00054
00055 #ifdef HAVE_PKTINFO
00056 #undef HAVE_PKTINFO
00057 #endif
00058 #endif
00059
00060 #include "asterisk/paths.h"
00061 #include "asterisk/network.h"
00062 #include "asterisk/channel.h"
00063 #include "asterisk/config.h"
00064 #include "asterisk/module.h"
00065 #include "asterisk/pbx.h"
00066 #include "asterisk/event.h"
00067 #include "asterisk/rtp_engine.h"
00068 #include "asterisk/netsock2.h"
00069 #include "asterisk/acl.h"
00070 #include "asterisk/callerid.h"
00071 #include "asterisk/cli.h"
00072 #include "asterisk/app.h"
00073 #include "asterisk/musiconhold.h"
00074 #include "asterisk/causes.h"
00075 #include "asterisk/indications.h"
00076 #include "asterisk/features.h"
00077 #include "asterisk/astobj2.h"
00078 #include "asterisk/astdb.h"
00079
00080
00081 #define DEFAULTCONTEXT "default"
00082 #define DEFAULTCALLERID "Unknown"
00083 #define DEFAULTCALLERNAME " "
00084 #define DEFAULTHEIGHT 3
00085 #define USTM_LOG_DIR "unistimHistory"
00086 #define USTM_LANG_DIR "unistimLang"
00087
00088
00089 #define MAX_BUF_SIZE 64
00090
00091 #define MAX_BUF_NUMBER 50
00092
00093 #define MAX_SCREEN_NUMBER 15
00094
00095 #define NB_MAX_RETRANSMIT 8
00096
00097 #define IDLE_WAIT 1000
00098
00099 #define RETRANSMIT_TIMER 2000
00100
00101 #define TIMER_MWI 5000
00102
00103 #define TIMER_DIAL 4000
00104
00105 #define DEFAULT_CODEC 0x00
00106 #define SIZE_PAGE 4096
00107 #define DEVICE_NAME_LEN 16
00108 #define AST_CONFIG_MAX_PATH 255
00109 #define MAX_ENTRY_LOG 30
00110
00111 #define SUB_REAL 0
00112 #define SUB_RING 1
00113 #define SUB_THREEWAY 2
00114 #define SUB_ONHOLD 3
00115
00116 struct ast_format_cap *global_cap;
00117
00118 enum autoprovision {
00119 AUTOPROVISIONING_NO = 0,
00120 AUTOPROVISIONING_YES,
00121 AUTOPROVISIONING_TN
00122 };
00123
00124 enum autoprov_extn {
00125
00126 EXTENSION_NONE = 0,
00127
00128 EXTENSION_ASK,
00129
00130 EXTENSION_LINE,
00131
00132 EXTENSION_TN
00133 };
00134 #define OUTPUT_HANDSET 0xC0
00135 #define OUTPUT_HEADPHONE 0xC1
00136 #define OUTPUT_SPEAKER 0xC2
00137
00138 #define VOLUME_LOW 0x01
00139 #define VOLUME_LOW_SPEAKER 0x03
00140 #define VOLUME_NORMAL 0x02
00141 #define VOLUME_INSANELY_LOUD 0x07
00142
00143 #define MUTE_OFF 0x00
00144 #define MUTE_ON 0xFF
00145 #define MUTE_ON_DISCRET 0xCE
00146
00147 #define SIZE_HEADER 6
00148 #define SIZE_MAC_ADDR 17
00149 #define TEXT_LENGTH_MAX 24
00150 #define TEXT_LINE0 0x00
00151 #define TEXT_LINE1 0x20
00152 #define TEXT_LINE2 0x40
00153 #define TEXT_NORMAL 0x05
00154 #define TEXT_INVERSE 0x25
00155 #define STATUS_LENGTH_MAX 28
00156
00157 #define FAV_ICON_NONE 0x00
00158 #define FAV_ICON_ONHOOK_BLACK 0x20
00159 #define FAV_ICON_ONHOOK_WHITE 0x21
00160 #define FAV_ICON_SPEAKER_ONHOOK_BLACK 0x22
00161 #define FAV_ICON_SPEAKER_ONHOOK_WHITE 0x23
00162 #define FAV_ICON_OFFHOOK_BLACK 0x24
00163 #define FAV_ICON_OFFHOOK_WHITE 0x25
00164 #define FAV_ICON_ONHOLD_BLACK 0x26
00165 #define FAV_ICON_ONHOLD_WHITE 0x27
00166 #define FAV_ICON_SPEAKER_OFFHOOK_BLACK 0x28
00167 #define FAV_ICON_SPEAKER_OFFHOOK_WHITE 0x29
00168 #define FAV_ICON_PHONE_BLACK 0x2A
00169 #define FAV_ICON_PHONE_WHITE 0x2B
00170 #define FAV_ICON_SPEAKER_ONHOLD_BLACK 0x2C
00171 #define FAV_ICON_SPEAKER_ONHOLD_WHITE 0x2D
00172 #define FAV_ICON_HEADPHONES 0x2E
00173 #define FAV_ICON_HEADPHONES_ONHOLD 0x2F
00174 #define FAV_ICON_HOME 0x30
00175 #define FAV_ICON_CITY 0x31
00176 #define FAV_ICON_SHARP 0x32
00177 #define FAV_ICON_PAGER 0x33
00178 #define FAV_ICON_CALL_CENTER 0x34
00179 #define FAV_ICON_FAX 0x35
00180 #define FAV_ICON_MAILBOX 0x36
00181 #define FAV_ICON_REFLECT 0x37
00182 #define FAV_ICON_COMPUTER 0x38
00183 #define FAV_ICON_FORWARD 0x39
00184 #define FAV_ICON_LOCKED 0x3A
00185 #define FAV_ICON_TRASH 0x3B
00186 #define FAV_ICON_INBOX 0x3C
00187 #define FAV_ICON_OUTBOX 0x3D
00188 #define FAV_ICON_MEETING 0x3E
00189 #define FAV_ICON_BOX 0x3F
00190
00191 #define FAV_BLINK_FAST 0x20
00192 #define FAV_BLINK_SLOW 0x40
00193
00194 #define FAV_MAX_LENGTH 0x0A
00195
00196 #define FAVNUM 6
00197 #define FAV_LINE_ICON FAV_ICON_ONHOOK_BLACK
00198
00199 static void dummy(char *unused, ...)
00200 {
00201 return;
00202 }
00203
00204
00205
00206 static struct ast_jb_conf default_jbconf =
00207 {
00208 .flags = 0,
00209 .max_size = 200,
00210 .resync_threshold = 1000,
00211 .impl = "fixed",
00212 .target_extra = 40,
00213 };
00214 static struct ast_jb_conf global_jbconf;
00215
00216
00217
00218
00219
00220 #define DEBUG_TIMER dummy
00221
00222 static int unistimdebug = 0;
00223 static int unistim_port;
00224 static enum autoprovision autoprovisioning = AUTOPROVISIONING_NO;
00225 static int unistim_keepalive;
00226 static int unistimsock = -1;
00227
00228 static struct {
00229 unsigned int tos;
00230 unsigned int tos_audio;
00231 unsigned int cos;
00232 unsigned int cos_audio;
00233 } qos = { 0, 0, 0, 0 };
00234
00235 static struct io_context *io;
00236 static struct ast_sched_context *sched;
00237 static struct sockaddr_in public_ip = { 0, };
00238 static unsigned char *buff;
00239 static int unistim_reloading = 0;
00240 AST_MUTEX_DEFINE_STATIC(unistim_reload_lock);
00241
00242
00243
00244 static pthread_t monitor_thread = AST_PTHREADT_NULL;
00245
00246
00247
00248 AST_MUTEX_DEFINE_STATIC(monlock);
00249
00250 AST_MUTEX_DEFINE_STATIC(sessionlock);
00251
00252 AST_MUTEX_DEFINE_STATIC(devicelock);
00253
00254 enum phone_state {
00255 STATE_INIT,
00256 STATE_AUTHDENY,
00257 STATE_MAINPAGE,
00258 STATE_EXTENSION,
00259 STATE_DIALPAGE,
00260 STATE_RINGING,
00261 STATE_CALL,
00262 STATE_SELECTOPTION,
00263 STATE_SELECTCODEC,
00264 STATE_SELECTLANGUAGE,
00265 STATE_CLEANING,
00266 STATE_HISTORY
00267 };
00268
00269 enum handset_state {
00270 STATE_ONHOOK,
00271 STATE_OFFHOOK,
00272 };
00273
00274 enum phone_key {
00275 KEY_0 = 0x40,
00276 KEY_1 = 0x41,
00277 KEY_2 = 0x42,
00278 KEY_3 = 0x43,
00279 KEY_4 = 0x44,
00280 KEY_5 = 0x45,
00281 KEY_6 = 0x46,
00282 KEY_7 = 0x47,
00283 KEY_8 = 0x48,
00284 KEY_9 = 0x49,
00285 KEY_STAR = 0x4a,
00286 KEY_SHARP = 0x4b,
00287 KEY_UP = 0x4c,
00288 KEY_DOWN = 0x4d,
00289 KEY_RIGHT = 0x4e,
00290 KEY_LEFT = 0x4f,
00291 KEY_QUIT = 0x50,
00292 KEY_COPY = 0x51,
00293 KEY_FUNC1 = 0x54,
00294 KEY_FUNC2 = 0x55,
00295 KEY_FUNC3 = 0x56,
00296 KEY_FUNC4 = 0x57,
00297 KEY_ONHOLD = 0x5b,
00298 KEY_HANGUP = 0x5c,
00299 KEY_MUTE = 0x5d,
00300 KEY_HEADPHN = 0x5e,
00301 KEY_LOUDSPK = 0x5f,
00302 KEY_FAV0 = 0x60,
00303 KEY_FAV1 = 0x61,
00304 KEY_FAV2 = 0x62,
00305 KEY_FAV3 = 0x63,
00306 KEY_FAV4 = 0x64,
00307 KEY_FAV5 = 0x65,
00308 KEY_COMPUTR = 0x7b,
00309 KEY_CONF = 0x7c,
00310 KEY_SNDHIST = 0x7d,
00311 KEY_RCVHIST = 0x7e,
00312 KEY_INDEX = 0x7f
00313 };
00314
00315 enum charset {
00316 LANG_DEFAULT,
00317 ISO_8859_1,
00318 ISO_8859_2,
00319 ISO_8859_4,
00320 ISO_8859_5,
00321 ISO_2022_JP,
00322 };
00323
00324 static const int dtmf_row[] = { 697, 770, 852, 941 };
00325 static const float dtmf_col[] = { 1209, 1336, 1477, 1633 };
00326
00327 struct wsabuf {
00328 u_long len;
00329 unsigned char *buf;
00330 };
00331
00332 struct unistim_subchannel {
00333 ast_mutex_t lock;
00334 unsigned int subtype;
00335 struct ast_channel *owner;
00336 struct unistim_line *parent;
00337 struct ast_rtp_instance *rtp;
00338 int softkey;
00339 pthread_t ss_thread;
00340 int alreadygone;
00341 char ringvolume;
00342 char ringstyle;
00343 int moh;
00344 AST_LIST_ENTRY(unistim_subchannel) list;
00345 };
00346
00347
00348
00349
00350 struct unistim_line {
00351 ast_mutex_t lock;
00352 char name[80];
00353 char fullname[80];
00354 char exten[AST_MAX_EXTENSION];
00355 char cid_num[AST_MAX_EXTENSION];
00356 char mailbox[AST_MAX_EXTENSION];
00357 int lastmsgssent;
00358 time_t nextmsgcheck;
00359 char musicclass[MAX_MUSICCLASS];
00360 ast_group_t callgroup;
00361 ast_group_t pickupgroup;
00362 char accountcode[AST_MAX_ACCOUNT_CODE];
00363 int amaflags;
00364 struct ast_format_cap *cap;
00365 char parkinglot[AST_MAX_CONTEXT];
00366 struct unistim_line *next;
00367 struct unistim_device *parent;
00368 AST_LIST_ENTRY(unistim_line) list;
00369 };
00370
00371
00372
00373
00374 static struct unistim_device {
00375 ast_mutex_t lock;
00376 int receiver_state;
00377 int size_phone_number;
00378 char context[AST_MAX_EXTENSION];
00379 char phone_number[AST_MAX_EXTENSION];
00380 char redial_number[AST_MAX_EXTENSION];
00381 char id[18];
00382 char name[DEVICE_NAME_LEN];
00383 char softkeylabel[FAVNUM][11];
00384 char softkeynumber[FAVNUM][AST_MAX_EXTENSION];
00385 char softkeyicon[FAVNUM];
00386 char softkeydevice[FAVNUM][16];
00387 struct unistim_subchannel *ssub[FAVNUM];
00388 struct unistim_line *sline[FAVNUM];
00389 struct unistim_device *sp[FAVNUM];
00390 char language[MAX_LANGUAGE];
00391 int height;
00392 char maintext0[25];
00393 char maintext1[25];
00394 char maintext2[25];
00395 char titledefault[13];
00396 char datetimeformat;
00397 char contrast;
00398 char country[3];
00399 struct ast_tone_zone *tz;
00400 char ringvolume;
00401 char ringstyle;
00402 char cwvolume;
00403 char cwstyle;
00404 time_t nextdial;
00405 int rtp_port;
00406 int rtp_method;
00407 int status_method;
00408 char codec_number;
00409 int missed_call;
00410 int callhistory;
00411 int sharp_dial;
00412 char lst_cid[TEXT_LENGTH_MAX];
00413 char lst_cnm[TEXT_LENGTH_MAX];
00414 char call_forward[AST_MAX_EXTENSION];
00415 int output;
00416 int previous_output;
00417 int volume;
00418 int selected;
00419 int mute;
00420 int nat;
00421 enum autoprov_extn extension;
00422 char extension_number[11];
00423 char to_delete;
00424 struct ast_silence_generator *silence_generator;
00425 AST_LIST_HEAD(,unistim_subchannel) subs;
00426 AST_LIST_HEAD(,unistim_line) lines;
00427 struct ast_ha *ha;
00428 struct unistimsession *session;
00429 struct unistim_device *next;
00430 } *devices = NULL;
00431
00432 static struct unistimsession {
00433 ast_mutex_t lock;
00434 struct sockaddr_in sin;
00435 struct sockaddr_in sout;
00436 int timeout;
00437 unsigned short seq_phone;
00438 unsigned short seq_server;
00439 unsigned short last_seq_ack;
00440 unsigned long tick_next_ping;
00441 int last_buf_available;
00442 int nb_retransmit;
00443 int state;
00444 int size_buff_entry;
00445 char buff_entry[16];
00446 char macaddr[18];
00447 struct wsabuf wsabufsend[MAX_BUF_NUMBER];
00448 unsigned char buf[MAX_BUF_NUMBER][MAX_BUF_SIZE];
00449 struct unistim_device *device;
00450 struct unistimsession *next;
00451 } *sessions = NULL;
00452
00453
00454 struct unistim_menu_item {
00455 char *label;
00456 int state;
00457 void (*handle_option)(struct unistimsession *);
00458 };
00459
00460
00461 struct unistim_languages {
00462 char *label;
00463 char *lang_short;
00464 int encoding;
00465 struct ao2_container *trans;
00466 };
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479 static const unsigned char packet_rcv_discovery[] =
00480 { 0xff, 0xff, 0xff, 0xff, 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 };
00481 static const unsigned char packet_send_discovery_ack[] =
00482 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
00483
00484 static const unsigned char packet_recv_firm_version[] =
00485 { 0x00, 0x00, 0x00, 0x13, 0x9a, 0x0a, 0x02 };
00486 static const unsigned char packet_recv_it_type[] =
00487 { 0x00, 0x00, 0x00, 0x13, 0x9a, 0x04, 0x03 };
00488 static const unsigned char packet_recv_pressed_key[] =
00489 { 0x00, 0x00, 0x00, 0x13, 0x99, 0x04, 0x00 };
00490 static const unsigned char packet_recv_pick_up[] =
00491 { 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x04 };
00492 static const unsigned char packet_recv_hangup[] =
00493 { 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x03 };
00494 static const unsigned char packet_recv_r2[] = { 0x00, 0x00, 0x00, 0x13, 0x96, 0x03, 0x03 };
00495
00496
00497 static const unsigned char packet_recv_resume_connection_with_server[] =
00498 { 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 };
00499 static const unsigned char packet_recv_mac_addr[] =
00500 { 0xff, 0xff, 0xff, 0xff, 0x9a, 0x0d, 0x07 };
00501
00502 static const unsigned char packet_send_date_time3[] =
00503 { 0x11, 0x09, 0x02, 0x02, 0x05, 0x06, 0x07,
00504 0x08, 0x32
00505 };
00506 static const unsigned char packet_send_date_time[] =
00507 { 0x11, 0x09, 0x02, 0x0a, 0x05, 0x06, 0x07,
00508 0x08, 0x32, 0x17, 0x04, 0x24, 0x07, 0x19,
00509 0x04, 0x07, 0x00, 0x19, 0x05, 0x09, 0x3e, 0x0f, 0x16, 0x05, 0x00, 0x80, 0x00, 0x1e,
00510 0x05, 0x12, 0x00, 0x78
00511 };
00512
00513 static const unsigned char packet_send_no_ring[] =
00514 { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00 };
00515 static const unsigned char packet_send_s4[] =
00516 { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00, 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff,
00517 0x16, 0x05, 0x1c, 0x00, 0x00, 0x17, 0x05,
00518 0x0b, 0x00, 0x00, 0x19, 0x04, 0x00, 0x00, 0x19, 0x04, 0x00, 0x08, 0x19, 0x04, 0x00,
00519 0x10, 0x19, 0x04, 0x00, 0x18, 0x16, 0x05,
00520 0x31, 0x00, 0x00, 0x16, 0x05, 0x04, 0x00, 0x00
00521 };
00522 static const unsigned char packet_send_call[] =
00523 { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00, 0x16, 0x06, 0x32, 0xdf,
00524 0x00, 0xff, 0x16, 0x05, 0x1c, 0x00, 0x00, 0x16, 0x0a, 0x38, 0x00, 0x12, 0xca, 0x03,
00525 0xc0, 0xc3, 0xc5, 0x16, 0x16, 0x30, 0x00,
00526 0x00, 0x12, 0x12, 0x01, 0x5c, 0x00,
00527 0x0f, 0xa0, 0x9c, 0x41,
00528 0x0f, 0xa0, 0x9c, 0x41, 0x0a, 0x01,
00529 0x16, 0x66
00530 };
00531 static const unsigned char packet_send_stream_based_tone_off[] =
00532 { 0x16, 0x05, 0x1c, 0x00, 0x00 };
00533
00534
00535
00536
00537 static const unsigned char packet_send_stream_based_tone_on[] =
00538 { 0x16, 0x06, 0x1b, 0x00, 0x00, 0x05 };
00539 static const unsigned char packet_send_stream_based_tone_single_freq[] =
00540 { 0x16, 0x06, 0x1d, 0x00, 0x01, 0xb8 };
00541 static const unsigned char packet_send_stream_based_tone_dial_freq[] =
00542 { 0x16, 0x08, 0x1d, 0x00, 0x01, 0xb8, 0x01, 0x5e };
00543 static const unsigned char packet_send_select_output[] =
00544 { 0x16, 0x06, 0x32, 0xc0, 0x01, 0x00 };
00545 static const unsigned char packet_send_ring[] =
00546 { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x1c, 0x00, 0x00, 0x16,
00547 0x04, 0x1a, 0x01, 0x16, 0x05, 0x12, 0x13 , 0x18, 0x16, 0x04, 0x18,
00548 0x20, 0x16, 0x04, 0x10, 0x00
00549 };
00550 static const unsigned char packet_send_end_call[] =
00551 { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x31, 0x00, 0x00, 0x19, 0x04, 0x00,
00552 0x10, 0x19, 0x04, 0x00, 0x18, 0x16, 0x05,
00553 0x04, 0x00, 0x00, 0x16, 0x04, 0x37, 0x10
00554 };
00555 static const unsigned char packet_send_s9[] =
00556 { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x19, 0x04, 0x00, 0x10, 0x16, 0x05, 0x1c, 0x00,
00557 0x00 };
00558 static const unsigned char packet_send_rtp_packet_size[] =
00559 { 0x16, 0x08, 0x38, 0x00, 0x00, 0xe0, 0x00, 0xa0 };
00560 static const unsigned char packet_send_jitter_buffer_conf[] =
00561 { 0x16, 0x0e, 0x3a, 0x00, 0x02, 0x04, 0x00, 0x00,
00562 0x3e, 0x80,
00563 0x00, 0x00, 0x3e, 0x80
00564 };
00565
00566
00567
00568
00569 static const unsigned char packet_send_open_audio_stream_rx[] =
00570 { 0x16, 0x1a, 0x30, 0x00, 0xff, 0x00, 0x00, 0x01, 0x00, 0xb8, 0xb8, 0x0e,
00571 0x0e, 0x01, 0x14, 0x50, 0x00,
00572 0x00, 0x14, 0x50, 0x00, 0x00, 0x0a, 0x93, 0x69, 0x05
00573 };
00574 static const unsigned char packet_send_open_audio_stream_tx[] =
00575 { 0x16, 0x1a, 0x30, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb8, 0xb8, 0x0e,
00576 0x0e, 0x01, 0x14, 0x50,
00577 0x00, 0x00, 0x14, 0x50, 0x00, 0x00, 0x0a, 0x93, 0x69, 0x05
00578 };
00579
00580 static const unsigned char packet_send_open_audio_stream_rx3[] =
00581 { 0x16, 0x1a, 0x30, 0x00, 0xff, 0x00, 0x00, 0x02, 0x01, 0xb8, 0xb8, 0x06,
00582 0x06, 0x81, 0x14, 0x50,
00583 0x14,
00584 0x51, 0x14, 0x50, 0x00, 0x00, 0x0a, 0x93,
00585 0x69, 0x05
00586 };
00587 static const unsigned char packet_send_open_audio_stream_tx3[] =
00588 { 0x16, 0x1a, 0x30, 0xff, 0x00, 0x00, 0x00, 0x02, 0x01, 0xb8, 0xb8, 0x06,
00589 0x06, 0x81, 0x14, 0x50,
00590 0x00, 0x00, 0x14, 0x50, 0x00, 0x00,
00591 0x0a, 0x93, 0x69, 0x05
00592 };
00593
00594 static const unsigned char packet_send_arrow[] = { 0x17, 0x04, 0x04, 0x00 };
00595 static const unsigned char packet_send_blink_cursor[] = { 0x17, 0x04, 0x10, 0x86 };
00596 static const unsigned char packet_send_date_time2[] = { 0x17, 0x04, 0x17, 0x3d, 0x11, 0x09, 0x02, 0x0a, 0x05,
00597 0x06, 0x07, 0x08, 0x32
00598 };
00599 static const unsigned char packet_send_Contrast[] =
00600 { 0x17, 0x04, 0x24, 0x08 };
00601 static const unsigned char packet_send_start_timer[] =
00602 { 0x17, 0x05, 0x0b, 0x05, 0x00, 0x17, 0x08, 0x16,
00603 0x44, 0x75, 0x72, 0xe9, 0x65 };
00604 static const unsigned char packet_send_stop_timer[] = { 0x17, 0x05, 0x0b, 0x02, 0x00 };
00605 static const unsigned char packet_send_icon[] = { 0x17, 0x05, 0x14, 0x00, 0x25 };
00606 static const unsigned char packet_send_S7[] = { 0x17, 0x06, 0x0f, 0x30, 0x07, 0x07 };
00607 static const unsigned char packet_send_set_pos_cursor[] =
00608 { 0x17, 0x06, 0x10, 0x81, 0x04, 0x20 };
00609
00610
00611
00612 static const unsigned char packet_send_favorite[] =
00613 { 0x17, 0x0f, 0x19, 0x10, 0x01, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
00614 0x20, 0x20, 0x20, 0x20, 0x19,
00615 0x05, 0x0f, 0x01, 0x00
00616 };
00617 static const unsigned char packet_send_title[] =
00618 { 0x17, 0x10, 0x19, 0x02, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
00619 0x20, 0x20, 0x20, 0x20 };
00620 static const unsigned char packet_send_text[] =
00621 { 0x17, 0x1e, 0x1b, 0x04, 0x00, 0x25, 0x20, 0x20,
00622 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
00623 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
00624 0x17, 0x04, 0x10, 0x87
00625 };
00626 static const unsigned char packet_send_status[] =
00627 { 0x17, 0x20, 0x19, 0x08, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
00628 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
00629 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
00630 };
00631 static const unsigned char packet_send_status2[] =
00632 { 0x17, 0x0b, 0x19, 0x00, 0x20, 0x20, 0x20, 0x20,
00633 0x20, 0x20, 0x20 };
00634
00635
00636
00637 static const unsigned char packet_send_charset_iso_8859_1[] =
00638 { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x41, 0x1b, 0x00 };
00639
00640 static const unsigned char packet_send_charset_iso_8859_2[] =
00641 { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x42, 0x1b, 0x00 };
00642
00643 static const unsigned char packet_send_charset_iso_8859_4[] =
00644 { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x44, 0x1b, 0x00 };
00645
00646 static const unsigned char packet_send_charset_iso_8859_5[] =
00647 { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x4c, 0x1b, 0x00 };
00648
00649 static const unsigned char packet_send_charset_iso_2022_jp[] =
00650 { 0x17, 0x08, 0x21, 0x1b, 0x29, 0x49, 0x1b, 0x7e };
00651
00652 static const unsigned char packet_send_led_update[] = { 0x19, 0x04, 0x00, 0x00 };
00653
00654 static const unsigned char packet_send_query_basic_manager_04[] = { 0x1a, 0x04, 0x01, 0x04 };
00655 static const unsigned char packet_send_query_mac_address[] = { 0x1a, 0x04, 0x01, 0x08 };
00656 static const unsigned char packet_send_query_basic_manager_10[] = { 0x1a, 0x04, 0x01, 0x10 };
00657 static const unsigned char packet_send_S1[] = { 0x1a, 0x07, 0x07, 0x00, 0x00, 0x00, 0x13 };
00658
00659 static unsigned char packet_send_ping[] =
00660 { 0x1e, 0x05, 0x12, 0x00, 0x78 };
00661
00662 #define BUFFSEND unsigned char buffsend[64] = { 0x00, 0x00, 0xaa, 0xbb, 0x02, 0x01 }
00663
00664 static const char tdesc[] = "UNISTIM Channel Driver";
00665 static const char channel_type[] = "USTM";
00666
00667
00668 static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const char *linkedid);
00669 static int load_module(void);
00670 static int reload(void);
00671 static int unload_module(void);
00672 static int reload_config(void);
00673 static void show_main_page(struct unistimsession *pte);
00674 static struct ast_channel *unistim_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor,
00675 const char *dest, int *cause);
00676 static int unistim_call(struct ast_channel *ast, const char *dest, int timeout);
00677 static int unistim_hangup(struct ast_channel *ast);
00678 static int unistim_answer(struct ast_channel *ast);
00679 static struct ast_frame *unistim_read(struct ast_channel *ast);
00680 static int unistim_write(struct ast_channel *ast, struct ast_frame *frame);
00681 static int unistim_indicate(struct ast_channel *ast, int ind, const void *data,
00682 size_t datalen);
00683 static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00684 static int unistim_senddigit_begin(struct ast_channel *ast, char digit);
00685 static int unistim_senddigit_end(struct ast_channel *ast, char digit,
00686 unsigned int duration);
00687 static int unistim_sendtext(struct ast_channel *ast, const char *text);
00688
00689 static int write_entry_history(struct unistimsession *pte, FILE * f, char c,
00690 char *line1);
00691 static void change_callerid(struct unistimsession *pte, int type, char *callerid);
00692
00693 static struct ast_channel_tech unistim_tech = {
00694 .type = channel_type,
00695 .description = tdesc,
00696 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
00697 .requester = unistim_request,
00698 .call = unistim_call,
00699 .hangup = unistim_hangup,
00700 .answer = unistim_answer,
00701 .read = unistim_read,
00702 .write = unistim_write,
00703 .indicate = unistim_indicate,
00704 .fixup = unistim_fixup,
00705 .send_digit_begin = unistim_senddigit_begin,
00706 .send_digit_end = unistim_senddigit_end,
00707 .send_text = unistim_sendtext,
00708 .bridge = ast_rtp_instance_bridge,
00709 };
00710
00711 static void send_start_rtp(struct unistim_subchannel *);
00712
00713 static void send_callerid_screen(struct unistimsession *, struct unistim_subchannel *);
00714 static void key_favorite(struct unistimsession *, char);
00715
00716 static void handle_select_codec(struct unistimsession *);
00717 static void handle_select_language(struct unistimsession *);
00718 static int find_language(const char*);
00719
00720 static int unistim_free_sub(struct unistim_subchannel *);
00721
00722 static struct unistim_menu_item options_menu[] =
00723 {
00724 {"Change codec", STATE_SELECTCODEC, handle_select_codec},
00725 {"Language", STATE_SELECTLANGUAGE, handle_select_language},
00726 {NULL, 0, NULL}
00727 };
00728
00729 static struct unistim_languages options_languages[] =
00730 {
00731 {"English", "en", ISO_8859_1, NULL},
00732 {"Russian", "ru", ISO_8859_5, NULL},
00733 {NULL, NULL, 0, NULL}
00734 };
00735
00736 static char ustm_strcopy[1024];
00737
00738 struct ustm_lang_entry {
00739 const char *str_orig;
00740 const char *str_trans;
00741 };
00742
00743 static int lang_hash_fn(const void *obj, const int flags)
00744 {
00745 const struct ustm_lang_entry *entry = obj;
00746 return ast_str_hash(entry->str_orig);
00747 }
00748
00749 static int lang_cmp_fn(void *obj, void *arg, int flags)
00750 {
00751 struct ustm_lang_entry *entry1 = obj;
00752 struct ustm_lang_entry *entry2 = arg;
00753
00754 return (!strcmp(entry1->str_orig, entry2->str_orig)) ? (CMP_MATCH | CMP_STOP) : 0;
00755 }
00756
00757 static const char *ustmtext(const char *str, struct unistimsession *pte)
00758 {
00759 struct ustm_lang_entry *lang_entry;
00760 struct ustm_lang_entry le_search;
00761 struct unistim_languages *lang = NULL;
00762 int size;
00763
00764 if (pte->device) {
00765 lang = &options_languages[find_language(pte->device->language)];
00766 }
00767 if (!lang) {
00768 return str;
00769 }
00770
00771 if (!lang->trans) {
00772 char tmp[1024], *p, *p_orig = NULL, *p_trans = NULL;
00773 FILE *f;
00774
00775 if (!(lang->trans = ao2_container_alloc(8, lang_hash_fn, lang_cmp_fn))) {
00776 ast_log(LOG_ERROR, "Unable to allocate container for translation!\n");
00777 return str;
00778 }
00779 snprintf(tmp, sizeof(tmp), "%s/%s/%s.po", ast_config_AST_VAR_DIR,
00780 USTM_LANG_DIR, lang->lang_short);
00781 f = fopen(tmp, "r");
00782 if (!f) {
00783 ast_log(LOG_ERROR, "There is no translation file for '%s'\n", pte->device->language);
00784 return str;
00785 }
00786 while (fgets(tmp, sizeof(tmp), f)) {
00787 if (!(p = strchr(tmp, '\n'))) {
00788 ast_log(LOG_ERROR, "Too long line found in language file - truncated!\n");
00789 continue;
00790 }
00791 *p = '\0';
00792 if (!(p = strchr(tmp, '"'))) {
00793 continue;
00794 }
00795 if (tmp == strstr(tmp, "msgid")) {
00796 p_orig = ast_strdup(p + 1);
00797 p = strchr(p_orig, '"');
00798 } else if (tmp == strstr(tmp, "msgstr")) {
00799 p_trans = ast_strdup(p + 1);
00800 p = strchr(p_trans, '"');
00801 } else {
00802 continue;
00803 }
00804 *p = '\0';
00805 if (!p_trans || !p_orig) {
00806 continue;
00807 }
00808 if (ast_strlen_zero(p_trans)) {
00809 ast_free(p_trans);
00810 ast_free(p_orig);
00811 p_trans = NULL;
00812 p_orig = NULL;
00813 continue;
00814 }
00815 if (!(lang_entry = ao2_alloc(sizeof(*lang_entry), NULL))) {
00816 fclose(f);
00817 return str;
00818 }
00819
00820 lang_entry->str_trans = p_trans;
00821 lang_entry->str_orig = p_orig;
00822 ao2_link(lang->trans, lang_entry);
00823 p_trans = NULL;
00824 p_orig = NULL;
00825 }
00826
00827 fclose(f);
00828 }
00829
00830 le_search.str_orig = str;
00831 if ((lang_entry = ao2_find(lang->trans, &le_search, OBJ_POINTER))) {
00832 size = strlen(lang_entry->str_trans)+1;
00833 if (size > 1024) {
00834 size = 1024;
00835 }
00836 memcpy(ustm_strcopy, lang_entry->str_trans, size);
00837 ao2_ref(lang_entry, -1);
00838 return ustm_strcopy;
00839 }
00840
00841 return str;
00842 }
00843
00844 static void display_last_error(const char *sz_msg)
00845 {
00846
00847 ast_log(LOG_WARNING, "%s : (%u) %s\n", sz_msg, errno, strerror(errno));
00848 }
00849
00850 static unsigned int get_tick_count(void)
00851 {
00852 struct timeval now = ast_tvnow();
00853
00854 return (now.tv_sec * 1000) + (now.tv_usec / 1000);
00855 }
00856
00857
00858 static void send_raw_client(int size, const unsigned char *data, struct sockaddr_in *addr_to,
00859 const struct sockaddr_in *addr_ourip)
00860 {
00861 #ifdef HAVE_PKTINFO
00862 struct iovec msg_iov;
00863 struct msghdr msg;
00864 char buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
00865 struct cmsghdr *ip_msg = (struct cmsghdr *) buffer;
00866 struct in_pktinfo *pki = (struct in_pktinfo *) CMSG_DATA(ip_msg);
00867
00868
00869
00870
00871
00872
00873 msg_iov.iov_base = (char *) data;
00874 msg_iov.iov_len = size;
00875
00876 msg.msg_name = addr_to;
00877 msg.msg_namelen = sizeof(struct sockaddr_in);
00878 msg.msg_iov = &msg_iov;
00879 msg.msg_iovlen = 1;
00880 msg.msg_control = ip_msg;
00881 msg.msg_controllen = sizeof(buffer);
00882 msg.msg_flags = 0;
00883
00884 ip_msg->cmsg_len = CMSG_LEN(sizeof(*pki));
00885 ip_msg->cmsg_level = IPPROTO_IP;
00886 ip_msg->cmsg_type = IP_PKTINFO;
00887 pki->ipi_ifindex = 0;
00888 pki->ipi_spec_dst.s_addr = addr_ourip->sin_addr.s_addr;
00889
00890
00891 #ifdef DUMP_PACKET
00892 if (unistimdebug) {
00893 int tmp;
00894 ast_verb(0, "\n**> From %s sending %d bytes to %s ***\n",
00895 ast_inet_ntoa(addr_ourip->sin_addr), (int) size,
00896 ast_inet_ntoa(addr_to->sin_addr));
00897 for (tmp = 0; tmp < size; tmp++)
00898 ast_verb(0, "%.2x ", (unsigned char) data[tmp]);
00899 ast_verb(0, "\n******************************************\n");
00900
00901 }
00902 #endif
00903
00904 if (sendmsg(unistimsock, &msg, 0) == -1) {
00905 display_last_error("Error sending datas");
00906 }
00907 #else
00908 if (sendto(unistimsock, data, size, 0, (struct sockaddr *) addr_to, sizeof(*addr_to))
00909 == -1)
00910 display_last_error("Error sending datas");
00911 #endif
00912 }
00913
00914 static void send_client(int size, const unsigned char *data, struct unistimsession *pte)
00915 {
00916 unsigned int tick;
00917 int buf_pos;
00918 unsigned short seq = ntohs(++pte->seq_server);
00919
00920 ast_mutex_lock(&pte->lock);
00921 buf_pos = pte->last_buf_available;
00922
00923 if (buf_pos >= MAX_BUF_NUMBER) {
00924 ast_log(LOG_WARNING, "Error : send queue overflow\n");
00925 ast_mutex_unlock(&pte->lock);
00926 return;
00927 }
00928 memcpy((void *)data + sizeof(unsigned short), (void *)&seq, sizeof(unsigned short));
00929 pte->wsabufsend[buf_pos].len = size;
00930 memcpy(pte->wsabufsend[buf_pos].buf, data, size);
00931
00932 tick = get_tick_count();
00933 pte->timeout = tick + RETRANSMIT_TIMER;
00934
00935
00936 if (unistimdebug) {
00937 ast_verb(6, "Sending datas with seq #0x%.4x Using slot #%d :\n", pte->seq_server, buf_pos);
00938 }
00939
00940 send_raw_client(pte->wsabufsend[buf_pos].len, pte->wsabufsend[buf_pos].buf, &(pte->sin),
00941 &(pte->sout));
00942 pte->last_buf_available++;
00943 ast_mutex_unlock(&pte->lock);
00944 }
00945
00946 static void send_ping(struct unistimsession *pte)
00947 {
00948 BUFFSEND;
00949 if (unistimdebug) {
00950 ast_verb(6, "Sending ping\n");
00951 }
00952 pte->tick_next_ping = get_tick_count() + unistim_keepalive;
00953 memcpy(buffsend + SIZE_HEADER, packet_send_ping, sizeof(packet_send_ping));
00954 send_client(SIZE_HEADER + sizeof(packet_send_ping), buffsend, pte);
00955 }
00956
00957 static int get_to_address(int fd, struct sockaddr_in *toAddr)
00958 {
00959 #ifdef HAVE_PKTINFO
00960 int err;
00961 struct msghdr msg;
00962 struct {
00963 struct cmsghdr cm;
00964 int len;
00965 struct in_addr address;
00966 } ip_msg;
00967
00968
00969
00970 memset(&msg, 0, sizeof(msg));
00971 memset(&ip_msg, 0, sizeof(ip_msg));
00972
00973
00974 msg.msg_control = &ip_msg;
00975 msg.msg_controllen = sizeof(ip_msg);
00976
00977 err = recvmsg(fd, &msg, MSG_PEEK);
00978 if (err == -1) {
00979 ast_log(LOG_WARNING, "recvmsg returned an error: %s\n", strerror(errno));
00980 }
00981 memcpy(&toAddr->sin_addr, &ip_msg.address, sizeof(struct in_addr));
00982 return err;
00983 #else
00984 memcpy(&toAddr, &public_ip, sizeof(&toAddr));
00985 return 0;
00986 #endif
00987 }
00988
00989
00990
00991 static struct unistimsession *create_client(const struct sockaddr_in *addr_from)
00992 {
00993 int tmp;
00994 struct unistimsession *s;
00995
00996 if (!(s = ast_calloc(1, sizeof(*s))))
00997 return NULL;
00998
00999 memcpy(&s->sin, addr_from, sizeof(struct sockaddr_in));
01000 get_to_address(unistimsock, &s->sout);
01001 s->sout.sin_family = AF_INET;
01002 if (unistimdebug) {
01003 ast_verb(0, "Creating a new entry for the phone from %s received via server ip %s\n",
01004 ast_inet_ntoa(addr_from->sin_addr), ast_inet_ntoa(s->sout.sin_addr));
01005 }
01006 ast_mutex_init(&s->lock);
01007 ast_mutex_lock(&sessionlock);
01008 s->next = sessions;
01009 sessions = s;
01010
01011 s->timeout = get_tick_count() + RETRANSMIT_TIMER;
01012 s->state = STATE_INIT;
01013 s->tick_next_ping = get_tick_count() + unistim_keepalive;
01014
01015 for (tmp = 0; tmp < MAX_BUF_NUMBER; tmp++) {
01016 s->wsabufsend[tmp].buf = s->buf[tmp];
01017 }
01018 ast_mutex_unlock(&sessionlock);
01019 return s;
01020 }
01021
01022 static void send_end_call(struct unistimsession *pte)
01023 {
01024 BUFFSEND;
01025 if (unistimdebug) {
01026 ast_verb(0, "Sending end call\n");
01027 }
01028 memcpy(buffsend + SIZE_HEADER, packet_send_end_call, sizeof(packet_send_end_call));
01029 send_client(SIZE_HEADER + sizeof(packet_send_end_call), buffsend, pte);
01030 }
01031
01032 static void set_ping_timer(struct unistimsession *pte)
01033 {
01034 unsigned int tick = 0;
01035
01036 pte->timeout = pte->tick_next_ping;
01037 DEBUG_TIMER("tick = %u next ping at %u tick\n", tick, pte->timeout);
01038 return;
01039 }
01040
01041
01042
01043 static void check_send_queue(struct unistimsession *pte)
01044 {
01045
01046 if (pte->last_buf_available == 1) {
01047 if (unistimdebug) {
01048 ast_verb(6, "Our single packet was ACKed.\n");
01049 }
01050 pte->last_buf_available--;
01051 set_ping_timer(pte);
01052 return;
01053 }
01054
01055 else if (pte->last_seq_ack + 1 == pte->seq_server + 1) {
01056 if (unistimdebug) {
01057 ast_verb(6, "Our send queue is completely ACKed.\n");
01058 }
01059 pte->last_buf_available = 0;
01060 set_ping_timer(pte);
01061 return;
01062 }
01063 if (unistimdebug) {
01064 ast_verb(6, "We still have packets in our send queue\n");
01065 }
01066 return;
01067 }
01068
01069 static void send_start_timer(struct unistimsession *pte)
01070 {
01071 BUFFSEND;
01072 if (unistimdebug) {
01073 ast_verb(0, "Sending start timer\n");
01074 }
01075 memcpy(buffsend + SIZE_HEADER, packet_send_start_timer, sizeof(packet_send_start_timer));
01076 send_client(SIZE_HEADER + sizeof(packet_send_start_timer), buffsend, pte);
01077 }
01078
01079 static void send_stop_timer(struct unistimsession *pte)
01080 {
01081 BUFFSEND;
01082 if (unistimdebug) {
01083 ast_verb(0, "Sending stop timer\n");
01084 }
01085 memcpy(buffsend + SIZE_HEADER, packet_send_stop_timer, sizeof(packet_send_stop_timer));
01086 send_client(SIZE_HEADER + sizeof(packet_send_stop_timer), buffsend, pte);
01087 }
01088
01089 static void send_icon(unsigned char pos, unsigned char status, struct unistimsession *pte)
01090 {
01091 BUFFSEND;
01092 if (unistimdebug) {
01093 ast_verb(0, "Sending icon pos %d with status 0x%.2x\n", pos, status);
01094 }
01095 memcpy(buffsend + SIZE_HEADER, packet_send_icon, sizeof(packet_send_icon));
01096 buffsend[9] = pos;
01097 buffsend[10] = status;
01098 send_client(SIZE_HEADER + sizeof(packet_send_icon), buffsend, pte);
01099 }
01100
01101 static void send_tone(struct unistimsession *pte, uint16_t tone1, uint16_t tone2)
01102 {
01103 BUFFSEND;
01104 if (!tone1) {
01105 if (unistimdebug) {
01106 ast_verb(0, "Sending Stream Based Tone Off\n");
01107 }
01108 memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_off,
01109 sizeof(packet_send_stream_based_tone_off));
01110 send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_off), buffsend, pte);
01111 return;
01112 }
01113
01114
01115
01116
01117
01118 if (unistimdebug) {
01119 ast_verb(0, "Sending Stream Based Tone Frequency Component List Download %d %d\n", tone1, tone2);
01120 }
01121 tone1 *= 8;
01122 if (!tone2) {
01123 memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_single_freq,
01124 sizeof(packet_send_stream_based_tone_single_freq));
01125 buffsend[10] = (tone1 & 0xff00) >> 8;
01126 buffsend[11] = (tone1 & 0x00ff);
01127 send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_single_freq), buffsend,
01128 pte);
01129 } else {
01130 tone2 *= 8;
01131 memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_dial_freq,
01132 sizeof(packet_send_stream_based_tone_dial_freq));
01133 buffsend[10] = (tone1 & 0xff00) >> 8;
01134 buffsend[11] = (tone1 & 0x00ff);
01135 buffsend[12] = (tone2 & 0xff00) >> 8;
01136 buffsend[13] = (tone2 & 0x00ff);
01137 send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_dial_freq), buffsend,
01138 pte);
01139 }
01140
01141 if (unistimdebug) {
01142 ast_verb(0, "Sending Stream Based Tone On\n");
01143 }
01144 memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_on,
01145 sizeof(packet_send_stream_based_tone_on));
01146 send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_on), buffsend, pte);
01147 }
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157 static void
01158 send_favorite(unsigned char pos, unsigned char status, struct unistimsession *pte,
01159 const char *text)
01160 {
01161 BUFFSEND;
01162 int i;
01163
01164 if (unistimdebug) {
01165 ast_verb(0, "Sending favorite pos %d with status 0x%.2x\n", pos, status);
01166 }
01167 memcpy(buffsend + SIZE_HEADER, packet_send_favorite, sizeof(packet_send_favorite));
01168 buffsend[10] = pos;
01169 buffsend[24] = pos;
01170 buffsend[25] = status;
01171 i = strlen(ustmtext(text, pte));
01172 if (i > FAV_MAX_LENGTH) {
01173 i = FAV_MAX_LENGTH;
01174 }
01175 memcpy(buffsend + FAV_MAX_LENGTH + 1, ustmtext(text, pte), i);
01176 send_client(SIZE_HEADER + sizeof(packet_send_favorite), buffsend, pte);
01177 }
01178
01179 static void send_favorite_short(unsigned char pos, unsigned char status, struct unistimsession *pte) {
01180 send_favorite(pos, status, pte, pte->device->softkeylabel[pos]);
01181 return;
01182 }
01183
01184 static void send_favorite_selected(unsigned char status, struct unistimsession *pte) {
01185 if (pte->device->selected != -1) {
01186 send_favorite(pte->device->selected, status, pte, pte->device->softkeylabel[pte->device->selected]);
01187 }
01188 return;
01189 }
01190
01191 static int soft_key_visible(struct unistim_device* d, unsigned char num)
01192 {
01193 if(d->height == 1 && num % 3 == 2) {
01194 return 0;
01195 }
01196 return 1;
01197 }
01198
01199 static void refresh_all_favorite(struct unistimsession *pte)
01200 {
01201 unsigned char i = 0;
01202 char data[256];
01203 struct unistim_line *line;
01204 line = AST_LIST_FIRST(&pte->device->lines);
01205
01206 if (unistimdebug) {
01207 ast_verb(0, "Refreshing all favorite\n");
01208 }
01209 for (i = 0; i < FAVNUM; i++) {
01210 unsigned char status = pte->device->softkeyicon[i];
01211
01212 if (!soft_key_visible(pte->device, i)) {
01213 continue;
01214 }
01215 if (!strcasecmp(pte->device->softkeylabel[i], "DND") && line) {
01216 if (!ast_db_get("DND", line->name, data, sizeof(data))) {
01217 status = FAV_ICON_SPEAKER_ONHOOK_WHITE;
01218 }
01219 }
01220
01221 send_favorite_short(i, status, pte);
01222 }
01223 }
01224
01225 static int is_key_favorite(struct unistim_device *d, int fav)
01226 {
01227 if ((fav < 0) && (fav > 5)) {
01228 return 0;
01229 }
01230 if (d->sline[fav]) {
01231 return 0;
01232 }
01233 if (d->softkeynumber[fav][0] == '\0') {
01234 return 0;
01235 }
01236 return 1;
01237 }
01238
01239 static int is_key_line(struct unistim_device *d, int fav)
01240 {
01241 if ((fav < 0) && (fav > 5)) {
01242 return 0;
01243 }
01244 if (!d->sline[fav]) {
01245 return 0;
01246 }
01247 if (is_key_favorite(d, fav)) {
01248 return 0;
01249 }
01250 return 1;
01251 }
01252
01253 static int get_active_softkey(struct unistimsession *pte)
01254 {
01255 return pte->device->selected;
01256 }
01257
01258 static int get_avail_softkey(struct unistimsession *pte, const char* name)
01259 {
01260 int i;
01261
01262 if (!is_key_line(pte->device, pte->device->selected)) {
01263 pte->device->selected = -1;
01264 }
01265 for (i = 0; i < FAVNUM; i++) {
01266 if (pte->device->selected != -1 && pte->device->selected != i) {
01267 continue;
01268 }
01269 if (!soft_key_visible(pte->device, i)) {
01270 continue;
01271 }
01272 if (pte->device->ssub[i]) {
01273 continue;
01274 }
01275 if (is_key_line(pte->device, i)) {
01276 if (name && strcmp(name, pte->device->sline[i]->name)) {
01277 continue;
01278 }
01279 if (unistimdebug) {
01280 ast_verb(0, "Found softkey %d for device %s\n", i, name);
01281 }
01282 return i;
01283 }
01284 }
01285 return -1;
01286 }
01287
01288
01289
01290
01291 static void change_favorite_icon(struct unistimsession *pte, unsigned char status)
01292 {
01293 struct unistim_device *d = devices;
01294 int i;
01295
01296 if (pte->state != STATE_CLEANING) {
01297 int softkeylinepos = get_active_softkey(pte);
01298 if (softkeylinepos != -1) {
01299 send_favorite_short(softkeylinepos, status, pte);
01300 }
01301 }
01302
01303 while (d) {
01304 for (i = 0; i < FAVNUM; i++) {
01305 if (d->sp[i] == pte->device) {
01306 if (d->softkeyicon[i] != status) {
01307 d->softkeyicon[i] = status;
01308 if (d->session) {
01309 send_favorite(i, status + 1, d->session, d->softkeylabel[i]);
01310 }
01311 }
01312 }
01313 }
01314 d = d->next;
01315 }
01316 }
01317
01318 static int register_extension(const struct unistimsession *pte)
01319 {
01320 struct unistim_line *line;
01321 line = AST_LIST_FIRST(&pte->device->lines);
01322 if (unistimdebug) {
01323 ast_verb(0, "Trying to register extension '%s' into context '%s' to %s\n",
01324 pte->device->extension_number, pte->device->context,
01325 line->fullname);
01326 }
01327 return ast_add_extension(pte->device->context, 0,
01328 pte->device->extension_number, 1, NULL, NULL, "Dial",
01329 line->fullname, 0, "Unistim");
01330 }
01331
01332 static int unregister_extension(const struct unistimsession *pte)
01333 {
01334 if (unistimdebug) {
01335 ast_verb(0, "Trying to unregister extension '%s' context '%s'\n",
01336 pte->device->extension_number, pte->device->context);
01337 }
01338 return ast_context_remove_extension(pte->device->context,
01339 pte->device->extension_number, 1, "Unistim");
01340 }
01341
01342
01343 static void close_client(struct unistimsession *s)
01344 {
01345 struct unistim_subchannel *sub = NULL;
01346 struct unistimsession *cur, *prev = NULL;
01347 ast_mutex_lock(&sessionlock);
01348 cur = sessions;
01349
01350 while (cur) {
01351 if (cur == s) {
01352 break;
01353 }
01354 prev = cur;
01355 cur = cur->next;
01356 }
01357 if (cur) {
01358 if (cur->device) {
01359 s->state = STATE_CLEANING;
01360 if (unistimdebug) {
01361 ast_verb(0, "close_client session %p device %p\n", s, s->device);
01362 }
01363 change_favorite_icon(s, FAV_ICON_NONE);
01364 ast_mutex_lock(&s->device->lock);
01365 AST_LIST_LOCK(&s->device->subs);
01366 AST_LIST_TRAVERSE_SAFE_BEGIN(&s->device->subs, sub, list) {
01367 if (!sub) {
01368 continue;
01369 }
01370 if (sub->owner) {
01371 if (unistimdebug) {
01372 ast_verb(0, "Aborting call\n");
01373 }
01374 ast_queue_hangup_with_cause(sub->owner, AST_CAUSE_NETWORK_OUT_OF_ORDER);
01375 } else {
01376 if (unistimdebug) {
01377 ast_debug(1, "Released sub %d of channel %s@%s\n", sub->subtype, sub->parent->name, s->device->name);
01378 }
01379 AST_LIST_REMOVE_CURRENT(list);
01380 unistim_free_sub(sub);
01381 }
01382 }
01383 AST_LIST_TRAVERSE_SAFE_END;
01384 AST_LIST_UNLOCK(&s->device->subs);
01385
01386 if (!ast_strlen_zero(s->device->extension_number)) {
01387 unregister_extension(s);
01388 }
01389 cur->device->session = NULL;
01390 ast_mutex_unlock(&s->device->lock);
01391 } else {
01392 if (unistimdebug) {
01393 ast_verb(0, "Freeing an unregistered client\n");
01394 }
01395 }
01396 if (prev) {
01397 prev->next = cur->next;
01398 } else {
01399 sessions = cur->next;
01400 }
01401 ast_mutex_destroy(&s->lock);
01402 ast_free(s);
01403 } else {
01404 ast_log(LOG_WARNING, "Trying to delete non-existent session %p?\n", s);
01405 }
01406 ast_mutex_unlock(&sessionlock);
01407 return;
01408 }
01409
01410
01411 static int send_retransmit(struct unistimsession *pte)
01412 {
01413 int i;
01414
01415 ast_mutex_lock(&pte->lock);
01416 if (++pte->nb_retransmit >= NB_MAX_RETRANSMIT) {
01417 if (unistimdebug) {
01418 ast_verb(0, "Too many retransmit - freeing client\n");
01419 }
01420 ast_mutex_unlock(&pte->lock);
01421 close_client(pte);
01422 return 1;
01423 }
01424 pte->timeout = get_tick_count() + RETRANSMIT_TIMER;
01425
01426 for (i = pte->last_buf_available - (pte->seq_server - pte->last_seq_ack);
01427 i < pte->last_buf_available; i++) {
01428 if (i < 0) {
01429 ast_log(LOG_WARNING,
01430 "Asked to retransmit an ACKed slot ! last_buf_available=%d, seq_server = #0x%.4x last_seq_ack = #0x%.4x\n",
01431 pte->last_buf_available, pte->seq_server, pte->last_seq_ack);
01432 continue;
01433 }
01434
01435 if (unistimdebug) {
01436 unsigned short *sbuf = (unsigned short *) pte->wsabufsend[i].buf;
01437 unsigned short seq;
01438
01439 seq = ntohs(sbuf[1]);
01440 ast_verb(0, "Retransmit slot #%d (seq=#0x%.4x), last ack was #0x%.4x\n", i,
01441 seq, pte->last_seq_ack);
01442 }
01443 send_raw_client(pte->wsabufsend[i].len, pte->wsabufsend[i].buf, &pte->sin,
01444 &pte->sout);
01445 }
01446 ast_mutex_unlock(&pte->lock);
01447 return 0;
01448 }
01449
01450
01451 static void
01452 send_text(unsigned char pos, unsigned char inverse, struct unistimsession *pte,
01453 const char *text)
01454 {
01455 int i;
01456 BUFFSEND;
01457 if (!text) {
01458 ast_log(LOG_ERROR, "Asked to display NULL text (pos %d, inverse flag %d)\n", pos, inverse);
01459 return;
01460 }
01461 if (pte->device && pte->device->height == 1 && pos != TEXT_LINE0) {
01462 return;
01463 }
01464 if (unistimdebug) {
01465 ast_verb(0, "Sending text at pos %d, inverse flag %d\n", pos, inverse);
01466 }
01467 memcpy(buffsend + SIZE_HEADER, packet_send_text, sizeof(packet_send_text));
01468 buffsend[10] = pos;
01469 buffsend[11] = inverse;
01470 i = strlen(text);
01471 if (i > TEXT_LENGTH_MAX) {
01472 i = TEXT_LENGTH_MAX;
01473 }
01474 memcpy(buffsend + 12, text, i);
01475 send_client(SIZE_HEADER + sizeof(packet_send_text), buffsend, pte);
01476 }
01477
01478 static void send_text_status(struct unistimsession *pte, const char *text)
01479 {
01480 BUFFSEND;
01481 int i;
01482 if (unistimdebug) {
01483 ast_verb(0, "Sending status text\n");
01484 }
01485 if (pte->device) {
01486 if (pte->device->status_method == 1) {
01487 int n = strlen(text);
01488
01489 int j;
01490 for (i = 0, j = 0; i < 4; i++, j += 7) {
01491 int pos = 0x08 + (i * 0x20);
01492 memcpy(buffsend + SIZE_HEADER, packet_send_status2,
01493 sizeof(packet_send_status2));
01494
01495 buffsend[9] = pos;
01496 memcpy(buffsend + 10, (j < n) ? (text + j) : " ", 7);
01497 send_client(SIZE_HEADER + sizeof(packet_send_status2), buffsend, pte);
01498 }
01499 return;
01500 }
01501 }
01502
01503
01504 memcpy(buffsend + SIZE_HEADER, packet_send_status, sizeof(packet_send_status));
01505 i = strlen(text);
01506 if (i > STATUS_LENGTH_MAX) {
01507 i = STATUS_LENGTH_MAX;
01508 }
01509 memcpy(buffsend + 10, text, i);
01510 send_client(SIZE_HEADER + sizeof(packet_send_status), buffsend, pte);
01511
01512 }
01513
01514
01515
01516
01517
01518 static void send_led_update(struct unistimsession *pte, unsigned char led)
01519 {
01520 BUFFSEND;
01521 if (unistimdebug) {
01522 ast_verb(0, "Sending led_update (%x)\n", led);
01523 }
01524 memcpy(buffsend + SIZE_HEADER, packet_send_led_update, sizeof(packet_send_led_update));
01525 buffsend[9] = led;
01526 send_client(SIZE_HEADER + sizeof(packet_send_led_update), buffsend, pte);
01527 }
01528
01529
01530
01531
01532 static void
01533 send_select_output(struct unistimsession *pte, unsigned char output, unsigned char volume,
01534 unsigned char mute)
01535 {
01536 BUFFSEND;
01537 if (unistimdebug) {
01538 ast_verb(0, "Sending select output packet output=%x volume=%x mute=%x\n", output,
01539 volume, mute);
01540 }
01541 memcpy(buffsend + SIZE_HEADER, packet_send_select_output,
01542 sizeof(packet_send_select_output));
01543 buffsend[9] = output;
01544 if (output == OUTPUT_SPEAKER) {
01545 volume = VOLUME_LOW_SPEAKER;
01546 } else {
01547 volume = VOLUME_LOW;
01548 }
01549 buffsend[10] = volume;
01550 if (mute == MUTE_ON_DISCRET) {
01551 buffsend[11] = MUTE_ON;
01552 } else {
01553 buffsend[11] = mute;
01554 }
01555 send_client(SIZE_HEADER + sizeof(packet_send_select_output), buffsend, pte);
01556 if (mute == MUTE_OFF) {
01557 send_led_update(pte, 0x18);
01558 } else if (mute == MUTE_ON) {
01559 send_led_update(pte, 0x19);
01560 }
01561 pte->device->mute = mute;
01562 if (output == OUTPUT_HANDSET) {
01563 if (mute == MUTE_ON) {
01564 change_favorite_icon(pte, FAV_ICON_ONHOLD_BLACK);
01565 } else {
01566 change_favorite_icon(pte, FAV_ICON_OFFHOOK_BLACK);
01567 }
01568 send_led_update(pte, 0x08);
01569 send_led_update(pte, 0x10);
01570 } else if (output == OUTPUT_HEADPHONE) {
01571 if (mute == MUTE_ON) {
01572 change_favorite_icon(pte, FAV_ICON_HEADPHONES_ONHOLD);
01573 } else {
01574 change_favorite_icon(pte, FAV_ICON_HEADPHONES);
01575 }
01576 send_led_update(pte, 0x08);
01577 send_led_update(pte, 0x11);
01578 } else if (output == OUTPUT_SPEAKER) {
01579 send_led_update(pte, 0x10);
01580 send_led_update(pte, 0x09);
01581 if (pte->device->receiver_state == STATE_OFFHOOK) {
01582 if (mute == MUTE_ON) {
01583 change_favorite_icon(pte, FAV_ICON_SPEAKER_ONHOLD_BLACK);
01584 } else {
01585 change_favorite_icon(pte, FAV_ICON_SPEAKER_ONHOOK_BLACK);
01586 }
01587 } else {
01588 if (mute == MUTE_ON) {
01589 change_favorite_icon(pte, FAV_ICON_SPEAKER_ONHOLD_BLACK);
01590 } else {
01591 change_favorite_icon(pte, FAV_ICON_SPEAKER_OFFHOOK_BLACK);
01592 }
01593 }
01594 } else {
01595 ast_log(LOG_WARNING, "Invalid output (%d)\n", output);
01596 }
01597 if (output != pte->device->output) {
01598 pte->device->previous_output = pte->device->output;
01599 }
01600 pte->device->output = output;
01601 }
01602
01603 static void send_ring(struct unistimsession *pte, char volume, char style)
01604 {
01605 BUFFSEND;
01606 if (unistimdebug) {
01607 ast_verb(0, "Sending ring packet\n");
01608 }
01609 memcpy(buffsend + SIZE_HEADER, packet_send_ring, sizeof(packet_send_ring));
01610 buffsend[24] = style + 0x10;
01611 buffsend[29] = volume * 0x10;
01612 send_client(SIZE_HEADER + sizeof(packet_send_ring), buffsend, pte);
01613 }
01614
01615 static void send_no_ring(struct unistimsession *pte)
01616 {
01617 BUFFSEND;
01618 if (unistimdebug) {
01619 ast_verb(0, "Sending no ring packet\n");
01620 }
01621 memcpy(buffsend + SIZE_HEADER, packet_send_no_ring, sizeof(packet_send_no_ring));
01622 send_client(SIZE_HEADER + sizeof(packet_send_no_ring), buffsend, pte);
01623 }
01624
01625 static void send_texttitle(struct unistimsession *pte, const char *text)
01626 {
01627 BUFFSEND;
01628 int i;
01629 if (unistimdebug) {
01630 ast_verb(0, "Sending title text\n");
01631 }
01632 memcpy(buffsend + SIZE_HEADER, packet_send_title, sizeof(packet_send_title));
01633 i = strlen(text);
01634 if (i > 12) {
01635 i = 12;
01636 }
01637 memcpy(buffsend + 10, text, i);
01638 send_client(SIZE_HEADER + sizeof(packet_send_title), buffsend, pte);
01639
01640 }
01641
01642 static void send_idle_clock(struct unistimsession *pte)
01643 {
01644 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "");
01645 }
01646
01647 static void send_date_time(struct unistimsession *pte)
01648 {
01649 BUFFSEND;
01650 struct timeval now = ast_tvnow();
01651 struct ast_tm atm = { 0, };
01652
01653 if (unistimdebug) {
01654 ast_verb(0, "Sending Time & Date\n");
01655 }
01656 memcpy(buffsend + SIZE_HEADER, packet_send_date_time, sizeof(packet_send_date_time));
01657 ast_localtime(&now, &atm, NULL);
01658 buffsend[10] = (unsigned char) atm.tm_mon + 1;
01659 buffsend[11] = (unsigned char) atm.tm_mday;
01660 buffsend[12] = (unsigned char) atm.tm_hour;
01661 buffsend[13] = (unsigned char) atm.tm_min;
01662 send_client(SIZE_HEADER + sizeof(packet_send_date_time), buffsend, pte);
01663 }
01664
01665 static void send_date_time2(struct unistimsession *pte)
01666 {
01667 BUFFSEND;
01668 struct timeval now = ast_tvnow();
01669 struct ast_tm atm = { 0, };
01670
01671 if (unistimdebug) {
01672 ast_verb(0, "Sending Time & Date #2\n");
01673 }
01674 memcpy(buffsend + SIZE_HEADER, packet_send_date_time2, sizeof(packet_send_date_time2));
01675 ast_localtime(&now, &atm, NULL);
01676 if (pte->device) {
01677 buffsend[9] = pte->device->datetimeformat;
01678 } else {
01679 buffsend[9] = 61;
01680 }
01681 buffsend[14] = (unsigned char) atm.tm_mon + 1;
01682 buffsend[15] = (unsigned char) atm.tm_mday;
01683 buffsend[16] = (unsigned char) atm.tm_hour;
01684 buffsend[17] = (unsigned char) atm.tm_min;
01685 send_client(SIZE_HEADER + sizeof(packet_send_date_time2), buffsend, pte);
01686 }
01687
01688 static void send_date_time3(struct unistimsession *pte)
01689 {
01690 BUFFSEND;
01691 struct timeval now = ast_tvnow();
01692 struct ast_tm atm = { 0, };
01693
01694 if (unistimdebug) {
01695 ast_verb(0, "Sending Time & Date #3\n");
01696 }
01697 memcpy(buffsend + SIZE_HEADER, packet_send_date_time3, sizeof(packet_send_date_time3));
01698 ast_localtime(&now, &atm, NULL);
01699 buffsend[10] = (unsigned char) atm.tm_mon + 1;
01700 buffsend[11] = (unsigned char) atm.tm_mday;
01701 buffsend[12] = (unsigned char) atm.tm_hour;
01702 buffsend[13] = (unsigned char) atm.tm_min;
01703 send_client(SIZE_HEADER + sizeof(packet_send_date_time3), buffsend, pte);
01704 }
01705
01706 static void send_blink_cursor(struct unistimsession *pte)
01707 {
01708 BUFFSEND;
01709 if (unistimdebug) {
01710 ast_verb(0, "Sending set blink\n");
01711 }
01712 memcpy(buffsend + SIZE_HEADER, packet_send_blink_cursor, sizeof(packet_send_blink_cursor));
01713 send_client(SIZE_HEADER + sizeof(packet_send_blink_cursor), buffsend, pte);
01714 return;
01715 }
01716
01717
01718 static void send_cursor_pos(struct unistimsession *pte, unsigned char pos)
01719 {
01720 BUFFSEND;
01721 if (unistimdebug) {
01722 ast_verb(0, "Sending set cursor position\n");
01723 }
01724 memcpy(buffsend + SIZE_HEADER, packet_send_set_pos_cursor,
01725 sizeof(packet_send_set_pos_cursor));
01726 buffsend[11] = pos;
01727 send_client(SIZE_HEADER + sizeof(packet_send_set_pos_cursor), buffsend, pte);
01728 return;
01729 }
01730
01731 static void send_charset_update(struct unistimsession *pte, int charset)
01732 {
01733 const unsigned char* packet_send_charset;
01734 int packet_size;
01735 BUFFSEND;
01736 if (unistimdebug) {
01737 ast_verb(0, "Sending set default charset\n");
01738 }
01739 if (charset == LANG_DEFAULT) {
01740 charset = options_languages[find_language(pte->device->language)].encoding;
01741 }
01742 switch (charset) {
01743 case ISO_8859_2:
01744 packet_send_charset = packet_send_charset_iso_8859_2;
01745 packet_size = sizeof(packet_send_charset_iso_8859_2);
01746 break;
01747 case ISO_8859_4:
01748 packet_send_charset = packet_send_charset_iso_8859_4;
01749 packet_size = sizeof(packet_send_charset_iso_8859_4);
01750 break;
01751 case ISO_8859_5:
01752 packet_send_charset = packet_send_charset_iso_8859_5;
01753 packet_size = sizeof(packet_send_charset_iso_8859_5);
01754 break;
01755 case ISO_2022_JP:
01756 packet_send_charset = packet_send_charset_iso_2022_jp;
01757 packet_size = sizeof(packet_send_charset_iso_2022_jp);
01758 break;
01759 case ISO_8859_1:
01760 default:
01761 packet_send_charset = packet_send_charset_iso_8859_1;
01762 packet_size = sizeof(packet_send_charset_iso_8859_1);
01763 }
01764 memcpy(buffsend + SIZE_HEADER, packet_send_charset, packet_size);
01765 send_client(SIZE_HEADER + packet_size, buffsend, pte);
01766 return;
01767 }
01768
01769 static void rcv_resume_connection_with_server(struct unistimsession *pte)
01770 {
01771 BUFFSEND;
01772 if (unistimdebug) {
01773 ast_verb(0, "ResumeConnectionWithServer received\n");
01774 ast_verb(0, "Sending packet_send_query_mac_address\n");
01775 }
01776 memcpy(buffsend + SIZE_HEADER, packet_send_query_mac_address,
01777 sizeof(packet_send_query_mac_address));
01778 send_client(SIZE_HEADER + sizeof(packet_send_query_mac_address), buffsend, pte);
01779 return;
01780 }
01781
01782 static int unistim_register(struct unistimsession *s)
01783 {
01784 struct unistim_device *d;
01785
01786 ast_mutex_lock(&devicelock);
01787 d = devices;
01788 while (d) {
01789 if (!strcasecmp(s->macaddr, d->id)) {
01790
01791 s->device = d;
01792 d->session = s;
01793 d->codec_number = DEFAULT_CODEC;
01794 d->missed_call = 0;
01795 d->receiver_state = STATE_ONHOOK;
01796 break;
01797 }
01798 d = d->next;
01799 }
01800 ast_mutex_unlock(&devicelock);
01801
01802 if (!d) {
01803 return 0;
01804 }
01805
01806 return 1;
01807 }
01808
01809 static void unistim_line_copy(struct unistim_line *dst, struct unistim_line *src)
01810 {
01811 struct ast_format_cap *tmp = src->cap;
01812 memcpy(dst, src, sizeof(*dst));
01813 src->cap = tmp;
01814 ast_format_cap_copy(src->cap, dst->cap);
01815 }
01816
01817 static struct unistim_line *unistim_line_destroy(struct unistim_line *l)
01818 {
01819 if (!l) {
01820 return NULL;
01821 }
01822 l->cap = ast_format_cap_destroy(l->cap);
01823 ast_free(l);
01824 return NULL;
01825 }
01826
01827 static struct unistim_line *unistim_line_alloc(void)
01828 {
01829 struct unistim_line *l;
01830 if (!(l = ast_calloc(1, sizeof(*l)))) {
01831 return NULL;
01832 }
01833
01834 if (!(l->cap = ast_format_cap_alloc_nolock())) {
01835 ast_free(l);
01836 return NULL;
01837 }
01838 return l;
01839 }
01840
01841 static int unistim_free_sub(struct unistim_subchannel *sub) {
01842 if (unistimdebug) {
01843 ast_debug(1, "Released sub %d of channel %s@%s\n", sub->subtype, sub->parent->name, sub->parent->parent->name);
01844 }
01845 ast_mutex_destroy(&sub->lock);
01846 ast_free(sub);
01847 return 0;
01848 }
01849
01850 static struct unistim_subchannel *unistim_alloc_sub(struct unistim_device *d, int x)
01851 {
01852 struct unistim_subchannel *sub;
01853 if (!(sub = ast_calloc(1, sizeof(*sub)))) {
01854 return NULL;
01855 }
01856
01857 if (unistimdebug) {
01858 ast_verb(3, "Allocating UNISTIM subchannel #%d on %s ptr=%p\n", x, d->name, sub);
01859 }
01860 sub->ss_thread = AST_PTHREADT_NULL;
01861 sub->subtype = x;
01862 AST_LIST_LOCK(&d->subs);
01863 AST_LIST_INSERT_TAIL(&d->subs, sub, list);
01864 AST_LIST_UNLOCK(&d->subs);
01865 ast_mutex_init(&sub->lock);
01866 return sub;
01867 }
01868
01869 static int unistim_unalloc_sub(struct unistim_device *d, struct unistim_subchannel *sub)
01870 {
01871 struct unistim_subchannel *s;
01872
01873 AST_LIST_LOCK(&d->subs);
01874 AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, s, list) {
01875 if (!s) {
01876 continue;
01877 }
01878 if (s != sub) {
01879 continue;
01880 }
01881 AST_LIST_REMOVE_CURRENT(list);
01882 unistim_free_sub(sub);
01883 }
01884 AST_LIST_TRAVERSE_SAFE_END;
01885 AST_LIST_UNLOCK(&d->subs);
01886 return 0;
01887 }
01888
01889 static const char *subtype_tostr(const int type)
01890 {
01891 switch (type) {
01892 case SUB_REAL:
01893 return "REAL";
01894 case SUB_ONHOLD:
01895 return "ONHOLD";
01896 case SUB_RING:
01897 return "RINGING";
01898 case SUB_THREEWAY:
01899 return "THREEWAY";
01900 }
01901 return "UNKNOWN";
01902 }
01903
01904 static const char *ptestate_tostr(const int type)
01905 {
01906 switch (type) {
01907 case STATE_INIT:
01908 return "INIT";
01909 case STATE_AUTHDENY:
01910 return "AUTHDENY";
01911 case STATE_MAINPAGE:
01912 return "MAINPAGE";
01913 case STATE_EXTENSION:
01914 return "EXTENSION";
01915 case STATE_DIALPAGE:
01916 return "DIALPAGE";
01917 case STATE_RINGING:
01918 return "RINGING";
01919 case STATE_CALL:
01920 return "CALL";
01921 case STATE_SELECTOPTION:
01922 return "SELECTOPTION";
01923 case STATE_SELECTCODEC:
01924 return "SELECTCODEC";
01925 case STATE_SELECTLANGUAGE:
01926 return "SELECTLANGUAGE";
01927 case STATE_CLEANING:
01928 return "CLEARING";
01929 case STATE_HISTORY:
01930 return "HISTORY";
01931 }
01932 return "UNKNOWN";
01933 }
01934
01935 static void rcv_mac_addr(struct unistimsession *pte, const unsigned char *buf)
01936 {
01937 BUFFSEND;
01938 int tmp, i = 0;
01939 char addrmac[19];
01940 int res = 0;
01941 for (tmp = 15; tmp < 15 + SIZE_HEADER; tmp++) {
01942 sprintf(&addrmac[i], "%.2x", (unsigned char) buf[tmp]);
01943 i += 2;
01944 }
01945 if (unistimdebug) {
01946 ast_verb(0, "MAC Address received: %s\n", addrmac);
01947 }
01948 strcpy(pte->macaddr, addrmac);
01949 res = unistim_register(pte);
01950 if (!res) {
01951 switch (autoprovisioning) {
01952 case AUTOPROVISIONING_NO:
01953 ast_log(LOG_WARNING, "No entry found for this phone : %s\n", addrmac);
01954 pte->state = STATE_AUTHDENY;
01955 break;
01956 case AUTOPROVISIONING_YES:
01957 {
01958 struct unistim_device *d = NULL, *newd = NULL;
01959 struct unistim_line *newl = NULL, *l = NULL;
01960 if (unistimdebug) {
01961 ast_verb(0, "New phone, autoprovisioning on\n");
01962 }
01963
01964 ast_mutex_lock(&devicelock);
01965 d = devices;
01966 while (d) {
01967 if (strcasecmp(d->name, "template")) {
01968 d = d->next;
01969 continue;
01970 }
01971
01972 if (!(newd = ast_malloc(sizeof(*newd)))) {
01973 ast_mutex_unlock(&devicelock);
01974 return;
01975 }
01976 memcpy(newd, d, sizeof(*newd));
01977 ast_mutex_init(&newd->lock);
01978 newd->lines.first = NULL;
01979 newd->lines.last = NULL;
01980 AST_LIST_LOCK(&d->lines);
01981 AST_LIST_TRAVERSE(&d->lines, l, list) {
01982 if (!(newl = unistim_line_alloc())) {
01983 break;
01984 }
01985 unistim_line_copy(l, newl);
01986 newl->parent = newd;
01987 ast_copy_string(newl->name, l->name, sizeof(newl->name));
01988 snprintf(newl->fullname, sizeof(newl->fullname), "USTM/%s@%s",
01989 newl->name, newd->name);
01990 snprintf(l->name, sizeof(l->name), "%d", atoi(l->name) + 1);
01991
01992 AST_LIST_LOCK(&newd->lines);
01993 AST_LIST_INSERT_TAIL(&newd->lines, newl, list);
01994 AST_LIST_UNLOCK(&newd->lines);
01995 }
01996 AST_LIST_UNLOCK(&d->lines);
01997 if (!newl) {
01998 ast_free(newd);
01999 ast_mutex_unlock(&devicelock);
02000 }
02001
02002
02003 ast_copy_string(newd->id, addrmac, sizeof(newd->id));
02004 ast_copy_string(newd->name, addrmac, sizeof(newd->name));
02005 if (newd->extension == EXTENSION_NONE) {
02006 newd->extension = EXTENSION_ASK;
02007 }
02008
02009 newd->receiver_state = STATE_ONHOOK;
02010 newd->session = pte;
02011 newd->language[0] = '\0';
02012 newd->to_delete = -1;
02013 newd->next = NULL;
02014 pte->device = newd;
02015
02016
02017 while (d->next) {
02018 d = d->next;
02019 }
02020 d->next = newd;
02021 d = newd;
02022 break;
02023 }
02024 ast_mutex_unlock(&devicelock);
02025 if (!d) {
02026 ast_log(LOG_WARNING, "No entry [template] found in unistim.conf\n");
02027 pte->state = STATE_AUTHDENY;
02028 }
02029 }
02030 break;
02031 case AUTOPROVISIONING_TN:
02032 pte->state = STATE_AUTHDENY;
02033 break;
02034 default:
02035 ast_log(LOG_WARNING, "Internal error : unknown autoprovisioning value = %d\n",
02036 autoprovisioning);
02037 }
02038 }
02039 if (pte->state != STATE_AUTHDENY) {
02040 struct unistim_line *line;
02041 struct unistim_subchannel *sub;
02042
02043 ast_verb(3, "Device '%s' successfuly registered\n", pte->device->name);
02044
02045 AST_LIST_LOCK(&pte->device->subs);
02046 AST_LIST_TRAVERSE_SAFE_BEGIN(&pte->device->subs, sub, list) {
02047 if (sub) {
02048 ast_log(LOG_ERROR, "Subchannel lost sice reboot. Hanged channel may apear!\n");
02049 AST_LIST_REMOVE_CURRENT(list);
02050 ast_free(sub);
02051 }
02052 }
02053 AST_LIST_TRAVERSE_SAFE_END;
02054 AST_LIST_UNLOCK(&pte->device->subs);
02055
02056 switch (pte->device->extension) {
02057 case EXTENSION_NONE:
02058 pte->state = STATE_MAINPAGE;
02059 break;
02060 case EXTENSION_ASK:
02061
02062 if (ast_strlen_zero(pte->device->extension_number)) {
02063 pte->state = STATE_EXTENSION;
02064 } else {
02065
02066 if (register_extension(pte)) {
02067 pte->state = STATE_EXTENSION;
02068 } else {
02069 pte->state = STATE_MAINPAGE;
02070 }
02071 }
02072 break;
02073 case EXTENSION_LINE:
02074 line = AST_LIST_FIRST(&pte->device->lines);
02075 ast_copy_string(pte->device->extension_number, line->name,
02076 sizeof(pte->device->extension_number));
02077 if (register_extension(pte)) {
02078 pte->state = STATE_EXTENSION;
02079 } else {
02080 pte->state = STATE_MAINPAGE;
02081 }
02082 break;
02083 case EXTENSION_TN:
02084
02085 pte->state = STATE_MAINPAGE;
02086 break;
02087 default:
02088 ast_log(LOG_WARNING, "Internal error, extension value unknown : %d\n",
02089 pte->device->extension);
02090 pte->state = STATE_AUTHDENY;
02091 break;
02092 }
02093 }
02094 if (pte->state == STATE_EXTENSION) {
02095 if (pte->device->extension != EXTENSION_TN) {
02096 pte->device->extension = EXTENSION_ASK;
02097 }
02098 pte->device->extension_number[0] = '\0';
02099 }
02100 if (unistimdebug) {
02101 ast_verb(0, "\nSending S1\n");
02102 }
02103 memcpy(buffsend + SIZE_HEADER, packet_send_S1, sizeof(packet_send_S1));
02104 send_client(SIZE_HEADER + sizeof(packet_send_S1), buffsend, pte);
02105
02106 if (unistimdebug) {
02107 ast_verb(0, "Sending query_basic_manager_04\n");
02108 }
02109 memcpy(buffsend + SIZE_HEADER, packet_send_query_basic_manager_04,
02110 sizeof(packet_send_query_basic_manager_04));
02111 send_client(SIZE_HEADER + sizeof(packet_send_query_basic_manager_04), buffsend, pte);
02112
02113 if (unistimdebug) {
02114 ast_verb(0, "Sending query_basic_manager_10\n");
02115 }
02116 memcpy(buffsend + SIZE_HEADER, packet_send_query_basic_manager_10,
02117 sizeof(packet_send_query_basic_manager_10));
02118 send_client(SIZE_HEADER + sizeof(packet_send_query_basic_manager_10), buffsend, pte);
02119
02120 send_date_time(pte);
02121 return;
02122 }
02123
02124 static int write_entry_history(struct unistimsession *pte, FILE * f, char c, char *line1)
02125 {
02126 if (fwrite(&c, 1, 1, f) != 1) {
02127 display_last_error("Unable to write history log header.");
02128 return -1;
02129 }
02130 if (fwrite(line1, TEXT_LENGTH_MAX, 1, f) != 1) {
02131 display_last_error("Unable to write history entry - date.");
02132 return -1;
02133 }
02134 if (fwrite(pte->device->lst_cid, TEXT_LENGTH_MAX, 1, f) != 1) {
02135 display_last_error("Unable to write history entry - callerid.");
02136 return -1;
02137 }
02138 if (fwrite(pte->device->lst_cnm, TEXT_LENGTH_MAX, 1, f) != 1) {
02139 display_last_error("Unable to write history entry - callername.");
02140 return -1;
02141 }
02142 return 0;
02143 }
02144
02145 static int write_history(struct unistimsession *pte, char way, char ismissed)
02146 {
02147 char tmp[AST_CONFIG_MAX_PATH], tmp2[AST_CONFIG_MAX_PATH];
02148 char line1[TEXT_LENGTH_MAX + 1];
02149 char count = 0, *histbuf;
02150 int size;
02151 FILE *f, *f2;
02152 struct timeval now = ast_tvnow();
02153 struct ast_tm atm = { 0, };
02154
02155 if (!pte->device) {
02156 return -1;
02157 }
02158 if (!pte->device->callhistory) {
02159 return 0;
02160 }
02161 if (strchr(pte->device->name, '/') || (pte->device->name[0] == '.')) {
02162 ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n",
02163 pte->device->name);
02164 return -1;
02165 }
02166
02167 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_LOG_DIR, USTM_LOG_DIR);
02168 if (ast_mkdir(tmp, 0770)) {
02169 ast_log(LOG_WARNING, "Unable to create directory for history\n");
02170 return -1;
02171 }
02172
02173 ast_localtime(&now, &atm, NULL);
02174 if (ismissed) {
02175 if (way == 'i') {
02176 ast_copy_string(tmp2, ustmtext("Miss", pte), sizeof(tmp2));
02177 } else {
02178 ast_copy_string(tmp2, ustmtext("Fail", pte), sizeof(tmp2));
02179 }
02180 } else {
02181 ast_copy_string(tmp2, ustmtext("Answ", pte), sizeof(tmp2));
02182 }
02183 snprintf(line1, sizeof(line1), "%04d/%02d/%02d %02d:%02d:%02d %s",
02184 atm.tm_year + 1900, atm.tm_mon + 1, atm.tm_mday, atm.tm_hour,
02185 atm.tm_min, atm.tm_sec, tmp2);
02186
02187 snprintf(tmp, sizeof(tmp), "%s/%s/%s-%c.csv", ast_config_AST_LOG_DIR,
02188 USTM_LOG_DIR, pte->device->name, way);
02189 if ((f = fopen(tmp, "r"))) {
02190 struct stat bufstat;
02191
02192 if (stat(tmp, &bufstat)) {
02193 display_last_error("Unable to stat history log.");
02194 fclose(f);
02195 return -1;
02196 }
02197 size = 1 + (MAX_ENTRY_LOG * TEXT_LENGTH_MAX * 3);
02198 if (bufstat.st_size != size) {
02199 ast_log(LOG_WARNING,
02200 "History file %s has an incorrect size (%d instead of %d). It will be replaced by a new one.",
02201 tmp, (int) bufstat.st_size, size);
02202 fclose(f);
02203 f = NULL;
02204 count = 1;
02205 }
02206 }
02207
02208
02209 if (!f) {
02210 char c = 1;
02211 int i;
02212
02213 if ((errno != ENOENT) && (count == 0)) {
02214 display_last_error("Unable to open history log.");
02215 return -1;
02216 }
02217 f = fopen(tmp, "w");
02218 if (!f) {
02219 display_last_error("Unable to create history log.");
02220 return -1;
02221 }
02222 if (write_entry_history(pte, f, c, line1)) {
02223 fclose(f);
02224 return -1;
02225 }
02226 memset(line1, ' ', TEXT_LENGTH_MAX);
02227 for (i = 3; i < MAX_ENTRY_LOG * 3; i++) {
02228 if (fwrite(line1, TEXT_LENGTH_MAX, 1, f) != 1) {
02229 display_last_error("Unable to write history entry - stuffing.");
02230 fclose(f);
02231 return -1;
02232 }
02233 }
02234 if (fclose(f)) {
02235 display_last_error("Unable to close history - creation.");
02236 }
02237 return 0;
02238 }
02239
02240 if (fread(&count, 1, 1, f) != 1) {
02241 display_last_error("Unable to read history header.");
02242 fclose(f);
02243 return -1;
02244 }
02245 if (count > MAX_ENTRY_LOG) {
02246 ast_log(LOG_WARNING, "Invalid count in history header of %s (%d max %d)\n", tmp,
02247 count, MAX_ENTRY_LOG);
02248 fclose(f);
02249 return -1;
02250 }
02251 snprintf(tmp2, sizeof(tmp2), "%s/%s/%s-%c.csv.tmp", ast_config_AST_LOG_DIR,
02252 USTM_LOG_DIR, pte->device->name, way);
02253 if (!(f2 = fopen(tmp2, "w"))) {
02254 display_last_error("Unable to create temporary history log.");
02255 fclose(f);
02256 return -1;
02257 }
02258
02259 if (++count > MAX_ENTRY_LOG) {
02260 count = MAX_ENTRY_LOG;
02261 }
02262 if (write_entry_history(pte, f2, count, line1)) {
02263 fclose(f);
02264 fclose(f2);
02265 return -1;
02266 }
02267 size = (MAX_ENTRY_LOG - 1) * TEXT_LENGTH_MAX * 3;
02268 if (!(histbuf = ast_malloc(size))) {
02269 fclose(f);
02270 fclose(f2);
02271 return -1;
02272 }
02273
02274 if (fread(histbuf, size, 1, f) != 1) {
02275 ast_free(histbuf);
02276 fclose(f);
02277 fclose(f2);
02278 display_last_error("Unable to read previous history entries.");
02279 return -1;
02280 }
02281 if (fwrite(histbuf, size, 1, f2) != 1) {
02282 ast_free(histbuf);
02283 fclose(f);
02284 fclose(f2);
02285 display_last_error("Unable to write previous history entries.");
02286 return -1;
02287 }
02288 ast_free(histbuf);
02289 if (fclose(f)) {
02290 display_last_error("Unable to close history log.");
02291 }
02292 if (fclose(f2)) {
02293 display_last_error("Unable to close temporary history log.");
02294 }
02295 if (unlink(tmp)) {
02296 display_last_error("Unable to remove old history log.");
02297 }
02298 if (rename(tmp2, tmp)) {
02299 display_last_error("Unable to rename new history log.");
02300 }
02301 return 0;
02302 }
02303
02304 static void unistim_quiet_chan(struct ast_channel *chan)
02305 {
02306 if (chan && ast_channel_state(chan) == AST_STATE_UP) {
02307 if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH)) {
02308 ast_moh_stop(chan);
02309 } else if (ast_channel_generatordata(chan)) {
02310 ast_deactivate_generator(chan);
02311 }
02312 }
02313 }
02314
02315 static int attempt_transfer(struct unistim_subchannel *p1, struct unistim_subchannel *p2)
02316 {
02317 int res = 0;
02318 struct ast_channel
02319 *chana = NULL, *chanb = NULL, *bridgea = NULL, *bridgeb = NULL, *peera =
02320 NULL, *peerb = NULL, *peerc = NULL, *peerd = NULL;
02321
02322 if (!p1->owner || !p2->owner) {
02323 ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n");
02324 return -1;
02325 }
02326 chana = p1->owner;
02327 chanb = p2->owner;
02328 bridgea = ast_bridged_channel(chana);
02329 bridgeb = ast_bridged_channel(chanb);
02330
02331 if (bridgea) {
02332 peera = chana;
02333 peerb = chanb;
02334 peerc = bridgea;
02335 peerd = bridgeb;
02336 } else if (bridgeb) {
02337 peera = chanb;
02338 peerb = chana;
02339 peerc = bridgeb;
02340 peerd = bridgea;
02341 }
02342
02343 if (peera && peerb && peerc && (peerb != peerc)) {
02344 unistim_quiet_chan(peera);
02345 unistim_quiet_chan(peerb);
02346 unistim_quiet_chan(peerc);
02347 if (peerd) {
02348 unistim_quiet_chan(peerd);
02349 }
02350
02351 if (ast_channel_cdr(peera) && ast_channel_cdr(peerb)) {
02352 ast_channel_cdr_set(peerb, ast_cdr_append(ast_channel_cdr(peerb), ast_channel_cdr(peera)));
02353 } else if (ast_channel_cdr(peera)) {
02354 ast_channel_cdr_set(peerb, ast_channel_cdr(peera));
02355 }
02356 ast_channel_cdr_set(peera, NULL);
02357
02358 if (ast_channel_cdr(peerb) && ast_channel_cdr(peerc)) {
02359 ast_channel_cdr_set(peerb, ast_cdr_append(ast_channel_cdr(peerb), ast_channel_cdr(peerc)));
02360 } else if (ast_channel_cdr(peerc)) {
02361 ast_channel_cdr_set(peerb, ast_channel_cdr(peerc));
02362 }
02363 ast_channel_cdr_set(peerc, NULL);
02364
02365 ast_log(LOG_NOTICE, "UNISTIM transfer: trying to masquerade %s into %s\n", ast_channel_name(peerc), ast_channel_name(peerb));
02366 if (ast_channel_masquerade(peerb, peerc)) {
02367 ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", ast_channel_name(peerb),
02368 ast_channel_name(peerc));
02369 res = -1;
02370 }
02371 return res;
02372 } else {
02373 ast_log(LOG_NOTICE,
02374 "Transfer attempted with no appropriate bridged calls to transfer\n");
02375 if (chana) {
02376 ast_softhangup_nolock(chana, AST_SOFTHANGUP_DEV);
02377 }
02378 if (chanb) {
02379 ast_softhangup_nolock(chanb, AST_SOFTHANGUP_DEV);
02380 }
02381 return -1;
02382 }
02383 return 0;
02384 }
02385
02386 void change_callerid(struct unistimsession *pte, int type, char *callerid)
02387 {
02388 char *data;
02389 int size;
02390
02391 if (type) {
02392 data = pte->device->lst_cnm;
02393 } else {
02394 data = pte->device->lst_cid;
02395 }
02396
02397
02398
02399 memset(data, ' ', TEXT_LENGTH_MAX);
02400 size = strlen(callerid);
02401 if (size > TEXT_LENGTH_MAX) {
02402 size = TEXT_LENGTH_MAX;
02403 }
02404 memcpy(data, callerid, size);
02405 }
02406
02407 static struct unistim_subchannel* get_sub(struct unistim_device *device, int type)
02408 {
02409 struct unistim_subchannel *sub = NULL;
02410
02411 AST_LIST_LOCK(&device->subs);
02412 AST_LIST_TRAVERSE(&device->subs, sub, list) {
02413 if (!sub) {
02414 continue;
02415 }
02416 if (sub->subtype == type) {
02417 break;
02418 }
02419 }
02420 AST_LIST_UNLOCK(&device->subs);
02421
02422 return sub;
02423 }
02424
02425 static void sub_start_silence(struct unistimsession *pte, struct unistim_subchannel *sub)
02426 {
02427
02428 if (!pte->device->silence_generator) {
02429 pte->device->silence_generator =
02430 ast_channel_start_silence_generator(sub->owner);
02431 if (pte->device->silence_generator == NULL) {
02432 ast_log(LOG_WARNING, "Unable to start a silence generator.\n");
02433 } else if (unistimdebug) {
02434 ast_verb(0, "Starting silence generator\n");
02435 }
02436 }
02437
02438 }
02439
02440 static void sub_stop_silence(struct unistimsession *pte, struct unistim_subchannel *sub)
02441 {
02442
02443 if (pte->device->silence_generator) {
02444 if (unistimdebug) {
02445 ast_verb(0, "Stopping silence generator\n");
02446 }
02447 if (sub->owner) {
02448 ast_channel_stop_silence_generator(sub->owner, pte->device->silence_generator);
02449 } else {
02450 ast_log(LOG_WARNING, "Trying to stop silence generator on a null channel!\n");
02451 }
02452 pte->device->silence_generator = NULL;
02453 }
02454 }
02455
02456 static void sub_hold(struct unistimsession *pte, struct unistim_subchannel *sub)
02457 {
02458 if (!sub) {
02459 return;
02460 }
02461 sub->moh = 1;
02462 sub->subtype = SUB_ONHOLD;
02463 send_favorite_short(sub->softkey, FAV_ICON_ONHOLD_BLACK + FAV_BLINK_SLOW, pte);
02464 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON);
02465 send_stop_timer(pte);
02466 if (sub->owner) {
02467 ast_queue_control_data(sub->owner, AST_CONTROL_HOLD, NULL, 0);
02468 send_end_call(pte);
02469 }
02470 return;
02471 }
02472
02473 static void sub_unhold(struct unistimsession *pte, struct unistim_subchannel *sub)
02474 {
02475 struct unistim_subchannel *sub_real;
02476
02477 sub_real = get_sub(pte->device, SUB_REAL);
02478 if (sub_real) {
02479 sub_hold(pte, sub_real);
02480 }
02481
02482 sub->moh = 0;
02483 sub->subtype = SUB_REAL;
02484 send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, pte);
02485 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
02486 send_start_timer(pte);
02487 if (sub->owner) {
02488 ast_queue_control_data(sub->owner, AST_CONTROL_UNHOLD, NULL, 0);
02489 if (sub->rtp) {
02490 send_start_rtp(sub);
02491 }
02492 }
02493 return;
02494 }
02495
02496 static void close_call(struct unistimsession *pte)
02497 {
02498 struct unistim_subchannel *sub, *sub_transf;
02499
02500 sub = get_sub(pte->device, SUB_REAL);
02501 sub_transf = get_sub(pte->device, SUB_THREEWAY);
02502 send_stop_timer(pte);
02503 if (!sub) {
02504 ast_log(LOG_WARNING, "Close call without sub\n");
02505 return;
02506 }
02507 send_favorite_short(sub->softkey, FAV_LINE_ICON, pte);
02508 if (sub->owner) {
02509 sub->alreadygone = 1;
02510 if (sub_transf) {
02511 sub_transf->alreadygone = 1;
02512 if (attempt_transfer(sub, sub_transf) < 0) {
02513 ast_verb(0, "attempt_transfer failed.\n");
02514 }
02515 } else {
02516 ast_queue_hangup(sub->owner);
02517 }
02518 } else {
02519 if (sub_transf) {
02520 if (sub_transf->owner) {
02521 ast_queue_hangup_with_cause(sub_transf->owner, AST_CAUSE_NORMAL_CLEARING);
02522 } else {
02523 ast_log(LOG_WARNING, "threeway sub without owner\n");
02524 }
02525 } else {
02526 ast_verb(0, "USTM(%s@%s-%d) channel already destroyed\n", sub->parent->name,
02527 pte->device->name, sub->softkey);
02528 }
02529 }
02530 change_callerid(pte, 0, pte->device->redial_number);
02531 change_callerid(pte, 1, "");
02532 write_history(pte, 'o', pte->device->missed_call);
02533 pte->device->missed_call = 0;
02534 show_main_page(pte);
02535 return;
02536 }
02537
02538 static void ignore_call(struct unistimsession *pte)
02539 {
02540 send_no_ring(pte);
02541 return;
02542 }
02543
02544 static void discard_call(struct unistimsession *pte)
02545 {
02546 struct unistim_subchannel* sub;
02547 sub = get_sub(pte->device, SUB_RING);
02548 if (!sub) {
02549 return;
02550 }
02551
02552 ast_queue_hangup_with_cause(sub->owner, AST_CAUSE_NORMAL_CLEARING);
02553 return;
02554 }
02555
02556 static void *unistim_ss(void *data)
02557 {
02558 struct ast_channel *chan = data;
02559 struct unistim_subchannel *sub = ast_channel_tech_pvt(chan);
02560 struct unistim_line *l = sub->parent;
02561 struct unistimsession *s = l->parent->session;
02562 int res;
02563
02564 ast_verb(3, "Starting switch on '%s@%s-%d' to %s\n", l->name, l->parent->name, sub->softkey, s->device->phone_number);
02565 ast_channel_exten_set(chan, s->device->phone_number);
02566 ast_copy_string(s->device->redial_number, s->device->phone_number,
02567 sizeof(s->device->redial_number));
02568 ast_setstate(chan, AST_STATE_RING);
02569 res = ast_pbx_run(chan);
02570 if (res) {
02571 ast_log(LOG_WARNING, "PBX exited non-zero\n");
02572 send_tone(s, 1000, 0);
02573 }
02574 return NULL;
02575 }
02576
02577 static int find_rtp_port(struct unistim_subchannel *s)
02578 {
02579 struct unistim_subchannel *sub = NULL;
02580 int rtp_start = s->parent->parent->rtp_port;
02581 struct ast_sockaddr us_tmp;
02582 struct sockaddr_in us = { 0, };
02583
02584 AST_LIST_LOCK(&s->parent->parent->subs);
02585 AST_LIST_TRAVERSE(&s->parent->parent->subs, sub, list) {
02586 if (!sub) {
02587 continue;
02588 }
02589 if (sub->rtp) {
02590 ast_rtp_instance_get_remote_address(sub->rtp, &us_tmp);
02591 ast_sockaddr_to_sin(&us_tmp, &us);
02592 if (htons(us.sin_port)) {
02593 rtp_start = htons(us.sin_port) + 1;
02594 break;
02595 }
02596 }
02597 }
02598 AST_LIST_UNLOCK(&s->parent->parent->subs);
02599 return rtp_start;
02600 }
02601
02602 static void send_start_rtp(struct unistim_subchannel *sub)
02603 {
02604 BUFFSEND;
02605
02606 int codec;
02607 struct sockaddr_in public = { 0, };
02608 struct sockaddr_in us = { 0, };
02609 struct sockaddr_in sin = { 0, };
02610 struct ast_sockaddr us_tmp;
02611 struct ast_sockaddr sin_tmp;
02612 struct unistimsession *pte;
02613
02614 ast_rtp_instance_get_local_address(sub->rtp, &us_tmp);
02615 ast_sockaddr_to_sin(&us_tmp, &us);
02616 ast_rtp_instance_get_remote_address(sub->rtp, &sin_tmp);
02617 ast_sockaddr_to_sin(&sin_tmp, &sin);
02618
02619
02620 if (public_ip.sin_family == 0) {
02621 memcpy(&public, &us, sizeof(public));
02622 } else {
02623 memcpy(&public, &public_ip, sizeof(public));
02624 }
02625 if (unistimdebug) {
02626 ast_verb(0, "RTP started : Our IP/port is : %s:%hd with codec %s\n",
02627 ast_inet_ntoa(us.sin_addr),
02628 htons(us.sin_port), ast_getformatname(ast_channel_readformat(sub->owner)));
02629 ast_verb(0, "Starting phone RTP stack. Our public IP is %s\n",
02630 ast_inet_ntoa(public.sin_addr));
02631 }
02632
02633 pte = sub->parent->parent->session;
02634 codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, ast_channel_readformat(sub->owner), 0);
02635 if ((ast_channel_readformat(sub->owner)->id == AST_FORMAT_ULAW) ||
02636 (ast_channel_readformat(sub->owner)->id == AST_FORMAT_ALAW)) {
02637 if (unistimdebug) {
02638 ast_verb(0, "Sending packet_send_rtp_packet_size for codec %d\n", codec);
02639 }
02640 memcpy(buffsend + SIZE_HEADER, packet_send_rtp_packet_size,
02641 sizeof(packet_send_rtp_packet_size));
02642 buffsend[10] = (int) codec & 0xffffffffLL;
02643 send_client(SIZE_HEADER + sizeof(packet_send_rtp_packet_size), buffsend, pte);
02644 }
02645 if (unistimdebug) {
02646 ast_verb(0, "Sending Jitter Buffer Parameters Configuration\n");
02647 }
02648 memcpy(buffsend + SIZE_HEADER, packet_send_jitter_buffer_conf,
02649 sizeof(packet_send_jitter_buffer_conf));
02650 send_client(SIZE_HEADER + sizeof(packet_send_jitter_buffer_conf), buffsend, pte);
02651 if (pte->device->rtp_method != 0) {
02652 uint16_t rtcpsin_port = htons(us.sin_port) + 1;
02653
02654 if (unistimdebug) {
02655 ast_verb(0, "Sending OpenAudioStreamTX using method #%d\n", pte->device->rtp_method);
02656 }
02657 if (pte->device->rtp_method == 3) {
02658 memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_tx3,
02659 sizeof(packet_send_open_audio_stream_tx3));
02660 } else {
02661 memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_tx,
02662 sizeof(packet_send_open_audio_stream_tx));
02663 }
02664 if (pte->device->rtp_method != 2) {
02665 memcpy(buffsend + 28, &public.sin_addr, sizeof(public.sin_addr));
02666 buffsend[20] = (htons(sin.sin_port) & 0xff00) >> 8;
02667 buffsend[21] = (htons(sin.sin_port) & 0x00ff);
02668 buffsend[23] = (rtcpsin_port & 0x00ff);
02669 buffsend[22] = (rtcpsin_port & 0xff00) >> 8;
02670 buffsend[25] = (us.sin_port & 0xff00) >> 8;
02671 buffsend[24] = (us.sin_port & 0x00ff);
02672 buffsend[27] = (rtcpsin_port & 0x00ff);
02673 buffsend[26] = (rtcpsin_port & 0xff00) >> 8;
02674 } else {
02675 memcpy(buffsend + 23, &public.sin_addr, sizeof(public.sin_addr));
02676 buffsend[15] = (htons(sin.sin_port) & 0xff00) >> 8;
02677 buffsend[16] = (htons(sin.sin_port) & 0x00ff);
02678 buffsend[20] = (us.sin_port & 0xff00) >> 8;
02679 buffsend[19] = (us.sin_port & 0x00ff);
02680 buffsend[11] = codec;
02681 }
02682 buffsend[12] = codec;
02683 send_client(SIZE_HEADER + sizeof(packet_send_open_audio_stream_tx), buffsend, pte);
02684
02685 if (unistimdebug) {
02686 ast_verb(0, "Sending OpenAudioStreamRX\n");
02687 }
02688 if (pte->device->rtp_method == 3) {
02689 memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_rx3,
02690 sizeof(packet_send_open_audio_stream_rx3));
02691 } else {
02692 memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_rx,
02693 sizeof(packet_send_open_audio_stream_rx));
02694 }
02695 if (pte->device->rtp_method != 2) {
02696 memcpy(buffsend + 28, &public.sin_addr, sizeof(public.sin_addr));
02697 buffsend[20] = (htons(sin.sin_port) & 0xff00) >> 8;
02698 buffsend[21] = (htons(sin.sin_port) & 0x00ff);
02699 buffsend[23] = (rtcpsin_port & 0x00ff);
02700 buffsend[22] = (rtcpsin_port & 0xff00) >> 8;
02701 buffsend[25] = (us.sin_port & 0xff00) >> 8;
02702 buffsend[24] = (us.sin_port & 0x00ff);
02703 buffsend[27] = (rtcpsin_port & 0x00ff);
02704 buffsend[26] = (rtcpsin_port & 0xff00) >> 8;
02705 } else {
02706 memcpy(buffsend + 23, &public.sin_addr, sizeof(public.sin_addr));
02707 buffsend[15] = (htons(sin.sin_port) & 0xff00) >> 8;
02708 buffsend[16] = (htons(sin.sin_port) & 0x00ff);
02709 buffsend[20] = (us.sin_port & 0xff00) >> 8;
02710 buffsend[19] = (us.sin_port & 0x00ff);
02711 buffsend[12] = codec;
02712 }
02713 buffsend[11] = codec;
02714 send_client(SIZE_HEADER + sizeof(packet_send_open_audio_stream_rx), buffsend, pte);
02715 } else {
02716 uint16_t rtcpsin_port = htons(us.sin_port) + 1;
02717
02718 if (unistimdebug) {
02719 ast_verb(0, "Sending packet_send_call default method\n");
02720 }
02721
02722 memcpy(buffsend + SIZE_HEADER, packet_send_call, sizeof(packet_send_call));
02723 memcpy(buffsend + 53, &public.sin_addr, sizeof(public.sin_addr));
02724
02725 buffsend[49] = (us.sin_port & 0x00ff);
02726 buffsend[50] = (us.sin_port & 0xff00) >> 8;
02727
02728 buffsend[52] = (rtcpsin_port & 0x00ff);
02729 buffsend[51] = (rtcpsin_port & 0xff00) >> 8;
02730
02731 buffsend[40] = codec;
02732 buffsend[41] = codec;
02733 if (ast_channel_readformat(sub->owner)->id == AST_FORMAT_ULAW) {
02734 buffsend[42] = 1;
02735 } else if (ast_channel_readformat(sub->owner)->id == AST_FORMAT_ALAW) {
02736 buffsend[42] = 1;
02737 } else if (ast_channel_readformat(sub->owner)->id == AST_FORMAT_G723_1) {
02738 buffsend[42] = 2;
02739 } else if (ast_channel_readformat(sub->owner)->id == AST_FORMAT_G729A) {
02740 buffsend[42] = 2;
02741 } else {
02742 ast_log(LOG_WARNING, "Unsupported codec %s!\n",
02743 ast_getformatname(ast_channel_readformat(sub->owner)));
02744 }
02745
02746 buffsend[45] = (htons(sin.sin_port) & 0xff00) >> 8;
02747 buffsend[46] = (htons(sin.sin_port) & 0x00ff);
02748 buffsend[47] = (rtcpsin_port & 0xff00) >> 8;
02749 buffsend[48] = (rtcpsin_port & 0x00ff);
02750 send_client(SIZE_HEADER + sizeof(packet_send_call), buffsend, pte);
02751 }
02752 }
02753
02754 static void start_rtp(struct unistim_subchannel *sub)
02755 {
02756 struct sockaddr_in sin = { 0, };
02757 struct sockaddr_in sout = { 0, };
02758 struct ast_sockaddr sin_tmp;
02759 struct ast_sockaddr sout_tmp;
02760
02761
02762 if (!sub) {
02763 ast_log(LOG_WARNING, "start_rtp with a null subchannel !\n");
02764 return;
02765 }
02766 if (!sub->parent) {
02767 ast_log(LOG_WARNING, "start_rtp with a null line!\n");
02768 return;
02769 }
02770 if (!sub->parent->parent) {
02771 ast_log(LOG_WARNING, "start_rtp with a null device!\n");
02772 return;
02773 }
02774 if (!sub->parent->parent->session) {
02775 ast_log(LOG_WARNING, "start_rtp with a null session!\n");
02776 return;
02777 }
02778 if (!sub->owner) {
02779 ast_log(LOG_WARNING, "start_rtp with a null asterisk channel!\n");
02780 return;
02781 }
02782 sout = sub->parent->parent->session->sout;
02783 ast_mutex_lock(&sub->lock);
02784
02785 if (unistimdebug) {
02786 ast_verb(0, "Starting RTP. Bind on %s\n", ast_inet_ntoa(sout.sin_addr));
02787 }
02788 ast_sockaddr_from_sin(&sout_tmp, &sout);
02789 sub->rtp = ast_rtp_instance_new("asterisk", sched, &sout_tmp, NULL);
02790 if (!sub->rtp) {
02791 ast_log(LOG_WARNING, "Unable to create RTP session: %s binaddr=%s\n",
02792 strerror(errno), ast_inet_ntoa(sout.sin_addr));
02793 ast_mutex_unlock(&sub->lock);
02794 return;
02795 }
02796 ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_RTCP, 1);
02797 ast_channel_internal_fd_set(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
02798 ast_channel_internal_fd_set(sub->owner, 1, ast_rtp_instance_fd(sub->rtp, 1));
02799 ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "UNISTIM RTP");
02800 ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, sub->parent->parent->nat);
02801
02802
02803 sin.sin_family = AF_INET;
02804
02805 memcpy(&sin.sin_addr, &sub->parent->parent->session->sin.sin_addr,
02806 sizeof(sin.sin_addr));
02807
02808 sin.sin_port = htons(find_rtp_port(sub));
02809 ast_sockaddr_from_sin(&sin_tmp, &sin);
02810 ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
02811 if (!ast_format_cap_iscompatible(ast_channel_nativeformats(sub->owner), ast_channel_readformat(sub->owner))) {
02812 struct ast_format tmpfmt;
02813 char tmp[256];
02814 ast_best_codec(ast_channel_nativeformats(sub->owner), &tmpfmt);
02815 ast_log(LOG_WARNING,
02816 "Our read/writeformat has been changed to something incompatible: %s, using %s best codec from %s\n",
02817 ast_getformatname(ast_channel_readformat(sub->owner)),
02818 ast_getformatname(&tmpfmt),
02819 ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(sub->owner)));
02820
02821 ast_format_copy(ast_channel_readformat(sub->owner), &tmpfmt);
02822 ast_format_copy(ast_channel_writeformat(sub->owner), &tmpfmt);
02823 }
02824 send_start_rtp(sub);
02825 ast_mutex_unlock(&sub->lock);
02826 }
02827
02828 static void send_dial_tone(struct unistimsession *pte)
02829 {
02830 struct ast_tone_zone_sound *ts = NULL;
02831 struct ast_tone_zone_part tone_data;
02832 char *s = NULL;
02833 char *ind;
02834
02835 if ((ts = ast_get_indication_tone(pte->device->tz, "dial"))) {
02836 ind = ast_strdupa(ts->data);
02837 s = strsep(&ind, ",");
02838 ast_tone_zone_part_parse(s, &tone_data);
02839 if (tone_data.modulate) {
02840 tone_data.freq2 = 0;
02841 }
02842 send_tone(pte, tone_data.freq1, tone_data.freq2);
02843 if (unistimdebug) {
02844 ast_verb(0, "Country code found (%s), freq1=%d freq2=%d\n",
02845 pte->device->tz->country, tone_data.freq1, tone_data.freq2);
02846 }
02847 ts = ast_tone_zone_sound_unref(ts);
02848 }
02849 }
02850
02851 static void show_phone_number(struct unistimsession *pte)
02852 {
02853 char tmp[TEXT_LENGTH_MAX + 1];
02854 const char *tmp_number = ustmtext("Number:", pte);
02855 int line, tmp_copy, offset = 0, i;
02856
02857 pte->device->phone_number[pte->device->size_phone_number] = '\0';
02858 if (pte->device->size_phone_number > MAX_SCREEN_NUMBER) {
02859 offset = pte->device->size_phone_number - MAX_SCREEN_NUMBER - 1;
02860 if (offset > strlen(tmp_number)) {
02861 offset = strlen(tmp_number);
02862 }
02863 tmp_copy = strlen(tmp_number) - offset + 1;
02864 if (tmp_copy > sizeof(tmp)) {
02865 tmp_copy = sizeof(tmp);
02866 }
02867 memcpy(tmp, tmp_number + offset, tmp_copy);
02868 } else {
02869 ast_copy_string(tmp, tmp_number, sizeof(tmp));
02870 }
02871
02872 offset = (pte->device->size_phone_number >= TEXT_LENGTH_MAX) ? (pte->device->size_phone_number - TEXT_LENGTH_MAX +1) : 0;
02873 if (pte->device->size_phone_number) {
02874 memcpy(tmp + strlen(tmp), pte->device->phone_number + offset, pte->device->size_phone_number - offset + 1);
02875 }
02876 offset = strlen(tmp);
02877
02878 for (i = strlen(tmp); i < TEXT_LENGTH_MAX; i++) {
02879 tmp[i] = '.';
02880 }
02881 tmp[i] = '\0';
02882
02883 line = (pte->device->height == 1) ? TEXT_LINE0 : TEXT_LINE2;
02884 send_text(line, TEXT_NORMAL, pte, tmp);
02885 send_blink_cursor(pte);
02886 send_cursor_pos(pte, (unsigned char) (line + offset));
02887 send_led_update(pte, 0);
02888 }
02889
02890 static void handle_dial_page(struct unistimsession *pte)
02891 {
02892 pte->state = STATE_DIALPAGE;
02893 if (pte->device->call_forward[0] == -1) {
02894 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "");
02895 send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Enter forward", pte));
02896 send_text_status(pte, ustmtext("Fwd Cancel BackSp Erase", pte));
02897 if (pte->device->call_forward[1] != 0) {
02898 ast_copy_string(pte->device->phone_number, pte->device->call_forward + 1,
02899 sizeof(pte->device->phone_number));
02900 show_phone_number(pte);
02901 send_led_update(pte, 0);
02902 return;
02903 }
02904 } else {
02905 if ((pte->device->output == OUTPUT_HANDSET) &&
02906 (pte->device->receiver_state == STATE_ONHOOK)) {
02907 send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
02908 } else {
02909 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
02910 }
02911 send_dial_tone(pte);
02912
02913 if (pte->device->height > 1) {
02914 send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Enter the number to dial", pte));
02915 send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("and press Call", pte));
02916 }
02917 send_text_status(pte, ustmtext("Call Redial BackSp Erase", pte));
02918 }
02919
02920 pte->device->size_phone_number = 0;
02921 pte->device->phone_number[0] = 0;
02922 show_phone_number(pte);
02923 change_favorite_icon(pte, FAV_ICON_PHONE_BLACK);
02924 send_icon(TEXT_LINE0, FAV_ICON_NONE, pte);
02925 pte->device->missed_call = 0;
02926 send_led_update(pte, 0);
02927 return;
02928 }
02929
02930 static void swap_subs(struct unistim_subchannel *a, struct unistim_subchannel *b)
02931 {
02932 struct ast_rtp_instance *rtp;
02933 int fds;
02934
02935 if (unistimdebug) {
02936 ast_verb(0, "Swapping %p and %p\n", a, b);
02937 }
02938 if ((!a->owner) || (!b->owner)) {
02939 ast_log(LOG_WARNING,
02940 "Attempted to swap subchannels with a null owner : sub #%p=%p sub #%p=%p\n",
02941 a, a->owner, b, b->owner);
02942 return;
02943 }
02944 rtp = a->rtp;
02945 a->rtp = b->rtp;
02946 b->rtp = rtp;
02947
02948 fds = ast_channel_fd(a->owner, 0);
02949 ast_channel_internal_fd_set(a->owner, 0, ast_channel_fd(b->owner, 0));
02950 ast_channel_internal_fd_set(b->owner, 0, fds);
02951
02952 fds = ast_channel_fd(a->owner, 1);
02953 ast_channel_internal_fd_set(a->owner, 1, ast_channel_fd(b->owner, 1));
02954 ast_channel_internal_fd_set(b->owner, 1, fds);
02955 }
02956
02957
02958 static void transfer_call_step1(struct unistimsession *pte)
02959 {
02960 struct unistim_subchannel *sub ;
02961 struct unistim_device *d = pte->device;
02962
02963 sub = get_sub(d, SUB_REAL);
02964
02965
02966 if (!sub || !sub->owner) {
02967 ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
02968 return;
02969 }
02970
02971 if (sub->moh) {
02972 ast_log(LOG_WARNING, "Transfer with peer already listening music on hold\n");
02973 } else {
02974 if (ast_bridged_channel(sub->owner)) {
02975 ast_moh_start(ast_bridged_channel(sub->owner),
02976 sub->parent->musicclass, NULL);
02977 sub->moh = 1;
02978 sub->subtype = SUB_THREEWAY;
02979 } else {
02980 ast_log(LOG_WARNING, "Unable to find peer subchannel for music on hold\n");
02981 return;
02982 }
02983 }
02984 sub_start_silence(pte, sub);
02985 handle_dial_page(pte);
02986 }
02987
02988 static void transfer_cancel_step2(struct unistimsession *pte)
02989 {
02990 struct unistim_subchannel *sub, *sub_trans;
02991 struct unistim_device *d = pte->device;
02992
02993 sub = get_sub(d, SUB_REAL);
02994 sub_trans = get_sub(d, SUB_THREEWAY);
02995
02996 if (!sub || !sub->owner) {
02997 ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
02998 return;
02999 }
03000 if (sub_trans) {
03001 if (unistimdebug) {
03002 ast_verb(0, "Transfer canceled, hangup our threeway channel\n");
03003 }
03004 if (sub->owner) {
03005 swap_subs(sub, sub_trans);
03006 ast_moh_stop(ast_bridged_channel(sub_trans->owner));
03007 sub_trans->moh = 0;
03008 sub_trans->subtype = SUB_REAL;
03009 sub->subtype = SUB_THREEWAY;
03010 ast_queue_hangup_with_cause(sub->owner, AST_CAUSE_NORMAL_CLEARING);
03011 } else {
03012 ast_log(LOG_WARNING, "Canceling a threeway channel without owner\n");
03013 }
03014 return;
03015 }
03016 }
03017
03018
03019 static void handle_call_outgoing(struct unistimsession *s)
03020 {
03021 struct ast_channel *c;
03022 struct unistim_subchannel *sub;
03023 int softkey;
03024
03025 s->state = STATE_CALL;
03026
03027 sub = get_sub(s->device, SUB_THREEWAY);
03028 if (sub) {
03029
03030 struct unistim_subchannel *sub_trans = NULL;
03031 struct unistim_device *d = s->device;
03032
03033 sub_trans = get_sub(d, SUB_REAL);
03034 if (sub_trans) {
03035 ast_log(LOG_WARNING, "Can't transfer while active subchannel exists!\n");
03036 return;
03037 }
03038 if (!sub->owner) {
03039 ast_log(LOG_WARNING, "Unable to find subchannel with music on hold\n");
03040 return;
03041 }
03042
03043 sub_trans = unistim_alloc_sub(d, SUB_REAL);
03044 if (!sub_trans) {
03045 ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
03046 return;
03047 }
03048 sub_trans->parent = sub->parent;
03049 sub_stop_silence(s, sub);
03050 send_tone(s, 0, 0);
03051
03052 c = unistim_new(sub_trans, AST_STATE_DOWN, NULL);
03053 if (!c) {
03054 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %p\n", sub->parent);
03055 return;
03056 }
03057
03058 swap_subs(sub, sub_trans);
03059 send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
03060 if (s->device->height == 1) {
03061 send_text(TEXT_LINE0, TEXT_NORMAL, s, s->device->phone_number);
03062 } else {
03063 send_text(TEXT_LINE0, TEXT_NORMAL, s, ustmtext("Calling (pre-transfer)", s));
03064 send_text(TEXT_LINE1, TEXT_NORMAL, s, s->device->phone_number);
03065 send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Dialing...", s));
03066 }
03067 send_text_status(s, ustmtext("TransfrCancel", s));
03068
03069 if (ast_pthread_create(&sub->ss_thread, NULL, unistim_ss, c)) {
03070 ast_log(LOG_WARNING, "Unable to start simple switch on channel %p\n", c);
03071 sub->ss_thread = AST_PTHREADT_NULL;
03072 ast_hangup(c);
03073 return;
03074 }
03075 if (unistimdebug) {
03076 ast_verb(0, "Started three way call on channel %p (%s) subchan %d\n",
03077 sub_trans->owner, ast_channel_name(sub_trans->owner), sub_trans->subtype);
03078 }
03079 return;
03080 }
03081
03082 softkey = get_avail_softkey(s, NULL);
03083 if (softkey == -1) {
03084 ast_log(LOG_WARNING, "Have no avail softkey for calling\n");
03085 return;
03086 }
03087 sub = get_sub(s->device, SUB_REAL);
03088 if (sub) {
03089 sub_hold(s, sub);
03090 }
03091 if (!(sub = unistim_alloc_sub(s->device, SUB_REAL))) {
03092 ast_log(LOG_WARNING, "Unable to allocate subchannel!\n");
03093 return;
03094 }
03095 sub->parent = s->device->sline[softkey];
03096 s->device->ssub[softkey] = sub;
03097 sub->softkey = softkey;
03098
03099 if (unistimdebug) {
03100 ast_verb(0, "Using softkey %d, line %p\n", sub->softkey, sub->parent);
03101 }
03102 send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, s);
03103 s->device->selected = -1;
03104 if (!sub->owner) {
03105 c = unistim_new(sub, AST_STATE_DOWN, NULL);
03106 if (!sub->rtp) {
03107 start_rtp(sub);
03108 }
03109 if (c && !strcmp(s->device->phone_number, ast_pickup_ext())) {
03110 if (unistimdebug) {
03111 ast_verb(0, "Try to pickup in unistim_new\n");
03112 }
03113 send_text(TEXT_LINE0, TEXT_NORMAL, s, "");
03114 send_text_status(s, ustmtext(" Transf Hangup", s));
03115 send_start_timer(s);
03116 if (ast_pickup_call(c)) {
03117 ast_log(LOG_NOTICE, "Nothing to pick up\n");
03118 ast_channel_hangupcause_set(c, AST_CAUSE_CALL_REJECTED);
03119 } else {
03120 ast_channel_hangupcause_set(c, AST_CAUSE_NORMAL_CLEARING);
03121 }
03122 ast_hangup(c);
03123 c = NULL;
03124 } else if (c) {
03125 send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
03126 send_tone(s, 0, 0);
03127 if (s->device->height == 1) {
03128 if (strlen(s->device->phone_number) > 0) {
03129 send_text(TEXT_LINE0, TEXT_NORMAL, s, s->device->phone_number);
03130 } else {
03131 send_text(TEXT_LINE0, TEXT_NORMAL, s, ustmtext("Calling...", s));
03132 }
03133 } else {
03134 send_text(TEXT_LINE0, TEXT_NORMAL, s, ustmtext("Calling :", s));
03135 send_text(TEXT_LINE1, TEXT_NORMAL, s, s->device->phone_number);
03136 send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Dialing...", s));
03137 }
03138 send_text_status(s, ustmtext(" Hangup", s));
03139
03140
03141 if (ast_pthread_create(&sub->ss_thread, NULL, unistim_ss, c)) {
03142 ast_log(LOG_WARNING, "Unable to create switch thread\n");
03143 sub->ss_thread = AST_PTHREADT_NULL;
03144 ast_queue_hangup_with_cause(c, AST_CAUSE_SWITCH_CONGESTION);
03145 }
03146 } else
03147 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n",
03148 sub->parent->name, s->device->name);
03149 } else {
03150 ast_debug(1, "Current sub [%s] already has owner\n", ast_channel_name(sub->owner));
03151 }
03152 return;
03153 }
03154
03155
03156 static void handle_call_incoming(struct unistimsession *s)
03157 {
03158 struct unistim_subchannel *sub = NULL;
03159 int i;
03160
03161 s->state = STATE_CALL;
03162 s->device->missed_call = 0;
03163 send_no_ring(s);
03164 sub = get_sub(s->device, SUB_RING);
03165 if (!sub) {
03166 ast_log(LOG_WARNING, "No ringing lines on: %s\n", s->device->name);
03167 return;
03168 }
03169
03170 for (i = 0; i < FAVNUM; i++) {
03171 if (!s->device->ssub[i]) {
03172 continue;
03173 }
03174 if (s->device->ssub[i]->subtype == SUB_REAL) {
03175 sub_hold(s, s->device->ssub[i]);
03176 }
03177 if (s->device->ssub[i] != sub) {
03178 continue;
03179 }
03180 if (sub->softkey == i) {
03181 continue;
03182 }
03183 if (sub->softkey < 0) {
03184 sub->softkey = i;
03185 continue;
03186 }
03187 send_favorite_short(i, FAV_LINE_ICON, s);
03188 s->device->ssub[i] = NULL;
03189 }
03190 if (sub->softkey < 0) {
03191 ast_log(LOG_WARNING, "Can not assign softkey for incoming call on: %s\n", s->device->name);
03192 return;
03193 }
03194 send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, s);
03195 sub->parent = s->device->sline[sub->softkey];
03196 sub->subtype = SUB_REAL;
03197 if (unistimdebug) {
03198 ast_verb(0, "Handle Call Incoming for %s@%s\n", sub->parent->name,
03199 s->device->name);
03200 }
03201 start_rtp(sub);
03202 if (!sub->rtp) {
03203 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name,
03204 s->device->name);
03205 }
03206 if (sub->owner) {
03207 ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
03208 }
03209 send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("is on-line", s));
03210 send_text_status(s, ustmtext(" Transf Hangup", s));
03211 send_start_timer(s);
03212
03213 if ((s->device->output == OUTPUT_HANDSET) &&
03214 (s->device->receiver_state == STATE_ONHOOK)) {
03215 send_select_output(s, OUTPUT_SPEAKER, s->device->volume, MUTE_OFF);
03216 } else {
03217 send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
03218 }
03219 write_history(s, 'i', 0);
03220 return;
03221 }
03222
03223 static int unistim_do_senddigit(struct unistimsession *pte, char digit)
03224 {
03225 struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass.integer = digit, .src = "unistim" };
03226 struct unistim_subchannel *sub;
03227 int row, col;
03228
03229 sub = get_sub(pte->device, SUB_REAL);
03230 if (!sub || !sub->owner || sub->alreadygone) {
03231 ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit\n");
03232 return -1;
03233 }
03234
03235
03236 ast_queue_frame(sub->owner, &f);
03237
03238 if (unistimdebug) {
03239 ast_verb(0, "Send Digit %c\n", digit);
03240 }
03241 row = (digit - '1') % 3;
03242 col = (digit - '1' - row) / 3;
03243 if (digit >= '1' && digit <='9') {
03244 send_tone(pte, dtmf_row[row], dtmf_col[col]);
03245 } else if (digit >= 'A' && digit <= 'D') {
03246 send_tone(pte, dtmf_row[digit-'A'], dtmf_col[3]);
03247 } else if (digit == '*') {
03248 send_tone(pte, dtmf_row[3], dtmf_col[0]);
03249 } else if (digit == '0') {
03250 send_tone(pte, dtmf_row[3], dtmf_col[1]);
03251 } else if (digit == '#') {
03252 send_tone(pte, dtmf_row[3], dtmf_col[2]);
03253 } else {
03254 send_tone(pte, 500, 2000);
03255 }
03256 usleep(150000);
03257 send_tone(pte, 0, 0);
03258 return 0;
03259 }
03260
03261 static void handle_key_fav(struct unistimsession *pte, char keycode)
03262 {
03263 int keynum = keycode - KEY_FAV0;
03264 struct unistim_subchannel *sub;
03265
03266 sub = get_sub(pte->device, SUB_REAL);
03267
03268
03269 if (!pte->device->ssub[keynum]) {
03270 send_favorite_selected(FAV_LINE_ICON, pte);
03271 if (is_key_line(pte->device, keynum)) {
03272 if (unistimdebug) {
03273 ast_verb(0, "Handle line w/o sub - dialpage\n");
03274 }
03275 pte->device->selected = keynum;
03276 sub_hold(pte, sub);
03277 send_stop_timer(pte);
03278 handle_dial_page(pte);
03279 } else if (is_key_favorite(pte->device, keynum)) {
03280
03281
03282 if (unistimdebug) {
03283 ast_verb(0, "Handle favorite w/o sub - dialing\n");
03284 }
03285 if ((pte->device->output == OUTPUT_HANDSET) &&
03286 (pte->device->receiver_state == STATE_ONHOOK)) {
03287 send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
03288 } else {
03289 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
03290 }
03291 key_favorite(pte, keycode);
03292 }
03293 } else {
03294 sub = pte->device->ssub[keynum];
03295
03296 if (sub->subtype == SUB_REAL) {
03297 sub_hold(pte, sub);
03298 show_main_page(pte);
03299 } else if (sub->subtype == SUB_RING) {
03300 sub->softkey = keynum;
03301 handle_call_incoming(pte);
03302 } else if (sub->subtype == SUB_ONHOLD) {
03303 if (pte->state == STATE_DIALPAGE){
03304 send_tone(pte, 0, 0);
03305 }
03306 send_callerid_screen(pte, sub);
03307 sub_unhold(pte, sub);
03308 pte->state = STATE_CALL;
03309 }
03310 }
03311 }
03312
03313 static void key_call(struct unistimsession *pte, char keycode)
03314 {
03315 struct unistim_subchannel *sub = NULL;
03316 if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
03317 if (keycode == KEY_SHARP) {
03318 keycode = '#';
03319 } else if (keycode == KEY_STAR) {
03320 keycode = '*';
03321 } else {
03322 keycode -= 0x10;
03323 }
03324 unistim_do_senddigit(pte, keycode);
03325 return;
03326 }
03327 switch (keycode) {
03328 case KEY_FUNC1:
03329 if (get_sub(pte->device, SUB_THREEWAY)) {
03330 close_call(pte);
03331 }
03332 break;
03333 case KEY_FUNC2:
03334 if (get_sub(pte->device, SUB_THREEWAY)) {
03335 transfer_cancel_step2(pte);
03336 } else {
03337 transfer_call_step1(pte);
03338 }
03339 break;
03340 case KEY_HANGUP:
03341 case KEY_FUNC4:
03342 if (!get_sub(pte->device, SUB_THREEWAY)) {
03343 close_call(pte);
03344 }
03345 break;
03346 case KEY_FAV0:
03347 case KEY_FAV1:
03348 case KEY_FAV2:
03349 case KEY_FAV3:
03350 case KEY_FAV4:
03351 case KEY_FAV5:
03352 handle_key_fav(pte, keycode);
03353 break;
03354 case KEY_HEADPHN:
03355 if (pte->device->output == OUTPUT_HEADPHONE) {
03356 send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
03357 } else {
03358 send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
03359 }
03360 break;
03361 case KEY_LOUDSPK:
03362 if (pte->device->output != OUTPUT_SPEAKER)
03363 send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
03364 else
03365 send_select_output(pte, pte->device->previous_output, pte->device->volume,
03366 MUTE_OFF);
03367 break;
03368 case KEY_MUTE:
03369 sub = get_sub(pte->device, SUB_REAL);
03370 if (!sub || !sub->owner) {
03371 ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
03372 return;
03373 }
03374 if (!sub->moh) {
03375 if (pte->device->mute == MUTE_ON) {
03376 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
03377 } else {
03378 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON);
03379 }
03380 break;
03381 }
03382 break;
03383 case KEY_ONHOLD:
03384 sub = get_sub(pte->device, SUB_REAL);
03385 if (!sub) {
03386 if(pte->device->ssub[pte->device->selected]) {
03387 sub_hold(pte, pte->device->ssub[pte->device->selected]);
03388 }
03389 } else {
03390 sub_hold(pte, sub);
03391 }
03392 break;
03393 }
03394 return;
03395 }
03396
03397 static void key_ringing(struct unistimsession *pte, char keycode)
03398 {
03399 switch (keycode) {
03400 case KEY_FAV0:
03401 case KEY_FAV1:
03402 case KEY_FAV2:
03403 case KEY_FAV3:
03404 case KEY_FAV4:
03405 case KEY_FAV5:
03406 handle_key_fav(pte, keycode);
03407 break;
03408 case KEY_FUNC3:
03409 ignore_call(pte);
03410 break;
03411 case KEY_HANGUP:
03412 case KEY_FUNC4:
03413 discard_call(pte);
03414 break;
03415 case KEY_LOUDSPK:
03416 pte->device->output = OUTPUT_SPEAKER;
03417 handle_call_incoming(pte);
03418 break;
03419 case KEY_HEADPHN:
03420 pte->device->output = OUTPUT_HEADPHONE;
03421 handle_call_incoming(pte);
03422 break;
03423 case KEY_FUNC1:
03424 handle_call_incoming(pte);
03425 break;
03426 }
03427 return;
03428 }
03429
03430 static void key_favorite(struct unistimsession *pte, char keycode)
03431 {
03432 int fav = keycode - KEY_FAV0;
03433 if (!is_key_favorite(pte->device, fav)) {
03434 ast_log(LOG_WARNING, "It's not a favorite key\n");
03435 return;
03436 }
03437 ast_copy_string(pte->device->phone_number, pte->device->softkeynumber[fav],
03438 sizeof(pte->device->phone_number));
03439 handle_call_outgoing(pte);
03440 return;
03441 }
03442
03443 static void key_dial_page(struct unistimsession *pte, char keycode)
03444 {
03445 struct unistim_subchannel *sub = get_sub(pte->device, SUB_THREEWAY);
03446
03447 pte->device->nextdial = 0;
03448 if (keycode == KEY_FUNC3) {
03449 if (pte->device->size_phone_number <= 1) {
03450 keycode = KEY_FUNC4;
03451 } else {
03452 pte->device->size_phone_number -= 2;
03453 keycode = pte->device->phone_number[pte->device->size_phone_number] + 0x10;
03454 }
03455 }
03456 if (keycode == KEY_SHARP && pte->device->sharp_dial == 1) {
03457 keycode = KEY_FUNC1;
03458 }
03459 if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
03460 int i = pte->device->size_phone_number;
03461
03462 if (pte->device->size_phone_number == 0) {
03463 send_tone(pte, 0, 0);
03464 }
03465 if (keycode == KEY_SHARP) {
03466 keycode = '#';
03467 } else if (keycode == KEY_STAR) {
03468 keycode = '*';
03469 } else {
03470 keycode -= 0x10;
03471 }
03472 pte->device->phone_number[i] = keycode;
03473 pte->device->size_phone_number++;
03474 pte->device->phone_number[i + 1] = 0;
03475 show_phone_number(pte);
03476
03477 if (ast_exists_extension(NULL, pte->device->context, pte->device->phone_number, 1, NULL) &&
03478 !ast_matchmore_extension(NULL, pte->device->context, pte->device->phone_number, 1, NULL)) {
03479 keycode = KEY_FUNC1;
03480 } else {
03481 pte->device->nextdial = get_tick_count() + TIMER_DIAL;
03482 }
03483 }
03484 if (keycode == KEY_FUNC4) {
03485 pte->device->size_phone_number = 0;
03486 show_phone_number(pte);
03487 return;
03488 }
03489
03490 if (pte->device->call_forward[0] == -1) {
03491 if (keycode == KEY_FUNC1) {
03492 ast_copy_string(pte->device->call_forward, pte->device->phone_number,
03493 sizeof(pte->device->call_forward));
03494 show_main_page(pte);
03495 } else if ((keycode == KEY_FUNC2) || (keycode == KEY_HANGUP)) {
03496 pte->device->call_forward[0] = '\0';
03497 send_led_update(pte, 0x08);
03498 send_led_update(pte, 0x10);
03499 show_main_page(pte);
03500 }
03501 return;
03502 }
03503 switch (keycode) {
03504 case KEY_FUNC2:
03505 if (ast_strlen_zero(pte->device->redial_number)) {
03506 break;
03507 }
03508 ast_copy_string(pte->device->phone_number, pte->device->redial_number,
03509 sizeof(pte->device->phone_number));
03510 case KEY_FUNC1:
03511 handle_call_outgoing(pte);
03512 break;
03513 case KEY_HANGUP:
03514 if (sub && sub->owner) {
03515 struct ast_channel *bridgepeer = NULL;
03516
03517 sub_stop_silence(pte, sub);
03518 send_tone(pte, 0, 0);
03519 if ((bridgepeer = ast_bridged_channel(sub->owner))) {
03520 ast_moh_stop(bridgepeer);
03521 }
03522 sub->moh = 0;
03523 sub->subtype = SUB_REAL;
03524 pte->state = STATE_CALL;
03525
03526 send_text_status(pte, ustmtext(" Transf Hangup", pte));
03527 send_callerid_screen(pte, sub);
03528 } else {
03529 send_led_update(pte, 0x08);
03530 send_led_update(pte, 0x10);
03531 show_main_page(pte);
03532 }
03533 break;
03534 case KEY_FAV0:
03535 case KEY_FAV1:
03536 case KEY_FAV2:
03537 case KEY_FAV3:
03538 case KEY_FAV4:
03539 case KEY_FAV5:
03540 send_favorite_selected(FAV_LINE_ICON, pte);
03541 pte->device->selected = -1;
03542 handle_key_fav(pte, keycode);
03543 break;
03544 case KEY_LOUDSPK:
03545 if (pte->device->output == OUTPUT_SPEAKER) {
03546 if (pte->device->receiver_state == STATE_OFFHOOK) {
03547 send_select_output(pte, pte->device->previous_output, pte->device->volume,
03548 MUTE_OFF);
03549 } else {
03550 show_main_page(pte);
03551 }
03552 } else {
03553 send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
03554 }
03555 break;
03556 case KEY_HEADPHN:
03557 if (pte->device->output == OUTPUT_HEADPHONE) {
03558 if (pte->device->receiver_state == STATE_OFFHOOK) {
03559 send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
03560 } else {
03561 show_main_page(pte);
03562 }
03563 } else {
03564 send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
03565 }
03566 break;
03567 }
03568 return;
03569 }
03570
03571 static void handle_select_option(struct unistimsession *pte)
03572 {
03573 char tmp[128];
03574
03575 if (pte->state != STATE_SELECTOPTION) {
03576 pte->state = STATE_SELECTOPTION;
03577 pte->size_buff_entry = 1;
03578 pte->buff_entry[0] = 0;
03579 }
03580 snprintf(tmp, sizeof(tmp), "%d. %s", pte->buff_entry[0] + 1, ustmtext(options_menu[(int)pte->buff_entry[0]].label, pte));
03581 send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmp);
03582 send_text_status(pte, ustmtext("Select Cancel", pte));
03583 return;
03584 }
03585
03586 static void key_select_option(struct unistimsession *pte, char keycode)
03587 {
03588 switch (keycode) {
03589 case KEY_DOWN:
03590 pte->buff_entry[0]++;
03591 if (options_menu[(int)pte->buff_entry[0]].label == NULL) {
03592 pte->buff_entry[0]--;
03593 }
03594 break;
03595 case KEY_UP:
03596 if (pte->buff_entry[0] > 0) {
03597 pte->buff_entry[0]--;
03598 }
03599 break;
03600 case KEY_FUNC1:
03601 options_menu[(int)pte->buff_entry[0]].handle_option(pte);
03602 return;
03603 case KEY_HANGUP:
03604 case KEY_FUNC4:
03605 show_main_page(pte);
03606 return;
03607 }
03608
03609 handle_select_option(pte);
03610 return;
03611 }
03612
03613 #define SELECTCODEC_START_ENTRY_POS 15
03614 #define SELECTCODEC_MAX_LENGTH 2
03615 #define SELECTCODEC_MSG "Codec number : .."
03616 static void handle_select_codec(struct unistimsession *pte)
03617 {
03618 char buf[30], buf2[5];
03619
03620 pte->state = STATE_SELECTCODEC;
03621 ast_copy_string(buf, ustmtext("Using codec", pte), sizeof(buf));
03622 snprintf(buf2, sizeof(buf2), " %d", pte->device->codec_number);
03623 strcat(buf, buf2);
03624 strcat(buf, " (G711u=0,");
03625
03626 send_text(TEXT_LINE0, TEXT_NORMAL, pte, buf);
03627 send_text(TEXT_LINE1, TEXT_NORMAL, pte, "G723=4,G711a=8,G729A=18)");
03628 send_text(TEXT_LINE2, TEXT_INVERSE, pte, SELECTCODEC_MSG);
03629 send_blink_cursor(pte);
03630 send_cursor_pos(pte, TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS);
03631 pte->size_buff_entry = 0;
03632 send_text_status(pte, ustmtext("Select BackSp Erase Cancel", pte));
03633 return;
03634 }
03635
03636 static void key_select_codec(struct unistimsession *pte, char keycode)
03637 {
03638 if (keycode == KEY_FUNC2) {
03639 if (pte->size_buff_entry <= 1) {
03640 keycode = KEY_FUNC3;
03641 } else {
03642 pte->size_buff_entry -= 2;
03643 keycode = pte->buff_entry[pte->size_buff_entry] + 0x10;
03644 }
03645 }
03646 if ((keycode >= KEY_0) && (keycode <= KEY_9)) {
03647 char tmpbuf[] = SELECTCODEC_MSG;
03648 int i = 0;
03649
03650 if (pte->size_buff_entry >= SELECTCODEC_MAX_LENGTH) {
03651 return;
03652 }
03653 while (i < pte->size_buff_entry) {
03654 tmpbuf[i + SELECTCODEC_START_ENTRY_POS] = pte->buff_entry[i];
03655 i++;
03656 }
03657 tmpbuf[i + SELECTCODEC_START_ENTRY_POS] = keycode - 0x10;
03658 pte->buff_entry[i] = keycode - 0x10;
03659 pte->size_buff_entry++;
03660 send_text(TEXT_LINE2, TEXT_INVERSE, pte, tmpbuf);
03661 send_blink_cursor(pte);
03662 send_cursor_pos(pte,
03663 (unsigned char) (TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS + 1 + i));
03664 return;
03665 }
03666
03667 switch (keycode) {
03668 case KEY_FUNC1:
03669 if (pte->size_buff_entry == 1) {
03670 pte->device->codec_number = pte->buff_entry[0] - 48;
03671 } else if (pte->size_buff_entry == 2) {
03672 pte->device->codec_number =
03673 ((pte->buff_entry[0] - 48) * 10) + (pte->buff_entry[1] - 48);
03674 }
03675 show_main_page(pte);
03676 break;
03677 case KEY_FUNC3:
03678 pte->size_buff_entry = 0;
03679 send_text(TEXT_LINE2, TEXT_INVERSE, pte, SELECTCODEC_MSG);
03680 send_blink_cursor(pte);
03681 send_cursor_pos(pte, TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS);
03682 break;
03683 case KEY_HANGUP:
03684 case KEY_FUNC4:
03685 show_main_page(pte);
03686 break;
03687 }
03688 return;
03689 }
03690
03691 static int find_language(const char* lang)
03692 {
03693 int i = 0;
03694 while (options_languages[i].lang_short != NULL) {
03695 if(!strcmp(options_languages[i].lang_short, lang)) {
03696 return i;
03697 }
03698 i++;
03699 }
03700 return 0;
03701 }
03702
03703 static void handle_select_language(struct unistimsession *pte)
03704 {
03705 char tmp_language[40];
03706 struct unistim_languages lang;
03707
03708 if (pte->state != STATE_SELECTLANGUAGE) {
03709 pte->state = STATE_SELECTLANGUAGE;
03710 pte->size_buff_entry = 1;
03711 pte->buff_entry[0] = find_language(pte->device->language);
03712 }
03713 lang = options_languages[(int)pte->buff_entry[0]];
03714 ast_copy_string(tmp_language, pte->device->language, sizeof(tmp_language));
03715 ast_copy_string(pte->device->language, lang.lang_short, sizeof(pte->device->language));
03716 send_charset_update(pte, lang.encoding);
03717 send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext(lang.label, pte));
03718
03719 ast_copy_string(pte->device->language, tmp_language, sizeof(pte->device->language));
03720 lang = options_languages[find_language(pte->device->language)];
03721 send_charset_update(pte, lang.encoding);
03722 send_text_status(pte, ustmtext("Select Cancel", pte));
03723 return;
03724 }
03725
03726 static void key_select_language(struct unistimsession *pte, char keycode)
03727 {
03728 switch (keycode) {
03729 case KEY_DOWN:
03730 pte->buff_entry[0]++;
03731 if (options_languages[(int)pte->buff_entry[0]].label == NULL) {
03732 pte->buff_entry[0]--;
03733 }
03734 break;
03735 case KEY_UP:
03736 if (pte->buff_entry[0] > 0) {
03737 pte->buff_entry[0]--;
03738 }
03739 break;
03740 case KEY_FUNC1:
03741 ast_copy_string(pte->device->language, options_languages[(int)pte->buff_entry[0]].lang_short, sizeof(pte->device->language));
03742 send_charset_update(pte, options_languages[(int)pte->buff_entry[0]].encoding);
03743 refresh_all_favorite(pte);
03744 show_main_page(pte);
03745 return;
03746 case KEY_HANGUP:
03747 case KEY_FUNC4:
03748 handle_select_option(pte);
03749 return;
03750 }
03751
03752 handle_select_language(pte);
03753 return;
03754 }
03755
03756
03757 #define SELECTEXTENSION_START_ENTRY_POS 0
03758 #define SELECTEXTENSION_MAX_LENGTH 10
03759 #define SELECTEXTENSION_MSG ".........."
03760 static void show_extension_page(struct unistimsession *pte)
03761 {
03762 pte->state = STATE_EXTENSION;
03763
03764 send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Please enter a Terminal", pte));
03765 send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Number (TN) :", pte));
03766 send_text(TEXT_LINE2, TEXT_NORMAL, pte, SELECTEXTENSION_MSG);
03767 send_blink_cursor(pte);
03768 send_cursor_pos(pte, TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS);
03769 send_text_status(pte, ustmtext("Enter BackSpcErase", pte));
03770 pte->size_buff_entry = 0;
03771 return;
03772 }
03773
03774 static void key_select_extension(struct unistimsession *pte, char keycode)
03775 {
03776 if (keycode == KEY_FUNC2) {
03777 if (pte->size_buff_entry <= 1) {
03778 keycode = KEY_FUNC3;
03779 } else {
03780 pte->size_buff_entry -= 2;
03781 keycode = pte->buff_entry[pte->size_buff_entry] + 0x10;
03782 }
03783 }
03784 if ((keycode >= KEY_0) && (keycode <= KEY_9)) {
03785 char tmpbuf[] = SELECTEXTENSION_MSG;
03786 int i = 0;
03787
03788 if (pte->size_buff_entry >= SELECTEXTENSION_MAX_LENGTH) {
03789 return;
03790 }
03791 while (i < pte->size_buff_entry) {
03792 tmpbuf[i + SELECTEXTENSION_START_ENTRY_POS] = pte->buff_entry[i];
03793 i++;
03794 }
03795 tmpbuf[i + SELECTEXTENSION_START_ENTRY_POS] = keycode - 0x10;
03796 pte->buff_entry[i] = keycode - 0x10;
03797 pte->size_buff_entry++;
03798 send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
03799 send_blink_cursor(pte);
03800 send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS + 1 + i));
03801 return;
03802 }
03803
03804 switch (keycode) {
03805 case KEY_FUNC1:
03806 if (pte->size_buff_entry < 1) {
03807 return;
03808 }
03809 if (autoprovisioning == AUTOPROVISIONING_TN) {
03810 struct unistim_device *d;
03811
03812
03813 ast_mutex_lock(&devicelock);
03814 d = devices;
03815 pte->buff_entry[pte->size_buff_entry] = '\0';
03816 while (d) {
03817 if (d->id[0] == 'T') {
03818
03819 if (!strcmp((d->id) + 1, pte->buff_entry)) {
03820 pte->device = d;
03821 d->session = pte;
03822 d->codec_number = DEFAULT_CODEC;
03823 d->missed_call = 0;
03824 d->receiver_state = STATE_ONHOOK;
03825 strcpy(d->id, pte->macaddr);
03826 pte->device->extension_number[0] = 'T';
03827 pte->device->extension = EXTENSION_TN;
03828 ast_copy_string((pte->device->extension_number) + 1,
03829 pte->buff_entry, pte->size_buff_entry + 1);
03830 ast_mutex_unlock(&devicelock);
03831 show_main_page(pte);
03832 refresh_all_favorite(pte);
03833 return;
03834 }
03835 }
03836 d = d->next;
03837 }
03838 ast_mutex_unlock(&devicelock);
03839 send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Invalid Terminal Number.", pte));
03840 send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Please try again :", pte));
03841 send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS +
03842 pte->size_buff_entry));
03843 send_blink_cursor(pte);
03844 } else {
03845 ast_copy_string(pte->device->extension_number, pte->buff_entry,
03846 pte->size_buff_entry + 1);
03847 if (register_extension(pte)) {
03848 send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Invalid extension.", pte));
03849 send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Please try again :", pte));
03850 send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 +
03851 SELECTEXTENSION_START_ENTRY_POS +
03852 pte->size_buff_entry));
03853 send_blink_cursor(pte);
03854 } else
03855 show_main_page(pte);
03856 }
03857 break;
03858 case KEY_FUNC3:
03859 pte->size_buff_entry = 0;
03860 send_text(TEXT_LINE2, TEXT_NORMAL, pte, SELECTEXTENSION_MSG);
03861 send_blink_cursor(pte);
03862 send_cursor_pos(pte, TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS);
03863 break;
03864 }
03865 return;
03866 }
03867
03868 static void show_entry_history(struct unistimsession *pte, FILE ** f)
03869 {
03870 char line[TEXT_LENGTH_MAX + 1], status[STATUS_LENGTH_MAX + 1], func1[10], func2[10],
03871 func3[10];
03872
03873 if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
03874 display_last_error("Can't read history date entry");
03875 fclose(*f);
03876 return;
03877 }
03878 line[sizeof(line) - 1] = '\0';
03879 if (pte->device->height == 1) {
03880 if (pte->buff_entry[3] == 1) {
03881 send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03882 }
03883 } else {
03884 send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03885 }
03886 if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
03887 display_last_error("Can't read callerid entry");
03888 fclose(*f);
03889 return;
03890 }
03891 line[sizeof(line) - 1] = '\0';
03892 ast_copy_string(pte->device->lst_cid, line, sizeof(pte->device->lst_cid));
03893 if (pte->device->height == 1) {
03894 if (pte->buff_entry[3] == 2) {
03895 send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03896 }
03897 } else {
03898 send_text(TEXT_LINE1, TEXT_NORMAL, pte, line);
03899 }
03900 if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
03901 display_last_error("Can't read callername entry");
03902 fclose(*f);
03903 return;
03904 }
03905 line[sizeof(line) - 1] = '\0';
03906 if (pte->device->height == 1) {
03907 if (pte->buff_entry[3] == 3) {
03908 send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03909 }
03910 } else {
03911 send_text(TEXT_LINE2, TEXT_NORMAL, pte, line);
03912 }
03913 fclose(*f);
03914
03915 snprintf(line, sizeof(line), "%s %03d/%03d", ustmtext("Call", pte), pte->buff_entry[2],
03916 pte->buff_entry[1]);
03917 send_texttitle(pte, line);
03918
03919 if (pte->buff_entry[2] == 1) {
03920 ast_copy_string(func1, " ", sizeof(func1));
03921 } else {
03922 ast_copy_string(func1, ustmtext("Prev ", pte), sizeof(func1));
03923 }
03924 if (pte->buff_entry[2] >= pte->buff_entry[1]) {
03925 ast_copy_string(func2, " ", sizeof(func2));
03926 } else {
03927 ast_copy_string(func2, ustmtext("Next ", pte), sizeof(func2));
03928 }
03929 if (strlen(pte->device->lst_cid)) {
03930 ast_copy_string(func3, ustmtext("Redial ", pte), sizeof(func3));
03931 } else {
03932 ast_copy_string(func3, " ", sizeof(func3));
03933 }
03934 snprintf(status, sizeof(status), "%s%s%s%s", func1, func2, func3, ustmtext("Cancel", pte));
03935 send_text_status(pte, status);
03936 }
03937
03938 static char open_history(struct unistimsession *pte, char way, FILE ** f)
03939 {
03940 char tmp[AST_CONFIG_MAX_PATH];
03941 char count;
03942
03943 snprintf(tmp, sizeof(tmp), "%s/%s/%s-%c.csv", ast_config_AST_LOG_DIR,
03944 USTM_LOG_DIR, pte->device->name, way);
03945 *f = fopen(tmp, "r");
03946 if (!*f) {
03947 display_last_error("Unable to open history file");
03948 return 0;
03949 }
03950 if (fread(&count, 1, 1, *f) != 1) {
03951 display_last_error("Unable to read history header - display.");
03952 fclose(*f);
03953 *f = NULL;
03954 return 0;
03955 }
03956 if (count > MAX_ENTRY_LOG) {
03957 ast_log(LOG_WARNING, "Invalid count in history header of %s (%d max %d)\n", tmp,
03958 count, MAX_ENTRY_LOG);
03959 fclose(*f);
03960 *f = NULL;
03961 return 0;
03962 }
03963 return count;
03964 }
03965
03966 static void show_history(struct unistimsession *pte, char way)
03967 {
03968 FILE *f;
03969 char count;
03970
03971 if (!pte->device) {
03972 return;
03973 }
03974 if (!pte->device->callhistory) {
03975 return;
03976 }
03977 count = open_history(pte, way, &f);
03978 if (!count) {
03979 return;
03980 }
03981 pte->buff_entry[0] = way;
03982 pte->buff_entry[1] = count;
03983 pte->buff_entry[2] = 1;
03984 pte->buff_entry[3] = 1;
03985 show_entry_history(pte, &f);
03986 pte->state = STATE_HISTORY;
03987 }
03988
03989 static void show_main_page(struct unistimsession *pte)
03990 {
03991 char tmpbuf[TEXT_LENGTH_MAX + 1];
03992 const char *text;
03993
03994 if ((pte->device->extension == EXTENSION_ASK) &&
03995 (ast_strlen_zero(pte->device->extension_number))) {
03996 show_extension_page(pte);
03997 return;
03998 }
03999
04000 pte->state = STATE_MAINPAGE;
04001
04002 send_tone(pte, 0, 0);
04003 send_stop_timer(pte);
04004 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON_DISCRET);
04005 send_led_update(pte, 0x08);
04006 send_led_update(pte, 0x10);
04007
04008 if (!ast_strlen_zero(pte->device->call_forward)) {
04009 if (pte->device->height == 1) {
04010 char tmp_field[100];
04011 snprintf(tmp_field, sizeof(tmp_field), "%s %s", ustmtext("Fwd to:", pte), pte->device->call_forward);
04012 send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmp_field);
04013 } else {
04014 send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Call forwarded to :", pte));
04015 send_text(TEXT_LINE1, TEXT_NORMAL, pte, pte->device->call_forward);
04016 }
04017 send_icon(TEXT_LINE0, FAV_ICON_REFLECT + FAV_BLINK_SLOW, pte);
04018 send_text_status(pte, ustmtext("Dial Redial NoFwd ", pte));
04019 } else {
04020 if ((pte->device->extension == EXTENSION_ASK) ||
04021 (pte->device->extension == EXTENSION_TN)) {
04022 send_text_status(pte, ustmtext("Dial Redial Fwd Unregis", pte));
04023 } else {
04024 send_text_status(pte, ustmtext("Dial Redial Fwd Pickup", pte));
04025 }
04026 send_text(TEXT_LINE1, TEXT_NORMAL, pte, pte->device->maintext1);
04027 if (pte->device->missed_call == 0) {
04028 send_date_time2(pte);
04029 send_idle_clock(pte);
04030 if (strlen(pte->device->maintext0)) {
04031 send_text(TEXT_LINE0, TEXT_NORMAL, pte, pte->device->maintext0);
04032 }
04033 } else {
04034 if (pte->device->missed_call == 1) {
04035 text = ustmtext("unanswered call", pte);
04036 } else {
04037 text = ustmtext("unanswered calls", pte);
04038 }
04039 snprintf(tmpbuf, sizeof(tmpbuf), "%d %s", pte->device->missed_call, text);
04040 send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmpbuf);
04041 send_icon(TEXT_LINE0, FAV_ICON_CALL_CENTER + FAV_BLINK_SLOW, pte);
04042 }
04043 }
04044 if (pte->device->height > 1) {
04045 if (ast_strlen_zero(pte->device->maintext2)) {
04046 strcpy(tmpbuf, "IP : ");
04047 strcat(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr));
04048 send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
04049 } else {
04050 send_text(TEXT_LINE2, TEXT_NORMAL, pte, pte->device->maintext2);
04051 }
04052 }
04053
04054 send_texttitle(pte, pte->device->titledefault);
04055 change_favorite_icon(pte, FAV_LINE_ICON);
04056 }
04057
04058 static void key_main_page(struct unistimsession *pte, char keycode)
04059 {
04060 if (pte->device->missed_call) {
04061 send_icon(TEXT_LINE0, FAV_ICON_NONE, pte);
04062 pte->device->missed_call = 0;
04063 }
04064 if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
04065 handle_dial_page(pte);
04066 key_dial_page(pte, keycode);
04067 return;
04068 }
04069 switch (keycode) {
04070 case KEY_FUNC1:
04071 pte->device->selected = get_avail_softkey(pte, NULL);
04072 handle_dial_page(pte);
04073 break;
04074 case KEY_FUNC2:
04075 if (ast_strlen_zero(pte->device->redial_number)) {
04076 break;
04077 }
04078 if ((pte->device->output == OUTPUT_HANDSET) &&
04079 (pte->device->receiver_state == STATE_ONHOOK)) {
04080 send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
04081 } else {
04082 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
04083 }
04084 ast_copy_string(pte->device->phone_number, pte->device->redial_number,
04085 sizeof(pte->device->phone_number));
04086 handle_call_outgoing(pte);
04087 break;
04088 case KEY_FUNC3:
04089 if (!ast_strlen_zero(pte->device->call_forward)) {
04090
04091 memmove(pte->device->call_forward + 1, pte->device->call_forward,
04092 sizeof(pte->device->call_forward) - 1);
04093 pte->device->call_forward[0] = '\0';
04094 send_icon(TEXT_LINE0, FAV_ICON_NONE, pte);
04095 pte->device->output = OUTPUT_HANDSET;
04096 show_main_page(pte);
04097 break;
04098 }
04099 pte->device->call_forward[0] = -1;
04100 handle_dial_page(pte);
04101 break;
04102 case KEY_FUNC4:
04103 if (pte->device->extension == EXTENSION_ASK) {
04104 unregister_extension(pte);
04105 pte->device->extension_number[0] = '\0';
04106 show_extension_page(pte);
04107 } else if (pte->device->extension == EXTENSION_TN) {
04108 ast_mutex_lock(&devicelock);
04109 strcpy(pte->device->id, pte->device->extension_number);
04110 pte->buff_entry[0] = '\0';
04111 pte->size_buff_entry = 0;
04112 pte->device->session = NULL;
04113 pte->device = NULL;
04114 ast_mutex_unlock(&devicelock);
04115 show_extension_page(pte);
04116 } else {
04117 pte->device->selected = -1;
04118 ast_copy_string(pte->device->phone_number, ast_pickup_ext(),
04119 sizeof(pte->device->phone_number));
04120 handle_call_outgoing(pte);
04121 }
04122 break;
04123 case KEY_FAV0:
04124 case KEY_FAV1:
04125 case KEY_FAV2:
04126 case KEY_FAV3:
04127 case KEY_FAV4:
04128 case KEY_FAV5:
04129 handle_key_fav(pte, keycode);
04130 break;
04131 case KEY_CONF:
04132 handle_select_option(pte);
04133 break;
04134 case KEY_LOUDSPK:
04135 send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
04136 handle_dial_page(pte);
04137 break;
04138 case KEY_HEADPHN:
04139 send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
04140 handle_dial_page(pte);
04141 break;
04142 case KEY_SNDHIST:
04143 show_history(pte, 'o');
04144 break;
04145 case KEY_RCVHIST:
04146 show_history(pte, 'i');
04147 break;
04148 }
04149 return;
04150 }
04151
04152 static void key_history(struct unistimsession *pte, char keycode)
04153 {
04154 FILE *f;
04155 char count;
04156 long offset;
04157 int flag = 0;
04158
04159 switch (keycode) {
04160 case KEY_LEFT:
04161 if (pte->device->height == 1) {
04162 if (pte->buff_entry[3] <= 1) {
04163 return;
04164 }
04165 pte->buff_entry[3]--;
04166 flag = 1;
04167 break;
04168 }
04169 case KEY_UP:
04170 case KEY_FUNC1:
04171 if (pte->buff_entry[2] <= 1) {
04172 return;
04173 }
04174 pte->buff_entry[2]--;
04175 flag = 1;
04176 break;
04177 case KEY_RIGHT:
04178 if (pte->device->height == 1) {
04179 if (pte->buff_entry[3] == 3) {
04180 return;
04181 }
04182 pte->buff_entry[3]++;
04183 flag = 1;
04184 break;
04185 }
04186 case KEY_DOWN:
04187 case KEY_FUNC2:
04188 if (pte->buff_entry[2] >= pte->buff_entry[1]) {
04189 return;
04190 }
04191 pte->buff_entry[2]++;
04192 flag = 1;
04193 break;
04194 case KEY_FUNC3:
04195 if (ast_strlen_zero(pte->device->lst_cid)) {
04196 break;
04197 }
04198 ast_copy_string(pte->device->redial_number, pte->device->lst_cid,
04199 sizeof(pte->device->redial_number));
04200 key_main_page(pte, KEY_FUNC2);
04201 break;
04202 case KEY_FUNC4:
04203 case KEY_HANGUP:
04204 show_main_page(pte);
04205 break;
04206 case KEY_SNDHIST:
04207 if (pte->buff_entry[0] == 'i') {
04208 show_history(pte, 'o');
04209 } else {
04210 show_main_page(pte);
04211 }
04212 break;
04213 case KEY_RCVHIST:
04214 if (pte->buff_entry[0] == 'i') {
04215 show_main_page(pte);
04216 } else {
04217 show_history(pte, 'i');
04218 }
04219 break;
04220 }
04221
04222 if (flag) {
04223 count = open_history(pte, pte->buff_entry[0], &f);
04224 if (!count) {
04225 return;
04226 }
04227 offset = ((pte->buff_entry[2] - 1) * TEXT_LENGTH_MAX * 3);
04228 if (fseek(f, offset, SEEK_CUR)) {
04229 display_last_error("Unable to seek history entry.");
04230 fclose(f);
04231 return;
04232 }
04233 show_entry_history(pte, &f);
04234 }
04235
04236 return;
04237 }
04238
04239 static void init_phone_step2(struct unistimsession *pte)
04240 {
04241 BUFFSEND;
04242 if (unistimdebug) {
04243 ast_verb(0, "Sending S4\n");
04244 }
04245 memcpy(buffsend + SIZE_HEADER, packet_send_s4, sizeof(packet_send_s4));
04246 send_client(SIZE_HEADER + sizeof(packet_send_s4), buffsend, pte);
04247 send_date_time2(pte);
04248 send_date_time3(pte);
04249 if (unistimdebug) {
04250 ast_verb(0, "Sending S7\n");
04251 }
04252 memcpy(buffsend + SIZE_HEADER, packet_send_S7, sizeof(packet_send_S7));
04253 send_client(SIZE_HEADER + sizeof(packet_send_S7), buffsend, pte);
04254 if (unistimdebug) {
04255 ast_verb(0, "Sending Contrast\n");
04256 }
04257 memcpy(buffsend + SIZE_HEADER, packet_send_Contrast, sizeof(packet_send_Contrast));
04258 if (pte->device != NULL) {
04259 buffsend[9] = pte->device->contrast;
04260 }
04261 send_client(SIZE_HEADER + sizeof(packet_send_Contrast), buffsend, pte);
04262
04263 if (unistimdebug) {
04264 ast_verb(0, "Sending S9\n");
04265 }
04266 memcpy(buffsend + SIZE_HEADER, packet_send_s9, sizeof(packet_send_s9));
04267 send_client(SIZE_HEADER + sizeof(packet_send_s9), buffsend, pte);
04268 send_no_ring(pte);
04269
04270 if (unistimdebug) {
04271 ast_verb(0, "Sending S7\n");
04272 }
04273 memcpy(buffsend + SIZE_HEADER, packet_send_S7, sizeof(packet_send_S7));
04274 send_client(SIZE_HEADER + sizeof(packet_send_S7), buffsend, pte);
04275 send_led_update(pte, 0);
04276 send_ping(pte);
04277 if (unistimdebug) {
04278 ast_verb(0, "Sending init language\n");
04279 }
04280 if (pte->device) {
04281 send_charset_update(pte, options_languages[find_language(pte->device->language)].encoding);
04282 }
04283 if (pte->state < STATE_MAINPAGE) {
04284 if (autoprovisioning == AUTOPROVISIONING_TN) {
04285 show_extension_page(pte);
04286 return;
04287 } else {
04288 int i;
04289 char tmp[30];
04290
04291 for (i = 1; i < FAVNUM; i++) {
04292 send_favorite(i, 0, pte, "");
04293 }
04294 send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Phone is not registered", pte));
04295 send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("in unistim.conf", pte));
04296 strcpy(tmp, "MAC = ");
04297 strcat(tmp, pte->macaddr);
04298 send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
04299 send_text_status(pte, "");
04300 send_texttitle(pte, "UNISTIM for*");
04301 return;
04302 }
04303 }
04304 show_main_page(pte);
04305 refresh_all_favorite(pte);
04306 if (unistimdebug) {
04307 ast_verb(0, "Sending arrow\n");
04308 }
04309 memcpy(buffsend + SIZE_HEADER, packet_send_arrow, sizeof(packet_send_arrow));
04310 send_client(SIZE_HEADER + sizeof(packet_send_arrow), buffsend, pte);
04311 return;
04312 }
04313
04314 static void process_request(int size, unsigned char *buf, struct unistimsession *pte)
04315 {
04316 char tmpbuf[255];
04317 if (memcmp
04318 (buf + SIZE_HEADER, packet_recv_resume_connection_with_server,
04319 sizeof(packet_recv_resume_connection_with_server)) == 0) {
04320 rcv_resume_connection_with_server(pte);
04321 return;
04322 }
04323 if (memcmp(buf + SIZE_HEADER, packet_recv_firm_version, sizeof(packet_recv_firm_version)) == 0) {
04324 buf[size] = 0;
04325 if (unistimdebug) {
04326 ast_verb(0, "Got the firmware version : '%s'\n", buf + 13);
04327 }
04328 init_phone_step2(pte);
04329 return;
04330 }
04331 if (memcmp(buf + SIZE_HEADER, packet_recv_it_type, sizeof(packet_recv_it_type)) == 0) {
04332 char type = buf[13];
04333 if (unistimdebug) {
04334 ast_verb(0, "Got the equipment type: '%d'\n", type);
04335 }
04336 switch (type) {
04337 case 0x03:
04338 if (pte->device) {
04339 pte->device->height = 1;
04340 }
04341 break;
04342 }
04343 return;
04344 }
04345 if (memcmp(buf + SIZE_HEADER, packet_recv_mac_addr, sizeof(packet_recv_mac_addr)) == 0) {
04346 rcv_mac_addr(pte, buf);
04347 return;
04348 }
04349 if (memcmp(buf + SIZE_HEADER, packet_recv_r2, sizeof(packet_recv_r2)) == 0) {
04350 if (unistimdebug) {
04351 ast_verb(0, "R2 received\n");
04352 }
04353 return;
04354 }
04355
04356 if (pte->state < STATE_MAINPAGE) {
04357 if (unistimdebug) {
04358 ast_verb(0, "Request not authorized in this state\n");
04359 }
04360 return;
04361 }
04362 if (!memcmp(buf + SIZE_HEADER, packet_recv_pressed_key, sizeof(packet_recv_pressed_key))) {
04363 char keycode = buf[13];
04364
04365 if (unistimdebug) {
04366 ast_verb(0, "Key pressed: keycode = 0x%.2x - current state: %s\n", keycode,
04367 ptestate_tostr(pte->state));
04368 }
04369 switch (pte->state) {
04370 case STATE_INIT:
04371 if (unistimdebug) {
04372 ast_verb(0, "No keys allowed in the init state\n");
04373 }
04374 break;
04375 case STATE_AUTHDENY:
04376 if (unistimdebug) {
04377 ast_verb(0, "No keys allowed in authdeny state\n");
04378 }
04379 break;
04380 case STATE_MAINPAGE:
04381 key_main_page(pte, keycode);
04382 break;
04383 case STATE_DIALPAGE:
04384 key_dial_page(pte, keycode);
04385 break;
04386 case STATE_RINGING:
04387 key_ringing(pte, keycode);
04388 break;
04389 case STATE_CALL:
04390 key_call(pte, keycode);
04391 break;
04392 case STATE_EXTENSION:
04393 key_select_extension(pte, keycode);
04394 break;
04395 case STATE_SELECTOPTION:
04396 key_select_option(pte, keycode);
04397 break;
04398 case STATE_SELECTCODEC:
04399 key_select_codec(pte, keycode);
04400 break;
04401 case STATE_SELECTLANGUAGE:
04402 key_select_language(pte, keycode);
04403 break;
04404 case STATE_HISTORY:
04405 key_history(pte, keycode);
04406 break;
04407 default:
04408 ast_log(LOG_WARNING, "Key : Unknown state\n");
04409 }
04410 return;
04411 }
04412 if (memcmp(buf + SIZE_HEADER, packet_recv_pick_up, sizeof(packet_recv_pick_up)) == 0) {
04413 if (unistimdebug) {
04414 ast_verb(0, "Handset off hook\n");
04415 }
04416 if (!pte->device) {
04417 return;
04418 }
04419 pte->device->receiver_state = STATE_OFFHOOK;
04420 if (pte->device->output == OUTPUT_HEADPHONE) {
04421 send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
04422 } else {
04423 send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
04424 }
04425 if (pte->state == STATE_RINGING) {
04426 handle_call_incoming(pte);
04427 } else if ((pte->state == STATE_DIALPAGE) || (pte->state == STATE_CALL)) {
04428 send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
04429 } else if (pte->state == STATE_EXTENSION) {
04430 return;
04431 } else {
04432 pte->device->selected = get_avail_softkey(pte, NULL);
04433 send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
04434 handle_dial_page(pte);
04435 }
04436 return;
04437 }
04438 if (memcmp(buf + SIZE_HEADER, packet_recv_hangup, sizeof(packet_recv_hangup)) == 0) {
04439 if (unistimdebug) {
04440 ast_verb(0, "Handset on hook\n");
04441 }
04442 if (!pte->device) {
04443 return;
04444 }
04445 pte->device->receiver_state = STATE_ONHOOK;
04446 if (pte->state == STATE_CALL) {
04447 if (pte->device->output != OUTPUT_SPEAKER) {
04448 close_call(pte);
04449 }
04450 } else if (pte->state == STATE_EXTENSION) {
04451 return;
04452 } else {
04453 show_main_page(pte);
04454 }
04455 return;
04456 }
04457 strcpy(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr));
04458 strcat(tmpbuf, " Unknown request packet\n");
04459 if (unistimdebug) {
04460 ast_debug(1, "%s", tmpbuf);
04461 }
04462 return;
04463 }
04464
04465 static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
04466 struct sockaddr_in *addr_from)
04467 {
04468 unsigned short *sbuf = (unsigned short *) buf;
04469 unsigned short seq;
04470 char tmpbuf[255];
04471
04472 strcpy(tmpbuf, ast_inet_ntoa(addr_from->sin_addr));
04473
04474 if (size < 10) {
04475 if (size == 0) {
04476 ast_log(LOG_WARNING, "%s Read error\n", tmpbuf);
04477 } else {
04478 ast_log(LOG_NOTICE, "%s Packet too short - ignoring\n", tmpbuf);
04479 }
04480 return;
04481 }
04482 if (sbuf[0] == 0xffff) {
04483 if (size != sizeof(packet_rcv_discovery)) {
04484 ast_log(LOG_NOTICE, "%s Invalid size of a discovery packet\n", tmpbuf);
04485 } else {
04486 if (memcmp(buf, packet_rcv_discovery, sizeof(packet_rcv_discovery)) == 0) {
04487 if (unistimdebug) {
04488 ast_verb(0, "Discovery packet received - Sending Discovery ACK\n");
04489 }
04490 if (pte) {
04491 if (pte->state == STATE_INIT) {
04492 if (unistimdebug) {
04493 ast_verb(1, "Duplicated Discovery packet\n");
04494 }
04495 send_raw_client(sizeof(packet_send_discovery_ack),
04496 packet_send_discovery_ack, addr_from, &pte->sout);
04497 pte->seq_phone = (short) 0x0000;
04498 } else {
04499 close_client(pte);
04500 if (create_client(addr_from)) {
04501 send_raw_client(sizeof(packet_send_discovery_ack),
04502 packet_send_discovery_ack, addr_from, &pte->sout);
04503 }
04504 }
04505 } else {
04506
04507 if ((pte = create_client(addr_from))) {
04508 send_raw_client(sizeof(packet_send_discovery_ack),
04509 packet_send_discovery_ack, addr_from, &pte->sout);
04510 }
04511 }
04512 return;
04513 }
04514 ast_log(LOG_NOTICE, "%s Invalid discovery packet\n", tmpbuf);
04515 }
04516 return;
04517 }
04518 if (!pte) {
04519 if (unistimdebug) {
04520 ast_verb(0, "%s Not a discovery packet from an unknown source : ignoring\n", tmpbuf);
04521 }
04522 return;
04523 }
04524
04525 if (sbuf[0] != 0) {
04526 ast_log(LOG_NOTICE, "Unknown packet received - ignoring\n");
04527 return;
04528 }
04529 if (buf[5] != 2) {
04530 ast_log(LOG_NOTICE, "%s Wrong direction : got 0x%.2x expected 0x02\n", tmpbuf,
04531 buf[5]);
04532 return;
04533 }
04534 seq = ntohs(sbuf[1]);
04535 if (buf[4] == 1) {
04536 ast_mutex_lock(&pte->lock);
04537 if (unistimdebug) {
04538 ast_verb(6, "ACK received for packet #0x%.4x\n", seq);
04539 }
04540 pte->nb_retransmit = 0;
04541
04542 if ((pte->last_seq_ack) + 1 == seq) {
04543 pte->last_seq_ack++;
04544 check_send_queue(pte);
04545 ast_mutex_unlock(&pte->lock);
04546 return;
04547 }
04548 if (pte->last_seq_ack > seq) {
04549 if (pte->last_seq_ack == 0xffff) {
04550 ast_verb(0, "ACK at 0xffff, restarting counter.\n");
04551 pte->last_seq_ack = 0;
04552 } else {
04553 ast_log(LOG_NOTICE,
04554 "%s Warning : ACK received for an already ACKed packet : #0x%.4x we are at #0x%.4x\n",
04555 tmpbuf, seq, pte->last_seq_ack);
04556 }
04557 ast_mutex_unlock(&pte->lock);
04558 return;
04559 }
04560 if (pte->seq_server < seq) {
04561 ast_log(LOG_NOTICE,
04562 "%s Error : ACK received for a non-existent packet : #0x%.4x\n",
04563 tmpbuf, pte->seq_server);
04564 ast_mutex_unlock(&pte->lock);
04565 return;
04566 }
04567 if (unistimdebug) {
04568 ast_verb(0, "%s ACK gap : Received ACK #0x%.4x, previous was #0x%.4x\n",
04569 tmpbuf, seq, pte->last_seq_ack);
04570 }
04571 pte->last_seq_ack = seq;
04572 check_send_queue(pte);
04573 ast_mutex_unlock(&pte->lock);
04574 return;
04575 }
04576 if (buf[4] == 2) {
04577 if (unistimdebug) {
04578 ast_verb(0, "Request received\n");
04579 }
04580 if (pte->seq_phone == seq) {
04581
04582 buf[4] = 1;
04583 buf[5] = 1;
04584 send_raw_client(SIZE_HEADER, buf, addr_from, &pte->sout);
04585 pte->seq_phone++;
04586
04587 process_request(size, buf, pte);
04588 return;
04589 }
04590 if (pte->seq_phone > seq) {
04591 ast_log(LOG_NOTICE,
04592 "%s Warning : received a retransmitted packet : #0x%.4x (we are at #0x%.4x)\n",
04593 tmpbuf, seq, pte->seq_phone);
04594
04595
04596 buf[4] = 1;
04597 buf[5] = 1;
04598 send_raw_client(SIZE_HEADER, buf, addr_from, &pte->sout);
04599 return;
04600 }
04601 ast_log(LOG_NOTICE,
04602 "%s Warning : we lost a packet : received #0x%.4x (we are at #0x%.4x)\n",
04603 tmpbuf, seq, pte->seq_phone);
04604 return;
04605 }
04606 if (buf[4] == 0) {
04607 ast_log(LOG_NOTICE, "%s Retransmit request for packet #0x%.4x\n", tmpbuf, seq);
04608 if (pte->last_seq_ack > seq) {
04609 ast_log(LOG_NOTICE,
04610 "%s Error : received a request for an already ACKed packet : #0x%.4x\n",
04611 tmpbuf, pte->last_seq_ack);
04612 return;
04613 }
04614 if (pte->seq_server < seq) {
04615 ast_log(LOG_NOTICE,
04616 "%s Error : received a request for a non-existent packet : #0x%.4x\n",
04617 tmpbuf, pte->seq_server);
04618 return;
04619 }
04620 send_retransmit(pte);
04621 return;
04622 }
04623 ast_log(LOG_NOTICE, "%s Unknown request : got 0x%.2x expected 0x00,0x01 or 0x02\n",
04624 tmpbuf, buf[4]);
04625 return;
04626 }
04627
04628 static struct unistimsession *channel_to_session(struct ast_channel *ast)
04629 {
04630 struct unistim_subchannel *sub;
04631 if (!ast) {
04632 ast_log(LOG_WARNING, "Unistim callback function called with a null channel\n");
04633 return NULL;
04634 }
04635 if (!ast_channel_tech_pvt(ast)) {
04636 ast_log(LOG_WARNING, "Unistim callback function called without a tech_pvt\n");
04637 return NULL;
04638 }
04639 sub = ast_channel_tech_pvt(ast);
04640
04641 if (!sub->parent) {
04642 ast_log(LOG_WARNING, "Unistim callback function called without a line\n");
04643 return NULL;
04644 }
04645 if (!sub->parent->parent) {
04646 ast_log(LOG_WARNING, "Unistim callback function called without a device\n");
04647 return NULL;
04648 }
04649 ast_mutex_lock(&sub->parent->parent->lock);
04650 if (!sub->parent->parent->session) {
04651 ast_log(LOG_WARNING, "Unistim callback function called without a session\n");
04652 return NULL;
04653 }
04654 ast_mutex_unlock(&sub->parent->parent->lock);
04655 return sub->parent->parent->session;
04656 }
04657
04658 static void send_callerid_screen(struct unistimsession *pte, struct unistim_subchannel *sub)
04659 {
04660 char *cidname_str;
04661 char *cidnum_str;
04662
04663 if (!sub) {
04664 return;
04665 }
04666 if (sub->owner) {
04667 if (ast_channel_connected(sub->owner)->id.number.valid && ast_channel_connected(sub->owner)->id.number.str) {
04668 cidnum_str = ast_channel_connected(sub->owner)->id.number.str;
04669 } else {
04670 cidnum_str = DEFAULTCALLERID;
04671 }
04672 change_callerid(pte, 0, cidnum_str);
04673 if (strlen(cidnum_str) == 0) {
04674 cidnum_str = DEFAULTCALLERID;
04675 }
04676
04677 if (ast_channel_connected(sub->owner)->id.name.valid && ast_channel_connected(sub->owner)->id.name.str) {
04678 cidname_str = ast_channel_connected(sub->owner)->id.name.str;
04679 } else {
04680 cidname_str = DEFAULTCALLERNAME;
04681 }
04682 change_callerid(pte, 1, cidname_str);
04683 if (strlen(cidname_str) == 0) {
04684 cidname_str = DEFAULTCALLERNAME;
04685 }
04686
04687 if (pte->device->height == 1) {
04688 char tmpstr[256];
04689 snprintf(tmpstr, sizeof(tmpstr), "%s %s", cidnum_str, ustmtext(cidname_str, pte));
04690 send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmpstr);
04691 } else {
04692 send_text(TEXT_LINE0, TEXT_NORMAL, pte, cidname_str);
04693 send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext(cidnum_str, pte));
04694 }
04695 }
04696 }
04697
04698
04699
04700 static int unistim_call(struct ast_channel *ast, const char *dest, int timeout)
04701 {
04702 int res = 0, i;
04703 struct unistim_subchannel *sub, *sub_real;
04704 struct unistimsession *session;
04705 char ringstyle, ringvolume;
04706
04707 session = channel_to_session(ast);
04708 if (!session) {
04709 ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
04710 return -1;
04711 }
04712 sub = ast_channel_tech_pvt(ast);
04713 sub_real = get_sub(session->device, SUB_REAL);
04714 if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
04715 ast_log(LOG_WARNING, "unistim_call called on %s, neither down nor reserved\n",
04716 ast_channel_name(ast));
04717 return -1;
04718 }
04719
04720 if (unistimdebug) {
04721 ast_verb(3, "unistim_call(%s)\n", ast_channel_name(ast));
04722 }
04723 session->state = STATE_RINGING;
04724 send_callerid_screen(session, sub);
04725 if (ast_strlen_zero(ast_channel_call_forward(ast))) {
04726 send_text(TEXT_LINE2, TEXT_NORMAL, session, ustmtext("is calling you.", session));
04727 send_text_status(session, ustmtext("Accept Ignore Hangup", session));
04728
04729 if (sub_real) {
04730 ringstyle = session->device->cwstyle;
04731 ringvolume = session->device->cwvolume;
04732 } else {
04733 ringstyle = (sub->ringstyle == -1) ? session->device->ringstyle : sub->ringstyle;
04734 ringvolume = (sub->ringvolume == -1) ? session->device->ringvolume : sub->ringvolume;
04735 }
04736 send_ring(session, ringvolume, ringstyle);
04737 change_favorite_icon(session, FAV_ICON_SPEAKER_ONHOOK_BLACK + FAV_BLINK_FAST);
04738
04739 for (i = 0; i < FAVNUM; i++) {
04740 if (!soft_key_visible(session->device, i)) {
04741 continue;
04742 }
04743 if (session->device->ssub[i]) {
04744 continue;
04745 }
04746 if (is_key_line(session->device, i) && !strcmp(sub->parent->name, session->device->sline[i]->name)) {
04747 if (unistimdebug) {
04748 ast_verb(0, "Found softkey %d for line %s\n", i, sub->parent->name);
04749 }
04750 send_favorite_short(i, FAV_ICON_SPEAKER_ONHOOK_BLACK + FAV_BLINK_FAST, session);
04751 session->device->ssub[i] = sub;
04752 }
04753 }
04754 }
04755 ast_setstate(ast, AST_STATE_RINGING);
04756 ast_queue_control(ast, AST_CONTROL_RINGING);
04757 return res;
04758 }
04759
04760 static int unistim_hangup_clean(struct ast_channel *ast, struct unistim_subchannel *sub) {
04761 ast_mutex_lock(&sub->lock);
04762 ast_channel_tech_pvt_set(ast, NULL);
04763 sub->owner = NULL;
04764 sub->alreadygone = 0;
04765 ast_mutex_unlock(&sub->lock);
04766 if (sub->rtp) {
04767 if (unistimdebug) {
04768 ast_verb(0, "Destroying RTP session\n");
04769 }
04770 ast_rtp_instance_destroy(sub->rtp);
04771 sub->rtp = NULL;
04772 }
04773 return 0;
04774 }
04775
04776
04777 static int unistim_hangup(struct ast_channel *ast)
04778 {
04779 struct unistim_subchannel *sub = NULL, *sub_real = NULL, *sub_trans = NULL;
04780 struct unistim_line *l;
04781 struct unistim_device *d;
04782 struct unistimsession *s;
04783 int i;
04784
04785 s = channel_to_session(ast);
04786 sub = ast_channel_tech_pvt(ast);
04787 l = sub->parent;
04788 d = l->parent;
04789 if (!s) {
04790 ast_debug(1, "Asked to hangup channel not connected\n");
04791 unistim_hangup_clean(ast, sub);
04792 return 0;
04793 }
04794 if (unistimdebug) {
04795 ast_verb(0, "unistim_hangup(%s) on %s@%s (STATE_%s)\n", ast_channel_name(ast), l->name, l->parent->name, ptestate_tostr(s->state));
04796 }
04797 sub_trans = get_sub(d, SUB_THREEWAY);
04798 if (sub_trans && (sub_trans->owner) && (sub->subtype == SUB_REAL) &&
04799 (sub->alreadygone == 0)) {
04800 if (unistimdebug) {
04801 ast_verb(0, "Threeway call disconnected, switching to real call\n");
04802 }
04803 if (ast_bridged_channel(sub_trans->owner)) {
04804 ast_moh_stop(ast_bridged_channel(sub_trans->owner));
04805 }
04806 sub_trans->moh = 0;
04807 sub_trans->subtype = SUB_REAL;
04808 swap_subs(sub_trans, sub);
04809
04810 send_text_status(s, ustmtext(" Transf Hangup", s));
04811 send_callerid_screen(s, sub_trans);
04812 unistim_hangup_clean(ast, sub);
04813 unistim_unalloc_sub(d, sub);
04814 return 0;
04815 }
04816 sub_real = get_sub(d, SUB_REAL);
04817 if (sub_real && (sub_real->owner) && (sub->subtype == SUB_THREEWAY) &&
04818 (sub->alreadygone == 0)) {
04819 if (unistimdebug) {
04820 ast_verb(0, "Real call disconnected, stay in call\n");
04821 }
04822 send_text_status(s, ustmtext(" Transf Hangup", s));
04823 send_callerid_screen(s, sub_real);
04824 unistim_hangup_clean(ast, sub);
04825 unistim_unalloc_sub(d, sub);
04826 return 0;
04827 }
04828
04829 if (sub->subtype == SUB_REAL) {
04830 sub_stop_silence(s, sub);
04831 send_end_call(s);
04832 } else if (sub->subtype == SUB_RING) {
04833 send_no_ring(s);
04834 for (i = 0; i < FAVNUM; i++) {
04835 if (!soft_key_visible(s->device, i))
04836 continue;
04837 if (d->ssub[i] != sub)
04838 continue;
04839 if (is_key_line(d, i) && !strcmp(l->name, d->sline[i]->name)) {
04840 send_favorite_short(i, FAV_LINE_ICON, s);
04841 d->ssub[i] = NULL;
04842 }
04843 }
04844 }
04845 sub->moh = 0;
04846 if (sub->softkey >= 0) {
04847 send_favorite_short(sub->softkey, FAV_LINE_ICON, s);
04848 }
04849
04850 for (i = 0; i < FAVNUM; i++) {
04851 if (d->ssub[i] == sub) {
04852 d->ssub[i] = NULL;
04853 break;
04854 }
04855 }
04856 refresh_all_favorite(s);
04857 if (s->state == STATE_RINGING && sub->subtype == SUB_RING) {
04858 send_no_ring(s);
04859 if (!ast_test_flag(ast_channel_flags(ast), AST_FLAG_ANSWERED_ELSEWHERE) && ast_channel_hangupcause(ast) != AST_CAUSE_ANSWERED_ELSEWHERE) {
04860 d->missed_call++;
04861 write_history(s, 'i', 1);
04862 }
04863 if (!sub_real) {
04864 show_main_page(s);
04865 }
04866 }
04867 if (s->state == STATE_CALL && sub->subtype == SUB_REAL) {
04868 close_call(s);
04869 }
04870 sub->softkey = -1;
04871 unistim_hangup_clean(ast, sub);
04872 unistim_unalloc_sub(d, sub);
04873 return 0;
04874 }
04875
04876
04877 static int unistim_answer(struct ast_channel *ast)
04878 {
04879 int res = 0;
04880 struct unistim_subchannel *sub;
04881 struct unistim_line *l;
04882 struct unistim_device *d;
04883 struct unistimsession *s;
04884
04885 s = channel_to_session(ast);
04886 if (!s) {
04887 ast_log(LOG_WARNING, "unistim_answer on a disconnected device ?\n");
04888 return -1;
04889 }
04890 sub = ast_channel_tech_pvt(ast);
04891 l = sub->parent;
04892 d = l->parent;
04893
04894 if ((!sub->rtp) && (!get_sub(d, SUB_THREEWAY))) {
04895 start_rtp(sub);
04896 }
04897 if (unistimdebug) {
04898 ast_verb(0, "unistim_answer(%s) on %s@%s-%d\n", ast_channel_name(ast), l->name,
04899 l->parent->name, sub->softkey);
04900 }
04901 send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("is now on-line", s));
04902 if (get_sub(d, SUB_THREEWAY)) {
04903 send_text_status(s, ustmtext("Transf Cancel", s));
04904 } else {
04905 send_text_status(s, ustmtext(" Transf Hangup", s));
04906 }
04907 send_start_timer(s);
04908 if (ast_channel_state(ast) != AST_STATE_UP)
04909 ast_setstate(ast, AST_STATE_UP);
04910 return res;
04911 }
04912
04913
04914
04915 static int unistimsock_read(int *id, int fd, short events, void *ignore)
04916 {
04917 struct sockaddr_in addr_from = { 0, };
04918 struct unistimsession *cur = NULL;
04919 int found = 0;
04920 int tmp = 0;
04921 int dw_num_bytes_rcvd;
04922 unsigned int size_addr_from;
04923 #ifdef DUMP_PACKET
04924 int dw_num_bytes_rcvdd;
04925 #endif
04926
04927 size_addr_from = sizeof(addr_from);
04928 dw_num_bytes_rcvd =
04929 recvfrom(unistimsock, buff, SIZE_PAGE, 0, (struct sockaddr *) &addr_from,
04930 &size_addr_from);
04931 if (dw_num_bytes_rcvd == -1) {
04932 if (errno == EAGAIN) {
04933 ast_log(LOG_NOTICE, "UNISTIM: Received packet with bad UDP checksum\n");
04934 } else if (errno != ECONNREFUSED) {
04935 ast_log(LOG_WARNING, "Recv error %d (%s)\n", errno, strerror(errno));
04936 }
04937 return 1;
04938 }
04939
04940
04941 ast_mutex_lock(&sessionlock);
04942 cur = sessions;
04943 while (cur) {
04944 if (cur->sin.sin_addr.s_addr == addr_from.sin_addr.s_addr) {
04945 found = 1;
04946 break;
04947 }
04948 tmp++;
04949 cur = cur->next;
04950 }
04951 ast_mutex_unlock(&sessionlock);
04952
04953 #ifdef DUMP_PACKET
04954 if (unistimdebug)
04955 ast_verb(0, "\n*** Dump %d bytes from %s - phone_table[%d] ***\n",
04956 dw_num_bytes_rcvd, ast_inet_ntoa(addr_from.sin_addr), tmp);
04957 for (dw_num_bytes_rcvdd = 0; dw_num_bytes_rcvdd < dw_num_bytes_rcvd;
04958 dw_num_bytes_rcvdd++)
04959 ast_verb(0, "%.2x ", (unsigned char) buff[dw_num_bytes_rcvdd]);
04960 ast_verb(0, "\n******************************************\n");
04961 #endif
04962
04963 if (!found) {
04964 if (unistimdebug) {
04965 ast_verb(0, "Received a packet from an unknown source\n");
04966 }
04967 parsing(dw_num_bytes_rcvd, buff, NULL, (struct sockaddr_in *) &addr_from);
04968
04969 } else {
04970 parsing(dw_num_bytes_rcvd, buff, cur, (struct sockaddr_in *) &addr_from);
04971 }
04972 return 1;
04973 }
04974
04975 static struct ast_frame *unistim_rtp_read(const struct ast_channel *ast,
04976 const struct unistim_subchannel *sub)
04977 {
04978
04979 struct ast_frame *f;
04980
04981 if (!ast) {
04982 ast_log(LOG_WARNING, "Channel NULL while reading\n");
04983 return &ast_null_frame;
04984 }
04985
04986 if (!sub->rtp) {
04987 ast_log(LOG_WARNING, "RTP handle NULL while reading on subchannel %d\n",
04988 sub->subtype);
04989 return &ast_null_frame;
04990 }
04991
04992 switch (ast_channel_fdno(ast)) {
04993 case 0:
04994 f = ast_rtp_instance_read(sub->rtp, 0);
04995 break;
04996 case 1:
04997 f = ast_rtp_instance_read(sub->rtp, 1);
04998 break;
04999 default:
05000 f = &ast_null_frame;
05001 }
05002
05003 if (sub->owner) {
05004
05005 if (f->frametype == AST_FRAME_VOICE) {
05006 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(sub->owner), &f->subclass.format))) {
05007 char tmp[256];
05008 ast_debug(1,
05009 "Oooh, format changed from %s to %s\n",
05010 ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(sub->owner)),
05011 ast_getformatname(&f->subclass.format));
05012
05013 ast_format_cap_set(ast_channel_nativeformats(sub->owner), &f->subclass.format);
05014 ast_set_read_format(sub->owner, ast_channel_readformat(sub->owner));
05015 ast_set_write_format(sub->owner, ast_channel_writeformat(sub->owner));
05016 }
05017 }
05018 }
05019
05020 return f;
05021 }
05022
05023 static struct ast_frame *unistim_read(struct ast_channel *ast)
05024 {
05025 struct ast_frame *fr;
05026 struct unistim_subchannel *sub = ast_channel_tech_pvt(ast);
05027
05028 ast_mutex_lock(&sub->lock);
05029 fr = unistim_rtp_read(ast, sub);
05030 ast_mutex_unlock(&sub->lock);
05031
05032 return fr;
05033 }
05034
05035 static int unistim_write(struct ast_channel *ast, struct ast_frame *frame)
05036 {
05037 struct unistim_subchannel *sub = ast_channel_tech_pvt(ast);
05038 int res = 0;
05039
05040 if (frame->frametype != AST_FRAME_VOICE) {
05041 if (frame->frametype == AST_FRAME_IMAGE) {
05042 return 0;
05043 } else {
05044 ast_log(LOG_WARNING, "Can't send %d type frames with unistim_write\n",
05045 frame->frametype);
05046 return 0;
05047 }
05048 } else {
05049 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
05050 char tmp[256];
05051 ast_log(LOG_WARNING,
05052 "Asked to transmit frame type %s, while native formats is %s (read/write = (%s/%s)\n",
05053 ast_getformatname(&frame->subclass.format),
05054 ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(ast)),
05055 ast_getformatname(ast_channel_readformat(ast)),
05056 ast_getformatname(ast_channel_writeformat(ast)));
05057 return -1;
05058 }
05059 }
05060
05061 if (sub) {
05062 ast_mutex_lock(&sub->lock);
05063 if (sub->rtp) {
05064 res = ast_rtp_instance_write(sub->rtp, frame);
05065 }
05066 ast_mutex_unlock(&sub->lock);
05067 }
05068
05069 return res;
05070 }
05071
05072 static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
05073 {
05074 struct unistim_subchannel *p = ast_channel_tech_pvt(newchan);
05075 struct unistim_line *l = p->parent;
05076
05077 ast_mutex_lock(&p->lock);
05078
05079 ast_debug(1, "New owner for channel USTM/%s@%s-%d is %s\n", l->name,
05080 l->parent->name, p->subtype, ast_channel_name(newchan));
05081
05082 if (p->owner != oldchan) {
05083 ast_log(LOG_WARNING, "old channel wasn't %s (%p) but was %s (%p)\n",
05084 ast_channel_name(oldchan), oldchan, ast_channel_name(p->owner), p->owner);
05085 return -1;
05086 }
05087
05088 p->owner = newchan;
05089
05090 ast_mutex_unlock(&p->lock);
05091
05092 return 0;
05093
05094 }
05095
05096 static char *control2str(int ind)
05097 {
05098 switch (ind) {
05099 case AST_CONTROL_HANGUP:
05100 return "Other end has hungup";
05101 case AST_CONTROL_RING:
05102 return "Local ring";
05103 case AST_CONTROL_RINGING:
05104 return "Remote end is ringing";
05105 case AST_CONTROL_ANSWER:
05106 return "Remote end has answered";
05107 case AST_CONTROL_BUSY:
05108 return "Remote end is busy";
05109 case AST_CONTROL_TAKEOFFHOOK:
05110 return "Make it go off hook";
05111 case AST_CONTROL_OFFHOOK:
05112 return "Line is off hook";
05113 case AST_CONTROL_CONGESTION:
05114 return "Congestion (circuits busy)";
05115 case AST_CONTROL_FLASH:
05116 return "Flash hook";
05117 case AST_CONTROL_WINK:
05118 return "Wink";
05119 case AST_CONTROL_OPTION:
05120 return "Set a low-level option";
05121 case AST_CONTROL_RADIO_KEY:
05122 return "Key Radio";
05123 case AST_CONTROL_RADIO_UNKEY:
05124 return "Un-Key Radio";
05125 case AST_CONTROL_CONNECTED_LINE:
05126 return "Remote end changed";
05127 case AST_CONTROL_SRCCHANGE:
05128 return "RTP source updated";
05129 case AST_CONTROL_SRCUPDATE:
05130 return "Source of media changed";
05131 case -1:
05132 return "Stop tone";
05133 }
05134 return "UNKNOWN";
05135 }
05136
05137 static void in_band_indication(struct ast_channel *ast, const struct ast_tone_zone *tz,
05138 const char *indication)
05139 {
05140 struct ast_tone_zone_sound *ts = NULL;
05141
05142 if ((ts = ast_get_indication_tone(tz, indication))) {
05143 ast_playtones_start(ast, 0, ts->data, 1);
05144 ts = ast_tone_zone_sound_unref(ts);
05145 } else {
05146 ast_log(LOG_WARNING, "Unable to get indication tone for %s\n", indication);
05147 }
05148 }
05149
05150 static int unistim_indicate(struct ast_channel *ast, int ind, const void *data,
05151 size_t datalen)
05152 {
05153 struct unistim_subchannel *sub;
05154 struct unistim_line *l;
05155 struct unistimsession *s;
05156
05157 if (unistimdebug) {
05158 ast_verb(3, "Asked to indicate '%s' (%d) condition on channel %s\n",
05159 control2str(ind), ind, ast_channel_name(ast));
05160 }
05161
05162 s = channel_to_session(ast);
05163 if (!s) {
05164 return -1;
05165 }
05166 sub = ast_channel_tech_pvt(ast);
05167 l = sub->parent;
05168
05169 switch (ind) {
05170 case AST_CONTROL_RINGING:
05171 if (ast_channel_state(ast) != AST_STATE_UP) {
05172 send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Ringing...", s));
05173 in_band_indication(ast, l->parent->tz, "ring");
05174 s->device->missed_call = -1;
05175 break;
05176 }
05177 return -1;
05178 case AST_CONTROL_BUSY:
05179 if (ast_channel_state(ast) != AST_STATE_UP) {
05180 sub->alreadygone = 1;
05181 send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Busy", s));
05182 in_band_indication(ast, l->parent->tz, "busy");
05183 s->device->missed_call = -1;
05184 break;
05185 }
05186 return -1;
05187 case AST_CONTROL_INCOMPLETE:
05188
05189
05190
05191 case AST_CONTROL_CONGESTION:
05192 if (ast_channel_state(ast) != AST_STATE_UP) {
05193 sub->alreadygone = 1;
05194 send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Congestion", s));
05195 in_band_indication(ast, l->parent->tz, "congestion");
05196 s->device->missed_call = -1;
05197 break;
05198 }
05199 return -1;
05200 case AST_CONTROL_HOLD:
05201 ast_moh_start(ast, data, NULL);
05202 break;
05203 case AST_CONTROL_UNHOLD:
05204 ast_moh_stop(ast);
05205 break;
05206 case AST_CONTROL_PROGRESS:
05207 case AST_CONTROL_SRCUPDATE:
05208 case AST_CONTROL_PROCEEDING:
05209 break;
05210 case -1:
05211 ast_playtones_stop(ast);
05212 s->device->missed_call = 0;
05213 break;
05214 case AST_CONTROL_CONNECTED_LINE:
05215 ast_log(LOG_NOTICE, "Connected party is now %s <%s>\n",
05216 S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, ""),
05217 S_COR(ast_channel_connected(ast)->id.number.valid, ast_channel_connected(ast)->id.number.str, ""));
05218 if (sub->subtype == SUB_REAL) {
05219 send_callerid_screen(s, sub);
05220 }
05221 break;
05222 case AST_CONTROL_SRCCHANGE:
05223 ast_rtp_instance_change_source(sub->rtp);
05224 break;
05225 default:
05226 ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
05227
05228 case AST_CONTROL_PVT_CAUSE_CODE:
05229 return -1;
05230 }
05231
05232 return 0;
05233 }
05234
05235 static struct unistim_subchannel *find_subchannel_by_name(const char *dest)
05236 {
05237 struct unistim_line *l;
05238 struct unistim_device *d;
05239 struct unistim_subchannel *sub = NULL;
05240 char line[256];
05241 char *at;
05242 char *device;
05243
05244 ast_copy_string(line, dest, sizeof(line));
05245 at = strchr(line, '@');
05246 if (!at) {
05247 ast_log(LOG_NOTICE, "Device '%s' has no @ (at) sign!\n", dest);
05248 return NULL;
05249 }
05250 *at = '\0';
05251 at++;
05252 device = at;
05253 ast_mutex_lock(&devicelock);
05254 d = devices;
05255 at = strchr(device, '/');
05256 if (at) {
05257 *at = '\0';
05258 }
05259 while (d) {
05260 if (!strcasecmp(d->name, device)) {
05261 if (unistimdebug) {
05262 ast_verb(0, "Found device: %s\n", d->name);
05263 }
05264
05265 AST_LIST_LOCK(&d->lines);
05266 AST_LIST_TRAVERSE(&d->lines, l, list) {
05267
05268 if (!strcasecmp(l->name, line)) {
05269 if (unistimdebug) {
05270 ast_verb(0, "Found line: %s\n", l->name);
05271 }
05272 sub = get_sub(d, SUB_REAL);
05273 if (!sub) {
05274 sub = unistim_alloc_sub(d, SUB_REAL);
05275 }
05276 if (sub->owner) {
05277
05278 sub = unistim_alloc_sub(d, SUB_ONHOLD);
05279 }
05280 sub->ringvolume = -1;
05281 sub->ringstyle = -1;
05282 if (at) {
05283 at++;
05284 if (*at == 'r') {
05285 at++;
05286 if ((*at < '0') || (*at > '7')) {
05287 ast_log(LOG_WARNING, "Invalid ring selection (%s)", at);
05288 } else {
05289 char ring_volume = -1;
05290 char ring_style = *at - '0';
05291 at++;
05292 if ((*at >= '0') && (*at <= '3')) {
05293 ring_volume = *at - '0';
05294 }
05295 if (unistimdebug) {
05296 ast_verb(0, "Distinctive ring: style #%d volume %d\n",
05297 ring_style, ring_volume);
05298 }
05299 sub->ringvolume = ring_volume;
05300 sub->ringstyle = ring_style;
05301 }
05302 }
05303 }
05304 sub->parent = l;
05305 break;
05306 }
05307 }
05308 AST_LIST_UNLOCK(&d->lines);
05309 if (sub) {
05310 ast_mutex_unlock(&devicelock);
05311 return sub;
05312 }
05313 }
05314 d = d->next;
05315 }
05316
05317 ast_mutex_unlock(&devicelock);
05318
05319 return NULL;
05320 }
05321
05322 static int unistim_senddigit_begin(struct ast_channel *ast, char digit)
05323 {
05324 struct unistimsession *pte = channel_to_session(ast);
05325
05326 if (!pte) {
05327 return -1;
05328 }
05329 return unistim_do_senddigit(pte, digit);
05330 }
05331
05332 static int unistim_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
05333 {
05334 struct unistimsession *pte = channel_to_session(ast);
05335 struct ast_frame f = { 0, };
05336 struct unistim_subchannel *sub;
05337
05338 sub = get_sub(pte->device, SUB_REAL);
05339
05340 if (!sub || !sub->owner || sub->alreadygone) {
05341 ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit_end\n");
05342 return -1;
05343 }
05344
05345 if (unistimdebug) {
05346 ast_verb(0, "Send Digit off %c\n", digit);
05347 }
05348 if (!pte) {
05349 return -1;
05350 }
05351 send_tone(pte, 0, 0);
05352 f.frametype = AST_FRAME_DTMF;
05353 f.subclass.integer = digit;
05354 f.src = "unistim";
05355 ast_queue_frame(sub->owner, &f);
05356
05357 return 0;
05358 }
05359
05360
05361
05362 static int unistim_sendtext(struct ast_channel *ast, const char *text)
05363 {
05364 struct unistimsession *pte = channel_to_session(ast);
05365 int size;
05366 char tmp[TEXT_LENGTH_MAX + 1];
05367
05368 if (unistimdebug) {
05369 ast_verb(0, "unistim_sendtext called\n");
05370 }
05371 if (!text) {
05372 ast_log(LOG_WARNING, "unistim_sendtext called with a null text\n");
05373 return -1;
05374 }
05375
05376 if (!pte) {
05377 return -1;
05378 }
05379
05380 size = strlen(text);
05381 if (text[0] == '@') {
05382 int pos = 0, i = 1, tok = 0, sz = 0;
05383 char label[11];
05384 char number[16];
05385 char icon = '\0';
05386 char cur = '\0';
05387
05388 memset(label, 0, 11);
05389 memset(number, 0, 16);
05390 while (text[i]) {
05391 cur = text[i++];
05392 switch (tok) {
05393 case 0:
05394 if ((cur < '0') && (cur > '5')) {
05395 ast_log(LOG_WARNING,
05396 "sendtext failed : position must be a number beetween 0 and 5\n");
05397 return 1;
05398 }
05399 pos = cur - '0';
05400 tok = 1;
05401 continue;
05402 case 1:
05403 if (cur != '@') {
05404 ast_log(LOG_WARNING, "sendtext failed : invalid position\n");
05405 return 1;
05406 }
05407 tok = 2;
05408 continue;
05409 case 2:
05410 if ((cur < '3') && (cur > '6')) {
05411 ast_log(LOG_WARNING,
05412 "sendtext failed : icon must be a number beetween 32 and 63 (first digit invalid)\n");
05413 return 1;
05414 }
05415 icon = (cur - '0') * 10;
05416 tok = 3;
05417 continue;
05418 case 3:
05419 if ((cur < '0') && (cur > '9')) {
05420 ast_log(LOG_WARNING,
05421 "sendtext failed : icon must be a number beetween 32 and 63 (second digit invalid)\n");
05422 return 1;
05423 }
05424 icon += (cur - '0');
05425 tok = 4;
05426 continue;
05427 case 4:
05428 if (cur != '@') {
05429 ast_log(LOG_WARNING,
05430 "sendtext failed : icon must be a number beetween 32 and 63 (too many digits)\n");
05431 return 1;
05432 }
05433 tok = 5;
05434 continue;
05435 case 5:
05436 if (cur == '@') {
05437 tok = 6;
05438 sz = 0;
05439 continue;
05440 }
05441 if (sz > 10) {
05442 continue;
05443 }
05444 label[sz] = cur;
05445 sz++;
05446 continue;
05447 case 6:
05448 if (sz > 15) {
05449 ast_log(LOG_WARNING,
05450 "sendtext failed : extension too long = %d (15 car max)\n",
05451 sz);
05452 return 1;
05453 }
05454 number[sz] = cur;
05455 sz++;
05456 continue;
05457 }
05458 }
05459 if (tok != 6) {
05460 ast_log(LOG_WARNING, "sendtext failed : incomplet command\n");
05461 return 1;
05462 }
05463 if (!pte->device) {
05464 ast_log(LOG_WARNING, "sendtext failed : no device ?\n");
05465 return 1;
05466 }
05467 strcpy(pte->device->softkeylabel[pos], label);
05468 strcpy(pte->device->softkeynumber[pos], number);
05469 pte->device->softkeyicon[pos] = icon;
05470 send_favorite(pos, icon, pte, label);
05471 return 0;
05472 }
05473
05474 if (size <= TEXT_LENGTH_MAX * 2) {
05475 if (pte->device->height == 1) {
05476 send_text(TEXT_LINE0, TEXT_NORMAL, pte, text);
05477 } else {
05478 send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Message :", pte));
05479 send_text(TEXT_LINE1, TEXT_NORMAL, pte, text);
05480 }
05481 if (size <= TEXT_LENGTH_MAX) {
05482 send_text(TEXT_LINE2, TEXT_NORMAL, pte, "");
05483 return 0;
05484 }
05485 memcpy(tmp, text + TEXT_LENGTH_MAX, TEXT_LENGTH_MAX);
05486 tmp[sizeof(tmp) - 1] = '\0';
05487 send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
05488 return 0;
05489 }
05490 send_text(TEXT_LINE0, TEXT_NORMAL, pte, text);
05491 memcpy(tmp, text + TEXT_LENGTH_MAX, TEXT_LENGTH_MAX);
05492 tmp[sizeof(tmp) - 1] = '\0';
05493 send_text(TEXT_LINE1, TEXT_NORMAL, pte, tmp);
05494 memcpy(tmp, text + TEXT_LENGTH_MAX * 2, TEXT_LENGTH_MAX);
05495 tmp[sizeof(tmp) - 1] = '\0';
05496 send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
05497 return 0;
05498 }
05499
05500
05501 static int unistim_send_mwi_to_peer(struct unistim_line *peer, unsigned int tick)
05502 {
05503 struct ast_event *event;
05504 int new;
05505 char *mailbox, *context;
05506
05507 context = mailbox = ast_strdupa(peer->mailbox);
05508 strsep(&context, "@");
05509 if (ast_strlen_zero(context)) {
05510 context = "default";
05511 }
05512 event = ast_event_get_cached(AST_EVENT_MWI,
05513 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
05514 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
05515 AST_EVENT_IE_END);
05516
05517 if (event) {
05518 new = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
05519 ast_event_destroy(event);
05520 } else {
05521 new = ast_app_has_voicemail(peer->mailbox, "INBOX");
05522 }
05523
05524 peer->nextmsgcheck = tick + TIMER_MWI;
05525
05526
05527 if (new == peer->lastmsgssent) {
05528 return 0;
05529 }
05530
05531 peer->lastmsgssent = new;
05532 send_led_update(peer->parent->session, (new > 0));
05533
05534 return 0;
05535 }
05536
05537
05538
05539 static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const char *linkedid)
05540 {
05541 struct ast_channel *tmp;
05542 struct unistim_line *l;
05543 struct ast_format tmpfmt;
05544
05545 if (!sub) {
05546 ast_log(LOG_WARNING, "subchannel null in unistim_new\n");
05547 return NULL;
05548 }
05549 if (!sub->parent) {
05550 ast_log(LOG_WARNING, "no line for subchannel %p\n", sub);
05551 return NULL;
05552 }
05553 l = sub->parent;
05554 tmp = ast_channel_alloc(1, state, l->cid_num, NULL, l->accountcode, l->exten,
05555 l->parent->context, linkedid, l->amaflags, "USTM/%s@%s-%p", l->name, l->parent->name, sub);
05556 if (unistimdebug) {
05557 ast_verb(0, "unistim_new sub=%d (%p) chan=%p line=%s\n", sub->subtype, sub, tmp, l->name);
05558 }
05559 if (!tmp) {
05560 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
05561 return NULL;
05562 }
05563
05564 ast_format_cap_copy(ast_channel_nativeformats(tmp), l->cap);
05565 if (ast_format_cap_is_empty(ast_channel_nativeformats(tmp))) {
05566 ast_format_cap_copy(ast_channel_nativeformats(tmp), global_cap);
05567 }
05568 ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
05569
05570 if (unistimdebug) {
05571 char tmp1[256], tmp2[256], tmp3[256];
05572 ast_verb(0, "Best codec = %s from nativeformats %s (line cap=%s global=%s)\n",
05573 ast_getformatname(&tmpfmt),
05574 ast_getformatname_multiple(tmp1, sizeof(tmp1), ast_channel_nativeformats(tmp)),
05575 ast_getformatname_multiple(tmp2, sizeof(tmp2), l->cap),
05576 ast_getformatname_multiple(tmp3, sizeof(tmp3), global_cap));
05577 }
05578 if ((sub->rtp) && (sub->subtype == 0)) {
05579 if (unistimdebug) {
05580 ast_verb(0, "New unistim channel with a previous rtp handle ?\n");
05581 }
05582 ast_channel_internal_fd_set(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
05583 ast_channel_internal_fd_set(tmp, 1, ast_rtp_instance_fd(sub->rtp, 1));
05584 }
05585 if (sub->rtp) {
05586 ast_jb_configure(tmp, &global_jbconf);
05587 }
05588
05589 ast_setstate(tmp, state);
05590 if (state == AST_STATE_RING) {
05591 ast_channel_rings_set(tmp, 1);
05592 }
05593 ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
05594 ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
05595 ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
05596 ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
05597 ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
05598 ast_channel_tech_pvt_set(tmp, sub);
05599 ast_channel_tech_set(tmp, &unistim_tech);
05600
05601 if (!ast_strlen_zero(l->parent->language)) {
05602 ast_channel_language_set(tmp, l->parent->language);
05603 }
05604 sub->owner = tmp;
05605 ast_update_use_count();
05606 ast_channel_callgroup_set(tmp, l->callgroup);
05607 ast_channel_pickupgroup_set(tmp, l->pickupgroup);
05608 ast_channel_call_forward_set(tmp, l->parent->call_forward);
05609 if (!ast_strlen_zero(l->cid_num)) {
05610 char *name, *loc, *instr;
05611 instr = ast_strdup(l->cid_num);
05612 if (instr) {
05613 ast_callerid_parse(instr, &name, &loc);
05614 ast_channel_caller(tmp)->id.number.valid = 1;
05615 ast_free(ast_channel_caller(tmp)->id.number.str);
05616 ast_channel_caller(tmp)->id.number.str = ast_strdup(loc);
05617 ast_channel_caller(tmp)->id.name.valid = 1;
05618 ast_free(ast_channel_caller(tmp)->id.name.str);
05619 ast_channel_caller(tmp)->id.name.str = ast_strdup(name);
05620 ast_free(instr);
05621 }
05622 }
05623 ast_channel_priority_set(tmp, 1);
05624 if (state != AST_STATE_DOWN) {
05625 if (unistimdebug) {
05626 ast_verb(0, "Starting pbx in unistim_new\n");
05627 }
05628 if (ast_pbx_start(tmp)) {
05629 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
05630 ast_hangup(tmp);
05631 tmp = NULL;
05632 }
05633 }
05634
05635 return tmp;
05636 }
05637
05638 static void *do_monitor(void *data)
05639 {
05640 struct unistimsession *cur = NULL;
05641 unsigned int dw_timeout = 0;
05642 unsigned int tick;
05643 int res;
05644 int reloading;
05645
05646
05647 if (unistimsock > -1) {
05648 ast_io_add(io, unistimsock, unistimsock_read, AST_IO_IN, NULL);
05649 }
05650
05651 for (;;) {
05652
05653
05654 tick = get_tick_count();
05655 dw_timeout = UINT_MAX;
05656 ast_mutex_lock(&sessionlock);
05657 cur = sessions;
05658 DEBUG_TIMER("checking timeout for session %p with tick = %u\n", cur, tick);
05659 while (cur) {
05660 DEBUG_TIMER("checking timeout for session %p timeout = %u\n", cur,
05661 cur->timeout);
05662
05663 if (cur->timeout <= tick) {
05664 DEBUG_TIMER("Event for session %p\n", cur);
05665
05666 if (cur->last_buf_available == 0) {
05667 send_ping(cur);
05668 } else {
05669 if (send_retransmit(cur)) {
05670 DEBUG_TIMER("The chained link was modified, restarting...\n");
05671 cur = sessions;
05672 dw_timeout = UINT_MAX;
05673 continue;
05674 }
05675 }
05676 }
05677 if (dw_timeout > cur->timeout - tick) {
05678 dw_timeout = cur->timeout - tick;
05679 }
05680
05681 if (cur->device) {
05682 struct unistim_line *l;
05683 AST_LIST_LOCK(&cur->device->lines);
05684 AST_LIST_TRAVERSE(&cur->device->lines, l, list) {
05685 if ((!ast_strlen_zero(l->mailbox)) && (tick >= l->nextmsgcheck)) {
05686 DEBUG_TIMER("Checking mailbox for MWI\n");
05687 unistim_send_mwi_to_peer(l, tick);
05688 break;
05689 }
05690 }
05691 AST_LIST_UNLOCK(&cur->device->lines);
05692 if (cur->device->nextdial && tick >= cur->device->nextdial) {
05693 handle_call_outgoing(cur);
05694 cur->device->nextdial = 0;
05695 }
05696 }
05697 cur = cur->next;
05698 }
05699 ast_mutex_unlock(&sessionlock);
05700 DEBUG_TIMER("Waiting for %dus\n", dw_timeout);
05701 res = dw_timeout;
05702
05703 if ((res < 0) || (res > IDLE_WAIT)) {
05704 res = IDLE_WAIT;
05705 }
05706
05707 res = ast_io_wait(io, res);
05708
05709 ast_mutex_lock(&unistim_reload_lock);
05710 reloading = unistim_reloading;
05711 unistim_reloading = 0;
05712 ast_mutex_unlock(&unistim_reload_lock);
05713 if (reloading) {
05714 ast_verb(1, "Reloading unistim.conf...\n");
05715 reload_config();
05716 }
05717 pthread_testcancel();
05718 }
05719
05720 return NULL;
05721 }
05722
05723
05724 static int restart_monitor(void)
05725 {
05726 pthread_attr_t attr;
05727
05728 if (monitor_thread == AST_PTHREADT_STOP) {
05729 return 0;
05730 }
05731 if (ast_mutex_lock(&monlock)) {
05732 ast_log(LOG_WARNING, "Unable to lock monitor\n");
05733 return -1;
05734 }
05735 if (monitor_thread == pthread_self()) {
05736 ast_mutex_unlock(&monlock);
05737 ast_log(LOG_WARNING, "Cannot kill myself\n");
05738 return -1;
05739 }
05740 if (monitor_thread != AST_PTHREADT_NULL) {
05741
05742 pthread_kill(monitor_thread, SIGURG);
05743 } else {
05744 pthread_attr_init(&attr);
05745 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
05746
05747 if (ast_pthread_create(&monitor_thread, &attr, do_monitor, NULL) < 0) {
05748 ast_mutex_unlock(&monlock);
05749 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
05750 return -1;
05751 }
05752 }
05753 ast_mutex_unlock(&monlock);
05754 return 0;
05755 }
05756
05757
05758
05759 static struct ast_channel *unistim_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest,
05760 int *cause)
05761 {
05762 struct unistim_subchannel *sub, *sub_ring, *sub_trans;
05763 struct unistim_device *d;
05764 struct ast_channel *tmpc = NULL;
05765 char tmp[256];
05766 char tmp2[256];
05767
05768 if (!(ast_format_cap_has_joint(cap, global_cap))) {
05769 ast_log(LOG_NOTICE,
05770 "Asked to get a channel of unsupported format %s while capability is %s\n",
05771 ast_getformatname_multiple(tmp2, sizeof(tmp2), cap), ast_getformatname_multiple(tmp, sizeof(tmp), global_cap));
05772 return NULL;
05773 }
05774
05775 ast_copy_string(tmp, dest, sizeof(tmp));
05776 if (ast_strlen_zero(tmp)) {
05777 ast_log(LOG_NOTICE, "Unistim channels require a device\n");
05778 return NULL;
05779 }
05780 sub = find_subchannel_by_name(tmp);
05781 if (!sub) {
05782 ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
05783 *cause = AST_CAUSE_CONGESTION;
05784 return NULL;
05785 }
05786 d = sub->parent->parent;
05787 sub_ring = get_sub(d, SUB_RING);
05788 sub_trans = get_sub(d, SUB_THREEWAY);
05789
05790 if (!d->session) {
05791 unistim_unalloc_sub(d, sub);
05792 *cause = AST_CAUSE_CONGESTION;
05793 return NULL;
05794 }
05795 if (sub_ring || sub_trans) {
05796 if (unistimdebug) {
05797 ast_verb(0, "Can't create channel, request already in progress: Busy!\n");
05798 }
05799 unistim_unalloc_sub(d, sub);
05800 *cause = AST_CAUSE_BUSY;
05801 return NULL;
05802 }
05803 if (get_avail_softkey(d->session, sub->parent->name) == -1) {
05804 if (unistimdebug) {
05805 ast_verb(0, "Can't create channel for line %s, all lines busy\n", sub->parent->name);
05806 }
05807 unistim_unalloc_sub(d, sub);
05808 *cause = AST_CAUSE_BUSY;
05809 return NULL;
05810 }
05811 sub->subtype = SUB_RING;
05812 sub->softkey = -1;
05813 ast_format_cap_copy(sub->parent->cap, cap);
05814 tmpc = unistim_new(sub, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
05815 if (!tmpc) {
05816 ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
05817 }
05818 if (unistimdebug) {
05819 ast_verb(0, "unistim_request owner = %p\n", sub->owner);
05820 }
05821 restart_monitor();
05822
05823
05824 return tmpc;
05825 }
05826
05827 static char *unistim_show_info(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05828 {
05829 struct unistim_device *device = devices;
05830 struct unistim_line *line;
05831 struct unistim_subchannel *sub;
05832 struct unistimsession *s;
05833 struct ast_channel *tmp;
05834
05835 switch (cmd) {
05836 case CLI_INIT:
05837 e->command = "unistim show info";
05838 e->usage =
05839 "Usage: unistim show info\n"
05840 " Dump internal structures.\n\n"
05841 " device\n"
05842 " ->line\n"
05843 " -->sub\n"
05844 " ==>key\n";
05845 return NULL;
05846
05847 case CLI_GENERATE:
05848 return NULL;
05849 }
05850
05851 if (a->argc != e->args) {
05852 return CLI_SHOWUSAGE;
05853 }
05854 ast_cli(a->fd, "Dumping internal structures:\n");
05855 ast_mutex_lock(&devicelock);
05856 while (device) {
05857 int i;
05858
05859 ast_cli(a->fd, "\nname=%s id=%s ha=%p sess=%p device=%p selected=%d height=%d\n",
05860 device->name, device->id, device->ha, device->session,
05861 device, device->selected, device->height);
05862 AST_LIST_LOCK(&device->lines);
05863 AST_LIST_TRAVERSE(&device->lines,line,list) {
05864 char tmp2[256];
05865 ast_cli(a->fd,
05866 "->name=%s fullname=%s exten=%s callid=%s cap=%s line=%p\n",
05867 line->name, line->fullname, line->exten, line->cid_num,
05868 ast_getformatname_multiple(tmp2, sizeof(tmp2), line->cap), line);
05869 }
05870 AST_LIST_UNLOCK(&device->lines);
05871
05872 AST_LIST_LOCK(&device->subs);
05873 AST_LIST_TRAVERSE(&device->subs, sub, list) {
05874 if (!sub) {
05875 continue;
05876 }
05877 if (!sub->owner) {
05878 tmp = (void *) -42;
05879 } else {
05880 tmp = ast_channel_internal_bridged_channel(sub->owner);
05881 }
05882 ast_cli(a->fd,
05883 "-->subtype=%s chan=%p rtp=%p bridge=%p line=%p alreadygone=%d softkey=%d\n",
05884 subtype_tostr(sub->subtype), sub->owner, sub->rtp, tmp, sub->parent,
05885 sub->alreadygone, sub->softkey);
05886 }
05887 AST_LIST_UNLOCK(&device->subs);
05888
05889 for (i = 0; i < FAVNUM; i++) {
05890 if (!soft_key_visible(device, i)) {
05891 continue;
05892 }
05893 ast_cli(a->fd, "==> %d. dev=%s icon=%#-4x label=%-10s number=%-5s sub=%p line=%p\n",
05894 i, device->softkeydevice[i], device->softkeyicon[i], device->softkeylabel[i], device->softkeynumber[i],
05895 device->ssub[i], device->sline[i]);
05896 }
05897 device = device->next;
05898 }
05899 ast_mutex_unlock(&devicelock);
05900 ast_cli(a->fd, "\nSessions:\n");
05901 ast_mutex_lock(&sessionlock);
05902 s = sessions;
05903 while (s) {
05904 ast_cli(a->fd,
05905 "sin=%s timeout=%u state=%s macaddr=%s device=%s session=%p\n",
05906 ast_inet_ntoa(s->sin.sin_addr), s->timeout, ptestate_tostr(s->state), s->macaddr,
05907 s->device->name, s);
05908 s = s->next;
05909 }
05910 ast_mutex_unlock(&sessionlock);
05911
05912 return CLI_SUCCESS;
05913 }
05914
05915 static char *unistim_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05916 {
05917 struct unistim_device *device = devices;
05918
05919 switch (cmd) {
05920 case CLI_INIT:
05921 e->command = "unistim show devices";
05922 e->usage =
05923 "Usage: unistim show devices\n"
05924 " Lists all known Unistim devices.\n";
05925 return NULL;
05926 case CLI_GENERATE:
05927 return NULL;
05928 }
05929
05930 if (a->argc != e->args)
05931 return CLI_SHOWUSAGE;
05932
05933 ast_cli(a->fd, "%-20.20s %-20.20s %-15.15s %s\n", "Name/username", "MAC", "Host", "Status");
05934 ast_mutex_lock(&devicelock);
05935 while (device) {
05936 ast_cli(a->fd, "%-20.20s %-20.20s %-15.15s %s\n",
05937 device->name, device->id,
05938 (!device->session) ? "(Unspecified)" : ast_inet_ntoa(device->session->sin.sin_addr),
05939 (!device->session) ? "UNKNOWN" : "OK");
05940 device = device->next;
05941 }
05942 ast_mutex_unlock(&devicelock);
05943
05944 return CLI_SUCCESS;
05945 }
05946
05947 static char *unistim_sp(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05948 {
05949 BUFFSEND;
05950 struct unistim_subchannel *sub;
05951 int i, j = 0, len;
05952 unsigned char c, cc;
05953 char tmp[256];
05954
05955 switch (cmd) {
05956 case CLI_INIT:
05957 e->command = "unistim send packet";
05958 e->usage =
05959 "Usage: unistim send packet USTM/line@name hexa\n"
05960 " unistim send packet USTM/1000@hans 19040004\n";
05961 return NULL;
05962
05963 case CLI_GENERATE:
05964 return NULL;
05965 }
05966
05967 if (a->argc < 5) {
05968 return CLI_SHOWUSAGE;
05969 }
05970 if (strlen(a->argv[3]) < 9) {
05971 return CLI_SHOWUSAGE;
05972 }
05973 len = strlen(a->argv[4]);
05974 if (len % 2) {
05975 return CLI_SHOWUSAGE;
05976 }
05977 ast_copy_string(tmp, a->argv[3] + 5, sizeof(tmp));
05978 sub = find_subchannel_by_name(tmp);
05979 if (!sub) {
05980 ast_cli(a->fd, "Can't find '%s'\n", tmp);
05981 return CLI_SUCCESS;
05982 }
05983 if (!sub->parent->parent->session) {
05984 ast_cli(a->fd, "'%s' is not connected\n", tmp);
05985 return CLI_SUCCESS;
05986 }
05987 ast_cli(a->fd, "Sending '%s' to %s (%p)\n", a->argv[4], tmp, sub->parent->parent->session);
05988 for (i = 0; i < len; i++) {
05989 c = a->argv[4][i];
05990 if (c >= 'a') {
05991 c -= 'a' - 10;
05992 } else {
05993 c -= '0';
05994 }
05995 i++;
05996 cc = a->argv[4][i];
05997 if (cc >= 'a') {
05998 cc -= 'a' - 10;
05999 } else {
06000 cc -= '0';
06001 }
06002 tmp[j++] = (c << 4) | cc;
06003 }
06004 memcpy(buffsend + SIZE_HEADER, tmp, j);
06005 send_client(SIZE_HEADER + j, buffsend, sub->parent->parent->session);
06006 return CLI_SUCCESS;
06007 }
06008
06009 static char *unistim_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06010 {
06011 switch (cmd) {
06012 case CLI_INIT:
06013 e->command = "unistim set debug {on|off}";
06014 e->usage =
06015 "Usage: unistim set debug\n"
06016 " Display debug messages.\n";
06017 return NULL;
06018
06019 case CLI_GENERATE:
06020 return NULL;
06021 }
06022
06023 if (a->argc != e->args) {
06024 return CLI_SHOWUSAGE;
06025 }
06026 if (!strcasecmp(a->argv[3], "on")) {
06027 unistimdebug = 1;
06028 ast_cli(a->fd, "UNISTIM Debugging Enabled\n");
06029 } else if (!strcasecmp(a->argv[3], "off")) {
06030 unistimdebug = 0;
06031 ast_cli(a->fd, "UNISTIM Debugging Disabled\n");
06032 } else {
06033 return CLI_SHOWUSAGE;
06034 }
06035 return CLI_SUCCESS;
06036 }
06037
06038
06039
06040
06041
06042 static char *unistim_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06043 {
06044 switch (cmd) {
06045 case CLI_INIT:
06046 e->command = "unistim reload";
06047 e->usage =
06048 "Usage: unistim reload\n"
06049 " Reloads UNISTIM configuration from unistim.conf\n";
06050 return NULL;
06051
06052 case CLI_GENERATE:
06053 return NULL;
06054 }
06055
06056 if (e && a && a->argc != e->args) {
06057 return CLI_SHOWUSAGE;
06058 }
06059 reload();
06060
06061 return CLI_SUCCESS;
06062 }
06063
06064 static struct ast_cli_entry unistim_cli[] = {
06065 AST_CLI_DEFINE(unistim_reload, "Reload UNISTIM configuration"),
06066 AST_CLI_DEFINE(unistim_show_info, "Show UNISTIM info"),
06067 AST_CLI_DEFINE(unistim_show_devices, "Show UNISTIM devices"),
06068 AST_CLI_DEFINE(unistim_sp, "Send packet (for reverse engineering)"),
06069 AST_CLI_DEFINE(unistim_do_debug, "Toggle UNITSTIM debugging"),
06070 };
06071
06072 static void unquote(char *out, const char *src, int maxlen)
06073 {
06074 int len = strlen(src);
06075 if (!len) {
06076 return;
06077 }
06078 if ((len > 1) && src[0] == '\"') {
06079
06080 src++;
06081
06082 len--;
06083 if (maxlen > len - 1) {
06084 maxlen = len - 1;
06085 }
06086 memcpy(out, src, maxlen);
06087 ((char *) out)[maxlen] = '\0';
06088 } else {
06089 memcpy(out, src, maxlen);
06090 }
06091 return;
06092 }
06093
06094 static int parse_bookmark(const char *text, struct unistim_device *d)
06095 {
06096 char line[256];
06097 char *at;
06098 char *number;
06099 char *icon;
06100 int p;
06101 int len = strlen(text);
06102
06103 ast_copy_string(line, text, sizeof(line));
06104
06105 if ((len > 2) && (line[1] == '@')) {
06106 p = line[0];
06107 if ((p >= '0') && (p <= '5')) {
06108 p -= '0';
06109 } else {
06110 ast_log(LOG_WARNING,
06111 "Invalid position for bookmark : must be between 0 and 5\n");
06112 return 0;
06113 }
06114 if (d->softkeyicon[p] != 0) {
06115 ast_log(LOG_WARNING, "Invalid position %d for bookmark : already used\n:", p);
06116 return 0;
06117 }
06118 memmove(line, line + 2, sizeof(line) - 2);
06119 } else {
06120
06121 for (p = 0; p <= 5; p++) {
06122 if (!d->softkeyicon[p]) {
06123 break;
06124 }
06125 }
06126 if (p > 5) {
06127 ast_log(LOG_WARNING, "No more free bookmark position\n");
06128 return 0;
06129 }
06130 }
06131 at = strchr(line, '@');
06132 if (!at) {
06133 ast_log(LOG_NOTICE, "Bookmark entry '%s' has no @ (at) sign!\n", text);
06134 return 0;
06135 }
06136 *at = '\0';
06137 at++;
06138 number = at;
06139 at = strchr(at, '@');
06140 if (ast_strlen_zero(number)) {
06141 ast_log(LOG_NOTICE, "Bookmark entry '%s' has no number\n", text);
06142 return 0;
06143 }
06144 if (ast_strlen_zero(line)) {
06145 ast_log(LOG_NOTICE, "Bookmark entry '%s' has no description\n", text);
06146 return 0;
06147 }
06148
06149 at = strchr(number, '@');
06150 if (!at) {
06151 d->softkeyicon[p] = FAV_ICON_SHARP;
06152 } else {
06153 *at = '\0';
06154 at++;
06155 icon = at;
06156 if (ast_strlen_zero(icon)) {
06157 ast_log(LOG_NOTICE, "Bookmark entry '%s' has no icon value\n", text);
06158 return 0;
06159 }
06160 if (strncmp(icon, "USTM/", 5)) {
06161 d->softkeyicon[p] = atoi(icon);
06162 } else {
06163 d->softkeyicon[p] = 1;
06164 ast_copy_string(d->softkeydevice[p], icon + 5, sizeof(d->softkeydevice[p]));
06165 }
06166 }
06167 ast_copy_string(d->softkeylabel[p], line, sizeof(d->softkeylabel[p]));
06168 ast_copy_string(d->softkeynumber[p], number, sizeof(d->softkeynumber[p]));
06169 if (unistimdebug) {
06170 ast_verb(0, "New bookmark at pos %d label='%s' number='%s' icon=%#x\n",
06171 p, d->softkeylabel[p], d->softkeynumber[p], d->softkeyicon[p]);
06172 }
06173 return 1;
06174 }
06175
06176
06177 static void finish_bookmark(void)
06178 {
06179 struct unistim_device *d = devices;
06180 int i;
06181 ast_mutex_lock(&devicelock);
06182 while (d) {
06183 for (i = 0; i < 6; i++) {
06184 if (d->softkeyicon[i] == 1) {
06185 struct unistim_device *d2 = devices;
06186 while (d2) {
06187 if (!strcmp(d->softkeydevice[i], d2->name)) {
06188 d->sp[i] = d2;
06189 d->softkeyicon[i] = 0;
06190 break;
06191 }
06192 d2 = d2->next;
06193 }
06194 if (d->sp[i] == NULL) {
06195 ast_log(LOG_NOTICE, "Bookmark entry with device %s not found\n",
06196 d->softkeydevice[i]);
06197 }
06198 }
06199 }
06200 d = d->next;
06201 }
06202 ast_mutex_unlock(&devicelock);
06203 }
06204
06205 static struct unistim_line *find_line_by_number(struct unistim_device *d, const char *val) {
06206 struct unistim_line *l, *ret = NULL;
06207
06208 AST_LIST_LOCK(&d->lines);
06209 AST_LIST_TRAVERSE(&d->lines, l, list) {
06210 if (!strcmp(l->name, val)) {
06211 ret = l;
06212 break;
06213 }
06214 }
06215 AST_LIST_UNLOCK(&d->lines);
06216 return ret;
06217 }
06218
06219 static struct unistim_device *build_device(const char *cat, const struct ast_variable *v)
06220 {
06221 struct unistim_device *d;
06222 struct unistim_line *l = NULL, *lt = NULL;
06223 int create = 1;
06224 int nbsoftkey, dateformat, timeformat, callhistory, sharpdial, linecnt;
06225 char linelabel[AST_MAX_EXTENSION];
06226 char ringvolume, ringstyle, cwvolume, cwstyle;
06227
06228
06229
06230 ast_mutex_lock(&devicelock);
06231 d = devices;
06232 while (d) {
06233 if (!strcmp(d->name, cat)) {
06234
06235 if (unistimsock < 0) {
06236
06237 ast_log(LOG_WARNING, "Duplicate entry found (%s), ignoring.\n", cat);
06238 ast_mutex_unlock(&devicelock);
06239 return NULL;
06240 }
06241
06242 create = 0;
06243 break;
06244 }
06245 d = d->next;
06246 }
06247 if (!(lt = ast_calloc(1, sizeof(*lt)))) {
06248 return NULL;
06249 }
06250 ast_mutex_unlock(&devicelock);
06251 if (create) {
06252 if (!(d = ast_calloc(1, sizeof(*d)))) {
06253 return NULL;
06254 }
06255 ast_mutex_init(&d->lock);
06256 ast_copy_string(d->name, cat, sizeof(d->name));
06257 } else {
06258
06259 AST_LIST_LOCK(&d->lines);
06260 AST_LIST_TRAVERSE_SAFE_BEGIN(&d->lines, l, list){
06261 AST_LIST_REMOVE_CURRENT(list);
06262 unistim_line_destroy(l);
06263 }
06264 AST_LIST_TRAVERSE_SAFE_END
06265 AST_LIST_UNLOCK(&d->lines);
06266
06267
06268 memset(d->softkeylabel, 0, sizeof(d->softkeylabel));
06269 memset(d->softkeynumber, 0, sizeof(d->softkeynumber));
06270 memset(d->softkeyicon, 0, sizeof(d->softkeyicon));
06271 memset(d->softkeydevice, 0, sizeof(d->softkeydevice));
06272 memset(d->ssub, 0, sizeof(d->ssub));
06273 memset(d->sline, 0, sizeof(d->sline));
06274 memset(d->sp, 0, sizeof(d->sp));
06275 }
06276
06277 ast_copy_string(d->context, DEFAULTCONTEXT, sizeof(d->context));
06278 d->contrast = -1;
06279 d->output = OUTPUT_HANDSET;
06280 d->previous_output = OUTPUT_HANDSET;
06281 d->volume = VOLUME_LOW;
06282 d->mute = MUTE_OFF;
06283 d->height = DEFAULTHEIGHT;
06284 d->selected = -1;
06285 linelabel[0] = '\0';
06286 dateformat = 1;
06287 timeformat = 1;
06288 ringvolume = 2;
06289 cwvolume = 1;
06290 callhistory = 1;
06291 sharpdial = 0;
06292 ringstyle = 3;
06293 cwstyle = 2;
06294 nbsoftkey = 0;
06295 linecnt = 0;
06296 while (v) {
06297 if (!strcasecmp(v->name, "rtp_port")) {
06298 d->rtp_port = atoi(v->value);
06299 } else if (!strcasecmp(v->name, "rtp_method")) {
06300 d->rtp_method = atoi(v->value);
06301 } else if (!strcasecmp(v->name, "status_method")) {
06302 d->status_method = atoi(v->value);
06303 } else if (!strcasecmp(v->name, "device")) {
06304 ast_copy_string(d->id, v->value, sizeof(d->id));
06305 } else if (!strcasecmp(v->name, "tn")) {
06306 ast_copy_string(d->extension_number, v->value, sizeof(d->extension_number));
06307 } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
06308 d->ha = ast_append_ha(v->name, v->value, d->ha, NULL);
06309 } else if (!strcasecmp(v->name, "context")) {
06310 ast_copy_string(d->context, v->value, sizeof(d->context));
06311 } else if (!strcasecmp(v->name, "maintext0")) {
06312 unquote(d->maintext0, v->value, sizeof(d->maintext0) - 1);
06313 } else if (!strcasecmp(v->name, "maintext1")) {
06314 unquote(d->maintext1, v->value, sizeof(d->maintext1) - 1);
06315 } else if (!strcasecmp(v->name, "maintext2")) {
06316 unquote(d->maintext2, v->value, sizeof(d->maintext2) - 1);
06317 } else if (!strcasecmp(v->name, "titledefault")) {
06318 unquote(d->titledefault, v->value, sizeof(d->titledefault) - 1);
06319 } else if (!strcasecmp(v->name, "dateformat")) {
06320 dateformat = atoi(v->value);
06321 } else if (!strcasecmp(v->name, "timeformat")) {
06322 timeformat = atoi(v->value);
06323 } else if (!strcasecmp(v->name, "contrast")) {
06324 d->contrast = atoi(v->value);
06325 if ((d->contrast < 0) || (d->contrast > 15)) {
06326 ast_log(LOG_WARNING, "contrast must be beetween 0 and 15\n");
06327 d->contrast = 8;
06328 }
06329 } else if (!strcasecmp(v->name, "nat")) {
06330 d->nat = ast_true(v->value);
06331 } else if (!strcasecmp(v->name, "ringvolume")) {
06332 ringvolume = atoi(v->value);
06333 } else if (!strcasecmp(v->name, "ringstyle")) {
06334 ringstyle = atoi(v->value);
06335 } else if (!strcasecmp(v->name, "cwvolume")) {
06336 cwvolume = atoi(v->value);
06337 } else if (!strcasecmp(v->name, "cwstyle")) {
06338 cwstyle = atoi(v->value);
06339 } else if (!strcasecmp(v->name, "callhistory")) {
06340 callhistory = atoi(v->value);
06341 } else if (!strcasecmp(v->name, "sharpdial")) {
06342 sharpdial = ast_true(v->value) ? 1 : 0;
06343 } else if (!strcasecmp(v->name, "callerid")) {
06344 if (!strcasecmp(v->value, "asreceived")) {
06345 lt->cid_num[0] = '\0';
06346 } else {
06347 ast_copy_string(lt->cid_num, v->value, sizeof(lt->cid_num));
06348 }
06349 } else if (!strcasecmp(v->name, "language")) {
06350 ast_copy_string(d->language, v->value, sizeof(d->language));
06351 } else if (!strcasecmp(v->name, "country")) {
06352 ast_copy_string(d->country, v->value, sizeof(d->country));
06353 } else if (!strcasecmp(v->name, "accountcode")) {
06354 ast_copy_string(lt->accountcode, v->value, sizeof(lt->accountcode));
06355 } else if (!strcasecmp(v->name, "amaflags")) {
06356 int y;
06357 y = ast_cdr_amaflags2int(v->value);
06358 if (y < 0) {
06359 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value,
06360 v->lineno);
06361 } else {
06362 lt->amaflags = y;
06363 }
06364 } else if (!strcasecmp(v->name, "musiconhold")) {
06365 ast_copy_string(lt->musicclass, v->value, sizeof(lt->musicclass));
06366 } else if (!strcasecmp(v->name, "callgroup")) {
06367 lt->callgroup = ast_get_group(v->value);
06368 } else if (!strcasecmp(v->name, "pickupgroup")) {
06369 lt->pickupgroup = ast_get_group(v->value);
06370 } else if (!strcasecmp(v->name, "mailbox")) {
06371 ast_copy_string(lt->mailbox, v->value, sizeof(lt->mailbox));
06372 } else if (!strcasecmp(v->name, "parkinglot")) {
06373 ast_copy_string(lt->parkinglot, v->value, sizeof(lt->parkinglot));
06374 } else if (!strcasecmp(v->name, "linelabel")) {
06375 unquote(linelabel, v->value, sizeof(linelabel) - 1);
06376 } else if (!strcasecmp(v->name, "extension")) {
06377 if (!strcasecmp(v->value, "none")) {
06378 d->extension = EXTENSION_NONE;
06379 } else if (!strcasecmp(v->value, "ask")) {
06380 d->extension = EXTENSION_ASK;
06381 } else if (!strcasecmp(v->value, "line")) {
06382 d->extension = EXTENSION_LINE;
06383 } else {
06384 ast_log(LOG_WARNING, "Unknown extension option.\n");
06385 }
06386 } else if (!strcasecmp(v->name, "bookmark")) {
06387 if (nbsoftkey > 5) {
06388 ast_log(LOG_WARNING,
06389 "More than 6 softkeys defined. Ignoring new entries.\n");
06390 } else {
06391 if (parse_bookmark(v->value, d)) {
06392 nbsoftkey++;
06393 }
06394 }
06395 } else if (!strcasecmp(v->name, "line")) {
06396 int len = strlen(linelabel);
06397 int create_line = 0;
06398
06399 l = find_line_by_number(d, v->value);
06400 if (!l) {
06401 if (!(l = unistim_line_alloc())) {
06402 ast_free(d);
06403 ast_free(lt);
06404 return NULL;
06405 }
06406 lt->cap = l->cap;
06407 memcpy(l, lt, sizeof(*l));
06408 ast_mutex_init(&l->lock);
06409 create_line = 1;
06410 }
06411 d->to_delete = 0;
06412
06413
06414 d->sline[nbsoftkey] = l;
06415 d->softkeyicon[nbsoftkey] = FAV_LINE_ICON;
06416 if (!len) {
06417 ast_copy_string(d->softkeylabel[nbsoftkey], v->value, sizeof(d->softkeylabel[nbsoftkey]));
06418 } else {
06419 int softkeylinepos = 0;
06420 if ((len > 2) && (linelabel[1] == '@')) {
06421 softkeylinepos = linelabel[0];
06422 if ((softkeylinepos >= '0') && (softkeylinepos <= '5')) {
06423 softkeylinepos -= '0';
06424 d->softkeyicon[nbsoftkey] = FAV_ICON_NONE;
06425 } else {
06426 ast_log(LOG_WARNING,
06427 "Invalid position for linelabel : must be between 0 and 5\n");
06428 }
06429 ast_copy_string(d->softkeylabel[softkeylinepos], linelabel + 2,
06430 sizeof(d->softkeylabel[softkeylinepos]));
06431 d->softkeyicon[softkeylinepos] = FAV_LINE_ICON;
06432 } else {
06433 ast_copy_string(d->softkeylabel[nbsoftkey], linelabel,
06434 sizeof(d->softkeylabel[nbsoftkey]));
06435 }
06436 }
06437 nbsoftkey++;
06438
06439 if (create_line) {
06440 ast_copy_string(l->name, v->value, sizeof(l->name));
06441 snprintf(l->fullname, sizeof(l->fullname), "USTM/%s@%s", l->name, d->name);
06442 if (!ast_strlen_zero(l->mailbox)) {
06443 if (unistimdebug) {
06444 ast_verb(3, "Setting mailbox '%s' on %s@%s\n", l->mailbox, d->name, l->name);
06445 }
06446 }
06447 ast_format_cap_copy(l->cap, global_cap);
06448 l->parent = d;
06449 linecnt++;
06450 AST_LIST_LOCK(&d->lines);
06451 AST_LIST_INSERT_TAIL(&d->lines, l, list);
06452 AST_LIST_UNLOCK(&d->lines);
06453 }
06454 } else if (!strcasecmp(v->name, "height")) {
06455
06456
06457 d->height = atoi(v->value);
06458 } else
06459 ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name,
06460 v->lineno);
06461 v = v->next;
06462 }
06463 ast_free(lt);
06464 if (linecnt == 0) {
06465 ast_log(LOG_ERROR, "An Unistim device must have at least one line!\n");
06466 ast_free(d);
06467 return NULL;
06468 }
06469 d->ringvolume = ringvolume;
06470 d->ringstyle = ringstyle;
06471 d->cwvolume = cwvolume;
06472 d->cwstyle = cwstyle;
06473 d->callhistory = callhistory;
06474 d->sharp_dial = sharpdial;
06475 d->tz = ast_get_indication_zone(d->country);
06476 if ((d->tz == NULL) && !ast_strlen_zero(d->country)) {
06477 ast_log(LOG_WARNING, "Country '%s' was not found in indications.conf\n",
06478 d->country);
06479 }
06480 d->datetimeformat = 56 + (dateformat * 4);
06481 d->datetimeformat += timeformat;
06482 if ((autoprovisioning == AUTOPROVISIONING_TN) &&
06483 (!ast_strlen_zero(d->extension_number))) {
06484 d->extension = EXTENSION_TN;
06485 if (!ast_strlen_zero(d->id)) {
06486 ast_log(LOG_WARNING,
06487 "tn= and device= can't be used together. Ignoring device= entry\n");
06488 }
06489 d->id[0] = 'T';
06490 ast_copy_string((d->id) + 1, d->extension_number, sizeof(d->id) - 1);
06491 d->extension_number[0] = '\0';
06492 } else if (ast_strlen_zero(d->id)) {
06493 if (strcmp(d->name, "template")) {
06494 ast_log(LOG_ERROR, "You must specify the mac address with device=\n");
06495 if (d->tz) {
06496 d->tz = ast_tone_zone_unref(d->tz);
06497 }
06498 ast_free(d);
06499 return NULL;
06500 } else {
06501 strcpy(d->id, "000000000000");
06502 }
06503 }
06504 if (!d->rtp_port) {
06505 d->rtp_port = 10000;
06506 }
06507 if (d->contrast == -1) {
06508 d->contrast = 8;
06509 }
06510 if (ast_strlen_zero(d->maintext1)) {
06511 strcpy(d->maintext1, d->name);
06512 }
06513 if (ast_strlen_zero(d->titledefault)) {
06514 struct ast_tm tm = { 0, };
06515 struct timeval cur_time = ast_tvnow();
06516
06517 if ((ast_localtime(&cur_time, &tm, 0)) == 0 || ast_strlen_zero(tm.tm_zone)) {
06518 ast_log(LOG_WARNING, "Error in ast_localtime()\n");
06519 ast_copy_string(d->titledefault, "UNISTIM for*", 12);
06520 } else {
06521 if (strlen(tm.tm_zone) < 4) {
06522 strcpy(d->titledefault, "TimeZone ");
06523 strcat(d->titledefault, tm.tm_zone);
06524 } else if (strlen(tm.tm_zone) < 9) {
06525 strcpy(d->titledefault, "TZ ");
06526 strcat(d->titledefault, tm.tm_zone);
06527 } else {
06528 ast_copy_string(d->titledefault, tm.tm_zone, 12);
06529 }
06530 }
06531 }
06532
06533 if (create) {
06534 ast_mutex_lock(&devicelock);
06535 d->next = devices;
06536 devices = d;
06537 ast_mutex_unlock(&devicelock);
06538 ast_verb(3, "Added device '%s'\n", d->name);
06539 } else {
06540 ast_verb(3, "Device '%s' reloaded\n", d->name);
06541 }
06542 return d;
06543 }
06544
06545
06546 static int reload_config(void)
06547 {
06548 struct ast_config *cfg;
06549 struct ast_variable *v;
06550 struct ast_hostent ahp;
06551 struct hostent *hp;
06552 struct sockaddr_in bindaddr = { 0, };
06553 char *config = "unistim.conf";
06554 char *cat;
06555 struct unistim_device *d;
06556 const int reuseFlag = 1;
06557 struct unistimsession *s;
06558 struct ast_flags config_flags = { 0, };
06559
06560 cfg = ast_config_load(config, config_flags);
06561
06562 if (!cfg) {
06563 ast_log(LOG_ERROR, "Unable to load config %s\n", config);
06564 return -1;
06565 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06566 ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config);
06567 return -1;
06568 }
06569
06570
06571 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
06572
06573 unistim_keepalive = 120;
06574 unistim_port = 0;
06575 v = ast_variable_browse(cfg, "general");
06576 while (v) {
06577
06578 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
06579 continue;
06580 }
06581 if (!strcasecmp(v->name, "keepalive")) {
06582 unistim_keepalive = atoi(v->value);
06583 } else if (!strcasecmp(v->name, "port")) {
06584 unistim_port = atoi(v->value);
06585 } else if (!strcasecmp(v->name, "tos")) {
06586 if (ast_str2tos(v->value, &qos.tos)) {
06587 ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
06588 }
06589 } else if (!strcasecmp(v->name, "tos_audio")) {
06590 if (ast_str2tos(v->value, &qos.tos_audio)) {
06591 ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
06592 }
06593 } else if (!strcasecmp(v->name, "cos")) {
06594 if (ast_str2cos(v->value, &qos.cos)) {
06595 ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
06596 }
06597 } else if (!strcasecmp(v->name, "cos_audio")) {
06598 if (ast_str2cos(v->value, &qos.cos_audio)) {
06599 ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
06600 }
06601 } else if (!strcasecmp(v->name, "debug")) {
06602 if (!strcasecmp(v->value, "no")) {
06603 unistimdebug = 0;
06604 } else if (!strcasecmp(v->value, "yes")) {
06605 unistimdebug = 1;
06606 }
06607 } else if (!strcasecmp(v->name, "autoprovisioning")) {
06608 if (!strcasecmp(v->value, "no")) {
06609 autoprovisioning = AUTOPROVISIONING_NO;
06610 } else if (!strcasecmp(v->value, "yes")) {
06611 autoprovisioning = AUTOPROVISIONING_YES;
06612 } else if (!strcasecmp(v->value, "tn")) {
06613 autoprovisioning = AUTOPROVISIONING_TN;
06614 } else {
06615 ast_log(LOG_WARNING, "Unknown autoprovisioning option.\n");
06616 }
06617 } else if (!strcasecmp(v->name, "public_ip")) {
06618 if (!ast_strlen_zero(v->value)) {
06619 if (!(hp = ast_gethostbyname(v->value, &ahp))) {
06620 ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
06621 } else {
06622 memcpy(&public_ip.sin_addr, hp->h_addr, sizeof(public_ip.sin_addr));
06623 public_ip.sin_family = AF_INET;
06624 }
06625 }
06626 }
06627 v = v->next;
06628 }
06629 if ((unistim_keepalive < 10) ||
06630 (unistim_keepalive >
06631 255 - (((NB_MAX_RETRANSMIT + 1) * RETRANSMIT_TIMER) / 1000))) {
06632 ast_log(LOG_ERROR, "keepalive is invalid in %s\n", config);
06633 ast_config_destroy(cfg);
06634 return -1;
06635 }
06636 packet_send_ping[4] =
06637 unistim_keepalive + (((NB_MAX_RETRANSMIT + 1) * RETRANSMIT_TIMER) / 1000);
06638 if ((unistim_port < 1) || (unistim_port > 65535)) {
06639 ast_log(LOG_ERROR, "port is not set or invalid in %s\n", config);
06640 ast_config_destroy(cfg);
06641 return -1;
06642 }
06643 unistim_keepalive *= 1000;
06644
06645 ast_mutex_lock(&devicelock);
06646 d = devices;
06647 while (d) {
06648 if (d->to_delete >= 0) {
06649 d->to_delete = 1;
06650 }
06651 d = d->next;
06652 }
06653 ast_mutex_unlock(&devicelock);
06654
06655 cat = ast_category_browse(cfg, NULL);
06656 while (cat) {
06657 if (strcasecmp(cat, "general")) {
06658 d = build_device(cat, ast_variable_browse(cfg, cat));
06659 }
06660 cat = ast_category_browse(cfg, cat);
06661 }
06662 ast_mutex_lock(&devicelock);
06663 d = devices;
06664 while (d) {
06665 if (d->to_delete) {
06666 struct unistim_line *l;
06667 struct unistim_subchannel *sub;
06668
06669 if (unistimdebug) {
06670 ast_verb(0, "Removing device '%s'\n", d->name);
06671 }
06672 AST_LIST_LOCK(&d->subs);
06673 AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, sub, list){
06674 if (sub->subtype == SUB_REAL) {
06675 if (!sub) {
06676 ast_log(LOG_ERROR, "Device '%s' without a subchannel !, aborting\n",
06677 d->name);
06678 ast_config_destroy(cfg);
06679 return 0;
06680 }
06681 if (sub->owner) {
06682 ast_log(LOG_WARNING,
06683 "Device '%s' was not deleted : a call is in progress. Try again later.\n",
06684 d->name);
06685 d = d->next;
06686 continue;
06687 }
06688 }
06689 if (sub->subtype == SUB_THREEWAY) {
06690 ast_log(LOG_WARNING,
06691 "Device '%s' with threeway call subchannels allocated, aborting.\n",
06692 d->name);
06693 break;
06694 }
06695 AST_LIST_REMOVE_CURRENT(list);
06696 ast_mutex_destroy(&sub->lock);
06697 ast_free(sub);
06698 }
06699 AST_LIST_TRAVERSE_SAFE_END
06700 AST_LIST_UNLOCK(&d->subs);
06701
06702
06703 AST_LIST_LOCK(&d->lines);
06704 AST_LIST_TRAVERSE_SAFE_BEGIN(&d->lines, l, list){
06705 AST_LIST_REMOVE_CURRENT(list);
06706 ast_mutex_destroy(&l->lock);
06707 unistim_line_destroy(l);
06708 }
06709 AST_LIST_TRAVERSE_SAFE_END
06710 AST_LIST_UNLOCK(&d->lines);
06711
06712 if (d->session) {
06713 if (sessions == d->session) {
06714 sessions = d->session->next;
06715 } else {
06716 s = sessions;
06717 while (s) {
06718 if (s->next == d->session) {
06719 s->next = d->session->next;
06720 break;
06721 }
06722 s = s->next;
06723 }
06724 }
06725 ast_mutex_destroy(&d->session->lock);
06726 ast_free(d->session);
06727 }
06728 if (devices == d) {
06729 devices = d->next;
06730 } else {
06731 struct unistim_device *d2 = devices;
06732 while (d2) {
06733 if (d2->next == d) {
06734 d2->next = d->next;
06735 break;
06736 }
06737 d2 = d2->next;
06738 }
06739 }
06740 if (d->tz) {
06741 d->tz = ast_tone_zone_unref(d->tz);
06742 }
06743 ast_mutex_destroy(&d->lock);
06744 ast_free(d);
06745 d = devices;
06746 continue;
06747 }
06748 d = d->next;
06749 }
06750 finish_bookmark();
06751 ast_mutex_unlock(&devicelock);
06752 ast_config_destroy(cfg);
06753 ast_mutex_lock(&sessionlock);
06754 s = sessions;
06755 while (s) {
06756 if (s->device) {
06757 refresh_all_favorite(s);
06758 if (ast_strlen_zero(s->device->language)) {
06759 struct unistim_languages lang;
06760 lang = options_languages[find_language(s->device->language)];
06761 send_charset_update(s, lang.encoding);
06762 }
06763 }
06764 s = s->next;
06765 }
06766 ast_mutex_unlock(&sessionlock);
06767
06768 if (unistimsock > -1) {
06769 return 0;
06770 }
06771 bindaddr.sin_addr.s_addr = INADDR_ANY;
06772 bindaddr.sin_port = htons(unistim_port);
06773 bindaddr.sin_family = AF_INET;
06774 unistimsock = socket(AF_INET, SOCK_DGRAM, 0);
06775 if (unistimsock < 0) {
06776 ast_log(LOG_WARNING, "Unable to create UNISTIM socket: %s\n", strerror(errno));
06777 return -1;
06778 }
06779 #ifdef HAVE_PKTINFO
06780 {
06781 const int pktinfoFlag = 1;
06782 setsockopt(unistimsock, IPPROTO_IP, IP_PKTINFO, &pktinfoFlag,
06783 sizeof(pktinfoFlag));
06784 }
06785 #else
06786 if (public_ip.sin_family == 0) {
06787 ast_log(LOG_WARNING,
06788 "Your OS does not support IP_PKTINFO, you must set public_ip.\n");
06789 unistimsock = -1;
06790 return -1;
06791 }
06792 #endif
06793 setsockopt(unistimsock, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuseFlag,
06794 sizeof(reuseFlag));
06795 if (bind(unistimsock, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) < 0) {
06796 ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
06797 ast_inet_ntoa(bindaddr.sin_addr), htons(bindaddr.sin_port),
06798 strerror(errno));
06799 close(unistimsock);
06800 unistimsock = -1;
06801 } else {
06802 ast_verb(2, "UNISTIM Listening on %s:%d\n", ast_inet_ntoa(bindaddr.sin_addr), htons(bindaddr.sin_port));
06803 ast_set_qos(unistimsock, qos.tos, qos.cos, "UNISTIM");
06804 }
06805 return 0;
06806 }
06807
06808 static enum ast_rtp_glue_result unistim_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
06809 {
06810 struct unistim_subchannel *sub = ast_channel_tech_pvt(chan);
06811
06812 ao2_ref(sub->rtp, +1);
06813 *instance = sub->rtp;
06814
06815 return AST_RTP_GLUE_RESULT_LOCAL;
06816 }
06817
06818 static struct ast_rtp_glue unistim_rtp_glue = {
06819 .type = channel_type,
06820 .get_rtp_info = unistim_get_rtp_peer,
06821 };
06822
06823
06824 int load_module(void)
06825 {
06826 int res;
06827 struct ast_format tmpfmt;
06828 if (!(global_cap = ast_format_cap_alloc())) {
06829 goto buff_failed;
06830 }
06831 if (!(unistim_tech.capabilities = ast_format_cap_alloc())) {
06832 goto buff_failed;
06833 }
06834
06835 ast_format_cap_add(global_cap, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
06836 ast_format_cap_add(global_cap, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
06837 ast_format_cap_copy(unistim_tech.capabilities, global_cap);
06838 if (!(buff = ast_malloc(SIZE_PAGE))) {
06839 goto buff_failed;
06840 }
06841
06842 io = io_context_create();
06843 if (!io) {
06844 ast_log(LOG_ERROR, "Failed to allocate IO context\n");
06845 goto io_failed;
06846 }
06847
06848 sched = ast_sched_context_create();
06849 if (!sched) {
06850 ast_log(LOG_ERROR, "Failed to allocate scheduler context\n");
06851 goto sched_failed;
06852 }
06853
06854 res = reload_config();
06855 if (res) {
06856 return AST_MODULE_LOAD_DECLINE;
06857 }
06858
06859 if (ast_channel_register(&unistim_tech)) {
06860 ast_log(LOG_ERROR, "Unable to register channel type '%s'\n", channel_type);
06861 goto chanreg_failed;
06862 }
06863
06864 ast_rtp_glue_register(&unistim_rtp_glue);
06865
06866 ast_cli_register_multiple(unistim_cli, ARRAY_LEN(unistim_cli));
06867
06868 restart_monitor();
06869
06870 return AST_MODULE_LOAD_SUCCESS;
06871
06872 chanreg_failed:
06873
06874 ast_sched_context_destroy(sched);
06875 sched = NULL;
06876 sched_failed:
06877 io_context_destroy(io);
06878 io = NULL;
06879 io_failed:
06880 ast_free(buff);
06881 buff = NULL;
06882 global_cap = ast_format_cap_destroy(global_cap);
06883 unistim_tech.capabilities = ast_format_cap_destroy(unistim_tech.capabilities);
06884 buff_failed:
06885 return AST_MODULE_LOAD_FAILURE;
06886 }
06887
06888 static int unload_module(void)
06889 {
06890
06891 if (sched) {
06892 ast_sched_context_destroy(sched);
06893 }
06894
06895 ast_cli_unregister_multiple(unistim_cli, ARRAY_LEN(unistim_cli));
06896
06897 ast_channel_unregister(&unistim_tech);
06898 ast_rtp_glue_unregister(&unistim_rtp_glue);
06899
06900 ast_mutex_lock(&monlock);
06901 if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
06902 pthread_cancel(monitor_thread);
06903 pthread_kill(monitor_thread, SIGURG);
06904 pthread_join(monitor_thread, NULL);
06905 }
06906 monitor_thread = AST_PTHREADT_STOP;
06907 ast_mutex_unlock(&monlock);
06908
06909 if (buff) {
06910 ast_free(buff);
06911 }
06912 if (unistimsock > -1) {
06913 close(unistimsock);
06914 }
06915 global_cap = ast_format_cap_destroy(global_cap);
06916 unistim_tech.capabilities = ast_format_cap_destroy(unistim_tech.capabilities);
06917
06918 return 0;
06919 }
06920
06921
06922 int reload(void)
06923 {
06924 if (unistimdebug) {
06925 ast_verb(0, "reload unistim\n");
06926 }
06927 ast_mutex_lock(&unistim_reload_lock);
06928 if (!unistim_reloading) {
06929 unistim_reloading = 1;
06930 }
06931 ast_mutex_unlock(&unistim_reload_lock);
06932
06933 restart_monitor();
06934
06935 return 0;
06936 }
06937
06938 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "UNISTIM Protocol (USTM)",
06939 .load = load_module,
06940 .unload = unload_module,
06941 .reload = reload,
06942 );