Asterisk - The Open Source Telephony Project GIT-master-0034c23
chan_unistim.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * UNISTIM channel driver for asterisk
5 *
6 * Copyright (C) 2005 - 2007, Cedric Hans
7 *
8 * Cedric Hans <cedric.hans@mlkj.net>
9 *
10 * Asterisk 1.4 patch by Peter Be
11 *
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.
17 *
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.
21 */
22
23/*!
24 * \file
25 *
26 * \brief chan_unistim channel driver for Asterisk
27 * \author Cedric Hans <cedric.hans@mlkj.net>
28 *
29 * Unistim (Unified Networks IP Stimulus) channel driver
30 * for Nortel i2002, i2004 and i2050
31 *
32 * \ingroup channel_drivers
33 */
34
35/*** MODULEINFO
36 <support_level>extended</support_level>
37 ***/
38
39#include "asterisk.h"
40
41#include <sys/stat.h>
42#include <signal.h>
43
44#if defined(__CYGWIN__) || defined(__NetBSD__)
45/*
46 * cygwin headers are partly inconsistent. struct iovec is defined in sys/uio.h
47 * which is not included by default by sys/socket.h - in_pktinfo is defined in
48 * w32api/ws2tcpip.h but this probably has compatibility problems with sys/socket.h
49 * So for the time being we simply disable HAVE_PKTINFO when building under cygwin.
50 * This should be done in some common header, but for now this is the only file
51 * using iovec and in_pktinfo so it suffices to apply the fix here.
52 */
53#ifdef HAVE_PKTINFO
54#undef HAVE_PKTINFO
55#endif
56#endif /* __CYGWIN__ || __NetBSD__ */
57
58#include "asterisk/paths.h" /* ast_config_AST_LOG_DIR used in (too ?) many places */
59#include "asterisk/network.h"
60#include "asterisk/channel.h"
61#include "asterisk/config.h"
62#include "asterisk/module.h"
63#include "asterisk/pbx.h"
64#include "asterisk/rtp_engine.h"
65#include "asterisk/unaligned.h"
66#include "asterisk/netsock2.h"
67#include "asterisk/acl.h"
68#include "asterisk/callerid.h"
69#include "asterisk/cli.h"
70#include "asterisk/app.h"
71#include "asterisk/mwi.h"
73#include "asterisk/causes.h"
75#include "asterisk/pickup.h"
76#include "asterisk/astobj2.h"
77#include "asterisk/astdb.h"
79#include "asterisk/bridge.h"
82
83#define DEFAULTCONTEXT "default"
84#define DEFAULTCALLERID "Unknown"
85#define DEFAULTCALLERNAME " "
86#define DEFAULTHEIGHT 3
87#define USTM_LOG_DIR "unistimHistory"
88#define USTM_LANG_DIR "unistimLang"
89
90/*! Size of the transmit buffer */
91#define MAX_BUF_SIZE 64
92/*! Number of slots for the transmit queue */
93#define MAX_BUF_NUMBER 150
94/*! Number of digits displayed on screen */
95#define MAX_SCREEN_NUMBER 15
96/*! Length of month label size */
97#define MONTH_LABEL_SIZE 3
98/*! Try x times before removing the phone */
99#define NB_MAX_RETRANSMIT 8
100/*! Nb of milliseconds waited when no events are scheduled */
101#define IDLE_WAIT 1000
102/*! Wait x milliseconds before resending a packet */
103#define RETRANSMIT_TIMER 2000
104/*! How often the mailbox is checked for new messages */
105#define TIMER_MWI 5000
106/*! Timeout value for entered number being dialed */
107#define DEFAULT_INTERDIGIT_TIMER 4000
108
109/*! Not used */
110#define DEFAULT_CODEC 0x00
111#define SIZE_PAGE 4096
112#define DEVICE_NAME_LEN 16
113#define AST_CONFIG_MAX_PATH 255
114#define MAX_ENTRY_LOG 30
115
116#define SUB_REAL 0
117#define SUB_RING 1
118#define SUB_THREEWAY 2
119
121
127
129 /*! Do not create an extension into the default dialplan */
131 /*! Prompt user for an extension number and register it */
133 /*! Register an extension with the line=> value */
135 /*! Used with AUTOPROVISIONING_TN */
138#define OUTPUT_HANDSET 0xC0
139#define OUTPUT_HEADPHONE 0xC1
140#define OUTPUT_SPEAKER 0xC2
141
142#define VOLUME_LOW 0x01
143#define VOLUME_LOW_SPEAKER 0x03
144#define VOLUME_NORMAL 0x02
145#define VOLUME_INSANELY_LOUD 0x07
146
147#define MUTE_OFF 0x00
148#define MUTE_ON 0xFF
149#define MUTE_ON_DISCRET 0xCE
150
151#define LED_BAR_OFF 0x00 /* bar off */
152#define LED_BAR_ON 0x01 /* bar on */
153#define LED_BAR_P2 0x02 /* bar 1s on/1s */
154#define LED_BAR_P3 0x03 /* bar 2.5s on/0.5s off */
155#define LED_BAR_P4 0x04 /* bar 0.6s on/0.3s off */
156#define LED_BAR_P5 0x05 /* bar 0.5s on/0.5s off */
157#define LED_BAR_P6 0x06 /* bar 2s on/0.5s off */
158#define LED_BAR_P7 0x07 /* bar off */
159#define LED_SPEAKER_OFF 0x08
160#define LED_SPEAKER_ON 0x09
161#define LED_HEADPHONE_OFF 0x010
162#define LED_HEADPHONE_ON 0x011
163#define LED_MUTE_OFF 0x018
164#define LED_MUTE_ON 0x019
165#define LED_MUTE_BLINK 0x1A
166
167#define SIZE_HEADER 6
168#define SIZE_MAC_ADDR 17
169#define TEXT_LENGTH_MAX 24
170#define TEXT_LINE0 0x00
171#define TEXT_LINE1 0x20
172#define TEXT_LINE2 0x40
173#define TEXT_NORMAL 0x05
174#define TEXT_INVERSE 0x25
175#define STATUS_LENGTH_MAX 28
176
177#define FAV_ICON_NONE 0x00
178#define FAV_ICON_ONHOOK_BLACK 0x20
179#define FAV_ICON_ONHOOK_WHITE 0x21
180#define FAV_ICON_SPEAKER_ONHOOK_BLACK 0x22
181#define FAV_ICON_SPEAKER_ONHOOK_WHITE 0x23
182#define FAV_ICON_OFFHOOK_BLACK 0x24
183#define FAV_ICON_OFFHOOK_WHITE 0x25
184#define FAV_ICON_ONHOLD_BLACK 0x26
185#define FAV_ICON_ONHOLD_WHITE 0x27
186#define FAV_ICON_SPEAKER_OFFHOOK_BLACK 0x28
187#define FAV_ICON_SPEAKER_OFFHOOK_WHITE 0x29
188#define FAV_ICON_PHONE_BLACK 0x2A
189#define FAV_ICON_PHONE_WHITE 0x2B
190#define FAV_ICON_SPEAKER_ONHOLD_BLACK 0x2C
191#define FAV_ICON_SPEAKER_ONHOLD_WHITE 0x2D
192#define FAV_ICON_HEADPHONES 0x2E
193#define FAV_ICON_HEADPHONES_ONHOLD 0x2F
194#define FAV_ICON_HOME 0x30
195#define FAV_ICON_CITY 0x31
196#define FAV_ICON_SHARP 0x32
197#define FAV_ICON_PAGER 0x33
198#define FAV_ICON_CALL_CENTER 0x34
199#define FAV_ICON_FAX 0x35
200#define FAV_ICON_MAILBOX 0x36
201#define FAV_ICON_REFLECT 0x37
202#define FAV_ICON_COMPUTER 0x38
203#define FAV_ICON_FORWARD 0x39
204#define FAV_ICON_LOCKED 0x3A
205#define FAV_ICON_TRASH 0x3B
206#define FAV_ICON_INBOX 0x3C
207#define FAV_ICON_OUTBOX 0x3D
208#define FAV_ICON_MEETING 0x3E
209#define FAV_ICON_BOX 0x3F
210
211#define FAV_BLINK_FAST 0x20
212#define FAV_BLINK_SLOW 0x40
213
214#define FAV_MAX_LENGTH 0x0A
215
216#define FAVNUM 6
217#define EXPNUM 24
218#define FAV_LINE_ICON FAV_ICON_ONHOOK_BLACK
219
220static void dummy(char *unused, ...)
221{
222 return;
223}
224
225/*! \brief Global jitterbuffer configuration - by default, jb is disabled
226 * \note Values shown here match the defaults shown in unistim.conf.sample */
228{
229 .flags = 0,
230 .max_size = 200,
231 .resync_threshold = 1000,
232 .impl = "fixed",
233 .target_extra = 40,
234};
236
237
238/* #define DUMP_PACKET 1 */
239/* #define DEBUG_TIMER ast_verbose */
240
241#define DEBUG_TIMER dummy
242/*! Enable verbose output. can also be set with the CLI */
243static int unistimdebug = 0;
244static int unistim_port;
247static int unistimsock = -1;
248
249static struct {
250 unsigned int tos;
251 unsigned int tos_audio;
252 unsigned int cos;
253 unsigned int cos_audio;
254} qos = { 0, 0, 0, 0 };
255
256static struct io_context *io;
258static struct sockaddr_in public_ip = { 0, };
259static unsigned char *buff; /*! Receive buffer address */
260static int unistim_reloading = 0;
262
263/*! This is the thread for the monitor which checks for input on the channels
264 * which are not currently in use. */
266
267/*! Protect the monitoring thread, so only one process can kill or start it, and not
268 * when it's doing something critical. */
270/*! Protect the session list */
272/*! Protect the device list */
274
289
293};
294
296 KEY_0 = 0x40,
297 KEY_1 = 0x41,
298 KEY_2 = 0x42,
299 KEY_3 = 0x43,
300 KEY_4 = 0x44,
301 KEY_5 = 0x45,
302 KEY_6 = 0x46,
303 KEY_7 = 0x47,
304 KEY_8 = 0x48,
305 KEY_9 = 0x49,
306 KEY_STAR = 0x4a,
307 KEY_SHARP = 0x4b,
308 KEY_UP = 0x4c,
309 KEY_DOWN = 0x4d,
310 KEY_RIGHT = 0x4e,
311 KEY_LEFT = 0x4f,
312 KEY_QUIT = 0x50,
313 KEY_COPY = 0x51,
314 KEY_FUNC1 = 0x54,
315 KEY_FUNC2 = 0x55,
316 KEY_FUNC3 = 0x56,
317 KEY_FUNC4 = 0x57,
320 KEY_MUTE = 0x5d,
323 KEY_FAV0 = 0x60,
324 KEY_FAV1 = 0x61,
325 KEY_FAV2 = 0x62,
326 KEY_FAV3 = 0x63,
327 KEY_FAV4 = 0x64,
328 KEY_FAV5 = 0x65,
330 KEY_CONF = 0x7c,
333 KEY_INDEX = 0x7f
335
343};
344
345static const int dtmf_row[] = { 697, 770, 852, 941 };
346static const float dtmf_col[] = { 1209, 1336, 1477, 1633 };
347
348struct wsabuf {
349 u_long len;
350 unsigned char *buf;
351};
352
355 unsigned int subtype; /*! SUB_REAL, SUB_RING or SUB_THREEWAY */
356 struct ast_channel *owner; /*! Asterisk channel used by the subchannel */
357 struct unistim_line *parent; /*! Unistim line */
358 struct ast_rtp_instance *rtp; /*! RTP handle */
359 int softkey; /*! Softkey assigned */
360 pthread_t ss_thread; /*! unistim_ss thread handle */
362 int holding; /*! this subchannel holds someone */
363 signed char ringvolume;
364 signed char ringstyle;
365 int moh; /*!< Music on hold in progress */
367};
368
369/*!
370 * \todo Convert to stringfields
371 */
374 char name[80]; /*! Like 200 */
375 char fullname[101]; /*! Like USTM/200\@black */
376 char exten[AST_MAX_EXTENSION]; /*! Extension where to start */
377 char cid_num[AST_MAX_EXTENSION]; /*! CallerID Number */
378 char mailbox[AST_MAX_EXTENSION]; /*! Mailbox for MWI */
379 char musicclass[MAX_MUSICCLASS]; /*! MusicOnHold class */
380 ast_group_t callgroup; /*! Call group */
381 ast_group_t pickupgroup; /*! Pickup group */
382 char accountcode[AST_MAX_ACCOUNT_CODE]; /*! Account code (for billing) */
383 int amaflags; /*! AMA flags (for billing) */
384 struct ast_format_cap *cap; /*! Codec supported */
385 char parkinglot[AST_MAX_CONTEXT]; /*! Parkinglot */
389};
390
391/*!
392 * \brief A device containing one or more lines
393 */
394static struct unistim_device {
396 int receiver_state; /*!< state of the receiver (see ReceiverState) */
397 int size_phone_number; /*!< size of the phone number */
398 char context[AST_MAX_EXTENSION]; /*!< Context to start in */
399 char phone_number[AST_MAX_EXTENSION]; /*!< the phone number entered by the user */
400 char redial_number[AST_MAX_EXTENSION]; /*!< the last phone number entered by the user */
401 char id[18]; /*!< mac address of the current phone in ascii */
402 char name[DEVICE_NAME_LEN]; /*!< name of the device */
403 int hasexp; /*!< if device have expansion connected */
404 char expsoftkeylabel[EXPNUM][11]; /*!< soft key label */
405 char softkeylabel[FAVNUM][11]; /*!< soft key label */
406 char softkeynumber[FAVNUM][AST_MAX_EXTENSION]; /*!< number dialed when the soft key is pressed */
407 char softkeyicon[FAVNUM]; /*!< icon number */
408 char softkeydevice[FAVNUM][16]; /*!< name of the device monitored */
411 struct unistim_device *sp[FAVNUM]; /*!< pointer to the device monitored by this soft key */
412 char language[MAX_LANGUAGE]; /*!< Language for asterisk sounds */
413 int height; /*!< The number of lines the phone can display */
414 char maintext0[25]; /*!< when the phone is idle, display this string on line 0 */
415 char maintext1[25]; /*!< when the phone is idle, display this string on line 1 */
416 char maintext2[25]; /*!< when the phone is idle, display this string on line 2 */
417 char titledefault[13]; /*!< title (text before date/time) */
418 char datetimeformat; /*!< format used for displaying time/date */
419 signed char contrast; /*!< contrast */
420 char country[3]; /*!< country used for dial tone frequency */
421 struct ast_tone_zone *tz; /*!< Tone zone for res_indications (ring, busy, congestion) */
422 signed char ringvolume; /*!< Ring volume */
423 signed char ringstyle; /*!< Ring melody */
424 signed char cwvolume; /*!< Ring volume on call waiting */
425 signed char cwstyle; /*!< Ring melody on call waiting */
426 int interdigit_timer; /*!< Interdigit timer for dialing number by timeout */
427 int dtmfduration; /*!< DTMF playback duration */
428 time_t nextdial; /*!< Timer used for dial by timeout */
429 int rtp_port; /*!< RTP port used by the phone */
430 int rtp_method; /*!< Select the unistim data used to establish a RTP session */
431 int status_method; /*!< Select the unistim packet used for sending status text */
432 char codec_number; /*!< The current codec used to make calls */
433 int missed_call; /*!< Number of call unanswered */
434 int callhistory; /*!< Allowed to record call history */
435 int sharp_dial; /*!< Execute Dial on '#' or not */
436 char lst_cid[TEXT_LENGTH_MAX]; /*!< Last callerID received */
437 char lst_cnm[TEXT_LENGTH_MAX]; /*!< Last callername recevied */
438 char call_forward[AST_MAX_EXTENSION]; /*!< Forward number */
439 int output; /*!< Handset, headphone or speaker */
440 int previous_output; /*!< Previous output */
441 int volume; /*!< Default volume */
442 int selected; /*!< softkey selected */
443 int microphone; /*!< Microphone mode (audio tx) */
444 int lastmsgssent; /*! Used by MWI */
445 time_t nextmsgcheck; /*! Used by MWI */
446 int nat; /*!< Used by the obscure ast_rtp_setnat */
447 enum autoprov_extn extension; /*!< See ifdef EXTENSION for valid values */
448 char extension_number[11]; /*!< Extension number entered by the user */
449 signed char to_delete; /*!< Used in reload */
451 AST_LIST_HEAD(,unistim_subchannel) subs; /*!< pointer to our current connection, channel... */
453 struct ast_ha *ha;
457
458static struct unistimsession {
460 struct sockaddr_in sin; /*!< IP address of the phone */
461 struct sockaddr_in sout; /*!< IP address of server */
462 int timeout; /*!< time-out in ticks : resend packet if no ack was received before the timeout occured */
463 unsigned short seq_phone; /*!< sequence number for the next packet (when we receive a request) */
464 unsigned short seq_server; /*!< sequence number for the next packet (when we send a request) */
465 unsigned short last_seq_ack; /*!< sequence number of the last ACK received */
466 unsigned long tick_next_ping; /*!< time for the next ping */
467 int last_buf_available; /*!< number of a free slot */
468 int nb_retransmit; /*!< number of retransmission */
469 int state; /*!< state of the phone (see phone_state) */
470 int size_buff_entry; /*!< size of the buffer used to enter datas */
471 char buff_entry[16]; /*!< Buffer for temporary datas */
472 char macaddr[18]; /*!< mac address of the phone (not always available) */
473 char firmware[8]; /*!< firmware of the phone (not always available) */
474 struct wsabuf wsabufsend[MAX_BUF_NUMBER]; /*!< Size of each paquet stored in the buffer array & pointer to this buffer */
475 unsigned char buf[MAX_BUF_NUMBER][MAX_BUF_SIZE]; /*!< Buffer array used to keep the lastest non-acked paquets */
479
480/*! Store on screen phone menu item (label and handler function) */
482 char *label;
483 int state;
484 void (*handle_option)(struct unistimsession *);
485};
486
487/*! Language item for currently existed translations */
489 char *label;
493};
494
495/*!
496 * \page Unistim datagram formats
497 *
498 * Format of datagrams :
499 * bytes 0 & 1 : ffff for discovery packet, 0000 for everything else
500 * byte 2 : sequence number (high part)
501 * byte 3 : sequence number (low part)
502 * byte 4 : 2 = ask question or send info, 1 = answer or ACK, 0 = retransmit request
503 * byte 5 : direction, 1 = server to phone, 2 = phone to server arguments
504 */
505
506static const unsigned char packet_rcv_discovery[] =
507 { 0xff, 0xff, 0xff, 0xff, 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 };
508static const unsigned char packet_send_discovery_ack[] =
509 { 0x00, 0x00, /*Initial Seq (2 bytes) */ 0x00, 0x00, 0x00, 0x01 };
510
511static const unsigned char packet_recv_firm_version[] =
512 { 0x00, 0x00, 0x00, 0x13, 0x9a, 0x0a, 0x02 };
513static const unsigned char packet_recv_it_type[] =
514 { 0x00, 0x00, 0x00, 0x13, 0x9a, 0x04, 0x03 };
515static const unsigned char packet_recv_pressed_key[] =
516 { 0x00, 0x00, 0x00, 0x13, 0x99, 0x04, 0x00 };
517static const unsigned char packet_recv_pick_up[] =
518 { 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x04 };
519static const unsigned char packet_recv_hangup[] =
520 { 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x03 };
521static const unsigned char packet_recv_r2[] = { 0x00, 0x00, 0x00, 0x13, 0x96, 0x03, 0x03 };
522
523/*! Expansion module (i2004 KEM) */
524static const unsigned char packet_recv_expansion_pressed_key[] =
525 { 0x00, 0x00, 0x00, 0x13, 0x89, 0x04, 0x59 };
526static const unsigned char packet_send_expansion_next[] = { 0x09, 0x03, 0x17 };
527static const unsigned char packet_send_expansion_icon[] = { 0x09, 0x06, 0x59, 0x05, /*pos */ 0x47, /*icon */ 0x20 }; /* display an icon in front of the text zone */
528static const unsigned char packet_send_expansion_text[] = { 0x09, 0x0f, 0x57, 0x19, /*pos */ 0x47, /*text */ 0x20,
529 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 /*end_text */ };
530
531
532/*! TransportAdapter */
533static const unsigned char packet_recv_resume_connection_with_server[] =
534 { 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 };
535static const unsigned char packet_recv_mac_addr[] =
536 { 0xff, 0xff, 0xff, 0xff, 0x9a, 0x0d, 0x07 /*MacAddr */ };
537
538static const unsigned char packet_send_date_time3[] =
539 { 0x11, 0x09, 0x02, 0x02, /*Month */ 0x05, /*Day */ 0x06, /*Hour */ 0x07,
540/*Minutes */ 0x08, 0x32
541};
542static const unsigned char packet_send_date_time[] =
543 { 0x11, 0x09, 0x02, 0x0a, /*Month */ 0x05, /*Day */ 0x06, /*Hour */ 0x07, /*Minutes */
5440x08, 0x32, 0x17, 0x04, 0x24, 0x07, 0x19,
545 0x04, 0x07, 0x00, 0x19, 0x05, 0x09, 0x3e, 0x0f, 0x16, 0x05, 0x00, 0x80, 0x00, 0x1e,
546 0x05, 0x12, 0x00, 0x78
547};
548
549static const unsigned char packet_send_no_ring[] =
550 { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00 };
551static const unsigned char packet_send_s4[] =
552 { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00, 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff,
5530x16, 0x05, 0x1c, 0x00, 0x00, 0x17, 0x05,
554 0x0b, 0x00, 0x00, 0x19, 0x04, 0x00, 0x00, 0x19, 0x04, 0x00, 0x08, 0x19, 0x04, 0x00,
555 0x10, 0x19, 0x04, 0x00, 0x18, 0x16, 0x05,
556 0x31, 0x00, 0x00, 0x16, 0x05, 0x04, 0x00, 0x00
557};
558static const unsigned char packet_send_call[] =
559 { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00, 0x16, 0x06, 0x32, 0xdf,
560 0x00, 0xff, 0x16, 0x05, 0x1c, 0x00, 0x00, 0x16, 0x0a, 0x38, 0x00, 0x12, 0xca, 0x03,
561 0xc0, 0xc3, 0xc5, 0x16, 0x16, 0x30, 0x00,
562 0x00, /*codec */ 0x12, 0x12, /* frames per packet */ 0x01, 0x5c, 0x00, /*port RTP */
563 0x0f, 0xa0, /* port RTCP */ 0x9c, 0x41,
564 /*port RTP */ 0x0f, 0xa0, /* port RTCP */ 0x9c, 0x41, /* IP Address */ 0x0a, 0x01,
565 0x16, 0x66
566};
567static const unsigned char packet_send_stream_based_tone_off[] =
568 { 0x16, 0x05, 0x1c, 0x00, 0x00 };
569
570static const unsigned char packet_send_mute[] = { 0x16, 0x05, 0x04, 0x00, 0x00 };
571#ifdef NOT_USED
572static const unsigned char packet_send_CloseAudioStreamRX[] = { 0x16, 0x05, 0x31, 0x00, 0xff };
573static const unsigned char packet_send_CloseAudioStreamTX[] = { 0x16, 0x05, 0x31, 0xff, 0x00 };
574#endif
575static const unsigned char packet_send_stream_based_tone_on[] =
576 { 0x16, 0x06, 0x1b, 0x00, 0x00, 0x05 };
577static const unsigned char packet_send_stream_based_tone_single_freq[] =
578 { 0x16, 0x06, 0x1d, 0x00, 0x01, 0xb8 };
579static const unsigned char packet_send_stream_based_tone_dual_freq[] =
580 { 0x16, 0x08, 0x1d, 0x00, 0x01, 0xb8, 0x01, 0x5e };
581static const unsigned char packet_send_select_output[] =
582 { 0x16, 0x06, 0x32, 0xc0, 0x01, 0x00 };
583
584static const unsigned char packet_send_ring[] =
585 { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x1c, 0x00, 0x00, 0x16,
586 0x04, 0x1a, 0x01, 0x16, 0x05, 0x12, 0x13 /* Ring type 10 to 17 */ , 0x18, 0x16, 0x04, 0x18, /* volume 00, 10, 20... */
587 0x20, 0x16, 0x04, 0x10, 0x00
588};
589//static const unsigned char packet_send_end_call[] =
590// { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x31, 0x00, 0x00, /* Headset LED off */ 0x19, 0x04, 0x00,
591//0x10, /* Mute LED off */ 0x19, 0x04, 0x00, 0x18,/* Stream unmute */ 0x16, 0x05, 0x04, 0x00, 0x00, /* Query RTCP */ 0x16, 0x04, 0x37, 0x10 };
592static const unsigned char packet_send_end_call[] =
593 { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x31, 0x00, 0x00, /* Query RTCP */ 0x16, 0x04, 0x37, 0x10 };
594static const unsigned char packet_send_s9[] =
595 { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x19, 0x04, 0x00, 0x10, 0x16, 0x05, 0x1c, 0x00,
5960x00 };
597static const unsigned char packet_send_rtp_packet_size[] =
598 { 0x16, 0x08, 0x38, 0x00, 0x00, 0xe0, 0x00, 0xa0 };
599static const unsigned char packet_send_jitter_buffer_conf[] =
600 { 0x16, 0x0e, 0x3a, 0x00, /* jitter */ 0x02, /* high water mark */ 0x04, 0x00, 0x00,
601/* early packet resync 2 bytes */ 0x3e, 0x80,
602 0x00, 0x00, /* late packet resync 2 bytes */ 0x3e, 0x80
603};
604
605/* Duration in ms div 2 (0x20 = 64ms, 0x08 = 16ms)
606static unsigned char packet_send_StreamBasedToneCad[] =
607 { 0x16, 0x0a, 0x1e, 0x00, duration on 0x0a, duration off 0x0d, duration on 0x0a, duration off 0x0d, duration on 0x0a, duration off 0x2b }; */
608static const unsigned char packet_send_open_audio_stream_rx[] =
609 { 0x16, 0x1a, 0x30, 0x00, 0xff, /* Codec */ 0x00, 0x00, 0x01, 0x00, 0xb8, 0xb8, 0x0e,
6100x0e, 0x01, /* Port */ 0x14, 0x50, 0x00,
611 0x00, /* Port */ 0x14, 0x50, 0x00, 0x00, /* Dest IP */ 0x0a, 0x93, 0x69, 0x05
612};
613static const unsigned char packet_send_open_audio_stream_tx[] =
614 { 0x16, 0x1a, 0x30, 0xff, 0x00, 0x00, /* Codec */ 0x00, 0x01, 0x00, 0xb8, 0xb8, 0x0e,
6150x0e, 0x01, /* Local port */ 0x14, 0x50,
616 0x00, 0x00, /* Rmt Port */ 0x14, 0x50, 0x00, 0x00, /* Dest IP */ 0x0a, 0x93, 0x69, 0x05
617};
618
619static const unsigned char packet_send_open_audio_stream_rx3[] =
620 { 0x16, 0x1a, 0x30, 0x00, 0xff, /* Codec */ 0x00, 0x00, 0x02, 0x01, 0xb8, 0xb8, 0x06,
6210x06, 0x81, /* RTP Port */ 0x14, 0x50,
622/* RTCP Port */ 0x14,
623 0x51, /* RTP Port */ 0x14, 0x50, /* RTCP Port */ 0x00, 0x00, /* Dest IP */ 0x0a, 0x93,
624 0x69, 0x05
625};
626static const unsigned char packet_send_open_audio_stream_tx3[] =
627 { 0x16, 0x1a, 0x30, 0xff, 0x00, 0x00, /* Codec */ 0x00, 0x02, 0x01, 0xb8, 0xb8, 0x06,
6280x06, 0x81, /* RTP Local port */ 0x14, 0x50,
629 /* RTCP Port */ 0x00, 0x00, /* RTP Rmt Port */ 0x14, 0x50, /* RTCP Port */ 0x00, 0x00,
630 /* Dest IP */ 0x0a, 0x93, 0x69, 0x05
631};
632
633static const unsigned char packet_send_arrow[] = { 0x17, 0x04, 0x04, 0x00 };
634static const unsigned char packet_send_blink_cursor[] = { 0x17, 0x04, 0x10, 0x86 };
635static const unsigned char packet_send_date_time2[] = { 0x17, 0x04, 0x17, 0x3d, 0x11, 0x09, 0x02, 0x0a, /*Month */ 0x05, /*Day */
636 0x06, /*Hour */ 0x07, /*Minutes */ 0x08, 0x32
637};
638static const unsigned char packet_send_Contrast[] =
639 { 0x17, 0x04, 0x24, /*Contrast */ 0x08 };
640static const unsigned char packet_send_start_timer[] =
641 { 0x17, 0x05, 0x0b, /*Timer option*/0x05, /* Timer ID */0x00, 0x17, 0x08, 0x16,
642 /* Text */ 'T', 'i', 'm', 'e', 'r' };
643static const unsigned char packet_send_stop_timer[] = { 0x17, 0x05, 0x0b, 0x02, 0x00 };
644static const unsigned char packet_send_icon[] = { 0x17, 0x05, 0x14, /*pos */ 0x00, /*icon */ 0x25 }; /* display an icon in front of the text zone */
645static const unsigned char packet_send_S7[] = { 0x17, 0x06, 0x0f, 0x30, 0x07, 0x07 };
646static const unsigned char packet_send_set_pos_cursor[] =
647 { 0x17, 0x06, 0x10, 0x81, 0x04, /*pos */ 0x20 };
648
649static unsigned char monthlabels[] =
650 { 'J', 'a', 'n', 'F', 'e', 'b', 'M', 'a', 'r', 'A', 'p', 'r', 'M', 'a', 'y', 'J', 'u', 'n',
651 'J', 'u', 'l', 'A', 'u', 'g', 'S', 'e', 'p', 'O', 'c', 't', 'N', 'o', 'v', 'D', 'e', 'c' };
652static unsigned char packet_send_monthlabels_download[] =
653 { 0x17, 0x0a, 0x15, /* Month (3 char) */ '-', '-', '-', '-', '-', '-', 0x20 };
654static const unsigned char packet_send_favorite[] =
655 { 0x17, 0x0f, 0x19, 0x10, /*pos */ 0x01, /*name */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
6560x20, 0x20, 0x20, 0x20, /*end_name */ 0x19,
657 0x05, 0x0f, /*pos */ 0x01, /*icone */ 0x00
658};
659static const unsigned char packet_send_title[] =
660 { 0x17, 0x10, 0x19, 0x02, /*text */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
6610x20, 0x20, 0x20, 0x20 /*end_text */ };
662static const unsigned char packet_send_text[] =
663 { 0x17, 0x1e, 0x1b, 0x04, /*pos */ 0x00, /*inverse */ 0x25, /*text */ 0x20, 0x20,
6640x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
665 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
666 /*end_text */ 0x17, 0x04, 0x10, 0x87
667};
668static const unsigned char packet_send_status[] =
669 { 0x17, 0x20, 0x19, 0x08, /*text */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
6700x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
671 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 /*end_text */
672};
673static const unsigned char packet_send_status2[] =
674 { 0x17, 0x0b, 0x19, /* pos [08|28|48|68] */ 0x00, /* text */ 0x20, 0x20, 0x20, 0x20,
6750x20, 0x20, 0x20 /* end_text */ };
676
677/* Multiple character set support */
678/* ISO-8859-1 - Western European) */
679static const unsigned char packet_send_charset_iso_8859_1[] =
680 { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x41, 0x1b, 0x00 };
681/* ISO-8859-2 - Central European) */
682static const unsigned char packet_send_charset_iso_8859_2[] =
683 { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x42, 0x1b, 0x00 };
684/* ISO-8859-4 - Baltic) */
685static const unsigned char packet_send_charset_iso_8859_4[] =
686 { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x44, 0x1b, 0x00 };
687/* ISO 8859-5 - cyrillic */
688static const unsigned char packet_send_charset_iso_8859_5[] =
689 { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x4c, 0x1b, 0x00 };
690/* Japanese (ISO-2022-JP ?) */
691static const unsigned char packet_send_charset_iso_2022_jp[] =
692 { 0x17, 0x08, 0x21, 0x1b, 0x29, 0x49, 0x1b, 0x7e };
693
694static const unsigned char packet_send_led_update[] = { 0x19, 0x04, 0x00, 0x00 };
695
696static const unsigned char packet_send_query_basic_manager_04[] = { 0x1a, 0x04, 0x01, 0x04 };
697static const unsigned char packet_send_query_mac_address[] = { 0x1a, 0x04, 0x01, 0x08 };
698static const unsigned char packet_send_query_basic_manager_10[] = { 0x1a, 0x04, 0x01, 0x10 };
699static const unsigned char packet_send_S1[] = { 0x1a, 0x07, 0x07, 0x00, 0x00, 0x00, 0x13 };
700
701static unsigned char packet_send_ping[] =
702 { 0x1e, 0x05, 0x12, 0x00, /*Watchdog timer */ 0x78 };
703
704#define BUFFSEND unsigned char buffsend[64] = { 0x00, 0x00, 0xaa, 0xbb, 0x02, 0x01 }
705
706static const char tdesc[] = "UNISTIM Channel Driver";
707static const char channel_type[] = "USTM";
708
709/*! Protos */
710static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor);
711static int load_module(void);
712static int reload(void);
713static int unload_module(void);
714static int reload_config(void);
715static void unistim_set_owner(struct unistim_subchannel *sub, struct ast_channel *chan);
716static void show_main_page(struct unistimsession *pte);
717static struct ast_channel *unistim_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
718 const char *dest, int *cause);
719static int unistim_call(struct ast_channel *ast, const char *dest, int timeout);
720static int unistim_hangup(struct ast_channel *ast);
721static int unistim_answer(struct ast_channel *ast);
722static struct ast_frame *unistim_read(struct ast_channel *ast);
723static int unistim_write(struct ast_channel *ast, struct ast_frame *frame);
724static int unistim_indicate(struct ast_channel *ast, int ind, const void *data,
725 size_t datalen);
726static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
727static int unistim_senddigit_begin(struct ast_channel *ast, char digit);
728static int unistim_senddigit_end(struct ast_channel *ast, char digit,
729 unsigned int duration);
730static int unistim_sendtext(struct ast_channel *ast, const char *text);
731
732static int write_entry_history(struct unistimsession *pte, FILE * f, char c,
733 char *line1);
734static void change_callerid(struct unistimsession *pte, int type, char *callerid);
735
738 .description = tdesc,
740 .requester = unistim_request,
741 .call = unistim_call,
742 .hangup = unistim_hangup,
743 .answer = unistim_answer,
744 .read = unistim_read,
745 .write = unistim_write,
746 .indicate = unistim_indicate,
747 .fixup = unistim_fixup,
748 .send_digit_begin = unistim_senddigit_begin,
749 .send_digit_end = unistim_senddigit_end,
750 .send_text = unistim_sendtext,
751};
752
753static void send_start_rtp(struct unistim_subchannel *);
754
755static void send_callerid_screen(struct unistimsession *, struct unistim_subchannel *);
756static void key_favorite(struct unistimsession *, char);
757
758static void handle_select_codec(struct unistimsession *);
759static void handle_select_language(struct unistimsession *);
760static int find_language(const char*);
761
762static int unistim_free_sub(struct unistim_subchannel *);
763
765{
766 {"Change codec", STATE_SELECTCODEC, handle_select_codec},
768 {NULL, 0, NULL}
769};
770
772{
773 {"English", "en", ISO_8859_1, NULL},
774 {"French", "fr", ISO_8859_1, NULL},
775 {"Russian", "ru", ISO_8859_5, NULL},
776 {NULL, NULL, 0, NULL}
777};
778
779static char ustm_strcopy[1024];
780
782 const char *str_orig;
783 const char *str_trans;
784};
785
786static int lang_hash_fn(const void *obj, const int flags)
787{
788 const struct ustm_lang_entry *entry = obj;
789 return ast_str_hash(entry->str_orig);
790}
791
792static int lang_cmp_fn(void *obj, void *arg, int flags)
793{
794 struct ustm_lang_entry *entry1 = obj;
795 struct ustm_lang_entry *entry2 = arg;
796
797 return (!strcmp(entry1->str_orig, entry2->str_orig)) ? (CMP_MATCH | CMP_STOP) : 0;
798}
799
800static const char *ustmtext(const char *str, struct unistimsession *pte)
801{
802 struct ustm_lang_entry *lang_entry;
803 struct ustm_lang_entry le_search;
804 struct unistim_languages *lang = NULL;
805 int size;
806
807 if (pte->device) {
809 }
810 if (!lang) {
811 return str;
812 }
813 /* Check if specified language exists */
814 if (!lang->trans) {
815 char tmp[1024], *p, *p_orig = NULL, *p_trans = NULL;
816 FILE *f;
817
820 if (!lang->trans) {
821 ast_log(LOG_ERROR, "Unable to allocate container for translation!\n");
822 return str;
823 }
824 snprintf(tmp, sizeof(tmp), "%s/%s/%s.po", ast_config_AST_VAR_DIR,
826 f = fopen(tmp, "r");
827 if (!f) {
828 ast_log(LOG_WARNING, "There is no translation file for '%s'\n", lang->lang_short);
829 return str;
830 }
831 while (fgets(tmp, sizeof(tmp), f)) {
832 if (!(p = strchr(tmp, '\n'))) {
833 ast_log(LOG_ERROR, "Too long line found in language file - truncated!\n");
834 continue;
835 }
836 *p = '\0';
837 if (!(p = strchr(tmp, '"'))) {
838 continue;
839 }
840 if (tmp == strstr(tmp, "msgid")) {
841 p_orig = ast_strdup(p + 1);
842 p = strchr(p_orig, '"');
843 } else if (tmp == strstr(tmp, "msgstr")) {
844 p_trans = ast_strdup(p + 1);
845 p = strchr(p_trans, '"');
846 } else {
847 continue;
848 }
849 *p = '\0';
850 if (!p_trans || !p_orig) {
851 continue;
852 }
853 if (ast_strlen_zero(p_trans)) {
854 ast_free(p_trans);
855 ast_free(p_orig);
856 p_trans = NULL;
857 p_orig = NULL;
858 continue;
859 }
860 if (!(lang_entry = ao2_alloc(sizeof(*lang_entry), NULL))) {
861 fclose(f);
862 return str;
863 }
864
865 lang_entry->str_trans = p_trans;
866 lang_entry->str_orig = p_orig;
867 ao2_link(lang->trans, lang_entry);
868 p_trans = NULL;
869 p_orig = NULL;
870 }
871
872 fclose(f);
873 }
874
875 le_search.str_orig = str;
876 if ((lang_entry = ao2_find(lang->trans, &le_search, OBJ_POINTER))) {
877 size = strlen(lang_entry->str_trans)+1;
878 if (size > 1024) {
879 size = 1024;
880 }
881 memcpy(ustm_strcopy, lang_entry->str_trans, size);
882 ao2_ref(lang_entry, -1);
883 return ustm_strcopy;
884 }
885
886 return str;
887}
888
889static void display_last_error(const char *sz_msg)
890{
891 /* Display the error message */
892 ast_log(LOG_WARNING, "%s : (%d) %s\n", sz_msg, errno, strerror(errno));
893}
894
895static unsigned int get_tick_count(void)
896{
897 struct timeval now = ast_tvnow();
898
899 return (now.tv_sec * 1000) + (now.tv_usec / 1000);
900}
901
902/* Send data to a phone without retransmit nor buffering */
903static void send_raw_client(int size, const unsigned char *data, struct sockaddr_in *addr_to,
904 const struct sockaddr_in *addr_ourip)
905{
906#ifdef HAVE_PKTINFO
907 struct iovec msg_iov;
908 struct msghdr msg;
909 char buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
910 struct cmsghdr *ip_msg = (struct cmsghdr *) buffer;
911 struct in_pktinfo *pki = (struct in_pktinfo *) CMSG_DATA(ip_msg);
912
913 /* cast this to a non-const pointer, since the sendmsg() API
914 * does not provide read-only and write-only flavors of the
915 * structures used for its arguments, but in this case we know
916 * the data will not be modified
917 */
918 msg_iov.iov_base = (char *) data;
919 msg_iov.iov_len = size;
920
921 msg.msg_name = addr_to; /* optional address */
922 msg.msg_namelen = sizeof(struct sockaddr_in); /* size of address */
923 msg.msg_iov = &msg_iov; /* scatter/gather array */
924 msg.msg_iovlen = 1; /* # elements in msg_iov */
925 msg.msg_control = ip_msg; /* ancillary data */
926 msg.msg_controllen = sizeof(buffer); /* ancillary data buffer len */
927 msg.msg_flags = 0; /* flags on received message */
928
929 ip_msg->cmsg_len = CMSG_LEN(sizeof(*pki));
930 ip_msg->cmsg_level = IPPROTO_IP;
931 ip_msg->cmsg_type = IP_PKTINFO;
932 pki->ipi_ifindex = 0; /* Interface index, 0 = use interface specified in routing table */
933 pki->ipi_spec_dst.s_addr = addr_ourip->sin_addr.s_addr; /* Local address */
934 /* pki->ipi_addr = ; Header Destination address - ignored by kernel */
935
936#ifdef DUMP_PACKET
937 if (unistimdebug) {
938 int tmp;
939 ast_verb(0, "\n**> From %s sending %d bytes to %s ***\n",
940 ast_inet_ntoa(addr_ourip->sin_addr), (int) size,
941 ast_inet_ntoa(addr_to->sin_addr));
942 for (tmp = 0; tmp < size; tmp++)
943 ast_verb(0, "%02hhx ", data[tmp]);
944 ast_verb(0, "\n******************************************\n");
945
946 }
947#endif
948
949 if (sendmsg(unistimsock, &msg, 0) == -1) {
950 display_last_error("Error sending datas");
951 }
952#else
953 if (sendto(unistimsock, data, size, 0, (struct sockaddr *) addr_to, sizeof(*addr_to))
954 == -1)
955 display_last_error("Error sending datas");
956#endif
957}
958
959static void send_client(int size, const unsigned char *data, struct unistimsession *pte)
960{
961 unsigned int tick;
962 int buf_pos;
963 unsigned short seq = ntohs(++pte->seq_server);
964
965 ast_mutex_lock(&pte->lock);
966 buf_pos = pte->last_buf_available;
967
968 if (buf_pos >= MAX_BUF_NUMBER) {
969 ast_log(LOG_WARNING, "Error : send queue overflow\n");
970 ast_mutex_unlock(&pte->lock);
971 return;
972 }
973 memcpy((void *)data + sizeof(unsigned short), (void *)&seq, sizeof(unsigned short));
974 pte->wsabufsend[buf_pos].len = size;
975 memcpy(pte->wsabufsend[buf_pos].buf, data, size);
976
977 tick = get_tick_count();
978 pte->timeout = tick + RETRANSMIT_TIMER;
979
980/*#ifdef DUMP_PACKET */
981 if (unistimdebug) {
982 ast_verb(0, "Sending datas with seq #0x%04x Using slot #%d :\n", (unsigned)pte->seq_server, buf_pos);
983 }
984/*#endif */
985 send_raw_client(pte->wsabufsend[buf_pos].len, pte->wsabufsend[buf_pos].buf, &(pte->sin),
986 &(pte->sout));
987 pte->last_buf_available++;
988 ast_mutex_unlock(&pte->lock);
989}
990
991static void send_ping(struct unistimsession *pte)
992{
993 BUFFSEND;
994 if (unistimdebug) {
995 ast_verb(0, "Sending ping\n");
996 }
998 memcpy(buffsend + SIZE_HEADER, packet_send_ping, sizeof(packet_send_ping));
999 send_client(SIZE_HEADER + sizeof(packet_send_ping), buffsend, pte);
1000}
1001
1002static int get_to_address(int fd, struct sockaddr_in *toAddr)
1003{
1004#ifdef HAVE_PKTINFO
1005 int err;
1006 char cmbuf[0x100];
1007 struct cmsghdr *cmsg;
1008 struct sockaddr_in peeraddr;
1009 struct in_addr addr;
1010 struct msghdr mh = {
1011 .msg_name = &peeraddr,
1012 .msg_namelen = sizeof(peeraddr),
1013 .msg_control = cmbuf,
1014 .msg_controllen = sizeof(cmbuf),
1015 };
1016 memset(&addr, 0, sizeof(addr));
1017 /* Get info about the incoming packet */
1018 err = recvmsg(fd, &mh, MSG_PEEK);
1019 if (err == -1) {
1020 ast_log(LOG_WARNING, "recvmsg returned an error: %s\n", strerror(errno));
1021 return err;
1022 }
1023 for(cmsg = CMSG_FIRSTHDR(&mh);
1024 cmsg != NULL;
1025 cmsg = CMSG_NXTHDR(&mh, cmsg))
1026 {
1027 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
1028 struct in_pktinfo *pkt = (struct in_pktinfo*)CMSG_DATA(cmsg);
1029 addr = pkt->ipi_addr;
1030 if (unistimdebug) {
1031 ast_verb(0, "message received on address %s\n", ast_inet_ntoa(addr));
1032 }
1033 }
1034 }
1035 memcpy(&toAddr->sin_addr, &addr, sizeof(struct in_addr));
1036 return err;
1037#else
1038 memcpy(toAddr, &public_ip, sizeof(*toAddr));
1039 return 0;
1040#endif
1041}
1042
1043
1044/* Allocate memory & initialize structures for a new phone */
1045/* addr_from : ip address of the phone */
1046static struct unistimsession *create_client(const struct sockaddr_in *addr_from)
1047{
1048 int tmp;
1049 struct unistimsession *s;
1050
1051 if (!(s = ast_calloc(1, sizeof(*s))))
1052 return NULL;
1053
1054 memcpy(&s->sin, addr_from, sizeof(struct sockaddr_in));
1055 if (get_to_address(unistimsock, &s->sout) < 0) {
1056 ast_free(s);
1057 return NULL;
1058 }
1059 s->sout.sin_family = AF_INET;
1060 if (unistimdebug) {
1061 ast_verb(0, "Creating a new entry for the phone from %s received via server ip %s\n",
1062 ast_inet_ntoa(addr_from->sin_addr), ast_inet_ntoa(s->sout.sin_addr));
1063 }
1064 ast_mutex_init(&s->lock);
1066 s->next = sessions;
1067 sessions = s;
1068
1070 s->state = STATE_INIT;
1072 /* Initialize struct wsabuf */
1073 for (tmp = 0; tmp < MAX_BUF_NUMBER; tmp++) {
1074 s->wsabufsend[tmp].buf = s->buf[tmp];
1075 }
1077 return s;
1078}
1079
1080static void send_end_call(struct unistimsession *pte)
1081{
1082 BUFFSEND;
1083 if (unistimdebug) {
1084 ast_verb(0, "Sending end call\n");
1085 }
1086 memcpy(buffsend + SIZE_HEADER, packet_send_end_call, sizeof(packet_send_end_call));
1087 send_client(SIZE_HEADER + sizeof(packet_send_end_call), buffsend, pte);
1088}
1089
1090static void set_ping_timer(struct unistimsession *pte)
1091{
1092 unsigned int tick = 0; /* XXX what is this for, anyways */
1093
1094 pte->timeout = pte->tick_next_ping;
1095 DEBUG_TIMER("tick = %u next ping at %u tick\n", tick, pte->timeout);
1096 return;
1097}
1098
1099/* Checking if our send queue is empty,
1100 * if true, setting up a timer for keepalive */
1101static void check_send_queue(struct unistimsession *pte)
1102{
1103 /* Check if our send queue contained only one element */
1104 if (pte->last_buf_available == 1) {
1105 if (unistimdebug) {
1106 ast_verb(0, "Our single packet was ACKed.\n");
1107 }
1108 pte->last_buf_available--;
1109 set_ping_timer(pte);
1110 return;
1111 }
1112 /* Check if this ACK catch up our latest packet */
1113 else if (pte->last_seq_ack + 1 == pte->seq_server + 1) {
1114 if (unistimdebug) {
1115 ast_verb(0, "Our send queue is completely ACKed.\n");
1116 }
1117 pte->last_buf_available = 0; /* Purge the send queue */
1118 set_ping_timer(pte);
1119 return;
1120 }
1121 if (unistimdebug) {
1122 ast_verb(0, "We still have packets in our send queue\n");
1123 }
1124 return;
1125}
1126
1127static void send_start_timer(struct unistimsession *pte)
1128{
1129 BUFFSEND;
1130 if (unistimdebug) {
1131 ast_verb(0, "Sending start timer\n");
1132 }
1133 memcpy(buffsend + SIZE_HEADER, packet_send_start_timer, sizeof(packet_send_start_timer));
1134 send_client(SIZE_HEADER + sizeof(packet_send_start_timer), buffsend, pte);
1135}
1136
1137static void send_stop_timer(struct unistimsession *pte)
1138{
1139 BUFFSEND;
1140 if (unistimdebug) {
1141 ast_verb(0, "Sending stop timer\n");
1142 }
1143 memcpy(buffsend + SIZE_HEADER, packet_send_stop_timer, sizeof(packet_send_stop_timer));
1144 send_client(SIZE_HEADER + sizeof(packet_send_stop_timer), buffsend, pte);
1145}
1146
1147static void send_icon(unsigned char pos, unsigned char status, struct unistimsession *pte)
1148{
1149 BUFFSEND;
1150 if (unistimdebug) {
1151 ast_verb(0, "Sending icon pos %d with status 0x%02hhx\n", pos, status);
1152 }
1153 memcpy(buffsend + SIZE_HEADER, packet_send_icon, sizeof(packet_send_icon));
1154 buffsend[9] = pos;
1155 buffsend[10] = status;
1156 send_client(SIZE_HEADER + sizeof(packet_send_icon), buffsend, pte);
1157}
1158
1159static void send_expansion_next(struct unistimsession *pte)
1160{
1161 BUFFSEND;
1163 send_client(SIZE_HEADER + sizeof(packet_send_expansion_next), buffsend, pte);
1164}
1165
1166
1167static void send_expansion_icon(unsigned char pos, unsigned char status, struct unistimsession *pte)
1168{
1169 BUFFSEND;
1170 if (unistimdebug) {
1171 ast_verb(0, "Sending expansion icon pos %d with status 0x%02hhx\n", pos, status);
1172 }
1174 buffsend[10] = pos;
1175 buffsend[11] = status;
1176 send_client(SIZE_HEADER + sizeof(packet_send_expansion_icon), buffsend, pte);
1177}
1178
1179/* inverse : TEXT_INVERSE : yes, TEXT_NORMAL : no */
1180static void send_expansion_text(unsigned char pos, struct unistimsession *pte, const char *text)
1181{
1182 int i;
1183 BUFFSEND;
1184 if (!text) {
1185 ast_log(LOG_ERROR, "[expansion] Asked to display NULL text (pos %d)\n", pos);
1186 return;
1187 }
1188 if (unistimdebug) {
1189 ast_verb(0, "[expansion] Sending text at pos %d\n", pos);
1190 }
1192 buffsend[10] = pos;
1193 i = strlen(text);
1194 if (i > TEXT_LENGTH_MAX) {
1195 i = TEXT_LENGTH_MAX;
1196 }
1197 memcpy(buffsend + 11, text, i);
1198 send_client(SIZE_HEADER + sizeof(packet_send_expansion_text), buffsend, pte);
1199}
1200
1201static void send_tone(struct unistimsession *pte, uint16_t tone1, uint16_t tone2)
1202{
1203 BUFFSEND;
1204 if (!tone1) {
1205 if (unistimdebug) {
1206 ast_verb(0, "Sending Stream Based Tone Off\n");
1207 }
1211 return;
1212 }
1213 /* Since most of the world use a continuous tone, it's useless
1214 if (unistimdebug)
1215 ast_verb(0, "Sending Stream Based Tone Cadence Download\n");
1216 memcpy (buffsend + SIZE_HEADER, packet_send_StreamBasedToneCad, sizeof (packet_send_StreamBasedToneCad));
1217 send_client (SIZE_HEADER + sizeof (packet_send_StreamBasedToneCad), buffsend, pte); */
1218 if (unistimdebug) {
1219 ast_verb(0, "Sending Stream Based Tone Frequency Component List Download %d %d\n", tone1, tone2);
1220 }
1221 tone1 *= 8;
1222 if (!tone2) {
1225 put_unaligned_uint16(&buffsend[10], htons(tone1));
1227 pte);
1228 } else {
1229 tone2 *= 8;
1232 put_unaligned_uint16(&buffsend[10], htons(tone1));
1233 put_unaligned_uint16(&buffsend[12], htons(tone2));
1235 pte);
1236 }
1237
1238 if (unistimdebug) {
1239 ast_verb(0, "Sending Stream Based Tone On\n");
1240 }
1244}
1245
1246/* Positions for favorites
1247 |--------------------|
1248 | 5 2 | <-- not on screen in i2002
1249 | 4 1 |
1250 | 3 0 |
1251
1252
1253 KEM Positions
1254
1255 |--------------------|
1256 | 12 24 |
1257 | 11 23 |
1258 | 10 22 |
1259 | 9 21 |
1260 | 8 20 |
1261 | 7 19 |
1262 | 6 18 |
1263 | 5 17 |
1264 | 4 16 |
1265 | 3 15 |
1266 | 2 14 |
1267 | 1 13 |
1268
1269*/
1270
1271/* status (icons) : 00 = nothing, 2x/3x = see parser.h, 4x/5x = blink fast, 6x/7x = blink slow */
1272static void
1273send_favorite(unsigned char pos, unsigned char status, struct unistimsession *pte,
1274 const char *text)
1275{
1276 BUFFSEND;
1277 int i;
1278
1279 if (unistimdebug) {
1280 ast_verb(0, "Sending favorite pos %d with status 0x%02hhx\n", pos, status);
1281 }
1282 memcpy(buffsend + SIZE_HEADER, packet_send_favorite, sizeof(packet_send_favorite));
1283 buffsend[10] = pos;
1284 buffsend[24] = pos;
1285 buffsend[25] = status;
1286 i = strlen(ustmtext(text, pte));
1287 if (i > FAV_MAX_LENGTH) {
1288 i = FAV_MAX_LENGTH;
1289 }
1290 memcpy(buffsend + FAV_MAX_LENGTH + 1, ustmtext(text, pte), i);
1291 send_client(SIZE_HEADER + sizeof(packet_send_favorite), buffsend, pte);
1292}
1293
1294static void send_favorite_short(unsigned char pos, unsigned char status, struct unistimsession *pte) {
1295 send_favorite(pos, status, pte, pte->device->softkeylabel[pos]);
1296 return;
1297}
1298
1299static void send_favorite_selected(unsigned char status, struct unistimsession *pte) {
1300 if (pte->device->selected != -1) {
1302 }
1303 return;
1304}
1305
1306static void send_expansion_short(unsigned char pos, unsigned char status, struct unistimsession *pte) {
1307 send_expansion_icon(pos, status, pte);
1308 send_expansion_text(pos, pte, ustmtext(pte->device->expsoftkeylabel[pos], pte));
1310 return;
1311}
1312
1313static int soft_key_visible(struct unistim_device* d, unsigned char num)
1314{
1315 if(d->height == 1 && num % 3 == 2) {
1316 return 0;
1317 }
1318 return 1;
1319}
1320
1321static void refresh_all_favorite(struct unistimsession *pte)
1322{
1323 unsigned char i = 0;
1324 char data[256];
1325 struct unistim_line *line;
1326 line = AST_LIST_FIRST(&pte->device->lines);
1327
1328 if (unistimdebug) {
1329 ast_verb(0, "Refreshing all favorite\n");
1330 }
1331 for (i = 0; i < FAVNUM; i++) {
1332 unsigned char status = pte->device->softkeyicon[i];
1333
1334 if (!soft_key_visible(pte->device, i)) {
1335 continue;
1336 }
1337 if (!strcasecmp(pte->device->softkeylabel[i], "DND") && line) {
1338 if (!ast_db_get("DND", line->name, data, sizeof(data))) {
1340 }
1341 }
1342
1343 send_favorite_short(i, status, pte);
1344 }
1345 if (pte->device->hasexp) {
1346 for (i = 0; i < EXPNUM; i++) {
1348 }
1349 }
1350}
1351
1352static int is_key_favorite(struct unistim_device *d, int fav)
1353{
1354 if ((fav < 0) || (fav >= FAVNUM)) {
1355 return 0;
1356 }
1357 if (d->sline[fav]) {
1358 return 0;
1359 }
1360 if (d->softkeynumber[fav][0] == '\0') {
1361 return 0;
1362 }
1363 return 1;
1364}
1365
1366static int is_key_line(struct unistim_device *d, int fav)
1367{
1368 if ((fav < 0) || (fav >= FAVNUM)) {
1369 return 0;
1370 }
1371 if (!d->sline[fav]) {
1372 return 0;
1373 }
1374 if (is_key_favorite(d, fav)) {
1375 return 0;
1376 }
1377 return 1;
1378}
1379
1380static int get_active_softkey(struct unistimsession *pte)
1381{
1382 return pte->device->selected;
1383}
1384
1385static int get_avail_softkey(struct unistimsession *pte, const char* name)
1386{
1387 int i;
1388
1389 if (!is_key_line(pte->device, pte->device->selected)) {
1390 pte->device->selected = -1;
1391 }
1392 for (i = 0; i < FAVNUM; i++) {
1393 if (pte->device->selected != -1 && pte->device->selected != i) {
1394 continue;
1395 }
1396 if (!soft_key_visible(pte->device, i)) {
1397 continue;
1398 }
1399 if (pte->device->ssub[i]) {
1400 continue;
1401 }
1402 if (is_key_line(pte->device, i)) {
1403 if (name && strcmp(name, pte->device->sline[i]->name)) {
1404 continue;
1405 }
1406 if (unistimdebug) {
1407 ast_verb(0, "Found softkey %d for device %s\n", i, name);
1408 }
1409 return i;
1410 }
1411 }
1412 return -1;
1413}
1414
1415
1416/* Change the status for this phone (pte) and update for each phones where pte is bookmarked
1417 * use FAV_ICON_*_BLACK constant in status parameters */
1418static void change_favorite_icon(struct unistimsession *pte, unsigned char status)
1419{
1420 struct unistim_device *d = devices;
1421 int i;
1422 /* Update the current phone line softkey icon */
1423 if (pte->state != STATE_CLEANING) {
1424 int softkeylinepos = get_active_softkey(pte);
1425 if (softkeylinepos != -1) {
1426 send_favorite_short(softkeylinepos, status, pte);
1427 }
1428 }
1429 /* Notify other phones if we're in their bookmark */
1430 while (d) {
1431 for (i = 0; i < FAVNUM; i++) {
1432 if (d->sp[i] == pte->device) { /* It's us ? */
1433 if (d->softkeyicon[i] != status) { /* Avoid resending the same icon */
1434 d->softkeyicon[i] = status;
1435 if (d->session) {
1436 send_favorite(i, status + 1, d->session, d->softkeylabel[i]);
1437 }
1438 }
1439 }
1440 }
1441 d = d->next;
1442 }
1443}
1444
1445static int register_extension(const struct unistimsession *pte)
1446{
1447 struct unistim_line *line;
1448 line = AST_LIST_FIRST(&pte->device->lines);
1449 if (unistimdebug) {
1450 ast_verb(0, "Trying to register extension '%s' into context '%s' to %s\n",
1452 line->fullname);
1453 }
1454 return ast_add_extension(pte->device->context, 0,
1455 pte->device->extension_number, 1, NULL, NULL, "Dial",
1456 line->fullname, 0, "Unistim");
1457}
1458
1459static int unregister_extension(const struct unistimsession *pte)
1460{
1461 if (unistimdebug) {
1462 ast_verb(0, "Trying to unregister extension '%s' context '%s'\n",
1463 pte->device->extension_number, pte->device->context);
1464 }
1466 pte->device->extension_number, 1, "Unistim");
1467}
1468
1469/* Free memory allocated for a phone */
1470static void close_client(struct unistimsession *s)
1471{
1472 struct unistim_subchannel *sub = NULL;
1473 struct unistimsession *cur, *prev = NULL;
1475 cur = sessions;
1476 /* Looking for the session in the linked chain */
1477 while (cur) {
1478 if (cur == s) {
1479 break;
1480 }
1481 prev = cur;
1482 cur = cur->next;
1483 }
1484 if (cur) { /* Session found ? */
1485 if (cur->device) { /* This session was registered ? */
1486 s->state = STATE_CLEANING;
1487 if (unistimdebug) {
1488 ast_verb(0, "close_client session %p device %p\n", s, s->device);
1489 }
1494 if (!sub) {
1495 continue;
1496 }
1497 if (sub->owner) { /* Call in progress ? */
1498 if (unistimdebug) {
1499 ast_verb(0, "Aborting call\n");
1500 }
1502 } else {
1503 if (unistimdebug) {
1504 ast_debug(1, "Released sub %u of channel %s@%s\n", sub->subtype, sub->parent->name, s->device->name);
1505 }
1508 }
1509 }
1512
1515 }
1516 cur->device->session = NULL;
1518 } else {
1519 if (unistimdebug) {
1520 ast_verb(0, "Freeing an unregistered client\n");
1521 }
1522 }
1523 if (prev) {
1524 prev->next = cur->next;
1525 } else {
1526 sessions = cur->next;
1527 }
1529 ast_free(s);
1530 } else {
1531 ast_log(LOG_WARNING, "Trying to delete non-existent session %p?\n", s);
1532 }
1534 return;
1535}
1536
1537/* Return 1 if the session chained link was modified */
1538static int send_retransmit(struct unistimsession *pte)
1539{
1540 int i;
1541
1542 ast_mutex_lock(&pte->lock);
1543 if (++pte->nb_retransmit >= NB_MAX_RETRANSMIT) {
1544 if (unistimdebug) {
1545 ast_verb(0, "Too many retransmit - freeing client\n");
1546 }
1547 ast_mutex_unlock(&pte->lock);
1548 close_client(pte);
1549 return 1;
1550 }
1552
1553 for (i = pte->last_buf_available - (pte->seq_server - pte->last_seq_ack);
1554 i < pte->last_buf_available; i++) {
1555 if (i < 0) {
1557 "Asked to retransmit an ACKed slot ! last_buf_available=%d, seq_server = #0x%04x last_seq_ack = #0x%04x\n",
1558 pte->last_buf_available, (unsigned)pte->seq_server, (unsigned)pte->last_seq_ack);
1559 continue;
1560 }
1561
1562 if (unistimdebug) {
1563 unsigned short *sbuf = (unsigned short *) pte->wsabufsend[i].buf;
1564 unsigned short seq;
1565
1566 seq = ntohs(sbuf[1]);
1567 ast_verb(0, "Retransmit slot #%d (seq=#0x%04x), last ack was #0x%04x\n", i,
1568 (unsigned)seq, (unsigned)pte->last_seq_ack);
1569 }
1570 send_raw_client(pte->wsabufsend[i].len, pte->wsabufsend[i].buf, &pte->sin,
1571 &pte->sout);
1572 }
1573 ast_mutex_unlock(&pte->lock);
1574 return 0;
1575}
1576
1577/* inverse : TEXT_INVERSE : yes, TEXT_NORMAL : no */
1578static void send_text(unsigned char pos, unsigned char inverse, struct unistimsession *pte,
1579 const char *text)
1580{
1581 int i;
1582 BUFFSEND;
1583 if (!text) {
1584 ast_log(LOG_ERROR, "Asked to display NULL text (pos %d, inverse flag %d)\n", pos, inverse);
1585 return;
1586 }
1587 if (pte->device && pte->device->height == 1 && pos != TEXT_LINE0) {
1588 return;
1589 }
1590 if (unistimdebug) {
1591 ast_verb(0, "Sending text at pos %d, inverse flag %d\n", pos, inverse);
1592 }
1593 memcpy(buffsend + SIZE_HEADER, packet_send_text, sizeof(packet_send_text));
1594 buffsend[10] = pos;
1595 buffsend[11] = inverse;
1596 i = strlen(text);
1597 if (i > TEXT_LENGTH_MAX) {
1598 i = TEXT_LENGTH_MAX;
1599 }
1600 memcpy(buffsend + 12, text, i);
1601 send_client(SIZE_HEADER + sizeof(packet_send_text), buffsend, pte);
1602}
1603
1604static void send_text_status(struct unistimsession *pte, const char *text)
1605{
1606 BUFFSEND;
1607 int i;
1608 if (unistimdebug) {
1609 ast_verb(0, "Sending status text\n");
1610 }
1611 if (pte->device) {
1612 if (pte->device->status_method == 1) { /* For new firmware and i2050 soft phone */
1613 int n = strlen(text);
1614 /* Must send individual button separately */
1615 int j;
1616 for (i = 0, j = 0; i < 4; i++, j += 7) {
1617 int pos = 0x08 + (i * 0x20);
1618 memcpy(buffsend + SIZE_HEADER, packet_send_status2,
1619 sizeof(packet_send_status2));
1620
1621 buffsend[9] = pos;
1622 memcpy(buffsend + 10, (j < n) ? (text + j) : " ", 7);
1623 send_client(SIZE_HEADER + sizeof(packet_send_status2), buffsend, pte);
1624 }
1625 return;
1626 }
1627 }
1628
1629 memcpy(buffsend + SIZE_HEADER, packet_send_status, sizeof(packet_send_status));
1630 i = strlen(text);
1631 if (i > STATUS_LENGTH_MAX) {
1633 }
1634 memcpy(buffsend + 10, text, i);
1635 send_client(SIZE_HEADER + sizeof(packet_send_status), buffsend, pte);
1636
1637}
1638
1639static void send_led_update(struct unistimsession *pte, unsigned char led)
1640{
1641 BUFFSEND;
1642 if (unistimdebug) {
1643 ast_verb(0, "Sending led_update (%x)\n", (unsigned)led);
1644 }
1645 memcpy(buffsend + SIZE_HEADER, packet_send_led_update, sizeof(packet_send_led_update));
1646 buffsend[9] = led;
1647 send_client(SIZE_HEADER + sizeof(packet_send_led_update), buffsend, pte);
1648}
1649
1650static void send_mute(struct unistimsession *pte, unsigned char mute)
1651{
1652/*
1653 0x00 = unmute TX, 0x01 = mute TX
1654 0x20 = unmute RX, 0x21 = mute RX
1655*/
1656 BUFFSEND;
1657 if (unistimdebug) {
1658 ast_verb(0, "Sending mute packet (%x)\n", (unsigned)mute);
1659 }
1660 memcpy(buffsend + SIZE_HEADER, packet_send_mute, sizeof(packet_send_mute));
1661 buffsend[9] = mute;
1662 send_client(SIZE_HEADER + sizeof(packet_send_mute), buffsend, pte);
1663}
1664
1665
1666/* output = OUTPUT_HANDSET, OUTPUT_HEADPHONE or OUTPUT_SPEAKER
1667 * volume = VOLUME_LOW, VOLUME_NORMAL, VOLUME_INSANELY_LOUD
1668 * mute = MUTE_OFF, MUTE_ON */
1669static void
1670send_select_output(struct unistimsession *pte, unsigned char output, unsigned char volume,
1671 unsigned char mute)
1672{
1673 BUFFSEND;
1674 int mute_icon = -1;
1675 if (unistimdebug) {
1676 ast_verb(0, "Sending select output packet output=%x volume=%x mute=%x\n",
1677 (unsigned)output, (unsigned)volume, (unsigned)mute);
1678 }
1679 memcpy(buffsend + SIZE_HEADER, packet_send_select_output,
1681 buffsend[9] = output;
1682 if (output == OUTPUT_SPEAKER && volume == VOLUME_LOW) {
1684 }
1685 buffsend[10] = volume;
1686 if (mute == MUTE_ON_DISCRET) {
1687 buffsend[11] = MUTE_ON;
1688 } else {
1689 buffsend[11] = mute;
1690 }
1691 send_client(SIZE_HEADER + sizeof(packet_send_select_output), buffsend, pte);
1692 if (output == OUTPUT_HANDSET) {
1693 mute_icon = (mute == MUTE_ON) ? FAV_ICON_ONHOLD_BLACK : FAV_ICON_OFFHOOK_BLACK;
1696 } else if (output == OUTPUT_HEADPHONE) {
1700 } else if (output == OUTPUT_SPEAKER) {
1703 if (pte->device->receiver_state == STATE_OFFHOOK) {
1705 } else {
1707 }
1708 } else {
1709 ast_log(LOG_WARNING, "Invalid output (%d)\n", output);
1710 }
1711 if (mute_icon != -1) {
1712 change_favorite_icon(pte, mute_icon);
1713 }
1714 if (output != pte->device->output) {
1715 pte->device->previous_output = pte->device->output;
1716 }
1717 pte->device->output = output;
1718}
1719static void send_ring(struct unistimsession *pte, signed char volume, signed char style)
1720{
1721 BUFFSEND;
1722 if (unistimdebug) {
1723 ast_verb(0, "Sending ring packet\n");
1724 }
1725 memcpy(buffsend + SIZE_HEADER, packet_send_ring, sizeof(packet_send_ring));
1726 buffsend[24] = style + 0x10;
1727 buffsend[29] = volume * 0x10;
1728 send_client(SIZE_HEADER + sizeof(packet_send_ring), buffsend, pte);
1729}
1730
1731static void send_no_ring(struct unistimsession *pte)
1732{
1733 BUFFSEND;
1734 if (unistimdebug) {
1735 ast_verb(0, "Sending no ring packet\n");
1736 }
1737 memcpy(buffsend + SIZE_HEADER, packet_send_no_ring, sizeof(packet_send_no_ring));
1738 send_client(SIZE_HEADER + sizeof(packet_send_no_ring), buffsend, pte);
1739}
1740
1741static void send_texttitle(struct unistimsession *pte, const char *text)
1742{
1743 BUFFSEND;
1744 int i;
1745 if (unistimdebug) {
1746 ast_verb(0, "Sending title text\n");
1747 }
1748 memcpy(buffsend + SIZE_HEADER, packet_send_title, sizeof(packet_send_title));
1749 i = strlen(text);
1750 if (i > 12) {
1751 i = 12;
1752 }
1753 memcpy(buffsend + 10, text, i);
1754 send_client(SIZE_HEADER + sizeof(packet_send_title), buffsend, pte);
1755}
1756
1757static void send_idle_clock(struct unistimsession *pte)
1758{
1759 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "");
1760}
1761
1762static void send_month_labels(struct unistimsession *pte, int month)
1763{
1764 BUFFSEND;
1765 char month_name[MONTH_LABEL_SIZE + 1];
1766 int i = 0;
1767 if (unistimdebug) {
1768 ast_verb(0, "Sending Month Labels\n");
1769 }
1770 month_name[MONTH_LABEL_SIZE] = '\0';
1772 while (i < 2) {
1773 memcpy(month_name, &monthlabels[month * MONTH_LABEL_SIZE], MONTH_LABEL_SIZE);
1774 memcpy(buffsend + SIZE_HEADER + 3 + i*MONTH_LABEL_SIZE, ustmtext(month_name, pte), MONTH_LABEL_SIZE);
1775 ast_log(LOG_WARNING,"%s\n", month_name);
1776 ast_log(LOG_WARNING,"%s\n", ustmtext(month_name, pte));
1777 month = (month + 1)%12;
1778 i++;
1779 }
1781}
1782
1783
1784static void send_date_time(struct unistimsession *pte)
1785{
1786 BUFFSEND;
1787 struct timeval now = ast_tvnow();
1788 struct ast_tm atm = { 0, };
1789
1790 if (unistimdebug) {
1791 ast_verb(0, "Sending Time & Date\n");
1792 }
1793 memcpy(buffsend + SIZE_HEADER, packet_send_date_time, sizeof(packet_send_date_time));
1794 ast_localtime(&now, &atm, NULL);
1795 buffsend[10] = (unsigned char) atm.tm_mon + 1;
1796 buffsend[11] = (unsigned char) atm.tm_mday;
1797 buffsend[12] = (unsigned char) atm.tm_hour;
1798 buffsend[13] = (unsigned char) atm.tm_min;
1799 send_client(SIZE_HEADER + sizeof(packet_send_date_time), buffsend, pte);
1800 send_month_labels(pte, atm.tm_mon);
1801}
1802
1803static void send_date_time2(struct unistimsession *pte)
1804{
1805 BUFFSEND;
1806 struct timeval now = ast_tvnow();
1807 struct ast_tm atm = { 0, };
1808
1809 if (unistimdebug) {
1810 ast_verb(0, "Sending Time & Date #2\n");
1811 }
1812 memcpy(buffsend + SIZE_HEADER, packet_send_date_time2, sizeof(packet_send_date_time2));
1813 ast_localtime(&now, &atm, NULL);
1814 if (pte->device) {
1815 buffsend[9] = pte->device->datetimeformat;
1816 } else {
1817 buffsend[9] = 61;
1818 }
1819 buffsend[14] = (unsigned char) atm.tm_mon + 1;
1820 buffsend[15] = (unsigned char) atm.tm_mday;
1821 buffsend[16] = (unsigned char) atm.tm_hour;
1822 buffsend[17] = (unsigned char) atm.tm_min;
1823 send_client(SIZE_HEADER + sizeof(packet_send_date_time2), buffsend, pte);
1824}
1825
1826static void send_date_time3(struct unistimsession *pte)
1827{
1828 BUFFSEND;
1829 struct timeval now = ast_tvnow();
1830 struct ast_tm atm = { 0, };
1831
1832 if (unistimdebug) {
1833 ast_verb(0, "Sending Time & Date #3\n");
1834 }
1835 memcpy(buffsend + SIZE_HEADER, packet_send_date_time3, sizeof(packet_send_date_time3));
1836 ast_localtime(&now, &atm, NULL);
1837 buffsend[10] = (unsigned char) atm.tm_mon + 1;
1838 buffsend[11] = (unsigned char) atm.tm_mday;
1839 buffsend[12] = (unsigned char) atm.tm_hour;
1840 buffsend[13] = (unsigned char) atm.tm_min;
1841 send_client(SIZE_HEADER + sizeof(packet_send_date_time3), buffsend, pte);
1842}
1843
1844static void send_blink_cursor(struct unistimsession *pte)
1845{
1846 BUFFSEND;
1847 if (unistimdebug) {
1848 ast_verb(0, "Sending set blink\n");
1849 }
1851 send_client(SIZE_HEADER + sizeof(packet_send_blink_cursor), buffsend, pte);
1852 return;
1853}
1854
1855/* pos : 0xab (a=0/2/4 = line ; b = row) */
1856static void send_cursor_pos(struct unistimsession *pte, unsigned char pos)
1857{
1858 BUFFSEND;
1859 if (unistimdebug) {
1860 ast_verb(0, "Sending set cursor position\n");
1861 }
1862 memcpy(buffsend + SIZE_HEADER, packet_send_set_pos_cursor,
1864 buffsend[11] = pos;
1865 send_client(SIZE_HEADER + sizeof(packet_send_set_pos_cursor), buffsend, pte);
1866 return;
1867}
1868
1869static void send_charset_update(struct unistimsession *pte, int charset)
1870{
1871 const unsigned char* packet_send_charset;
1872 int packet_size;
1873 BUFFSEND;
1874 if (unistimdebug) {
1875 ast_verb(0, "Sending set default charset\n");
1876 }
1877 if (charset == LANG_DEFAULT) {
1879 }
1880 switch (charset) {
1881 case ISO_8859_2:
1882 packet_send_charset = packet_send_charset_iso_8859_2;
1883 packet_size = sizeof(packet_send_charset_iso_8859_2);
1884 break;
1885 case ISO_8859_4:
1886 packet_send_charset = packet_send_charset_iso_8859_4;
1887 packet_size = sizeof(packet_send_charset_iso_8859_4);
1888 break;
1889 case ISO_8859_5:
1890 packet_send_charset = packet_send_charset_iso_8859_5;
1891 packet_size = sizeof(packet_send_charset_iso_8859_5);
1892 break;
1893 case ISO_2022_JP:
1894 packet_send_charset = packet_send_charset_iso_2022_jp;
1895 packet_size = sizeof(packet_send_charset_iso_2022_jp);
1896 break;
1897 case ISO_8859_1:
1898 default:
1899 packet_send_charset = packet_send_charset_iso_8859_1;
1900 packet_size = sizeof(packet_send_charset_iso_8859_1);
1901 }
1902 memcpy(buffsend + SIZE_HEADER, packet_send_charset, packet_size);
1903 send_client(SIZE_HEADER + packet_size, buffsend, pte);
1904 return;
1905}
1906
1908{
1909 BUFFSEND;
1910 if (unistimdebug) {
1911 ast_verb(0, "ResumeConnectionWithServer received\n");
1912 ast_verb(0, "Sending packet_send_query_mac_address\n");
1913 }
1914 memcpy(buffsend + SIZE_HEADER, packet_send_query_mac_address,
1916 send_client(SIZE_HEADER + sizeof(packet_send_query_mac_address), buffsend, pte);
1917 return;
1918}
1919
1921{
1922 struct unistim_device *d;
1923
1925 d = devices;
1926 while (d) {
1927 if (!strcasecmp(s->macaddr, d->id)) {
1928 /* XXX Deal with IP authentication */
1929 s->device = d;
1930 d->session = s;
1931 d->codec_number = DEFAULT_CODEC;
1932 d->missed_call = 0;
1933 d->receiver_state = STATE_ONHOOK;
1934 break;
1935 }
1936 d = d->next;
1937 }
1939
1940 if (!d) {
1941 return 0;
1942 }
1943
1944 return 1;
1945}
1946
1947static void unistim_line_copy(struct unistim_line *dst, struct unistim_line *src)
1948{
1949 struct ast_format_cap *tmp = src->cap;
1950 memcpy(dst, src, sizeof(*dst)); /* this over writes the cap ptr, so we have to reset it */
1951 src->cap = tmp;
1953}
1954
1956{
1957 if (!l) {
1958 return NULL;
1959 }
1960 ao2_ref(l->cap, -1);
1961 ast_free(l);
1962 return NULL;
1963}
1964
1966{
1967 struct unistim_line *l;
1968 if (!(l = ast_calloc(1, sizeof(*l)))) {
1969 return NULL;
1970 }
1971
1973 ast_free(l);
1974 return NULL;
1975 }
1976 return l;
1977}
1978
1980 if (unistimdebug) {
1981 ast_debug(1, "Released sub %u of channel %s@%s\n", sub->subtype, sub->parent->name, sub->parent->parent->name);
1982 }
1983 ast_mutex_destroy(&sub->lock);
1984 ast_free(sub);
1985 return 0;
1986}
1987
1989{
1990 struct unistim_subchannel *sub;
1991 if (!(sub = ast_calloc(1, sizeof(*sub)))) {
1992 return NULL;
1993 }
1994
1995 if (unistimdebug) {
1996 ast_verb(3, "Allocating UNISTIM subchannel #%d on %s ptr=%p\n", x, d->name, sub);
1997 }
1998 sub->ss_thread = AST_PTHREADT_NULL;
1999 sub->subtype = x;
2000 AST_LIST_LOCK(&d->subs);
2001 AST_LIST_INSERT_TAIL(&d->subs, sub, list);
2002 AST_LIST_UNLOCK(&d->subs);
2003 ast_mutex_init(&sub->lock);
2004 return sub;
2005}
2006
2008{
2009 struct unistim_subchannel *s;
2010
2011 AST_LIST_LOCK(&d->subs);
2012 AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, s, list) {
2013 if (!s) {
2014 continue;
2015 }
2016 if (s != sub) {
2017 continue;
2018 }
2021 }
2023 AST_LIST_UNLOCK(&d->subs);
2024 return 0;
2025}
2026
2027static const char *subtype_tostr(const int type)
2028{
2029 switch (type) {
2030 case SUB_REAL:
2031 return "REAL";
2032 case SUB_RING:
2033 return "RINGING";
2034 case SUB_THREEWAY:
2035 return "THREEWAY";
2036 }
2037 return "UNKNOWN";
2038}
2039
2040static const char *ptestate_tostr(const int type)
2041{
2042 switch (type) {
2043 case STATE_INIT:
2044 return "INIT";
2045 case STATE_AUTHDENY:
2046 return "AUTHDENY";
2047 case STATE_MAINPAGE:
2048 return "MAINPAGE";
2049 case STATE_EXTENSION:
2050 return "EXTENSION";
2051 case STATE_DIALPAGE:
2052 return "DIALPAGE";
2053 case STATE_RINGING:
2054 return "RINGING";
2055 case STATE_CALL:
2056 return "CALL";
2057 case STATE_SELECTOPTION:
2058 return "SELECTOPTION";
2059 case STATE_SELECTCODEC:
2060 return "SELECTCODEC";
2062 return "SELECTLANGUAGE";
2063 case STATE_CLEANING:
2064 return "CLEARING";
2065 case STATE_HISTORY:
2066 return "HISTORY";
2067 }
2068 return "UNKNOWN";
2069}
2070
2071static void rcv_mac_addr(struct unistimsession *pte, const unsigned char *buf)
2072{
2073 BUFFSEND;
2074 int tmp, i = 0;
2075 char addrmac[19];
2076 int res = 0;
2077 for (tmp = 15; tmp < 15 + SIZE_HEADER; tmp++) {
2078 sprintf(&addrmac[i], "%02hhx", buf[tmp]);
2079 i += 2;
2080 }
2081 if (unistimdebug) {
2082 ast_verb(0, "MAC Address received: %s\n", addrmac);
2083 }
2084 strcpy(pte->macaddr, addrmac);
2085 res = unistim_register(pte);
2086 if (!res) {
2087 switch (autoprovisioning) {
2089 ast_log(LOG_WARNING, "No entry found for this phone : %s\n", addrmac);
2090 pte->state = STATE_AUTHDENY;
2091 break;
2093 {
2094 struct unistim_device *d = NULL, *newd = NULL;
2095 struct unistim_line *newl = NULL, *l = NULL;
2096 if (unistimdebug) {
2097 ast_verb(0, "New phone, autoprovisioning on\n");
2098 }
2099 /* First : locate the [template] section */
2101 d = devices;
2102 while (d) {
2103 if (strcasecmp(d->name, "template")) {
2104 d = d->next;
2105 continue;
2106 }
2107 /* Found, cloning this entry */
2108 if (!(newd = ast_malloc(sizeof(*newd)))) {
2110 return;
2111 }
2112 memcpy(newd, d, sizeof(*newd));
2113 ast_mutex_init(&newd->lock);
2114 newd->lines.first = NULL;
2115 newd->lines.last = NULL;
2116 AST_LIST_LOCK(&d->lines);
2117 AST_LIST_TRAVERSE(&d->lines, l, list) {
2118 if (!(newl = unistim_line_alloc())) {
2119 break;
2120 }
2121 unistim_line_copy(l, newl);
2122 newl->parent = newd;
2123 ast_copy_string(newl->name, l->name, sizeof(newl->name));
2124 snprintf(newl->fullname, sizeof(newl->fullname), "USTM/%s@%s",
2125 newl->name, newd->name);
2126 snprintf(l->name, sizeof(l->name), "%d", atoi(l->name) + 1);
2127
2128 AST_LIST_LOCK(&newd->lines);
2129 AST_LIST_INSERT_TAIL(&newd->lines, newl, list);
2130 AST_LIST_UNLOCK(&newd->lines);
2131 }
2132 AST_LIST_UNLOCK(&d->lines);
2133 if (!newl) {
2134 ast_free(newd);
2136 }
2137
2138 /* Ok, now updating some fields */
2139 ast_copy_string(newd->id, addrmac, sizeof(newd->id));
2140 ast_copy_string(newd->name, addrmac, sizeof(newd->name));
2141 if (newd->extension == EXTENSION_NONE) {
2142 newd->extension = EXTENSION_ASK;
2143 }
2144
2145 newd->receiver_state = STATE_ONHOOK;
2146 newd->session = pte;
2147 newd->language[0] = '\0';
2148 newd->to_delete = -1;
2149 newd->next = NULL;
2150 pte->device = newd;
2151
2152 /* Go to the end of the linked chain */
2153 while (d->next) {
2154 d = d->next;
2155 }
2156 d->next = newd;
2157 d = newd;
2158 break;
2159 }
2161 if (!d) {
2162 ast_log(LOG_WARNING, "No entry [template] found in unistim.conf\n");
2163 pte->state = STATE_AUTHDENY;
2164 }
2165 }
2166 break;
2168 pte->state = STATE_AUTHDENY;
2169 break;
2170 default:
2171 ast_log(LOG_WARNING, "Internal error : unknown autoprovisioning value = %u\n",
2173 }
2174 }
2175 if (pte->state != STATE_AUTHDENY) {
2176 struct unistim_line *line;
2177 struct unistim_subchannel *sub;
2178
2179 ast_verb(3, "Device '%s' successfuly registered\n", pte->device->name);
2180
2181 AST_LIST_LOCK(&pte->device->subs);
2183 if (sub) {
2184 ast_log(LOG_ERROR, "Subchannel lost sice reboot. Hanged channel may apear!\n");
2186 ast_free(sub);
2187 }
2188 }
2190 AST_LIST_UNLOCK(&pte->device->subs);
2191
2192 switch (pte->device->extension) {
2193 case EXTENSION_NONE:
2194 pte->state = STATE_MAINPAGE;
2195 break;
2196 case EXTENSION_ASK:
2197 /* Checking if we already have an extension number */
2199 pte->state = STATE_EXTENSION;
2200 } else {
2201 /* Yes, because of a phone reboot. We don't ask again for the TN */
2202 if (register_extension(pte)) {
2203 pte->state = STATE_EXTENSION;
2204 } else {
2205 pte->state = STATE_MAINPAGE;
2206 }
2207 }
2208 break;
2209 case EXTENSION_LINE:
2210 line = AST_LIST_FIRST(&pte->device->lines);
2212 sizeof(pte->device->extension_number));
2213 if (register_extension(pte)) {
2214 pte->state = STATE_EXTENSION;
2215 } else {
2216 pte->state = STATE_MAINPAGE;
2217 }
2218 break;
2219 case EXTENSION_TN:
2220 /* If we are here, it's because of a phone reboot */
2221 pte->state = STATE_MAINPAGE;
2222 break;
2223 default:
2224 ast_log(LOG_WARNING, "Internal error, extension value unknown : %u\n",
2225 pte->device->extension);
2226 pte->state = STATE_AUTHDENY;
2227 break;
2228 }
2229 }
2230 if (pte->state == STATE_EXTENSION) {
2231 if (pte->device->extension != EXTENSION_TN) {
2233 }
2234 pte->device->extension_number[0] = '\0';
2235 }
2236 if (unistimdebug) {
2237 ast_verb(0, "\nSending S1\n");
2238 }
2239 memcpy(buffsend + SIZE_HEADER, packet_send_S1, sizeof(packet_send_S1));
2240 send_client(SIZE_HEADER + sizeof(packet_send_S1), buffsend, pte);
2241
2242 if (unistimdebug) {
2243 ast_verb(0, "Sending query_basic_manager_04\n");
2244 }
2248
2249 if (unistimdebug) {
2250 ast_verb(0, "Sending query_basic_manager_10\n");
2251 }
2255
2256 send_date_time(pte);
2257 return;
2258}
2259
2260static int write_entry_history(struct unistimsession *pte, FILE * f, char c, char *line1)
2261{
2262 if (fwrite(&c, 1, 1, f) != 1) {
2263 display_last_error("Unable to write history log header.");
2264 return -1;
2265 }
2266 if (fwrite(line1, TEXT_LENGTH_MAX, 1, f) != 1) {
2267 display_last_error("Unable to write history entry - date.");
2268 return -1;
2269 }
2270 if (fwrite(pte->device->lst_cid, TEXT_LENGTH_MAX, 1, f) != 1) {
2271 display_last_error("Unable to write history entry - callerid.");
2272 return -1;
2273 }
2274 if (fwrite(pte->device->lst_cnm, TEXT_LENGTH_MAX, 1, f) != 1) {
2275 display_last_error("Unable to write history entry - callername.");
2276 return -1;
2277 }
2278 return 0;
2279}
2280
2281static int write_history(struct unistimsession *pte, char way, char ismissed)
2282{
2284 char line1[TEXT_LENGTH_MAX + 1];
2285 char count = 0, *histbuf;
2286 int size;
2287 FILE *f, *f2;
2288 struct timeval now = ast_tvnow();
2289 struct ast_tm atm = { 0, };
2290
2291 if (!pte->device) {
2292 return -1;
2293 }
2294 if (!pte->device->callhistory) {
2295 return 0;
2296 }
2297 if (strchr(pte->device->name, '/') || (pte->device->name[0] == '.')) {
2298 ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n",
2299 pte->device->name);
2300 return -1;
2301 }
2302
2303 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_LOG_DIR, USTM_LOG_DIR);
2304 if (ast_mkdir(tmp, 0770)) {
2305 ast_log(LOG_WARNING, "Unable to create directory for history\n");
2306 return -1;
2307 }
2308
2309 ast_localtime(&now, &atm, NULL);
2310 if (ismissed) {
2311 if (way == 'i') {
2312 ast_copy_string(tmp2, ustmtext("Miss", pte), sizeof(tmp2));
2313 } else {
2314 ast_copy_string(tmp2, ustmtext("Fail", pte), sizeof(tmp2));
2315 }
2316 } else {
2317 ast_copy_string(tmp2, ustmtext("Answ", pte), sizeof(tmp2));
2318 }
2319 snprintf(line1, sizeof(line1), "%04d/%02d/%02d %02d:%02d:%02d %s",
2320 atm.tm_year + 1900, atm.tm_mon + 1, atm.tm_mday, atm.tm_hour,
2321 atm.tm_min, atm.tm_sec, tmp2);
2322
2323 snprintf(tmp, sizeof(tmp), "%s/%s/%s-%c.csv", ast_config_AST_LOG_DIR,
2324 USTM_LOG_DIR, pte->device->name, way);
2325 if ((f = fopen(tmp, "r"))) {
2326 struct stat bufstat;
2327
2328 if (stat(tmp, &bufstat)) {
2329 display_last_error("Unable to stat history log.");
2330 fclose(f);
2331 return -1;
2332 }
2333 size = 1 + (MAX_ENTRY_LOG * TEXT_LENGTH_MAX * 3);
2334 if (bufstat.st_size != size) {
2336 "History file %s has an incorrect size (%d instead of %d). It will be replaced by a new one.",
2337 tmp, (int) bufstat.st_size, size);
2338 fclose(f);
2339 f = NULL;
2340 count = 1;
2341 }
2342 }
2343
2344 /* If we can't open the log file, we create a brand new one */
2345 if (!f) {
2346 char c = 1;
2347 int i;
2348
2349 if ((errno != ENOENT) && (count == 0)) {
2350 display_last_error("Unable to open history log.");
2351 return -1;
2352 }
2353 f = fopen(tmp, "w");
2354 if (!f) {
2355 display_last_error("Unable to create history log.");
2356 return -1;
2357 }
2358 if (write_entry_history(pte, f, c, line1)) {
2359 fclose(f);
2360 return -1;
2361 }
2362 memset(line1, ' ', TEXT_LENGTH_MAX);
2363 for (i = 3; i < MAX_ENTRY_LOG * 3; i++) {
2364 if (fwrite(line1, TEXT_LENGTH_MAX, 1, f) != 1) {
2365 display_last_error("Unable to write history entry - stuffing.");
2366 fclose(f);
2367 return -1;
2368 }
2369 }
2370 if (fclose(f)) {
2371 display_last_error("Unable to close history - creation.");
2372 }
2373 return 0;
2374 }
2375 /* We can open the log file, we create a temporary one, we add our entry and copy the rest */
2376 if (fread(&count, 1, 1, f) != 1) {
2377 display_last_error("Unable to read history header.");
2378 fclose(f);
2379 return -1;
2380 }
2381 if (count > MAX_ENTRY_LOG) {
2382 ast_log(LOG_WARNING, "Invalid count in history header of %s (%d max %d)\n", tmp,
2383 count, MAX_ENTRY_LOG);
2384 fclose(f);
2385 return -1;
2386 }
2387 snprintf(tmp2, sizeof(tmp2), "%s/%s/%s-%c.csv.tmp", ast_config_AST_LOG_DIR,
2388 USTM_LOG_DIR, pte->device->name, way);
2389 if (!(f2 = fopen(tmp2, "w"))) {
2390 display_last_error("Unable to create temporary history log.");
2391 fclose(f);
2392 return -1;
2393 }
2394
2395 if (++count > MAX_ENTRY_LOG) {
2396 count = MAX_ENTRY_LOG;
2397 }
2398 if (write_entry_history(pte, f2, count, line1)) {
2399 fclose(f);
2400 fclose(f2);
2401 return -1;
2402 }
2403 size = (MAX_ENTRY_LOG - 1) * TEXT_LENGTH_MAX * 3;
2404 if (!(histbuf = ast_malloc(size))) {
2405 fclose(f);
2406 fclose(f2);
2407 return -1;
2408 }
2409
2410 if (fread(histbuf, size, 1, f) != 1) {
2411 ast_free(histbuf);
2412 fclose(f);
2413 fclose(f2);
2414 display_last_error("Unable to read previous history entries.");
2415 return -1;
2416 }
2417 if (fwrite(histbuf, size, 1, f2) != 1) {
2418 ast_free(histbuf);
2419 fclose(f);
2420 fclose(f2);
2421 display_last_error("Unable to write previous history entries.");
2422 return -1;
2423 }
2424 ast_free(histbuf);
2425 if (fclose(f)) {
2426 display_last_error("Unable to close history log.");
2427 }
2428 if (fclose(f2)) {
2429 display_last_error("Unable to close temporary history log.");
2430 }
2431 if (unlink(tmp)) {
2432 display_last_error("Unable to remove old history log.");
2433 }
2434 if (rename(tmp2, tmp)) {
2435 display_last_error("Unable to rename new history log.");
2436 }
2437 return 0;
2438}
2439
2441{
2442 RAII_VAR(struct ast_channel *, chana, NULL, ast_channel_unref);
2443 RAII_VAR(struct ast_channel *, chanb, NULL, ast_channel_unref);
2444
2445 if (!p1->owner || !p2->owner) {
2446 ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n");
2447 return -1;
2448 }
2449 chana = ast_channel_ref(p1->owner);
2450 chanb = ast_channel_ref(p2->owner);
2451
2452 switch (ast_bridge_transfer_attended(chana, chanb)) {
2454 ast_log(LOG_WARNING, "Transfer failed. Invalid bridge setup\n");
2455 break;
2457 ast_log(LOG_WARNING, "Transfer not permitted\n");
2458 break;
2460 ast_log(LOG_WARNING, "Transfer encountered internal error\n");
2461 break;
2463 return 0;
2464 }
2465
2466 /* Control only reaches this point if transfer has failed */
2469 return -1;
2470}
2471
2472void change_callerid(struct unistimsession *pte, int type, char *callerid)
2473{
2474 char *data;
2475 int size;
2476
2477 if (type) {
2478 data = pte->device->lst_cnm;
2479 } else {
2480 data = pte->device->lst_cid;
2481 }
2482
2483 /* This is very nearly strncpy(), except that the remaining buffer
2484 * is padded with ' ', instead of '\0' */
2485 memset(data, ' ', TEXT_LENGTH_MAX);
2486 size = strlen(callerid);
2487 if (size > TEXT_LENGTH_MAX) {
2488 size = TEXT_LENGTH_MAX;
2489 }
2490 memcpy(data, callerid, size);
2491}
2492
2493static struct unistim_subchannel* get_sub(struct unistim_device *device, int type)
2494{
2495 struct unistim_subchannel *sub = NULL;
2496
2497 AST_LIST_LOCK(&device->subs);
2498 AST_LIST_TRAVERSE(&device->subs, sub, list) {
2499 if (!sub) {
2500 continue;
2501 }
2502 if (sub->subtype == type) {
2503 break;
2504 }
2505 }
2506 AST_LIST_UNLOCK(&device->subs);
2507
2508 return sub;
2509}
2510
2511static struct unistim_subchannel* get_sub_holding(struct unistim_device *device, int type, int holding)
2512{
2513 struct unistim_subchannel *sub = NULL;
2514
2515 AST_LIST_LOCK(&device->subs);
2516 AST_LIST_TRAVERSE(&device->subs, sub, list) {
2517 if (!sub) {
2518 continue;
2519 }
2520 if (sub->subtype == type && sub->holding == holding) {
2521 break;
2522 }
2523 }
2524 AST_LIST_UNLOCK(&device->subs);
2525
2526 return sub;
2527}
2528
2530{
2531 /* Silence our channel */
2532 if (!pte->device->silence_generator) {
2535 if (pte->device->silence_generator == NULL) {
2536 ast_log(LOG_WARNING, "Unable to start a silence generator.\n");
2537 } else if (unistimdebug) {
2538 ast_verb(0, "Starting silence generator\n");
2539 }
2540 }
2541
2542}
2543
2545{
2546 /* Stop the silence generator */
2547 if (pte->device->silence_generator) {
2548 if (unistimdebug) {
2549 ast_verb(0, "Stopping silence generator\n");
2550 }
2551 if (sub->owner) {
2553 } else {
2554 ast_log(LOG_WARNING, "Trying to stop silence generator on a null channel!\n");
2555 }
2557 }
2558}
2559
2560static void sub_hold(struct unistimsession *pte, struct unistim_subchannel *sub)
2561{
2562 if (!sub) {
2563 return;
2564 }
2565 sub->moh = 1;
2566 sub->holding = 1;
2569 send_stop_timer(pte);
2570 if (sub->owner) {
2571 ast_queue_hold(sub->owner, NULL);
2572 }
2573 return;
2574}
2575
2576static void sub_unhold(struct unistimsession *pte, struct unistim_subchannel *sub)
2577{
2578 struct unistim_subchannel *sub_real;
2579
2580 sub_real = get_sub(pte->device, SUB_REAL);
2581 if (sub_real) {
2582 sub_hold(pte, sub_real);
2583 }
2584
2585 sub->moh = 0;
2586 sub->holding = 0;
2589 send_start_timer(pte);
2590 if (sub->owner) {
2591 ast_queue_unhold(sub->owner);
2592 if (sub->rtp) {
2594 }
2595 }
2596 return;
2597}
2598
2599static void close_call(struct unistimsession *pte)
2600{
2601 struct unistim_subchannel *sub, *sub_transf;
2602
2603 sub = get_sub(pte->device, SUB_REAL);
2604 sub_transf = get_sub(pte->device, SUB_THREEWAY);
2605 send_stop_timer(pte);
2606 if (!sub) {
2607 ast_log(LOG_WARNING, "Close call without sub\n");
2608 return;
2609 }
2610 send_favorite_short(sub->softkey, FAV_LINE_ICON, pte);
2611 if (sub->owner) {
2612 sub->alreadygone = 1;
2613 if (sub_transf) {
2614 sub_transf->alreadygone = 1;
2615 if (attempt_transfer(sub, sub_transf) < 0) {
2616 ast_verb(0, "attempt_transfer failed.\n");
2617 }
2618 } else {
2619 ast_queue_hangup(sub->owner);
2620 }
2621 } else {
2622 if (sub_transf) {
2623 if (sub_transf->owner) {
2625 } else {
2626 ast_log(LOG_WARNING, "threeway sub without owner\n");
2627 }
2628 } else {
2629 ast_verb(0, "USTM(%s@%s-%d) channel already destroyed\n", sub->parent->name,
2630 pte->device->name, sub->softkey);
2631 }
2632 }
2633 change_callerid(pte, 0, pte->device->redial_number);
2634 change_callerid(pte, 1, "");
2635 write_history(pte, 'o', pte->device->missed_call);
2636 pte->device->missed_call = 0;
2637 show_main_page(pte);
2638 return;
2639}
2640
2641static void ignore_call(struct unistimsession *pte)
2642{
2643 send_no_ring(pte);
2644 return;
2645}
2646
2647static void discard_call(struct unistimsession *pte)
2648{
2649 struct unistim_subchannel* sub;
2650 sub = get_sub(pte->device, SUB_RING);
2651 if (!sub) {
2652 return;
2653 }
2654
2656 return;
2657}
2658
2659static void *unistim_ss(void *data)
2660{
2661 struct ast_channel *chan = data;
2663 struct unistim_line *l = sub->parent;
2664 struct unistimsession *s = l->parent->session;
2665 int res;
2666
2667 if (!s) {
2668 return NULL;
2669 }
2670 ast_verb(3, "Starting switch on '%s@%s-%d' to %s\n", l->name, l->parent->name, sub->softkey, s->device->phone_number);
2671 ast_channel_lock(chan);
2674 ast_channel_unlock(chan);
2676 sizeof(s->device->redial_number));
2677 res = ast_pbx_run(chan);
2678 if (res) {
2679 ast_log(LOG_WARNING, "PBX exited non-zero\n");
2680 send_tone(s, 1000, 0);
2681 }
2682 return NULL;
2683}
2684
2686{
2687 struct unistim_subchannel *sub = NULL;
2688 int rtp_start = s->parent->parent->rtp_port;
2689 struct ast_sockaddr us_tmp;
2690 struct sockaddr_in us = { 0, };
2691
2693 AST_LIST_TRAVERSE(&s->parent->parent->subs, sub, list) {
2694 if (!sub) {
2695 continue;
2696 }
2697 if (sub->rtp) {
2699 ast_sockaddr_to_sin(&us_tmp, &us);
2700 if (htons(us.sin_port)) {
2701 rtp_start = htons(us.sin_port) + 1;
2702 break;
2703 }
2704 }
2705 }
2707 return rtp_start;
2708}
2709
2711{
2712 BUFFSEND;
2713
2714 int codec;
2715 struct sockaddr_in public = { 0, };
2716 struct sockaddr_in us = { 0, };
2717 struct sockaddr_in sin = { 0, };
2718 struct ast_sockaddr us_tmp;
2719 struct ast_sockaddr sin_tmp;
2720 struct unistimsession *pte;
2721
2723 ast_sockaddr_to_sin(&us_tmp, &us);
2725 ast_sockaddr_to_sin(&sin_tmp, &sin);
2726
2727 /* Setting up RTP of the phone */
2728 if (public_ip.sin_family == 0) { /* NAT IP override ? */
2729 memcpy(&public, &us, sizeof(public)); /* No defined, using IP from recvmsg */
2730 } else {
2731 memcpy(&public, &public_ip, sizeof(public)); /* override */
2732 }
2733 if (unistimdebug) {
2734 ast_verb(0, "RTP started : Our IP/port is : %s:%hd with codec %s\n",
2735 ast_inet_ntoa(us.sin_addr),
2736 htons(us.sin_port), ast_format_get_name(ast_channel_readformat(sub->owner)));
2737 ast_verb(0, "Starting phone RTP stack. Our public IP is %s\n",
2738 ast_inet_ntoa(public.sin_addr));
2739 }
2740
2741 pte = sub->parent->parent->session;
2743 1, ast_channel_readformat(sub->owner), 0);
2746 if (unistimdebug) {
2747 ast_verb(0, "Sending packet_send_rtp_packet_size for codec %d\n", codec);
2748 }
2749 memcpy(buffsend + SIZE_HEADER, packet_send_rtp_packet_size,
2751 buffsend[10] = (int) codec & 0xffffffffLL;
2752 send_client(SIZE_HEADER + sizeof(packet_send_rtp_packet_size), buffsend, pte);
2753 }
2754 if (unistimdebug) {
2755 ast_verb(0, "Sending Jitter Buffer Parameters Configuration\n");
2756 }
2759 send_client(SIZE_HEADER + sizeof(packet_send_jitter_buffer_conf), buffsend, pte);
2760 if (pte->device->rtp_method != 0) {
2761 uint16_t rtcpsin_port = ntohs(us.sin_port) + 1; /* RTCP port is RTP + 1 */
2762
2763 if (unistimdebug) {
2764 ast_verb(0, "Sending OpenAudioStreamTX using method #%d\n", pte->device->rtp_method);
2765 }
2766 if (pte->device->rtp_method == 3) {
2769 } else {
2772 }
2773 if (pte->device->rtp_method != 2) {
2774 memcpy(buffsend + 28, &public.sin_addr, sizeof(public.sin_addr));
2775 put_unaligned_uint16(&buffsend[20], sin.sin_port);
2776 put_unaligned_uint16(&buffsend[22], htons(rtcpsin_port));
2777 put_unaligned_uint16(&buffsend[24], us.sin_port);
2778 put_unaligned_uint16(&buffsend[26], htons(rtcpsin_port));
2779 } else {
2780 memcpy(buffsend + 23, &public.sin_addr, sizeof(public.sin_addr));
2781 put_unaligned_uint16(&buffsend[15], sin.sin_port);
2782 put_unaligned_uint16(&buffsend[19], us.sin_port);
2783 }
2784 buffsend[11] = codec; /* rx */
2785 buffsend[12] = codec; /* tx */
2787
2788 if (unistimdebug) {
2789 ast_verb(0, "Sending OpenAudioStreamRX\n");
2790 }
2791 if (pte->device->rtp_method == 3) {
2794 } else {
2797 }
2798 if (pte->device->rtp_method != 2) {
2799 memcpy(buffsend + 28, &public.sin_addr, sizeof(public.sin_addr));
2800 put_unaligned_uint16(&buffsend[20], sin.sin_port);
2801 put_unaligned_uint16(&buffsend[22], htons(rtcpsin_port));
2802 put_unaligned_uint16(&buffsend[24], us.sin_port);
2803 put_unaligned_uint16(&buffsend[26], htons(rtcpsin_port));
2804 } else {
2805 memcpy(buffsend + 23, &public.sin_addr, sizeof(public.sin_addr));
2806 put_unaligned_uint16(&buffsend[15], sin.sin_port);
2807 put_unaligned_uint16(&buffsend[19], us.sin_port);
2808 }
2809 buffsend[11] = codec; /* rx */
2810 buffsend[12] = codec; /* tx */
2812 } else {
2813 uint16_t rtcpsin_port = htons(us.sin_port) + 1; /* RTCP port is RTP + 1 */
2814
2815 if (unistimdebug) {
2816 ast_verb(0, "Sending packet_send_call default method\n");
2817 }
2818
2819 memcpy(buffsend + SIZE_HEADER, packet_send_call, sizeof(packet_send_call));
2820 memcpy(buffsend + 53, &public.sin_addr, sizeof(public.sin_addr));
2821 /* Destination port when sending RTP */
2822 put_unaligned_uint16(&buffsend[49], us.sin_port);
2823 /* Destination port when sending RTCP */
2824 put_unaligned_uint16(&buffsend[51], htons(rtcpsin_port));
2825 /* Codec */
2826 buffsend[40] = codec;
2827 buffsend[41] = codec;
2829 buffsend[42] = 1; /* 1 = 20ms (160 bytes), 2 = 40ms (320 bytes) */
2831 buffsend[42] = 1; /* 1 = 20ms (160 bytes), 2 = 40ms (320 bytes) */
2833 buffsend[42] = 2; /* 1 = 30ms (24 bytes), 2 = 60 ms (48 bytes) */
2835 buffsend[42] = 2; /* 1 = 10ms (10 bytes), 2 = 20ms (20 bytes) */
2836 } else {
2837 ast_log(LOG_WARNING, "Unsupported codec %s!\n",
2839 }
2840 /* Source port for transmit RTP and Destination port for receiving RTP */
2841 put_unaligned_uint16(&buffsend[45], sin.sin_port);
2842 put_unaligned_uint16(&buffsend[47], htons(rtcpsin_port));
2843 send_client(SIZE_HEADER + sizeof(packet_send_call), buffsend, pte);
2844 }
2845}
2846
2848{
2849 struct sockaddr_in sin = { 0, };
2850 struct sockaddr_in sout = { 0, };
2851 struct ast_sockaddr sin_tmp;
2852 struct ast_sockaddr sout_tmp;
2853
2854 /* Sanity checks */
2855 if (!sub) {
2856 ast_log(LOG_WARNING, "start_rtp with a null subchannel !\n");
2857 return;
2858 }
2859 if (!sub->parent) {
2860 ast_log(LOG_WARNING, "start_rtp with a null line!\n");
2861 return;
2862 }
2863 if (!sub->parent->parent) {
2864 ast_log(LOG_WARNING, "start_rtp with a null device!\n");
2865 return;
2866 }
2867 if (!sub->parent->parent->session) {
2868 ast_log(LOG_WARNING, "start_rtp with a null session!\n");
2869 return;
2870 }
2871 if (!sub->owner) {
2872 ast_log(LOG_WARNING, "start_rtp with a null asterisk channel!\n");
2873 return;
2874 }
2875 sout = sub->parent->parent->session->sout;
2876 ast_mutex_lock(&sub->lock);
2877 /* Allocate the RTP */
2878 if (unistimdebug) {
2879 ast_verb(0, "Starting RTP. Bind on %s\n", ast_inet_ntoa(sout.sin_addr));
2880 }
2881 ast_sockaddr_from_sin(&sout_tmp, &sout);
2882 sub->rtp = ast_rtp_instance_new("asterisk", sched, &sout_tmp, NULL);
2883 if (!sub->rtp) {
2884 ast_log(LOG_WARNING, "Unable to create RTP session: %s binaddr=%s\n",
2885 strerror(errno), ast_inet_ntoa(sout.sin_addr));
2886 ast_mutex_unlock(&sub->lock);
2887 return;
2888 }
2893 ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "UNISTIM RTP");
2894 ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, sub->parent->parent->nat);
2895
2896 /* Create the RTP connection */
2897 sin.sin_family = AF_INET;
2898 /* Setting up RTP for our side */
2899 memcpy(&sin.sin_addr, &sub->parent->parent->session->sin.sin_addr,
2900 sizeof(sin.sin_addr));
2901
2902 sin.sin_port = htons(find_rtp_port(sub));
2903 ast_sockaddr_from_sin(&sin_tmp, &sin);
2906 struct ast_format *tmpfmt;
2908
2911 "Our read/writeformat has been changed to something incompatible: %s, using %s best codec from %s\n",
2913 ast_format_get_name(tmpfmt),
2915
2916 ast_channel_set_readformat(sub->owner, tmpfmt);
2917 ast_channel_set_writeformat(sub->owner, tmpfmt);
2918 ao2_ref(tmpfmt, -1);
2919 }
2921 ast_mutex_unlock(&sub->lock);
2922}
2923
2924static void send_dial_tone(struct unistimsession *pte)
2925{
2926 struct ast_tone_zone_sound *ts = NULL;
2927 struct ast_tone_zone_part tone_data;
2928 char *s = NULL;
2929 char *ind;
2930
2931 if ((ts = ast_get_indication_tone(pte->device->tz, "dial"))) {
2932 ind = ast_strdupa(ts->data);
2933 s = strsep(&ind, ",");
2934 ast_tone_zone_part_parse(s, &tone_data);
2935 send_tone(pte, tone_data.freq1, tone_data.freq2);
2936 if (unistimdebug) {
2937 ast_verb(0, "Country code found (%s), freq1=%u freq2=%u\n",
2938 pte->device->tz->country, tone_data.freq1, tone_data.freq2);
2939 }
2941 }
2942}
2943
2944static void show_phone_number(struct unistimsession *pte)
2945{
2946 char tmp[TEXT_LENGTH_MAX + 1];
2947 const char *tmp_number = ustmtext("Number:", pte);
2948 int line, tmp_copy, offset = 0, i;
2949
2950 pte->device->phone_number[pte->device->size_phone_number] = '\0';
2952 offset = pte->device->size_phone_number - MAX_SCREEN_NUMBER - 1;
2953 if (offset > strlen(tmp_number)) {
2954 offset = strlen(tmp_number);
2955 }
2956 tmp_copy = strlen(tmp_number) - offset + 1;
2957 if (tmp_copy > sizeof(tmp)) {
2958 tmp_copy = sizeof(tmp);
2959 }
2960 memcpy(tmp, tmp_number + offset, tmp_copy);
2961 } else {
2962 ast_copy_string(tmp, tmp_number, sizeof(tmp));
2963 }
2964
2965 offset = (pte->device->size_phone_number >= TEXT_LENGTH_MAX) ? (pte->device->size_phone_number - TEXT_LENGTH_MAX +1) : 0;
2966 if (pte->device->size_phone_number) {
2967 memcpy(tmp + strlen(tmp), pte->device->phone_number + offset, pte->device->size_phone_number - offset + 1);
2968 }
2969 offset = strlen(tmp);
2970
2971 for (i = strlen(tmp); i < TEXT_LENGTH_MAX; i++) {
2972 tmp[i] = '.';
2973 }
2974 tmp[i] = '\0';
2975
2976 line = (pte->device->height == 1) ? TEXT_LINE0 : TEXT_LINE2;
2977 send_text(line, TEXT_NORMAL, pte, tmp);
2978 send_blink_cursor(pte);
2979 send_cursor_pos(pte, (unsigned char) (line + offset));
2981}
2982
2983static void handle_dial_page(struct unistimsession *pte)
2984{
2985 pte->state = STATE_DIALPAGE;
2986 if (pte->device->call_forward[0] == -1) {
2987 send_text(TEXT_LINE0, TEXT_NORMAL, pte, "");
2988 send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Enter forward", pte));
2989 send_text_status(pte, ustmtext("Fwd Cancel BackSp Erase", pte));
2990 if (pte->device->call_forward[1] != 0) {
2992 sizeof(pte->device->phone_number));
2993 show_phone_number(pte);
2995 return;
2996 }
2997 } else {
2998 if ((pte->device->output == OUTPUT_HANDSET) &&
2999 (pte->device->receiver_state == STATE_ONHOOK)) {
3001 } else {
3003 }
3004 send_dial_tone(pte);
3005
3006 if (pte->device->height > 1) {
3007 send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Enter the number to dial", pte));
3008 send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("and press Call", pte));
3009 }
3011 send_text_status(pte, ustmtext("Call BackSp Erase", pte));
3012 } else {
3013 send_text_status(pte, ustmtext("Call Redial BackSp Erase", pte));
3014 }
3015 }
3016
3017 pte->device->size_phone_number = 0;
3018 pte->device->phone_number[0] = 0;
3019 show_phone_number(pte);
3022 pte->device->missed_call = 0;
3024 pte->device->lastmsgssent = -1;
3025 return;
3026}
3027
3029{
3030 struct ast_rtp_instance *rtp;
3031 int fds;
3032
3033 if (unistimdebug) {
3034 ast_verb(0, "Swapping %p and %p\n", a, b);
3035 }
3036 if ((!a->owner) || (!b->owner)) {
3038 "Attempted to swap subchannels with a null owner : sub #%p=%p sub #%p=%p\n",
3039 a, a->owner, b, b->owner);
3040 return;
3041 }
3042 rtp = a->rtp;
3043 a->rtp = b->rtp;
3044 b->rtp = rtp;
3045
3046 fds = ast_channel_fd(a->owner, 0);
3047 ast_channel_internal_fd_set(a->owner, 0, ast_channel_fd(b->owner, 0));
3048 ast_channel_internal_fd_set(b->owner, 0, fds);
3049
3050 fds = ast_channel_fd(a->owner, 1);
3051 ast_channel_internal_fd_set(a->owner, 1, ast_channel_fd(b->owner, 1));
3052 ast_channel_internal_fd_set(b->owner, 1, fds);
3053}
3054
3055/* Step 1 : Music On Hold for peer, Dialing screen for us */
3056static void transfer_call_step1(struct unistimsession *pte)
3057{
3058 struct unistim_subchannel *sub /*, *sub_trans */;
3059 struct unistim_device *d = pte->device;
3060
3061 sub = get_sub(d, SUB_REAL);
3062 /* sub_trans = get_sub(d, SUB_THREEWAY); */
3063
3064 if (!sub || !sub->owner) {
3065 ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
3066 return;
3067 }
3068 /* Start music on hold if appropriate */
3069 if (sub->moh) {
3070 ast_log(LOG_WARNING, "Transfer with peer already listening music on hold\n");
3071 } else {
3072 ast_queue_hold(sub->owner, sub->parent->musicclass);
3073 sub->moh = 1;
3074 sub->subtype = SUB_THREEWAY;
3075 }
3076 sub_start_silence(pte, sub);
3077 handle_dial_page(pte);
3078}
3079
3081{
3082 struct unistim_subchannel *sub, *sub_trans;
3083 struct unistim_device *d = pte->device;
3084
3085 sub = get_sub(d, SUB_REAL);
3086 sub_trans = get_sub(d, SUB_THREEWAY);
3087
3088 if (!sub || !sub->owner) {
3089 ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
3090 return;
3091 }
3092 if (sub_trans) {
3093 if (unistimdebug) {
3094 ast_verb(0, "Transfer canceled, hangup our threeway channel\n");
3095 }
3096 if (sub->owner) {
3097 swap_subs(sub, sub_trans);
3098 ast_queue_unhold(sub_trans->owner);
3099 sub_trans->moh = 0;
3100 sub_trans->subtype = SUB_REAL;
3101 sub->subtype = SUB_THREEWAY;
3103 } else {
3104 ast_log(LOG_WARNING, "Canceling a threeway channel without owner\n");
3105 }
3106 return;
3107 }
3108}
3109
3110/* From phone to PBX */
3112{
3113 struct ast_channel *c;
3114 struct unistim_subchannel *sub;
3115 int softkey;
3116
3117 s->state = STATE_CALL;
3118
3120 if (sub) {
3121 /* If sub for threway call created than we use transfer behavior */
3122 struct unistim_subchannel *sub_trans = NULL;
3123 struct unistim_device *d = s->device;
3124
3125 sub_trans = get_sub(d, SUB_REAL);
3126 if (sub_trans) {
3127 ast_log(LOG_WARNING, "Can't transfer while active subchannel exists!\n");
3128 return;
3129 }
3130 if (!sub->owner) {
3131 ast_log(LOG_WARNING, "Unable to find subchannel with music on hold\n");
3132 return;
3133 }
3134
3135 sub_trans = unistim_alloc_sub(d, SUB_REAL);
3136 if (!sub_trans) {
3137 ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
3138 return;
3139 }
3140 sub_trans->parent = sub->parent;
3142 send_tone(s, 0, 0);
3143 /* Make new channel */
3144 c = unistim_new(sub_trans, AST_STATE_DOWN, NULL, NULL);
3145 if (!c) {
3146 ast_log(LOG_WARNING, "Cannot allocate new structure on channel %p\n", sub->parent);
3147 return;
3148 }
3149 /* Swap things around between the three-way and real call */
3150 swap_subs(sub, sub_trans);
3152 if (s->device->height == 1) {
3154 } else {
3155 send_text(TEXT_LINE0, TEXT_NORMAL, s, ustmtext("Calling (pre-transfer)", s));
3157 send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Dialing...", s));
3158 }
3159 send_text_status(s, ustmtext("TransfrCancel", s));
3160
3161 if (ast_pthread_create(&sub->ss_thread, NULL, unistim_ss, c)) {
3162 ast_log(LOG_WARNING, "Unable to start simple switch on channel %p\n", c);
3163 sub->ss_thread = AST_PTHREADT_NULL;
3164 ast_hangup(c);
3165 return;
3166 }
3167 if (unistimdebug) {
3168 ast_verb(0, "Started three way call on channel %p (%s) subchan %u\n",
3169 sub_trans->owner, ast_channel_name(sub_trans->owner), sub_trans->subtype);
3170 }
3171 return;
3172 }
3173
3174 softkey = get_avail_softkey(s, NULL);
3175 if (softkey == -1) {
3176 ast_log(LOG_WARNING, "Have no avail softkey for calling\n");
3177 return;
3178 }
3179 sub = get_sub(s->device, SUB_REAL);
3180 if (sub) { /* have already call assigned */
3181 sub_hold(s, sub); /* Need to put on hold */
3182 }
3183 if (!(sub = unistim_alloc_sub(s->device, SUB_REAL))) {
3184 ast_log(LOG_WARNING, "Unable to allocate subchannel!\n");
3185 return;
3186 }
3187 sub->parent = s->device->sline[softkey];
3188 s->device->ssub[softkey] = sub;
3189 sub->softkey = softkey;
3190
3191 if (unistimdebug) {
3192 ast_verb(0, "Using softkey %d, line %p\n", sub->softkey, sub->parent);
3193 }
3195 s->device->selected = -1;
3196 if (!sub->owner) { /* A call is already in progress ? */
3197 RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
3198 const char *pickupexten;
3199
3200 c = unistim_new(sub, AST_STATE_DOWN, NULL, NULL); /* No, starting a new one */
3201 if (!sub->rtp) { /* Need to start RTP before calling ast_pbx_run */
3202 start_rtp(sub);
3203 }
3204 if (c) {
3207 if (!pickup_cfg) {
3208 ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
3209 pickupexten = "";
3210 } else {
3211 pickupexten = ast_strdupa(pickup_cfg->pickupexten);
3212 }
3214 }
3215 if (c && !strcmp(s->device->phone_number, pickupexten)) {
3216 if (unistimdebug) {
3217 ast_verb(0, "Try to pickup in unistim_new\n");
3218 }
3220 send_text_status(s, ustmtext(" Transf Hangup", s));
3222 if (ast_pickup_call(c)) {
3223 ast_log(LOG_NOTICE, "Nothing to pick up\n");
3225 } else {
3227 }
3228 ast_hangup(c);
3229 c = NULL;
3230 } else if (c) {
3232 send_tone(s, 0, 0); /* Dialing empty number should also stop dial tone */
3233 if (s->device->height == 1) {
3234 if (strlen(s->device->phone_number) > 0) {
3236 } else {
3237 send_text(TEXT_LINE0, TEXT_NORMAL, s, ustmtext("Calling...", s));
3238 }
3239 } else {
3240 send_text(TEXT_LINE0, TEXT_NORMAL, s, ustmtext("Calling :", s));
3242 send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Dialing...", s));
3243 }
3244 send_text_status(s, ustmtext(" Hangup", s));
3245
3246 /* start switch */
3247 if (ast_pthread_create(&sub->ss_thread, NULL, unistim_ss, c)) {
3248 ast_log(LOG_WARNING, "Unable to create switch thread\n");
3249 sub->ss_thread = AST_PTHREADT_NULL;
3251 }
3252 } else
3253 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n",
3254 sub->parent->name, s->device->name);
3255 } else {
3256 ast_debug(1, "Current sub [%s] already has owner\n", ast_channel_name(sub->owner));
3257 }
3258 return;
3259}
3260
3261/* From PBX to phone */
3263{
3264 struct unistim_subchannel *sub = NULL;
3265 int i;
3266
3267 s->state = STATE_CALL;
3268 s->device->missed_call = 0;
3269 send_no_ring(s);
3270 sub = get_sub(s->device, SUB_RING); /* Put other SUB_REAL call on hold */
3271 if (!sub) {
3272 ast_log(LOG_WARNING, "No ringing lines on: %s\n", s->device->name);
3273 return;
3274 }
3275 /* Change icons for all ringing keys */
3276 for (i = 0; i < FAVNUM; i++) {
3277 if (!s->device->ssub[i]) { /* No sub assigned - skip */
3278 continue;
3279 }
3280 if (s->device->ssub[i]->subtype == SUB_REAL) {
3281 sub_hold(s, s->device->ssub[i]);
3282 }
3283 if (s->device->ssub[i] != sub) {
3284 continue;
3285 }
3286 if (sub->softkey == i) { /* If softkey assigned at this moment - do not erase */
3287 continue;
3288 }
3289 if (sub->softkey < 0) { /* If softkey not defined - first one used */
3290 sub->softkey = i;
3291 continue;
3292 }
3294 s->device->ssub[i] = NULL;
3295 }
3296 if (sub->softkey < 0) {
3297 ast_log(LOG_WARNING, "Can not assign softkey for incoming call on: %s\n", s->device->name);
3298 return;
3299 }
3301 sub->parent = s->device->sline[sub->softkey];
3302 sub->subtype = SUB_REAL;
3303 if (unistimdebug) {
3304 ast_verb(0, "Handle Call Incoming for %s@%s\n", sub->parent->name,
3305 s->device->name);
3306 }
3307 start_rtp(sub);
3308 if (!sub->rtp) {
3309 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name, s->device->name);
3310 return;
3311 }
3312 if (sub->owner) {
3314 }
3315 send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("is on-line", s));
3316 send_text_status(s, ustmtext(" Transf Hangup", s));
3318
3319 if ((s->device->output == OUTPUT_HANDSET) &&
3322 } else {
3324 }
3325 write_history(s, 'i', 0);
3326 return;
3327}
3328
3329static int send_dtmf_tone(struct unistimsession *pte, char digit)
3330{
3331 int row, col;
3332
3333 if (unistimdebug) {
3334 ast_verb(0, "Phone Play Digit %c\n", digit);
3335 }
3336 if (pte->device->dtmfduration > 0) {
3337 row = (digit - '1') % 3;
3338 col = (digit - '1' - row) / 3;
3339 if (digit >= '1' && digit <='9') {
3340 send_tone(pte, dtmf_row[row], dtmf_col[col]);
3341 } else if (digit >= 'A' && digit <= 'D') {
3342 send_tone(pte, dtmf_row[digit-'A'], dtmf_col[3]);
3343 } else if (digit == '*') {
3344 send_tone(pte, dtmf_row[3], dtmf_col[0]);
3345 } else if (digit == '0') {
3346 send_tone(pte, dtmf_row[3], dtmf_col[1]);
3347 } else if (digit == '#') {
3348 send_tone(pte, dtmf_row[3], dtmf_col[2]);
3349 } else {
3350 send_tone(pte, 500, 2000);
3351 }
3352 }
3353 return 0;
3354}
3355
3356static int unistim_do_senddigit(struct unistimsession *pte, char digit)
3357{
3358 struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass.integer = digit, .src = "unistim" };
3359 struct unistim_subchannel *sub;
3360
3361 sub = get_sub(pte->device, SUB_REAL);
3362 if (!sub || !sub->owner || sub->alreadygone) {
3363 ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit\n");
3364 return -1;
3365 }
3366
3367 /* Send DTMF indication _before_ playing sounds */
3368 ast_queue_frame(sub->owner, &f);
3369 if (pte->device->dtmfduration > 0) {
3370 if (unistimdebug) {
3371 ast_verb(0, "Send Digit %c (%i ms)\n", digit, pte->device->dtmfduration);
3372 }
3373 send_dtmf_tone(pte, digit);
3374 usleep(pte->device->dtmfduration * 1000); /* XXX Less than perfect, blocking an important thread is not a good idea */
3375 send_tone(pte, 0, 0);
3376 }
3377 return 0;
3378}
3379
3380static void handle_key_fav(struct unistimsession *pte, char keycode)
3381{
3382 int keynum = keycode - KEY_FAV0;
3383 struct unistim_subchannel *sub, *sub_key = NULL;
3384 sub = get_sub_holding(pte->device, SUB_REAL, 0);
3385
3386 /* Make an action on selected favorite key */
3387 if (!pte->device->ssub[keynum]) { /* Key have no assigned call */
3388 sub = get_sub_holding(pte->device, SUB_REAL, 0);
3390 if (is_key_line(pte->device, keynum)) {
3391 if (unistimdebug) {
3392 ast_verb(0, "Handle line w/o sub - dialpage\n");
3393 }
3394 pte->device->selected = keynum;
3395 sub_hold(pte, sub); /* Put active call on hold */
3396 send_stop_timer(pte);
3397 handle_dial_page(pte);
3398 } else if (is_key_favorite(pte->device, keynum)) {
3399 /* Put active call on hold in handle_call_outgoing function, after preparation and
3400 checking if lines available for calling */
3401 if (unistimdebug) {
3402 ast_verb(0, "Handle favorite w/o sub - dialing\n");
3403 }
3404 if ((pte->device->output == OUTPUT_HANDSET) &&
3405 (pte->device->receiver_state == STATE_ONHOOK)) {
3407 } else {
3409 }
3410 key_favorite(pte, keycode);
3411 }
3412 } else {
3413 sub_key = pte->device->ssub[keynum];
3414 /* Favicon have assigned sub, activate it and put current on hold */
3415 if (sub_key->subtype == SUB_REAL && !sub_key->holding) {
3416 sub_hold(pte, sub_key);
3417 show_main_page(pte);
3418 } else if (sub_key->subtype == SUB_REAL && sub_key->holding) {
3419 /* We are going to unhold line (we should put active line on hold, of any) */
3420 if (pte->state == STATE_DIALPAGE){
3421 send_tone(pte, 0, 0);
3422 }
3423 sub_hold(pte, sub);
3424 send_callerid_screen(pte, sub_key);
3425 sub_unhold(pte, sub_key);
3426 pte->state = STATE_CALL;
3427 } else if (sub_key->subtype == SUB_RING) {
3428 sub_hold(pte, sub);
3429 sub_key->softkey = keynum;
3431 }
3432 }
3433}
3434
3435static void key_call(struct unistimsession *pte, char keycode)
3436{
3437 struct unistim_subchannel *sub = get_sub(pte->device, SUB_REAL);
3438 struct unistim_subchannel *sub_3way = get_sub(pte->device, SUB_THREEWAY);
3439
3440 if (!sub) {
3441 return;
3442 }
3443 if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
3444 if (keycode == KEY_SHARP) {
3445 keycode = '#';
3446 } else if (keycode == KEY_STAR) {
3447 keycode = '*';
3448 } else {
3449 keycode -= 0x10;
3450 }
3451 unistim_do_senddigit(pte, keycode);
3452 return;
3453 }
3454 switch (keycode) {
3455 case KEY_FUNC1:
3456 if (sub->owner && ast_channel_state(sub->owner) == AST_STATE_UP) {
3457 if (sub_3way) {
3458 close_call(pte);
3459 }
3460 }
3461 break;
3462 case KEY_FUNC2:
3463 if (sub_3way) {
3465 } else if (ast_channel_state(sub->owner) == AST_STATE_UP) {
3467 }
3468 break;
3469 case KEY_HANGUP:
3470 case KEY_FUNC4:
3471 if (!sub_3way) {
3472 close_call(pte);
3473 }
3474 break;
3475 case KEY_FAV0:
3476 case KEY_FAV1:
3477 case KEY_FAV2:
3478 case KEY_FAV3:
3479 case KEY_FAV4:
3480 case KEY_FAV5:
3481 handle_key_fav(pte, keycode);
3482 break;
3483 case KEY_HEADPHN:
3484 if (pte->device->output == OUTPUT_HEADPHONE) {
3486 } else {
3488 }
3489 break;
3490 case KEY_LOUDSPK:
3491 if (pte->device->output != OUTPUT_SPEAKER)
3493 else
3495 MUTE_OFF);
3496 break;
3497 case KEY_ONHOLD:
3498 if (!sub) {
3499 if(pte->device->ssub[pte->device->selected]) {
3500 sub = pte->device->ssub[pte->device->selected];
3501 } else {
3502 break;
3503 }
3504 }
3505 if (sub->holding) {
3506 sub_unhold(pte, sub);
3507 } else {
3508 sub_hold(pte, sub);
3509 }
3510 break;
3511 }
3512 return;
3513}
3514
3515static void key_ringing(struct unistimsession *pte, char keycode)
3516{
3517 switch (keycode) {
3518 case KEY_FAV0:
3519 case KEY_FAV1:
3520 case KEY_FAV2:
3521 case KEY_FAV3:
3522 case KEY_FAV4:
3523 case KEY_FAV5:
3524 handle_key_fav(pte, keycode);
3525 break;
3526 case KEY_FUNC3:
3527 ignore_call(pte);
3528 break;
3529 case KEY_HANGUP:
3530 case KEY_FUNC4:
3531 discard_call(pte);
3532 break;
3533 case KEY_LOUDSPK:
3536 break;
3537 case KEY_HEADPHN:
3540 break;
3541 case KEY_FUNC1:
3543 break;
3544 }
3545 return;
3546}
3547
3548static void key_favorite(struct unistimsession *pte, char keycode)
3549{
3550 int fav = keycode - KEY_FAV0;
3551 if (!is_key_favorite(pte->device, fav)) {
3552 ast_log(LOG_WARNING, "It's not a favorite key\n");
3553 return;
3554 }
3556 sizeof(pte->device->phone_number));
3558 return;
3559}
3560
3561static void key_dial_page(struct unistimsession *pte, char keycode)
3562{
3564
3565 pte->device->nextdial = 0;
3566 if (keycode == KEY_FUNC3) {
3567 if (pte->device->size_phone_number <= 1) {
3568 keycode = KEY_FUNC4;
3569 } else {
3570 pte->device->size_phone_number -= 2;
3571 keycode = pte->device->phone_number[pte->device->size_phone_number] + 0x10;
3572 }
3573 }
3574 if (keycode == KEY_SHARP && pte->device->sharp_dial == 1) {
3575 keycode = KEY_FUNC1;
3576 }
3577 if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
3578 int i = pte->device->size_phone_number;
3579
3580 if (pte->device->size_phone_number == 0) {
3581 send_tone(pte, 0, 0);
3582 }
3583 if (keycode == KEY_SHARP) {
3584 keycode = '#';
3585 } else if (keycode == KEY_STAR) {
3586 keycode = '*';
3587 } else {
3588 keycode -= 0x10;
3589 }
3590 pte->device->phone_number[i] = keycode;
3591 pte->device->size_phone_number++;
3592 pte->device->phone_number[i + 1] = 0;
3593 show_phone_number(pte);
3594
3597 keycode = KEY_FUNC1;
3598 } else {
3599 if (pte->device->interdigit_timer) {
3601 }
3602 }
3603 }
3604 if (keycode == KEY_FUNC4) {
3605 pte->device->size_phone_number = 0;
3606 show_phone_number(pte);
3607 return;
3608 }
3609
3610 if (pte->device->call_forward[0] == -1) {
3611 if (keycode == KEY_FUNC1) {
3613 sizeof(pte->device->call_forward));
3614 show_main_page(pte);
3615 } else if ((keycode == KEY_FUNC2) || (keycode == KEY_HANGUP)) {
3616 pte->device->call_forward[0] = '\0';
3619 show_main_page(pte);
3620 }
3621 return;
3622 }
3623 switch (keycode) {
3624 case KEY_FUNC2:
3626 break;
3627 }
3629 sizeof(pte->device->phone_number));
3630 case KEY_FUNC1:
3632 break;
3633 case KEY_HANGUP:
3634 if (sub && sub->owner) {
3635 sub_stop_silence(pte, sub);
3636 send_tone(pte, 0, 0);
3637 ast_queue_unhold(sub->owner);
3638 sub->moh = 0;
3639 sub->subtype = SUB_REAL;
3640 pte->state = STATE_CALL;
3641
3642 send_text_status(pte, ustmtext(" Transf Hangup", pte));
3644 } else {
3647 show_main_page(pte);
3648 }
3649 break;
3650 case KEY_FAV0:
3651 case KEY_FAV1:
3652 case KEY_FAV2:
3653 case KEY_FAV3:
3654 case KEY_FAV4:
3655 case KEY_FAV5:
3657 pte->device->selected = -1;
3658 handle_key_fav(pte, keycode);
3659 break;
3660 case KEY_LOUDSPK:
3661 if (pte->device->output == OUTPUT_SPEAKER) {
3662 if (pte->device->receiver_state == STATE_OFFHOOK) {
3664 MUTE_OFF);
3665 } else {
3666 show_main_page(pte);
3667 }
3668 } else {
3670 }
3671 break;
3672 case KEY_HEADPHN:
3673 if (pte->device->output == OUTPUT_HEADPHONE) {
3674 if (pte->device->receiver_state == STATE_OFFHOOK) {
3676 } else {
3677 show_main_page(pte);
3678 }
3679 } else {
3681 }
3682 break;
3683 }
3684 return;
3685}
3686
3687static void handle_select_option(struct unistimsession *pte)
3688{
3689 char tmp[128];
3690
3691 if (pte->state != STATE_SELECTOPTION) {
3693 pte->size_buff_entry = 1;
3694 pte->buff_entry[0] = 0; /* Position in menu */
3695 }
3696 snprintf(tmp, sizeof(tmp), "%d. %s", pte->buff_entry[0] + 1, ustmtext(options_menu[(int)pte->buff_entry[0]].label, pte));
3698 send_text_status(pte, ustmtext("Select Cancel", pte));
3699 return;
3700}
3701
3702static void key_select_option(struct unistimsession *pte, char keycode)
3703{
3704 switch (keycode) {
3705 case KEY_DOWN:
3706 pte->buff_entry[0]++;
3707 if (options_menu[(int)pte->buff_entry[0]].label == NULL) {
3708 pte->buff_entry[0]--;
3709 }
3710 break;
3711 case KEY_UP:
3712 if (pte->buff_entry[0] > 0) {
3713 pte->buff_entry[0]--;
3714 }
3715 break;
3716 case KEY_FUNC1:
3717 options_menu[(int)pte->buff_entry[0]].handle_option(pte);
3718 return;
3719 case KEY_HANGUP:
3720 case KEY_FUNC4:
3721 show_main_page(pte);
3722 return;
3723 }
3724
3726 return;
3727}
3728
3729#define SELECTCODEC_START_ENTRY_POS 15
3730#define SELECTCODEC_MAX_LENGTH 2
3731#define SELECTCODEC_MSG "Codec number : .."
3732static void handle_select_codec(struct unistimsession *pte)
3733{
3734 char buf[30], buf2[6];
3735
3736 pte->state = STATE_SELECTCODEC;
3737 ast_copy_string(buf, ustmtext("Using codec", pte), sizeof(buf));
3738 snprintf(buf2, sizeof(buf2), " %d", pte->device->codec_number);
3739 strcat(buf, buf2);
3740 strcat(buf, " (G711u=0,");
3741
3743 send_text(TEXT_LINE1, TEXT_NORMAL, pte, "G723=4,G711a=8,G729A=18)");
3745 send_blink_cursor(pte);
3747 pte->size_buff_entry = 0;
3748 send_text_status(pte, ustmtext("Select BackSp Erase Cancel", pte));
3749 return;
3750}
3751
3752static void key_select_codec(struct unistimsession *pte, char keycode)
3753{
3754 if (keycode == KEY_FUNC2) {
3755 if (pte->size_buff_entry <= 1) {
3756 keycode = KEY_FUNC3;
3757 } else {
3758 pte->size_buff_entry -= 2;
3759 keycode = pte->buff_entry[pte->size_buff_entry] + 0x10;
3760 }
3761 }
3762 if ((keycode >= KEY_0) && (keycode <= KEY_9)) {
3763 char tmpbuf[] = SELECTCODEC_MSG;
3764 int i = 0;
3765
3767 return;
3768 }
3769 while (i < pte->size_buff_entry) {
3770 tmpbuf[i + SELECTCODEC_START_ENTRY_POS] = pte->buff_entry[i];
3771 i++;
3772 }
3773 tmpbuf[i + SELECTCODEC_START_ENTRY_POS] = keycode - 0x10;
3774 pte->buff_entry[i] = keycode - 0x10;
3775 pte->size_buff_entry++;
3776 send_text(TEXT_LINE2, TEXT_INVERSE, pte, tmpbuf);
3777 send_blink_cursor(pte);
3778 send_cursor_pos(pte,
3779 (unsigned char) (TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS + 1 + i));
3780 return;
3781 }
3782
3783 switch (keycode) {
3784 case KEY_FUNC1:
3785 if (pte->size_buff_entry == 1) {
3786 pte->device->codec_number = pte->buff_entry[0] - 48;
3787 } else if (pte->size_buff_entry == 2) {
3788 pte->device->codec_number =
3789 ((pte->buff_entry[0] - 48) * 10) + (pte->buff_entry[1] - 48);
3790 }
3791 show_main_page(pte);
3792 break;
3793 case KEY_FUNC3:
3794 pte->size_buff_entry = 0;
3796 send_blink_cursor(pte);
3798 break;
3799 case KEY_HANGUP:
3800 case KEY_FUNC4:
3801 show_main_page(pte);
3802 break;
3803 }
3804 return;
3805}
3806
3807static int find_language(const char* lang)
3808{
3809 int i = 0;
3810 while (options_languages[i].lang_short != NULL) {
3811 if(!strcmp(options_languages[i].lang_short, lang)) {
3812 return i;
3813 }
3814 i++;
3815 }
3816 return 0;
3817}
3818
3820{
3821 char tmp_language[40];
3822 struct unistim_languages lang;
3823
3824 if (pte->state != STATE_SELECTLANGUAGE) {
3826 pte->size_buff_entry = 1;
3827 pte->buff_entry[0] = find_language(pte->device->language);
3828 }
3829 lang = options_languages[(int)pte->buff_entry[0]];
3830 ast_copy_string(tmp_language, pte->device->language, sizeof(tmp_language));
3831 ast_copy_string(pte->device->language, lang.lang_short, sizeof(pte->device->language));
3832 send_charset_update(pte, lang.encoding);
3833 send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext(lang.label, pte));
3834
3835 ast_copy_string(pte->device->language, tmp_language, sizeof(pte->device->language));
3837 send_charset_update(pte, lang.encoding);
3838 send_text_status(pte, ustmtext("Select Cancel", pte));
3839 return;
3840}
3841
3842static void key_select_language(struct unistimsession *pte, char keycode)
3843{
3844 switch (keycode) {
3845 case KEY_DOWN:
3846 pte->buff_entry[0]++;
3847 if (options_languages[(int)pte->buff_entry[0]].label == NULL) {
3848 pte->buff_entry[0]--;
3849 }
3850 break;
3851 case KEY_UP:
3852 if (pte->buff_entry[0] > 0) {
3853 pte->buff_entry[0]--;
3854 }
3855 break;
3856 case KEY_FUNC1:
3860 show_main_page(pte);
3861 return;
3862 case KEY_HANGUP:
3863 case KEY_FUNC4:
3865 return;
3866 }
3867
3869 return;
3870}
3871
3872
3873#define SELECTEXTENSION_START_ENTRY_POS 0
3874#define SELECTEXTENSION_MAX_LENGTH 10
3875#define SELECTEXTENSION_MSG ".........."
3876static void show_extension_page(struct unistimsession *pte)
3877{
3878 pte->state = STATE_EXTENSION;
3879
3880 send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Please enter a Terminal", pte));
3881 send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Number (TN) :", pte));
3883 send_blink_cursor(pte);
3885