Creating tag for the release of asterisk-1.6.1-beta1
[asterisk-bristuff.git] / channels / chan_unistim.c
bloba605c6be7ca91c50937a7c9fb73a61373caf1d12
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * UNISTIM channel driver for asterisk
6 * Copyright (C) 2005 - 2007, Cedric Hans
7 *
8 * Cedric Hans <cedric.hans@mlkj.net>
10 * Asterisk 1.4 patch by Peter Be
12 * See http://www.asterisk.org for more information about
13 * the Asterisk project. Please do not directly contact
14 * any of the maintainers of this project for assistance;
15 * the project provides a web site, mailing lists and IRC
16 * channels for your use.
18 * This program is free software, distributed under the terms of
19 * the GNU General Public License Version 2. See the LICENSE file
20 * at the top of the source tree.
23 /*!
24 * \file
26 * \brief chan_unistim channel driver for Asterisk
27 * \author Cedric Hans <cedric.hans@mlkj.net>
29 * Unistim (Unified Networks IP Stimulus) channel driver
30 * for Nortel i2002, i2004 and i2050
32 * \ingroup channel_drivers
35 #include "asterisk.h"
37 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39 #include <sys/stat.h>
40 #include <signal.h>
42 #if defined(__CYGWIN__)
44 * cygwin headers are partly inconsistent. struct iovec is defined in sys/uio.h
45 * which is not included by default by sys/socket.h - in_pktinfo is defined in
46 * w32api/ws2tcpip.h but this probably has compatibility problems with sys/socket.h
47 * So for the time being we simply disable HAVE_PKTINFO when building under cygwin.
48 * This should be done in some common header, but for now this is the only file
49 * using iovec and in_pktinfo so it suffices to apply the fix here.
51 #ifdef HAVE_PKTINFO
52 #undef HAVE_PKTINFO
53 #endif
54 #endif /* __CYGWIN__ */
56 #include "asterisk/paths.h" /* ast_config_AST_LOG_DIR used in (too ?) many places */
57 #include "asterisk/network.h"
58 #include "asterisk/channel.h"
59 #include "asterisk/config.h"
60 #include "asterisk/module.h"
61 #include "asterisk/pbx.h"
62 #include "asterisk/event.h"
63 #include "asterisk/rtp.h"
64 #include "asterisk/netsock.h"
65 #include "asterisk/acl.h"
66 #include "asterisk/callerid.h"
67 #include "asterisk/cli.h"
68 #include "asterisk/app.h"
69 #include "asterisk/musiconhold.h"
70 #include "asterisk/causes.h"
71 #include "asterisk/indications.h"
73 /*! Beware, G729 and G723 are not supported by asterisk, except with the proper licence */
74 #define CAPABILITY AST_FORMAT_ALAW | AST_FORMAT_ULAW /* | AST_FORMAT_G729A | AST_FORMAT_G723_1 */
76 #define DEFAULTCONTEXT "default"
77 #define DEFAULTCALLERID "Unknown"
78 #define DEFAULTCALLERNAME " "
79 #define USTM_LOG_DIR "unistimHistory"
81 /*! Size of the transmit buffer */
82 #define MAX_BUF_SIZE 64
83 /*! Number of slots for the transmit queue */
84 #define MAX_BUF_NUMBER 50
85 /*! Try x times before removing the phone */
86 #define NB_MAX_RETRANSMIT 8
87 /*! Nb of milliseconds waited when no events are scheduled */
88 #define IDLE_WAIT 1000
89 /*! Wait x milliseconds before resending a packet */
90 #define RETRANSMIT_TIMER 2000
91 /*! How often the mailbox is checked for new messages */
92 #define TIMER_MWI 10000
93 /*! Not used */
94 #define DEFAULT_CODEC 0x00
95 #define SIZE_PAGE 4096
96 #define DEVICE_NAME_LEN 16
97 #define AST_CONFIG_MAX_PATH 255
98 #define MAX_ENTRY_LOG 30
100 #define SUB_REAL 0
101 #define SUB_THREEWAY 1
102 #define MAX_SUBS 2
104 enum autoprovision {
105 AUTOPROVISIONING_NO = 0,
106 AUTOPROVISIONING_YES,
107 AUTOPROVISIONING_DB,
108 AUTOPROVISIONING_TN
111 enum autoprov_extn {
112 /*! Do not create an extension into the default dialplan */
113 EXTENSION_NONE = 0,
114 /*! Prompt user for an extension number and register it */
115 EXTENSION_ASK,
116 /*! Register an extension with the line=> value */
117 EXTENSION_LINE,
118 /*! Used with AUTOPROVISIONING_TN */
119 EXTENSION_TN
121 #define OUTPUT_HANDSET 0xC0
122 #define OUTPUT_HEADPHONE 0xC1
123 #define OUTPUT_SPEAKER 0xC2
125 #define VOLUME_LOW 0x01
126 #define VOLUME_LOW_SPEAKER 0x03
127 #define VOLUME_NORMAL 0x02
128 #define VOLUME_INSANELY_LOUD 0x07
130 #define MUTE_OFF 0x00
131 #define MUTE_ON 0xFF
132 #define MUTE_ON_DISCRET 0xCE
134 #define SIZE_HEADER 6
135 #define SIZE_MAC_ADDR 17
136 #define TEXT_LENGTH_MAX 24
137 #define TEXT_LINE0 0x00
138 #define TEXT_LINE1 0x20
139 #define TEXT_LINE2 0x40
140 #define TEXT_NORMAL 0x05
141 #define TEXT_INVERSE 0x25
142 #define STATUS_LENGTH_MAX 28
144 #define FAV_ICON_NONE 0x00
145 #define FAV_ICON_ONHOOK_BLACK 0x20
146 #define FAV_ICON_ONHOOK_WHITE 0x21
147 #define FAV_ICON_SPEAKER_ONHOOK_BLACK 0x22
148 #define FAV_ICON_SPEAKER_ONHOOK_WHITE 0x23
149 #define FAV_ICON_OFFHOOK_BLACK 0x24
150 #define FAV_ICON_OFFHOOK_WHITE 0x25
151 #define FAV_ICON_ONHOLD_BLACK 0x26
152 #define FAV_ICON_ONHOLD_WHITE 0x27
153 #define FAV_ICON_SPEAKER_OFFHOOK_BLACK 0x28
154 #define FAV_ICON_SPEAKER_OFFHOOK_WHITE 0x29
155 #define FAV_ICON_PHONE_BLACK 0x2A
156 #define FAV_ICON_PHONE_WHITE 0x2B
157 #define FAV_ICON_SPEAKER_ONHOLD_BLACK 0x2C
158 #define FAV_ICON_SPEAKER_ONHOLD_WHITE 0x2D
159 #define FAV_ICON_HEADPHONES 0x2E
160 #define FAV_ICON_HEADPHONES_ONHOLD 0x2F
161 #define FAV_ICON_HOME 0x30
162 #define FAV_ICON_CITY 0x31
163 #define FAV_ICON_SHARP 0x32
164 #define FAV_ICON_PAGER 0x33
165 #define FAV_ICON_CALL_CENTER 0x34
166 #define FAV_ICON_FAX 0x35
167 #define FAV_ICON_MAILBOX 0x36
168 #define FAV_ICON_REFLECT 0x37
169 #define FAV_ICON_COMPUTER 0x38
170 #define FAV_ICON_FORWARD 0x39
171 #define FAV_ICON_LOCKED 0x3A
172 #define FAV_ICON_TRASH 0x3B
173 #define FAV_ICON_INBOX 0x3C
174 #define FAV_ICON_OUTBOX 0x3D
175 #define FAV_ICON_MEETING 0x3E
176 #define FAV_ICON_BOX 0x3F
178 #define FAV_BLINK_FAST 0x20
179 #define FAV_BLINK_SLOW 0x40
181 #define FAV_MAX_LENGTH 0x0A
183 static void dummy(char *unused, ...)
185 return;
188 /*! \brief Global jitterbuffer configuration - by default, jb is disabled */
189 static struct ast_jb_conf default_jbconf =
191 .flags = 0,
192 .max_size = -1,
193 .resync_threshold = -1,
194 .impl = ""
196 static struct ast_jb_conf global_jbconf;
199 /* #define DUMP_PACKET 1 */
200 /* #define DEBUG_TIMER ast_verbose */
202 #define DEBUG_TIMER dummy
203 /*! Enable verbose output. can also be set with the CLI */
204 static int unistimdebug = 0;
205 static int unistim_port;
206 static enum autoprovision autoprovisioning = AUTOPROVISIONING_NO;
207 static int unistim_keepalive;
208 static int unistimsock = -1;
210 static struct {
211 unsigned int tos;
212 unsigned int tos_audio;
213 unsigned int cos;
214 unsigned int cos_audio;
215 } qos = { 0, 0, 0, 0 };
217 static struct io_context *io;
218 static struct sched_context *sched;
219 static struct sockaddr_in public_ip = { 0, };
220 /*! give the IP address for the last packet received */
221 static struct sockaddr_in address_from;
222 /*! size of the sockaddr_in (in WSARecvFrom) */
223 static unsigned int size_addr_from = sizeof(address_from);
224 /*! Receive buffer address */
225 static unsigned char *buff;
226 static int unistim_reloading = 0;
227 AST_MUTEX_DEFINE_STATIC(unistim_reload_lock);
228 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
229 static int usecnt = 0;
230 /* extern char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH]; */
232 /*! This is the thread for the monitor which checks for input on the channels
233 * which are not currently in use. */
234 static pthread_t monitor_thread = AST_PTHREADT_NULL;
236 /*! Protect the monitoring thread, so only one process can kill or start it, and not
237 * when it's doing something critical. */
238 AST_MUTEX_DEFINE_STATIC(monlock);
239 /*! Protect the session list */
240 AST_MUTEX_DEFINE_STATIC(sessionlock);
241 /*! Protect the device list */
242 AST_MUTEX_DEFINE_STATIC(devicelock);
244 enum phone_state {
245 STATE_INIT,
246 STATE_AUTHDENY,
247 STATE_MAINPAGE,
248 STATE_EXTENSION,
249 STATE_DIALPAGE,
250 STATE_RINGING,
251 STATE_CALL,
252 STATE_SELECTCODEC,
253 STATE_CLEANING,
254 STATE_HISTORY
257 enum handset_state {
258 STATE_ONHOOK,
259 STATE_OFFHOOK,
262 enum phone_key {
263 KEY_0 = 0x40,
264 KEY_1 = 0x41,
265 KEY_2 = 0x42,
266 KEY_3 = 0x43,
267 KEY_4 = 0x44,
268 KEY_5 = 0x45,
269 KEY_6 = 0x46,
270 KEY_7 = 0x47,
271 KEY_8 = 0x48,
272 KEY_9 = 0x49,
273 KEY_STAR = 0x4a,
274 KEY_SHARP = 0x4b,
275 KEY_UP = 0x4c,
276 KEY_DOWN = 0x4d,
277 KEY_RIGHT = 0x4e,
278 KEY_LEFT = 0x4f,
279 KEY_QUIT = 0x50,
280 KEY_COPY = 0x51,
281 KEY_FUNC1 = 0x54,
282 KEY_FUNC2 = 0x55,
283 KEY_FUNC3 = 0x56,
284 KEY_FUNC4 = 0x57,
285 KEY_ONHOLD = 0x5b,
286 KEY_HANGUP = 0x5c,
287 KEY_MUTE = 0x5d,
288 KEY_HEADPHN = 0x5e,
289 KEY_LOUDSPK = 0x5f,
290 KEY_FAV0 = 0x60,
291 KEY_FAV1 = 0x61,
292 KEY_FAV2 = 0x62,
293 KEY_FAV3 = 0x63,
294 KEY_FAV4 = 0x64,
295 KEY_FAV5 = 0x65,
296 KEY_COMPUTR = 0x7b,
297 KEY_CONF = 0x7c,
298 KEY_SNDHIST = 0x7d,
299 KEY_RCVHIST = 0x7e,
300 KEY_INDEX = 0x7f
303 struct tone_zone_unistim {
304 char country[3];
305 int freq1;
306 int freq2;
309 static const struct tone_zone_unistim frequency[] = {
310 {"us", 350, 440},
311 {"fr", 440, 0},
312 {"au", 413, 438},
313 {"nl", 425, 0},
314 {"uk", 350, 440},
315 {"fi", 425, 0},
316 {"es", 425, 0},
317 {"jp", 400, 0},
318 {"no", 425, 0},
319 {"at", 420, 0},
320 {"nz", 400, 0},
321 {"tw", 350, 440},
322 {"cl", 400, 0},
323 {"se", 425, 0},
324 {"be", 425, 0},
325 {"sg", 425, 0},
326 {"il", 414, 0},
327 {"br", 425, 0},
328 {"hu", 425, 0},
329 {"lt", 425, 0},
330 {"pl", 425, 0},
331 {"za", 400, 0},
332 {"pt", 425, 0},
333 {"ee", 425, 0},
334 {"mx", 425, 0},
335 {"in", 400, 0},
336 {"de", 425, 0},
337 {"ch", 425, 0},
338 {"dk", 425, 0},
339 {"cn", 450, 0},
340 {"--", 0, 0}
343 struct wsabuf {
344 u_long len;
345 unsigned char *buf;
348 struct systemtime {
349 unsigned short w_year;
350 unsigned short w_month;
351 unsigned short w_day_of_week;
352 unsigned short w_day;
353 unsigned short w_hour;
354 unsigned short w_minute;
355 unsigned short w_second;
356 unsigned short w_milliseconds;
359 struct unistim_subchannel {
360 ast_mutex_t lock;
361 /*! SUBS_REAL or SUBS_THREEWAY */
362 unsigned int subtype;
363 /*! Asterisk channel used by the subchannel */
364 struct ast_channel *owner;
365 /*! Unistim line */
366 struct unistim_line *parent;
367 /*! RTP handle */
368 struct ast_rtp *rtp;
369 int alreadygone;
370 char ringvolume;
371 char ringstyle;
375 * \todo Convert to stringfields
377 struct unistim_line {
378 ast_mutex_t lock;
379 /*! Like 200 */
380 char name[80];
381 /*! Like USTM/200\@black */
382 char fullname[80];
383 /*! pointer to our current connection, channel... */
384 struct unistim_subchannel *subs[MAX_SUBS];
385 /*! Extension where to start */
386 char exten[AST_MAX_EXTENSION];
387 /*! Context to start in */
388 char context[AST_MAX_EXTENSION];
389 /*! Language for asterisk sounds */
390 char language[MAX_LANGUAGE];
391 /*! CallerID Number */
392 char cid_num[AST_MAX_EXTENSION];
393 /*! Mailbox for MWI */
394 char mailbox[AST_MAX_EXTENSION];
395 /*! Used by MWI */
396 int lastmsgssent;
397 /*! Used by MWI */
398 time_t nextmsgcheck;
399 /*! MusicOnHold class */
400 char musicclass[MAX_MUSICCLASS];
401 /*! Call group */
402 unsigned int callgroup;
403 /*! Pickup group */
404 unsigned int pickupgroup;
405 /*! Account code (for billing) */
406 char accountcode[80];
407 /*! AMA flags (for billing) */
408 int amaflags;
409 /*! Codec supported */
410 int capability;
411 /*! Parkinglot */
412 char parkinglot[AST_MAX_CONTEXT];
413 struct unistim_line *next;
414 struct unistim_device *parent;
417 /*!
418 * \brief A device containing one or more lines
420 static struct unistim_device {
421 int receiver_state; /*!< state of the receiver (see ReceiverState) */
422 int size_phone_number; /*!< size of the phone number */
423 char phone_number[16]; /*!< the phone number entered by the user */
424 char redial_number[16]; /*!< the last phone number entered by the user */
425 int phone_current; /*!< Number of the current phone */
426 int pos_fav; /*!< Position of the displayed favorites (used for scrolling) */
427 char id[18]; /*!< mac address of the current phone in ascii */
428 char name[DEVICE_NAME_LEN]; /*!< name of the device */
429 int softkeylinepos; /*!< position of the line softkey (default 0) */
430 char softkeylabel[6][11]; /*!< soft key label */
431 char softkeynumber[6][16]; /*!< number dialed when the soft key is pressed */
432 char softkeyicon[6]; /*!< icon number */
433 char softkeydevice[6][16]; /*!< name of the device monitored */
434 struct unistim_device *sp[6]; /*!< pointer to the device monitored by this soft key */
435 char maintext0[25]; /*!< when the phone is idle, display this string on line 0 */
436 char maintext1[25]; /*!< when the phone is idle, display this string on line 1 */
437 char maintext2[25]; /*!< when the phone is idle, display this string on line 2 */
438 char titledefault[13]; /*!< title (text before date/time) */
439 char datetimeformat; /*!< format used for displaying time/date */
440 char contrast; /*!< contrast */
441 char country[3]; /*!< country used for dial tone frequency */
442 struct ind_tone_zone *tz; /*!< Tone zone for res_indications (ring, busy, congestion) */
443 char ringvolume; /*!< Ring volume */
444 char ringstyle; /*!< Ring melody */
445 int rtp_port; /*!< RTP port used by the phone */
446 int rtp_method; /*!< Select the unistim data used to establish a RTP session */
447 int status_method; /*!< Select the unistim packet used for sending status text */
448 char codec_number; /*!< The current codec used to make calls */
449 int missed_call; /*!< Number of call unanswered */
450 int callhistory; /*!< Allowed to record call history */
451 char lst_cid[TEXT_LENGTH_MAX]; /*!< Last callerID received */
452 char lst_cnm[TEXT_LENGTH_MAX]; /*!< Last callername recevied */
453 char call_forward[AST_MAX_EXTENSION]; /*!< Forward number */
454 int output; /*!< Handset, headphone or speaker */
455 int previous_output; /*!< Previous output */
456 int volume; /*!< Default volume */
457 int mute; /*!< Mute mode */
458 int moh; /*!< Music on hold in progress */
459 int nat; /*!< Used by the obscure ast_rtp_setnat */
460 enum autoprov_extn extension; /*!< See ifdef EXTENSION for valid values */
461 char extension_number[11]; /*!< Extension number entered by the user */
462 char to_delete; /*!< Used in reload */
463 time_t start_call_timestamp; /*!< timestamp for the length calculation of the call */
464 struct ast_silence_generator *silence_generator;
465 struct unistim_line *lines;
466 struct ast_ha *ha;
467 struct unistimsession *session;
468 struct unistim_device *next;
469 } *devices = NULL;
471 static struct unistimsession {
472 ast_mutex_t lock;
473 struct sockaddr_in sin; /*!< IP address of the phone */
474 struct sockaddr_in sout; /*!< IP address of server */
475 int timeout; /*!< time-out in ticks : resend packet if no ack was received before the timeout occured */
476 unsigned short seq_phone; /*!< sequence number for the next packet (when we receive a request) */
477 unsigned short seq_server; /*!< sequence number for the next packet (when we send a request) */
478 unsigned short last_seq_ack; /*!< sequence number of the last ACK received */
479 unsigned long tick_next_ping; /*!< time for the next ping */
480 int last_buf_available; /*!< number of a free slot */
481 int nb_retransmit; /*!< number of retransmition */
482 int state; /*!< state of the phone (see phone_state) */
483 int size_buff_entry; /*!< size of the buffer used to enter datas */
484 char buff_entry[16]; /*!< Buffer for temporary datas */
485 char macaddr[18]; /*!< mac adress of the phone (not always available) */
486 struct wsabuf wsabufsend[MAX_BUF_NUMBER]; /*!< Size of each paquet stored in the buffer array & pointer to this buffer */
487 unsigned char buf[MAX_BUF_NUMBER][MAX_BUF_SIZE]; /*!< Buffer array used to keep the lastest non-acked paquets */
488 struct unistim_device *device;
489 struct unistimsession *next;
490 } *sessions = NULL;
493 * \page Unistim datagram formats
495 * Format of datagrams :
496 * bytes 0 & 1 : ffff for discovery packet, 0000 for everything else
497 * byte 2 : sequence number (high part)
498 * byte 3 : sequence number (low part)
499 * byte 4 : 2 = ask question or send info, 1 = answer or ACK, 0 = retransmit request
500 * byte 5 : direction, 1 = server to phone, 2 = phone to server arguments
503 static const unsigned char packet_rcv_discovery[] =
504 { 0xff, 0xff, 0xff, 0xff, 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 };
505 static unsigned char packet_send_discovery_ack[] =
506 { 0x00, 0x00, /*Initial Seq (2 bytes) */ 0x00, 0x00, 0x00, 0x01 };
508 static const unsigned char packet_recv_firm_version[] =
509 { 0x00, 0x00, 0x00, 0x13, 0x9a, 0x0a, 0x02 };
510 static const unsigned char packet_recv_pressed_key[] =
511 { 0x00, 0x00, 0x00, 0x13, 0x99, 0x04, 0x00 };
512 static const unsigned char packet_recv_pick_up[] =
513 { 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x04 };
514 static const unsigned char packet_recv_hangup[] =
515 { 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x03 };
516 static const unsigned char packet_recv_r2[] = { 0x00, 0x00, 0x00, 0x13, 0x96, 0x03, 0x03 };
518 /*! TransportAdapter */
519 static const unsigned char packet_recv_resume_connection_with_server[] =
520 { 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 };
521 static const unsigned char packet_recv_mac_addr[] =
522 { 0xff, 0xff, 0xff, 0xff, 0x9a, 0x0d, 0x07 /*MacAddr */ };
524 static const unsigned char packet_send_date_time3[] =
525 { 0x11, 0x09, 0x02, 0x02, /*Month */ 0x05, /*Day */ 0x06, /*Hour */ 0x07,
526 /*Minutes */ 0x08, 0x32
528 static const unsigned char packet_send_date_time[] =
529 { 0x11, 0x09, 0x02, 0x0a, /*Month */ 0x05, /*Day */ 0x06, /*Hour */ 0x07, /*Minutes */
530 0x08, 0x32, 0x17, 0x04, 0x24, 0x07, 0x19,
531 0x04, 0x07, 0x00, 0x19, 0x05, 0x09, 0x3e, 0x0f, 0x16, 0x05, 0x00, 0x80, 0x00, 0x1e,
532 0x05, 0x12, 0x00, 0x78
535 static const unsigned char packet_send_no_ring[] =
536 { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00 };
537 static const unsigned char packet_send_s4[] =
538 { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00, 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff,
539 0x16, 0x05, 0x1c, 0x00, 0x00, 0x17, 0x05,
540 0x0b, 0x00, 0x00, 0x19, 0x04, 0x00, 0x00, 0x19, 0x04, 0x00, 0x08, 0x19, 0x04, 0x00,
541 0x10, 0x19, 0x04, 0x00, 0x18, 0x16, 0x05,
542 0x31, 0x00, 0x00, 0x16, 0x05, 0x04, 0x00, 0x00
544 static const unsigned char packet_send_call[] =
545 { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00, 0x16, 0x06, 0x32, 0xdf,
546 0x00, 0xff, 0x16, 0x05, 0x1c, 0x00, 0x00, 0x16, 0x0a, 0x38, 0x00, 0x12, 0xca, 0x03,
547 0xc0, 0xc3, 0xc5, 0x16, 0x16, 0x30, 0x00,
548 0x00, /*codec */ 0x12, 0x12, /* frames per packet */ 0x01, 0x5c, 0x00, /*port RTP */
549 0x0f, 0xa0, /* port RTCP */ 0x9c, 0x41,
550 /*port RTP */ 0x0f, 0xa0, /* port RTCP */ 0x9c, 0x41, /* IP Address */ 0x0a, 0x01,
551 0x16, 0x66
553 static const unsigned char packet_send_stream_based_tone_off[] =
554 { 0x16, 0x05, 0x1c, 0x00, 0x00 };
556 /* static const unsigned char packet_send_Mute[] = { 0x16, 0x05, 0x04, 0x00, 0x00 };
557 static const unsigned char packet_send_CloseAudioStreamRX[] = { 0x16, 0x05, 0x31, 0x00, 0xff };
558 static const unsigned char packet_send_CloseAudioStreamTX[] = { 0x16, 0x05, 0x31, 0xff, 0x00 };*/
559 static const unsigned char packet_send_stream_based_tone_on[] =
560 { 0x16, 0x06, 0x1b, 0x00, 0x00, 0x05 };
561 static const unsigned char packet_send_stream_based_tone_single_freq[] =
562 { 0x16, 0x06, 0x1d, 0x00, 0x01, 0xb8 };
563 static const unsigned char packet_send_stream_based_tone_dial_freq[] =
564 { 0x16, 0x08, 0x1d, 0x00, 0x01, 0xb8, 0x01, 0x5e };
565 static const unsigned char packet_send_select_output[] =
566 { 0x16, 0x06, 0x32, 0xc0, 0x01, 0x00 };
567 static const unsigned char packet_send_ring[] =
568 { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x1c, 0x00, 0x00, 0x16,
569 0x04, 0x1a, 0x01, 0x16, 0x05, 0x12, 0x13 /* Ring type 10 to 17 */ , 0x18, 0x16, 0x04, 0x18, /* volume 00, 10, 20... */
570 0x20, 0x16, 0x04, 0x10, 0x00
572 static const unsigned char packet_send_end_call[] =
573 { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x31, 0x00, 0x00, 0x19, 0x04, 0x00,
574 0x10, 0x19, 0x04, 0x00, 0x18, 0x16, 0x05,
575 0x04, 0x00, 0x00, 0x16, 0x04, 0x37, 0x10
577 static const unsigned char packet_send_s9[] =
578 { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x19, 0x04, 0x00, 0x10, 0x16, 0x05, 0x1c, 0x00,
579 0x00 };
580 static const unsigned char packet_send_rtp_packet_size[] =
581 { 0x16, 0x08, 0x38, 0x00, 0x00, 0xe0, 0x00, 0xa0 };
582 static const unsigned char packet_send_jitter_buffer_conf[] =
583 { 0x16, 0x0e, 0x3a, 0x00, /* jitter */ 0x02, /* high water mark */ 0x04, 0x00, 0x00,
584 /* early packet resync 2 bytes */ 0x3e, 0x80,
585 0x00, 0x00, /* late packet resync 2 bytes */ 0x3e, 0x80
588 /* Duration in ms div 2 (0x20 = 64ms, 0x08 = 16ms)
589 static unsigned char packet_send_StreamBasedToneCad[] =
590 { 0x16, 0x0a, 0x1e, 0x00, duration on 0x0a, duration off 0x0d, duration on 0x0a, duration off 0x0d, duration on 0x0a, duration off 0x2b }; */
591 static const unsigned char packet_send_open_audio_stream_rx[] =
592 { 0x16, 0x1a, 0x30, 0x00, 0xff, /* Codec */ 0x00, 0x00, 0x01, 0x00, 0xb8, 0xb8, 0x0e,
593 0x0e, 0x01, /* Port */ 0x14, 0x50, 0x00,
594 0x00, /* Port */ 0x14, 0x50, 0x00, 0x00, /* Dest IP */ 0x0a, 0x93, 0x69, 0x05
596 static const unsigned char packet_send_open_audio_stream_tx[] =
597 { 0x16, 0x1a, 0x30, 0xff, 0x00, 0x00, /* Codec */ 0x00, 0x01, 0x00, 0xb8, 0xb8, 0x0e,
598 0x0e, 0x01, /* Local port */ 0x14, 0x50,
599 0x00, 0x00, /* Rmt Port */ 0x14, 0x50, 0x00, 0x00, /* Dest IP */ 0x0a, 0x93, 0x69, 0x05
602 static const unsigned char packet_send_open_audio_stream_rx3[] =
603 { 0x16, 0x1a, 0x30, 0x00, 0xff, /* Codec */ 0x00, 0x00, 0x02, 0x01, 0xb8, 0xb8, 0x06,
604 0x06, 0x81, /* RTP Port */ 0x14, 0x50,
605 /* RTCP Port */ 0x14,
606 0x51, /* RTP Port */ 0x14, 0x50, /* RTCP Port */ 0x00, 0x00, /* Dest IP */ 0x0a, 0x93,
607 0x69, 0x05
609 static const unsigned char packet_send_open_audio_stream_tx3[] =
610 { 0x16, 0x1a, 0x30, 0xff, 0x00, 0x00, /* Codec */ 0x00, 0x02, 0x01, 0xb8, 0xb8, 0x06,
611 0x06, 0x81, /* RTP Local port */ 0x14, 0x50,
612 /* RTCP Port */ 0x00, 0x00, /* RTP Rmt Port */ 0x14, 0x50, /* RTCP Port */ 0x00, 0x00,
613 /* Dest IP */ 0x0a, 0x93, 0x69, 0x05
616 static const unsigned char packet_send_arrow[] = { 0x17, 0x04, 0x04, 0x00 };
617 static const unsigned char packet_send_blink_cursor[] = { 0x17, 0x04, 0x10, 0x86 };
618 static const unsigned char packet_send_date_time2[] = { 0x17, 0x04, 0x17, 0x3d, 0x11, 0x09, 0x02, 0x0a, /*Month */ 0x05, /*Day */
619 0x06, /*Hour */ 0x07, /*Minutes */ 0x08, 0x32
621 static const unsigned char packet_send_Contrast[] =
622 { 0x17, 0x04, 0x24, /*Contrast */ 0x08 };
623 static const unsigned char packet_send_StartTimer[] =
624 { 0x17, 0x05, 0x0b, 0x05, 0x00, 0x17, 0x08, 0x16, /* Text */ 0x44, 0x75, 0x72, 0xe9,
625 0x65 };
626 static const unsigned char packet_send_stop_timer[] = { 0x17, 0x05, 0x0b, 0x02, 0x00 };
627 static const unsigned char packet_send_icon[] = { 0x17, 0x05, 0x14, /*pos */ 0x00, /*icon */ 0x25 }; /* display an icon in front of the text zone */
628 static const unsigned char packet_send_S7[] = { 0x17, 0x06, 0x0f, 0x30, 0x07, 0x07 };
629 static const unsigned char packet_send_set_pos_cursor[] =
630 { 0x17, 0x06, 0x10, 0x81, 0x04, /*pos */ 0x20 };
632 /*static unsigned char packet_send_MonthLabelsDownload[] =
633 { 0x17, 0x0a, 0x15, Month (3 char) 0x46, 0x65, 0x62, 0x4d, 0xe4, 0x72, 0x20 }; */
634 static const unsigned char packet_send_favorite[] =
635 { 0x17, 0x0f, 0x19, 0x10, /*pos */ 0x01, /*name */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
636 0x20, 0x20, 0x20, 0x20, /*end_name */ 0x19,
637 0x05, 0x0f, /*pos */ 0x01, /*icone */ 0x00
639 static const unsigned char packet_send_title[] =
640 { 0x17, 0x10, 0x19, 0x02, /*text */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
641 0x20, 0x20, 0x20, 0x20 /*end_text */ };
642 static const unsigned char packet_send_text[] =
643 { 0x17, 0x1e, 0x1b, 0x04, /*pos */ 0x00, /*inverse */ 0x25, /*text */ 0x20, 0x20,
644 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
645 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
646 /*end_text */ 0x17, 0x04, 0x10, 0x87
648 static const unsigned char packet_send_status[] =
649 { 0x17, 0x20, 0x19, 0x08, /*text */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
650 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
651 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 /*end_text */
653 static const unsigned char packet_send_status2[] =
654 { 0x17, 0x0b, 0x19, /* pos [08|28|48|68] */ 0x00, /* text */ 0x20, 0x20, 0x20, 0x20,
655 0x20, 0x20, 0x20 /* end_text */ };
657 static const unsigned char packet_send_led_update[] = { 0x19, 0x04, 0x00, 0x00 };
659 static const unsigned char packet_send_query_basic_manager_04[] = { 0x1a, 0x04, 0x01, 0x04 };
660 static const unsigned char packet_send_query_mac_address[] = { 0x1a, 0x04, 0x01, 0x08 };
661 static const unsigned char packet_send_query_basic_manager_10[] = { 0x1a, 0x04, 0x01, 0x10 };
662 static const unsigned char packet_send_S1[] = { 0x1a, 0x07, 0x07, 0x00, 0x00, 0x00, 0x13 };
664 static unsigned char packet_send_ping[] =
665 { 0x1e, 0x05, 0x12, 0x00, /*Watchdog timer */ 0x78 };
667 #define BUFFSEND unsigned char buffsend[64] = { 0x00, 0x00, 0xaa, 0xbb, 0x02, 0x01 }
669 static const char tdesc[] = "UNISTIM Channel Driver";
670 static const char channel_type[] = "USTM";
672 /*! Protos */
673 static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state);
674 static int load_module(void);
675 static int reload(void);
676 static int unload_module(void);
677 static int reload_config(void);
678 static void show_main_page(struct unistimsession *pte);
679 static struct ast_channel *unistim_request(const char *type, int format,
680 void *data, int *cause);
681 static int unistim_call(struct ast_channel *ast, char *dest, int timeout);
682 static int unistim_hangup(struct ast_channel *ast);
683 static int unistim_answer(struct ast_channel *ast);
684 static struct ast_frame *unistim_read(struct ast_channel *ast);
685 static int unistim_write(struct ast_channel *ast, struct ast_frame *frame);
686 static int unistim_indicate(struct ast_channel *ast, int ind, const void *data,
687 size_t datalen);
688 static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
689 static int unistim_senddigit_begin(struct ast_channel *ast, char digit);
690 static int unistim_senddigit_end(struct ast_channel *ast, char digit,
691 unsigned int duration);
692 static int unistim_sendtext(struct ast_channel *ast, const char *text);
694 static int write_entry_history(struct unistimsession *pte, FILE * f, char c,
695 char *line1);
696 static void change_callerid(struct unistimsession *pte, int type, char *callerid);
698 static const struct ast_channel_tech unistim_tech = {
699 .type = channel_type,
700 .description = tdesc,
701 .capabilities = CAPABILITY,
702 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
703 .requester = unistim_request,
704 .call = unistim_call,
705 .hangup = unistim_hangup,
706 .answer = unistim_answer,
707 .read = unistim_read,
708 .write = unistim_write,
709 .indicate = unistim_indicate,
710 .fixup = unistim_fixup,
711 .send_digit_begin = unistim_senddigit_begin,
712 .send_digit_end = unistim_senddigit_end,
713 .send_text = unistim_sendtext,
714 /* .bridge = ast_rtp_bridge, */
717 static void display_last_error(const char *sz_msg)
719 time_t cur_time;
721 time(&cur_time);
723 /* Display the error message */
724 ast_log(LOG_WARNING, "%s %s : (%u) %s\n", ctime(&cur_time), sz_msg, errno,
725 strerror(errno));
728 static unsigned int get_tick_count(void)
730 struct timeval now = ast_tvnow();
732 return (now.tv_sec * 1000) + (now.tv_usec / 1000);
735 /* Send data to a phone without retransmit nor buffering */
736 static void send_raw_client(int size, unsigned char *data, struct sockaddr_in *addr_to,
737 const struct sockaddr_in *addr_ourip)
739 #ifdef HAVE_PKTINFO
740 struct iovec msg_iov;
741 struct msghdr msg;
742 char buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
743 struct cmsghdr *ip_msg = (struct cmsghdr *) buffer;
744 struct in_pktinfo *pki = (struct in_pktinfo *) CMSG_DATA(ip_msg);
746 msg_iov.iov_base = data;
747 msg_iov.iov_len = size;
749 msg.msg_name = addr_to; /* optional address */
750 msg.msg_namelen = sizeof(struct sockaddr_in); /* size of address */
751 msg.msg_iov = &msg_iov; /* scatter/gather array */
752 msg.msg_iovlen = 1; /* # elements in msg_iov */
753 msg.msg_control = ip_msg; /* ancillary data */
754 msg.msg_controllen = sizeof(buffer); /* ancillary data buffer len */
755 msg.msg_flags = 0; /* flags on received message */
757 ip_msg->cmsg_len = CMSG_LEN(sizeof(*pki));
758 ip_msg->cmsg_level = IPPROTO_IP;
759 ip_msg->cmsg_type = IP_PKTINFO;
760 pki->ipi_ifindex = 0; /* Interface index, 0 = use interface specified in routing table */
761 pki->ipi_spec_dst.s_addr = addr_ourip->sin_addr.s_addr; /* Local address */
762 /* pki->ipi_addr = ; Header Destination address - ignored by kernel */
764 #ifdef DUMP_PACKET
765 if (unistimdebug) {
766 int tmp;
767 char iabuf[INET_ADDRSTRLEN];
768 char iabuf2[INET_ADDRSTRLEN];
769 ast_verb(0, "\n**> From %s sending %d bytes to %s ***\n",
770 ast_inet_ntoa(addr_ourip->sin_addr), (int) size,
771 ast_inet_ntoa(addr_to->sin_addr));
772 for (tmp = 0; tmp < size; tmp++)
773 ast_verb(0, "%.2x ", (unsigned char) data[tmp]);
774 ast_verb(0, "\n******************************************\n");
777 #endif
779 if (sendmsg(unistimsock, &msg, 0) == -1)
780 display_last_error("Error sending datas");
781 #else
782 if (sendto(unistimsock, data, size, 0, (struct sockaddr *) addr_to, sizeof(*addr_to))
783 == -1)
784 display_last_error("Error sending datas");
785 #endif
788 static void send_client(int size, const unsigned char *data, struct unistimsession *pte)
790 unsigned int tick;
791 int buf_pos;
792 unsigned short *sdata = (unsigned short *) data;
794 ast_mutex_lock(&pte->lock);
795 buf_pos = pte->last_buf_available;
797 if (buf_pos >= MAX_BUF_NUMBER) {
798 ast_log(LOG_WARNING, "Error : send queue overflow\n");
799 ast_mutex_unlock(&pte->lock);
800 return;
802 sdata[1] = ntohs(++(pte->seq_server));
803 pte->wsabufsend[buf_pos].len = size;
804 memcpy(pte->wsabufsend[buf_pos].buf, data, size);
806 tick = get_tick_count();
807 pte->timeout = tick + RETRANSMIT_TIMER;
809 /*#ifdef DUMP_PACKET */
810 if (unistimdebug)
811 ast_verb(6, "Sending datas with seq #0x%.4x Using slot #%d :\n", pte->seq_server, buf_pos);
812 /*#endif */
813 send_raw_client(pte->wsabufsend[buf_pos].len, pte->wsabufsend[buf_pos].buf, &(pte->sin),
814 &(pte->sout));
815 pte->last_buf_available++;
816 ast_mutex_unlock(&pte->lock);
819 static void send_ping(struct unistimsession *pte)
821 BUFFSEND;
822 if (unistimdebug)
823 ast_verb(6, "Sending ping\n");
824 pte->tick_next_ping = get_tick_count() + unistim_keepalive;
825 memcpy(buffsend + SIZE_HEADER, packet_send_ping, sizeof(packet_send_ping));
826 send_client(SIZE_HEADER + sizeof(packet_send_ping), buffsend, pte);
829 static int get_to_address(int fd, struct sockaddr_in *toAddr)
831 #ifdef HAVE_PKTINFO
832 int err;
833 struct msghdr msg;
834 struct {
835 struct cmsghdr cm;
836 int len;
837 struct in_addr address;
838 } ip_msg;
840 /* Zero out the structures before we use them */
841 /* This sets several key values to NULL */
842 memset(&msg, 0, sizeof(msg));
843 memset(&ip_msg, 0, sizeof(ip_msg));
845 /* Initialize the message structure */
846 msg.msg_control = &ip_msg;
847 msg.msg_controllen = sizeof(ip_msg);
848 /* Get info about the incoming packet */
849 err = recvmsg(fd, &msg, MSG_PEEK);
850 if (err == -1)
851 ast_log(LOG_WARNING, "recvmsg returned an error: %s\n", strerror(errno));
852 memcpy(&toAddr->sin_addr, &ip_msg.address, sizeof(struct in_addr));
853 return err;
854 #else
855 memcpy(&toAddr, &public_ip, sizeof(&toAddr));
856 return 0;
857 #endif
860 /* Allocate memory & initialize structures for a new phone */
861 /* addr_from : ip address of the phone */
862 static struct unistimsession *create_client(const struct sockaddr_in *addr_from)
864 int tmp;
865 struct unistimsession *s;
867 if (!(s = ast_calloc(1, sizeof(*s))))
868 return NULL;
870 memcpy(&s->sin, addr_from, sizeof(struct sockaddr_in));
871 get_to_address(unistimsock, &s->sout);
872 if (unistimdebug) {
873 ast_verb(0, "Creating a new entry for the phone from %s received via server ip %s\n",
874 ast_inet_ntoa(addr_from->sin_addr), ast_inet_ntoa(s->sout.sin_addr));
876 ast_mutex_init(&s->lock);
877 ast_mutex_lock(&sessionlock);
878 s->next = sessions;
879 sessions = s;
881 s->timeout = get_tick_count() + RETRANSMIT_TIMER;
882 s->seq_phone = (short) 0x0000;
883 s->seq_server = (short) 0x0000;
884 s->last_seq_ack = (short) 0x000;
885 s->last_buf_available = 0;
886 s->nb_retransmit = 0;
887 s->state = STATE_INIT;
888 s->tick_next_ping = get_tick_count() + unistim_keepalive;
889 /* Initialize struct wsabuf */
890 for (tmp = 0; tmp < MAX_BUF_NUMBER; tmp++) {
891 s->wsabufsend[tmp].buf = s->buf[tmp];
893 ast_mutex_unlock(&sessionlock);
894 return s;
897 static void send_end_call(struct unistimsession *pte)
899 BUFFSEND;
900 if (unistimdebug)
901 ast_verb(0, "Sending end call\n");
902 memcpy(buffsend + SIZE_HEADER, packet_send_end_call, sizeof(packet_send_end_call));
903 send_client(SIZE_HEADER + sizeof(packet_send_end_call), buffsend, pte);
906 static void set_ping_timer(struct unistimsession *pte)
908 unsigned int tick = 0; /* XXX what is this for, anyways */
910 pte->timeout = pte->tick_next_ping;
911 DEBUG_TIMER("tick = %u next ping at %u tick\n", tick, pte->timeout);
912 return;
915 /* Checking if our send queue is empty,
916 * if true, setting up a timer for keepalive */
917 static void check_send_queue(struct unistimsession *pte)
919 /* Check if our send queue contained only one element */
920 if (pte->last_buf_available == 1) {
921 if (unistimdebug)
922 ast_verb(6, "Our single packet was ACKed.\n");
923 pte->last_buf_available--;
924 set_ping_timer(pte);
925 return;
927 /* Check if this ACK catch up our latest packet */
928 else if (pte->last_seq_ack + 1 == pte->seq_server + 1) {
929 if (unistimdebug)
930 ast_verb(6, "Our send queue is completely ACKed.\n");
931 pte->last_buf_available = 0; /* Purge the send queue */
932 set_ping_timer(pte);
933 return;
935 if (unistimdebug)
936 ast_verb(6, "We still have packets in our send queue\n");
937 return;
940 static void send_start_timer(struct unistimsession *pte)
942 BUFFSEND;
943 if (unistimdebug)
944 ast_verb(0, "Sending start timer\n");
945 memcpy(buffsend + SIZE_HEADER, packet_send_StartTimer, sizeof(packet_send_StartTimer));
946 send_client(SIZE_HEADER + sizeof(packet_send_StartTimer), buffsend, pte);
949 static void send_stop_timer(struct unistimsession *pte)
951 BUFFSEND;
952 if (unistimdebug)
953 ast_verb(0, "Sending stop timer\n");
954 memcpy(buffsend + SIZE_HEADER, packet_send_stop_timer, sizeof(packet_send_stop_timer));
955 send_client(SIZE_HEADER + sizeof(packet_send_stop_timer), buffsend, pte);
958 static void Sendicon(unsigned char pos, unsigned char status, struct unistimsession *pte)
960 BUFFSEND;
961 if (unistimdebug)
962 ast_verb(0, "Sending icon pos %d with status 0x%.2x\n", pos, status);
963 memcpy(buffsend + SIZE_HEADER, packet_send_icon, sizeof(packet_send_icon));
964 buffsend[9] = pos;
965 buffsend[10] = status;
966 send_client(SIZE_HEADER + sizeof(packet_send_icon), buffsend, pte);
969 static void send_tone(struct unistimsession *pte, uint16_t tone1, uint16_t tone2)
971 BUFFSEND;
972 if (!tone1) {
973 if (unistimdebug)
974 ast_verb(0, "Sending Stream Based Tone Off\n");
975 memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_off,
976 sizeof(packet_send_stream_based_tone_off));
977 send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_off), buffsend, pte);
978 return;
980 /* Since most of the world use a continuous tone, it's useless
981 if (unistimdebug)
982 ast_verb(0, "Sending Stream Based Tone Cadence Download\n");
983 memcpy (buffsend + SIZE_HEADER, packet_send_StreamBasedToneCad, sizeof (packet_send_StreamBasedToneCad));
984 send_client (SIZE_HEADER + sizeof (packet_send_StreamBasedToneCad), buffsend, pte); */
985 if (unistimdebug)
986 ast_verb(0, "Sending Stream Based Tone Frequency Component List Download %d %d\n", tone1, tone2);
987 tone1 *= 8;
988 if (!tone2) {
989 memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_single_freq,
990 sizeof(packet_send_stream_based_tone_single_freq));
991 buffsend[10] = (tone1 & 0xff00) >> 8;
992 buffsend[11] = (tone1 & 0x00ff);
993 send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_single_freq), buffsend,
994 pte);
995 } else {
996 tone2 *= 8;
997 memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_dial_freq,
998 sizeof(packet_send_stream_based_tone_dial_freq));
999 buffsend[10] = (tone1 & 0xff00) >> 8;
1000 buffsend[11] = (tone1 & 0x00ff);
1001 buffsend[12] = (tone2 & 0xff00) >> 8;
1002 buffsend[13] = (tone2 & 0x00ff);
1003 send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_dial_freq), buffsend,
1004 pte);
1007 if (unistimdebug)
1008 ast_verb(0, "Sending Stream Based Tone On\n");
1009 memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_on,
1010 sizeof(packet_send_stream_based_tone_on));
1011 send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_on), buffsend, pte);
1014 /* Positions for favorites
1015 |--------------------|
1016 | 5 2 |
1017 | 4 1 |
1018 | 3 0 |
1021 /* status (icons) : 00 = nothing, 2x/3x = see parser.h, 4x/5x = blink fast, 6x/7x = blink slow */
1022 static void
1023 send_favorite(unsigned char pos, unsigned char status, struct unistimsession *pte,
1024 const char *text)
1026 BUFFSEND;
1027 int i;
1029 if (unistimdebug)
1030 ast_verb(0, "Sending favorite pos %d with status 0x%.2x\n", pos, status);
1031 memcpy(buffsend + SIZE_HEADER, packet_send_favorite, sizeof(packet_send_favorite));
1032 buffsend[10] = pos;
1033 buffsend[24] = pos;
1034 buffsend[25] = status;
1035 i = strlen(text);
1036 if (i > FAV_MAX_LENGTH)
1037 i = FAV_MAX_LENGTH;
1038 memcpy(buffsend + FAV_MAX_LENGTH + 1, text, i);
1039 send_client(SIZE_HEADER + sizeof(packet_send_favorite), buffsend, pte);
1042 static void refresh_all_favorite(struct unistimsession *pte)
1044 int i = 0;
1046 if (unistimdebug)
1047 ast_verb(0, "Refreshing all favorite\n");
1048 for (i = 0; i < 6; i++) {
1049 if ((pte->device->softkeyicon[i] <= FAV_ICON_HEADPHONES_ONHOLD) &&
1050 (pte->device->softkeylinepos != i))
1051 send_favorite((unsigned char) i, pte->device->softkeyicon[i] + 1, pte,
1052 pte->device->softkeylabel[i]);
1053 else
1054 send_favorite((unsigned char) i, pte->device->softkeyicon[i], pte,
1055 pte->device->softkeylabel[i]);
1060 /* Change the status for this phone (pte) and update for each phones where pte is bookmarked
1061 * use FAV_ICON_*_BLACK constant in status parameters */
1062 static void change_favorite_icon(struct unistimsession *pte, unsigned char status)
1064 struct unistim_device *d = devices;
1065 int i;
1066 /* Update the current phone */
1067 if (pte->state != STATE_CLEANING)
1068 send_favorite(pte->device->softkeylinepos, status, pte,
1069 pte->device->softkeylabel[pte->device->softkeylinepos]);
1070 /* Notify other phones if we're in their bookmark */
1071 while (d) {
1072 for (i = 0; i < 6; i++) {
1073 if (d->sp[i] == pte->device) { /* It's us ? */
1074 if (d->softkeyicon[i] != status) { /* Avoid resending the same icon */
1075 d->softkeyicon[i] = status;
1076 if (d->session)
1077 send_favorite(i, status + 1, d->session, d->softkeylabel[i]);
1081 d = d->next;
1085 static int RegisterExtension(const struct unistimsession *pte)
1087 if (unistimdebug)
1088 ast_verb(0, "Trying to register extension '%s' into context '%s' to %s\n",
1089 pte->device->extension_number, pte->device->lines->context,
1090 pte->device->lines->fullname);
1091 return ast_add_extension(pte->device->lines->context, 0,
1092 pte->device->extension_number, 1, NULL, NULL, "Dial",
1093 pte->device->lines->fullname, 0, "Unistim");
1096 static int UnregisterExtension(const struct unistimsession *pte)
1098 if (unistimdebug)
1099 ast_verb(0, "Trying to unregister extension '%s' context '%s'\n",
1100 pte->device->extension_number, pte->device->lines->context);
1101 return ast_context_remove_extension(pte->device->lines->context,
1102 pte->device->extension_number, 1, "Unistim");
1105 /* Free memory allocated for a phone */
1106 static void close_client(struct unistimsession *s)
1108 struct unistim_subchannel *sub;
1109 struct unistimsession *cur, *prev = NULL;
1110 ast_mutex_lock(&sessionlock);
1111 cur = sessions;
1112 /* Looking for the session in the linked chain */
1113 while (cur) {
1114 if (cur == s)
1115 break;
1116 prev = cur;
1117 cur = cur->next;
1119 if (cur) { /* Session found ? */
1120 if (cur->device) { /* This session was registred ? */
1121 s->state = STATE_CLEANING;
1122 if (unistimdebug)
1123 ast_verb(0, "close_client session %p device %p lines %p sub %p\n",
1124 s, s->device, s->device->lines,
1125 s->device->lines->subs[SUB_REAL]);
1126 change_favorite_icon(s, FAV_ICON_NONE);
1127 sub = s->device->lines->subs[SUB_REAL];
1128 if (sub) {
1129 if (sub->owner) { /* Call in progress ? */
1130 if (unistimdebug)
1131 ast_verb(0, "Aborting call\n");
1132 ast_queue_hangup_with_cause(sub->owner, AST_CAUSE_NETWORK_OUT_OF_ORDER);
1134 } else
1135 ast_log(LOG_WARNING, "Freeing a client with no subchannel !\n");
1136 if (!ast_strlen_zero(s->device->extension_number))
1137 UnregisterExtension(s);
1138 cur->device->session = NULL;
1139 } else {
1140 if (unistimdebug)
1141 ast_verb(0, "Freeing an unregistered client\n");
1143 if (prev)
1144 prev->next = cur->next;
1145 else
1146 sessions = cur->next;
1147 ast_mutex_destroy(&s->lock);
1148 ast_free(s);
1149 } else
1150 ast_log(LOG_WARNING, "Trying to delete non-existent session %p?\n", s);
1151 ast_mutex_unlock(&sessionlock);
1152 return;
1155 /* Return 1 if the session chained link was modified */
1156 static int send_retransmit(struct unistimsession *pte)
1158 int i;
1160 ast_mutex_lock(&pte->lock);
1161 if (++pte->nb_retransmit >= NB_MAX_RETRANSMIT) {
1162 if (unistimdebug)
1163 ast_verb(0, "Too many retransmit - freeing client\n");
1164 ast_mutex_unlock(&pte->lock);
1165 close_client(pte);
1166 return 1;
1168 pte->timeout = get_tick_count() + RETRANSMIT_TIMER;
1170 for (i = pte->last_buf_available - (pte->seq_server - pte->last_seq_ack);
1171 i < pte->last_buf_available; i++) {
1172 if (i < 0) {
1173 ast_log(LOG_WARNING,
1174 "Asked to retransmit an ACKed slot ! last_buf_available=%d, seq_server = #0x%.4x last_seq_ack = #0x%.4x\n",
1175 pte->last_buf_available, pte->seq_server, pte->last_seq_ack);
1176 continue;
1179 if (unistimdebug) {
1180 unsigned short *sbuf = (unsigned short *) pte->wsabufsend[i].buf;
1181 unsigned short seq;
1183 seq = ntohs(sbuf[1]);
1184 ast_verb(0, "Retransmit slot #%d (seq=#0x%.4x), last ack was #0x%.4x\n", i,
1185 seq, pte->last_seq_ack);
1187 send_raw_client(pte->wsabufsend[i].len, pte->wsabufsend[i].buf, &pte->sin,
1188 &pte->sout);
1190 ast_mutex_unlock(&pte->lock);
1191 return 0;
1194 /* inverse : TEXT_INVERSE : yes, TEXT_NORMAL : no */
1195 static void
1196 send_text(unsigned char pos, unsigned char inverse, struct unistimsession *pte,
1197 const char *text)
1199 int i;
1200 BUFFSEND;
1201 if (unistimdebug)
1202 ast_verb(0, "Sending text at pos %d, inverse flag %d\n", pos, inverse);
1203 memcpy(buffsend + SIZE_HEADER, packet_send_text, sizeof(packet_send_text));
1204 buffsend[10] = pos;
1205 buffsend[11] = inverse;
1206 i = strlen(text);
1207 if (i > TEXT_LENGTH_MAX)
1208 i = TEXT_LENGTH_MAX;
1209 memcpy(buffsend + 12, text, i);
1210 send_client(SIZE_HEADER + sizeof(packet_send_text), buffsend, pte);
1213 static void send_text_status(struct unistimsession *pte, const char *text)
1215 BUFFSEND;
1216 int i;
1217 if (unistimdebug)
1218 ast_verb(0, "Sending status text\n");
1219 if (pte->device) {
1220 if (pte->device->status_method == 1) { /* For new firmware and i2050 soft phone */
1221 int n = strlen(text);
1222 /* Must send individual button separately */
1223 int j;
1224 for (i = 0, j = 0; i < 4; i++, j += 7) {
1225 int pos = 0x08 + (i * 0x20);
1226 memcpy(buffsend + SIZE_HEADER, packet_send_status2,
1227 sizeof(packet_send_status2));
1229 buffsend[9] = pos;
1230 memcpy(buffsend + 10, (j < n) ? (text + j) : " ", 7);
1231 send_client(SIZE_HEADER + sizeof(packet_send_status2), buffsend, pte);
1233 return;
1238 memcpy(buffsend + SIZE_HEADER, packet_send_status, sizeof(packet_send_status));
1239 i = strlen(text);
1240 if (i > STATUS_LENGTH_MAX)
1241 i = STATUS_LENGTH_MAX;
1242 memcpy(buffsend + 10, text, i);
1243 send_client(SIZE_HEADER + sizeof(packet_send_status), buffsend, pte);
1247 /* led values in hexa : 0 = bar off, 1 = bar on, 2 = bar 1s on/1s off, 3 = bar 2.5s on/0.5s off
1248 * 4 = bar 0.6s on/0.3s off, 5 = bar 0.5s on/0.5s off, 6 = bar 2s on/0.5s off
1249 * 7 = bar off, 8 = speaker off, 9 = speaker on, 10 = headphone off, 11 = headphone on
1250 * 18 = mute off, 19 mute on */
1251 static void send_led_update(struct unistimsession *pte, unsigned char led)
1253 BUFFSEND;
1254 if (unistimdebug)
1255 ast_verb(0, "Sending led_update (%x)\n", led);
1256 memcpy(buffsend + SIZE_HEADER, packet_send_led_update, sizeof(packet_send_led_update));
1257 buffsend[9] = led;
1258 send_client(SIZE_HEADER + sizeof(packet_send_led_update), buffsend, pte);
1261 /* output = OUTPUT_HANDSET, OUTPUT_HEADPHONE or OUTPUT_SPEAKER
1262 * volume = VOLUME_LOW, VOLUME_NORMAL, VOLUME_INSANELY_LOUD
1263 * mute = MUTE_OFF, MUTE_ON */
1264 static void
1265 send_select_output(struct unistimsession *pte, unsigned char output, unsigned char volume,
1266 unsigned char mute)
1268 BUFFSEND;
1269 if (unistimdebug)
1270 ast_verb(0, "Sending select output packet output=%x volume=%x mute=%x\n", output,
1271 volume, mute);
1272 memcpy(buffsend + SIZE_HEADER, packet_send_select_output,
1273 sizeof(packet_send_select_output));
1274 buffsend[9] = output;
1275 if (output == OUTPUT_SPEAKER)
1276 volume = VOLUME_LOW_SPEAKER;
1277 else
1278 volume = VOLUME_LOW;
1279 buffsend[10] = volume;
1280 if (mute == MUTE_ON_DISCRET)
1281 buffsend[11] = MUTE_ON;
1282 else
1283 buffsend[11] = mute;
1284 send_client(SIZE_HEADER + sizeof(packet_send_select_output), buffsend, pte);
1285 if (mute == MUTE_OFF)
1286 send_led_update(pte, 0x18);
1287 else if (mute == MUTE_ON)
1288 send_led_update(pte, 0x19);
1289 pte->device->mute = mute;
1290 if (output == OUTPUT_HANDSET) {
1291 if (mute == MUTE_ON)
1292 change_favorite_icon(pte, FAV_ICON_ONHOLD_BLACK);
1293 else
1294 change_favorite_icon(pte, FAV_ICON_OFFHOOK_BLACK);
1295 send_led_update(pte, 0x08);
1296 send_led_update(pte, 0x10);
1297 } else if (output == OUTPUT_HEADPHONE) {
1298 if (mute == MUTE_ON)
1299 change_favorite_icon(pte, FAV_ICON_HEADPHONES_ONHOLD);
1300 else
1301 change_favorite_icon(pte, FAV_ICON_HEADPHONES);
1302 send_led_update(pte, 0x08);
1303 send_led_update(pte, 0x11);
1304 } else if (output == OUTPUT_SPEAKER) {
1305 send_led_update(pte, 0x10);
1306 send_led_update(pte, 0x09);
1307 if (pte->device->receiver_state == STATE_OFFHOOK) {
1308 if (mute == MUTE_ON)
1309 change_favorite_icon(pte, FAV_ICON_SPEAKER_ONHOLD_BLACK);
1310 else
1311 change_favorite_icon(pte, FAV_ICON_SPEAKER_ONHOOK_BLACK);
1312 } else {
1313 if (mute == MUTE_ON)
1314 change_favorite_icon(pte, FAV_ICON_SPEAKER_ONHOLD_BLACK);
1315 else
1316 change_favorite_icon(pte, FAV_ICON_SPEAKER_OFFHOOK_BLACK);
1318 } else
1319 ast_log(LOG_WARNING, "Invalid ouput (%d)\n", output);
1320 if (output != pte->device->output)
1321 pte->device->previous_output = pte->device->output;
1322 pte->device->output = output;
1325 static void send_ring(struct unistimsession *pte, char volume, char style)
1327 BUFFSEND;
1328 if (unistimdebug)
1329 ast_verb(0, "Sending ring packet\n");
1330 memcpy(buffsend + SIZE_HEADER, packet_send_ring, sizeof(packet_send_ring));
1331 buffsend[24] = style + 0x10;
1332 buffsend[29] = volume * 0x10;
1333 send_client(SIZE_HEADER + sizeof(packet_send_ring), buffsend, pte);
1336 static void send_no_ring(struct unistimsession *pte)
1338 BUFFSEND;
1339 if (unistimdebug)
1340 ast_verb(0, "Sending no ring packet\n");
1341 memcpy(buffsend + SIZE_HEADER, packet_send_no_ring, sizeof(packet_send_no_ring));
1342 send_client(SIZE_HEADER + sizeof(packet_send_no_ring), buffsend, pte);
1345 static void send_texttitle(struct unistimsession *pte, const char *text)
1347 BUFFSEND;
1348 int i;
1349 if (unistimdebug)
1350 ast_verb(0, "Sending title text\n");
1351 memcpy(buffsend + SIZE_HEADER, packet_send_title, sizeof(packet_send_title));
1352 i = strlen(text);
1353 if (i > 12)
1354 i = 12;
1355 memcpy(buffsend + 10, text, i);
1356 send_client(SIZE_HEADER + sizeof(packet_send_title), buffsend, pte);
1360 static void send_date_time(struct unistimsession *pte)
1362 BUFFSEND;
1363 struct timeval now = ast_tvnow();
1364 struct ast_tm atm = { 0, };
1366 if (unistimdebug)
1367 ast_verb(0, "Sending Time & Date\n");
1368 memcpy(buffsend + SIZE_HEADER, packet_send_date_time, sizeof(packet_send_date_time));
1369 ast_localtime(&now, &atm, NULL);
1370 buffsend[10] = (unsigned char) atm.tm_mon + 1;
1371 buffsend[11] = (unsigned char) atm.tm_mday;
1372 buffsend[12] = (unsigned char) atm.tm_hour;
1373 buffsend[13] = (unsigned char) atm.tm_min;
1374 send_client(SIZE_HEADER + sizeof(packet_send_date_time), buffsend, pte);
1377 static void send_date_time2(struct unistimsession *pte)
1379 BUFFSEND;
1380 struct timeval now = ast_tvnow();
1381 struct ast_tm atm = { 0, };
1383 if (unistimdebug)
1384 ast_verb(0, "Sending Time & Date #2\n");
1385 memcpy(buffsend + SIZE_HEADER, packet_send_date_time2, sizeof(packet_send_date_time2));
1386 ast_localtime(&now, &atm, NULL);
1387 if (pte->device)
1388 buffsend[9] = pte->device->datetimeformat;
1389 else
1390 buffsend[9] = 61;
1391 buffsend[14] = (unsigned char) atm.tm_mon + 1;
1392 buffsend[15] = (unsigned char) atm.tm_mday;
1393 buffsend[16] = (unsigned char) atm.tm_hour;
1394 buffsend[17] = (unsigned char) atm.tm_min;
1395 send_client(SIZE_HEADER + sizeof(packet_send_date_time2), buffsend, pte);
1398 static void send_date_time3(struct unistimsession *pte)
1400 BUFFSEND;
1401 struct timeval now = ast_tvnow();
1402 struct ast_tm atm = { 0, };
1404 if (unistimdebug)
1405 ast_verb(0, "Sending Time & Date #3\n");
1406 memcpy(buffsend + SIZE_HEADER, packet_send_date_time3, sizeof(packet_send_date_time3));
1407 ast_localtime(&now, &atm, NULL);
1408 buffsend[10] = (unsigned char) atm.tm_mon + 1;
1409 buffsend[11] = (unsigned char) atm.tm_mday;
1410 buffsend[12] = (unsigned char) atm.tm_hour;
1411 buffsend[13] = (unsigned char) atm.tm_min;
1412 send_client(SIZE_HEADER + sizeof(packet_send_date_time3), buffsend, pte);
1415 static void send_blink_cursor(struct unistimsession *pte)
1417 BUFFSEND;
1418 if (unistimdebug)
1419 ast_verb(0, "Sending set blink\n");
1420 memcpy(buffsend + SIZE_HEADER, packet_send_blink_cursor, sizeof(packet_send_blink_cursor));
1421 send_client(SIZE_HEADER + sizeof(packet_send_blink_cursor), buffsend, pte);
1422 return;
1425 /* pos : 0xab (a=0/2/4 = line ; b = row) */
1426 static void send_cursor_pos(struct unistimsession *pte, unsigned char pos)
1428 BUFFSEND;
1429 if (unistimdebug)
1430 ast_verb(0, "Sending set cursor position\n");
1431 memcpy(buffsend + SIZE_HEADER, packet_send_set_pos_cursor,
1432 sizeof(packet_send_set_pos_cursor));
1433 buffsend[11] = pos;
1434 send_client(SIZE_HEADER + sizeof(packet_send_set_pos_cursor), buffsend, pte);
1435 return;
1438 static void rcv_resume_connection_with_server(struct unistimsession *pte)
1440 BUFFSEND;
1441 if (unistimdebug) {
1442 ast_verb(0, "ResumeConnectionWithServer received\n");
1443 ast_verb(0, "Sending packet_send_query_mac_address\n");
1445 memcpy(buffsend + SIZE_HEADER, packet_send_query_mac_address,
1446 sizeof(packet_send_query_mac_address));
1447 send_client(SIZE_HEADER + sizeof(packet_send_query_mac_address), buffsend, pte);
1448 return;
1451 static int unistim_register(struct unistimsession *s)
1453 struct unistim_device *d;
1455 ast_mutex_lock(&devicelock);
1456 d = devices;
1457 while (d) {
1458 if (!strcasecmp(s->macaddr, d->id)) {
1459 /* XXX Deal with IP authentication */
1460 s->device = d;
1461 d->session = s;
1462 d->codec_number = DEFAULT_CODEC;
1463 d->pos_fav = 0;
1464 d->missed_call = 0;
1465 d->receiver_state = STATE_ONHOOK;
1466 break;
1468 d = d->next;
1470 ast_mutex_unlock(&devicelock);
1472 if (!d)
1473 return 0;
1475 return 1;
1478 static int alloc_sub(struct unistim_line *l, int x)
1480 struct unistim_subchannel *sub;
1481 if (!(sub = ast_calloc(1, sizeof(*sub))))
1482 return 0;
1484 if (unistimdebug)
1485 ast_verb(3, "Allocating UNISTIM subchannel #%d on %s@%s ptr=%p\n", x, l->name, l->parent->name, sub);
1486 sub->parent = l;
1487 sub->subtype = x;
1488 l->subs[x] = sub;
1489 ast_mutex_init(&sub->lock);
1490 return 1;
1493 static int unalloc_sub(struct unistim_line *p, int x)
1495 if (!x) {
1496 ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name,
1497 p->parent->name);
1498 return -1;
1500 if (unistimdebug)
1501 ast_debug(1, "Released sub %d of channel %s@%s\n", x, p->name,
1502 p->parent->name);
1503 ast_mutex_destroy(&p->lock);
1504 ast_free(p->subs[x]);
1505 p->subs[x] = 0;
1506 return 0;
1509 static void rcv_mac_addr(struct unistimsession *pte, const unsigned char *buf)
1511 BUFFSEND;
1512 int tmp, i = 0;
1513 char addrmac[19];
1514 int res = 0;
1515 if (unistimdebug)
1516 ast_verb(0, "Mac Address received : ");
1517 for (tmp = 15; tmp < 15 + SIZE_HEADER; tmp++) {
1518 sprintf(&addrmac[i], "%.2x", (unsigned char) buf[tmp]);
1519 i += 2;
1521 if (unistimdebug)
1522 ast_verb(0, "%s\n", addrmac);
1523 strcpy(pte->macaddr, addrmac);
1524 res = unistim_register(pte);
1525 if (!res) {
1526 switch (autoprovisioning) {
1527 case AUTOPROVISIONING_NO:
1528 ast_log(LOG_WARNING, "No entry found for this phone : %s\n", addrmac);
1529 pte->state = STATE_AUTHDENY;
1530 break;
1531 case AUTOPROVISIONING_YES:
1533 struct unistim_device *d, *newd;
1534 struct unistim_line *newl;
1535 if (unistimdebug)
1536 ast_verb(0, "New phone, autoprovisioning on\n");
1537 /* First : locate the [template] section */
1538 ast_mutex_lock(&devicelock);
1539 d = devices;
1540 while (d) {
1541 if (!strcasecmp(d->name, "template")) {
1542 /* Found, cloning this entry */
1543 if (!(newd = ast_malloc(sizeof(*newd)))) {
1544 ast_mutex_unlock(&devicelock);
1545 return;
1548 memcpy(newd, d, sizeof(*newd));
1549 if (!(newl = ast_malloc(sizeof(*newl)))) {
1550 ast_free(newd);
1551 ast_mutex_unlock(&devicelock);
1552 return;
1555 memcpy(newl, d->lines, sizeof(*newl));
1556 if (!alloc_sub(newl, SUB_REAL)) {
1557 ast_free(newd);
1558 ast_free(newl);
1559 ast_mutex_unlock(&devicelock);
1560 return;
1562 /* Ok, now updating some fields */
1563 ast_copy_string(newd->id, addrmac, sizeof(newd->id));
1564 ast_copy_string(newd->name, addrmac, sizeof(newd->name));
1565 if (newd->extension == EXTENSION_NONE)
1566 newd->extension = EXTENSION_ASK;
1567 newd->lines = newl;
1568 newd->receiver_state = STATE_ONHOOK;
1569 newd->session = pte;
1570 newd->to_delete = -1;
1571 pte->device = newd;
1572 newd->next = NULL;
1573 newl->parent = newd;
1574 strcpy(newl->name, d->lines->name);
1575 snprintf(d->lines->name, sizeof(d->lines->name), "%d",
1576 atoi(d->lines->name) + 1);
1577 snprintf(newl->fullname, sizeof(newl->fullname), "USTM/%s@%s",
1578 newl->name, newd->name);
1579 /* Go to the end of the linked chain */
1580 while (d->next) {
1581 d = d->next;
1583 d->next = newd;
1584 d = newd;
1585 break;
1587 d = d->next;
1589 ast_mutex_unlock(&devicelock);
1590 if (!d) {
1591 ast_log(LOG_WARNING, "No entry [template] found in unistim.conf\n");
1592 pte->state = STATE_AUTHDENY;
1595 break;
1596 case AUTOPROVISIONING_TN:
1597 pte->state = STATE_AUTHDENY;
1598 break;
1599 case AUTOPROVISIONING_DB:
1600 ast_log(LOG_WARNING,
1601 "Autoprovisioning with database is not yet functional\n");
1602 break;
1603 default:
1604 ast_log(LOG_WARNING, "Internal error : unknown autoprovisioning value = %d\n",
1605 autoprovisioning);
1608 if (pte->state != STATE_AUTHDENY) {
1609 ast_verb(3, "Device '%s' successfuly registered\n", pte->device->name);
1610 switch (pte->device->extension) {
1611 case EXTENSION_NONE:
1612 pte->state = STATE_MAINPAGE;
1613 break;
1614 case EXTENSION_ASK:
1615 /* Checking if we already have an extension number */
1616 if (ast_strlen_zero(pte->device->extension_number))
1617 pte->state = STATE_EXTENSION;
1618 else {
1619 /* Yes, because of a phone reboot. We don't ask again for the TN */
1620 if (RegisterExtension(pte))
1621 pte->state = STATE_EXTENSION;
1622 else
1623 pte->state = STATE_MAINPAGE;
1625 break;
1626 case EXTENSION_LINE:
1627 ast_copy_string(pte->device->extension_number, pte->device->lines->name,
1628 sizeof(pte->device->extension_number));
1629 if (RegisterExtension(pte))
1630 pte->state = STATE_EXTENSION;
1631 else
1632 pte->state = STATE_MAINPAGE;
1633 break;
1634 case EXTENSION_TN:
1635 /* If we are here, it's because of a phone reboot */
1636 pte->state = STATE_MAINPAGE;
1637 break;
1638 default:
1639 ast_log(LOG_WARNING, "Internal error, extension value unknown : %d\n",
1640 pte->device->extension);
1641 pte->state = STATE_AUTHDENY;
1642 break;
1645 if (pte->state == STATE_EXTENSION) {
1646 if (pte->device->extension != EXTENSION_TN)
1647 pte->device->extension = EXTENSION_ASK;
1648 pte->device->extension_number[0] = '\0';
1650 if (unistimdebug)
1651 ast_verb(0, "\nSending S1\n");
1652 memcpy(buffsend + SIZE_HEADER, packet_send_S1, sizeof(packet_send_S1));
1653 send_client(SIZE_HEADER + sizeof(packet_send_S1), buffsend, pte);
1655 if (unistimdebug)
1656 ast_verb(0, "Sending query_basic_manager_04\n");
1657 memcpy(buffsend + SIZE_HEADER, packet_send_query_basic_manager_04,
1658 sizeof(packet_send_query_basic_manager_04));
1659 send_client(SIZE_HEADER + sizeof(packet_send_query_basic_manager_04), buffsend, pte);
1661 if (unistimdebug)
1662 ast_verb(0, "Sending query_basic_manager_10\n");
1663 memcpy(buffsend + SIZE_HEADER, packet_send_query_basic_manager_10,
1664 sizeof(packet_send_query_basic_manager_10));
1665 send_client(SIZE_HEADER + sizeof(packet_send_query_basic_manager_10), buffsend, pte);
1667 send_date_time(pte);
1668 return;
1671 static int write_entry_history(struct unistimsession *pte, FILE * f, char c, char *line1)
1673 if (fwrite(&c, 1, 1, f) != 1) {
1674 display_last_error("Unable to write history log header.");
1675 return -1;
1677 if (fwrite(line1, TEXT_LENGTH_MAX, 1, f) != 1) {
1678 display_last_error("Unable to write history entry - date.");
1679 return -1;
1681 if (fwrite(pte->device->lst_cid, TEXT_LENGTH_MAX, 1, f) != 1) {
1682 display_last_error("Unable to write history entry - callerid.");
1683 return -1;
1685 if (fwrite(pte->device->lst_cnm, TEXT_LENGTH_MAX, 1, f) != 1) {
1686 display_last_error("Unable to write history entry - callername.");
1687 return -1;
1689 return 0;
1692 static int write_history(struct unistimsession *pte, char way, char ismissed)
1694 char tmp[AST_CONFIG_MAX_PATH], tmp2[AST_CONFIG_MAX_PATH];
1695 char line1[TEXT_LENGTH_MAX + 1];
1696 char count = 0, *histbuf;
1697 int size;
1698 FILE *f, *f2;
1699 struct timeval now = ast_tvnow();
1700 struct ast_tm atm = { 0, };
1702 if (!pte->device)
1703 return -1;
1704 if (!pte->device->callhistory)
1705 return 0;
1706 if (strchr(pte->device->name, '/') || (pte->device->name[0] == '.')) {
1707 ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n",
1708 pte->device->name);
1709 return -1;
1712 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_LOG_DIR, USTM_LOG_DIR);
1713 if (ast_mkdir(tmp, 0770)) {
1714 if (errno != EEXIST) {
1715 display_last_error("Unable to create directory for history");
1716 return -1;
1720 ast_localtime(&now, &atm, NULL);
1721 if (ismissed) {
1722 if (way == 'i')
1723 strcpy(tmp2, "Miss");
1724 else
1725 strcpy(tmp2, "Fail");
1726 } else
1727 strcpy(tmp2, "Answ");
1728 snprintf(line1, sizeof(line1), "%04d/%02d/%02d %02d:%02d:%02d %s",
1729 atm.tm_year + 1900, atm.tm_mon + 1, atm.tm_mday, atm.tm_hour,
1730 atm.tm_min, atm.tm_sec, tmp2);
1732 snprintf(tmp, sizeof(tmp), "%s/%s/%s-%c.csv", ast_config_AST_LOG_DIR,
1733 USTM_LOG_DIR, pte->device->name, way);
1734 if ((f = fopen(tmp, "r"))) {
1735 struct stat bufstat;
1737 if (stat(tmp, &bufstat)) {
1738 display_last_error("Unable to stat history log.");
1739 fclose(f);
1740 return -1;
1742 size = 1 + (MAX_ENTRY_LOG * TEXT_LENGTH_MAX * 3);
1743 if (bufstat.st_size != size) {
1744 ast_log(LOG_WARNING,
1745 "History file %s has an incorrect size (%d instead of %d). It will be replaced by a new one.",
1746 tmp, (int) bufstat.st_size, size);
1747 fclose(f);
1748 f = NULL;
1749 count = 1;
1753 /* If we can't open the log file, we create a brand new one */
1754 if (!f) {
1755 char c = 1;
1756 int i;
1758 if ((errno != ENOENT) && (count == 0)) {
1759 display_last_error("Unable to open history log.");
1760 return -1;
1762 f = fopen(tmp, "w");
1763 if (!f) {
1764 display_last_error("Unable to create history log.");
1765 return -1;
1767 if (write_entry_history(pte, f, c, line1)) {
1768 fclose(f);
1769 return -1;
1771 memset(line1, ' ', TEXT_LENGTH_MAX);
1772 for (i = 3; i < MAX_ENTRY_LOG * 3; i++) {
1773 if (fwrite(line1, TEXT_LENGTH_MAX, 1, f) != 1) {
1774 display_last_error("Unable to write history entry - stuffing.");
1775 fclose(f);
1776 return -1;
1779 if (fclose(f))
1780 display_last_error("Unable to close history - creation.");
1781 return 0;
1783 /* We can open the log file, we create a temporary one, we add our entry and copy the rest */
1784 if (fread(&count, 1, 1, f) != 1) {
1785 display_last_error("Unable to read history header.");
1786 fclose(f);
1787 return -1;
1789 if (count > MAX_ENTRY_LOG) {
1790 ast_log(LOG_WARNING, "Invalid count in history header of %s (%d max %d)\n", tmp,
1791 count, MAX_ENTRY_LOG);
1792 fclose(f);
1793 return -1;
1795 snprintf(tmp2, sizeof(tmp2), "%s/%s/%s-%c.csv.tmp", ast_config_AST_LOG_DIR,
1796 USTM_LOG_DIR, pte->device->name, way);
1797 if (!(f2 = fopen(tmp2, "w"))) {
1798 display_last_error("Unable to create temporary history log.");
1799 fclose(f);
1800 return -1;
1803 if (++count > MAX_ENTRY_LOG)
1804 count = MAX_ENTRY_LOG;
1806 if (write_entry_history(pte, f2, count, line1)) {
1807 fclose(f);
1808 fclose(f2);
1809 return -1;
1812 size = (MAX_ENTRY_LOG - 1) * TEXT_LENGTH_MAX * 3;
1813 if (!(histbuf = ast_malloc(size))) {
1814 fclose(f);
1815 fclose(f2);
1816 return -1;
1819 if (fread(histbuf, size, 1, f) != 1) {
1820 ast_free(histbuf);
1821 fclose(f);
1822 fclose(f2);
1823 display_last_error("Unable to read previous history entries.");
1824 return -1;
1826 if (fwrite(histbuf, size, 1, f2) != 1) {
1827 ast_free(histbuf);
1828 fclose(f);
1829 fclose(f2);
1830 display_last_error("Unable to write previous history entries.");
1831 return -1;
1833 ast_free(histbuf);
1834 if (fclose(f))
1835 display_last_error("Unable to close history log.");
1836 if (fclose(f2))
1837 display_last_error("Unable to close temporary history log.");
1838 if (unlink(tmp))
1839 display_last_error("Unable to remove old history log.");
1840 if (rename(tmp2, tmp))
1841 display_last_error("Unable to rename new history log.");
1842 return 0;
1845 static void cancel_dial(struct unistimsession *pte)
1847 send_no_ring(pte);
1848 pte->device->missed_call++;
1849 write_history(pte, 'i', 1);
1850 show_main_page(pte);
1851 return;
1854 static void swap_subs(struct unistim_line *p, int a, int b)
1856 /* struct ast_channel *towner; */
1857 struct ast_rtp *rtp;
1858 int fds;
1860 if (unistimdebug)
1861 ast_verb(0, "Swapping %d and %d\n", a, b);
1863 if ((!p->subs[a]->owner) || (!p->subs[b]->owner)) {
1864 ast_log(LOG_WARNING,
1865 "Attempted to swap subchannels with a null owner : sub #%d=%p sub #%d=%p\n",
1866 a, p->subs[a]->owner, b, p->subs[b]->owner);
1867 return;
1869 rtp = p->subs[a]->rtp;
1870 p->subs[a]->rtp = p->subs[b]->rtp;
1871 p->subs[b]->rtp = rtp;
1873 fds = p->subs[a]->owner->fds[0];
1874 p->subs[a]->owner->fds[0] = p->subs[b]->owner->fds[0];
1875 p->subs[b]->owner->fds[0] = fds;
1877 fds = p->subs[a]->owner->fds[1];
1878 p->subs[a]->owner->fds[1] = p->subs[b]->owner->fds[1];
1879 p->subs[b]->owner->fds[1] = fds;
1882 static int attempt_transfer(struct unistim_subchannel *p1, struct unistim_subchannel *p2)
1884 int res = 0;
1885 struct ast_channel
1886 *chana = NULL, *chanb = NULL, *bridgea = NULL, *bridgeb = NULL, *peera =
1887 NULL, *peerb = NULL, *peerc = NULL, *peerd = NULL;
1889 if (!p1->owner || !p2->owner) {
1890 ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n");
1891 return -1;
1893 chana = p1->owner;
1894 chanb = p2->owner;
1895 bridgea = ast_bridged_channel(chana);
1896 bridgeb = ast_bridged_channel(chanb);
1898 if (bridgea) {
1899 peera = chana;
1900 peerb = chanb;
1901 peerc = bridgea;
1902 peerd = bridgeb;
1903 } else if (bridgeb) {
1904 peera = chanb;
1905 peerb = chana;
1906 peerc = bridgeb;
1907 peerd = bridgea;
1910 if (peera && peerb && peerc && (peerb != peerc)) {
1911 /*ast_quiet_chan(peera);
1912 ast_quiet_chan(peerb);
1913 ast_quiet_chan(peerc);
1914 ast_quiet_chan(peerd); */
1916 if (peera->cdr && peerb->cdr) {
1917 peerb->cdr = ast_cdr_append(peerb->cdr, peera->cdr);
1918 } else if (peera->cdr) {
1919 peerb->cdr = peera->cdr;
1921 peera->cdr = NULL;
1923 if (peerb->cdr && peerc->cdr) {
1924 peerb->cdr = ast_cdr_append(peerb->cdr, peerc->cdr);
1925 } else if (peerc->cdr) {
1926 peerb->cdr = peerc->cdr;
1928 peerc->cdr = NULL;
1930 if (ast_channel_masquerade(peerb, peerc)) {
1931 ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", peerb->name,
1932 peerc->name);
1933 res = -1;
1935 return res;
1936 } else {
1937 ast_log(LOG_NOTICE,
1938 "Transfer attempted with no appropriate bridged calls to transfer\n");
1939 if (chana)
1940 ast_softhangup_nolock(chana, AST_SOFTHANGUP_DEV);
1941 if (chanb)
1942 ast_softhangup_nolock(chanb, AST_SOFTHANGUP_DEV);
1943 return -1;
1945 return 0;
1948 void change_callerid(struct unistimsession *pte, int type, char *callerid)
1950 char *data;
1951 int size;
1953 if (type)
1954 data = pte->device->lst_cnm;
1955 else
1956 data = pte->device->lst_cid;
1958 /* This is very nearly strncpy(), except that the remaining buffer
1959 * is padded with ' ', instead of '\0' */
1960 memset(data, ' ', TEXT_LENGTH_MAX);
1961 size = strlen(callerid);
1962 if (size > TEXT_LENGTH_MAX)
1963 size = TEXT_LENGTH_MAX;
1964 memcpy(data, callerid, size);
1967 static void close_call(struct unistimsession *pte)
1969 struct unistim_subchannel *sub;
1970 struct unistim_line *l = pte->device->lines;
1972 sub = pte->device->lines->subs[SUB_REAL];
1973 send_stop_timer(pte);
1974 if (sub->owner) {
1975 sub->alreadygone = 1;
1976 if (l->subs[SUB_THREEWAY]) {
1977 l->subs[SUB_THREEWAY]->alreadygone = 1;
1978 if (attempt_transfer(sub, l->subs[SUB_THREEWAY]) < 0)
1979 ast_verb(0, "attempt_transfer failed.\n");
1980 } else
1981 ast_queue_hangup(sub->owner);
1982 } else {
1983 if (l->subs[SUB_THREEWAY]) {
1984 if (l->subs[SUB_THREEWAY]->owner)
1985 ast_queue_hangup_with_cause(l->subs[SUB_THREEWAY]->owner, AST_CAUSE_NORMAL_CLEARING);
1986 else
1987 ast_log(LOG_WARNING, "threeway sub without owner\n");
1988 } else
1989 ast_verb(0, "USTM(%s@%s-%d) channel already destroyed\n", sub->parent->name,
1990 sub->parent->parent->name, sub->subtype);
1992 change_callerid(pte, 0, pte->device->redial_number);
1993 change_callerid(pte, 1, "");
1994 write_history(pte, 'o', pte->device->missed_call);
1995 pte->device->missed_call = 0;
1996 show_main_page(pte);
1997 return;
2000 static void IgnoreCall(struct unistimsession *pte)
2002 send_no_ring(pte);
2003 return;
2006 static void *unistim_ss(void *data)
2008 struct ast_channel *chan = data;
2009 struct unistim_subchannel *sub = chan->tech_pvt;
2010 struct unistim_line *l = sub->parent;
2011 struct unistimsession *s = l->parent->session;
2012 int res;
2014 ast_verb(3, "Starting switch on '%s@%s-%d' to %s\n", l->name, l->parent->name, sub->subtype, s->device->phone_number);
2015 ast_copy_string(chan->exten, s->device->phone_number, sizeof(chan->exten));
2016 ast_copy_string(s->device->redial_number, s->device->phone_number,
2017 sizeof(s->device->redial_number));
2018 ast_setstate(chan, AST_STATE_RING);
2019 res = ast_pbx_run(chan);
2020 if (res) {
2021 ast_log(LOG_WARNING, "PBX exited non-zero\n");
2022 send_tone(s, 1000, 0);;
2024 return NULL;
2027 static void start_rtp(struct unistim_subchannel *sub)
2029 BUFFSEND;
2030 struct sockaddr_in us;
2031 struct sockaddr_in public;
2032 struct sockaddr_in sin;
2033 int codec;
2034 struct sockaddr_in sout;
2036 /* Sanity checks */
2037 if (!sub) {
2038 ast_log(LOG_WARNING, "start_rtp with a null subchannel !\n");
2039 return;
2041 if (!sub->parent) {
2042 ast_log(LOG_WARNING, "start_rtp with a null line !\n");
2043 return;
2045 if (!sub->parent->parent) {
2046 ast_log(LOG_WARNING, "start_rtp with a null device !\n");
2047 return;
2049 if (!sub->parent->parent->session) {
2050 ast_log(LOG_WARNING, "start_rtp with a null session !\n");
2051 return;
2053 sout = sub->parent->parent->session->sout;
2055 ast_mutex_lock(&sub->lock);
2056 /* Allocate the RTP */
2057 if (unistimdebug)
2058 ast_verb(0, "Starting RTP. Bind on %s\n", ast_inet_ntoa(sout.sin_addr));
2059 sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, sout.sin_addr);
2060 if (!sub->rtp) {
2061 ast_log(LOG_WARNING, "Unable to create RTP session: %s binaddr=%s\n",
2062 strerror(errno), ast_inet_ntoa(sout.sin_addr));
2063 ast_mutex_unlock(&sub->lock);
2064 return;
2066 if (sub->rtp && sub->owner) {
2067 sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
2068 sub->owner->fds[1] = ast_rtcp_fd(sub->rtp);
2070 if (sub->rtp) {
2071 ast_rtp_setqos(sub->rtp, qos.tos_audio, qos.cos_audio, "UNISTIM RTP");
2072 ast_rtp_setnat(sub->rtp, sub->parent->parent->nat);
2075 /* Create the RTP connection */
2076 ast_rtp_get_us(sub->rtp, &us);
2077 sin.sin_family = AF_INET;
2078 /* Setting up RTP for our side */
2079 memcpy(&sin.sin_addr, &sub->parent->parent->session->sin.sin_addr,
2080 sizeof(sin.sin_addr));
2081 sin.sin_port = htons(sub->parent->parent->rtp_port);
2082 ast_rtp_set_peer(sub->rtp, &sin);
2083 if (!(sub->owner->nativeformats & sub->owner->readformat)) {
2084 int fmt;
2085 fmt = ast_best_codec(sub->owner->nativeformats);
2086 ast_log(LOG_WARNING,
2087 "Our read/writeformat has been changed to something incompatible : %s (%d), using %s (%d) best codec from %d\n",
2088 ast_getformatname(sub->owner->readformat),
2089 sub->owner->readformat, ast_getformatname(fmt), fmt,
2090 sub->owner->nativeformats);
2091 sub->owner->readformat = fmt;
2092 sub->owner->writeformat = fmt;
2094 codec = ast_rtp_lookup_code(sub->rtp, 1, sub->owner->readformat);
2095 /* Setting up RTP of the phone */
2096 if (public_ip.sin_family == 0) /* NAT IP override ? */
2097 memcpy(&public, &us, sizeof(public)); /* No defined, using IP from recvmsg */
2098 else
2099 memcpy(&public, &public_ip, sizeof(public)); /* override */
2100 if (unistimdebug) {
2101 ast_verb(0, "RTP started : Our IP/port is : %s:%hd with codec %s (%d)\n",
2102 ast_inet_ntoa(us.sin_addr),
2103 htons(us.sin_port), ast_getformatname(sub->owner->readformat),
2104 sub->owner->readformat);
2105 ast_verb(0, "Starting phone RTP stack. Our public IP is %s\n",
2106 ast_inet_ntoa(public.sin_addr));
2108 if ((sub->owner->readformat == AST_FORMAT_ULAW) ||
2109 (sub->owner->readformat == AST_FORMAT_ALAW)) {
2110 if (unistimdebug)
2111 ast_verb(0, "Sending packet_send_rtp_packet_size for codec %d\n", codec);
2112 memcpy(buffsend + SIZE_HEADER, packet_send_rtp_packet_size,
2113 sizeof(packet_send_rtp_packet_size));
2114 buffsend[10] = codec;
2115 send_client(SIZE_HEADER + sizeof(packet_send_rtp_packet_size), buffsend,
2116 sub->parent->parent->session);
2118 if (unistimdebug)
2119 ast_verb(0, "Sending Jitter Buffer Parameters Configuration\n");
2120 memcpy(buffsend + SIZE_HEADER, packet_send_jitter_buffer_conf,
2121 sizeof(packet_send_jitter_buffer_conf));
2122 send_client(SIZE_HEADER + sizeof(packet_send_jitter_buffer_conf), buffsend,
2123 sub->parent->parent->session);
2124 if (sub->parent->parent->rtp_method != 0) {
2125 uint16_t rtcpsin_port = htons(us.sin_port) + 1; /* RTCP port is RTP + 1 */
2127 if (unistimdebug)
2128 ast_verb(0, "Sending OpenAudioStreamTX using method #%d\n",
2129 sub->parent->parent->rtp_method);
2130 if (sub->parent->parent->rtp_method == 3)
2131 memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_tx3,
2132 sizeof(packet_send_open_audio_stream_tx3));
2133 else
2134 memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_tx,
2135 sizeof(packet_send_open_audio_stream_tx));
2136 if (sub->parent->parent->rtp_method != 2) {
2137 memcpy(buffsend + 28, &public.sin_addr, sizeof(public.sin_addr));
2138 buffsend[20] = (htons(sin.sin_port) & 0xff00) >> 8;
2139 buffsend[21] = (htons(sin.sin_port) & 0x00ff);
2140 buffsend[23] = (rtcpsin_port & 0x00ff);
2141 buffsend[22] = (rtcpsin_port & 0xff00) >> 8;
2142 buffsend[25] = (us.sin_port & 0xff00) >> 8;
2143 buffsend[24] = (us.sin_port & 0x00ff);
2144 buffsend[27] = (rtcpsin_port & 0x00ff);
2145 buffsend[26] = (rtcpsin_port & 0xff00) >> 8;
2146 } else {
2147 memcpy(buffsend + 23, &public.sin_addr, sizeof(public.sin_addr));
2148 buffsend[15] = (htons(sin.sin_port) & 0xff00) >> 8;
2149 buffsend[16] = (htons(sin.sin_port) & 0x00ff);
2150 buffsend[20] = (us.sin_port & 0xff00) >> 8;
2151 buffsend[19] = (us.sin_port & 0x00ff);
2152 buffsend[11] = codec;
2154 buffsend[12] = codec;
2155 send_client(SIZE_HEADER + sizeof(packet_send_open_audio_stream_tx), buffsend,
2156 sub->parent->parent->session);
2158 if (unistimdebug)
2159 ast_verb(0, "Sending OpenAudioStreamRX\n");
2160 if (sub->parent->parent->rtp_method == 3)
2161 memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_rx3,
2162 sizeof(packet_send_open_audio_stream_rx3));
2163 else
2164 memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_rx,
2165 sizeof(packet_send_open_audio_stream_rx));
2166 if (sub->parent->parent->rtp_method != 2) {
2167 memcpy(buffsend + 28, &public.sin_addr, sizeof(public.sin_addr));
2168 buffsend[20] = (htons(sin.sin_port) & 0xff00) >> 8;
2169 buffsend[21] = (htons(sin.sin_port) & 0x00ff);
2170 buffsend[23] = (rtcpsin_port & 0x00ff);
2171 buffsend[22] = (rtcpsin_port & 0xff00) >> 8;
2172 buffsend[25] = (us.sin_port & 0xff00) >> 8;
2173 buffsend[24] = (us.sin_port & 0x00ff);
2174 buffsend[27] = (rtcpsin_port & 0x00ff);
2175 buffsend[26] = (rtcpsin_port & 0xff00) >> 8;
2176 } else {
2177 memcpy(buffsend + 23, &public.sin_addr, sizeof(public.sin_addr));
2178 buffsend[15] = (htons(sin.sin_port) & 0xff00) >> 8;
2179 buffsend[16] = (htons(sin.sin_port) & 0x00ff);
2180 buffsend[20] = (us.sin_port & 0xff00) >> 8;
2181 buffsend[19] = (us.sin_port & 0x00ff);
2182 buffsend[12] = codec;
2184 buffsend[11] = codec;
2185 send_client(SIZE_HEADER + sizeof(packet_send_open_audio_stream_rx), buffsend,
2186 sub->parent->parent->session);
2187 } else {
2188 uint16_t rtcpsin_port = htons(us.sin_port) + 1; /* RTCP port is RTP + 1 */
2190 if (unistimdebug)
2191 ast_verb(0, "Sending packet_send_call default method\n");
2193 memcpy(buffsend + SIZE_HEADER, packet_send_call, sizeof(packet_send_call));
2194 memcpy(buffsend + 53, &public.sin_addr, sizeof(public.sin_addr));
2195 /* Destination port when sending RTP */
2196 buffsend[49] = (us.sin_port & 0x00ff);
2197 buffsend[50] = (us.sin_port & 0xff00) >> 8;
2198 /* Destination port when sending RTCP */
2199 buffsend[52] = (rtcpsin_port & 0x00ff);
2200 buffsend[51] = (rtcpsin_port & 0xff00) >> 8;
2201 /* Codec */
2202 buffsend[40] = codec;
2203 buffsend[41] = codec;
2204 if (sub->owner->readformat == AST_FORMAT_ULAW)
2205 buffsend[42] = 1; /* 1 = 20ms (160 bytes), 2 = 40ms (320 bytes) */
2206 else if (sub->owner->readformat == AST_FORMAT_ALAW)
2207 buffsend[42] = 1; /* 1 = 20ms (160 bytes), 2 = 40ms (320 bytes) */
2208 else if (sub->owner->readformat == AST_FORMAT_G723_1)
2209 buffsend[42] = 2; /* 1 = 30ms (24 bytes), 2 = 60 ms (48 bytes) */
2210 else if (sub->owner->readformat == AST_FORMAT_G729A)
2211 buffsend[42] = 2; /* 1 = 10ms (10 bytes), 2 = 20ms (20 bytes) */
2212 else
2213 ast_log(LOG_WARNING, "Unsupported codec %s (%d) !\n",
2214 ast_getformatname(sub->owner->readformat), sub->owner->readformat);
2215 /* Source port for transmit RTP and Destination port for receiving RTP */
2216 buffsend[45] = (htons(sin.sin_port) & 0xff00) >> 8;
2217 buffsend[46] = (htons(sin.sin_port) & 0x00ff);
2218 buffsend[47] = (rtcpsin_port & 0xff00) >> 8;
2219 buffsend[48] = (rtcpsin_port & 0x00ff);
2220 send_client(SIZE_HEADER + sizeof(packet_send_call), buffsend,
2221 sub->parent->parent->session);
2223 ast_mutex_unlock(&sub->lock);
2226 static void SendDialTone(struct unistimsession *pte)
2228 int i;
2229 /* No country defined ? Using US tone */
2230 if (ast_strlen_zero(pte->device->country)) {
2231 if (unistimdebug)
2232 ast_verb(0, "No country defined, using US tone\n");
2233 send_tone(pte, 350, 440);
2234 return;
2236 if (strlen(pte->device->country) != 2) {
2237 if (unistimdebug)
2238 ast_verb(0, "Country code != 2 char, using US tone\n");
2239 send_tone(pte, 350, 440);
2240 return;
2242 i = 0;
2243 while (frequency[i].freq1) {
2244 if ((frequency[i].country[0] == pte->device->country[0]) &&
2245 (frequency[i].country[1] == pte->device->country[1])) {
2246 if (unistimdebug)
2247 ast_verb(0, "Country code found (%s), freq1=%d freq2=%d\n",
2248 frequency[i].country, frequency[i].freq1, frequency[i].freq2);
2249 send_tone(pte, frequency[i].freq1, frequency[i].freq2);
2251 i++;
2255 static void handle_dial_page(struct unistimsession *pte)
2257 pte->state = STATE_DIALPAGE;
2258 if (pte->device->call_forward[0] == -1) {
2259 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "");
2260 send_text(TEXT_LINE1, TEXT_NORMAL, pte, "Enter forward");
2261 send_text_status(pte, "ForwardCancel BackSpcErase");
2262 if (pte->device->call_forward[1] != 0) {
2263 char tmp[TEXT_LENGTH_MAX + 1];
2265 ast_copy_string(pte->device->phone_number, pte->device->call_forward + 1,
2266 sizeof(pte->device->phone_number));
2267 pte->device->size_phone_number = strlen(pte->device->phone_number);
2268 if (pte->device->size_phone_number > 15)
2269 pte->device->size_phone_number = 15;
2270 strcpy(tmp, "Number : ...............");
2271 memcpy(tmp + 9, pte->device->phone_number, pte->device->size_phone_number);
2272 send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
2273 send_blink_cursor(pte);
2274 send_cursor_pos(pte,
2275 (unsigned char) (TEXT_LINE2 + 0x09 +
2276 pte->device->size_phone_number));
2277 send_led_update(pte, 0);
2278 return;
2280 } else {
2281 if ((pte->device->output == OUTPUT_HANDSET) &&
2282 (pte->device->receiver_state == STATE_ONHOOK))
2283 send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
2284 else
2285 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
2286 SendDialTone(pte);
2287 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Enter the number to dial");
2288 send_text(TEXT_LINE1, TEXT_NORMAL, pte, "and press Call");
2289 send_text_status(pte, "Call Redial BackSpcErase");
2291 send_text(TEXT_LINE2, TEXT_NORMAL, pte, "Number : ...............");
2292 send_blink_cursor(pte);
2293 send_cursor_pos(pte, TEXT_LINE2 + 0x09);
2294 pte->device->size_phone_number = 0;
2295 pte->device->phone_number[0] = 0;
2296 change_favorite_icon(pte, FAV_ICON_PHONE_BLACK);
2297 Sendicon(TEXT_LINE0, FAV_ICON_NONE, pte);
2298 pte->device->missed_call = 0;
2299 send_led_update(pte, 0);
2300 return;
2303 /* Step 1 : Music On Hold for peer, Dialing screen for us */
2304 static void TransferCallStep1(struct unistimsession *pte)
2306 struct unistim_subchannel *sub;
2307 struct unistim_line *p = pte->device->lines;
2309 sub = p->subs[SUB_REAL];
2311 if (!sub->owner) {
2312 ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
2313 return;
2315 if (p->subs[SUB_THREEWAY]) {
2316 if (unistimdebug)
2317 ast_verb(0, "Transfer canceled, hangup our threeway channel\n");
2318 if (p->subs[SUB_THREEWAY]->owner)
2319 ast_queue_hangup_with_cause(p->subs[SUB_THREEWAY]->owner, AST_CAUSE_NORMAL_CLEARING);
2320 else
2321 ast_log(LOG_WARNING, "Canceling a threeway channel without owner\n");
2322 return;
2324 /* Start music on hold if appropriate */
2325 if (pte->device->moh)
2326 ast_log(LOG_WARNING, "Transfer with peer already listening music on hold\n");
2327 else {
2328 if (ast_bridged_channel(p->subs[SUB_REAL]->owner)) {
2329 ast_moh_start(ast_bridged_channel(p->subs[SUB_REAL]->owner),
2330 pte->device->lines->musicclass, NULL);
2331 pte->device->moh = 1;
2332 } else {
2333 ast_log(LOG_WARNING, "Unable to find peer subchannel for music on hold\n");
2334 return;
2337 /* Silence our channel */
2338 if (!pte->device->silence_generator) {
2339 pte->device->silence_generator =
2340 ast_channel_start_silence_generator(p->subs[SUB_REAL]->owner);
2341 if (pte->device->silence_generator == NULL)
2342 ast_log(LOG_WARNING, "Unable to start a silence generator.\n");
2343 else if (unistimdebug)
2344 ast_verb(0, "Starting silence generator\n");
2346 handle_dial_page(pte);
2349 /* From phone to PBX */
2350 static void HandleCallOutgoing(struct unistimsession *s)
2352 struct ast_channel *c;
2353 struct unistim_subchannel *sub;
2354 pthread_t t;
2355 s->state = STATE_CALL;
2356 sub = s->device->lines->subs[SUB_REAL];
2357 if (!sub) {
2358 ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
2359 return;
2361 if (!sub->owner) { /* A call is already in progress ? */
2362 c = unistim_new(sub, AST_STATE_DOWN); /* No, starting a new one */
2363 if (c) {
2364 /* Need to start RTP before calling ast_pbx_run */
2365 if (!sub->rtp)
2366 start_rtp(sub);
2367 send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
2368 send_text(TEXT_LINE0, TEXT_NORMAL, s, "Calling :");
2369 send_text(TEXT_LINE1, TEXT_NORMAL, s, s->device->phone_number);
2370 send_text(TEXT_LINE2, TEXT_NORMAL, s, "Dialing...");
2371 send_text_status(s, "Hangup");
2372 /* start switch */
2373 if (ast_pthread_create(&t, NULL, unistim_ss, c)) {
2374 display_last_error("Unable to create switch thread");
2375 ast_queue_hangup_with_cause(c, AST_CAUSE_SWITCH_CONGESTION);
2377 } else
2378 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n",
2379 sub->parent->name, s->device->name);
2380 } else { /* We already have a call, so we switch in a threeway call */
2382 if (s->device->moh) {
2383 struct unistim_subchannel *subchannel;
2384 struct unistim_line *p = s->device->lines;
2385 subchannel = p->subs[SUB_REAL];
2387 if (!subchannel->owner) {
2388 ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
2389 return;
2391 if (p->subs[SUB_THREEWAY]) {
2392 ast_log(LOG_WARNING,
2393 "Can't transfer while an another transfer is taking place\n");
2394 return;
2396 if (!alloc_sub(p, SUB_THREEWAY)) {
2397 ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
2398 return;
2400 /* Stop the silence generator */
2401 if (s->device->silence_generator) {
2402 if (unistimdebug)
2403 ast_verb(0, "Stopping silence generator\n");
2404 ast_channel_stop_silence_generator(subchannel->owner,
2405 s->device->silence_generator);
2406 s->device->silence_generator = NULL;
2408 send_tone(s, 0, 0);
2409 /* Make new channel */
2410 c = unistim_new(p->subs[SUB_THREEWAY], AST_STATE_DOWN);
2411 if (!c) {
2412 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %p\n", p);
2413 return;
2415 /* Swap things around between the three-way and real call */
2416 swap_subs(p, SUB_THREEWAY, SUB_REAL);
2417 send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
2418 send_text(TEXT_LINE0, TEXT_NORMAL, s, "Calling (pre-transfer)");
2419 send_text(TEXT_LINE1, TEXT_NORMAL, s, s->device->phone_number);
2420 send_text(TEXT_LINE2, TEXT_NORMAL, s, "Dialing...");
2421 send_text_status(s, "TransfrCancel");
2423 if (ast_pthread_create(&t, NULL, unistim_ss, p->subs[SUB_THREEWAY]->owner)) {
2424 ast_log(LOG_WARNING, "Unable to start simple switch on channel %p\n", p);
2425 ast_hangup(c);
2426 return;
2428 if (unistimdebug)
2429 ast_verb(0, "Started three way call on channel %p (%s) subchan %d\n",
2430 p->subs[SUB_THREEWAY]->owner, p->subs[SUB_THREEWAY]->owner->name,
2431 p->subs[SUB_THREEWAY]->subtype);
2432 } else
2433 ast_debug(1, "Current sub [%s] already has owner\n", sub->owner->name);
2435 return;
2438 /* From PBX to phone */
2439 static void HandleCallIncoming(struct unistimsession *s)
2441 struct unistim_subchannel *sub;
2442 s->state = STATE_CALL;
2443 s->device->missed_call = 0;
2444 send_no_ring(s);
2445 sub = s->device->lines->subs[SUB_REAL];
2446 if (!sub) {
2447 ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
2448 return;
2449 } else if (unistimdebug)
2450 ast_verb(0, "Handle Call Incoming for %s@%s\n", sub->parent->name,
2451 s->device->name);
2452 start_rtp(sub);
2453 if (!sub->rtp)
2454 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name,
2455 s->device->name);
2456 ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
2457 send_text(TEXT_LINE2, TEXT_NORMAL, s, "is on-line");
2458 send_text_status(s, "Hangup Transf");
2459 send_start_timer(s);
2461 if ((s->device->output == OUTPUT_HANDSET) &&
2462 (s->device->receiver_state == STATE_ONHOOK))
2463 send_select_output(s, OUTPUT_SPEAKER, s->device->volume, MUTE_OFF);
2464 else
2465 send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
2466 s->device->start_call_timestamp = time(0);
2467 write_history(s, 'i', 0);
2468 return;
2471 static int unistim_do_senddigit(struct unistimsession *pte, char digit)
2474 struct ast_frame f = { 0, };
2475 struct unistim_subchannel *sub;
2476 sub = pte->device->lines->subs[SUB_REAL];
2477 if (!sub->owner) {
2478 ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit\n");
2479 return -1;
2481 if (unistimdebug)
2482 ast_verb(0, "Send Digit %c\n", digit);
2483 switch (digit) {
2484 case '0':
2485 send_tone(pte, 941, 1336);
2486 break;
2487 case '1':
2488 send_tone(pte, 697, 1209);
2489 break;
2490 case '2':
2491 send_tone(pte, 697, 1336);
2492 break;
2493 case '3':
2494 send_tone(pte, 697, 1477);
2495 break;
2496 case '4':
2497 send_tone(pte, 770, 1209);
2498 break;
2499 case '5':
2500 send_tone(pte, 770, 1336);
2501 break;
2502 case '6':
2503 send_tone(pte, 770, 1477);
2504 break;
2505 case '7':
2506 send_tone(pte, 852, 1209);
2507 break;
2508 case '8':
2509 send_tone(pte, 852, 1336);
2510 break;
2511 case '9':
2512 send_tone(pte, 852, 1477);
2513 break;
2514 case 'A':
2515 send_tone(pte, 697, 1633);
2516 break;
2517 case 'B':
2518 send_tone(pte, 770, 1633);
2519 break;
2520 case 'C':
2521 send_tone(pte, 852, 1633);
2522 break;
2523 case 'D':
2524 send_tone(pte, 941, 1633);
2525 break;
2526 case '*':
2527 send_tone(pte, 941, 1209);
2528 break;
2529 case '#':
2530 send_tone(pte, 941, 1477);
2531 break;
2532 default:
2533 send_tone(pte, 500, 2000);
2535 usleep(150000); /* XXX Less than perfect, blocking an important thread is not a good idea */
2536 send_tone(pte, 0, 0);
2537 f.frametype = AST_FRAME_DTMF;
2538 f.subclass = digit;
2539 f.src = "unistim";
2540 ast_queue_frame(sub->owner, &f);
2541 return 0;
2544 static void key_call(struct unistimsession *pte, char keycode)
2546 if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
2547 if (keycode == KEY_SHARP)
2548 keycode = '#';
2549 else if (keycode == KEY_STAR)
2550 keycode = '*';
2551 else
2552 keycode -= 0x10;
2553 unistim_do_senddigit(pte, keycode);
2554 return;
2556 switch (keycode) {
2557 case KEY_HANGUP:
2558 case KEY_FUNC1:
2559 close_call(pte);
2560 break;
2561 case KEY_FUNC2:
2562 TransferCallStep1(pte);
2563 break;
2564 case KEY_HEADPHN:
2565 if (pte->device->output == OUTPUT_HEADPHONE)
2566 send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
2567 else
2568 send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
2569 break;
2570 case KEY_LOUDSPK:
2571 if (pte->device->output != OUTPUT_SPEAKER)
2572 send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
2573 else
2574 send_select_output(pte, pte->device->previous_output, pte->device->volume,
2575 MUTE_OFF);
2576 break;
2577 case KEY_MUTE:
2578 if (!pte->device->moh) {
2579 if (pte->device->mute == MUTE_ON)
2580 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
2581 else
2582 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON);
2583 break;
2585 case KEY_ONHOLD:
2587 struct unistim_subchannel *sub;
2588 struct ast_channel *bridgepeer = NULL;
2589 sub = pte->device->lines->subs[SUB_REAL];
2590 if (!sub->owner) {
2591 ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
2592 return;
2594 if ((bridgepeer = ast_bridged_channel(sub->owner))) {
2595 if (pte->device->moh) {
2596 ast_moh_stop(bridgepeer);
2597 pte->device->moh = 0;
2598 send_select_output(pte, pte->device->output, pte->device->volume,
2599 MUTE_OFF);
2600 } else {
2601 ast_moh_start(bridgepeer, pte->device->lines->musicclass, NULL);
2602 pte->device->moh = 1;
2603 send_select_output(pte, pte->device->output, pte->device->volume,
2604 MUTE_ON);
2606 } else
2607 ast_log(LOG_WARNING,
2608 "Unable to find peer subchannel for music on hold\n");
2609 break;
2612 return;
2615 static void key_ringing(struct unistimsession *pte, char keycode)
2617 if (keycode == KEY_FAV0 + pte->device->softkeylinepos) {
2618 HandleCallIncoming(pte);
2619 return;
2621 switch (keycode) {
2622 case KEY_HANGUP:
2623 case KEY_FUNC4:
2624 IgnoreCall(pte);
2625 break;
2626 case KEY_FUNC1:
2627 HandleCallIncoming(pte);
2628 break;
2630 return;
2633 static void Keyfavorite(struct unistimsession *pte, char keycode)
2635 int fav;
2637 if ((keycode < KEY_FAV1) && (keycode > KEY_FAV5)) {
2638 ast_log(LOG_WARNING, "It's not a favorite key\n");
2639 return;
2641 if (keycode == KEY_FAV0)
2642 return;
2643 fav = keycode - KEY_FAV0;
2644 if (pte->device->softkeyicon[fav] == 0)
2645 return;
2646 ast_copy_string(pte->device->phone_number, pte->device->softkeynumber[fav],
2647 sizeof(pte->device->phone_number));
2648 HandleCallOutgoing(pte);
2649 return;
2652 static void key_dial_page(struct unistimsession *pte, char keycode)
2654 if (keycode == KEY_FUNC3) {
2655 if (pte->device->size_phone_number <= 1)
2656 keycode = KEY_FUNC4;
2657 else {
2658 pte->device->size_phone_number -= 2;
2659 keycode = pte->device->phone_number[pte->device->size_phone_number] + 0x10;
2662 if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
2663 char tmpbuf[] = "Number : ...............";
2664 int i = 0;
2666 if (pte->device->size_phone_number >= 15)
2667 return;
2668 if (pte->device->size_phone_number == 0)
2669 send_tone(pte, 0, 0);
2670 while (i < pte->device->size_phone_number) {
2671 tmpbuf[i + 9] = pte->device->phone_number[i];
2672 i++;
2674 if (keycode == KEY_SHARP)
2675 keycode = '#';
2676 else if (keycode == KEY_STAR)
2677 keycode = '*';
2678 else
2679 keycode -= 0x10;
2680 tmpbuf[i + 9] = keycode;
2681 pte->device->phone_number[i] = keycode;
2682 pte->device->size_phone_number++;
2683 pte->device->phone_number[i + 1] = 0;
2684 send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
2685 send_blink_cursor(pte);
2686 send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 + 0x0a + i));
2687 return;
2689 if (keycode == KEY_FUNC4) {
2691 pte->device->size_phone_number = 0;
2692 send_text(TEXT_LINE2, TEXT_NORMAL, pte, "Number : ...............");
2693 send_blink_cursor(pte);
2694 send_cursor_pos(pte, TEXT_LINE2 + 0x09);
2695 return;
2698 if (pte->device->call_forward[0] == -1) {
2699 if (keycode == KEY_FUNC1) {
2700 ast_copy_string(pte->device->call_forward, pte->device->phone_number,
2701 sizeof(pte->device->call_forward));
2702 show_main_page(pte);
2703 } else if ((keycode == KEY_FUNC2) || (keycode == KEY_HANGUP)) {
2704 pte->device->call_forward[0] = '\0';
2705 show_main_page(pte);
2707 return;
2709 switch (keycode) {
2710 case KEY_FUNC2:
2711 if (ast_strlen_zero(pte->device->redial_number))
2712 break;
2713 ast_copy_string(pte->device->phone_number, pte->device->redial_number,
2714 sizeof(pte->device->phone_number));
2715 case KEY_FUNC1:
2716 HandleCallOutgoing(pte);
2717 break;
2718 case KEY_HANGUP:
2719 if (pte->device->lines->subs[SUB_REAL]->owner) {
2720 /* Stop the silence generator */
2721 if (pte->device->silence_generator) {
2722 if (unistimdebug)
2723 ast_verb(0, "Stopping silence generator\n");
2724 ast_channel_stop_silence_generator(pte->device->lines->subs[SUB_REAL]->
2725 owner, pte->device->silence_generator);
2726 pte->device->silence_generator = NULL;
2728 send_tone(pte, 0, 0);
2729 ast_moh_stop(ast_bridged_channel(pte->device->lines->subs[SUB_REAL]->owner));
2730 pte->device->moh = 0;
2731 pte->state = STATE_CALL;
2732 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Dialing canceled,");
2733 send_text(TEXT_LINE1, TEXT_NORMAL, pte, "switching back to");
2734 send_text(TEXT_LINE2, TEXT_NORMAL, pte, "previous call.");
2735 send_text_status(pte, "Hangup Transf");
2736 } else
2737 show_main_page(pte);
2738 break;
2739 case KEY_FAV1:
2740 case KEY_FAV2:
2741 case KEY_FAV3:
2742 case KEY_FAV4:
2743 case KEY_FAV5:
2744 Keyfavorite(pte, keycode);
2745 break;
2746 case KEY_LOUDSPK:
2747 if (pte->device->output == OUTPUT_SPEAKER) {
2748 if (pte->device->receiver_state == STATE_OFFHOOK)
2749 send_select_output(pte, pte->device->previous_output, pte->device->volume,
2750 MUTE_OFF);
2751 else
2752 show_main_page(pte);
2753 } else
2754 send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
2755 break;
2756 case KEY_HEADPHN:
2757 if (pte->device->output == OUTPUT_HEADPHONE) {
2758 if (pte->device->receiver_state == STATE_OFFHOOK)
2759 send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
2760 else
2761 show_main_page(pte);
2762 } else
2763 send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
2764 break;
2766 return;
2769 #define SELECTCODEC_START_ENTRY_POS 15
2770 #define SELECTCODEC_MAX_LENGTH 2
2771 #define SELECTCODEC_MSG "Codec number : .."
2772 static void HandleSelectCodec(struct unistimsession *pte)
2774 char buf[30], buf2[5];
2776 pte->state = STATE_SELECTCODEC;
2777 strcpy(buf, "Using codec ");
2778 sprintf(buf2, "%d", pte->device->codec_number);
2779 strcat(buf, buf2);
2780 strcat(buf, " (G711u=0,");
2782 send_text(TEXT_LINE0, TEXT_NORMAL, pte, buf);
2783 send_text(TEXT_LINE1, TEXT_NORMAL, pte, "G723=4,G711a=8,G729A=18)");
2784 send_text(TEXT_LINE2, TEXT_INVERSE, pte, SELECTCODEC_MSG);
2785 send_blink_cursor(pte);
2786 send_cursor_pos(pte, TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS);
2787 pte->size_buff_entry = 0;
2788 send_text_status(pte, "Select BackSpcErase Cancel");
2789 return;
2792 static void key_select_codec(struct unistimsession *pte, char keycode)
2794 if (keycode == KEY_FUNC2) {
2795 if (pte->size_buff_entry <= 1)
2796 keycode = KEY_FUNC3;
2797 else {
2798 pte->size_buff_entry -= 2;
2799 keycode = pte->buff_entry[pte->size_buff_entry] + 0x10;
2802 if ((keycode >= KEY_0) && (keycode <= KEY_9)) {
2803 char tmpbuf[] = SELECTCODEC_MSG;
2804 int i = 0;
2806 if (pte->size_buff_entry >= SELECTCODEC_MAX_LENGTH)
2807 return;
2809 while (i < pte->size_buff_entry) {
2810 tmpbuf[i + SELECTCODEC_START_ENTRY_POS] = pte->buff_entry[i];
2811 i++;
2813 tmpbuf[i + SELECTCODEC_START_ENTRY_POS] = keycode - 0x10;
2814 pte->buff_entry[i] = keycode - 0x10;
2815 pte->size_buff_entry++;
2816 send_text(TEXT_LINE2, TEXT_INVERSE, pte, tmpbuf);
2817 send_blink_cursor(pte);
2818 send_cursor_pos(pte,
2819 (unsigned char) (TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS + 1 + i));
2820 return;
2823 switch (keycode) {
2824 case KEY_FUNC1:
2825 if (pte->size_buff_entry == 1)
2826 pte->device->codec_number = pte->buff_entry[0] - 48;
2827 else if (pte->size_buff_entry == 2)
2828 pte->device->codec_number =
2829 ((pte->buff_entry[0] - 48) * 10) + (pte->buff_entry[1] - 48);
2830 show_main_page(pte);
2831 break;
2832 case KEY_FUNC3:
2833 pte->size_buff_entry = 0;
2834 send_text(TEXT_LINE2, TEXT_INVERSE, pte, SELECTCODEC_MSG);
2835 send_blink_cursor(pte);
2836 send_cursor_pos(pte, TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS);
2837 break;
2838 case KEY_HANGUP:
2839 case KEY_FUNC4:
2840 show_main_page(pte);
2841 break;
2843 return;
2846 #define SELECTEXTENSION_START_ENTRY_POS 0
2847 #define SELECTEXTENSION_MAX_LENGTH 10
2848 #define SELECTEXTENSION_MSG ".........."
2849 static void ShowExtensionPage(struct unistimsession *pte)
2851 pte->state = STATE_EXTENSION;
2853 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Please enter a Terminal");
2854 send_text(TEXT_LINE1, TEXT_NORMAL, pte, "Number (TN) :");
2855 send_text(TEXT_LINE2, TEXT_NORMAL, pte, SELECTEXTENSION_MSG);
2856 send_blink_cursor(pte);
2857 send_cursor_pos(pte, TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS);
2858 send_text_status(pte, "Enter BackSpcErase");
2859 pte->size_buff_entry = 0;
2860 return;
2863 static void key_select_extension(struct unistimsession *pte, char keycode)
2865 if (keycode == KEY_FUNC2) {
2866 if (pte->size_buff_entry <= 1)
2867 keycode = KEY_FUNC3;
2868 else {
2869 pte->size_buff_entry -= 2;
2870 keycode = pte->buff_entry[pte->size_buff_entry] + 0x10;
2873 if ((keycode >= KEY_0) && (keycode <= KEY_9)) {
2874 char tmpbuf[] = SELECTEXTENSION_MSG;
2875 int i = 0;
2877 if (pte->size_buff_entry >= SELECTEXTENSION_MAX_LENGTH)
2878 return;
2880 while (i < pte->size_buff_entry) {
2881 tmpbuf[i + SELECTEXTENSION_START_ENTRY_POS] = pte->buff_entry[i];
2882 i++;
2884 tmpbuf[i + SELECTEXTENSION_START_ENTRY_POS] = keycode - 0x10;
2885 pte->buff_entry[i] = keycode - 0x10;
2886 pte->size_buff_entry++;
2887 send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
2888 send_blink_cursor(pte);
2889 send_cursor_pos(pte,
2890 (unsigned char) (TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS + 1 +
2891 i));
2892 return;
2895 switch (keycode) {
2896 case KEY_FUNC1:
2897 if (pte->size_buff_entry < 1)
2898 return;
2899 if (autoprovisioning == AUTOPROVISIONING_TN) {
2900 struct unistim_device *d;
2902 /* First step : looking for this TN in our device list */
2903 ast_mutex_lock(&devicelock);
2904 d = devices;
2905 pte->buff_entry[pte->size_buff_entry] = '\0';
2906 while (d) {
2907 if (d->id[0] == 'T') { /* It's a TN device ? */
2908 /* It's the TN we're looking for ? */
2909 if (!strcmp((d->id) + 1, pte->buff_entry)) {
2910 pte->device = d;
2911 d->session = pte;
2912 d->codec_number = DEFAULT_CODEC;
2913 d->pos_fav = 0;
2914 d->missed_call = 0;
2915 d->receiver_state = STATE_ONHOOK;
2916 strcpy(d->id, pte->macaddr);
2917 pte->device->extension_number[0] = 'T';
2918 pte->device->extension = EXTENSION_TN;
2919 ast_copy_string((pte->device->extension_number) + 1,
2920 pte->buff_entry, pte->size_buff_entry + 1);
2921 ast_mutex_unlock(&devicelock);
2922 show_main_page(pte);
2923 refresh_all_favorite(pte);
2924 return;
2927 d = d->next;
2929 ast_mutex_unlock(&devicelock);
2930 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Invalid Terminal Number.");
2931 send_text(TEXT_LINE1, TEXT_NORMAL, pte, "Please try again :");
2932 send_cursor_pos(pte,
2933 (unsigned char) (TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS +
2934 pte->size_buff_entry));
2935 send_blink_cursor(pte);
2936 } else {
2937 ast_copy_string(pte->device->extension_number, pte->buff_entry,
2938 pte->size_buff_entry + 1);
2939 if (RegisterExtension(pte)) {
2940 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Invalid extension.");
2941 send_text(TEXT_LINE1, TEXT_NORMAL, pte, "Please try again :");
2942 send_cursor_pos(pte,
2943 (unsigned char) (TEXT_LINE2 +
2944 SELECTEXTENSION_START_ENTRY_POS +
2945 pte->size_buff_entry));
2946 send_blink_cursor(pte);
2947 } else
2948 show_main_page(pte);
2950 break;
2951 case KEY_FUNC3:
2952 pte->size_buff_entry = 0;
2953 send_text(TEXT_LINE2, TEXT_NORMAL, pte, SELECTEXTENSION_MSG);
2954 send_blink_cursor(pte);
2955 send_cursor_pos(pte, TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS);
2956 break;
2958 return;
2961 static int ReformatNumber(char *number)
2963 int pos = 0, i = 0, size = strlen(number);
2965 for (; i < size; i++) {
2966 if ((number[i] >= '0') && (number[i] <= '9')) {
2967 if (i == pos) {
2968 pos++;
2969 continue;
2971 number[pos] = number[i];
2972 pos++;
2975 number[pos] = 0;
2976 return pos;
2979 static void show_entry_history(struct unistimsession *pte, FILE ** f)
2981 char line[TEXT_LENGTH_MAX + 1], status[STATUS_LENGTH_MAX + 1], func1[10], func2[10],
2982 func3[10];
2984 if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
2985 display_last_error("Can't read history date entry");
2986 fclose(*f);
2987 return;
2989 line[sizeof(line) - 1] = '\0';
2990 send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
2991 if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
2992 display_last_error("Can't read callerid entry");
2993 fclose(*f);
2994 return;
2996 line[sizeof(line) - 1] = '\0';
2997 ast_copy_string(pte->device->lst_cid, line, sizeof(pte->device->lst_cid));
2998 send_text(TEXT_LINE1, TEXT_NORMAL, pte, line);
2999 if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
3000 display_last_error("Can't read callername entry");
3001 fclose(*f);
3002 return;
3004 line[sizeof(line) - 1] = '\0';
3005 send_text(TEXT_LINE2, TEXT_NORMAL, pte, line);
3006 fclose(*f);
3008 snprintf(line, sizeof(line), "Call %03d/%03d", pte->buff_entry[2],
3009 pte->buff_entry[1]);
3010 send_texttitle(pte, line);
3012 if (pte->buff_entry[2] == 1)
3013 strcpy(func1, " ");
3014 else
3015 strcpy(func1, "Prvious");
3016 if (pte->buff_entry[2] >= pte->buff_entry[1])
3017 strcpy(func2, " ");
3018 else
3019 strcpy(func2, "Next ");
3020 if (ReformatNumber(pte->device->lst_cid))
3021 strcpy(func3, "Redial ");
3022 else
3023 strcpy(func3, " ");
3024 snprintf(status, sizeof(status), "%s%s%sCancel", func1, func2, func3);
3025 send_text_status(pte, status);
3028 static char OpenHistory(struct unistimsession *pte, char way, FILE ** f)
3030 char tmp[AST_CONFIG_MAX_PATH];
3031 char count;
3033 snprintf(tmp, sizeof(tmp), "%s/%s/%s-%c.csv", ast_config_AST_LOG_DIR,
3034 USTM_LOG_DIR, pte->device->name, way);
3035 *f = fopen(tmp, "r");
3036 if (!*f) {
3037 display_last_error("Unable to open history file");
3038 return 0;
3040 if (fread(&count, 1, 1, *f) != 1) {
3041 display_last_error("Unable to read history header - display.");
3042 fclose(*f);
3043 return 0;
3045 if (count > MAX_ENTRY_LOG) {
3046 ast_log(LOG_WARNING, "Invalid count in history header of %s (%d max %d)\n", tmp,
3047 count, MAX_ENTRY_LOG);
3048 fclose(*f);
3049 return 0;
3051 return count;
3054 static void show_history(struct unistimsession *pte, char way)
3056 FILE *f;
3057 char count;
3059 if (!pte->device)
3060 return;
3061 if (!pte->device->callhistory)
3062 return;
3063 count = OpenHistory(pte, way, &f);
3064 if (!count)
3065 return;
3066 pte->buff_entry[0] = way;
3067 pte->buff_entry[1] = count;
3068 pte->buff_entry[2] = 1;
3069 show_entry_history(pte, &f);
3070 pte->state = STATE_HISTORY;
3073 static void show_main_page(struct unistimsession *pte)
3075 char tmpbuf[TEXT_LENGTH_MAX + 1];
3078 if ((pte->device->extension == EXTENSION_ASK) &&
3079 (ast_strlen_zero(pte->device->extension_number))) {
3080 ShowExtensionPage(pte);
3081 return;
3084 pte->state = STATE_MAINPAGE;
3086 send_tone(pte, 0, 0);
3087 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON_DISCRET);
3088 pte->device->lines->lastmsgssent = 0;
3089 send_favorite(pte->device->softkeylinepos, FAV_ICON_ONHOOK_BLACK, pte,
3090 pte->device->softkeylabel[pte->device->softkeylinepos]);
3091 if (!ast_strlen_zero(pte->device->call_forward)) {
3092 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Call forwarded to :");
3093 send_text(TEXT_LINE1, TEXT_NORMAL, pte, pte->device->call_forward);
3094 Sendicon(TEXT_LINE0, FAV_ICON_REFLECT + FAV_BLINK_SLOW, pte);
3095 send_text_status(pte, "Dial Redial NoForwd");
3096 } else {
3097 if ((pte->device->extension == EXTENSION_ASK) ||
3098 (pte->device->extension == EXTENSION_TN))
3099 send_text_status(pte, "Dial Redial ForwardUnregis");
3100 else
3101 send_text_status(pte, "Dial Redial Forward");
3103 send_text(TEXT_LINE1, TEXT_NORMAL, pte, pte->device->maintext1);
3104 if (pte->device->missed_call == 0)
3105 send_text(TEXT_LINE0, TEXT_NORMAL, pte, pte->device->maintext0);
3106 else {
3107 sprintf(tmpbuf, "%d unanswered call(s)", pte->device->missed_call);
3108 send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmpbuf);
3109 Sendicon(TEXT_LINE0, FAV_ICON_CALL_CENTER + FAV_BLINK_SLOW, pte);
3112 if (ast_strlen_zero(pte->device->maintext2)) {
3113 strcpy(tmpbuf, "IP : ");
3114 strcat(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr));
3115 send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
3116 } else
3117 send_text(TEXT_LINE2, TEXT_NORMAL, pte, pte->device->maintext2);
3118 send_texttitle(pte, pte->device->titledefault);
3119 change_favorite_icon(pte, FAV_ICON_ONHOOK_BLACK);
3122 static void key_main_page(struct unistimsession *pte, char keycode)
3124 if (pte->device->missed_call) {
3125 Sendicon(TEXT_LINE0, FAV_ICON_NONE, pte);
3126 pte->device->missed_call = 0;
3128 if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
3129 handle_dial_page(pte);
3130 key_dial_page(pte, keycode);
3131 return;
3133 switch (keycode) {
3134 case KEY_FUNC1:
3135 handle_dial_page(pte);
3136 break;
3137 case KEY_FUNC2:
3138 if (ast_strlen_zero(pte->device->redial_number))
3139 break;
3140 if ((pte->device->output == OUTPUT_HANDSET) &&
3141 (pte->device->receiver_state == STATE_ONHOOK))
3142 send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
3143 else
3144 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
3146 ast_copy_string(pte->device->phone_number, pte->device->redial_number,
3147 sizeof(pte->device->phone_number));
3148 HandleCallOutgoing(pte);
3149 break;
3150 case KEY_FUNC3:
3151 if (!ast_strlen_zero(pte->device->call_forward)) {
3152 /* Cancel call forwarding */
3153 memmove(pte->device->call_forward + 1, pte->device->call_forward,
3154 sizeof(pte->device->call_forward));
3155 pte->device->call_forward[0] = '\0';
3156 Sendicon(TEXT_LINE0, FAV_ICON_NONE, pte);
3157 pte->device->output = OUTPUT_HANDSET; /* Seems to be reseted somewhere */
3158 show_main_page(pte);
3159 break;
3161 pte->device->call_forward[0] = -1;
3162 handle_dial_page(pte);
3163 break;
3164 case KEY_FUNC4:
3165 if (pte->device->extension == EXTENSION_ASK) {
3166 UnregisterExtension(pte);
3167 pte->device->extension_number[0] = '\0';
3168 ShowExtensionPage(pte);
3169 } else if (pte->device->extension == EXTENSION_TN) {
3170 ast_mutex_lock(&devicelock);
3171 strcpy(pte->device->id, pte->device->extension_number);
3172 pte->buff_entry[0] = '\0';
3173 pte->size_buff_entry = 0;
3174 pte->device->session = NULL;
3175 pte->device = NULL;
3176 ast_mutex_unlock(&devicelock);
3177 ShowExtensionPage(pte);
3179 break;
3180 case KEY_FAV0:
3181 handle_dial_page(pte);
3182 break;
3183 case KEY_FAV1:
3184 case KEY_FAV2:
3185 case KEY_FAV3:
3186 case KEY_FAV4:
3187 case KEY_FAV5:
3188 if ((pte->device->output == OUTPUT_HANDSET) &&
3189 (pte->device->receiver_state == STATE_ONHOOK))
3190 send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
3191 else
3192 send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
3193 Keyfavorite(pte, keycode);
3194 break;
3195 case KEY_CONF:
3196 HandleSelectCodec(pte);
3197 break;
3198 case KEY_LOUDSPK:
3199 send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
3200 handle_dial_page(pte);
3201 break;
3202 case KEY_HEADPHN:
3203 send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
3204 handle_dial_page(pte);
3205 break;
3206 case KEY_SNDHIST:
3207 show_history(pte, 'o');
3208 break;
3209 case KEY_RCVHIST:
3210 show_history(pte, 'i');
3211 break;
3213 return;
3216 static void key_history(struct unistimsession *pte, char keycode)
3218 FILE *f;
3219 char count;
3220 long offset;
3222 switch (keycode) {
3223 case KEY_UP:
3224 case KEY_LEFT:
3225 case KEY_FUNC1:
3226 if (pte->buff_entry[2] <= 1)
3227 return;
3228 pte->buff_entry[2]--;
3229 count = OpenHistory(pte, pte->buff_entry[0], &f);
3230 if (!count)
3231 return;
3232 offset = ((pte->buff_entry[2] - 1) * TEXT_LENGTH_MAX * 3);
3233 if (fseek(f, offset, SEEK_CUR)) {
3234 display_last_error("Unable to seek history entry.");
3235 fclose(f);
3236 return;
3238 show_entry_history(pte, &f);
3239 break;
3240 case KEY_DOWN:
3241 case KEY_RIGHT:
3242 case KEY_FUNC2:
3243 if (pte->buff_entry[2] >= pte->buff_entry[1])
3244 return;
3245 pte->buff_entry[2]++;
3246 count = OpenHistory(pte, pte->buff_entry[0], &f);
3247 if (!count)
3248 return;
3249 offset = ((pte->buff_entry[2] - 1) * TEXT_LENGTH_MAX * 3);
3250 if (fseek(f, offset, SEEK_CUR)) {
3251 display_last_error("Unable to seek history entry.");
3252 fclose(f);
3253 return;
3255 show_entry_history(pte, &f);
3256 break;
3257 case KEY_FUNC3:
3258 if (!ReformatNumber(pte->device->lst_cid))
3259 break;
3260 ast_copy_string(pte->device->redial_number, pte->device->lst_cid,
3261 sizeof(pte->device->redial_number));
3262 key_main_page(pte, KEY_FUNC2);
3263 break;
3264 case KEY_FUNC4:
3265 case KEY_HANGUP:
3266 show_main_page(pte);
3267 break;
3268 case KEY_SNDHIST:
3269 if (pte->buff_entry[0] == 'i')
3270 show_history(pte, 'o');
3271 else
3272 show_main_page(pte);
3273 break;
3274 case KEY_RCVHIST:
3275 if (pte->buff_entry[0] == 'i')
3276 show_main_page(pte);
3277 else
3278 show_history(pte, 'i');
3279 break;
3281 return;
3284 static void init_phone_step2(struct unistimsession *pte)
3286 BUFFSEND;
3287 if (unistimdebug)
3288 ast_verb(0, "Sending S4\n");
3289 memcpy(buffsend + SIZE_HEADER, packet_send_s4, sizeof(packet_send_s4));
3290 send_client(SIZE_HEADER + sizeof(packet_send_s4), buffsend, pte);
3291 send_date_time2(pte);
3292 send_date_time3(pte);
3293 if (unistimdebug)
3294 ast_verb(0, "Sending S7\n");
3295 memcpy(buffsend + SIZE_HEADER, packet_send_S7, sizeof(packet_send_S7));
3296 send_client(SIZE_HEADER + sizeof(packet_send_S7), buffsend, pte);
3297 if (unistimdebug)
3298 ast_verb(0, "Sending Contrast\n");
3299 memcpy(buffsend + SIZE_HEADER, packet_send_Contrast, sizeof(packet_send_Contrast));
3300 if (pte->device != NULL)
3301 buffsend[9] = pte->device->contrast;
3302 send_client(SIZE_HEADER + sizeof(packet_send_Contrast), buffsend, pte);
3304 if (unistimdebug)
3305 ast_verb(0, "Sending S9\n");
3306 memcpy(buffsend + SIZE_HEADER, packet_send_s9, sizeof(packet_send_s9));
3307 send_client(SIZE_HEADER + sizeof(packet_send_s9), buffsend, pte);
3308 send_no_ring(pte);
3310 if (unistimdebug)
3311 ast_verb(0, "Sending S7\n");
3312 memcpy(buffsend + SIZE_HEADER, packet_send_S7, sizeof(packet_send_S7));
3313 send_client(SIZE_HEADER + sizeof(packet_send_S7), buffsend, pte);
3314 send_led_update(pte, 0);
3315 send_ping(pte);
3316 if (pte->state < STATE_MAINPAGE) {
3317 if (autoprovisioning == AUTOPROVISIONING_TN) {
3318 ShowExtensionPage(pte);
3319 return;
3320 } else {
3321 int i;
3322 char tmp[30];
3324 for (i = 1; i < 6; i++)
3325 send_favorite(i, 0, pte, "");
3326 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Sorry, this phone is not");
3327 send_text(TEXT_LINE1, TEXT_NORMAL, pte, "registred in unistim.cfg");
3328 strcpy(tmp, "MAC = ");
3329 strcat(tmp, pte->macaddr);
3330 send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
3331 send_text_status(pte, "");
3332 send_texttitle(pte, "UNISTIM for*");
3333 return;
3336 show_main_page(pte);
3337 refresh_all_favorite(pte);
3338 if (unistimdebug)
3339 ast_verb(0, "Sending arrow\n");
3340 memcpy(buffsend + SIZE_HEADER, packet_send_arrow, sizeof(packet_send_arrow));
3341 send_client(SIZE_HEADER + sizeof(packet_send_arrow), buffsend, pte);
3342 return;
3345 static void process_request(int size, unsigned char *buf, struct unistimsession *pte)
3347 char tmpbuf[255];
3348 if (memcmp
3349 (buf + SIZE_HEADER, packet_recv_resume_connection_with_server,
3350 sizeof(packet_recv_resume_connection_with_server)) == 0) {
3351 rcv_resume_connection_with_server(pte);
3352 return;
3354 if (memcmp(buf + SIZE_HEADER, packet_recv_firm_version, sizeof(packet_recv_firm_version)) ==
3355 0) {
3356 buf[size] = 0;
3357 if (unistimdebug)
3358 ast_verb(0, "Got the firmware version : '%s'\n", buf + 13);
3359 init_phone_step2(pte);
3360 return;
3362 if (memcmp(buf + SIZE_HEADER, packet_recv_mac_addr, sizeof(packet_recv_mac_addr)) == 0) {
3363 rcv_mac_addr(pte, buf);
3364 return;
3366 if (memcmp(buf + SIZE_HEADER, packet_recv_r2, sizeof(packet_recv_r2)) == 0) {
3367 if (unistimdebug)
3368 ast_verb(0, "R2 received\n");
3369 return;
3372 if (pte->state < STATE_MAINPAGE) {
3373 if (unistimdebug)
3374 ast_verb(0, "Request not authorized in this state\n");
3375 return;
3377 if (!memcmp(buf + SIZE_HEADER, packet_recv_pressed_key, sizeof(packet_recv_pressed_key))) {
3378 char keycode = buf[13];
3380 if (unistimdebug)
3381 ast_verb(0, "Key pressed : keycode = 0x%.2x - current state : %d\n", keycode,
3382 pte->state);
3384 switch (pte->state) {
3385 case STATE_INIT:
3386 if (unistimdebug)
3387 ast_verb(0, "No keys allowed in the init state\n");
3388 break;
3389 case STATE_AUTHDENY:
3390 if (unistimdebug)
3391 ast_verb(0, "No keys allowed in authdeny state\n");
3392 break;
3393 case STATE_MAINPAGE:
3394 key_main_page(pte, keycode);
3395 break;
3396 case STATE_DIALPAGE:
3397 key_dial_page(pte, keycode);
3398 break;
3399 case STATE_RINGING:
3400 key_ringing(pte, keycode);
3401 break;
3402 case STATE_CALL:
3403 key_call(pte, keycode);
3404 break;
3405 case STATE_EXTENSION:
3406 key_select_extension(pte, keycode);
3407 break;
3408 case STATE_SELECTCODEC:
3409 key_select_codec(pte, keycode);
3410 break;
3411 case STATE_HISTORY:
3412 key_history(pte, keycode);
3413 break;
3414 default:
3415 ast_log(LOG_WARNING, "Key : Unknown state\n");
3417 return;
3419 if (memcmp(buf + SIZE_HEADER, packet_recv_pick_up, sizeof(packet_recv_pick_up)) == 0) {
3420 if (unistimdebug)
3421 ast_verb(0, "Handset off hook\n");
3422 if (!pte->device) /* We are not yet registred (asking for a TN in AUTOPROVISIONING_TN) */
3423 return;
3424 pte->device->receiver_state = STATE_OFFHOOK;
3425 if (pte->device->output == OUTPUT_HEADPHONE)
3426 send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
3427 else
3428 send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
3429 if (pte->state == STATE_RINGING)
3430 HandleCallIncoming(pte);
3431 else if ((pte->state == STATE_DIALPAGE) || (pte->state == STATE_CALL))
3432 send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
3433 else if (pte->state == STATE_EXTENSION) /* We must have a TN before calling */
3434 return;
3435 else {
3436 send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
3437 handle_dial_page(pte);
3439 return;
3441 if (memcmp(buf + SIZE_HEADER, packet_recv_hangup, sizeof(packet_recv_hangup)) == 0) {
3442 if (unistimdebug)
3443 ast_verb(0, "Handset on hook\n");
3444 if (!pte->device)
3445 return;
3446 pte->device->receiver_state = STATE_ONHOOK;
3447 if (pte->state == STATE_CALL)
3448 close_call(pte);
3449 else if (pte->device->lines->subs[SUB_REAL]->owner)
3450 close_call(pte);
3451 else if (pte->state == STATE_EXTENSION)
3452 return;
3453 else
3454 show_main_page(pte);
3455 return;
3457 strcpy(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr));
3458 strcat(tmpbuf, " Unknown request packet\n");
3459 if (unistimdebug)
3460 ast_debug(1, "%s", tmpbuf);
3461 return;
3464 static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
3465 struct sockaddr_in *addr_from)
3467 unsigned short *sbuf = (unsigned short *) buf;
3468 unsigned short seq;
3469 char tmpbuf[255];
3471 strcpy(tmpbuf, ast_inet_ntoa(addr_from->sin_addr));
3473 if (size < 10) {
3474 if (size == 0) {
3475 ast_log(LOG_WARNING, "%s Read error\n", tmpbuf);
3476 } else {
3477 ast_log(LOG_NOTICE, "%s Packet too short - ignoring\n", tmpbuf);
3479 return;
3481 if (sbuf[0] == 0xffff) { /* Starting with 0xffff ? *//* Yes, discovery packet ? */
3482 if (size != sizeof(packet_rcv_discovery)) {
3483 ast_log(LOG_NOTICE, "%s Invalid size of a discovery packet\n", tmpbuf);
3484 } else {
3485 if (memcmp(buf, packet_rcv_discovery, sizeof(packet_rcv_discovery)) == 0) {
3486 if (unistimdebug)
3487 ast_verb(0, "Discovery packet received - Sending Discovery ACK\n");
3488 if (pte) { /* A session was already active for this IP ? */
3489 if (pte->state == STATE_INIT) { /* Yes, but it's a dupe */
3490 if (unistimdebug)
3491 ast_verb(1, "Duplicated Discovery packet\n");
3492 send_raw_client(sizeof(packet_send_discovery_ack),
3493 packet_send_discovery_ack, addr_from, &pte->sout);
3494 pte->seq_phone = (short) 0x0000; /* reset sequence number */
3495 } else { /* No, probably a reboot, phone side */
3496 close_client(pte); /* Cleanup the previous session */
3497 if (create_client(addr_from))
3498 send_raw_client(sizeof(packet_send_discovery_ack),
3499 packet_send_discovery_ack, addr_from, &pte->sout);
3501 } else {
3502 /* Creating new entry in our phone list */
3503 if ((pte = create_client(addr_from)))
3504 send_raw_client(sizeof(packet_send_discovery_ack),
3505 packet_send_discovery_ack, addr_from, &pte->sout);
3507 return;
3509 ast_log(LOG_NOTICE, "%s Invalid discovery packet\n", tmpbuf);
3511 return;
3513 if (!pte) {
3514 if (unistimdebug)
3515 ast_verb(0, "%s Not a discovery packet from an unknown source : ignoring\n",
3516 tmpbuf);
3517 return;
3520 if (sbuf[0] != 0) { /* Starting with something else than 0x0000 ? */
3521 ast_log(LOG_NOTICE, "Unknown packet received - ignoring\n");
3522 return;
3524 if (buf[5] != 2) {
3525 ast_log(LOG_NOTICE, "%s Wrong direction : got 0x%.2x expected 0x02\n", tmpbuf,
3526 buf[5]);
3527 return;
3529 seq = ntohs(sbuf[1]);
3530 if (buf[4] == 1) {
3531 ast_mutex_lock(&pte->lock);
3532 if (unistimdebug)
3533 ast_verb(6, "ACK received for packet #0x%.4x\n", seq);
3534 pte->nb_retransmit = 0;
3536 if ((pte->last_seq_ack) + 1 == seq) {
3537 pte->last_seq_ack++;
3538 check_send_queue(pte);
3539 ast_mutex_unlock(&pte->lock);
3540 return;
3542 if (pte->last_seq_ack > seq) {
3543 if (pte->last_seq_ack == 0xffff) {
3544 ast_verb(0, "ACK at 0xffff, restarting counter.\n");
3545 pte->last_seq_ack = 0;
3546 } else
3547 ast_log(LOG_NOTICE,
3548 "%s Warning : ACK received for an already ACKed packet : #0x%.4x we are at #0x%.4x\n",
3549 tmpbuf, seq, pte->last_seq_ack);
3550 ast_mutex_unlock(&pte->lock);
3551 return;
3553 if (pte->seq_server < seq) {
3554 ast_log(LOG_NOTICE,
3555 "%s Error : ACK received for a non-existent packet : #0x%.4x\n",
3556 tmpbuf, pte->seq_server);
3557 ast_mutex_unlock(&pte->lock);
3558 return;
3560 if (unistimdebug)
3561 ast_verb(0, "%s ACK gap : Received ACK #0x%.4x, previous was #0x%.4x\n",
3562 tmpbuf, seq, pte->last_seq_ack);
3563 pte->last_seq_ack = seq;
3564 check_send_queue(pte);
3565 ast_mutex_unlock(&pte->lock);
3566 return;
3568 if (buf[4] == 2) {
3569 if (unistimdebug)
3570 ast_verb(0, "Request received\n");
3571 if (pte->seq_phone == seq) {
3572 /* Send ACK */
3573 buf[4] = 1;
3574 buf[5] = 1;
3575 send_raw_client(SIZE_HEADER, buf, addr_from, &pte->sout);
3576 pte->seq_phone++;
3578 process_request(size, buf, pte);
3579 return;
3581 if (pte->seq_phone > seq) {
3582 ast_log(LOG_NOTICE,
3583 "%s Warning : received a retransmitted packet : #0x%.4x (we are at #0x%.4x)\n",
3584 tmpbuf, seq, pte->seq_phone);
3585 /* BUG ? pte->device->seq_phone = seq; */
3586 /* Send ACK */
3587 buf[4] = 1;
3588 buf[5] = 1;
3589 send_raw_client(SIZE_HEADER, buf, addr_from, &pte->sout);
3590 return;
3592 ast_log(LOG_NOTICE,
3593 "%s Warning : we lost a packet : received #0x%.4x (we are at #0x%.4x)\n",
3594 tmpbuf, seq, pte->seq_phone);
3595 return;
3597 if (buf[4] == 0) {
3598 ast_log(LOG_NOTICE, "%s Retransmit request for packet #0x%.4x\n", tmpbuf, seq);
3599 if (pte->last_seq_ack > seq) {
3600 ast_log(LOG_NOTICE,
3601 "%s Error : received a request for an already ACKed packet : #0x%.4x\n",
3602 tmpbuf, pte->last_seq_ack);
3603 return;
3605 if (pte->seq_server < seq) {
3606 ast_log(LOG_NOTICE,
3607 "%s Error : received a request for a non-existent packet : #0x%.4x\n",
3608 tmpbuf, pte->seq_server);
3609 return;
3611 send_retransmit(pte);
3612 return;
3614 ast_log(LOG_NOTICE, "%s Unknown request : got 0x%.2x expected 0x00,0x01 or 0x02\n",
3615 tmpbuf, buf[4]);
3616 return;
3619 static struct unistimsession *channel_to_session(struct ast_channel *ast)
3621 struct unistim_subchannel *sub;
3622 if (!ast) {
3623 ast_log(LOG_WARNING, "Unistim callback function called with a null channel\n");
3624 return NULL;
3626 if (!ast->tech_pvt) {
3627 ast_log(LOG_WARNING, "Unistim callback function called without a tech_pvt\n");
3628 return NULL;
3630 sub = ast->tech_pvt;
3632 if (!sub->parent) {
3633 ast_log(LOG_WARNING, "Unistim callback function called without a line\n");
3634 return NULL;
3636 if (!sub->parent->parent) {
3637 ast_log(LOG_WARNING, "Unistim callback function called without a device\n");
3638 return NULL;
3640 if (!sub->parent->parent->session) {
3641 ast_log(LOG_WARNING, "Unistim callback function called without a session\n");
3642 return NULL;
3644 return sub->parent->parent->session;
3647 /*--- unistim_call: Initiate UNISTIM call from PBX ---*/
3648 /* used from the dial() application */
3649 static int unistim_call(struct ast_channel *ast, char *dest, int timeout)
3651 int res = 0;
3652 struct unistim_subchannel *sub;
3653 struct unistimsession *session;
3655 session = channel_to_session(ast);
3656 if (!session) {
3657 ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
3658 return -1;
3661 sub = ast->tech_pvt;
3662 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
3663 ast_log(LOG_WARNING, "unistim_call called on %s, neither down nor reserved\n",
3664 ast->name);
3665 return -1;
3668 if (unistimdebug)
3669 ast_verb(3, "unistim_call(%s)\n", ast->name);
3671 session->state = STATE_RINGING;
3672 Sendicon(TEXT_LINE0, FAV_ICON_NONE, session);
3674 if (sub->owner) {
3675 if (sub->owner->cid.cid_num) {
3676 send_text(TEXT_LINE1, TEXT_NORMAL, session, sub->owner->cid.cid_num);
3677 change_callerid(session, 0, sub->owner->cid.cid_num);
3678 } else {
3679 send_text(TEXT_LINE1, TEXT_NORMAL, session, DEFAULTCALLERID);
3680 change_callerid(session, 0, DEFAULTCALLERID);
3682 if (sub->owner->cid.cid_name) {
3683 send_text(TEXT_LINE0, TEXT_NORMAL, session, sub->owner->cid.cid_name);
3684 change_callerid(session, 1, sub->owner->cid.cid_name);
3685 } else {
3686 send_text(TEXT_LINE0, TEXT_NORMAL, session, DEFAULTCALLERNAME);
3687 change_callerid(session, 1, DEFAULTCALLERNAME);
3690 send_text(TEXT_LINE2, TEXT_NORMAL, session, "is calling you.");
3691 send_text_status(session, "Accept Ignore");
3693 if (sub->ringstyle == -1)
3694 send_ring(session, session->device->ringvolume, session->device->ringstyle);
3695 else {
3696 if (sub->ringvolume == -1)
3697 send_ring(session, session->device->ringvolume, sub->ringstyle);
3698 else
3699 send_ring(session, sub->ringvolume, sub->ringstyle);
3701 change_favorite_icon(session, FAV_ICON_SPEAKER_ONHOOK_BLACK + FAV_BLINK_FAST);
3703 ast_setstate(ast, AST_STATE_RINGING);
3704 ast_queue_control(ast, AST_CONTROL_RINGING);
3705 return res;
3708 /*--- unistim_hangup: Hangup UNISTIM call */
3709 static int unistim_hangup(struct ast_channel *ast)
3711 struct unistim_subchannel *sub;
3712 struct unistim_line *l;
3713 struct unistimsession *s;
3715 s = channel_to_session(ast);
3716 sub = ast->tech_pvt;
3717 if (!s) {
3718 ast_debug(1, "Asked to hangup channel not connected\n");
3719 ast_mutex_lock(&sub->lock);
3720 sub->owner = NULL;
3721 ast->tech_pvt = NULL;
3722 sub->alreadygone = 0;
3723 ast_mutex_unlock(&sub->lock);
3724 if (sub->rtp) {
3725 if (unistimdebug)
3726 ast_verb(0, "Destroying RTP session\n");
3727 ast_rtp_destroy(sub->rtp);
3728 sub->rtp = NULL;
3730 return 0;
3732 l = sub->parent;
3733 if (unistimdebug)
3734 ast_verb(0, "unistim_hangup(%s) on %s@%s\n", ast->name, l->name, l->parent->name);
3736 if ((l->subs[SUB_THREEWAY]) && (sub->subtype == SUB_REAL)) {
3737 if (unistimdebug)
3738 ast_verb(0, "Real call disconnected while talking to threeway\n");
3739 sub->owner = NULL;
3740 ast->tech_pvt = NULL;
3741 return 0;
3743 if ((l->subs[SUB_REAL]->owner) && (sub->subtype == SUB_THREEWAY) &&
3744 (sub->alreadygone == 0)) {
3745 if (unistimdebug)
3746 ast_verb(0, "threeway call disconnected, switching to real call\n");
3747 send_text(TEXT_LINE0, TEXT_NORMAL, s, "Three way call canceled,");
3748 send_text(TEXT_LINE1, TEXT_NORMAL, s, "switching back to");
3749 send_text(TEXT_LINE2, TEXT_NORMAL, s, "previous call.");
3750 send_text_status(s, "Hangup Transf");
3751 ast_moh_stop(ast_bridged_channel(l->subs[SUB_REAL]->owner));
3752 swap_subs(l, SUB_THREEWAY, SUB_REAL);
3753 l->parent->moh = 0;
3754 ast_mutex_lock(&sub->lock);
3755 sub->owner = NULL;
3756 ast->tech_pvt = NULL;
3757 ast_mutex_unlock(&sub->lock);
3758 unalloc_sub(l, SUB_THREEWAY);
3759 return 0;
3761 ast_mutex_lock(&sub->lock);
3762 sub->owner = NULL;
3763 ast->tech_pvt = NULL;
3764 sub->alreadygone = 0;
3765 ast_mutex_unlock(&sub->lock);
3766 if (!s) {
3767 if (unistimdebug)
3768 ast_verb(0, "Asked to hangup channel not connected (no session)\n");
3769 if (sub->rtp) {
3770 if (unistimdebug)
3771 ast_verb(0, "Destroying RTP session\n");
3772 ast_rtp_destroy(sub->rtp);
3773 sub->rtp = NULL;
3775 return 0;
3777 if (sub->subtype == SUB_REAL) {
3778 /* Stop the silence generator */
3779 if (s->device->silence_generator) {
3780 if (unistimdebug)
3781 ast_verb(0, "Stopping silence generator\n");
3782 if (sub->owner)
3783 ast_channel_stop_silence_generator(sub->owner,
3784 s->device->silence_generator);
3785 else
3786 ast_log(LOG_WARNING,
3787 "Trying to stop silence generator on a null channel !\n");
3788 s->device->silence_generator = NULL;
3791 l->parent->moh = 0;
3792 send_no_ring(s);
3793 send_end_call(s);
3794 if (sub->rtp) {
3795 if (unistimdebug)
3796 ast_verb(0, "Destroying RTP session\n");
3797 ast_rtp_destroy(sub->rtp);
3798 sub->rtp = NULL;
3799 } else if (unistimdebug)
3800 ast_verb(0, "No RTP session to destroy\n");
3801 if (l->subs[SUB_THREEWAY]) {
3802 if (unistimdebug)
3803 ast_verb(0, "Cleaning other subchannels\n");
3804 unalloc_sub(l, SUB_THREEWAY);
3806 if (s->state == STATE_RINGING)
3807 cancel_dial(s);
3808 else if (s->state == STATE_CALL)
3809 close_call(s);
3811 return 0;
3814 /*--- unistim_answer: Answer UNISTIM call */
3815 static int unistim_answer(struct ast_channel *ast)
3817 int res = 0;
3818 struct unistim_subchannel *sub;
3819 struct unistim_line *l;
3820 struct unistimsession *s;
3822 s = channel_to_session(ast);
3823 if (!s) {
3824 ast_log(LOG_WARNING, "unistim_answer on a disconnected device ?\n");
3825 return -1;
3827 sub = ast->tech_pvt;
3828 l = sub->parent;
3830 if ((!sub->rtp) && (!l->subs[SUB_THREEWAY]))
3831 start_rtp(sub);
3832 if (unistimdebug)
3833 ast_verb(0, "unistim_answer(%s) on %s@%s-%d\n", ast->name, l->name,
3834 l->parent->name, sub->subtype);
3835 send_text(TEXT_LINE2, TEXT_NORMAL, l->parent->session, "is now on-line");
3836 if (l->subs[SUB_THREEWAY])
3837 send_text_status(l->parent->session, "Transf Cancel");
3838 else
3839 send_text_status(l->parent->session, "Hangup Transf");
3840 send_start_timer(l->parent->session);
3841 if (ast->_state != AST_STATE_UP)
3842 ast_setstate(ast, AST_STATE_UP);
3843 return res;
3846 /*--- unistimsock_read: Read data from UNISTIM socket ---*/
3847 /* Successful messages is connected to UNISTIM call and forwarded to parsing() */
3848 static int unistimsock_read(int *id, int fd, short events, void *ignore)
3850 struct sockaddr_in addr_from = { 0, };
3851 struct unistimsession *cur = NULL;
3852 int found = 0;
3853 int tmp = 0;
3854 int dw_num_bytes_rcvd;
3855 #ifdef DUMP_PACKET
3856 int dw_num_bytes_rcvdd;
3857 char iabuf[INET_ADDRSTRLEN];
3858 #endif
3860 dw_num_bytes_rcvd =
3861 recvfrom(unistimsock, buff, SIZE_PAGE, 0, (struct sockaddr *) &addr_from,
3862 &size_addr_from);
3863 if (dw_num_bytes_rcvd == -1) {
3864 if (errno == EAGAIN)
3865 ast_log(LOG_NOTICE, "UNISTIM: Received packet with bad UDP checksum\n");
3866 else if (errno != ECONNREFUSED)
3867 ast_log(LOG_WARNING, "Recv error %d (%s)\n", errno, strerror(errno));
3868 return 1;
3871 /* Looking in the phone list if we already have a registration for him */
3872 ast_mutex_lock(&sessionlock);
3873 cur = sessions;
3874 while (cur) {
3875 if (cur->sin.sin_addr.s_addr == addr_from.sin_addr.s_addr) {
3876 found = 1;
3877 break;
3879 tmp++;
3880 cur = cur->next;
3882 ast_mutex_unlock(&sessionlock);
3884 #ifdef DUMP_PACKET
3885 if (unistimdebug)
3886 ast_verb(0, "\n*** Dump %d bytes from %s - phone_table[%d] ***\n",
3887 dw_num_bytes_rcvd, ast_inet_ntoa(addr_from.sin_addr), tmp);
3888 for (dw_num_bytes_rcvdd = 0; dw_num_bytes_rcvdd < dw_num_bytes_rcvd;
3889 dw_num_bytes_rcvdd++)
3890 ast_verb(0, "%.2x ", (unsigned char) buff[dw_num_bytes_rcvdd]);
3891 ast_verb(0, "\n******************************************\n");
3892 #endif
3894 if (!found) {
3895 if (unistimdebug)
3896 ast_verb(0, "Received a packet from an unknown source\n");
3897 parsing(dw_num_bytes_rcvd, buff, NULL, (struct sockaddr_in *) &addr_from);
3899 } else
3900 parsing(dw_num_bytes_rcvd, buff, cur, (struct sockaddr_in *) &addr_from);
3902 return 1;
3905 static struct ast_frame *unistim_rtp_read(const struct ast_channel *ast,
3906 const struct unistim_subchannel *sub)
3908 /* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
3909 struct ast_frame *f;
3911 if (!ast) {
3912 ast_log(LOG_WARNING, "Channel NULL while reading\n");
3913 return &ast_null_frame;
3916 if (!sub->rtp) {
3917 ast_log(LOG_WARNING, "RTP handle NULL while reading on subchannel %d\n",
3918 sub->subtype);
3919 return &ast_null_frame;
3922 switch (ast->fdno) {
3923 case 0:
3924 f = ast_rtp_read(sub->rtp); /* RTP Audio */
3925 break;
3926 case 1:
3927 f = ast_rtcp_read(sub->rtp); /* RTCP Control Channel */
3928 break;
3929 default:
3930 f = &ast_null_frame;
3933 if (sub->owner) {
3934 /* We already hold the channel lock */
3935 if (f->frametype == AST_FRAME_VOICE) {
3936 if (f->subclass != sub->owner->nativeformats) {
3937 ast_debug(1,
3938 "Oooh, format changed from %s (%d) to %s (%d)\n",
3939 ast_getformatname(sub->owner->nativeformats),
3940 sub->owner->nativeformats, ast_getformatname(f->subclass),
3941 f->subclass);
3943 sub->owner->nativeformats = f->subclass;
3944 ast_set_read_format(sub->owner, sub->owner->readformat);
3945 ast_set_write_format(sub->owner, sub->owner->writeformat);
3950 return f;
3953 static struct ast_frame *unistim_read(struct ast_channel *ast)
3955 struct ast_frame *fr;
3956 struct unistim_subchannel *sub = ast->tech_pvt;
3958 ast_mutex_lock(&sub->lock);
3959 fr = unistim_rtp_read(ast, sub);
3960 ast_mutex_unlock(&sub->lock);
3962 return fr;
3965 static int unistim_write(struct ast_channel *ast, struct ast_frame *frame)
3967 struct unistim_subchannel *sub = ast->tech_pvt;
3968 int res = 0;
3970 if (frame->frametype != AST_FRAME_VOICE) {
3971 if (frame->frametype == AST_FRAME_IMAGE)
3972 return 0;
3973 else {
3974 ast_log(LOG_WARNING, "Can't send %d type frames with unistim_write\n",
3975 frame->frametype);
3976 return 0;
3978 } else {
3979 if (!(frame->subclass & ast->nativeformats)) {
3980 ast_log(LOG_WARNING,
3981 "Asked to transmit frame type %s (%d), while native formats is %s (%d) (read/write = %s (%d)/%d)\n",
3982 ast_getformatname(frame->subclass), frame->subclass,
3983 ast_getformatname(ast->nativeformats), ast->nativeformats,
3984 ast_getformatname(ast->readformat), ast->readformat,
3985 ast->writeformat);
3986 return -1;
3990 if (sub) {
3991 ast_mutex_lock(&sub->lock);
3992 if (sub->rtp) {
3993 res = ast_rtp_write(sub->rtp, frame);
3995 ast_mutex_unlock(&sub->lock);
3998 return res;
4001 static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
4003 struct unistim_subchannel *p = newchan->tech_pvt;
4004 struct unistim_line *l = p->parent;
4006 ast_mutex_lock(&p->lock);
4008 ast_debug(1, "New owner for channel USTM/%s@%s-%d is %s\n", l->name,
4009 l->parent->name, p->subtype, newchan->name);
4011 if (p->owner != oldchan) {
4012 ast_log(LOG_WARNING, "old channel wasn't %s (%p) but was %s (%p)\n",
4013 oldchan->name, oldchan, p->owner->name, p->owner);
4014 return -1;
4017 p->owner = newchan;
4019 ast_mutex_unlock(&p->lock);
4021 return 0;
4025 static char *control2str(int ind)
4027 switch (ind) {
4028 case AST_CONTROL_HANGUP:
4029 return "Other end has hungup";
4030 case AST_CONTROL_RING:
4031 return "Local ring";
4032 case AST_CONTROL_RINGING:
4033 return "Remote end is ringing";
4034 case AST_CONTROL_ANSWER:
4035 return "Remote end has answered";
4036 case AST_CONTROL_BUSY:
4037 return "Remote end is busy";
4038 case AST_CONTROL_TAKEOFFHOOK:
4039 return "Make it go off hook";
4040 case AST_CONTROL_OFFHOOK:
4041 return "Line is off hook";
4042 case AST_CONTROL_CONGESTION:
4043 return "Congestion (circuits busy)";
4044 case AST_CONTROL_FLASH:
4045 return "Flash hook";
4046 case AST_CONTROL_WINK:
4047 return "Wink";
4048 case AST_CONTROL_OPTION:
4049 return "Set a low-level option";
4050 case AST_CONTROL_RADIO_KEY:
4051 return "Key Radio";
4052 case AST_CONTROL_RADIO_UNKEY:
4053 return "Un-Key Radio";
4054 case -1:
4055 return "Stop tone";
4057 return "UNKNOWN";
4060 static void in_band_indication(struct ast_channel *ast, const struct ind_tone_zone *tz,
4061 const char *indication)
4063 const struct ind_tone_zone_sound *ts = NULL;
4065 ts = ast_get_indication_tone(tz, indication);
4067 if (ts && ts->data[0])
4068 ast_playtones_start(ast, 0, ts->data, 1);
4069 else
4070 ast_log(LOG_WARNING, "Unable to get indication tone for %s\n", indication);
4073 static int unistim_indicate(struct ast_channel *ast, int ind, const void *data,
4074 size_t datalen)
4076 struct unistim_subchannel *sub;
4077 struct unistim_line *l;
4078 struct unistimsession *s;
4080 if (unistimdebug) {
4081 ast_verb(3, "Asked to indicate '%s' condition on channel %s\n",
4082 control2str(ind), ast->name);
4085 s = channel_to_session(ast);
4086 if (!s)
4087 return -1;
4089 sub = ast->tech_pvt;
4090 l = sub->parent;
4092 switch (ind) {
4093 case AST_CONTROL_RINGING:
4094 if (ast->_state != AST_STATE_UP) {
4095 send_text(TEXT_LINE2, TEXT_NORMAL, s, "Ringing...");
4096 in_band_indication(ast, l->parent->tz, "ring");
4097 s->device->missed_call = -1;
4098 break;
4100 return -1;
4101 case AST_CONTROL_BUSY:
4102 if (ast->_state != AST_STATE_UP) {
4103 sub->alreadygone = 1;
4104 send_text(TEXT_LINE2, TEXT_NORMAL, s, "Busy");
4105 in_band_indication(ast, l->parent->tz, "busy");
4106 s->device->missed_call = -1;
4107 break;
4109 return -1;
4110 case AST_CONTROL_CONGESTION:
4111 if (ast->_state != AST_STATE_UP) {
4112 sub->alreadygone = 1;
4113 send_text(TEXT_LINE2, TEXT_NORMAL, s, "Congestion");
4114 in_band_indication(ast, l->parent->tz, "congestion");
4115 s->device->missed_call = -1;
4116 break;
4118 return -1;
4119 case AST_CONTROL_HOLD:
4120 ast_moh_start(ast, data, NULL);
4121 break;
4122 case AST_CONTROL_UNHOLD:
4123 ast_moh_stop(ast);
4124 break;
4125 case AST_CONTROL_PROGRESS:
4126 case AST_CONTROL_SRCUPDATE:
4127 break;
4128 case -1:
4129 ast_playtones_stop(ast);
4130 s->device->missed_call = 0;
4131 break;
4132 case AST_CONTROL_PROCEEDING:
4133 break;
4134 default:
4135 ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
4136 return -1;
4139 return 0;
4142 static struct unistim_subchannel *find_subchannel_by_name(const char *dest)
4144 struct unistim_line *l;
4145 struct unistim_device *d;
4146 char line[256];
4147 char *at;
4148 char *device;
4150 ast_copy_string(line, dest, sizeof(line));
4151 at = strchr(line, '@');
4152 if (!at) {
4153 ast_log(LOG_NOTICE, "Device '%s' has no @ (at) sign!\n", dest);
4154 return NULL;
4156 *at = '\0';
4157 at++;
4158 device = at;
4159 ast_mutex_lock(&devicelock);
4160 d = devices;
4161 at = strchr(device, '/'); /* Extra options ? */
4162 if (at)
4163 *at = '\0';
4164 while (d) {
4165 if (!strcasecmp(d->name, device)) {
4166 if (unistimdebug)
4167 ast_verb(0, "Found device: %s\n", d->name);
4168 /* Found the device */
4169 l = d->lines;
4170 while (l) {
4171 /* Search for the right line */
4172 if (!strcasecmp(l->name, line)) {
4173 l->subs[SUB_REAL]->ringvolume = -1;
4174 l->subs[SUB_REAL]->ringstyle = -1;
4175 if (at) { /* Other options ? */
4176 at++; /* Skip slash */
4177 if (*at == 'r') { /* distinctive ring */
4178 at++;
4179 if ((*at < '0') || (*at > '7')) /* ring style */
4180 ast_log(LOG_WARNING, "Invalid ring selection (%s)", at);
4181 else {
4182 char ring_volume = -1;
4183 char ring_style = *at - '0';
4184 at++;
4185 if ((*at >= '0') && (*at <= '3')) /* ring volume */
4186 ring_volume = *at - '0';
4187 if (unistimdebug)
4188 ast_verb(0, "Distinctive ring : style #%d volume %d\n",
4189 ring_style, ring_volume);
4190 l->subs[SUB_REAL]->ringvolume = ring_volume;
4191 l->subs[SUB_REAL]->ringstyle = ring_style;
4195 ast_mutex_unlock(&devicelock);
4196 return l->subs[SUB_REAL];
4198 l = l->next;
4201 d = d->next;
4203 /* Device not found */
4204 ast_mutex_unlock(&devicelock);
4206 return NULL;
4209 static int unistim_senddigit_begin(struct ast_channel *ast, char digit)
4211 struct unistimsession *pte = channel_to_session(ast);
4213 if (!pte)
4214 return -1;
4216 return unistim_do_senddigit(pte, digit);
4219 static int unistim_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
4221 struct unistimsession *pte = channel_to_session(ast);
4222 struct ast_frame f = { 0, };
4223 struct unistim_subchannel *sub;
4225 sub = pte->device->lines->subs[SUB_REAL];
4227 if (!sub->owner) {
4228 ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigiti_end\n");
4229 return -1;
4232 if (unistimdebug)
4233 ast_verb(0, "Send Digit off %c\n", digit);
4235 if (!pte)
4236 return -1;
4238 send_tone(pte, 0, 0);
4239 f.frametype = AST_FRAME_DTMF;
4240 f.subclass = digit;
4241 f.src = "unistim";
4242 ast_queue_frame(sub->owner, &f);
4244 return 0;
4247 /*--- unistim_sendtext: Display a text on the phone screen ---*/
4248 /* Called from PBX core text message functions */
4249 static int unistim_sendtext(struct ast_channel *ast, const char *text)
4251 struct unistimsession *pte = channel_to_session(ast);
4252 int size;
4253 char tmp[TEXT_LENGTH_MAX + 1];
4255 if (unistimdebug)
4256 ast_verb(0, "unistim_sendtext called\n");
4258 if (!text) {
4259 ast_log(LOG_WARNING, "unistim_sendtext called with a null text\n");
4260 return 1;
4263 size = strlen(text);
4264 if (text[0] == '@') {
4265 int pos = 0, i = 1, tok = 0, sz = 0;
4266 char label[11];
4267 char number[16];
4268 char icon = '\0';
4269 char cur = '\0';
4271 memset(label, 0, 11);
4272 memset(number, 0, 16);
4273 while (text[i]) {
4274 cur = text[i++];
4275 switch (tok) {
4276 case 0:
4277 if ((cur < '0') && (cur > '5')) {
4278 ast_log(LOG_WARNING,
4279 "sendtext failed : position must be a number beetween 0 and 5\n");
4280 return 1;
4282 pos = cur - '0';
4283 tok = 1;
4284 continue;
4285 case 1:
4286 if (cur != '@') {
4287 ast_log(LOG_WARNING, "sendtext failed : invalid position\n");
4288 return 1;
4290 tok = 2;
4291 continue;
4292 case 2:
4293 if ((cur < '3') && (cur > '6')) {
4294 ast_log(LOG_WARNING,
4295 "sendtext failed : icon must be a number beetween 32 and 63 (first digit invalid)\n");
4296 return 1;
4298 icon = (cur - '0') * 10;
4299 tok = 3;
4300 continue;
4301 case 3:
4302 if ((cur < '0') && (cur > '9')) {
4303 ast_log(LOG_WARNING,
4304 "sendtext failed : icon must be a number beetween 32 and 63 (second digit invalid)\n");
4305 return 1;
4307 icon += (cur - '0');
4308 tok = 4;
4309 continue;
4310 case 4:
4311 if (cur != '@') {
4312 ast_log(LOG_WARNING,
4313 "sendtext failed : icon must be a number beetween 32 and 63 (too many digits)\n");
4314 return 1;
4316 tok = 5;
4317 continue;
4318 case 5:
4319 if (cur == '@') {
4320 tok = 6;
4321 sz = 0;
4322 continue;
4324 if (sz > 10)
4325 continue;
4326 label[sz] = cur;
4327 sz++;
4328 continue;
4329 case 6:
4330 if (sz > 15) {
4331 ast_log(LOG_WARNING,
4332 "sendtext failed : extension too long = %d (15 car max)\n",
4333 sz);
4334 return 1;
4336 number[sz] = cur;
4337 sz++;
4338 continue;
4341 if (tok != 6) {
4342 ast_log(LOG_WARNING, "sendtext failed : incomplet command\n");
4343 return 1;
4345 if (!pte->device) {
4346 ast_log(LOG_WARNING, "sendtext failed : no device ?\n");
4347 return 1;
4349 strcpy(pte->device->softkeylabel[pos], label);
4350 strcpy(pte->device->softkeynumber[pos], number);
4351 pte->device->softkeyicon[pos] = icon;
4352 send_favorite(pos, icon, pte, label);
4353 return 0;
4356 if (size <= TEXT_LENGTH_MAX * 2) {
4357 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Message :");
4358 send_text(TEXT_LINE1, TEXT_NORMAL, pte, text);
4359 if (size <= TEXT_LENGTH_MAX) {
4360 send_text(TEXT_LINE2, TEXT_NORMAL, pte, "");
4361 return 0;
4363 memcpy(tmp, text + TEXT_LENGTH_MAX, TEXT_LENGTH_MAX);
4364 tmp[sizeof(tmp) - 1] = '\0';
4365 send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
4366 return 0;
4368 send_text(TEXT_LINE0, TEXT_NORMAL, pte, text);
4369 memcpy(tmp, text + TEXT_LENGTH_MAX, TEXT_LENGTH_MAX);
4370 tmp[sizeof(tmp) - 1] = '\0';
4371 send_text(TEXT_LINE1, TEXT_NORMAL, pte, tmp);
4372 memcpy(tmp, text + TEXT_LENGTH_MAX * 2, TEXT_LENGTH_MAX);
4373 tmp[sizeof(tmp) - 1] = '\0';
4374 send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
4375 return 0;
4378 /*--- unistim_send_mwi_to_peer: Send message waiting indication ---*/
4379 static int unistim_send_mwi_to_peer(struct unistimsession *s, unsigned int tick)
4381 struct ast_event *event;
4382 int new;
4383 char *mailbox, *context;
4384 struct unistim_line *peer = s->device->lines;
4386 context = mailbox = ast_strdupa(peer->mailbox);
4387 strsep(&context, "@");
4388 if (ast_strlen_zero(context))
4389 context = "default";
4391 event = ast_event_get_cached(AST_EVENT_MWI,
4392 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
4393 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
4394 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
4395 AST_EVENT_IE_END);
4397 if (event) {
4398 new = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
4399 ast_event_destroy(event);
4400 } else { /* Fall back on checking the mailbox directly */
4401 new = ast_app_has_voicemail(peer->mailbox, "INBOX");
4404 peer->nextmsgcheck = tick + TIMER_MWI;
4406 /* Return now if it's the same thing we told them last time */
4407 if (new == peer->lastmsgssent) {
4408 return 0;
4411 peer->lastmsgssent = new;
4412 if (new == 0) {
4413 send_led_update(s, 0);
4414 } else {
4415 send_led_update(s, 1);
4418 return 0;
4421 /*--- unistim_new: Initiate a call in the UNISTIM channel */
4422 /* called from unistim_request (calls from the pbx ) */
4423 static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state)
4425 struct ast_channel *tmp;
4426 struct unistim_line *l;
4427 int fmt;
4429 if (!sub) {
4430 ast_log(LOG_WARNING, "subchannel null in unistim_new\n");
4431 return NULL;
4433 if (!sub->parent) {
4434 ast_log(LOG_WARNING, "no line for subchannel %p\n", sub);
4435 return NULL;
4437 l = sub->parent;
4438 tmp = ast_channel_alloc(1, state, l->cid_num, NULL, l->accountcode, l->exten,
4439 l->context, l->amaflags, "%s-%08x", l->fullname, (int) (long) sub);
4440 if (unistimdebug)
4441 ast_verb(0, "unistim_new sub=%d (%p) chan=%p\n", sub->subtype, sub, tmp);
4442 if (!tmp) {
4443 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
4444 return NULL;
4447 tmp->nativeformats = l->capability;
4448 if (!tmp->nativeformats)
4449 tmp->nativeformats = CAPABILITY;
4450 fmt = ast_best_codec(tmp->nativeformats);
4451 if (unistimdebug)
4452 ast_verb(0, "Best codec = %d from nativeformats %d (line cap=%d global=%d)\n", fmt,
4453 tmp->nativeformats, l->capability, CAPABILITY);
4454 ast_string_field_build(tmp, name, "USTM/%s@%s-%d", l->name, l->parent->name,
4455 sub->subtype);
4456 if ((sub->rtp) && (sub->subtype == 0)) {
4457 if (unistimdebug)
4458 ast_verb(0, "New unistim channel with a previous rtp handle ?\n");
4459 tmp->fds[0] = ast_rtp_fd(sub->rtp);
4460 tmp->fds[1] = ast_rtcp_fd(sub->rtp);
4462 if (sub->rtp)
4463 ast_jb_configure(tmp, &global_jbconf);
4465 /* tmp->type = type; */
4466 ast_setstate(tmp, state);
4467 if (state == AST_STATE_RING)
4468 tmp->rings = 1;
4469 tmp->adsicpe = AST_ADSI_UNAVAILABLE;
4470 tmp->writeformat = fmt;
4471 tmp->rawwriteformat = fmt;
4472 tmp->readformat = fmt;
4473 tmp->rawreadformat = fmt;
4474 tmp->tech_pvt = sub;
4475 tmp->tech = &unistim_tech;
4476 if (!ast_strlen_zero(l->language))
4477 ast_string_field_set(tmp, language, l->language);
4478 sub->owner = tmp;
4479 ast_mutex_lock(&usecnt_lock);
4480 usecnt++;
4481 ast_mutex_unlock(&usecnt_lock);
4482 ast_update_use_count();
4483 tmp->callgroup = l->callgroup;
4484 tmp->pickupgroup = l->pickupgroup;
4485 ast_string_field_set(tmp, call_forward, l->parent->call_forward);
4486 if (!ast_strlen_zero(l->cid_num)) {
4487 char *name, *loc, *instr;
4488 instr = ast_strdup(l->cid_num);
4489 if (instr) {
4490 ast_callerid_parse(instr, &name, &loc);
4491 tmp->cid.cid_num = ast_strdup(loc);
4492 tmp->cid.cid_name = ast_strdup(name);
4493 ast_free(instr);
4496 tmp->priority = 1;
4497 if (state != AST_STATE_DOWN) {
4498 if (unistimdebug)
4499 ast_verb(0, "Starting pbx in unistim_new\n");
4500 if (ast_pbx_start(tmp)) {
4501 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
4502 ast_hangup(tmp);
4503 tmp = NULL;
4507 return tmp;
4510 static void *do_monitor(void *data)
4512 struct unistimsession *cur = NULL;
4513 unsigned int dw_timeout = 0;
4514 unsigned int tick;
4515 int res;
4516 int reloading;
4518 /* Add an I/O event to our UDP socket */
4519 if (unistimsock > -1)
4520 ast_io_add(io, unistimsock, unistimsock_read, AST_IO_IN, NULL);
4522 /* This thread monitors our UDP socket and timers */
4523 for (;;) {
4524 /* This loop is executed at least every IDLE_WAITus (1s) or every time a packet is received */
4525 /* Looking for the smallest time-out value */
4526 tick = get_tick_count();
4527 dw_timeout = UINT_MAX;
4528 ast_mutex_lock(&sessionlock);
4529 cur = sessions;
4530 DEBUG_TIMER("checking timeout for session %p with tick = %u\n", cur, tick);
4531 while (cur) {
4532 DEBUG_TIMER("checking timeout for session %p timeout = %u\n", cur,
4533 cur->timeout);
4534 /* Check if we have miss something */
4535 if (cur->timeout <= tick) {
4536 DEBUG_TIMER("Event for session %p\n", cur);
4537 /* If the queue is empty, send a ping */
4538 if (cur->last_buf_available == 0)
4539 send_ping(cur);
4540 else {
4541 if (send_retransmit(cur)) {
4542 DEBUG_TIMER("The chained link was modified, restarting...\n");
4543 cur = sessions;
4544 dw_timeout = UINT_MAX;
4545 continue;
4549 if (dw_timeout > cur->timeout - tick)
4550 dw_timeout = cur->timeout - tick;
4551 /* Checking if the phone is logged on for a new MWI */
4552 if (cur->device) {
4553 if ((!ast_strlen_zero(cur->device->lines->mailbox)) &&
4554 ((tick >= cur->device->lines->nextmsgcheck))) {
4555 DEBUG_TIMER("Checking mailbox for MWI\n");
4556 unistim_send_mwi_to_peer(cur, tick);
4557 break;
4560 cur = cur->next;
4562 ast_mutex_unlock(&sessionlock);
4563 DEBUG_TIMER("Waiting for %dus\n", dw_timeout);
4564 res = dw_timeout;
4565 /* We should not wait more than IDLE_WAIT */
4566 if ((res < 0) || (res > IDLE_WAIT))
4567 res = IDLE_WAIT;
4568 /* Wait for UDP messages for a maximum of res us */
4569 res = ast_io_wait(io, res); /* This function will call unistimsock_read if a packet is received */
4570 /* Check for a reload request */
4571 ast_mutex_lock(&unistim_reload_lock);
4572 reloading = unistim_reloading;
4573 unistim_reloading = 0;
4574 ast_mutex_unlock(&unistim_reload_lock);
4575 if (reloading) {
4576 ast_verb(1, "Reloading unistim.conf...\n");
4577 reload_config();
4579 pthread_testcancel();
4581 /* Never reached */
4582 return NULL;
4585 /*--- restart_monitor: Start the channel monitor thread ---*/
4586 static int restart_monitor(void)
4588 pthread_attr_t attr;
4589 /* If we're supposed to be stopped -- stay stopped */
4590 if (monitor_thread == AST_PTHREADT_STOP)
4591 return 0;
4592 if (ast_mutex_lock(&monlock)) {
4593 ast_log(LOG_WARNING, "Unable to lock monitor\n");
4594 return -1;
4596 if (monitor_thread == pthread_self()) {
4597 ast_mutex_unlock(&monlock);
4598 ast_log(LOG_WARNING, "Cannot kill myself\n");
4599 return -1;
4601 if (monitor_thread != AST_PTHREADT_NULL) {
4602 /* Wake up the thread */
4603 pthread_kill(monitor_thread, SIGURG);
4604 } else {
4605 pthread_attr_init(&attr);
4606 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
4607 /* Start a new monitor */
4608 if (ast_pthread_create(&monitor_thread, &attr, do_monitor, NULL) < 0) {
4609 ast_mutex_unlock(&monlock);
4610 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
4611 return -1;
4614 ast_mutex_unlock(&monlock);
4615 return 0;
4618 /*--- unistim_request: PBX interface function ---*/
4619 /* UNISTIM calls initiated by the PBX arrive here */
4620 static struct ast_channel *unistim_request(const char *type, int format, void *data,
4621 int *cause)
4623 int oldformat;
4624 struct unistim_subchannel *sub;
4625 struct ast_channel *tmpc = NULL;
4626 char tmp[256];
4627 char *dest = data;
4629 oldformat = format;
4630 format &= CAPABILITY;
4631 ast_log(LOG_NOTICE,
4632 "Asked to get a channel of format %s while capability is %d result : %s (%d) \n",
4633 ast_getformatname(oldformat), CAPABILITY, ast_getformatname(format), format);
4634 if (!format) {
4635 ast_log(LOG_NOTICE,
4636 "Asked to get a channel of unsupported format %s while capability is %s\n",
4637 ast_getformatname(oldformat), ast_getformatname(CAPABILITY));
4638 return NULL;
4641 ast_copy_string(tmp, dest, sizeof(tmp));
4642 if (ast_strlen_zero(tmp)) {
4643 ast_log(LOG_NOTICE, "Unistim channels require a device\n");
4644 return NULL;
4647 sub = find_subchannel_by_name(tmp);
4648 if (!sub) {
4649 ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
4650 *cause = AST_CAUSE_CONGESTION;
4651 return NULL;
4654 ast_verb(3, "unistim_request(%s)\n", tmp);
4655 /* Busy ? */
4656 if (sub->owner) {
4657 if (unistimdebug)
4658 ast_verb(0, "Can't create channel : Busy !\n");
4659 *cause = AST_CAUSE_BUSY;
4660 return NULL;
4662 sub->parent->capability = format;
4663 tmpc = unistim_new(sub, AST_STATE_DOWN);
4664 if (!tmpc)
4665 ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
4666 if (unistimdebug)
4667 ast_verb(0, "unistim_request owner = %p\n", sub->owner);
4668 restart_monitor();
4670 /* and finish */
4671 return tmpc;
4674 static char *unistim_info(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4676 struct unistim_device *device = devices;
4677 struct unistim_line *line;
4678 struct unistim_subchannel *sub;
4679 struct unistimsession *s;
4680 int i;
4681 struct ast_channel *tmp;
4683 switch (cmd) {
4684 case CLI_INIT:
4685 e->command = "unistim info";
4686 e->usage =
4687 "Usage: unistim info\n"
4688 " Dump internal structures.\n";
4689 return NULL;
4691 case CLI_GENERATE:
4692 return NULL; /* no completion */
4695 if (a->argc != e->args)
4696 return CLI_SHOWUSAGE;
4698 ast_cli(a->fd, "Dumping internal structures :\ndevice\n->line\n-->sub\n");
4699 while (device) {
4700 ast_cli(a->fd, "\nname=%s id=%s line=%p ha=%p sess=%p device=%p\n",
4701 device->name, device->id, device->lines, device->ha, device->session,
4702 device);
4703 line = device->lines;
4704 while (line) {
4705 ast_cli(a->fd,
4706 "->name=%s fullname=%s exten=%s callid=%s cap=%d device=%p line=%p\n",
4707 line->name, line->fullname, line->exten, line->cid_num,
4708 line->capability, line->parent, line);
4709 for (i = 0; i < MAX_SUBS; i++) {
4710 sub = line->subs[i];
4711 if (!sub)
4712 continue;
4713 if (!sub->owner)
4714 tmp = (void *) -42;
4715 else
4716 tmp = sub->owner->_bridge;
4717 if (sub->subtype != i)
4718 ast_cli(a->fd, "Warning ! subchannel->subs[%d] have a subtype=%d\n", i,
4719 sub->subtype);
4720 ast_cli(a->fd,
4721 "-->subtype=%d chan=%p rtp=%p bridge=%p line=%p alreadygone=%d\n",
4722 sub->subtype, sub->owner, sub->rtp, tmp, sub->parent,
4723 sub->alreadygone);
4725 line = line->next;
4727 device = device->next;
4729 ast_cli(a->fd, "\nSessions:\n");
4730 ast_mutex_lock(&sessionlock);
4731 s = sessions;
4732 while (s) {
4733 ast_cli(a->fd,
4734 "sin=%s timeout=%u state=%d macaddr=%s device=%p session=%p\n",
4735 ast_inet_ntoa(s->sin.sin_addr), s->timeout, s->state, s->macaddr,
4736 s->device, s);
4737 s = s->next;
4739 ast_mutex_unlock(&sessionlock);
4741 return CLI_SUCCESS;
4744 static char *unistim_sp(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4746 BUFFSEND;
4747 struct unistim_subchannel *sub;
4748 int i, j = 0, len;
4749 unsigned char c, cc;
4750 char tmp[256];
4752 switch (cmd) {
4753 case CLI_INIT:
4754 e->command = "unistim sp";
4755 e->usage =
4756 "Usage: unistim sp USTM/line@name hexa\n"
4757 " unistim sp USTM/1000@hans 19040004\n";
4758 return NULL;
4760 case CLI_GENERATE:
4761 return NULL; /* no completion */
4764 if (a->argc < 4)
4765 return CLI_SHOWUSAGE;
4767 if (strlen(a->argv[2]) < 9)
4768 return CLI_SHOWUSAGE;
4770 len = strlen(a->argv[3]);
4771 if (len % 2)
4772 return CLI_SHOWUSAGE;
4774 ast_copy_string(tmp, a->argv[2] + 5, sizeof(tmp));
4775 sub = find_subchannel_by_name(tmp);
4776 if (!sub) {
4777 ast_cli(a->fd, "Can't find '%s'\n", tmp);
4778 return CLI_SUCCESS;
4780 if (!sub->parent->parent->session) {
4781 ast_cli(a->fd, "'%s' is not connected\n", tmp);
4782 return CLI_SUCCESS;
4784 ast_cli(a->fd, "Sending '%s' to %s (%p)\n", a->argv[3], tmp, sub->parent->parent->session);
4785 for (i = 0; i < len; i++) {
4786 c = a->argv[3][i];
4787 if (c >= 'a')
4788 c -= 'a' - 10;
4789 else
4790 c -= '0';
4791 i++;
4792 cc = a->argv[3][i];
4793 if (cc >= 'a')
4794 cc -= 'a' - 10;
4795 else
4796 cc -= '0';
4797 tmp[j++] = (c << 4) | cc;
4799 memcpy(buffsend + SIZE_HEADER, tmp, j);
4800 send_client(SIZE_HEADER + j, buffsend, sub->parent->parent->session);
4801 return CLI_SUCCESS;
4804 static char *unistim_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4806 switch (cmd) {
4807 case CLI_INIT:
4808 e->command = "unistim set debug {on|off}";
4809 e->usage =
4810 "Usage: unistim set debug\n"
4811 " Display debug messages.\n";
4812 return NULL;
4814 case CLI_GENERATE:
4815 return NULL; /* no completion */
4818 if (a->argc != e->args)
4819 return CLI_SHOWUSAGE;
4821 if (!strcasecmp(a->argv[3], "on")) {
4822 unistimdebug = 1;
4823 ast_cli(a->fd, "UNISTIM Debugging Enabled\n");
4824 } else if (!strcasecmp(a->argv[3], "off")) {
4825 unistimdebug = 0;
4826 ast_cli(a->fd, "UNISTIM Debugging Disabled\n");
4827 } else
4828 return CLI_SHOWUSAGE;
4830 return CLI_SUCCESS;
4833 /*! \brief --- unistim_reload: Force reload of module from cli ---
4834 * Runs in the asterisk main thread, so don't do anything useful
4835 * but setting a flag and waiting for do_monitor to do the job
4836 * in our thread */
4837 static char *unistim_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4839 switch (cmd) {
4840 case CLI_INIT:
4841 e->command = "unistim reload";
4842 e->usage =
4843 "Usage: unistim reload\n"
4844 " Reloads UNISTIM configuration from unistim.conf\n";
4845 return NULL;
4847 case CLI_GENERATE:
4848 return NULL; /* no completion */
4851 if (e && a && a->argc != e->args)
4852 return CLI_SHOWUSAGE;
4854 if (unistimdebug)
4855 ast_verb(0, "reload unistim\n");
4857 ast_mutex_lock(&unistim_reload_lock);
4858 if (!unistim_reloading)
4859 unistim_reloading = 1;
4860 ast_mutex_unlock(&unistim_reload_lock);
4862 restart_monitor();
4864 return CLI_SUCCESS;
4867 static struct ast_cli_entry unistim_cli[] = {
4868 AST_CLI_DEFINE(unistim_reload, "Reload UNISTIM configuration"),
4869 AST_CLI_DEFINE(unistim_info, "Show UNISTIM info"),
4870 AST_CLI_DEFINE(unistim_sp, "Send packet (for reverse engineering)"),
4871 AST_CLI_DEFINE(unistim_do_debug, "Toggle UNITSTIM debugging"),
4874 static void unquote(char *out, const char *src, int maxlen)
4876 int len = strlen(src);
4877 if (!len)
4878 return;
4879 if ((len > 1) && src[0] == '\"') {
4880 /* This is a quoted string */
4881 src++;
4882 /* Don't take more than what's there */
4883 len--;
4884 if (maxlen > len - 1)
4885 maxlen = len - 1;
4886 memcpy(out, src, maxlen);
4887 ((char *) out)[maxlen] = '\0';
4888 } else
4889 memcpy(out, src, maxlen);
4890 return;
4893 static int ParseBookmark(const char *text, struct unistim_device *d)
4895 char line[256];
4896 char *at;
4897 char *number;
4898 char *icon;
4899 int p;
4900 int len = strlen(text);
4902 ast_copy_string(line, text, sizeof(line));
4903 /* Position specified ? */
4904 if ((len > 2) && (line[1] == '@')) {
4905 p = line[0];
4906 if ((p >= '0') && (p <= '5'))
4907 p -= '0';
4908 else {
4909 ast_log(LOG_WARNING,
4910 "Invalid position for bookmark : must be between 0 and 5\n");
4911 return 0;
4913 if (d->softkeyicon[p] != 0) {
4914 ast_log(LOG_WARNING, "Invalid position %d for bookmark : already used\n:", p);
4915 return 0;
4917 memmove(line, line + 2, sizeof(line));
4918 } else {
4919 /* No position specified, looking for a free slot */
4920 for (p = 0; p <= 5; p++) {
4921 if (!d->softkeyicon[p])
4922 break;
4924 if (p > 5) {
4925 ast_log(LOG_WARNING, "No more free bookmark position\n");
4926 return 0;
4929 at = strchr(line, '@');
4930 if (!at) {
4931 ast_log(LOG_NOTICE, "Bookmark entry '%s' has no @ (at) sign!\n", text);
4932 return 0;
4934 *at = '\0';
4935 at++;
4936 number = at;
4937 at = strchr(at, '@');
4938 if (ast_strlen_zero(number)) {
4939 ast_log(LOG_NOTICE, "Bookmark entry '%s' has no number\n", text);
4940 return 0;
4942 if (ast_strlen_zero(line)) {
4943 ast_log(LOG_NOTICE, "Bookmark entry '%s' has no description\n", text);
4944 return 0;
4947 at = strchr(number, '@');
4948 if (!at)
4949 d->softkeyicon[p] = FAV_ICON_SHARP; /* default icon */
4950 else {
4951 *at = '\0';
4952 at++;
4953 icon = at;
4954 if (ast_strlen_zero(icon)) {
4955 ast_log(LOG_NOTICE, "Bookmark entry '%s' has no icon value\n", text);
4956 return 0;
4958 if (strncmp(icon, "USTM/", 5))
4959 d->softkeyicon[p] = atoi(icon);
4960 else {
4961 d->softkeyicon[p] = 1;
4962 ast_copy_string(d->softkeydevice[p], icon + 5, sizeof(d->softkeydevice[p]));
4965 ast_copy_string(d->softkeylabel[p], line, sizeof(d->softkeylabel[p]));
4966 ast_copy_string(d->softkeynumber[p], number, sizeof(d->softkeynumber[p]));
4967 if (unistimdebug)
4968 ast_verb(0, "New bookmark at pos %d label='%s' number='%s' icon=%x\n",
4969 p, d->softkeylabel[p], d->softkeynumber[p], d->softkeyicon[p]);
4970 return 1;
4973 /* Looking for dynamic icons entries in bookmarks */
4974 static void finish_bookmark(void)
4976 struct unistim_device *d = devices;
4977 int i;
4978 while (d) {
4979 for (i = 0; i < 6; i++) {
4980 if (d->softkeyicon[i] == 1) { /* Something for us */
4981 struct unistim_device *d2 = devices;
4982 while (d2) {
4983 if (!strcmp(d->softkeydevice[i], d2->name)) {
4984 d->sp[i] = d2;
4985 d->softkeyicon[i] = 0;
4986 break;
4988 d2 = d2->next;
4990 if (d->sp[i] == NULL)
4991 ast_log(LOG_NOTICE, "Bookmark entry with device %s not found\n",
4992 d->softkeydevice[i]);
4995 d = d->next;
4999 static struct unistim_device *build_device(const char *cat, const struct ast_variable *v)
5001 struct unistim_device *d;
5002 struct unistim_line *l = NULL;
5003 int create = 1;
5004 int nbsoftkey, dateformat, timeformat, callhistory;
5005 char linelabel[AST_MAX_EXTENSION];
5006 char context[AST_MAX_EXTENSION];
5007 char ringvolume, ringstyle;
5009 /* First, we need to know if we already have this name in our list */
5010 /* Get a lock for the device chained list */
5011 ast_mutex_lock(&devicelock);
5012 d = devices;
5013 while (d) {
5014 if (!strcmp(d->name, cat)) {
5015 /* Yep, we alreay have this one */
5016 if (unistimsock < 0) {
5017 /* It's a dupe */
5018 ast_log(LOG_WARNING, "Duplicate entry found (%s), ignoring.\n", cat);
5019 ast_mutex_unlock(&devicelock);
5020 return NULL;
5022 /* we're reloading right now */
5023 create = 0;
5024 l = d->lines;
5025 break;
5027 d = d->next;
5029 ast_mutex_unlock(&devicelock);
5030 if (create) {
5031 if (!(d = ast_calloc(1, sizeof(*d))))
5032 return NULL;
5034 if (!(l = ast_calloc(1, sizeof(*l)))) {
5035 ast_free(d);
5036 return NULL;
5038 ast_copy_string(d->name, cat, sizeof(d->name));
5040 ast_copy_string(context, DEFAULTCONTEXT, sizeof(context));
5041 d->contrast = -1;
5042 d->output = OUTPUT_HANDSET;
5043 d->previous_output = OUTPUT_HANDSET;
5044 d->volume = VOLUME_LOW;
5045 d->mute = MUTE_OFF;
5046 linelabel[0] = '\0';
5047 dateformat = 1;
5048 timeformat = 1;
5049 ringvolume = 2;
5050 callhistory = 1;
5051 ringstyle = 3;
5052 nbsoftkey = 0;
5053 while (v) {
5054 if (!strcasecmp(v->name, "rtp_port"))
5055 d->rtp_port = atoi(v->value);
5056 else if (!strcasecmp(v->name, "rtp_method"))
5057 d->rtp_method = atoi(v->value);
5058 else if (!strcasecmp(v->name, "status_method"))
5059 d->status_method = atoi(v->value);
5060 else if (!strcasecmp(v->name, "device"))
5061 ast_copy_string(d->id, v->value, sizeof(d->id));
5062 else if (!strcasecmp(v->name, "tn"))
5063 ast_copy_string(d->extension_number, v->value, sizeof(d->extension_number));
5064 else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny"))
5065 d->ha = ast_append_ha(v->name, v->value, d->ha, NULL);
5066 else if (!strcasecmp(v->name, "context"))
5067 ast_copy_string(context, v->value, sizeof(context));
5068 else if (!strcasecmp(v->name, "maintext0"))
5069 unquote(d->maintext0, v->value, sizeof(d->maintext0) - 1);
5070 else if (!strcasecmp(v->name, "maintext1"))
5071 unquote(d->maintext1, v->value, sizeof(d->maintext1) - 1);
5072 else if (!strcasecmp(v->name, "maintext2"))
5073 unquote(d->maintext2, v->value, sizeof(d->maintext2) - 1);
5074 else if (!strcasecmp(v->name, "titledefault"))
5075 unquote(d->titledefault, v->value, sizeof(d->titledefault) - 1);
5076 else if (!strcasecmp(v->name, "dateformat"))
5077 dateformat = atoi(v->value);
5078 else if (!strcasecmp(v->name, "timeformat"))
5079 timeformat = atoi(v->value);
5080 else if (!strcasecmp(v->name, "contrast")) {
5081 d->contrast = atoi(v->value);
5082 if ((d->contrast < 0) || (d->contrast > 15)) {
5083 ast_log(LOG_WARNING, "constrast must be beetween 0 and 15");
5084 d->contrast = 8;
5086 } else if (!strcasecmp(v->name, "nat"))
5087 d->nat = ast_true(v->value);
5088 else if (!strcasecmp(v->name, "ringvolume"))
5089 ringvolume = atoi(v->value);
5090 else if (!strcasecmp(v->name, "ringstyle"))
5091 ringstyle = atoi(v->value);
5092 else if (!strcasecmp(v->name, "callhistory"))
5093 callhistory = atoi(v->value);
5094 else if (!strcasecmp(v->name, "callerid")) {
5095 if (!strcasecmp(v->value, "asreceived"))
5096 l->cid_num[0] = '\0';
5097 else
5098 ast_copy_string(l->cid_num, v->value, sizeof(l->cid_num));
5099 } else if (!strcasecmp(v->name, "language"))
5100 ast_copy_string(l->language, v->value, sizeof(l->language));
5101 else if (!strcasecmp(v->name, "country"))
5102 ast_copy_string(d->country, v->value, sizeof(d->country));
5103 else if (!strcasecmp(v->name, "accountcode"))
5104 ast_copy_string(l->accountcode, v->value, sizeof(l->accountcode));
5105 else if (!strcasecmp(v->name, "amaflags")) {
5106 int y;
5107 y = ast_cdr_amaflags2int(v->value);
5108 if (y < 0)
5109 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value,
5110 v->lineno);
5111 else
5112 l->amaflags = y;
5113 } else if (!strcasecmp(v->name, "musiconhold"))
5114 ast_copy_string(l->musicclass, v->value, sizeof(l->musicclass));
5115 else if (!strcasecmp(v->name, "callgroup"))
5116 l->callgroup = ast_get_group(v->value);
5117 else if (!strcasecmp(v->name, "pickupgroup"))
5118 l->pickupgroup = ast_get_group(v->value);
5119 else if (!strcasecmp(v->name, "mailbox"))
5120 ast_copy_string(l->mailbox, v->value, sizeof(l->mailbox));
5121 else if (!strcasecmp(v->name, "parkinglot"))
5122 ast_copy_string(l->parkinglot, v->value, sizeof(l->parkinglot));
5123 else if (!strcasecmp(v->name, "linelabel"))
5124 unquote(linelabel, v->value, sizeof(linelabel) - 1);
5125 else if (!strcasecmp(v->name, "extension")) {
5126 if (!strcasecmp(v->value, "none"))
5127 d->extension = EXTENSION_NONE;
5128 else if (!strcasecmp(v->value, "ask"))
5129 d->extension = EXTENSION_ASK;
5130 else if (!strcasecmp(v->value, "line"))
5131 d->extension = EXTENSION_LINE;
5132 else
5133 ast_log(LOG_WARNING, "Unknown extension option.\n");
5134 } else if (!strcasecmp(v->name, "bookmark")) {
5135 if (nbsoftkey > 5)
5136 ast_log(LOG_WARNING,
5137 "More than 6 softkeys defined. Ignoring new entries.\n");
5138 else {
5139 if (ParseBookmark(v->value, d))
5140 nbsoftkey++;
5142 } else if (!strcasecmp(v->name, "line")) {
5143 int len = strlen(linelabel);
5145 if (nbsoftkey) {
5146 ast_log(LOG_WARNING,
5147 "You must use bookmark AFTER line=>. Only one line is supported in this version\n");
5148 if (create) {
5149 ast_free(d);
5150 ast_free(l);
5152 return NULL;
5154 if (create) {
5155 ast_mutex_init(&l->lock);
5156 } else {
5157 d->to_delete = 0;
5158 /* reset bookmarks */
5159 memset(d->softkeylabel, 0, sizeof(d->softkeylabel));
5160 memset(d->softkeynumber, 0, sizeof(d->softkeynumber));
5161 memset(d->softkeyicon, 0, sizeof(d->softkeyicon));
5162 memset(d->softkeydevice, 0, sizeof(d->softkeydevice));
5163 memset(d->sp, 0, sizeof(d->sp));
5165 ast_copy_string(l->name, v->value, sizeof(l->name));
5166 snprintf(l->fullname, sizeof(l->fullname), "USTM/%s@%s", l->name, d->name);
5167 d->softkeyicon[0] = FAV_ICON_ONHOOK_BLACK;
5168 if (!len) /* label is undefined ? */
5169 ast_copy_string(d->softkeylabel[0], v->value, sizeof(d->softkeylabel[0]));
5170 else {
5171 if ((len > 2) && (linelabel[1] == '@')) {
5172 d->softkeylinepos = linelabel[0];
5173 if ((d->softkeylinepos >= '0') && (d->softkeylinepos <= '5')) {
5174 d->softkeylinepos -= '0';
5175 d->softkeyicon[0] = 0;
5176 } else {
5177 ast_log(LOG_WARNING,
5178 "Invalid position for linelabel : must be between 0 and 5\n");
5179 d->softkeylinepos = 0;
5181 ast_copy_string(d->softkeylabel[d->softkeylinepos], linelabel + 2,
5182 sizeof(d->softkeylabel[d->softkeylinepos]));
5183 d->softkeyicon[d->softkeylinepos] = FAV_ICON_ONHOOK_BLACK;
5184 } else
5185 ast_copy_string(d->softkeylabel[0], linelabel,
5186 sizeof(d->softkeylabel[0]));
5188 nbsoftkey++;
5189 ast_copy_string(l->context, context, sizeof(l->context));
5190 if (!ast_strlen_zero(l->mailbox)) {
5191 if (unistimdebug)
5192 ast_verb(3, "Setting mailbox '%s' on %s@%s\n", l->mailbox, d->name, l->name);
5195 l->capability = CAPABILITY;
5196 l->parent = d;
5198 if (create) {
5199 if (!alloc_sub(l, SUB_REAL)) {
5200 ast_mutex_destroy(&l->lock);
5201 ast_free(l);
5202 ast_free(d);
5203 return NULL;
5205 l->next = d->lines;
5206 d->lines = l;
5208 } else
5209 ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name,
5210 v->lineno);
5211 v = v->next;
5213 d->ringvolume = ringvolume;
5214 d->ringstyle = ringstyle;
5215 d->callhistory = callhistory;
5216 d->tz = ast_get_indication_zone(d->country);
5217 if ((d->tz == NULL) && !ast_strlen_zero(d->country))
5218 ast_log(LOG_WARNING, "Country '%s' was not found in indications.conf\n",
5219 d->country);
5220 d->datetimeformat = 56 + (dateformat * 4);
5221 d->datetimeformat += timeformat;
5222 if (!d->lines) {
5223 ast_log(LOG_ERROR, "An Unistim device must have at least one line!\n");
5224 ast_mutex_destroy(&l->lock);
5225 ast_free(l);
5226 ast_free(d);
5227 return NULL;
5229 if ((autoprovisioning == AUTOPROVISIONING_TN) &&
5230 (!ast_strlen_zero(d->extension_number))) {
5231 d->extension = EXTENSION_TN;
5232 if (!ast_strlen_zero(d->id))
5233 ast_log(LOG_WARNING,
5234 "tn= and device= can't be used together. Ignoring device= entry\n");
5235 d->id[0] = 'T'; /* magic : this is a tn entry */
5236 ast_copy_string((d->id) + 1, d->extension_number, sizeof(d->id) - 1);
5237 d->extension_number[0] = '\0';
5238 } else if (ast_strlen_zero(d->id)) {
5239 if (strcmp(d->name, "template")) {
5240 ast_log(LOG_ERROR, "You must specify the mac address with device=\n");
5241 ast_mutex_destroy(&l->lock);
5242 ast_free(l);
5243 ast_free(d);
5244 return NULL;
5245 } else
5246 strcpy(d->id, "000000000000");
5248 if (!d->rtp_port)
5249 d->rtp_port = 10000;
5250 if (d->contrast == -1)
5251 d->contrast = 8;
5252 if (ast_strlen_zero(d->maintext0))
5253 strcpy(d->maintext0, "Welcome");
5254 if (ast_strlen_zero(d->maintext1))
5255 strcpy(d->maintext1, d->name);
5256 if (ast_strlen_zero(d->titledefault)) {
5257 struct ast_tm tm = { 0, };
5258 struct timeval cur_time = ast_tvnow();
5260 if ((ast_localtime(&cur_time, &tm, 0)) == 0 || ast_strlen_zero(tm.tm_zone)) {
5261 display_last_error("Error in ast_localtime()");
5262 ast_copy_string(d->titledefault, "UNISTIM for*", 12);
5263 } else {
5264 if (strlen(tm.tm_zone) < 4) {
5265 strcpy(d->titledefault, "TimeZone ");
5266 strcat(d->titledefault, tm.tm_zone);
5267 } else if (strlen(tm.tm_zone) < 9) {
5268 strcpy(d->titledefault, "TZ ");
5269 strcat(d->titledefault, tm.tm_zone);
5270 } else
5271 ast_copy_string(d->titledefault, tm.tm_zone, 12);
5274 /* Update the chained link if it's a new device */
5275 if (create) {
5276 ast_mutex_lock(&devicelock);
5277 d->next = devices;
5278 devices = d;
5279 ast_mutex_unlock(&devicelock);
5280 ast_verb(3, "Added device '%s'\n", d->name);
5281 } else {
5282 ast_verb(3, "Device '%s' reloaded\n", d->name);
5284 return d;
5287 /*--- reload_config: Re-read unistim.conf config file ---*/
5288 static int reload_config(void)
5290 struct ast_config *cfg;
5291 struct ast_variable *v;
5292 struct ast_hostent ahp;
5293 struct hostent *hp;
5294 struct sockaddr_in bindaddr = { 0, };
5295 char *config = "unistim.conf";
5296 char *cat;
5297 struct unistim_device *d;
5298 const int reuseFlag = 1;
5299 struct unistimsession *s;
5300 struct ast_flags config_flags = { 0, };
5302 cfg = ast_config_load(config, config_flags);
5303 /* We *must* have a config file otherwise stop immediately */
5304 if (!cfg) {
5305 ast_log(LOG_ERROR, "Unable to load config %s\n", config);
5306 return -1;
5309 /* Copy the default jb config over global_jbconf */
5310 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
5312 unistim_keepalive = 120;
5313 unistim_port = 0;
5314 v = ast_variable_browse(cfg, "general");
5315 while (v) {
5316 /* handle jb conf */
5317 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
5318 continue;
5320 if (!strcasecmp(v->name, "keepalive"))
5321 unistim_keepalive = atoi(v->value);
5322 else if (!strcasecmp(v->name, "port"))
5323 unistim_port = atoi(v->value);
5324 else if (!strcasecmp(v->name, "tos")) {
5325 if (ast_str2tos(v->value, &qos.tos))
5326 ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
5327 } else if (!strcasecmp(v->name, "tos_audio")) {
5328 if (ast_str2tos(v->value, &qos.tos_audio))
5329 ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
5330 } else if (!strcasecmp(v->name, "cos")) {
5331 if (ast_str2cos(v->value, &qos.cos))
5332 ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
5333 } else if (!strcasecmp(v->name, "cos_audio")) {
5334 if (ast_str2cos(v->value, &qos.cos_audio))
5335 ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
5336 } else if (!strcasecmp(v->name, "autoprovisioning")) {
5337 if (!strcasecmp(v->value, "no"))
5338 autoprovisioning = AUTOPROVISIONING_NO;
5339 else if (!strcasecmp(v->value, "yes"))
5340 autoprovisioning = AUTOPROVISIONING_YES;
5341 else if (!strcasecmp(v->value, "db"))
5342 autoprovisioning = AUTOPROVISIONING_DB;
5343 else if (!strcasecmp(v->value, "tn"))
5344 autoprovisioning = AUTOPROVISIONING_TN;
5345 else
5346 ast_log(LOG_WARNING, "Unknown autoprovisioning option.\n");
5347 } else if (!strcasecmp(v->name, "public_ip")) {
5348 if (!ast_strlen_zero(v->value)) {
5349 if (!(hp = ast_gethostbyname(v->value, &ahp)))
5350 ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
5351 else {
5352 memcpy(&public_ip.sin_addr, hp->h_addr, sizeof(public_ip.sin_addr));
5353 public_ip.sin_family = AF_INET;
5357 v = v->next;
5359 if ((unistim_keepalive < 10) ||
5360 (unistim_keepalive >
5361 255 - (((NB_MAX_RETRANSMIT + 1) * RETRANSMIT_TIMER) / 1000))) {
5362 ast_log(LOG_ERROR, "keepalive is invalid in %s\n", config);
5363 ast_config_destroy(cfg);
5364 return -1;
5366 packet_send_ping[4] =
5367 unistim_keepalive + (((NB_MAX_RETRANSMIT + 1) * RETRANSMIT_TIMER) / 1000);
5368 if ((unistim_port < 1) || (unistim_port > 65535)) {
5369 ast_log(LOG_ERROR, "port is not set or invalid in %s\n", config);
5370 ast_config_destroy(cfg);
5371 return -1;
5373 unistim_keepalive *= 1000;
5375 ast_mutex_lock(&devicelock);
5376 d = devices;
5377 while (d) {
5378 if (d->to_delete >= 0)
5379 d->to_delete = 1;
5380 d = d->next;
5382 ast_mutex_unlock(&devicelock);
5383 /* load the device sections */
5384 cat = ast_category_browse(cfg, NULL);
5385 while (cat) {
5386 if (strcasecmp(cat, "general")) {
5387 d = build_device(cat, ast_variable_browse(cfg, cat));
5389 cat = ast_category_browse(cfg, cat);
5391 ast_mutex_lock(&devicelock);
5392 d = devices;
5393 while (d) {
5394 if (d->to_delete) {
5395 int i;
5397 if (unistimdebug)
5398 ast_verb(0, "Removing device '%s'\n", d->name);
5399 if (!d->lines) {
5400 ast_log(LOG_ERROR, "Device '%s' without a line !, aborting\n", d->name);
5401 ast_config_destroy(cfg);
5402 return 0;
5404 if (!d->lines->subs[0]) {
5405 ast_log(LOG_ERROR, "Device '%s' without a subchannel !, aborting\n",
5406 d->name);
5407 ast_config_destroy(cfg);
5408 return 0;
5410 if (d->lines->subs[0]->owner) {
5411 ast_log(LOG_WARNING,
5412 "Device '%s' was not deleted : a call is in progress. Try again later.\n",
5413 d->name);
5414 d = d->next;
5415 continue;
5417 ast_mutex_destroy(&d->lines->subs[0]->lock);
5418 ast_free(d->lines->subs[0]);
5419 for (i = 1; i < MAX_SUBS; i++) {
5420 if (d->lines->subs[i]) {
5421 ast_log(LOG_WARNING,
5422 "Device '%s' with threeway call subchannels allocated, aborting.\n",
5423 d->name);
5424 break;
5427 if (i < MAX_SUBS) {
5428 d = d->next;
5429 continue;
5431 ast_mutex_destroy(&d->lines->lock);
5432 ast_free(d->lines);
5433 if (d->session) {
5434 if (sessions == d->session)
5435 sessions = d->session->next;
5436 else {
5437 s = sessions;
5438 while (s) {
5439 if (s->next == d->session) {
5440 s->next = d->session->next;
5441 break;
5443 s = s->next;
5446 ast_mutex_destroy(&d->session->lock);
5447 ast_free(d->session);
5449 if (devices == d)
5450 devices = d->next;
5451 else {
5452 struct unistim_device *d2 = devices;
5453 while (d2) {
5454 if (d2->next == d) {
5455 d2->next = d->next;
5456 break;
5458 d2 = d2->next;
5461 ast_free(d);
5462 d = devices;
5463 continue;
5465 d = d->next;
5467 finish_bookmark();
5468 ast_mutex_unlock(&devicelock);
5469 ast_config_destroy(cfg);
5470 ast_mutex_lock(&sessionlock);
5471 s = sessions;
5472 while (s) {
5473 if (s->device)
5474 refresh_all_favorite(s);
5475 s = s->next;
5477 ast_mutex_unlock(&sessionlock);
5478 /* We don't recreate a socket when reloading (locks would be necessary). */
5479 if (unistimsock > -1)
5480 return 0;
5481 bindaddr.sin_addr.s_addr = INADDR_ANY;
5482 bindaddr.sin_port = htons(unistim_port);
5483 bindaddr.sin_family = AF_INET;
5484 unistimsock = socket(AF_INET, SOCK_DGRAM, 0);
5485 if (unistimsock < 0) {
5486 ast_log(LOG_WARNING, "Unable to create UNISTIM socket: %s\n", strerror(errno));
5487 return -1;
5489 #ifdef HAVE_PKTINFO
5491 const int pktinfoFlag = 1;
5492 setsockopt(unistimsock, IPPROTO_IP, IP_PKTINFO, &pktinfoFlag,
5493 sizeof(pktinfoFlag));
5495 #else
5496 if (public_ip.sin_family == 0) {
5497 ast_log(LOG_WARNING,
5498 "Your OS does not support IP_PKTINFO, you must set public_ip.\n");
5499 unistimsock = -1;
5500 return -1;
5502 #endif
5503 setsockopt(unistimsock, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuseFlag,
5504 sizeof(reuseFlag));
5505 if (bind(unistimsock, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) < 0) {
5506 ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
5507 ast_inet_ntoa(bindaddr.sin_addr), htons(bindaddr.sin_port),
5508 strerror(errno));
5509 close(unistimsock);
5510 unistimsock = -1;
5511 } else {
5512 ast_verb(2, "UNISTIM Listening on %s:%d\n", ast_inet_ntoa(bindaddr.sin_addr), htons(bindaddr.sin_port));
5513 ast_netsock_set_qos(unistimsock, qos.tos, qos.cos, "UNISTIM");
5515 return 0;
5518 static enum ast_rtp_get_result unistim_get_vrtp_peer(struct ast_channel *chan,
5519 struct ast_rtp **rtp)
5521 return AST_RTP_TRY_NATIVE;
5524 static enum ast_rtp_get_result unistim_get_rtp_peer(struct ast_channel *chan,
5525 struct ast_rtp **rtp)
5527 struct unistim_subchannel *sub;
5528 enum ast_rtp_get_result res = AST_RTP_GET_FAILED;
5530 if (unistimdebug)
5531 ast_verb(0, "unistim_get_rtp_peer called\n");
5533 sub = chan->tech_pvt;
5534 if (sub && sub->rtp) {
5535 *rtp = sub->rtp;
5536 res = AST_RTP_TRY_NATIVE;
5539 return res;
5542 static int unistim_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
5543 struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
5545 struct unistim_subchannel *sub;
5547 if (unistimdebug)
5548 ast_verb(0, "unistim_set_rtp_peer called\n");
5550 sub = chan->tech_pvt;
5552 if (sub)
5553 return 0;
5555 return -1;
5558 static struct ast_rtp_protocol unistim_rtp = {
5559 .type = channel_type,
5560 .get_rtp_info = unistim_get_rtp_peer,
5561 .get_vrtp_info = unistim_get_vrtp_peer,
5562 .set_rtp_peer = unistim_set_rtp_peer,
5565 /*--- load_module: PBX load module - initialization ---*/
5566 int load_module(void)
5568 int res;
5570 if (!(buff = ast_malloc(SIZE_PAGE)))
5571 goto buff_failed;
5573 io = io_context_create();
5574 if (!io) {
5575 ast_log(LOG_ERROR, "Failed to allocate IO context\n");
5576 goto io_failed;
5579 sched = sched_context_create();
5580 if (!sched) {
5581 ast_log(LOG_ERROR, "Failed to allocate scheduler context\n");
5582 goto sched_failed;
5585 res = reload_config();
5586 if (res)
5587 return AST_MODULE_LOAD_DECLINE;
5589 /* Make sure we can register our unistim channel type */
5590 if (ast_channel_register(&unistim_tech)) {
5591 ast_log(LOG_ERROR, "Unable to register channel type '%s'\n", channel_type);
5592 goto chanreg_failed;
5595 ast_rtp_proto_register(&unistim_rtp);
5597 ast_cli_register_multiple(unistim_cli, ARRAY_LEN(unistim_cli));
5599 restart_monitor();
5601 return AST_MODULE_LOAD_SUCCESS;
5603 chanreg_failed:
5604 /*! XXX \todo Leaking anything allocated by reload_config() ... */
5605 sched_context_destroy(sched);
5606 sched = NULL;
5607 sched_failed:
5608 io_context_destroy(io);
5609 io = NULL;
5610 io_failed:
5611 ast_free(buff);
5612 buff = NULL;
5613 buff_failed:
5614 return AST_MODULE_LOAD_FAILURE;
5617 static int unload_module(void)
5619 /* First, take us out of the channel loop */
5620 if (sched)
5621 sched_context_destroy(sched);
5623 ast_cli_unregister_multiple(unistim_cli, ARRAY_LEN(unistim_cli));
5625 ast_channel_unregister(&unistim_tech);
5626 ast_rtp_proto_unregister(&unistim_rtp);
5628 ast_mutex_lock(&monlock);
5629 if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
5630 pthread_cancel(monitor_thread);
5631 pthread_kill(monitor_thread, SIGURG);
5632 pthread_join(monitor_thread, NULL);
5634 monitor_thread = AST_PTHREADT_STOP;
5635 ast_mutex_unlock(&monlock);
5637 if (buff)
5638 ast_free(buff);
5639 if (unistimsock > -1)
5640 close(unistimsock);
5642 return 0;
5645 /*! reload: Part of Asterisk module interface ---*/
5646 int reload(void)
5648 unistim_reload(NULL, 0, NULL);
5649 return 0;
5652 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "UNISTIM Protocol (USTM)",
5653 .load = load_module,
5654 .unload = unload_module,
5655 .reload = reload,