Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
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"
72 #include "asterisk/musiconhold.h"
73 #include "asterisk/causes.h"
74 #include "asterisk/indications.h"
75 #include "asterisk/pickup.h"
76 #include "asterisk/astobj2.h"
77 #include "asterisk/astdb.h"
79 #include "asterisk/bridge.h"
81 #include "asterisk/format_cache.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 
126 };
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 */
137 };
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 
220 static 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 */
243 static int unistimdebug = 0;
244 static int unistim_port;
246 static int unistim_keepalive;
247 static int unistimsock = -1;
248 
249 static 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 
256 static struct io_context *io;
257 static struct ast_sched_context *sched;
258 static struct sockaddr_in public_ip = { 0, };
259 static unsigned char *buff; /*! Receive buffer address */
260 static 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 
288 };
289 
293 };
294 
295 enum phone_key {
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,
318  KEY_ONHOLD = 0x5b,
319  KEY_HANGUP = 0x5c,
320  KEY_MUTE = 0x5d,
321  KEY_HEADPHN = 0x5e,
322  KEY_LOUDSPK = 0x5f,
323  KEY_FAV0 = 0x60,
324  KEY_FAV1 = 0x61,
325  KEY_FAV2 = 0x62,
326  KEY_FAV3 = 0x63,
327  KEY_FAV4 = 0x64,
328  KEY_FAV5 = 0x65,
329  KEY_COMPUTR = 0x7b,
330  KEY_CONF = 0x7c,
331  KEY_SNDHIST = 0x7d,
332  KEY_RCVHIST = 0x7e,
333  KEY_INDEX = 0x7f
334 };
335 
336 enum charset {
343 };
344 
345 static const int dtmf_row[] = { 697, 770, 852, 941 };
346 static const float dtmf_col[] = { 1209, 1336, 1477, 1633 };
347 
348 struct 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  */
372 struct unistim_line {
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  */
394 static 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 */
409  struct unistim_subchannel *ssub[FAVNUM];
410  struct unistim_line *sline[FAVNUM];
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;
456 } *devices = NULL;
457 
458 static 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 retransmition */
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 */
478 } *sessions = NULL;
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;
490  char *lang_short;
491  int encoding;
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 
506 static const unsigned char packet_rcv_discovery[] =
507  { 0xff, 0xff, 0xff, 0xff, 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 };
508 static const unsigned char packet_send_discovery_ack[] =
509  { 0x00, 0x00, /*Initial Seq (2 bytes) */ 0x00, 0x00, 0x00, 0x01 };
510 
511 static const unsigned char packet_recv_firm_version[] =
512  { 0x00, 0x00, 0x00, 0x13, 0x9a, 0x0a, 0x02 };
513 static const unsigned char packet_recv_it_type[] =
514  { 0x00, 0x00, 0x00, 0x13, 0x9a, 0x04, 0x03 };
515 static const unsigned char packet_recv_pressed_key[] =
516  { 0x00, 0x00, 0x00, 0x13, 0x99, 0x04, 0x00 };
517 static const unsigned char packet_recv_pick_up[] =
518  { 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x04 };
519 static const unsigned char packet_recv_hangup[] =
520  { 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x03 };
521 static const unsigned char packet_recv_r2[] = { 0x00, 0x00, 0x00, 0x13, 0x96, 0x03, 0x03 };
522 
523 /*! Expansion module (i2004 KEM) */
524 static const unsigned char packet_recv_expansion_pressed_key[] =
525  { 0x00, 0x00, 0x00, 0x13, 0x89, 0x04, 0x59 };
526 static const unsigned char packet_send_expansion_next[] = { 0x09, 0x03, 0x17 };
527 static const unsigned char packet_send_expansion_icon[] = { 0x09, 0x06, 0x59, 0x05, /*pos */ 0x47, /*icon */ 0x20 }; /* display an icon in front of the text zone */
528 static 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 */
533 static const unsigned char packet_recv_resume_connection_with_server[] =
534  { 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 };
535 static const unsigned char packet_recv_mac_addr[] =
536  { 0xff, 0xff, 0xff, 0xff, 0x9a, 0x0d, 0x07 /*MacAddr */ };
537 
538 static const unsigned char packet_send_date_time3[] =
539  { 0x11, 0x09, 0x02, 0x02, /*Month */ 0x05, /*Day */ 0x06, /*Hour */ 0x07,
540 /*Minutes */ 0x08, 0x32
541 };
542 static const unsigned char packet_send_date_time[] =
543  { 0x11, 0x09, 0x02, 0x0a, /*Month */ 0x05, /*Day */ 0x06, /*Hour */ 0x07, /*Minutes */
544 0x08, 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 
549 static const unsigned char packet_send_no_ring[] =
550  { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00 };
551 static const unsigned char packet_send_s4[] =
552  { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00, 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff,
553 0x16, 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 };
558 static 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 };
567 static const unsigned char packet_send_stream_based_tone_off[] =
568  { 0x16, 0x05, 0x1c, 0x00, 0x00 };
569 
570 static const unsigned char packet_send_mute[] = { 0x16, 0x05, 0x04, 0x00, 0x00 };
571 #ifdef NOT_USED
572 static const unsigned char packet_send_CloseAudioStreamRX[] = { 0x16, 0x05, 0x31, 0x00, 0xff };
573 static const unsigned char packet_send_CloseAudioStreamTX[] = { 0x16, 0x05, 0x31, 0xff, 0x00 };
574 #endif
575 static const unsigned char packet_send_stream_based_tone_on[] =
576  { 0x16, 0x06, 0x1b, 0x00, 0x00, 0x05 };
577 static const unsigned char packet_send_stream_based_tone_single_freq[] =
578  { 0x16, 0x06, 0x1d, 0x00, 0x01, 0xb8 };
579 static const unsigned char packet_send_stream_based_tone_dual_freq[] =
580  { 0x16, 0x08, 0x1d, 0x00, 0x01, 0xb8, 0x01, 0x5e };
581 static const unsigned char packet_send_select_output[] =
582  { 0x16, 0x06, 0x32, 0xc0, 0x01, 0x00 };
583 
584 static 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 };
592 static 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 };
594 static const unsigned char packet_send_s9[] =
595  { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x19, 0x04, 0x00, 0x10, 0x16, 0x05, 0x1c, 0x00,
596 0x00 };
597 static const unsigned char packet_send_rtp_packet_size[] =
598  { 0x16, 0x08, 0x38, 0x00, 0x00, 0xe0, 0x00, 0xa0 };
599 static 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)
606 static 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 }; */
608 static const unsigned char packet_send_open_audio_stream_rx[] =
609  { 0x16, 0x1a, 0x30, 0x00, 0xff, /* Codec */ 0x00, 0x00, 0x01, 0x00, 0xb8, 0xb8, 0x0e,
610 0x0e, 0x01, /* Port */ 0x14, 0x50, 0x00,
611  0x00, /* Port */ 0x14, 0x50, 0x00, 0x00, /* Dest IP */ 0x0a, 0x93, 0x69, 0x05
612 };
613 static const unsigned char packet_send_open_audio_stream_tx[] =
614  { 0x16, 0x1a, 0x30, 0xff, 0x00, 0x00, /* Codec */ 0x00, 0x01, 0x00, 0xb8, 0xb8, 0x0e,
615 0x0e, 0x01, /* Local port */ 0x14, 0x50,
616  0x00, 0x00, /* Rmt Port */ 0x14, 0x50, 0x00, 0x00, /* Dest IP */ 0x0a, 0x93, 0x69, 0x05
617 };
618 
619 static const unsigned char packet_send_open_audio_stream_rx3[] =
620  { 0x16, 0x1a, 0x30, 0x00, 0xff, /* Codec */ 0x00, 0x00, 0x02, 0x01, 0xb8, 0xb8, 0x06,
621 0x06, 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 };
626 static const unsigned char packet_send_open_audio_stream_tx3[] =
627  { 0x16, 0x1a, 0x30, 0xff, 0x00, 0x00, /* Codec */ 0x00, 0x02, 0x01, 0xb8, 0xb8, 0x06,
628 0x06, 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 
633 static const unsigned char packet_send_arrow[] = { 0x17, 0x04, 0x04, 0x00 };
634 static const unsigned char packet_send_blink_cursor[] = { 0x17, 0x04, 0x10, 0x86 };
635 static 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 };
638 static const unsigned char packet_send_Contrast[] =
639  { 0x17, 0x04, 0x24, /*Contrast */ 0x08 };
640 static 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' };
643 static const unsigned char packet_send_stop_timer[] = { 0x17, 0x05, 0x0b, 0x02, 0x00 };
644 static const unsigned char packet_send_icon[] = { 0x17, 0x05, 0x14, /*pos */ 0x00, /*icon */ 0x25 }; /* display an icon in front of the text zone */
645 static const unsigned char packet_send_S7[] = { 0x17, 0x06, 0x0f, 0x30, 0x07, 0x07 };
646 static const unsigned char packet_send_set_pos_cursor[] =
647  { 0x17, 0x06, 0x10, 0x81, 0x04, /*pos */ 0x20 };
648 
649 static 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' };
652 static unsigned char packet_send_monthlabels_download[] =
653  { 0x17, 0x0a, 0x15, /* Month (3 char) */ '-', '-', '-', '-', '-', '-', 0x20 };
654 static const unsigned char packet_send_favorite[] =
655  { 0x17, 0x0f, 0x19, 0x10, /*pos */ 0x01, /*name */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
656 0x20, 0x20, 0x20, 0x20, /*end_name */ 0x19,
657  0x05, 0x0f, /*pos */ 0x01, /*icone */ 0x00
658 };
659 static const unsigned char packet_send_title[] =
660  { 0x17, 0x10, 0x19, 0x02, /*text */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
661 0x20, 0x20, 0x20, 0x20 /*end_text */ };
662 static const unsigned char packet_send_text[] =
663  { 0x17, 0x1e, 0x1b, 0x04, /*pos */ 0x00, /*inverse */ 0x25, /*text */ 0x20, 0x20,
664 0x20, 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 };
668 static const unsigned char packet_send_status[] =
669  { 0x17, 0x20, 0x19, 0x08, /*text */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
670 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
671  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 /*end_text */
672 };
673 static const unsigned char packet_send_status2[] =
674  { 0x17, 0x0b, 0x19, /* pos [08|28|48|68] */ 0x00, /* text */ 0x20, 0x20, 0x20, 0x20,
675 0x20, 0x20, 0x20 /* end_text */ };
676 
677 /* Multiple character set support */
678 /* ISO-8859-1 - Western European) */
679 static const unsigned char packet_send_charset_iso_8859_1[] =
680  { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x41, 0x1b, 0x00 };
681 /* ISO-8859-2 - Central European) */
682 static const unsigned char packet_send_charset_iso_8859_2[] =
683  { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x42, 0x1b, 0x00 };
684 /* ISO-8859-4 - Baltic) */
685 static const unsigned char packet_send_charset_iso_8859_4[] =
686  { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x44, 0x1b, 0x00 };
687 /* ISO 8859-5 - cyrilic */
688 static const unsigned char packet_send_charset_iso_8859_5[] =
689  { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x4c, 0x1b, 0x00 };
690 /* Japaneese (ISO-2022-JP ?) */
691 static const unsigned char packet_send_charset_iso_2022_jp[] =
692  { 0x17, 0x08, 0x21, 0x1b, 0x29, 0x49, 0x1b, 0x7e };
693 
694 static const unsigned char packet_send_led_update[] = { 0x19, 0x04, 0x00, 0x00 };
695 
696 static const unsigned char packet_send_query_basic_manager_04[] = { 0x1a, 0x04, 0x01, 0x04 };
697 static const unsigned char packet_send_query_mac_address[] = { 0x1a, 0x04, 0x01, 0x08 };
698 static const unsigned char packet_send_query_basic_manager_10[] = { 0x1a, 0x04, 0x01, 0x10 };
699 static const unsigned char packet_send_S1[] = { 0x1a, 0x07, 0x07, 0x00, 0x00, 0x00, 0x13 };
700 
701 static 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 
706 static const char tdesc[] = "UNISTIM Channel Driver";
707 static const char channel_type[] = "USTM";
708 
709 /*! Protos */
710 static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor);
711 static int load_module(void);
712 static int reload(void);
713 static int unload_module(void);
714 static int reload_config(void);
715 static void unistim_set_owner(struct unistim_subchannel *sub, struct ast_channel *chan);
716 static void show_main_page(struct unistimsession *pte);
717 static 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);
719 static int unistim_call(struct ast_channel *ast, const char *dest, int timeout);
720 static int unistim_hangup(struct ast_channel *ast);
721 static int unistim_answer(struct ast_channel *ast);
722 static struct ast_frame *unistim_read(struct ast_channel *ast);
723 static int unistim_write(struct ast_channel *ast, struct ast_frame *frame);
724 static int unistim_indicate(struct ast_channel *ast, int ind, const void *data,
725  size_t datalen);
726 static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
727 static int unistim_senddigit_begin(struct ast_channel *ast, char digit);
728 static int unistim_senddigit_end(struct ast_channel *ast, char digit,
729  unsigned int duration);
730 static int unistim_sendtext(struct ast_channel *ast, const char *text);
731 
732 static int write_entry_history(struct unistimsession *pte, FILE * f, char c,
733  char *line1);
734 static void change_callerid(struct unistimsession *pte, int type, char *callerid);
735 
737  .type = channel_type,
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 
753 static void send_start_rtp(struct unistim_subchannel *);
754 
755 static void send_callerid_screen(struct unistimsession *, struct unistim_subchannel *);
756 static void key_favorite(struct unistimsession *, char);
757 
758 static void handle_select_codec(struct unistimsession *);
759 static void handle_select_language(struct unistimsession *);
760 static int find_language(const char*);
761 
762 static 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 
779 static char ustm_strcopy[1024];
780 
782  const char *str_orig;
783  const char *str_trans;
784 };
785 
786 static 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 
792 static 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 
800 static 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) {
808  lang = &options_languages[find_language(pte->device->language)];
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,
825  USTM_LANG_DIR, lang->lang_short);
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 
889 static 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 
895 static 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 */
903 static 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 
959 static 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 
991 static 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 
1002 static 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 */
1046 static 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 
1080 static 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 
1090 static 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 */
1101 static 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 
1127 static 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 
1137 static 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 
1147 static 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 
1159 static 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 
1167 static 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 */
1180 static 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 
1201 static 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  }
1210  send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_off), buffsend, pte);
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  }
1241  memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_on,
1243  send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_on), buffsend, pte);
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 */
1272 static void
1273 send_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 
1294 static 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 
1299 static void send_favorite_selected(unsigned char status, struct unistimsession *pte) {
1300  if (pte->device->selected != -1) {
1301  send_favorite(pte->device->selected, status, pte, pte->device->softkeylabel[pte->device->selected]);
1302  }
1303  return;
1304 }
1305 
1306 static 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));
1309  send_expansion_next(pte);
1310  return;
1311 }
1312 
1313 static 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 
1321 static 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 
1352 static 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 
1366 static 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 
1380 static int get_active_softkey(struct unistimsession *pte)
1381 {
1382  return pte->device->selected;
1383 }
1384 
1385 static 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 */
1418 static 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 
1445 static 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",
1451  pte->device->extension_number, pte->device->context,
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 
1459 static 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 */
1470 static 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  }
1491  ast_mutex_lock(&s->device->lock);
1492  AST_LIST_LOCK(&s->device->subs);
1493  AST_LIST_TRAVERSE_SAFE_BEGIN(&s->device->subs, sub, list) {
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  }
1507  unistim_free_sub(sub);
1508  }
1509  }
1511  AST_LIST_UNLOCK(&s->device->subs);
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  }
1528  ast_mutex_destroy(&s->lock);
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 */
1538 static 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 */
1578 static 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 
1604 static 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) {
1632  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 
1639 static 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 
1650 static 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 */
1669 static void
1670 send_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,
1680  sizeof(packet_send_select_output));
1681  buffsend[9] = output;
1682  if (output == OUTPUT_SPEAKER && volume == VOLUME_LOW) {
1683  volume = VOLUME_LOW_SPEAKER;
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) {
1697  mute_icon = (mute == MUTE_ON)? FAV_ICON_HEADPHONES_ONHOLD : FAV_ICON_HEADPHONES;
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 }
1719 static 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 
1731 static 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 
1741 static 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 
1757 static void send_idle_clock(struct unistimsession *pte)
1758 {
1759  send_text(TEXT_LINE0, TEXT_NORMAL, pte, "");
1760 }
1761 
1762 static 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  }
1780  send_client(SIZE_HEADER + sizeof(packet_send_monthlabels_download), buffsend, pte);
1781 }
1782 
1783 
1784 static 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 
1803 static 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 
1826 static 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 
1844 static void send_blink_cursor(struct unistimsession *pte)
1845 {
1846  BUFFSEND;
1847  if (unistimdebug) {
1848  ast_verb(0, "Sending set blink\n");
1849  }
1850  memcpy(buffsend + SIZE_HEADER, packet_send_blink_cursor, sizeof(packet_send_blink_cursor));
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) */
1856 static 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,
1863  sizeof(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 
1869 static 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) {
1878  charset = options_languages[find_language(pte->device->language)].encoding;
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 
1920 static int unistim_register(struct unistimsession *s)
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;
1932  d->missed_call = 0;
1934  break;
1935  }
1936  d = d->next;
1937  }
1939 
1940  if (!d) {
1941  return 0;
1942  }
1943 
1944  return 1;
1945 }
1946 
1947 static 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 
1965 static struct unistim_line *unistim_line_alloc(void)
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  }
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);
2013  if (!s) {
2014  continue;
2015  }
2016  if (s != sub) {
2017  continue;
2018  }
2020  unistim_free_sub(sub);
2021  }
2023  AST_LIST_UNLOCK(&d->subs);
2024  return 0;
2025 }
2026 
2027 static 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 
2040 static 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";
2061  case STATE_SELECTLANGUAGE:
2062  return "SELECTLANGUAGE";
2063  case STATE_CLEANING:
2064  return "CLEARING";
2065  case STATE_HISTORY:
2066  return "HISTORY";
2067  }
2068  return "UNKNOWN";
2069 }
2070 
2071 static 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) {
2088  case AUTOPROVISIONING_NO:
2089  ast_log(LOG_WARNING, "No entry found for this phone : %s\n", addrmac);
2090  pte->state = STATE_AUTHDENY;
2091  break;
2092  case AUTOPROVISIONING_YES:
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;
2167  case AUTOPROVISIONING_TN:
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) {
2232  pte->device->extension = EXTENSION_ASK;
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  }
2245  memcpy(buffsend + SIZE_HEADER, packet_send_query_basic_manager_04,
2247  send_client(SIZE_HEADER + sizeof(packet_send_query_basic_manager_04), buffsend, pte);
2248 
2249  if (unistimdebug) {
2250  ast_verb(0, "Sending query_basic_manager_10\n");
2251  }
2252  memcpy(buffsend + SIZE_HEADER, packet_send_query_basic_manager_10,
2254  send_client(SIZE_HEADER + sizeof(packet_send_query_basic_manager_10), buffsend, pte);
2255 
2256  send_date_time(pte);
2257  return;
2258 }
2259 
2260 static 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 
2281 static 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 
2440 static int attempt_transfer(struct unistim_subchannel *p1, struct unistim_subchannel *p2)
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 
2472 void 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 
2493 static 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 
2511 static 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 
2529 static void sub_start_silence(struct unistimsession *pte, struct unistim_subchannel *sub)
2530 {
2531  /* Silence our channel */
2532  if (!pte->device->silence_generator) {
2533  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 
2544 static void sub_stop_silence(struct unistimsession *pte, struct unistim_subchannel *sub)
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  }
2556  pte->device->silence_generator = NULL;
2557  }
2558 }
2559 
2560 static 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;
2568  send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON);
2569  send_stop_timer(pte);
2570  if (sub->owner) {
2571  ast_queue_hold(sub->owner, NULL);
2572  }
2573  return;
2574 }
2575 
2576 static 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;
2588  send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
2589  send_start_timer(pte);
2590  if (sub->owner) {
2591  ast_queue_unhold(sub->owner);
2592  if (sub->rtp) {
2593  send_start_rtp(sub);
2594  }
2595  }
2596  return;
2597 }
2598 
2599 static 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  }
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 
2641 static void ignore_call(struct unistimsession *pte)
2642 {
2643  send_no_ring(pte);
2644  return;
2645 }
2646 
2647 static 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 
2659 static 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 
2685 static int find_rtp_port(struct unistim_subchannel *s)
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 
2722  ast_rtp_instance_get_local_address(sub->rtp, &us_tmp);
2723  ast_sockaddr_to_sin(&us_tmp, &us);
2724  ast_rtp_instance_get_remote_address(sub->rtp, &sin_tmp);
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,
2750  sizeof(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  }
2757  memcpy(buffsend + SIZE_HEADER, packet_send_jitter_buffer_conf,
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 {
2770  memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_tx,
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 */
2786  send_client(SIZE_HEADER + sizeof(packet_send_open_audio_stream_tx), buffsend, pte);
2787 
2788  if (unistimdebug) {
2789  ast_verb(0, "Sending OpenAudioStreamRX\n");
2790  }
2791  if (pte->device->rtp_method == 3) {
2794  } else {
2795  memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_rx,
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 */
2811  send_client(SIZE_HEADER + sizeof(packet_send_open_audio_stream_rx), buffsend, pte);
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 
2847 static void start_rtp(struct unistim_subchannel *sub)
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");
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);
2904  ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
2906  struct ast_format *tmpfmt;
2907  struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
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  }
2920  send_start_rtp(sub);
2921  ast_mutex_unlock(&sub->lock);
2922 }
2923 
2924 static 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  }
2940  ts = ast_tone_zone_sound_unref(ts);
2941  }
2942 }
2943 
2944 static 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 
2983 static 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 {
3002  send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
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  }
3010  if (ast_strlen_zero(pte->device->redial_number)) {
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 
3028 static void swap_subs(struct unistim_subchannel *a, struct unistim_subchannel *b)
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);
3048  ast_channel_internal_fd_set(b->owner, 0, fds);
3049 
3050  fds = ast_channel_fd(a->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 */
3056 static 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 
3080 static void transfer_cancel_step2(struct unistimsession *pte)
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 */
3111 static void handle_call_outgoing(struct unistimsession *s)
3112 {
3113  struct ast_channel *c;
3114  struct unistim_subchannel *sub;
3115  int softkey;
3116 
3117  s->state = STATE_CALL;
3118 
3119  sub = get_sub(s->device, SUB_THREEWAY);
3120  if (sub) {
3121  /* If sub for threway call created than we use transfer behaviuor */
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;
3141  sub_stop_silence(s, sub);
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);
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) {
3205  ast_channel_lock(c);
3206  pickup_cfg = ast_get_chan_features_pickup_config(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  }
3213  ast_channel_unlock(c);
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  }
3219  send_text(TEXT_LINE0, TEXT_NORMAL, s, "");
3220  send_text_status(s, ustmtext(" Transf Hangup", s));
3221  send_start_timer(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");
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 */
3262 static void handle_call_incoming(struct unistimsession *s)
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));
3317  send_start_timer(s);
3318 
3319  if ((s->device->output == OUTPUT_HANDSET) &&
3320  (s->device->receiver_state == STATE_ONHOOK)) {
3322  } else {
3324  }
3325  write_history(s, 'i', 0);
3326  return;
3327 }
3328 
3329 static 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 
3356 static 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 
3380 static 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 {
3408  send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
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;
3430  handle_call_incoming(pte);
3431  }
3432  }
3433 }
3434 
3435 static 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) {
3464  transfer_cancel_step2(pte);
3465  } else if (ast_channel_state(sub->owner) == AST_STATE_UP) {
3466  transfer_call_step1(pte);
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 
3515 static 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:
3534  pte->device->output = OUTPUT_SPEAKER;
3535  handle_call_incoming(pte);
3536  break;
3537  case KEY_HEADPHN:
3538  pte->device->output = OUTPUT_HEADPHONE;
3539  handle_call_incoming(pte);
3540  break;
3541  case KEY_FUNC1:
3542  handle_call_incoming(pte);
3543  break;
3544  }
3545  return;
3546 }
3547 
3548 static 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));
3557  handle_call_outgoing(pte);
3558  return;
3559 }
3560 
3561 static 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 
3595  if (ast_exists_extension(NULL, pte->device->context, pte->device->phone_number, 1, NULL) &&
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:
3625  if (ast_strlen_zero(pte->device->redial_number)) {
3626  break;
3627  }
3629  sizeof(pte->device->phone_number));
3630  case KEY_FUNC1:
3631  handle_call_outgoing(pte);
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));
3643  send_callerid_screen(pte, sub);
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 
3687 static void handle_select_option(struct unistimsession *pte)
3688 {
3689  char tmp[128];
3690 
3691  if (pte->state != STATE_SELECTOPTION) {
3692  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));
3697  send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmp);
3698  send_text_status(pte, ustmtext("Select Cancel", pte));
3699  return;
3700 }
3701 
3702 static 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 
3725  handle_select_option(pte);
3726  return;
3727 }
3728 
3729 #define SELECTCODEC_START_ENTRY_POS 15
3730 #define SELECTCODEC_MAX_LENGTH 2
3731 #define SELECTCODEC_MSG "Codec number : .."
3732 static 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 
3742  send_text(TEXT_LINE0, TEXT_NORMAL, pte, buf);
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 
3752 static 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 
3807 static 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 
3819 static void handle_select_language(struct unistimsession *pte)
3820 {
3821  char tmp_language[40];
3822  struct unistim_languages lang;
3823 
3824  if (pte->state != STATE_SELECTLANGUAGE) {
3825  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));
3836  lang = options_languages[find_language(pte->device->language)];
3837  send_charset_update(pte, lang.encoding);
3838  send_text_status(pte, ustmtext("Select Cancel", pte));
3839  return;
3840 }
3841 
3842 static 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:
3857  ast_copy_string(pte->device->language, options_languages[(int)pte->buff_entry[0]].lang_short, sizeof(pte->device->language));
3858  send_charset_update(pte, options_languages[(int)pte->buff_entry[0]].encoding);
3859  refresh_all_favorite(pte);
3860  show_main_page(pte);
3861  return;
3862  case KEY_HANGUP:
3863  case KEY_FUNC4:
3864  handle_select_option(pte);
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 ".........."
3876 static 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  send_text_status(pte, ustmtext("Enter BackSpcErase", pte));
3886  pte->size_buff_entry = 0;
3887  return;
3888 }
3889 
3890 static void key_select_extension(struct unistimsession *pte, char keycode)
3891 {
3892  if (keycode == KEY_FUNC2) {
3893  if (pte->size_buff_entry <= 1) {
3894  keycode = KEY_FUNC3;
3895  } else {
3896  pte->size_buff_entry -= 2;
3897  keycode = pte->buff_entry[pte->size_buff_entry] + 0x10;
3898  }
3899  }
3900  if ((keycode >= KEY_0) && (keycode <= KEY_9)) {
3901  char tmpbuf[] = SELECTEXTENSION_MSG;
3902  int i = 0;
3903 
3905  return;
3906  }
3907  while (i < pte->size_buff_entry) {
3908  tmpbuf[i + SELECTEXTENSION_START_ENTRY_POS] = pte->buff_entry[i];
3909  i++;
3910  }
3911  tmpbuf[i + SELECTEXTENSION_START_ENTRY_POS] = keycode - 0x10;
3912  pte->buff_entry[i] = keycode - 0x10;
3913  pte->size_buff_entry++;
3914  send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
3915  send_blink_cursor(pte);
3916  send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS + 1 + i));
3917  return;
3918  }
3919 
3920  switch (keycode) {
3921  case KEY_FUNC1:
3922  if (pte->size_buff_entry < 1) {
3923  return;
3924  }
3926  struct unistim_device *d;
3927 
3928  /* First step : looking for this TN in our device list */
3930  d = devices;
3931  pte->buff_entry[pte->size_buff_entry] = '\0';
3932  while (d) {
3933  if (d->id[0] == 'T') { /* It's a TN device ? */
3934  /* It's the TN we're looking for ? */
3935  if (!strcmp((d->id) + 1, pte->buff_entry)) {
3936  pte->device = d;
3937  d->session = pte;
3939  d->missed_call = 0;
3941  strcpy(d->id, pte->macaddr);
3942  pte->device->extension_number[0] = 'T';
3943  pte->device->extension = EXTENSION_TN;
3945  pte->buff_entry, pte->size_buff_entry + 1);
3947  show_main_page(pte);
3948  refresh_all_favorite(pte);
3949  return;
3950  }
3951  }
3952  d = d->next;
3953  }
3955  send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Invalid Terminal Number.", pte));
3956  send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Please try again :", pte));
3958  pte->size_buff_entry));
3959  send_blink_cursor(pte);
3960  } else {
3962  pte->size_buff_entry + 1);
3963  if (register_extension(pte)) {
3964  send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Invalid extension.", pte));
3965  send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Please try again :", pte));
3966  send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 +
3968  pte->size_buff_entry));
3969  send_blink_cursor(pte);
3970  } else
3971  show_main_page(pte);
3972  }
3973  break;
3974  case KEY_FUNC3:
3975  pte->size_buff_entry = 0;
3977  send_blink_cursor(pte);
3979  break;
3980  }
3981  return;
3982 }
3983 
3984 static void show_entry_history(struct unistimsession *pte, FILE ** f)
3985 {
3986  char line[TEXT_LENGTH_MAX + 1], status[STATUS_LENGTH_MAX + 1], func1[10], func2[10],
3987  func3[10];
3988 
3989  /* Display date/time and call status */
3990  if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
3991  display_last_error("Can't read history date entry");
3992  fclose(*f);
3993  return;
3994  }
3995  line[sizeof(line) - 1] = '\0';
3996  if (pte->device->height == 1) {
3997  if (pte->buff_entry[3] == 1) {
3998  send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
3999  }
4000  } else {
4001  send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
4002  }
4003  /* Display number */
4004  if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
4005  display_last_error("Can't read callerid entry");
4006  fclose(*f);
4007  return;
4008  }
4009  line[sizeof(line) - 1] = '\0';
4010  ast_copy_string(pte->device->lst_cid, line, sizeof(pte->device->lst_cid));
4012  if (pte->device->height == 1) {
4013  if (pte->buff_entry[3] == 2) {
4014  send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
4015  }
4016  } else {
4017  send_text(TEXT_LINE1, TEXT_NORMAL, pte, line);
4018  }
4019  /* Display name */
4020  if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
4021  display_last_error("Can't read callername entry");
4022  fclose(*f);
4023  return;
4024  }
4025  line[sizeof(line) - 1] = '\0';
4026  if (pte->device->height == 1) {
4027  if (pte->buff_entry[3] == 3) {
4028  send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
4029  }
4030  } else {
4031  send_text(TEXT_LINE2, TEXT_NORMAL, pte, line);
4032  }
4033  fclose(*f);
4034 
4035  snprintf(line, sizeof(line), "%s %03d/%03d", ustmtext("Call", pte), pte->buff_entry[2],
4036  pte->buff_entry[1]);
4037  send_texttitle(pte, line);
4038 
4039  if (pte->buff_entry[2] == 1) {
4040  ast_copy_string(func1, " ", sizeof(func1));
4041  } else {
4042  ast_copy_string(func1, ustmtext("Prev ", pte), sizeof(func1));
4043  }
4044  if (pte->buff_entry[2] >= pte->buff_entry[1]) {
4045  ast_copy_string(func2, " ", sizeof(func2));
4046  } else {
4047  ast_copy_string(func2, ustmtext("Next ", pte), sizeof(func2));
4048  }
4049  if (strlen(pte->device->lst_cid)) {
4050  ast_copy_string(func3, ustmtext("Redial ", pte), sizeof(func3));
4051  } else {
4052  ast_copy_string(func3, " ", sizeof(func3));
4053  }
4054  snprintf(status, sizeof(status), "%s%s%s%s", func1, func2, func3, ustmtext("Cancel", pte));
4055  send_text_status(pte, status);
4056 }
4057 
4058 static char open_history(struct unistimsession *pte, char way, FILE ** f)
4059 {
4060  char tmp[AST_CONFIG_MAX_PATH];
4061  char count;
4062 
4063  snprintf(tmp, sizeof(tmp), "%s/%s/%s-%c.csv", ast_config_AST_LOG_DIR,
4064  USTM_LOG_DIR, pte->device->name, way);
4065  *f = fopen(tmp, "r");
4066  if (!*f) {
4067  display_last_error("Unable to open history file");
4068  return 0;
4069  }
4070  if (fread(&count, 1, 1, *f) != 1) {
4071  display_last_error("Unable to read history header - display.");
4072  fclose(*f);
4073  *f = NULL;
4074  return 0;
4075  }
4076  if (count > MAX_ENTRY_LOG) {
4077  ast_log(LOG_WARNING, "Invalid count in history header of %s (%d max %d)\n", tmp,
4078  count, MAX_ENTRY_LOG);
4079  fclose(*f);
4080  *f = NULL;
4081  return 0;
4082  }
4083  return count;
4084 }
4085 
4086 static void show_history(struct unistimsession *pte, char way)
4087 {
4088  FILE *f;
4089  char count;
4090 
4091  if (!pte->device) {
4092  return;
4093  }
4094  if (!pte->device->callhistory) {
4095  return;
4096  }
4097  count = open_history(pte, way, &f);
4098  if (!count) {
4099  return;
4100  }
4101  pte->buff_entry[0] = way;
4102  pte->buff_entry[1] = count;
4103  pte->buff_entry[2] = 1;
4104  pte->buff_entry[3] = 1;
4105  show_entry_history(pte, &f);
4106  pte->state = STATE_HISTORY;
4107 }
4108 
4109 static void show_main_page(struct unistimsession *pte)
4110 {
4111  char tmpbuf[TEXT_LENGTH_MAX + 1];
4112  const char *text;
4113 
4114  if ((pte->device->extension == EXTENSION_ASK) &&
4116  show_extension_page(pte);
4117  return;
4118  }
4119 
4120  pte->state = STATE_MAINPAGE;
4122  pte->device->lastmsgssent = -1;
4123 
4124  send_tone(pte, 0, 0);
4125  send_stop_timer(pte); /* case of holding call */
4129 
4130  if (!ast_strlen_zero(pte->device->call_forward)) {
4131  if (pte->device->height == 1) {
4132  char tmp_field[100];
4133  snprintf(tmp_field, sizeof(tmp_field), "%s %s", ustmtext("Fwd to:", pte), pte->device->call_forward);
4134  send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmp_field);
4135  } else {
4136  send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Call forwarded to :", pte));
4138  }
4140  if (ast_strlen_zero(pte->device->redial_number)) {
4141  send_text_status(pte, ustmtext("Dial NoFwd ", pte));
4142  } else {
4143  send_text_status(pte, ustmtext("Dial Redial NoFwd ", pte));
4144  }
4145  } else {
4146  if ((pte->device->extension == EXTENSION_ASK) || (pte->device->extension == EXTENSION_TN)) {
4147  if (ast_strlen_zero(pte->device->redial_number)) {
4148  send_text_status(pte, ustmtext("Dial Fwd Unregis", pte));
4149  } else {
4150  send_text_status(pte, ustmtext("Dial Redial Fwd Unregis", pte));
4151  }
4152  } else {
4153  if (ast_strlen_zero(pte->device->redial_number)) {
4154  send_text_status(pte, ustmtext("Dial Fwd Pickup", pte));
4155  } else {
4156  send_text_status(pte, ustmtext("Dial Redial Fwd Pickup", pte));
4157  }
4158  }
4160  if (pte->device->missed_call == 0) {
4161  send_date_time2(pte);
4162  send_idle_clock(pte);
4163  if (strlen(pte->device->maintext0)) {
4165  }
4166  } else {
4167  if (pte->device->missed_call == 1) {
4168  text = ustmtext("unanswered call", pte);
4169  } else {
4170  text = ustmtext("unanswered calls", pte);
4171  }
4172  snprintf(tmpbuf, sizeof(tmpbuf), "%d %s", pte->device->missed_call, text);
4173  send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmpbuf);
4175  }
4176  }
4177  if (pte->device->height > 1) {
4178  if (ast_strlen_zero(pte->device->maintext2)) {
4179  strcpy(tmpbuf, "IP : ");
4180  strcat(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr));
4181  send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
4182  } else {
4184  }
4185  }
4186 
4187  send_texttitle(pte, ustmtext(pte->device->titledefault, pte));
4189 }
4190 
4191 static void key_main_page(struct unistimsession *pte, char keycode)
4192 {
4193  if (pte->device->missed_call) {
4195  pte->device->missed_call = 0;
4196  }
4197  if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
4198  handle_dial_page(pte);
4199  key_dial_page(pte, keycode);
4200  return;
4201  }
4202  switch (keycode) {
4203  case KEY_FUNC1:
4204  pte->device->selected = get_avail_softkey(pte, NULL);
4205  handle_dial_page(pte);
4206  break;
4207  case KEY_FUNC2:
4208  if (ast_strlen_zero(pte->device->redial_number)) {
4209  break;
4210  }
4211  if ((pte->device->output == OUTPUT_HANDSET) &&
4212  (pte->device->receiver_state == STATE_ONHOOK)) {
4214  } else {
4215  send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
4216  }
4218  sizeof(pte->device->phone_number));
4219  handle_call_outgoing(pte);
4220  break;
4221  case KEY_FUNC3:
4222  if (!ast_strlen_zero(pte->device->call_forward)) {
4223  /* Cancel call forwarding */
4224  memmove(pte->device->call_forward + 1, pte->device->call_forward,
4225  sizeof(pte->device->call_forward) - 1);
4226  pte->device->call_forward[0] = '\0';
4228  pte->device->output = OUTPUT_HANDSET; /* Seems to be reseted somewhere */
4229  show_main_page(pte);
4230  break;
4231  }
4232  pte->device->call_forward[0] = -1;
4233  handle_dial_page(pte);
4234  break;
4235  case KEY_FUNC4:
4236  if (pte->device->extension == EXTENSION_ASK) {
4237  unregister_extension(pte);
4238  pte->device->extension_number[0] = '\0';
4239  show_extension_page(pte);
4240  } else if (pte->device->extension == EXTENSION_TN) {
4242  strcpy(pte->device->id, pte->device->extension_number);
4243  pte->buff_entry[0] = '\0';
4244  pte->size_buff_entry = 0;
4245  pte->device->session = NULL;
4246  pte->device = NULL;
4248  show_extension_page(pte);
4249  } else { /* Pickup function */
4250  /* XXX Is there a way to get a specific channel here? */
4251  RAII_VAR(struct ast_features_pickup_config *, pickup_cfg,
4253 
4254  if (!pickup_cfg) {
4255  ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
4256  break;
4257  }
4258 
4259  pte->device->selected = -1;
4260  ast_copy_string(pte->device->phone_number, pickup_cfg->pickupexten,
4261  sizeof(pte->device->phone_number));
4262  handle_call_outgoing(pte);
4263  }
4264  break;
4265  case KEY_FAV0:
4266  case KEY_FAV1:
4267  case KEY_FAV2:
4268  case KEY_FAV3:
4269  case KEY_FAV4:
4270  case KEY_FAV5:
4271  handle_key_fav(pte, keycode);
4272  break;
4273  case KEY_CONF:
4274  handle_select_option(pte);
4275  break;
4276  case KEY_LOUDSPK:
4278  handle_dial_page(pte);
4279  break;
4280  case KEY_HEADPHN:
4282  handle_dial_page(pte);
4283  break;
4284  case KEY_SNDHIST:
4285  show_history(pte, 'o');
4286  break;
4287  case KEY_RCVHIST:
4288  show_history(pte, 'i');
4289  break;
4290  }
4291  return;
4292 }
4293 
4294 static void key_history(struct unistimsession *pte, char keycode)
4295 {
4296  FILE *f;
4297  char count;
4298  long offset;
4299  int flag = 0;
4300 
4301  switch (keycode) {
4302  case KEY_LEFT:
4303  if (pte->device->height == 1) {
4304  if (pte->buff_entry[3] <= 1) {
4305  return;
4306  }
4307  pte->buff_entry[3]--;
4308  flag = 1;
4309  break;
4310  }
4311  case KEY_UP:
4312  case KEY_FUNC1:
4313  if (pte->buff_entry[2] <= 1) {
4314  return;
4315  }
4316  pte->buff_entry[2]--;
4317  flag = 1;
4318  break;
4319  case KEY_RIGHT:
4320  if (pte->device->height == 1) {
4321  if (pte->buff_entry[3] == 3) {
4322  return;
4323  }
4324  pte->buff_entry[3]++;
4325  flag = 1;
4326  break;
4327  }
4328  case KEY_DOWN:
4329  case KEY_FUNC2:
4330  if (pte->buff_entry[2] >= pte->buff_entry[1]) {
4331  return;
4332  }
4333  pte->buff_entry[2]++;
4334  flag = 1;
4335  break;
4336  case KEY_FUNC3:
4337  if (ast_strlen_zero(pte->device->lst_cid)) {
4338  break;
4339  }
4341  sizeof(pte->device->redial_number));
4342  key_main_page(pte, KEY_FUNC2);
4343  break;
4344  case KEY_FUNC4:
4345  case KEY_HANGUP:
4346  show_main_page(pte);
4347  break;
4348  case KEY_SNDHIST:
4349  if (pte->buff_entry[0] == 'i') {
4350  show_history(pte, 'o');
4351  } else {
4352  show_main_page(pte);
4353  }
4354  break;
4355  case KEY_RCVHIST:
4356  if (pte->buff_entry[0] == 'i') {
4357  show_main_page(pte);
4358  } else {
4359  show_history(pte, 'i');
4360  }
4361  break;
4362  }
4363 
4364  if (flag) {
4365  count = open_history(pte, pte->buff_entry[0], &f);
4366  if (!count) {
4367  return;
4368  }
4369  offset = ((pte->buff_entry[2] - 1) * TEXT_LENGTH_MAX * 3);
4370  if (fseek(f, offset, SEEK_CUR)) {
4371  display_last_error("Unable to seek history e