chan_unistim.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * UNISTIM channel driver for asterisk
00005  *
00006  * Copyright (C) 2005 - 2007, Cedric Hans
00007  *
00008  * Cedric Hans <cedric.hans@mlkj.net>
00009  *
00010  * Asterisk 1.4 patch by Peter Be
00011  *
00012  * See http://www.asterisk.org for more information about
00013  * the Asterisk project. Please do not directly contact
00014  * any of the maintainers of this project for assistance;
00015  * the project provides a web site, mailing lists and IRC
00016  * channels for your use.
00017  *
00018  * This program is free software, distributed under the terms of
00019  * the GNU General Public License Version 2. See the LICENSE file
00020  * at the top of the source tree.
00021  */
00022 
00023 /*!
00024  * \file
00025  *
00026  * \brief chan_unistim channel driver for Asterisk
00027  * \author Cedric Hans <cedric.hans@mlkj.net>
00028  *
00029  * Unistim (Unified Networks IP Stimulus) channel driver
00030  * for Nortel i2002, i2004 and i2050
00031  *
00032  * \ingroup channel_drivers
00033  */
00034 
00035 /*** MODULEINFO
00036    <support_level>extended</support_level>
00037  ***/
00038 
00039 #include "asterisk.h"
00040 
00041 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 431000 $")
00042 
00043 #include <sys/stat.h>
00044 #include <signal.h>
00045 
00046 #if defined(__CYGWIN__)
00047 /*
00048  * cygwin headers are partly inconsistent. struct iovec is defined in sys/uio.h
00049  * which is not included by default by sys/socket.h - in_pktinfo is defined in
00050  * w32api/ws2tcpip.h but this probably has compatibility problems with sys/socket.h
00051  * So for the time being we simply disable HAVE_PKTINFO when building under cygwin.
00052  *    This should be done in some common header, but for now this is the only file
00053  * using iovec and in_pktinfo so it suffices to apply the fix here.
00054  */
00055 #ifdef HAVE_PKTINFO
00056 #undef HAVE_PKTINFO
00057 #endif
00058 #endif /* __CYGWIN__ */
00059 
00060 #include "asterisk/paths.h"   /* ast_config_AST_LOG_DIR used in (too ?) many places */
00061 #include "asterisk/network.h"
00062 #include "asterisk/channel.h"
00063 #include "asterisk/config.h"
00064 #include "asterisk/module.h"
00065 #include "asterisk/pbx.h"
00066 #include "asterisk/rtp_engine.h"
00067 #include "asterisk/netsock2.h"
00068 #include "asterisk/acl.h"
00069 #include "asterisk/callerid.h"
00070 #include "asterisk/cli.h"
00071 #include "asterisk/app.h"
00072 #include "asterisk/musiconhold.h"
00073 #include "asterisk/causes.h"
00074 #include "asterisk/indications.h"
00075 #include "asterisk/pickup.h"
00076 #include "asterisk/astobj2.h"
00077 #include "asterisk/astdb.h"
00078 #include "asterisk/features_config.h"
00079 #include "asterisk/bridge.h"
00080 #include "asterisk/stasis_channels.h"
00081 #include "asterisk/format_cache.h"
00082 
00083 #define DEFAULTCONTEXT    "default"
00084 #define DEFAULTCALLERID  "Unknown"
00085 #define DEFAULTCALLERNAME       " "
00086 #define DEFAULTHEIGHT    3
00087 #define USTM_LOG_DIR     "unistimHistory"
00088 #define USTM_LANG_DIR       "unistimLang"
00089 
00090 /*! Size of the transmit buffer */
00091 #define MAX_BUF_SIZE     64
00092 /*! Number of slots for the transmit queue */
00093 #define MAX_BUF_NUMBER    150
00094 /*! Number of digits displayed on screen */
00095 #define MAX_SCREEN_NUMBER   15
00096 /*! Length of month label size */
00097 #define MONTH_LABEL_SIZE 3
00098 /*! Try x times before removing the phone */
00099 #define NB_MAX_RETRANSMIT       8
00100 /*! Nb of milliseconds waited when no events are scheduled */
00101 #define IDLE_WAIT        1000
00102 /*! Wait x milliseconds before resending a packet */
00103 #define RETRANSMIT_TIMER   2000
00104 /*! How often the mailbox is checked for new messages */
00105 #define TIMER_MWI        5000
00106 /*! Timeout value for entered number being dialed */
00107 #define DEFAULT_INTERDIGIT_TIMER 4000
00108 
00109 /*! Not used */
00110 #define DEFAULT_CODEC      0x00
00111 #define SIZE_PAGE        4096
00112 #define DEVICE_NAME_LEN  16
00113 #define AST_CONFIG_MAX_PATH     255
00114 #define MAX_ENTRY_LOG      30
00115 
00116 #define SUB_REAL     0
00117 #define SUB_RING                1
00118 #define SUB_THREEWAY            2
00119 #define SUB_ONHOLD              3
00120 
00121 struct ast_format_cap *global_cap;
00122 
00123 enum autoprovision {
00124    AUTOPROVISIONING_NO = 0,
00125    AUTOPROVISIONING_YES,
00126    AUTOPROVISIONING_TN
00127 };
00128 
00129 enum autoprov_extn {
00130    /*! Do not create an extension into the default dialplan */
00131    EXTENSION_NONE = 0,
00132    /*! Prompt user for an extension number and register it */
00133    EXTENSION_ASK,
00134    /*! Register an extension with the line=> value */
00135    EXTENSION_LINE,
00136    /*! Used with AUTOPROVISIONING_TN */
00137    EXTENSION_TN
00138 };
00139 #define OUTPUT_HANDSET    0xC0
00140 #define OUTPUT_HEADPHONE   0xC1
00141 #define OUTPUT_SPEAKER    0xC2
00142 
00143 #define VOLUME_LOW         0x01
00144 #define VOLUME_LOW_SPEAKER      0x03
00145 #define VOLUME_NORMAL      0x02
00146 #define VOLUME_INSANELY_LOUD    0x07
00147 
00148 #define MUTE_OFF     0x00
00149 #define MUTE_ON       0xFF
00150 #define MUTE_ON_DISCRET  0xCE
00151 
00152 #define LED_BAR_OFF        0x00 /* bar off */
00153 #define LED_BAR_ON         0x01 /* bar on */
00154 #define LED_BAR_P2         0x02 /* bar 1s on/1s */
00155 #define LED_BAR_P3         0x03 /* bar 2.5s on/0.5s off */
00156 #define LED_BAR_P4         0x04 /* bar 0.6s on/0.3s off */
00157 #define LED_BAR_P5         0x05 /* bar 0.5s on/0.5s off */
00158 #define LED_BAR_P6         0x06 /* bar 2s on/0.5s off */
00159 #define LED_BAR_P7         0x07 /* bar off */
00160 #define LED_SPEAKER_OFF       0x08
00161 #define LED_SPEAKER_ON        0x09
00162 #define LED_HEADPHONE_OFF     0x010
00163 #define LED_HEADPHONE_ON      0x011
00164 #define LED_MUTE_OFF       0x018
00165 #define LED_MUTE_ON        0x019
00166 
00167 #define SIZE_HEADER       6
00168 #define SIZE_MAC_ADDR      17
00169 #define TEXT_LENGTH_MAX  24
00170 #define TEXT_LINE0         0x00
00171 #define TEXT_LINE1         0x20
00172 #define TEXT_LINE2         0x40
00173 #define TEXT_NORMAL       0x05
00174 #define TEXT_INVERSE     0x25
00175 #define STATUS_LENGTH_MAX       28
00176 
00177 #define FAV_ICON_NONE         0x00
00178 #define FAV_ICON_ONHOOK_BLACK    0x20
00179 #define FAV_ICON_ONHOOK_WHITE    0x21
00180 #define FAV_ICON_SPEAKER_ONHOOK_BLACK   0x22
00181 #define FAV_ICON_SPEAKER_ONHOOK_WHITE   0x23
00182 #define FAV_ICON_OFFHOOK_BLACK     0x24
00183 #define FAV_ICON_OFFHOOK_WHITE     0x25
00184 #define FAV_ICON_ONHOLD_BLACK    0x26
00185 #define FAV_ICON_ONHOLD_WHITE    0x27
00186 #define FAV_ICON_SPEAKER_OFFHOOK_BLACK  0x28
00187 #define FAV_ICON_SPEAKER_OFFHOOK_WHITE  0x29
00188 #define FAV_ICON_PHONE_BLACK      0x2A
00189 #define FAV_ICON_PHONE_WHITE      0x2B
00190 #define FAV_ICON_SPEAKER_ONHOLD_BLACK   0x2C
00191 #define FAV_ICON_SPEAKER_ONHOLD_WHITE   0x2D
00192 #define FAV_ICON_HEADPHONES        0x2E
00193 #define FAV_ICON_HEADPHONES_ONHOLD      0x2F
00194 #define FAV_ICON_HOME         0x30
00195 #define FAV_ICON_CITY         0x31
00196 #define FAV_ICON_SHARP       0x32
00197 #define FAV_ICON_PAGER       0x33
00198 #define FAV_ICON_CALL_CENTER      0x34
00199 #define FAV_ICON_FAX        0x35
00200 #define FAV_ICON_MAILBOX      0x36
00201 #define FAV_ICON_REFLECT      0x37
00202 #define FAV_ICON_COMPUTER         0x38
00203 #define FAV_ICON_FORWARD      0x39
00204 #define FAV_ICON_LOCKED     0x3A
00205 #define FAV_ICON_TRASH       0x3B
00206 #define FAV_ICON_INBOX       0x3C
00207 #define FAV_ICON_OUTBOX     0x3D
00208 #define FAV_ICON_MEETING      0x3E
00209 #define FAV_ICON_BOX        0x3F
00210 
00211 #define FAV_BLINK_FAST       0x20
00212 #define FAV_BLINK_SLOW       0x40
00213 
00214 #define FAV_MAX_LENGTH       0x0A
00215 
00216 #define FAVNUM                    6
00217 #define EXPNUM                    24
00218 #define FAV_LINE_ICON         FAV_ICON_ONHOOK_BLACK
00219 
00220 static void dummy(char *unused, ...)
00221 {
00222    return;
00223 }
00224 
00225 /*! \brief Global jitterbuffer configuration - by default, jb is disabled
00226  *  \note Values shown here match the defaults shown in unistim.conf.sample */
00227 static struct ast_jb_conf default_jbconf =
00228 {
00229    .flags = 0,
00230    .max_size = 200,
00231    .resync_threshold = 1000,
00232    .impl = "fixed",
00233    .target_extra = 40,
00234 };
00235 static struct ast_jb_conf global_jbconf;
00236 
00237 
00238 /* #define DUMP_PACKET 1 */
00239 /* #define DEBUG_TIMER ast_verbose */
00240 
00241 #define DEBUG_TIMER dummy
00242 /*! Enable verbose output. can also be set with the CLI */
00243 static int unistimdebug = 0;
00244 static int unistim_port;
00245 static enum autoprovision autoprovisioning = AUTOPROVISIONING_NO;
00246 static int unistim_keepalive;
00247 static int unistimsock = -1;
00248 
00249 static struct {
00250    unsigned int tos;
00251    unsigned int tos_audio;
00252    unsigned int cos;
00253    unsigned int cos_audio;
00254 } qos = { 0, 0, 0, 0 };
00255 
00256 static struct io_context *io;
00257 static struct ast_sched_context *sched;
00258 static struct sockaddr_in public_ip = { 0, };
00259 static unsigned char *buff; /*! Receive buffer address */
00260 static int unistim_reloading = 0;
00261 AST_MUTEX_DEFINE_STATIC(unistim_reload_lock);
00262 
00263 /*! This is the thread for the monitor which checks for input on the channels
00264  * which are not currently in use.  */
00265 static pthread_t monitor_thread = AST_PTHREADT_NULL;
00266 
00267 /*! Protect the monitoring thread, so only one process can kill or start it, and not
00268  *    when it's doing something critical. */
00269 AST_MUTEX_DEFINE_STATIC(monlock);
00270 /*! Protect the session list */
00271 AST_MUTEX_DEFINE_STATIC(sessionlock);
00272 /*! Protect the device list */
00273 AST_MUTEX_DEFINE_STATIC(devicelock);
00274 
00275 enum phone_state {
00276    STATE_INIT,
00277    STATE_AUTHDENY,
00278    STATE_MAINPAGE,
00279    STATE_EXTENSION,
00280    STATE_DIALPAGE,
00281    STATE_RINGING,
00282    STATE_CALL,
00283    STATE_SELECTOPTION,
00284    STATE_SELECTCODEC,
00285    STATE_SELECTLANGUAGE,
00286    STATE_CLEANING,
00287    STATE_HISTORY
00288 };
00289 
00290 enum handset_state {
00291    STATE_ONHOOK,
00292    STATE_OFFHOOK,
00293 };
00294 
00295 enum phone_key {
00296    KEY_0 = 0x40,
00297    KEY_1 = 0x41,
00298    KEY_2 = 0x42,
00299    KEY_3 = 0x43,
00300    KEY_4 = 0x44,
00301    KEY_5 = 0x45,
00302    KEY_6 = 0x46,
00303    KEY_7 = 0x47,
00304    KEY_8 = 0x48,
00305    KEY_9 = 0x49,
00306    KEY_STAR = 0x4a,
00307    KEY_SHARP = 0x4b,
00308    KEY_UP = 0x4c,
00309    KEY_DOWN = 0x4d,
00310    KEY_RIGHT = 0x4e,
00311    KEY_LEFT = 0x4f,
00312    KEY_QUIT = 0x50,
00313    KEY_COPY = 0x51,
00314    KEY_FUNC1 = 0x54,
00315    KEY_FUNC2 = 0x55,
00316    KEY_FUNC3 = 0x56,
00317    KEY_FUNC4 = 0x57,
00318    KEY_ONHOLD = 0x5b,
00319    KEY_HANGUP = 0x5c,
00320    KEY_MUTE = 0x5d,
00321    KEY_HEADPHN = 0x5e,
00322    KEY_LOUDSPK = 0x5f,
00323    KEY_FAV0 = 0x60,
00324    KEY_FAV1 = 0x61,
00325    KEY_FAV2 = 0x62,
00326    KEY_FAV3 = 0x63,
00327    KEY_FAV4 = 0x64,
00328    KEY_FAV5 = 0x65,
00329    KEY_COMPUTR = 0x7b,
00330    KEY_CONF = 0x7c,
00331    KEY_SNDHIST = 0x7d,
00332    KEY_RCVHIST = 0x7e,
00333    KEY_INDEX = 0x7f
00334 };
00335 
00336 enum charset {
00337    LANG_DEFAULT,
00338    ISO_8859_1,
00339    ISO_8859_2,
00340    ISO_8859_4,
00341    ISO_8859_5,
00342    ISO_2022_JP,
00343 };
00344 
00345 static const int dtmf_row[] = { 697,  770,  852,  941 };
00346 static const float dtmf_col[] = { 1209, 1336, 1477, 1633 };
00347 
00348 struct wsabuf {
00349    u_long len;
00350    unsigned char *buf;
00351 };
00352 
00353 struct unistim_subchannel {
00354    ast_mutex_t lock;
00355    unsigned int subtype;      /*! SUB_REAL, SUB_RING, SUB_THREEWAY or SUB_ONHOLD */
00356    struct ast_channel *owner; /*! Asterisk channel used by the subchannel */
00357    struct unistim_line *parent;  /*! Unistim line */
00358    struct ast_rtp_instance *rtp; /*! RTP handle */
00359    int softkey;         /*! Softkey assigned */
00360    pthread_t ss_thread;    /*! unistim_ss thread handle */
00361    int alreadygone;
00362    char ringvolume;
00363    char ringstyle;
00364    int moh;             /*!< Music on hold in progress */
00365    AST_LIST_ENTRY(unistim_subchannel) list;
00366 };
00367 
00368 /*!
00369  * \todo Convert to stringfields
00370  */
00371 struct unistim_line {
00372    ast_mutex_t lock;
00373    char name[80]; /*! Like 200 */
00374    char fullname[80]; /*! Like USTM/200\@black */
00375    char exten[AST_MAX_EXTENSION]; /*! Extension where to start */
00376    char cid_num[AST_MAX_EXTENSION]; /*! CallerID Number */
00377    char mailbox[AST_MAX_EXTENSION]; /*! Mailbox for MWI */
00378    char musicclass[MAX_MUSICCLASS]; /*! MusicOnHold class */
00379    ast_group_t callgroup; /*! Call group */
00380    ast_group_t pickupgroup; /*! Pickup group */
00381    char accountcode[AST_MAX_ACCOUNT_CODE]; /*! Account code (for billing) */
00382    int amaflags; /*! AMA flags (for billing) */
00383    struct ast_format_cap *cap; /*! Codec supported */
00384    char parkinglot[AST_MAX_CONTEXT]; /*! Parkinglot */
00385    struct unistim_line *next;
00386    struct unistim_device *parent;
00387    AST_LIST_ENTRY(unistim_line) list;
00388 };
00389 
00390 /*!
00391  * \brief A device containing one or more lines
00392  */
00393 static struct unistim_device {
00394    ast_mutex_t lock;
00395    int receiver_state;        /*!< state of the receiver (see ReceiverState) */
00396    int size_phone_number;    /*!< size of the phone number */
00397    char context[AST_MAX_EXTENSION]; /*!< Context to start in */
00398    char phone_number[AST_MAX_EXTENSION];    /*!< the phone number entered by the user */
00399    char redial_number[AST_MAX_EXTENSION];  /*!< the last phone number entered by the user */
00400    char id[18];             /*!< mac address of the current phone in ascii */
00401    char name[DEVICE_NAME_LEN];     /*!< name of the device */
00402    int hasexp;                          /*!< if device have expansion connected */
00403    char expsoftkeylabel[EXPNUM][11];       /*!< soft key label */
00404    char softkeylabel[FAVNUM][11];       /*!< soft key label */
00405    char softkeynumber[FAVNUM][AST_MAX_EXTENSION];      /*!< number dialed when the soft key is pressed */
00406    char softkeyicon[FAVNUM];      /*!< icon number */
00407    char softkeydevice[FAVNUM][16];      /*!< name of the device monitored */
00408    struct unistim_subchannel *ssub[FAVNUM];
00409    struct unistim_line *sline[FAVNUM];
00410    struct unistim_device *sp[FAVNUM];   /*!< pointer to the device monitored by this soft key */
00411    char language[MAX_LANGUAGE];    /*!< Language for asterisk sounds */
00412    int height;                   /*!< The number of lines the phone can display */
00413    char maintext0[25];          /*!< when the phone is idle, display this string on line 0 */
00414    char maintext1[25];          /*!< when the phone is idle, display this string on line 1 */
00415    char maintext2[25];          /*!< when the phone is idle, display this string on line 2 */
00416    char titledefault[13];    /*!< title (text before date/time) */
00417    char datetimeformat;     /*!< format used for displaying time/date */
00418    char contrast;         /*!< contrast */
00419    char country[3];        /*!< country used for dial tone frequency */
00420    struct ast_tone_zone *tz;         /*!< Tone zone for res_indications (ring, busy, congestion) */
00421    char ringvolume;        /*!< Ring volume */
00422    char ringstyle;          /*!< Ring melody */
00423    char cwvolume;       /*!< Ring volume on call waiting */
00424    char cwstyle;         /*!< Ring melody on call waiting */
00425    int interdigit_timer;      /*!< Interdigit timer for dialing number by timeout */
00426    int dtmfduration;    /*!< DTMF playback duration */
00427    time_t nextdial;     /*!< Timer used for dial by timeout */
00428    int rtp_port;           /*!< RTP port used by the phone */
00429    int rtp_method;          /*!< Select the unistim data used to establish a RTP session */
00430    int status_method;            /*!< Select the unistim packet used for sending status text */
00431    char codec_number;            /*!< The current codec used to make calls */
00432    int missed_call;        /*!< Number of call unanswered */
00433    int callhistory;        /*!< Allowed to record call history */
00434         int sharp_dial;          /*!< Execute Dial on '#' or not */
00435    char lst_cid[TEXT_LENGTH_MAX];  /*!< Last callerID received */
00436    char lst_cnm[TEXT_LENGTH_MAX];  /*!< Last callername recevied */
00437    char call_forward[AST_MAX_EXTENSION];   /*!< Forward number */
00438    int output;               /*!< Handset, headphone or speaker */
00439    int previous_output;     /*!< Previous output */
00440    int volume;               /*!< Default volume */
00441    int selected;                           /*!< softkey selected */
00442    int microphone;            /*!< Microphone mode (audio tx) */
00443    int lastmsgssent;                                                   /*! Used by MWI */
00444    time_t nextmsgcheck;                                            /*! Used by MWI */
00445    int nat;             /*!< Used by the obscure ast_rtp_setnat */
00446    enum autoprov_extn extension;   /*!< See ifdef EXTENSION for valid values */
00447    char extension_number[11];      /*!< Extension number entered by the user */
00448    char to_delete;          /*!< Used in reload */
00449    struct ast_silence_generator *silence_generator;
00450    AST_LIST_HEAD(,unistim_subchannel) subs; /*!< pointer to our current connection, channel... */
00451    AST_LIST_HEAD(,unistim_line) lines;
00452    struct ast_ha *ha;
00453    struct unistimsession *session;
00454    struct unistim_device *next;
00455 } *devices = NULL;
00456 
00457 static struct unistimsession {
00458    ast_mutex_t lock;
00459    struct sockaddr_in sin;  /*!< IP address of the phone */
00460    struct sockaddr_in sout;   /*!< IP address of server */
00461    int timeout;             /*!< time-out in ticks : resend packet if no ack was received before the timeout occured */
00462    unsigned short seq_phone;       /*!< sequence number for the next packet (when we receive a request) */
00463    unsigned short seq_server;      /*!< sequence number for the next packet (when we send a request) */
00464    unsigned short last_seq_ack;    /*!< sequence number of the last ACK received */
00465    unsigned long tick_next_ping;   /*!< time for the next ping */
00466    int last_buf_available;  /*!< number of a free slot */
00467    int nb_retransmit;            /*!< number of retransmition */
00468    int state;                 /*!< state of the phone (see phone_state) */
00469    int size_buff_entry;     /*!< size of the buffer used to enter datas */
00470    char buff_entry[16];     /*!< Buffer for temporary datas */
00471    char macaddr[18];           /*!< mac address of the phone (not always available) */
00472    char firmware[8];           /*!< firmware of the phone (not always available) */
00473    struct wsabuf wsabufsend[MAX_BUF_NUMBER];      /*!< Size of each paquet stored in the buffer array & pointer to this buffer */
00474    unsigned char buf[MAX_BUF_NUMBER][MAX_BUF_SIZE];   /*!< Buffer array used to keep the lastest non-acked paquets */
00475    struct unistim_device *device;
00476    struct unistimsession *next;
00477 } *sessions = NULL;
00478 
00479 /*! Store on screen phone menu item (label and handler function) */
00480 struct unistim_menu_item {
00481    char *label;
00482    int state;
00483    void (*handle_option)(struct unistimsession *);
00484 };
00485 
00486 /*! Language item for currently existed translations */
00487 struct unistim_languages {
00488    char *label;
00489    char *lang_short;
00490    int encoding;
00491    struct ao2_container *trans;
00492 };
00493 
00494 /*!
00495  * \page Unistim datagram formats
00496  *
00497  * Format of datagrams :
00498  * bytes 0 & 1 : ffff for discovery packet, 0000 for everything else
00499  * byte 2 : sequence number (high part)
00500  * byte 3 : sequence number (low part)
00501  * byte 4 : 2 = ask question or send info, 1 = answer or ACK, 0 = retransmit request
00502  * byte 5 : direction, 1 = server to phone, 2 = phone to server arguments
00503  */
00504 
00505 static const unsigned char packet_rcv_discovery[] =
00506    { 0xff, 0xff, 0xff, 0xff, 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 };
00507 static const unsigned char packet_send_discovery_ack[] =
00508    { 0x00, 0x00, /*Initial Seq (2 bytes) */ 0x00, 0x00, 0x00, 0x01 };
00509 
00510 static const unsigned char packet_recv_firm_version[] =
00511    { 0x00, 0x00, 0x00, 0x13, 0x9a, 0x0a, 0x02 };
00512 static const unsigned char packet_recv_it_type[] =
00513    { 0x00, 0x00, 0x00, 0x13, 0x9a, 0x04, 0x03 };
00514 static const unsigned char packet_recv_pressed_key[] =
00515    { 0x00, 0x00, 0x00, 0x13, 0x99, 0x04, 0x00 };
00516 static const unsigned char packet_recv_pick_up[] =
00517    { 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x04 };
00518 static const unsigned char packet_recv_hangup[] =
00519    { 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x03 };
00520 static const unsigned char packet_recv_r2[] = { 0x00, 0x00, 0x00, 0x13, 0x96, 0x03, 0x03 };
00521 
00522 /*! Expansion module (i2004 KEM) */
00523 static const unsigned char packet_recv_expansion_pressed_key[] =
00524    { 0x00, 0x00, 0x00, 0x13, 0x89, 0x04, 0x59 };
00525 static const unsigned char packet_send_expansion_next[] = { 0x09, 0x03, 0x17 };
00526 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 */
00527 static const unsigned char packet_send_expansion_text[] = { 0x09, 0x0f, 0x57, 0x19, /*pos */ 0x47, /*text */ 0x20,
00528    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 /*end_text */ };
00529 
00530 
00531 /*! TransportAdapter */
00532 static const unsigned char packet_recv_resume_connection_with_server[] =
00533    { 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 };
00534 static const unsigned char packet_recv_mac_addr[] =
00535    { 0xff, 0xff, 0xff, 0xff, 0x9a, 0x0d, 0x07 /*MacAddr */  };
00536 
00537 static const unsigned char packet_send_date_time3[] =
00538    { 0x11, 0x09, 0x02, 0x02, /*Month */ 0x05, /*Day */ 0x06, /*Hour */ 0x07,
00539 /*Minutes */ 0x08, 0x32
00540 };
00541 static const unsigned char packet_send_date_time[] =
00542    { 0x11, 0x09, 0x02, 0x0a, /*Month */ 0x05, /*Day */ 0x06, /*Hour */ 0x07, /*Minutes */
00543 0x08, 0x32, 0x17, 0x04, 0x24, 0x07, 0x19,
00544    0x04, 0x07, 0x00, 0x19, 0x05, 0x09, 0x3e, 0x0f, 0x16, 0x05, 0x00, 0x80, 0x00, 0x1e,
00545       0x05, 0x12, 0x00, 0x78
00546 };
00547 
00548 static const unsigned char packet_send_no_ring[] =
00549    { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00 };
00550 static const unsigned char packet_send_s4[] =
00551    { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00, 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff,
00552 0x16, 0x05, 0x1c, 0x00, 0x00, 0x17, 0x05,
00553    0x0b, 0x00, 0x00, 0x19, 0x04, 0x00, 0x00, 0x19, 0x04, 0x00, 0x08, 0x19, 0x04, 0x00,
00554       0x10, 0x19, 0x04, 0x00, 0x18, 0x16, 0x05,
00555    0x31, 0x00, 0x00, 0x16, 0x05, 0x04, 0x00, 0x00
00556 };
00557 static const unsigned char packet_send_call[] =
00558    { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00, 0x16, 0x06, 0x32, 0xdf,
00559    0x00, 0xff, 0x16, 0x05, 0x1c, 0x00, 0x00, 0x16, 0x0a, 0x38, 0x00, 0x12, 0xca, 0x03,
00560       0xc0, 0xc3, 0xc5, 0x16, 0x16, 0x30, 0x00,
00561    0x00, /*codec */ 0x12, 0x12, /* frames per packet */ 0x01, 0x5c, 0x00, /*port RTP */
00562       0x0f, 0xa0, /* port RTCP */ 0x9c, 0x41,
00563    /*port RTP */ 0x0f, 0xa0, /* port RTCP */ 0x9c, 0x41, /* IP Address */ 0x0a, 0x01,
00564       0x16, 0x66
00565 };
00566 static const unsigned char packet_send_stream_based_tone_off[] =
00567    { 0x16, 0x05, 0x1c, 0x00, 0x00 };
00568 
00569 static const unsigned char packet_send_mute[] = { 0x16, 0x05, 0x04, 0x00, 0x00 };
00570 static const unsigned char packet_send_CloseAudioStreamRX[] = { 0x16, 0x05, 0x31, 0x00, 0xff };
00571 static const unsigned char packet_send_CloseAudioStreamTX[] = { 0x16, 0x05, 0x31, 0xff, 0x00 };
00572 static const unsigned char packet_send_stream_based_tone_on[] =
00573    { 0x16, 0x06, 0x1b, 0x00, 0x00, 0x05 };
00574 static const unsigned char packet_send_stream_based_tone_single_freq[] =
00575    { 0x16, 0x06, 0x1d, 0x00, 0x01, 0xb8 };
00576 static const unsigned char packet_send_stream_based_tone_dial_freq[] =
00577    { 0x16, 0x08, 0x1d, 0x00, 0x01, 0xb8, 0x01, 0x5e };
00578 static const unsigned char packet_send_select_output[] =
00579    { 0x16, 0x06, 0x32, 0xc0, 0x01, 0x00 };
00580 
00581 static const unsigned char packet_send_ring[] =
00582    { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x1c, 0x00, 0x00, 0x16,
00583    0x04, 0x1a, 0x01, 0x16, 0x05, 0x12, 0x13 /* Ring type 10 to 17 */ , 0x18, 0x16, 0x04, 0x18,     /* volume 00, 10, 20... */
00584    0x20, 0x16, 0x04, 0x10, 0x00
00585 };
00586 //static const unsigned char packet_send_end_call[] =
00587 // { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x31, 0x00, 0x00, /* Headset LED off */ 0x19, 0x04, 0x00,
00588 //0x10, /* Mute LED off */ 0x19, 0x04, 0x00, 0x18,/* Stream unmute */ 0x16, 0x05, 0x04, 0x00, 0x00, /* Query RTCP */ 0x16, 0x04, 0x37, 0x10 };
00589 static const unsigned char packet_send_end_call[] =
00590    { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x31, 0x00, 0x00, /* Query RTCP */ 0x16, 0x04, 0x37, 0x10 };
00591 static const unsigned char packet_send_s9[] =
00592    { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x19, 0x04, 0x00, 0x10, 0x16, 0x05, 0x1c, 0x00,
00593 0x00 };
00594 static const unsigned char packet_send_rtp_packet_size[] =
00595    { 0x16, 0x08, 0x38, 0x00, 0x00, 0xe0, 0x00, 0xa0 };
00596 static const unsigned char packet_send_jitter_buffer_conf[] =
00597    { 0x16, 0x0e, 0x3a, 0x00, /* jitter */ 0x02, /* high water mark */ 0x04, 0x00, 0x00,
00598 /* early packet resync 2 bytes */ 0x3e, 0x80,
00599    0x00, 0x00, /* late packet resync 2 bytes */ 0x3e, 0x80
00600 };
00601 
00602 /* Duration in ms div 2 (0x20 = 64ms, 0x08 = 16ms)
00603 static unsigned char packet_send_StreamBasedToneCad[] =
00604   { 0x16, 0x0a, 0x1e, 0x00, duration on  0x0a, duration off  0x0d, duration on 0x0a, duration off 0x0d, duration on 0x0a, duration off 0x2b }; */
00605 static const unsigned char packet_send_open_audio_stream_rx[] =
00606    { 0x16, 0x1a, 0x30, 0x00, 0xff, /* Codec */ 0x00, 0x00, 0x01, 0x00, 0xb8, 0xb8, 0x0e,
00607 0x0e, 0x01, /* Port */ 0x14, 0x50, 0x00,
00608    0x00, /* Port */ 0x14, 0x50, 0x00, 0x00, /* Dest IP */ 0x0a, 0x93, 0x69, 0x05
00609 };
00610 static const unsigned char packet_send_open_audio_stream_tx[] =
00611    { 0x16, 0x1a, 0x30, 0xff, 0x00, 0x00, /* Codec */ 0x00, 0x01, 0x00, 0xb8, 0xb8, 0x0e,
00612 0x0e, 0x01, /* Local port */ 0x14, 0x50,
00613    0x00, 0x00, /* Rmt Port */ 0x14, 0x50, 0x00, 0x00, /* Dest IP */ 0x0a, 0x93, 0x69, 0x05
00614 };
00615 
00616 static const unsigned char packet_send_open_audio_stream_rx3[] =
00617    { 0x16, 0x1a, 0x30, 0x00, 0xff, /* Codec */ 0x00, 0x00, 0x02, 0x01, 0xb8, 0xb8, 0x06,
00618 0x06, 0x81, /* RTP Port */ 0x14, 0x50,
00619 /* RTCP Port */ 0x14,
00620    0x51, /* RTP Port */ 0x14, 0x50, /* RTCP Port */ 0x00, 0x00, /* Dest IP */ 0x0a, 0x93,
00621       0x69, 0x05
00622 };
00623 static const unsigned char packet_send_open_audio_stream_tx3[] =
00624    { 0x16, 0x1a, 0x30, 0xff, 0x00, 0x00, /* Codec */ 0x00, 0x02, 0x01, 0xb8, 0xb8, 0x06,
00625 0x06, 0x81, /* RTP Local port */ 0x14, 0x50,
00626    /* RTCP Port */ 0x00, 0x00, /* RTP Rmt Port */ 0x14, 0x50, /* RTCP Port */ 0x00, 0x00,
00627       /* Dest IP */ 0x0a, 0x93, 0x69, 0x05
00628 };
00629 
00630 static const unsigned char packet_send_arrow[] = { 0x17, 0x04, 0x04, 0x00 };
00631 static const unsigned char packet_send_blink_cursor[] = { 0x17, 0x04, 0x10, 0x86 };
00632 static const unsigned char packet_send_date_time2[] = { 0x17, 0x04, 0x17, 0x3d, 0x11, 0x09, 0x02, 0x0a, /*Month */ 0x05,   /*Day */
00633    0x06, /*Hour */ 0x07, /*Minutes */ 0x08, 0x32
00634 };
00635 static const unsigned char packet_send_Contrast[] =
00636    { 0x17, 0x04, 0x24, /*Contrast */ 0x08 };
00637 static const unsigned char packet_send_start_timer[] =
00638    { 0x17, 0x05, 0x0b, /*Timer option*/0x05, /* Timer ID */0x00, 0x17, 0x08, 0x16,
00639    /* Text */ 'T', 'i', 'm', 'e', 'r' };
00640 static const unsigned char packet_send_stop_timer[] = { 0x17, 0x05, 0x0b, 0x02, 0x00 };
00641 static const unsigned char packet_send_icon[] = { 0x17, 0x05, 0x14, /*pos */ 0x00, /*icon */ 0x25 };      /* display an icon in front of the text zone */
00642 static const unsigned char packet_send_S7[] = { 0x17, 0x06, 0x0f, 0x30, 0x07, 0x07 };
00643 static const unsigned char packet_send_set_pos_cursor[] =
00644    { 0x17, 0x06, 0x10, 0x81, 0x04, /*pos */ 0x20 };
00645 
00646 static unsigned char monthlabels[] =
00647    { 'J', 'a', 'n', 'F', 'e', 'b', 'M', 'a', 'r', 'A', 'p', 'r', 'M', 'a', 'y', 'J', 'u', 'n',
00648       'J', 'u', 'l', 'A', 'u', 'g', 'S', 'e', 'p', 'O', 'c', 't', 'N', 'o', 'v', 'D', 'e', 'c' };
00649 static unsigned char packet_send_monthlabels_download[] =
00650   { 0x17, 0x0a, 0x15, /* Month (3 char) */ '-', '-', '-', '-', '-', '-', 0x20 };
00651 static const unsigned char packet_send_favorite[] =
00652    { 0x17, 0x0f, 0x19, 0x10, /*pos */ 0x01, /*name */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
00653 0x20, 0x20, 0x20, 0x20, /*end_name */ 0x19,
00654    0x05, 0x0f, /*pos */ 0x01, /*icone */ 0x00
00655 };
00656 static const unsigned char packet_send_title[] =
00657    { 0x17, 0x10, 0x19, 0x02, /*text */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
00658 0x20, 0x20, 0x20, 0x20 /*end_text */  };
00659 static const unsigned char packet_send_text[] =
00660    { 0x17, 0x1e, 0x1b, 0x04, /*pos */ 0x00, /*inverse */ 0x25, /*text */ 0x20, 0x20,
00661 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
00662    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
00663       /*end_text */ 0x17, 0x04, 0x10, 0x87
00664 };
00665 static const unsigned char packet_send_status[] =
00666    { 0x17, 0x20, 0x19, 0x08, /*text */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
00667 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
00668    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20    /*end_text */
00669 };
00670 static const unsigned char packet_send_status2[] =
00671    { 0x17, 0x0b, 0x19, /* pos [08|28|48|68] */ 0x00, /* text */ 0x20, 0x20, 0x20, 0x20,
00672 0x20, 0x20, 0x20 /* end_text */  };
00673 
00674 /* Multiple character set support */
00675 /* ISO-8859-1 - Western European) */
00676 static const unsigned char packet_send_charset_iso_8859_1[] =
00677    { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x41, 0x1b, 0x00 };
00678 /* ISO-8859-2 - Central European) */
00679 static const unsigned char packet_send_charset_iso_8859_2[] =
00680    { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x42, 0x1b, 0x00 };
00681 /* ISO-8859-4 - Baltic) */
00682 static const unsigned char packet_send_charset_iso_8859_4[] =
00683    { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x44, 0x1b, 0x00 };
00684 /* ISO 8859-5 - cyrilic */
00685 static const unsigned char packet_send_charset_iso_8859_5[] =
00686    { 0x17, 0x08, 0x21, 0x1b, 0x2d, 0x4c, 0x1b, 0x00 };
00687 /* Japaneese (ISO-2022-JP ?) */
00688 static const unsigned char packet_send_charset_iso_2022_jp[] =
00689    { 0x17, 0x08, 0x21, 0x1b, 0x29, 0x49, 0x1b, 0x7e };
00690 
00691 static const unsigned char packet_send_led_update[] = { 0x19, 0x04, 0x00, 0x00 };
00692 
00693 static const unsigned char packet_send_query_basic_manager_04[] = { 0x1a, 0x04, 0x01, 0x04 };
00694 static const unsigned char packet_send_query_mac_address[] = { 0x1a, 0x04, 0x01, 0x08 };
00695 static const unsigned char packet_send_query_basic_manager_10[] = { 0x1a, 0x04, 0x01, 0x10 };
00696 static const unsigned char packet_send_S1[] = { 0x1a, 0x07, 0x07, 0x00, 0x00, 0x00, 0x13 };
00697 
00698 static unsigned char packet_send_ping[] =
00699    { 0x1e, 0x05, 0x12, 0x00, /*Watchdog timer */ 0x78 };
00700 
00701 #define BUFFSEND unsigned char buffsend[64] = { 0x00, 0x00, 0xaa, 0xbb, 0x02, 0x01 }
00702 
00703 static const char tdesc[] = "UNISTIM Channel Driver";
00704 static const char channel_type[] = "USTM";
00705 
00706 /*! Protos */
00707 static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor);
00708 static int load_module(void);
00709 static int reload(void);
00710 static int unload_module(void);
00711 static int reload_config(void);
00712 static void unistim_set_owner(struct unistim_subchannel *sub, struct ast_channel *chan);
00713 static void show_main_page(struct unistimsession *pte);
00714 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,
00715    const char *dest, int *cause);
00716 static int unistim_call(struct ast_channel *ast, const char *dest, int timeout);
00717 static int unistim_hangup(struct ast_channel *ast);
00718 static int unistim_answer(struct ast_channel *ast);
00719 static struct ast_frame *unistim_read(struct ast_channel *ast);
00720 static int unistim_write(struct ast_channel *ast, struct ast_frame *frame);
00721 static int unistim_indicate(struct ast_channel *ast, int ind, const void *data,
00722    size_t datalen);
00723 static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00724 static int unistim_senddigit_begin(struct ast_channel *ast, char digit);
00725 static int unistim_senddigit_end(struct ast_channel *ast, char digit,
00726    unsigned int duration);
00727 static int unistim_sendtext(struct ast_channel *ast, const char *text);
00728 
00729 static int write_entry_history(struct unistimsession *pte, FILE * f, char c,
00730    char *line1);
00731 static void change_callerid(struct unistimsession *pte, int type, char *callerid);
00732 
00733 static struct ast_channel_tech unistim_tech = {
00734    .type = channel_type,
00735    .description = tdesc,
00736    .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
00737    .requester = unistim_request,
00738    .call = unistim_call,
00739    .hangup = unistim_hangup,
00740    .answer = unistim_answer,
00741    .read = unistim_read,
00742    .write = unistim_write,
00743    .indicate = unistim_indicate,
00744    .fixup = unistim_fixup,
00745    .send_digit_begin = unistim_senddigit_begin,
00746    .send_digit_end = unistim_senddigit_end,
00747    .send_text = unistim_sendtext,
00748 };
00749 
00750 static void send_start_rtp(struct unistim_subchannel *);
00751 
00752 static void send_callerid_screen(struct unistimsession *, struct unistim_subchannel *);
00753 static void key_favorite(struct unistimsession *, char);
00754 
00755 static void handle_select_codec(struct unistimsession *);
00756 static void handle_select_language(struct unistimsession *);
00757 static int find_language(const char*);
00758 
00759 static int unistim_free_sub(struct unistim_subchannel *);
00760 
00761 static struct unistim_menu_item options_menu[] =
00762 {
00763    {"Change codec", STATE_SELECTCODEC, handle_select_codec},
00764    {"Language", STATE_SELECTLANGUAGE, handle_select_language},
00765    {NULL, 0, NULL}
00766 };
00767 
00768 static struct unistim_languages options_languages[] =
00769 {
00770    {"English", "en", ISO_8859_1, NULL},
00771    {"French", "fr", ISO_8859_1, NULL},
00772    {"Russian", "ru", ISO_8859_5, NULL},
00773    {NULL, NULL, 0, NULL}
00774 };
00775 
00776 static char ustm_strcopy[1024];
00777 
00778 struct ustm_lang_entry {
00779    const char *str_orig;
00780    const char *str_trans;
00781 };
00782 
00783 static int lang_hash_fn(const void *obj, const int flags)
00784 {
00785    const struct ustm_lang_entry *entry = obj;
00786    return ast_str_hash(entry->str_orig);
00787 }
00788 
00789 static int lang_cmp_fn(void *obj, void *arg, int flags)
00790 {
00791    struct ustm_lang_entry *entry1 = obj;
00792    struct ustm_lang_entry *entry2 = arg;
00793 
00794    return (!strcmp(entry1->str_orig, entry2->str_orig)) ? (CMP_MATCH | CMP_STOP) : 0;
00795 }
00796 
00797 static const char *ustmtext(const char *str, struct unistimsession *pte)
00798 {
00799    struct ustm_lang_entry *lang_entry;
00800    struct ustm_lang_entry le_search;
00801    struct unistim_languages *lang = NULL;
00802    int size;
00803 
00804    if (pte->device) {
00805       lang = &options_languages[find_language(pte->device->language)];
00806    }
00807    if (!lang) {
00808       return str;
00809    }
00810    /* Check if specified language exists */
00811    if (!lang->trans) {
00812       char tmp[1024], *p, *p_orig = NULL, *p_trans = NULL;
00813       FILE *f;
00814 
00815       if (!(lang->trans = ao2_container_alloc(8, lang_hash_fn, lang_cmp_fn))) {
00816          ast_log(LOG_ERROR, "Unable to allocate container for translation!\n");
00817          return str;
00818       }
00819       snprintf(tmp, sizeof(tmp), "%s/%s/%s.po", ast_config_AST_VAR_DIR,
00820           USTM_LANG_DIR, lang->lang_short);
00821       f = fopen(tmp, "r");
00822       if (!f) {
00823          ast_log(LOG_WARNING, "There is no translation file for '%s'\n", lang->lang_short);
00824          return str;
00825       }
00826       while (fgets(tmp, sizeof(tmp), f)) {
00827          if (!(p = strchr(tmp, '\n'))) {
00828             ast_log(LOG_ERROR, "Too long line found in language file - truncated!\n");
00829             continue;
00830          }
00831          *p = '\0';
00832          if (!(p = strchr(tmp, '"'))) {
00833             continue;
00834          }
00835          if (tmp == strstr(tmp, "msgid")) {
00836             p_orig = ast_strdup(p + 1);
00837             p = strchr(p_orig, '"');
00838          } else if (tmp == strstr(tmp, "msgstr")) {
00839             p_trans = ast_strdup(p + 1);
00840             p = strchr(p_trans, '"');
00841          } else {
00842             continue;
00843          }
00844          *p = '\0';
00845          if (!p_trans || !p_orig) {
00846             continue;
00847          }
00848          if (ast_strlen_zero(p_trans)) {
00849             ast_free(p_trans);
00850             ast_free(p_orig);
00851             p_trans = NULL;
00852             p_orig = NULL;
00853             continue;
00854          }
00855          if (!(lang_entry = ao2_alloc(sizeof(*lang_entry), NULL))) {
00856             fclose(f);
00857             return str;
00858          }
00859 
00860          lang_entry->str_trans = p_trans;
00861          lang_entry->str_orig = p_orig;
00862          ao2_link(lang->trans, lang_entry);
00863          p_trans = NULL;
00864          p_orig = NULL;
00865       }
00866 
00867       fclose(f);
00868    }
00869 
00870    le_search.str_orig = str;
00871    if ((lang_entry = ao2_find(lang->trans, &le_search, OBJ_POINTER))) {
00872       size = strlen(lang_entry->str_trans)+1;
00873          if (size > 1024) {
00874          size = 1024;
00875       }
00876       memcpy(ustm_strcopy, lang_entry->str_trans, size);
00877       ao2_ref(lang_entry, -1);
00878       return ustm_strcopy;
00879    }
00880 
00881    return str;
00882 }
00883 
00884 static void display_last_error(const char *sz_msg)
00885 {
00886    /* Display the error message */
00887    ast_log(LOG_WARNING, "%s : (%d) %s\n", sz_msg, errno, strerror(errno));
00888 }
00889 
00890 static unsigned int get_tick_count(void)
00891 {
00892    struct timeval now = ast_tvnow();
00893 
00894    return (now.tv_sec * 1000) + (now.tv_usec / 1000);
00895 }
00896 
00897 /* Send data to a phone without retransmit nor buffering */
00898 static void send_raw_client(int size, const unsigned char *data, struct sockaddr_in *addr_to,
00899              const struct sockaddr_in *addr_ourip)
00900 {
00901 #ifdef HAVE_PKTINFO
00902    struct iovec msg_iov;
00903    struct msghdr msg;
00904    char buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
00905    struct cmsghdr *ip_msg = (struct cmsghdr *) buffer;
00906    struct in_pktinfo *pki = (struct in_pktinfo *) CMSG_DATA(ip_msg);
00907 
00908    /* cast this to a non-const pointer, since the sendmsg() API
00909     * does not provide read-only and write-only flavors of the
00910     * structures used for its arguments, but in this case we know
00911     * the data will not be modified
00912     */
00913    msg_iov.iov_base = (char *) data;
00914    msg_iov.iov_len = size;
00915 
00916    msg.msg_name = addr_to;  /* optional address */
00917    msg.msg_namelen = sizeof(struct sockaddr_in);   /* size of address */
00918    msg.msg_iov = &msg_iov;  /* scatter/gather array */
00919    msg.msg_iovlen = 1;          /* # elements in msg_iov */
00920    msg.msg_control = ip_msg;       /* ancillary data */
00921    msg.msg_controllen = sizeof(buffer);    /* ancillary data buffer len */
00922    msg.msg_flags = 0;            /* flags on received message */
00923 
00924    ip_msg->cmsg_len = CMSG_LEN(sizeof(*pki));
00925    ip_msg->cmsg_level = IPPROTO_IP;
00926    ip_msg->cmsg_type = IP_PKTINFO;
00927    pki->ipi_ifindex = 0;      /* Interface index, 0 = use interface specified in routing table */
00928    pki->ipi_spec_dst.s_addr = addr_ourip->sin_addr.s_addr; /* Local address */
00929    /* pki->ipi_addr = ;   Header Destination address - ignored by kernel */
00930 
00931 #ifdef DUMP_PACKET
00932    if (unistimdebug) {
00933       int tmp;
00934       ast_verb(0, "\n**> From %s sending %d bytes to %s ***\n",
00935                ast_inet_ntoa(addr_ourip->sin_addr), (int) size,
00936                ast_inet_ntoa(addr_to->sin_addr));
00937       for (tmp = 0; tmp < size; tmp++)
00938          ast_verb(0, "%02hhx ", data[tmp]);
00939       ast_verb(0, "\n******************************************\n");
00940 
00941    }
00942 #endif
00943 
00944    if (sendmsg(unistimsock, &msg, 0) == -1) {
00945       display_last_error("Error sending datas");
00946    }
00947 #else
00948    if (sendto(unistimsock, data, size, 0, (struct sockaddr *) addr_to, sizeof(*addr_to))
00949       == -1)
00950       display_last_error("Error sending datas");
00951 #endif
00952 }
00953 
00954 static void send_client(int size, const unsigned char *data, struct unistimsession *pte)
00955 {
00956    unsigned int tick;
00957    int buf_pos;
00958    unsigned short seq = ntohs(++pte->seq_server);
00959 
00960    ast_mutex_lock(&pte->lock);
00961    buf_pos = pte->last_buf_available;
00962 
00963    if (buf_pos >= MAX_BUF_NUMBER) {
00964       ast_log(LOG_WARNING, "Error : send queue overflow\n");
00965       ast_mutex_unlock(&pte->lock);
00966       return;
00967    }
00968    memcpy((void *)data + sizeof(unsigned short), (void *)&seq, sizeof(unsigned short));
00969    pte->wsabufsend[buf_pos].len = size;
00970    memcpy(pte->wsabufsend[buf_pos].buf, data, size);
00971 
00972    tick = get_tick_count();
00973    pte->timeout = tick + RETRANSMIT_TIMER;
00974 
00975 /*#ifdef DUMP_PACKET */
00976    if (unistimdebug) {
00977       ast_verb(0, "Sending datas with seq #0x%04x Using slot #%d :\n", (unsigned)pte->seq_server, buf_pos);
00978    }
00979 /*#endif */
00980    send_raw_client(pte->wsabufsend[buf_pos].len, pte->wsabufsend[buf_pos].buf, &(pte->sin),
00981               &(pte->sout));
00982    pte->last_buf_available++;
00983    ast_mutex_unlock(&pte->lock);
00984 }
00985 
00986 static void send_ping(struct unistimsession *pte)
00987 {
00988    BUFFSEND;
00989    if (unistimdebug) {
00990       ast_verb(0, "Sending ping\n");
00991    }
00992    pte->tick_next_ping = get_tick_count() + unistim_keepalive;
00993    memcpy(buffsend + SIZE_HEADER, packet_send_ping, sizeof(packet_send_ping));
00994    send_client(SIZE_HEADER + sizeof(packet_send_ping), buffsend, pte);
00995 }
00996 
00997 static int get_to_address(int fd, struct sockaddr_in *toAddr)
00998 {
00999 #ifdef HAVE_PKTINFO
01000    int err;
01001    struct msghdr msg;
01002    struct {
01003       struct cmsghdr cm;
01004       int len;
01005       struct in_addr address;
01006    } ip_msg;
01007 
01008    /* Zero out the structures before we use them */
01009    /* This sets several key values to NULL */
01010    memset(&msg, 0, sizeof(msg));
01011    memset(&ip_msg, 0, sizeof(ip_msg));
01012 
01013    /* Initialize the message structure */
01014    msg.msg_control = &ip_msg;
01015    msg.msg_controllen = sizeof(ip_msg);
01016    /* Get info about the incoming packet */
01017    err = recvmsg(fd, &msg, MSG_PEEK);
01018    if (err == -1) {
01019       ast_log(LOG_WARNING, "recvmsg returned an error: %s\n", strerror(errno));
01020    }
01021    memcpy(&toAddr->sin_addr, &ip_msg.address, sizeof(struct in_addr));
01022    return err;
01023 #else
01024    memcpy(&toAddr, &public_ip, sizeof(&toAddr));
01025    return 0;
01026 #endif
01027 }
01028 
01029 /* Allocate memory & initialize structures for a new phone */
01030 /* addr_from : ip address of the phone */
01031 static struct unistimsession *create_client(const struct sockaddr_in *addr_from)
01032 {
01033    int tmp;
01034    struct unistimsession *s;
01035 
01036    if (!(s = ast_calloc(1, sizeof(*s))))
01037       return NULL;
01038 
01039    memcpy(&s->sin, addr_from, sizeof(struct sockaddr_in));
01040    get_to_address(unistimsock, &s->sout);
01041    s->sout.sin_family = AF_INET;
01042    if (unistimdebug) {
01043       ast_verb(0, "Creating a new entry for the phone from %s received via server ip %s\n",
01044           ast_inet_ntoa(addr_from->sin_addr), ast_inet_ntoa(s->sout.sin_addr));
01045    }
01046    ast_mutex_init(&s->lock);
01047    ast_mutex_lock(&sessionlock);
01048    s->next = sessions;
01049    sessions = s;
01050 
01051    s->timeout = get_tick_count() + RETRANSMIT_TIMER;
01052    s->state = STATE_INIT;
01053    s->tick_next_ping = get_tick_count() + unistim_keepalive;
01054    /* Initialize struct wsabuf  */
01055    for (tmp = 0; tmp < MAX_BUF_NUMBER; tmp++) {
01056       s->wsabufsend[tmp].buf = s->buf[tmp];
01057    }
01058    ast_mutex_unlock(&sessionlock);
01059    return s;
01060 }
01061 
01062 static void send_end_call(struct unistimsession *pte)
01063 {
01064    BUFFSEND;
01065    if (unistimdebug) {
01066       ast_verb(0, "Sending end call\n");
01067    }
01068    memcpy(buffsend + SIZE_HEADER, packet_send_end_call, sizeof(packet_send_end_call));
01069    send_client(SIZE_HEADER + sizeof(packet_send_end_call), buffsend, pte);
01070 }
01071 
01072 static void set_ping_timer(struct unistimsession *pte)
01073 {
01074    unsigned int tick = 0;  /* XXX what is this for, anyways */
01075 
01076    pte->timeout = pte->tick_next_ping;
01077    DEBUG_TIMER("tick = %u next ping at %u tick\n", tick, pte->timeout);
01078    return;
01079 }
01080 
01081 /* Checking if our send queue is empty,
01082  * if true, setting up a timer for keepalive */
01083 static void check_send_queue(struct unistimsession *pte)
01084 {
01085    /* Check if our send queue contained only one element */
01086    if (pte->last_buf_available == 1) {
01087       if (unistimdebug) {
01088          ast_verb(0, "Our single packet was ACKed.\n");
01089       }
01090       pte->last_buf_available--;
01091       set_ping_timer(pte);
01092       return;
01093    }
01094    /* Check if this ACK catch up our latest packet */
01095    else if (pte->last_seq_ack + 1 == pte->seq_server + 1) {
01096       if (unistimdebug) {
01097          ast_verb(0, "Our send queue is completely ACKed.\n");
01098       }
01099       pte->last_buf_available = 0;    /* Purge the send queue */
01100       set_ping_timer(pte);
01101       return;
01102    }
01103    if (unistimdebug) {
01104       ast_verb(0, "We still have packets in our send queue\n");
01105    }
01106    return;
01107 }
01108 
01109 static void send_start_timer(struct unistimsession *pte)
01110 {
01111    BUFFSEND;
01112    if (unistimdebug) {
01113       ast_verb(0, "Sending start timer\n");
01114    }
01115    memcpy(buffsend + SIZE_HEADER, packet_send_start_timer, sizeof(packet_send_start_timer));
01116    send_client(SIZE_HEADER + sizeof(packet_send_start_timer), buffsend, pte);
01117 }
01118 
01119 static void send_stop_timer(struct unistimsession *pte)
01120 {
01121    BUFFSEND;
01122    if (unistimdebug) {
01123       ast_verb(0, "Sending stop timer\n");
01124    }
01125    memcpy(buffsend + SIZE_HEADER, packet_send_stop_timer, sizeof(packet_send_stop_timer));
01126    send_client(SIZE_HEADER + sizeof(packet_send_stop_timer), buffsend, pte);
01127 }
01128 
01129 static void send_icon(unsigned char pos, unsigned char status, struct unistimsession *pte)
01130 {
01131    BUFFSEND;
01132    if (unistimdebug) {
01133       ast_verb(0, "Sending icon pos %d with status 0x%02hhx\n", pos, status);
01134    }
01135    memcpy(buffsend + SIZE_HEADER, packet_send_icon, sizeof(packet_send_icon));
01136    buffsend[9] = pos;
01137    buffsend[10] = status;
01138    send_client(SIZE_HEADER + sizeof(packet_send_icon), buffsend, pte);
01139 }
01140 
01141 static void send_expansion_next(struct unistimsession *pte)
01142 {
01143    BUFFSEND;
01144    memcpy(buffsend + SIZE_HEADER, packet_send_expansion_next, sizeof(packet_send_expansion_next));
01145    send_client(SIZE_HEADER + sizeof(packet_send_expansion_next), buffsend, pte);
01146 }
01147 
01148 
01149 static void send_expansion_icon(unsigned char pos, unsigned char status, struct unistimsession *pte)
01150 {
01151    BUFFSEND;
01152    if (unistimdebug) {
01153       ast_verb(0, "Sending expansion icon pos %d with status 0x%02hhx\n", pos, status);
01154    }
01155    memcpy(buffsend + SIZE_HEADER, packet_send_expansion_icon, sizeof(packet_send_expansion_icon));
01156    buffsend[10] = pos;
01157    buffsend[11] = status;
01158    send_client(SIZE_HEADER + sizeof(packet_send_expansion_icon), buffsend, pte);
01159 }
01160 
01161 /* inverse : TEXT_INVERSE : yes, TEXT_NORMAL  : no */
01162 static void send_expansion_text(unsigned char pos, struct unistimsession *pte, const char *text)
01163 {
01164    int i;
01165    BUFFSEND;
01166    if (!text) {
01167       ast_log(LOG_ERROR, "[expansion] Asked to display NULL text (pos %d)\n", pos);
01168       return;
01169    }
01170    if (unistimdebug) {
01171       ast_verb(0, "[expansion] Sending text at pos %d\n", pos);
01172    }
01173    memcpy(buffsend + SIZE_HEADER, packet_send_expansion_text, sizeof(packet_send_expansion_text));
01174    buffsend[10] = pos;
01175    i = strlen(text);
01176    if (i > TEXT_LENGTH_MAX) {
01177       i = TEXT_LENGTH_MAX;
01178    }
01179    memcpy(buffsend + 11, text, i);
01180    send_client(SIZE_HEADER + sizeof(packet_send_expansion_text), buffsend, pte);
01181 }
01182 
01183 static void send_tone(struct unistimsession *pte, uint16_t tone1, uint16_t tone2)
01184 {
01185    BUFFSEND;
01186    if (!tone1) {
01187       if (unistimdebug) {
01188          ast_verb(0, "Sending Stream Based Tone Off\n");
01189       }
01190       memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_off,
01191             sizeof(packet_send_stream_based_tone_off));
01192       send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_off), buffsend, pte);
01193       return;
01194    }
01195    /* Since most of the world use a continuous tone, it's useless
01196       if (unistimdebug)
01197       ast_verb(0, "Sending Stream Based Tone Cadence Download\n");
01198       memcpy (buffsend + SIZE_HEADER, packet_send_StreamBasedToneCad, sizeof (packet_send_StreamBasedToneCad));
01199       send_client (SIZE_HEADER + sizeof (packet_send_StreamBasedToneCad), buffsend, pte); */
01200    if (unistimdebug) {
01201       ast_verb(0, "Sending Stream Based Tone Frequency Component List Download %d %d\n", tone1, tone2);
01202    }
01203    tone1 *= 8;
01204    if (!tone2) {
01205       memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_single_freq,
01206             sizeof(packet_send_stream_based_tone_single_freq));
01207       buffsend[10] = (tone1 & 0xff00) >> 8;
01208       buffsend[11] = (tone1 & 0x00ff);
01209       send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_single_freq), buffsend,
01210                pte);
01211    } else {
01212       tone2 *= 8;
01213       memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_dial_freq,
01214             sizeof(packet_send_stream_based_tone_dial_freq));
01215       buffsend[10] = (tone1 & 0xff00) >> 8;
01216       buffsend[11] = (tone1 & 0x00ff);
01217       buffsend[12] = (tone2 & 0xff00) >> 8;
01218       buffsend[13] = (tone2 & 0x00ff);
01219       send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_dial_freq), buffsend,
01220                pte);
01221    }
01222 
01223    if (unistimdebug) {
01224       ast_verb(0, "Sending Stream Based Tone On\n");
01225    }
01226    memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_on,
01227          sizeof(packet_send_stream_based_tone_on));
01228    send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_on), buffsend, pte);
01229 }
01230 
01231 /* Positions for favorites
01232  |--------------------|
01233  |  5          2    | <-- not on screen in i2002
01234  |  4          1    |
01235  |  3          0    |
01236 
01237 
01238  KEM Positions
01239 
01240  |--------------------|
01241  |  12            24   |
01242  |  11            23   |
01243  |  10            22   |
01244  |  9          21   |
01245  |  8          20   |
01246  |  7          19   |
01247  |  6          18   |
01248  |  5          17   |
01249  |  4          16   |
01250  |  3          15   |
01251  |  2          14   |
01252  |  1          13   |
01253 
01254 */
01255 
01256 /* status (icons) : 00 = nothing, 2x/3x = see parser.h, 4x/5x = blink fast, 6x/7x = blink slow */
01257 static void
01258 send_favorite(unsigned char pos, unsigned char status, struct unistimsession *pte,
01259           const char *text)
01260 {
01261    BUFFSEND;
01262    int i;
01263 
01264    if (unistimdebug) {
01265       ast_verb(0, "Sending favorite pos %d with status 0x%02hhx\n", pos, status);
01266    }
01267    memcpy(buffsend + SIZE_HEADER, packet_send_favorite, sizeof(packet_send_favorite));
01268    buffsend[10] = pos;
01269    buffsend[24] = pos;
01270    buffsend[25] = status;
01271    i = strlen(ustmtext(text, pte));
01272    if (i > FAV_MAX_LENGTH) {
01273       i = FAV_MAX_LENGTH;
01274    }
01275    memcpy(buffsend + FAV_MAX_LENGTH + 1, ustmtext(text, pte), i);
01276    send_client(SIZE_HEADER + sizeof(packet_send_favorite), buffsend, pte);
01277 }
01278 
01279 static void send_favorite_short(unsigned char pos, unsigned char status, struct unistimsession *pte) {
01280    send_favorite(pos, status, pte, pte->device->softkeylabel[pos]);
01281    return;
01282 }
01283 
01284 static void send_favorite_selected(unsigned char status, struct unistimsession *pte) {
01285    if (pte->device->selected != -1) {
01286       send_favorite(pte->device->selected, status, pte, pte->device->softkeylabel[pte->device->selected]);
01287    }
01288    return;
01289 }
01290 
01291 static void send_expansion_short(unsigned char pos, unsigned char status, struct unistimsession *pte) {
01292    send_expansion_icon(pos, status, pte);
01293    send_expansion_text(pos, pte, ustmtext(pte->device->expsoftkeylabel[pos], pte));
01294    send_expansion_next(pte);
01295    return;
01296 }
01297 
01298 static int soft_key_visible(struct unistim_device* d, unsigned char num)
01299 {
01300    if(d->height == 1 && num % 3 == 2) {
01301       return 0;
01302    }
01303    return 1;
01304 }
01305 
01306 static void refresh_all_favorite(struct unistimsession *pte)
01307 {
01308    unsigned char i = 0;
01309    char data[256];
01310    struct unistim_line *line;
01311    line = AST_LIST_FIRST(&pte->device->lines);
01312 
01313    if (unistimdebug) {
01314       ast_verb(0, "Refreshing all favorite\n");
01315    }
01316    for (i = 0; i < FAVNUM; i++) {
01317       unsigned char status = pte->device->softkeyicon[i];
01318 
01319       if (!soft_key_visible(pte->device, i)) {
01320          continue;
01321       }
01322       if (!strcasecmp(pte->device->softkeylabel[i], "DND") && line) {
01323          if (!ast_db_get("DND", line->name, data, sizeof(data))) {
01324             status = FAV_ICON_SPEAKER_ONHOOK_WHITE;
01325          }
01326       }
01327 
01328       send_favorite_short(i, status, pte);
01329    }
01330    if (pte->device->hasexp) {
01331       for (i = 0; i < EXPNUM; i++) {
01332          send_expansion_short(i, FAV_ICON_NONE, pte);
01333       }
01334    }
01335 }
01336 
01337 static int is_key_favorite(struct unistim_device *d, int fav)
01338 {
01339    if ((fav < 0) && (fav > 5)) {
01340       return 0;
01341    }
01342    if (d->sline[fav]) {
01343       return 0;
01344    }
01345    if (d->softkeynumber[fav][0] == '\0') {
01346       return 0;
01347    }
01348    return 1;
01349 }
01350 
01351 static int is_key_line(struct unistim_device *d, int fav)
01352 {
01353    if ((fav < 0) && (fav > 5)) {
01354       return 0;
01355    }
01356    if (!d->sline[fav]) {
01357       return 0;
01358    }
01359    if (is_key_favorite(d, fav)) {
01360       return 0;
01361    }
01362    return 1;
01363 }
01364 
01365 static int get_active_softkey(struct unistimsession *pte)
01366 {
01367    return pte->device->selected;
01368 }
01369 
01370 static int get_avail_softkey(struct unistimsession *pte, const char* name)
01371 {
01372    int i;
01373 
01374    if (!is_key_line(pte->device, pte->device->selected)) {
01375       pte->device->selected = -1;
01376    }
01377    for (i = 0; i < FAVNUM; i++) {
01378       if (pte->device->selected != -1 && pte->device->selected != i) {
01379          continue;
01380       }
01381       if (!soft_key_visible(pte->device, i)) {
01382          continue;
01383       }
01384       if (pte->device->ssub[i]) {
01385          continue;
01386       }
01387       if (is_key_line(pte->device, i)) {
01388          if (name && strcmp(name, pte->device->sline[i]->name)) {
01389             continue;
01390          }
01391          if (unistimdebug) {
01392             ast_verb(0, "Found softkey %d for device %s\n", i, name);
01393          }
01394          return i;
01395       }
01396    }
01397    return -1;
01398 }
01399 
01400 
01401 /* Change the status for this phone (pte) and update for each phones where pte is bookmarked
01402  * use FAV_ICON_*_BLACK constant in status parameters */
01403 static void change_favorite_icon(struct unistimsession *pte, unsigned char status)
01404 {
01405    struct unistim_device *d = devices;
01406    int i;
01407    /* Update the current phone line softkey icon */
01408    if (pte->state != STATE_CLEANING) {
01409       int softkeylinepos = get_active_softkey(pte);
01410       if (softkeylinepos != -1) {
01411          send_favorite_short(softkeylinepos, status, pte);
01412       }
01413    }
01414    /* Notify other phones if we're in their bookmark */
01415    while (d) {
01416       for (i = 0; i < FAVNUM; i++) {
01417          if (d->sp[i] == pte->device) {  /* It's us ? */
01418             if (d->softkeyicon[i] != status) {      /* Avoid resending the same icon */
01419                d->softkeyicon[i] = status;
01420                if (d->session) {
01421                   send_favorite(i, status + 1, d->session, d->softkeylabel[i]);
01422                }
01423             }
01424          }
01425       }
01426       d = d->next;
01427    }
01428 }
01429 
01430 static int register_extension(const struct unistimsession *pte)
01431 {
01432    struct unistim_line *line;
01433    line = AST_LIST_FIRST(&pte->device->lines);
01434    if (unistimdebug) {
01435       ast_verb(0, "Trying to register extension '%s' into context '%s' to %s\n",
01436                pte->device->extension_number, pte->device->context,
01437                line->fullname);
01438    }
01439    return ast_add_extension(pte->device->context, 0,
01440                       pte->device->extension_number, 1, NULL, NULL, "Dial",
01441                       line->fullname, 0, "Unistim");
01442 }
01443 
01444 static int unregister_extension(const struct unistimsession *pte)
01445 {
01446    if (unistimdebug) {
01447       ast_verb(0, "Trying to unregister extension '%s' context '%s'\n",
01448                pte->device->extension_number, pte->device->context);
01449    }
01450    return ast_context_remove_extension(pte->device->context,
01451                               pte->device->extension_number, 1, "Unistim");
01452 }
01453 
01454 /* Free memory allocated for a phone */
01455 static void close_client(struct unistimsession *s)
01456 {
01457    struct unistim_subchannel *sub = NULL;
01458    struct unistimsession *cur, *prev = NULL;
01459    ast_mutex_lock(&sessionlock);
01460    cur = sessions;
01461    /* Looking for the session in the linked chain */
01462    while (cur) {
01463       if (cur == s) {
01464          break;
01465       }
01466       prev = cur;
01467       cur = cur->next;
01468    }
01469    if (cur) {                 /* Session found ? */
01470       if (cur->device) {         /* This session was registered ? */
01471          s->state = STATE_CLEANING;
01472          if (unistimdebug) {
01473             ast_verb(0, "close_client session %p device %p\n", s, s->device);
01474          }
01475          change_favorite_icon(s, FAV_ICON_NONE);
01476          ast_mutex_lock(&s->device->lock);
01477          AST_LIST_LOCK(&s->device->subs);
01478          AST_LIST_TRAVERSE_SAFE_BEGIN(&s->device->subs, sub, list) {
01479             if (!sub) {
01480                continue;
01481             }
01482             if (sub->owner) {       /* Call in progress ? */
01483                if (unistimdebug) {
01484                   ast_verb(0, "Aborting call\n");
01485                }
01486                ast_queue_hangup_with_cause(sub->owner, AST_CAUSE_NETWORK_OUT_OF_ORDER);
01487             } else {
01488                if (unistimdebug) {
01489                   ast_debug(1, "Released sub %u of channel %s@%s\n", sub->subtype, sub->parent->name, s->device->name);
01490                }
01491                AST_LIST_REMOVE_CURRENT(list);
01492                unistim_free_sub(sub);
01493             }
01494          }
01495          AST_LIST_TRAVERSE_SAFE_END;
01496          AST_LIST_UNLOCK(&s->device->subs);
01497 
01498          if (!ast_strlen_zero(s->device->extension_number)) {
01499             unregister_extension(s);
01500          }
01501          cur->device->session = NULL;
01502          ast_mutex_unlock(&s->device->lock);
01503       } else {
01504          if (unistimdebug) {
01505             ast_verb(0, "Freeing an unregistered client\n");
01506          }
01507       }
01508       if (prev) {
01509          prev->next = cur->next;
01510       } else {
01511          sessions = cur->next;
01512       }
01513       ast_mutex_destroy(&s->lock);
01514       ast_free(s);
01515    } else {
01516       ast_log(LOG_WARNING, "Trying to delete non-existent session %p?\n", s);
01517    }
01518    ast_mutex_unlock(&sessionlock);
01519    return;
01520 }
01521 
01522 /* Return 1 if the session chained link was modified */
01523 static int send_retransmit(struct unistimsession *pte)
01524 {
01525    int i;
01526 
01527    ast_mutex_lock(&pte->lock);
01528    if (++pte->nb_retransmit >= NB_MAX_RETRANSMIT) {
01529       if (unistimdebug) {
01530          ast_verb(0, "Too many retransmit - freeing client\n");
01531       }
01532       ast_mutex_unlock(&pte->lock);
01533       close_client(pte);
01534       return 1;
01535    }
01536    pte->timeout = get_tick_count() + RETRANSMIT_TIMER;
01537 
01538    for (i = pte->last_buf_available - (pte->seq_server - pte->last_seq_ack);
01539        i < pte->last_buf_available; i++) {
01540       if (i < 0) {
01541          ast_log(LOG_WARNING,
01542                "Asked to retransmit an ACKed slot ! last_buf_available=%d, seq_server = #0x%04x last_seq_ack = #0x%04x\n",
01543                pte->last_buf_available, (unsigned)pte->seq_server, (unsigned)pte->last_seq_ack);
01544          continue;
01545       }
01546 
01547       if (unistimdebug) {
01548          unsigned short *sbuf = (unsigned short *) pte->wsabufsend[i].buf;
01549          unsigned short seq;
01550 
01551          seq = ntohs(sbuf[1]);
01552          ast_verb(0, "Retransmit slot #%d (seq=#0x%04x), last ack was #0x%04x\n", i,
01553                   (unsigned)seq, (unsigned)pte->last_seq_ack);
01554       }
01555       send_raw_client(pte->wsabufsend[i].len, pte->wsabufsend[i].buf, &pte->sin,
01556                  &pte->sout);
01557    }
01558    ast_mutex_unlock(&pte->lock);
01559    return 0;
01560 }
01561 
01562 /* inverse : TEXT_INVERSE : yes, TEXT_NORMAL  : no */
01563 static void send_text(unsigned char pos, unsigned char inverse, struct unistimsession *pte,
01564        const char *text)
01565 {
01566    int i;
01567    BUFFSEND;
01568    if (!text) {
01569       ast_log(LOG_ERROR, "Asked to display NULL text (pos %d, inverse flag %d)\n", pos, inverse);
01570       return;
01571    }
01572    if (pte->device && pte->device->height == 1 && pos != TEXT_LINE0) {
01573       return;
01574    }
01575    if (unistimdebug) {
01576       ast_verb(0, "Sending text at pos %d, inverse flag %d\n", pos, inverse);
01577    }
01578    memcpy(buffsend + SIZE_HEADER, packet_send_text, sizeof(packet_send_text));
01579    buffsend[10] = pos;
01580    buffsend[11] = inverse;
01581    i = strlen(text);
01582    if (i > TEXT_LENGTH_MAX) {
01583       i = TEXT_LENGTH_MAX;
01584    }
01585    memcpy(buffsend + 12, text, i);
01586    send_client(SIZE_HEADER + sizeof(packet_send_text), buffsend, pte);
01587 }
01588 
01589 static void send_text_status(struct unistimsession *pte, const char *text)
01590 {
01591    BUFFSEND;
01592    int i;
01593    if (unistimdebug) {
01594       ast_verb(0, "Sending status text\n");
01595    }
01596    if (pte->device) {
01597       if (pte->device->status_method == 1) {  /* For new firmware and i2050 soft phone */
01598          int n = strlen(text);
01599          /* Must send individual button separately */
01600          int j;
01601          for (i = 0, j = 0; i < 4; i++, j += 7) {
01602             int pos = 0x08 + (i * 0x20);
01603             memcpy(buffsend + SIZE_HEADER, packet_send_status2,
01604                   sizeof(packet_send_status2));
01605 
01606             buffsend[9] = pos;
01607             memcpy(buffsend + 10, (j < n) ? (text + j) : "       ", 7);
01608             send_client(SIZE_HEADER + sizeof(packet_send_status2), buffsend, pte);
01609          }
01610          return;
01611       }
01612    }
01613 
01614    memcpy(buffsend + SIZE_HEADER, packet_send_status, sizeof(packet_send_status));
01615    i = strlen(text);
01616    if (i > STATUS_LENGTH_MAX) {
01617       i = STATUS_LENGTH_MAX;
01618    }
01619    memcpy(buffsend + 10, text, i);
01620    send_client(SIZE_HEADER + sizeof(packet_send_status), buffsend, pte);
01621 
01622 }
01623 
01624 static void send_led_update(struct unistimsession *pte, unsigned char led)
01625 {
01626    BUFFSEND;
01627    if (unistimdebug) {
01628       ast_verb(0, "Sending led_update (%x)\n", (unsigned)led);
01629    }
01630    memcpy(buffsend + SIZE_HEADER, packet_send_led_update, sizeof(packet_send_led_update));
01631    buffsend[9] = led;
01632    send_client(SIZE_HEADER + sizeof(packet_send_led_update), buffsend, pte);
01633 }
01634 
01635 static void send_mute(struct unistimsession *pte, unsigned char mute)
01636 {
01637 /*
01638    0x00 = unmute TX, 0x01 = mute TX
01639    0x20 = unmute RX, 0x21 = mute RX
01640 */
01641    BUFFSEND;
01642    if (unistimdebug) {
01643       ast_verb(0, "Sending mute packet (%x)\n", (unsigned)mute);
01644    }
01645    memcpy(buffsend + SIZE_HEADER, packet_send_mute, sizeof(packet_send_mute));
01646    buffsend[9] = mute;
01647    send_client(SIZE_HEADER + sizeof(packet_send_mute), buffsend, pte);
01648 }
01649 
01650 
01651 /* output = OUTPUT_HANDSET, OUTPUT_HEADPHONE or OUTPUT_SPEAKER
01652  * volume = VOLUME_LOW, VOLUME_NORMAL, VOLUME_INSANELY_LOUD
01653  * mute = MUTE_OFF, MUTE_ON */
01654 static void
01655 send_select_output(struct unistimsession *pte, unsigned char output, unsigned char volume,
01656              unsigned char mute)
01657 {
01658    BUFFSEND;
01659    int mute_icon = -1;
01660    if (unistimdebug) {
01661       ast_verb(0, "Sending select output packet output=%x volume=%x mute=%x\n",
01662          (unsigned)output, (unsigned)volume, (unsigned)mute);
01663    }
01664    memcpy(buffsend + SIZE_HEADER, packet_send_select_output,
01665          sizeof(packet_send_select_output));
01666    buffsend[9] = output;
01667    if (output == OUTPUT_SPEAKER && volume == VOLUME_LOW) {
01668       volume = VOLUME_LOW_SPEAKER;
01669    }
01670    buffsend[10] = volume;
01671    if (mute == MUTE_ON_DISCRET) {
01672       buffsend[11] = MUTE_ON;
01673    } else {
01674       buffsend[11] = mute;
01675    }
01676    send_client(SIZE_HEADER + sizeof(packet_send_select_output), buffsend, pte);
01677    if (output == OUTPUT_HANDSET) {
01678       mute_icon = (mute == MUTE_ON) ? FAV_ICON_ONHOLD_BLACK : FAV_ICON_OFFHOOK_BLACK;
01679       send_led_update(pte, LED_SPEAKER_OFF);
01680       send_led_update(pte, LED_HEADPHONE_OFF);
01681    } else if (output == OUTPUT_HEADPHONE) {
01682       mute_icon = (mute == MUTE_ON)? FAV_ICON_HEADPHONES_ONHOLD : FAV_ICON_HEADPHONES;
01683       send_led_update(pte, LED_SPEAKER_OFF);
01684       send_led_update(pte, LED_HEADPHONE_ON);
01685    } else if (output == OUTPUT_SPEAKER) {
01686       send_led_update(pte, LED_SPEAKER_ON);
01687       send_led_update(pte, LED_HEADPHONE_OFF);
01688       if (pte->device->receiver_state == STATE_OFFHOOK) {
01689          mute_icon = (mute == MUTE_ON)? FAV_ICON_SPEAKER_ONHOLD_BLACK : FAV_ICON_SPEAKER_ONHOOK_BLACK;
01690       } else {
01691          mute_icon = (mute == MUTE_ON)? FAV_ICON_SPEAKER_ONHOLD_BLACK : FAV_ICON_SPEAKER_OFFHOOK_BLACK;
01692       }
01693    } else {
01694       ast_log(LOG_WARNING, "Invalid output (%d)\n", output);
01695    }
01696    if (mute_icon != -1) {
01697       change_favorite_icon(pte, mute_icon);
01698    }
01699    if (output != pte->device->output) {
01700       pte->device->previous_output = pte->device->output;
01701    }
01702    pte->device->output = output;
01703 }
01704 static void send_ring(struct unistimsession *pte, char volume, char style)
01705 {
01706    BUFFSEND;
01707    if (unistimdebug) {
01708       ast_verb(0, "Sending ring packet\n");
01709    }
01710    memcpy(buffsend + SIZE_HEADER, packet_send_ring, sizeof(packet_send_ring));
01711    buffsend[24] = style + 0x10;
01712    buffsend[29] = volume * 0x10;
01713    send_client(SIZE_HEADER + sizeof(packet_send_ring), buffsend, pte);
01714 }
01715 
01716 static void send_no_ring(struct unistimsession *pte)
01717 {
01718    BUFFSEND;
01719    if (unistimdebug) {
01720       ast_verb(0, "Sending no ring packet\n");
01721    }
01722    memcpy(buffsend + SIZE_HEADER, packet_send_no_ring, sizeof(packet_send_no_ring));
01723    send_client(SIZE_HEADER + sizeof(packet_send_no_ring), buffsend, pte);
01724 }
01725 
01726 static void send_texttitle(struct unistimsession *pte, const char *text)
01727 {
01728    BUFFSEND;
01729    int i;
01730    if (unistimdebug) {
01731       ast_verb(0, "Sending title text\n");
01732    }
01733    memcpy(buffsend + SIZE_HEADER, packet_send_title, sizeof(packet_send_title));
01734    i = strlen(text);
01735    if (i > 12) {
01736       i = 12;
01737    }
01738    memcpy(buffsend + 10, text, i);
01739    send_client(SIZE_HEADER + sizeof(packet_send_title), buffsend, pte);
01740 }
01741 
01742 static void send_idle_clock(struct unistimsession *pte)
01743 {
01744    send_text(TEXT_LINE0, TEXT_NORMAL, pte, "");
01745 }
01746 
01747 static void send_month_labels(struct unistimsession *pte, int month)
01748 {
01749    BUFFSEND;
01750    char month_name[MONTH_LABEL_SIZE + 1];
01751    int i = 0;
01752    if (unistimdebug) {
01753            ast_verb(0, "Sending Month Labels\n");
01754    }
01755    month_name[MONTH_LABEL_SIZE] = '\0';
01756    memcpy(buffsend + SIZE_HEADER, packet_send_monthlabels_download, sizeof(packet_send_monthlabels_download));
01757    while (i < 2) {
01758       memcpy(month_name, &monthlabels[month * MONTH_LABEL_SIZE], MONTH_LABEL_SIZE);
01759       memcpy(buffsend + SIZE_HEADER + 3 + i*MONTH_LABEL_SIZE, ustmtext(month_name, pte), MONTH_LABEL_SIZE);
01760       ast_log(LOG_WARNING,"%s\n", month_name);
01761       ast_log(LOG_WARNING,"%s\n", ustmtext(month_name, pte));
01762       month = (month + 1)%12;
01763       i++;
01764    }
01765    send_client(SIZE_HEADER + sizeof(packet_send_monthlabels_download), buffsend, pte);
01766 }
01767 
01768 
01769 static void send_date_time(struct unistimsession *pte)
01770 {
01771    BUFFSEND;
01772    struct timeval now = ast_tvnow();
01773    struct ast_tm atm = { 0, };
01774 
01775    if (unistimdebug) {
01776       ast_verb(0, "Sending Time & Date\n");
01777    }
01778    memcpy(buffsend + SIZE_HEADER, packet_send_date_time, sizeof(packet_send_date_time));
01779    ast_localtime(&now, &atm, NULL);
01780    buffsend[10] = (unsigned char) atm.tm_mon + 1;
01781    buffsend[11] = (unsigned char) atm.tm_mday;
01782    buffsend[12] = (unsigned char) atm.tm_hour;
01783    buffsend[13] = (unsigned char) atm.tm_min;
01784    send_client(SIZE_HEADER + sizeof(packet_send_date_time), buffsend, pte);
01785    send_month_labels(pte, atm.tm_mon);
01786 }
01787 
01788 static void send_date_time2(struct unistimsession *pte)
01789 {
01790    BUFFSEND;
01791    struct timeval now = ast_tvnow();
01792    struct ast_tm atm = { 0, };
01793 
01794    if (unistimdebug) {
01795       ast_verb(0, "Sending Time & Date #2\n");
01796    }
01797    memcpy(buffsend + SIZE_HEADER, packet_send_date_time2, sizeof(packet_send_date_time2));
01798    ast_localtime(&now, &atm, NULL);
01799    if (pte->device) {
01800       buffsend[9] = pte->device->datetimeformat;
01801    } else {
01802       buffsend[9] = 61;
01803    }
01804    buffsend[14] = (unsigned char) atm.tm_mon + 1;
01805    buffsend[15] = (unsigned char) atm.tm_mday;
01806    buffsend[16] = (unsigned char) atm.tm_hour;
01807    buffsend[17] = (unsigned char) atm.tm_min;
01808    send_client(SIZE_HEADER + sizeof(packet_send_date_time2), buffsend, pte);
01809 }
01810 
01811 static void send_date_time3(struct unistimsession *pte)
01812 {
01813    BUFFSEND;
01814    struct timeval now = ast_tvnow();
01815    struct ast_tm atm = { 0, };
01816 
01817    if (unistimdebug) {
01818       ast_verb(0, "Sending Time & Date #3\n");
01819    }
01820    memcpy(buffsend + SIZE_HEADER, packet_send_date_time3, sizeof(packet_send_date_time3));
01821    ast_localtime(&now, &atm, NULL);
01822    buffsend[10] = (unsigned char) atm.tm_mon + 1;
01823    buffsend[11] = (unsigned char) atm.tm_mday;
01824    buffsend[12] = (unsigned char) atm.tm_hour;
01825    buffsend[13] = (unsigned char) atm.tm_min;
01826    send_client(SIZE_HEADER + sizeof(packet_send_date_time3), buffsend, pte);
01827 }
01828 
01829 static void send_blink_cursor(struct unistimsession *pte)
01830 {
01831    BUFFSEND;
01832    if (unistimdebug) {
01833       ast_verb(0, "Sending set blink\n");
01834    }
01835    memcpy(buffsend + SIZE_HEADER, packet_send_blink_cursor, sizeof(packet_send_blink_cursor));
01836    send_client(SIZE_HEADER + sizeof(packet_send_blink_cursor), buffsend, pte);
01837    return;
01838 }
01839 
01840 /* pos : 0xab (a=0/2/4 = line ; b = row) */
01841 static void send_cursor_pos(struct unistimsession *pte, unsigned char pos)
01842 {
01843    BUFFSEND;
01844    if (unistimdebug) {
01845       ast_verb(0, "Sending set cursor position\n");
01846    }
01847    memcpy(buffsend + SIZE_HEADER, packet_send_set_pos_cursor,
01848          sizeof(packet_send_set_pos_cursor));
01849    buffsend[11] = pos;
01850    send_client(SIZE_HEADER + sizeof(packet_send_set_pos_cursor), buffsend, pte);
01851    return;
01852 }
01853 
01854 static void send_charset_update(struct unistimsession *pte, int charset)
01855 {
01856    const unsigned char* packet_send_charset;
01857    int packet_size;
01858    BUFFSEND;
01859    if (unistimdebug) {
01860       ast_verb(0, "Sending set default charset\n");
01861    }
01862    if (charset == LANG_DEFAULT) {
01863       charset = options_languages[find_language(pte->device->language)].encoding;
01864    }
01865    switch (charset) {
01866    case ISO_8859_2:
01867       packet_send_charset = packet_send_charset_iso_8859_2;
01868       packet_size = sizeof(packet_send_charset_iso_8859_2);
01869       break;
01870    case ISO_8859_4:
01871       packet_send_charset = packet_send_charset_iso_8859_4;
01872       packet_size = sizeof(packet_send_charset_iso_8859_4);
01873       break;
01874    case ISO_8859_5:
01875       packet_send_charset = packet_send_charset_iso_8859_5;
01876       packet_size = sizeof(packet_send_charset_iso_8859_5);
01877       break;
01878    case ISO_2022_JP:
01879       packet_send_charset = packet_send_charset_iso_2022_jp;
01880       packet_size = sizeof(packet_send_charset_iso_2022_jp);
01881       break;
01882    case ISO_8859_1:
01883    default:
01884       packet_send_charset = packet_send_charset_iso_8859_1;
01885       packet_size = sizeof(packet_send_charset_iso_8859_1);
01886    }
01887    memcpy(buffsend + SIZE_HEADER, packet_send_charset, packet_size);
01888    send_client(SIZE_HEADER + packet_size, buffsend, pte);
01889    return;
01890 }
01891 
01892 static void rcv_resume_connection_with_server(struct unistimsession *pte)
01893 {
01894    BUFFSEND;
01895    if (unistimdebug) {
01896       ast_verb(0, "ResumeConnectionWithServer received\n");
01897       ast_verb(0, "Sending packet_send_query_mac_address\n");
01898    }
01899    memcpy(buffsend + SIZE_HEADER, packet_send_query_mac_address,
01900          sizeof(packet_send_query_mac_address));
01901    send_client(SIZE_HEADER + sizeof(packet_send_query_mac_address), buffsend, pte);
01902    return;
01903 }
01904 
01905 static int unistim_register(struct unistimsession *s)
01906 {
01907    struct unistim_device *d;
01908 
01909    ast_mutex_lock(&devicelock);
01910    d = devices;
01911    while (d) {
01912       if (!strcasecmp(s->macaddr, d->id)) {
01913          /* XXX Deal with IP authentication */
01914          s->device = d;
01915          d->session = s;
01916          d->codec_number = DEFAULT_CODEC;
01917          d->missed_call = 0;
01918          d->receiver_state = STATE_ONHOOK;
01919          break;
01920       }
01921       d = d->next;
01922    }
01923    ast_mutex_unlock(&devicelock);
01924 
01925    if (!d) {
01926       return 0;
01927    }
01928 
01929    return 1;
01930 }
01931 
01932 static void unistim_line_copy(struct unistim_line *dst, struct unistim_line *src)
01933 {
01934    struct ast_format_cap *tmp = src->cap;
01935    memcpy(dst, src, sizeof(*dst)); /* this over writes the cap ptr, so we have to reset it */
01936    src->cap = tmp;
01937    ast_format_cap_append_from_cap(src->cap, dst->cap, AST_MEDIA_TYPE_UNKNOWN);
01938 }
01939 
01940 static struct unistim_line *unistim_line_destroy(struct unistim_line *l)
01941 {
01942    if (!l) {
01943       return NULL;
01944    }
01945    ao2_ref(l->cap, -1);
01946    ast_free(l);
01947    return NULL;
01948 }
01949 
01950 static struct unistim_line *unistim_line_alloc(void)
01951 {
01952    struct unistim_line *l;
01953    if (!(l = ast_calloc(1, sizeof(*l)))) {
01954       return NULL;
01955    }
01956 
01957    if (!(l->cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
01958       ast_free(l);
01959       return NULL;
01960    }
01961    return l;
01962 }
01963 
01964 static int unistim_free_sub(struct unistim_subchannel *sub) {
01965    if (unistimdebug) {
01966       ast_debug(1, "Released sub %u of channel %s@%s\n", sub->subtype, sub->parent->name, sub->parent->parent->name);
01967    }
01968    ast_mutex_destroy(&sub->lock);
01969    ast_free(sub);
01970    return 0;
01971 }
01972 
01973 static struct unistim_subchannel *unistim_alloc_sub(struct unistim_device *d, int x)
01974 {
01975    struct unistim_subchannel *sub;
01976    if (!(sub = ast_calloc(1, sizeof(*sub)))) {
01977       return NULL;
01978    }
01979 
01980    if (unistimdebug) {
01981       ast_verb(3, "Allocating UNISTIM subchannel #%d on %s ptr=%p\n", x, d->name, sub);
01982    }
01983    sub->ss_thread = AST_PTHREADT_NULL;
01984    sub->subtype = x;
01985    AST_LIST_LOCK(&d->subs);
01986    AST_LIST_INSERT_TAIL(&d->subs, sub, list);
01987    AST_LIST_UNLOCK(&d->subs);
01988    ast_mutex_init(&sub->lock);
01989    return sub;
01990 }
01991 
01992 static int unistim_unalloc_sub(struct unistim_device *d, struct unistim_subchannel *sub)
01993 {
01994    struct unistim_subchannel *s;
01995 
01996    AST_LIST_LOCK(&d->subs);
01997    AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, s, list) {
01998       if (!s) {
01999          continue;
02000       }
02001       if (s != sub) {
02002          continue;
02003       }
02004       AST_LIST_REMOVE_CURRENT(list);
02005       unistim_free_sub(sub);
02006    }
02007    AST_LIST_TRAVERSE_SAFE_END;
02008    AST_LIST_UNLOCK(&d->subs);
02009    return 0;
02010 }
02011 
02012 static const char *subtype_tostr(const int type)
02013 {
02014    switch (type) {
02015    case SUB_REAL:
02016       return "REAL";
02017    case SUB_ONHOLD:
02018       return "ONHOLD";
02019    case SUB_RING:
02020       return "RINGING";
02021    case SUB_THREEWAY:
02022       return "THREEWAY";
02023    }
02024    return "UNKNOWN";
02025 }
02026 
02027 static const char *ptestate_tostr(const int type)
02028 {
02029    switch (type) {
02030    case STATE_INIT:
02031       return "INIT";
02032    case STATE_AUTHDENY:
02033       return "AUTHDENY";
02034    case STATE_MAINPAGE:
02035       return "MAINPAGE";
02036    case STATE_EXTENSION:
02037       return "EXTENSION";
02038    case STATE_DIALPAGE:
02039       return "DIALPAGE";
02040    case STATE_RINGING:
02041       return "RINGING";
02042    case STATE_CALL:
02043       return "CALL";
02044    case STATE_SELECTOPTION:
02045       return "SELECTOPTION";
02046    case STATE_SELECTCODEC:
02047       return "SELECTCODEC";
02048    case STATE_SELECTLANGUAGE:
02049       return "SELECTLANGUAGE";
02050    case STATE_CLEANING:
02051       return "CLEARING";
02052    case STATE_HISTORY:
02053       return "HISTORY";
02054    }
02055    return "UNKNOWN";
02056 }
02057 
02058 static void rcv_mac_addr(struct unistimsession *pte, const unsigned char *buf)
02059 {
02060    BUFFSEND;
02061    int tmp, i = 0;
02062    char addrmac[19];
02063    int res = 0;
02064    for (tmp = 15; tmp < 15 + SIZE_HEADER; tmp++) {
02065       sprintf(&addrmac[i], "%02hhx", buf[tmp]);
02066       i += 2;
02067    }
02068    if (unistimdebug) {
02069       ast_verb(0, "MAC Address received: %s\n", addrmac);
02070    }
02071    strcpy(pte->macaddr, addrmac);
02072    res = unistim_register(pte);
02073    if (!res) {
02074       switch (autoprovisioning) {
02075       case AUTOPROVISIONING_NO:
02076          ast_log(LOG_WARNING, "No entry found for this phone : %s\n", addrmac);
02077          pte->state = STATE_AUTHDENY;
02078          break;
02079       case AUTOPROVISIONING_YES:
02080          {
02081             struct unistim_device *d = NULL, *newd = NULL;
02082             struct unistim_line *newl = NULL, *l = NULL;
02083             if (unistimdebug) {
02084                ast_verb(0, "New phone, autoprovisioning on\n");
02085             }
02086             /* First : locate the [template] section */
02087             ast_mutex_lock(&devicelock);
02088             d = devices;
02089             while (d) {
02090                if (strcasecmp(d->name, "template")) {
02091                   d = d->next;
02092                   continue;
02093                }
02094                /* Found, cloning this entry */
02095                if (!(newd = ast_malloc(sizeof(*newd)))) {
02096                   ast_mutex_unlock(&devicelock);
02097                   return;
02098                }
02099                memcpy(newd, d, sizeof(*newd));
02100                ast_mutex_init(&newd->lock);
02101                newd->lines.first = NULL;
02102                newd->lines.last = NULL;
02103                AST_LIST_LOCK(&d->lines);
02104                AST_LIST_TRAVERSE(&d->lines, l, list) {
02105                   if (!(newl = unistim_line_alloc())) {
02106                      break;
02107                   }
02108                   unistim_line_copy(l, newl);
02109                   newl->parent = newd;
02110                   ast_copy_string(newl->name, l->name, sizeof(newl->name));
02111                   snprintf(newl->fullname, sizeof(newl->fullname), "USTM/%s@%s",
02112                          newl->name, newd->name);
02113                   snprintf(l->name, sizeof(l->name), "%d", atoi(l->name) + 1);
02114 
02115                   AST_LIST_LOCK(&newd->lines);
02116                   AST_LIST_INSERT_TAIL(&newd->lines, newl, list);
02117                   AST_LIST_UNLOCK(&newd->lines);
02118                }
02119                AST_LIST_UNLOCK(&d->lines);
02120                if (!newl) {
02121                   ast_free(newd);
02122                   ast_mutex_unlock(&devicelock);
02123                }
02124 
02125                /* Ok, now updating some fields */
02126                ast_copy_string(newd->id, addrmac, sizeof(newd->id));
02127                ast_copy_string(newd->name, addrmac, sizeof(newd->name));
02128                if (newd->extension == EXTENSION_NONE) {
02129                   newd->extension = EXTENSION_ASK;
02130                }
02131 
02132                newd->receiver_state = STATE_ONHOOK;
02133                newd->session = pte;
02134                newd->language[0] = '\0';
02135                newd->to_delete = -1;
02136                newd->next = NULL;
02137                pte->device = newd;
02138 
02139                /* Go to the end of the linked chain */
02140                while (d->next) {
02141                   d = d->next;
02142                }
02143                d->next = newd;
02144                d = newd;
02145                break;
02146             }
02147             ast_mutex_unlock(&devicelock);
02148             if (!d) {
02149                ast_log(LOG_WARNING, "No entry [template] found in unistim.conf\n");
02150                pte->state = STATE_AUTHDENY;
02151             }
02152          }
02153          break;
02154       case AUTOPROVISIONING_TN:
02155          pte->state = STATE_AUTHDENY;
02156          break;
02157       default:
02158          ast_log(LOG_WARNING, "Internal error : unknown autoprovisioning value = %u\n",
02159                autoprovisioning);
02160       }
02161    }
02162    if (pte->state != STATE_AUTHDENY) {
02163       struct unistim_line *line;
02164       struct unistim_subchannel *sub;
02165 
02166       ast_verb(3, "Device '%s' successfuly registered\n", pte->device->name);
02167 
02168       AST_LIST_LOCK(&pte->device->subs);
02169       AST_LIST_TRAVERSE_SAFE_BEGIN(&pte->device->subs, sub, list) {
02170          if (sub) {
02171             ast_log(LOG_ERROR, "Subchannel lost sice reboot. Hanged channel may apear!\n");
02172             AST_LIST_REMOVE_CURRENT(list);
02173             ast_free(sub);
02174          }
02175       }
02176       AST_LIST_TRAVERSE_SAFE_END;
02177       AST_LIST_UNLOCK(&pte->device->subs);
02178 
02179       switch (pte->device->extension) {
02180       case EXTENSION_NONE:
02181          pte->state = STATE_MAINPAGE;
02182          break;
02183       case EXTENSION_ASK:
02184          /* Checking if we already have an extension number */
02185          if (ast_strlen_zero(pte->device->extension_number)) {
02186             pte->state = STATE_EXTENSION;
02187          } else {
02188             /* Yes, because of a phone reboot. We don't ask again for the TN */
02189             if (register_extension(pte)) {
02190                pte->state = STATE_EXTENSION;
02191             } else {
02192                pte->state = STATE_MAINPAGE;
02193             }
02194          }
02195          break;
02196       case EXTENSION_LINE:
02197          line = AST_LIST_FIRST(&pte->device->lines);
02198          ast_copy_string(pte->device->extension_number, line->name,
02199                      sizeof(pte->device->extension_number));
02200          if (register_extension(pte)) {
02201             pte->state = STATE_EXTENSION;
02202          } else {
02203             pte->state = STATE_MAINPAGE;
02204          }
02205          break;
02206       case EXTENSION_TN:
02207          /* If we are here, it's because of a phone reboot */
02208          pte->state = STATE_MAINPAGE;
02209          break;
02210       default:
02211          ast_log(LOG_WARNING, "Internal error, extension value unknown : %u\n",
02212                pte->device->extension);
02213          pte->state = STATE_AUTHDENY;
02214          break;
02215       }
02216    }
02217    if (pte->state == STATE_EXTENSION) {
02218       if (pte->device->extension != EXTENSION_TN) {
02219          pte->device->extension = EXTENSION_ASK;
02220       }
02221       pte->device->extension_number[0] = '\0';
02222    }
02223    if (unistimdebug) {
02224       ast_verb(0, "\nSending S1\n");
02225    }
02226    memcpy(buffsend + SIZE_HEADER, packet_send_S1, sizeof(packet_send_S1));
02227    send_client(SIZE_HEADER + sizeof(packet_send_S1), buffsend, pte);
02228 
02229    if (unistimdebug) {
02230       ast_verb(0, "Sending query_basic_manager_04\n");
02231    }
02232    memcpy(buffsend + SIZE_HEADER, packet_send_query_basic_manager_04,
02233          sizeof(packet_send_query_basic_manager_04));
02234    send_client(SIZE_HEADER + sizeof(packet_send_query_basic_manager_04), buffsend, pte);
02235 
02236    if (unistimdebug) {
02237       ast_verb(0, "Sending query_basic_manager_10\n");
02238    }
02239    memcpy(buffsend + SIZE_HEADER, packet_send_query_basic_manager_10,
02240          sizeof(packet_send_query_basic_manager_10));
02241    send_client(SIZE_HEADER + sizeof(packet_send_query_basic_manager_10), buffsend, pte);
02242 
02243    send_date_time(pte);
02244    return;
02245 }
02246 
02247 static int write_entry_history(struct unistimsession *pte, FILE * f, char c, char *line1)
02248 {
02249    if (fwrite(&c, 1, 1, f) != 1) {
02250       display_last_error("Unable to write history log header.");
02251       return -1;
02252    }
02253    if (fwrite(line1, TEXT_LENGTH_MAX, 1, f) != 1) {
02254       display_last_error("Unable to write history entry - date.");
02255       return -1;
02256    }
02257    if (fwrite(pte->device->lst_cid, TEXT_LENGTH_MAX, 1, f) != 1) {
02258       display_last_error("Unable to write history entry - callerid.");
02259       return -1;
02260    }
02261    if (fwrite(pte->device->lst_cnm, TEXT_LENGTH_MAX, 1, f) != 1) {
02262       display_last_error("Unable to write history entry - callername.");
02263       return -1;
02264    }
02265    return 0;
02266 }
02267 
02268 static int write_history(struct unistimsession *pte, char way, char ismissed)
02269 {
02270    char tmp[AST_CONFIG_MAX_PATH], tmp2[AST_CONFIG_MAX_PATH];
02271    char line1[TEXT_LENGTH_MAX + 1];
02272    char count = 0, *histbuf;
02273    int size;
02274    FILE *f, *f2;
02275    struct timeval now = ast_tvnow();
02276    struct ast_tm atm = { 0, };
02277 
02278    if (!pte->device) {
02279       return -1;
02280    }
02281    if (!pte->device->callhistory) {
02282       return 0;
02283    }
02284    if (strchr(pte->device->name, '/') || (pte->device->name[0] == '.')) {
02285       ast_log(LOG_WARNING, "Account code '%s' insecure for writing file\n",
02286             pte->device->name);
02287       return -1;
02288    }
02289 
02290    snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_LOG_DIR, USTM_LOG_DIR);
02291    if (ast_mkdir(tmp, 0770)) {
02292       ast_log(LOG_WARNING, "Unable to create directory for history\n");
02293                 return -1;
02294    }
02295 
02296    ast_localtime(&now, &atm, NULL);
02297    if (ismissed) {
02298       if (way == 'i') {
02299          ast_copy_string(tmp2, ustmtext("Miss", pte), sizeof(tmp2));
02300       } else {
02301          ast_copy_string(tmp2, ustmtext("Fail", pte), sizeof(tmp2));
02302       }
02303    } else {
02304       ast_copy_string(tmp2, ustmtext("Answ", pte), sizeof(tmp2));
02305    }
02306    snprintf(line1, sizeof(line1), "%04d/%02d/%02d %02d:%02d:%02d %s",
02307           atm.tm_year + 1900, atm.tm_mon + 1, atm.tm_mday, atm.tm_hour,
02308           atm.tm_min, atm.tm_sec, tmp2);
02309 
02310    snprintf(tmp, sizeof(tmp), "%s/%s/%s-%c.csv", ast_config_AST_LOG_DIR,
02311           USTM_LOG_DIR, pte->device->name, way);
02312    if ((f = fopen(tmp, "r"))) {
02313       struct stat bufstat;
02314 
02315       if (stat(tmp, &bufstat)) {
02316          display_last_error("Unable to stat history log.");
02317          fclose(f);
02318          return -1;
02319       }
02320       size = 1 + (MAX_ENTRY_LOG * TEXT_LENGTH_MAX * 3);
02321       if (bufstat.st_size != size) {
02322          ast_log(LOG_WARNING,
02323                "History file %s has an incorrect size (%d instead of %d). It will be replaced by a new one.",
02324                tmp, (int) bufstat.st_size, size);
02325          fclose(f);
02326          f = NULL;
02327          count = 1;
02328       }
02329    }
02330 
02331    /* If we can't open the log file, we create a brand new one */
02332    if (!f) {
02333       char c = 1;
02334       int i;
02335 
02336       if ((errno != ENOENT) && (count == 0)) {
02337          display_last_error("Unable to open history log.");
02338          return -1;
02339       }
02340       f = fopen(tmp, "w");
02341       if (!f) {
02342          display_last_error("Unable to create history log.");
02343          return -1;
02344       }
02345       if (write_entry_history(pte, f, c, line1)) {
02346          fclose(f);
02347          return -1;
02348       }
02349       memset(line1, ' ', TEXT_LENGTH_MAX);
02350       for (i = 3; i < MAX_ENTRY_LOG * 3; i++) {
02351          if (fwrite(line1, TEXT_LENGTH_MAX, 1, f) != 1) {
02352             display_last_error("Unable to write history entry - stuffing.");
02353             fclose(f);
02354             return -1;
02355          }
02356       }
02357       if (fclose(f)) {
02358          display_last_error("Unable to close history - creation.");
02359       }
02360       return 0;
02361    }
02362    /* We can open the log file, we create a temporary one, we add our entry and copy the rest */
02363    if (fread(&count, 1, 1, f) != 1) {
02364       display_last_error("Unable to read history header.");
02365       fclose(f);
02366       return -1;
02367    }
02368    if (count > MAX_ENTRY_LOG) {
02369       ast_log(LOG_WARNING, "Invalid count in history header of %s (%d max %d)\n", tmp,
02370             count, MAX_ENTRY_LOG);
02371       fclose(f);
02372       return -1;
02373    }
02374    snprintf(tmp2, sizeof(tmp2), "%s/%s/%s-%c.csv.tmp", ast_config_AST_LOG_DIR,
02375           USTM_LOG_DIR, pte->device->name, way);
02376    if (!(f2 = fopen(tmp2, "w"))) {
02377       display_last_error("Unable to create temporary history log.");
02378       fclose(f);
02379       return -1;
02380    }
02381 
02382    if (++count > MAX_ENTRY_LOG) {
02383       count = MAX_ENTRY_LOG;
02384    }
02385    if (write_entry_history(pte, f2, count, line1)) {
02386       fclose(f);
02387       fclose(f2);
02388       return -1;
02389    }
02390    size = (MAX_ENTRY_LOG - 1) * TEXT_LENGTH_MAX * 3;
02391    if (!(histbuf = ast_malloc(size))) {
02392       fclose(f);
02393       fclose(f2);
02394       return -1;
02395    }
02396 
02397    if (fread(histbuf, size, 1, f) != 1) {
02398       ast_free(histbuf);
02399       fclose(f);
02400       fclose(f2);
02401       display_last_error("Unable to read previous history entries.");
02402       return -1;
02403    }
02404    if (fwrite(histbuf, size, 1, f2) != 1) {
02405       ast_free(histbuf);
02406       fclose(f);
02407       fclose(f2);
02408       display_last_error("Unable to write previous history entries.");
02409       return -1;
02410    }
02411    ast_free(histbuf);
02412    if (fclose(f)) {
02413       display_last_error("Unable to close history log.");
02414    }
02415    if (fclose(f2)) {
02416       display_last_error("Unable to close temporary history log.");
02417    }
02418    if (unlink(tmp)) {
02419       display_last_error("Unable to remove old history log.");
02420    }
02421    if (rename(tmp2, tmp)) {
02422       display_last_error("Unable to rename new history log.");
02423    }
02424    return 0;
02425 }
02426 
02427 static int attempt_transfer(struct unistim_subchannel *p1, struct unistim_subchannel *p2)
02428 {
02429    RAII_VAR(struct ast_channel *, chana, NULL, ast_channel_unref);
02430    RAII_VAR(struct ast_channel *, chanb, NULL, ast_channel_unref);
02431 
02432    if (!p1->owner || !p2->owner) {
02433       ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n");
02434       return -1;
02435    }
02436    chana = ast_channel_ref(p1->owner);
02437    chanb = ast_channel_ref(p2->owner);
02438 
02439    switch (ast_bridge_transfer_attended(chana, chanb)) {
02440    case AST_BRIDGE_TRANSFER_INVALID:
02441       ast_log(LOG_WARNING, "Transfer failed. Invalid bridge setup\n");
02442       break;
02443    case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
02444       ast_log(LOG_WARNING, "Transfer not permitted\n");
02445       break;
02446    case AST_BRIDGE_TRANSFER_FAIL:
02447       ast_log(LOG_WARNING, "Transfer encountered internal error\n");
02448       break;
02449    case AST_BRIDGE_TRANSFER_SUCCESS:
02450       return 0;
02451    }
02452 
02453    /* Control only reaches this point if transfer has failed */
02454    ast_softhangup_nolock(chana, AST_SOFTHANGUP_DEV);
02455    ast_softhangup_nolock(chanb, AST_SOFTHANGUP_DEV);
02456    return -1;
02457 }
02458 
02459 void change_callerid(struct unistimsession *pte, int type, char *callerid)
02460 {
02461    char *data;
02462    int size;
02463 
02464    if (type) {
02465       data = pte->device->lst_cnm;
02466    } else {
02467       data = pte->device->lst_cid;
02468    }
02469 
02470    /* This is very nearly strncpy(), except that the remaining buffer
02471     * is padded with ' ', instead of '\0' */
02472    memset(data, ' ', TEXT_LENGTH_MAX);
02473    size = strlen(callerid);
02474    if (size > TEXT_LENGTH_MAX) {
02475       size = TEXT_LENGTH_MAX;
02476    }
02477    memcpy(data, callerid, size);
02478 }
02479 
02480 static struct unistim_subchannel* get_sub(struct unistim_device *device, int type)
02481 {
02482    struct unistim_subchannel *sub = NULL;
02483 
02484    AST_LIST_LOCK(&device->subs);
02485    AST_LIST_TRAVERSE(&device->subs, sub, list) {
02486       if (!sub) {
02487          continue;
02488       }
02489       if (sub->subtype == type) {
02490          break;
02491       }
02492    }
02493    AST_LIST_UNLOCK(&device->subs);
02494 
02495    return sub;
02496 }
02497 
02498 static void sub_start_silence(struct unistimsession *pte, struct unistim_subchannel *sub)
02499 {
02500    /* Silence our channel */
02501    if (!pte->device->silence_generator) {
02502       pte->device->silence_generator =
02503          ast_channel_start_silence_generator(sub->owner);
02504       if (pte->device->silence_generator == NULL) {
02505          ast_log(LOG_WARNING, "Unable to start a silence generator.\n");
02506       } else if (unistimdebug) {
02507          ast_verb(0, "Starting silence generator\n");
02508       }
02509    }
02510 
02511 }
02512 
02513 static void sub_stop_silence(struct unistimsession *pte, struct unistim_subchannel *sub)
02514 {
02515    /* Stop the silence generator */
02516    if (pte->device->silence_generator) {
02517       if (unistimdebug) {
02518          ast_verb(0, "Stopping silence generator\n");
02519       }
02520       if (sub->owner) {
02521          ast_channel_stop_silence_generator(sub->owner, pte->device->silence_generator);
02522       } else {
02523          ast_log(LOG_WARNING, "Trying to stop silence generator on a null channel!\n");
02524       }
02525       pte->device->silence_generator = NULL;
02526    }
02527 }
02528 
02529 static void sub_hold(struct unistimsession *pte, struct unistim_subchannel *sub)
02530 {
02531    if (!sub) {
02532       return;
02533    }
02534    sub->moh = 1;
02535    sub->subtype = SUB_ONHOLD;
02536    send_favorite_short(sub->softkey, FAV_ICON_ONHOLD_BLACK + FAV_BLINK_SLOW, pte);
02537    send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON);
02538    send_stop_timer(pte);
02539    if (sub->owner) {
02540       ast_queue_hold(sub->owner, NULL);
02541       send_end_call(pte);
02542    }
02543    return;
02544 }
02545 
02546 static void sub_unhold(struct unistimsession *pte, struct unistim_subchannel *sub)
02547 {
02548    struct unistim_subchannel *sub_real;
02549 
02550    sub_real = get_sub(pte->device, SUB_REAL);
02551    if (sub_real) {
02552        sub_hold(pte, sub_real);
02553    }
02554 
02555    sub->moh = 0;
02556    sub->subtype = SUB_REAL;
02557    send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, pte);
02558    send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
02559    send_start_timer(pte);
02560    if (sub->owner) {
02561       ast_queue_unhold(sub->owner);
02562       if (sub->rtp) {
02563          send_start_rtp(sub);
02564       }
02565    }
02566    return;
02567 }
02568 
02569 static void close_call(struct unistimsession *pte)
02570 {
02571    struct unistim_subchannel *sub, *sub_transf;
02572 
02573    sub = get_sub(pte->device, SUB_REAL);
02574    sub_transf = get_sub(pte->device, SUB_THREEWAY);
02575    send_stop_timer(pte);
02576    if (!sub) {
02577       ast_log(LOG_WARNING, "Close call without sub\n");
02578       return;
02579    }
02580    send_favorite_short(sub->softkey, FAV_LINE_ICON, pte);
02581    if (sub->owner) {
02582       sub->alreadygone = 1;
02583       if (sub_transf) {
02584          sub_transf->alreadygone = 1;
02585          if (attempt_transfer(sub, sub_transf) < 0) {
02586             ast_verb(0, "attempt_transfer failed.\n");
02587          }
02588       } else {
02589          ast_queue_hangup(sub->owner);
02590       }
02591    } else {
02592       if (sub_transf) {
02593          if (sub_transf->owner) {
02594             ast_queue_hangup_with_cause(sub_transf->owner, AST_CAUSE_NORMAL_CLEARING);
02595          } else {
02596             ast_log(LOG_WARNING, "threeway sub without owner\n");
02597          }
02598       } else {
02599          ast_verb(0, "USTM(%s@%s-%d) channel already destroyed\n", sub->parent->name,
02600                   pte->device->name, sub->softkey);
02601       }
02602    }
02603    change_callerid(pte, 0, pte->device->redial_number);
02604    change_callerid(pte, 1, "");
02605    write_history(pte, 'o', pte->device->missed_call);
02606    pte->device->missed_call = 0;
02607    show_main_page(pte);
02608    return;
02609 }
02610 
02611 static void ignore_call(struct unistimsession *pte)
02612 {
02613    send_no_ring(pte);
02614    return;
02615 }
02616 
02617 static void discard_call(struct unistimsession *pte)
02618 {
02619    struct unistim_subchannel* sub;
02620    sub = get_sub(pte->device, SUB_RING);
02621    if (!sub) {
02622        return;
02623    }
02624 
02625    ast_queue_hangup_with_cause(sub->owner, AST_CAUSE_NORMAL_CLEARING);
02626    return;
02627 }
02628 
02629 static void *unistim_ss(void *data)
02630 {
02631    struct ast_channel *chan = data;
02632    struct unistim_subchannel *sub = ast_channel_tech_pvt(chan);
02633    struct unistim_line *l = sub->parent;
02634    struct unistimsession *s = l->parent->session;
02635    int res;
02636 
02637    if (!s) {
02638       return NULL;
02639    }
02640    ast_verb(3, "Starting switch on '%s@%s-%d' to %s\n", l->name, l->parent->name, sub->softkey, s->device->phone_number);
02641    ast_channel_lock(chan);
02642    ast_channel_exten_set(chan, s->device->phone_number);
02643    ast_setstate(chan, AST_STATE_RING);
02644    ast_channel_unlock(chan);
02645    ast_copy_string(s->device->redial_number, s->device->phone_number,
02646                sizeof(s->device->redial_number));
02647    res = ast_pbx_run(chan);
02648    if (res) {
02649       ast_log(LOG_WARNING, "PBX exited non-zero\n");
02650       send_tone(s, 1000, 0);
02651    }
02652    return NULL;
02653 }
02654 
02655 static int find_rtp_port(struct unistim_subchannel *s)
02656 {
02657    struct unistim_subchannel *sub = NULL;
02658    int rtp_start = s->parent->parent->rtp_port;
02659    struct ast_sockaddr us_tmp;
02660    struct sockaddr_in us = { 0, };
02661 
02662    AST_LIST_LOCK(&s->parent->parent->subs);
02663    AST_LIST_TRAVERSE(&s->parent->parent->subs, sub, list) {
02664       if (!sub) {
02665          continue;
02666       }
02667       if (sub->rtp) {
02668          ast_rtp_instance_get_remote_address(sub->rtp, &us_tmp);
02669          ast_sockaddr_to_sin(&us_tmp, &us);
02670          if (htons(us.sin_port)) {
02671             rtp_start = htons(us.sin_port) + 1;
02672             break;
02673          }
02674       }
02675    }
02676    AST_LIST_UNLOCK(&s->parent->parent->subs);
02677    return rtp_start;
02678 }
02679 
02680 static void send_start_rtp(struct unistim_subchannel *sub)
02681 {
02682    BUFFSEND;
02683 
02684    int codec;
02685    struct sockaddr_in public = { 0, };
02686    struct sockaddr_in us = { 0, };
02687    struct sockaddr_in sin = { 0, };
02688    struct ast_sockaddr us_tmp;
02689    struct ast_sockaddr sin_tmp;
02690    struct unistimsession *pte;
02691 
02692    ast_rtp_instance_get_local_address(sub->rtp, &us_tmp);
02693    ast_sockaddr_to_sin(&us_tmp, &us);
02694    ast_rtp_instance_get_remote_address(sub->rtp, &sin_tmp);
02695    ast_sockaddr_to_sin(&sin_tmp, &sin);
02696 
02697    /* Setting up RTP of the phone */
02698    if (public_ip.sin_family == 0) {  /* NAT IP override ?   */
02699       memcpy(&public, &us, sizeof(public));   /* No defined, using IP from recvmsg  */
02700    } else {
02701       memcpy(&public, &public_ip, sizeof(public));    /* override  */
02702    }
02703    if (unistimdebug) {
02704       ast_verb(0, "RTP started : Our IP/port is : %s:%hd with codec %s\n",
02705           ast_inet_ntoa(us.sin_addr),
02706           htons(us.sin_port), ast_format_get_name(ast_channel_readformat(sub->owner)));
02707       ast_verb(0, "Starting phone RTP stack. Our public IP is %s\n",
02708                ast_inet_ntoa(public.sin_addr));
02709    }
02710 
02711    pte = sub->parent->parent->session;
02712    codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, ast_channel_readformat(sub->owner), 0);
02713    if ((ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) ||
02714       (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_alaw) == AST_FORMAT_CMP_EQUAL)) {
02715       if (unistimdebug) {
02716          ast_verb(0, "Sending packet_send_rtp_packet_size for codec %d\n", codec);
02717       }
02718       memcpy(buffsend + SIZE_HEADER, packet_send_rtp_packet_size,
02719             sizeof(packet_send_rtp_packet_size));
02720       buffsend[10] = (int) codec & 0xffffffffLL;
02721       send_client(SIZE_HEADER + sizeof(packet_send_rtp_packet_size), buffsend, pte);
02722    }
02723    if (unistimdebug) {
02724       ast_verb(0, "Sending Jitter Buffer Parameters Configuration\n");
02725    }
02726    memcpy(buffsend + SIZE_HEADER, packet_send_jitter_buffer_conf,
02727          sizeof(packet_send_jitter_buffer_conf));
02728    send_client(SIZE_HEADER + sizeof(packet_send_jitter_buffer_conf), buffsend, pte);
02729    if (pte->device->rtp_method != 0) {
02730       uint16_t rtcpsin_port = htons(us.sin_port) + 1; /* RTCP port is RTP + 1 */
02731 
02732       if (unistimdebug) {
02733          ast_verb(0, "Sending OpenAudioStreamTX using method #%d\n", pte->device->rtp_method);
02734       }
02735       if (pte->device->rtp_method == 3) {
02736          memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_tx3,
02737                sizeof(packet_send_open_audio_stream_tx3));
02738       } else {
02739          memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_tx,
02740                sizeof(packet_send_open_audio_stream_tx));
02741       }
02742       if (pte->device->rtp_method != 2) {
02743          memcpy(buffsend + 28, &public.sin_addr, sizeof(public.sin_addr));
02744          buffsend[20] = (htons(sin.sin_port) & 0xff00) >> 8;
02745          buffsend[21] = (htons(sin.sin_port) & 0x00ff);
02746          buffsend[23] = (rtcpsin_port & 0x00ff);
02747          buffsend[22] = (rtcpsin_port & 0xff00) >> 8;
02748          buffsend[25] = (us.sin_port & 0xff00) >> 8;
02749          buffsend[24] = (us.sin_port & 0x00ff);
02750          buffsend[27] = (rtcpsin_port & 0x00ff);
02751          buffsend[26] = (rtcpsin_port & 0xff00) >> 8;
02752       } else {
02753          memcpy(buffsend + 23, &public.sin_addr, sizeof(public.sin_addr));
02754          buffsend[15] = (htons(sin.sin_port) & 0xff00) >> 8;
02755          buffsend[16] = (htons(sin.sin_port) & 0x00ff);
02756          buffsend[20] = (us.sin_port & 0xff00) >> 8;
02757          buffsend[19] = (us.sin_port & 0x00ff);
02758       }
02759       buffsend[11] = codec; /* rx */
02760       buffsend[12] = codec; /* tx */
02761       send_client(SIZE_HEADER + sizeof(packet_send_open_audio_stream_tx), buffsend, pte);
02762 
02763       if (unistimdebug) {
02764          ast_verb(0, "Sending OpenAudioStreamRX\n");
02765       }
02766       if (pte->device->rtp_method == 3) {
02767          memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_rx3,
02768                sizeof(packet_send_open_audio_stream_rx3));
02769       } else {
02770          memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_rx,
02771                sizeof(packet_send_open_audio_stream_rx));
02772       }
02773       if (pte->device->rtp_method != 2) {
02774          memcpy(buffsend + 28, &public.sin_addr, sizeof(public.sin_addr));
02775          buffsend[20] = (htons(sin.sin_port) & 0xff00) >> 8;
02776          buffsend[21] = (htons(sin.sin_port) & 0x00ff);
02777          buffsend[23] = (rtcpsin_port & 0x00ff);
02778          buffsend[22] = (rtcpsin_port & 0xff00) >> 8;
02779          buffsend[25] = (us.sin_port & 0xff00) >> 8;
02780          buffsend[24] = (us.sin_port & 0x00ff);
02781          buffsend[27] = (rtcpsin_port & 0x00ff);
02782          buffsend[26] = (rtcpsin_port & 0xff00) >> 8;
02783       } else {
02784          memcpy(buffsend + 23, &public.sin_addr, sizeof(public.sin_addr));
02785          buffsend[15] = (htons(sin.sin_port) & 0xff00) >> 8;
02786          buffsend[16] = (htons(sin.sin_port) & 0x00ff);
02787          buffsend[20] = (us.sin_port & 0xff00) >> 8;
02788          buffsend[19] = (us.sin_port & 0x00ff);
02789       }
02790       buffsend[11] = codec; /* rx */
02791       buffsend[12] = codec; /* tx */
02792       send_client(SIZE_HEADER + sizeof(packet_send_open_audio_stream_rx), buffsend, pte);
02793    } else {
02794       uint16_t rtcpsin_port = htons(us.sin_port) + 1; /* RTCP port is RTP + 1 */
02795 
02796       if (unistimdebug) {
02797          ast_verb(0, "Sending packet_send_call default method\n");
02798       }
02799 
02800       memcpy(buffsend + SIZE_HEADER, packet_send_call, sizeof(packet_send_call));
02801       memcpy(buffsend + 53, &public.sin_addr, sizeof(public.sin_addr));
02802       /* Destination port when sending RTP */
02803       buffsend[49] = (us.sin_port & 0x00ff);
02804       buffsend[50] = (us.sin_port & 0xff00) >> 8;
02805       /* Destination port when sending RTCP */
02806       buffsend[52] = (rtcpsin_port & 0x00ff);
02807       buffsend[51] = (rtcpsin_port & 0xff00) >> 8;
02808       /* Codec */
02809       buffsend[40] = codec;
02810       buffsend[41] = codec;
02811       if (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
02812          buffsend[42] = 1;       /* 1 = 20ms (160 bytes), 2 = 40ms (320 bytes) */
02813       } else if (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_alaw) == AST_FORMAT_CMP_EQUAL) {
02814          buffsend[42] = 1;       /* 1 = 20ms (160 bytes), 2 = 40ms (320 bytes) */
02815       } else if (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_g723) == AST_FORMAT_CMP_EQUAL) {
02816          buffsend[42] = 2;       /* 1 = 30ms (24 bytes), 2 = 60 ms (48 bytes) */
02817       } else if (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_g729) == AST_FORMAT_CMP_EQUAL) {
02818          buffsend[42] = 2;       /* 1 = 10ms (10 bytes), 2 = 20ms (20 bytes) */
02819       } else {
02820          ast_log(LOG_WARNING, "Unsupported codec %s!\n",
02821             ast_format_get_name(ast_channel_readformat(sub->owner)));
02822       }
02823       /* Source port for transmit RTP and Destination port for receiving RTP */
02824       buffsend[45] = (htons(sin.sin_port) & 0xff00) >> 8;
02825       buffsend[46] = (htons(sin.sin_port) & 0x00ff);
02826       buffsend[47] = (rtcpsin_port & 0xff00) >> 8;
02827       buffsend[48] = (rtcpsin_port & 0x00ff);
02828       send_client(SIZE_HEADER + sizeof(packet_send_call), buffsend, pte);
02829    }
02830 }
02831 
02832 static void start_rtp(struct unistim_subchannel *sub)
02833 {
02834    struct sockaddr_in sin = { 0, };
02835    struct sockaddr_in sout = { 0, };
02836    struct ast_sockaddr sin_tmp;
02837    struct ast_sockaddr sout_tmp;
02838 
02839    /* Sanity checks */
02840    if (!sub) {
02841       ast_log(LOG_WARNING, "start_rtp with a null subchannel !\n");
02842       return;
02843    }
02844    if (!sub->parent) {
02845       ast_log(LOG_WARNING, "start_rtp with a null line!\n");
02846       return;
02847    }
02848    if (!sub->parent->parent) {
02849       ast_log(LOG_WARNING, "start_rtp with a null device!\n");
02850       return;
02851    }
02852    if (!sub->parent->parent->session) {
02853       ast_log(LOG_WARNING, "start_rtp with a null session!\n");
02854       return;
02855    }
02856    if (!sub->owner) {
02857       ast_log(LOG_WARNING, "start_rtp with a null asterisk channel!\n");
02858       return;
02859    }
02860    sout = sub->parent->parent->session->sout;
02861    ast_mutex_lock(&sub->lock);
02862    /* Allocate the RTP */
02863    if (unistimdebug) {
02864       ast_verb(0, "Starting RTP. Bind on %s\n", ast_inet_ntoa(sout.sin_addr));
02865    }
02866    ast_sockaddr_from_sin(&sout_tmp, &sout);
02867    sub->rtp = ast_rtp_instance_new("asterisk", sched, &sout_tmp, NULL);
02868    if (!sub->rtp) {
02869       ast_log(LOG_WARNING, "Unable to create RTP session: %s binaddr=%s\n",
02870             strerror(errno), ast_inet_ntoa(sout.sin_addr));
02871       ast_mutex_unlock(&sub->lock);
02872       return;
02873    }
02874    ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_RTCP, 1);
02875    ast_rtp_instance_set_channel_id(sub->rtp, ast_channel_uniqueid(sub->owner));
02876    ast_channel_internal_fd_set(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
02877    ast_channel_internal_fd_set(sub->owner, 1, ast_rtp_instance_fd(sub->rtp, 1));
02878    ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "UNISTIM RTP");
02879    ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, sub->parent->parent->nat);
02880 
02881    /* Create the RTP connection */
02882    sin.sin_family = AF_INET;
02883    /* Setting up RTP for our side */
02884    memcpy(&sin.sin_addr, &sub->parent->parent->session->sin.sin_addr,
02885          sizeof(sin.sin_addr));
02886 
02887    sin.sin_port = htons(find_rtp_port(sub));
02888    ast_sockaddr_from_sin(&sin_tmp, &sin);
02889    ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
02890    if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), ast_channel_readformat(sub->owner)) == AST_FORMAT_CMP_NOT_EQUAL) {
02891       struct ast_format *tmpfmt;
02892       struct ast_str *cap_buf = ast_str_alloca(64);
02893 
02894       tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(sub->owner), 0);
02895       ast_log(LOG_WARNING,
02896             "Our read/writeformat has been changed to something incompatible: %s, using %s best codec from %s\n",
02897             ast_format_get_name(ast_channel_readformat(sub->owner)),
02898             ast_format_get_name(tmpfmt),
02899             ast_format_cap_get_names(ast_channel_nativeformats(sub->owner), &cap_buf));
02900 
02901       ast_channel_set_readformat(sub->owner, tmpfmt);
02902       ast_channel_set_writeformat(sub->owner, tmpfmt);
02903         ao2_ref(tmpfmt, -1);
02904    }
02905    send_start_rtp(sub);
02906    ast_mutex_unlock(&sub->lock);
02907 }
02908 
02909 static void send_dial_tone(struct unistimsession *pte)
02910 {
02911    struct ast_tone_zone_sound *ts = NULL;
02912    struct ast_tone_zone_part tone_data;
02913    char *s = NULL;
02914    char *ind;
02915 
02916    if ((ts = ast_get_indication_tone(pte->device->tz, "dial"))) {
02917       ind = ast_strdupa(ts->data);
02918       s = strsep(&ind, ",");
02919       ast_tone_zone_part_parse(s, &tone_data);
02920       send_tone(pte, tone_data.freq1, tone_data.freq2);
02921       if (unistimdebug) {
02922          ast_verb(0, "Country code found (%s), freq1=%u freq2=%u\n",
02923                      pte->device->tz->country, tone_data.freq1, tone_data.freq2);
02924       }
02925       ts = ast_tone_zone_sound_unref(ts);
02926    }
02927 }
02928 
02929 static void show_phone_number(struct unistimsession *pte)
02930 {
02931    char tmp[TEXT_LENGTH_MAX + 1];
02932    const char *tmp_number = ustmtext("Number:", pte);
02933    int line, tmp_copy, offset = 0, i;
02934 
02935    pte->device->phone_number[pte->device->size_phone_number] = '\0';
02936    if  (pte->device->size_phone_number > MAX_SCREEN_NUMBER) {
02937       offset = pte->device->size_phone_number - MAX_SCREEN_NUMBER - 1;
02938       if (offset > strlen(tmp_number)) {
02939          offset = strlen(tmp_number);
02940       }
02941       tmp_copy = strlen(tmp_number) - offset + 1;
02942       if (tmp_copy > sizeof(tmp)) {
02943          tmp_copy = sizeof(tmp);
02944       }
02945       memcpy(tmp, tmp_number + offset, tmp_copy);
02946    } else {
02947       ast_copy_string(tmp, tmp_number, sizeof(tmp));
02948    }
02949 
02950    offset = (pte->device->size_phone_number >= TEXT_LENGTH_MAX) ? (pte->device->size_phone_number - TEXT_LENGTH_MAX +1) : 0;
02951    if (pte->device->size_phone_number) {
02952       memcpy(tmp + strlen(tmp), pte->device->phone_number + offset, pte->device->size_phone_number - offset + 1);
02953    }
02954    offset = strlen(tmp);
02955 
02956    for (i = strlen(tmp); i < TEXT_LENGTH_MAX; i++) {
02957       tmp[i] = '.';
02958    }
02959    tmp[i] = '\0';
02960 
02961    line = (pte->device->height == 1) ? TEXT_LINE0 : TEXT_LINE2;
02962    send_text(line, TEXT_NORMAL, pte, tmp);
02963    send_blink_cursor(pte);
02964    send_cursor_pos(pte, (unsigned char) (line + offset));
02965    send_led_update(pte, LED_BAR_OFF);
02966 }
02967 
02968 static void handle_dial_page(struct unistimsession *pte)
02969 {
02970    pte->state = STATE_DIALPAGE;
02971    if (pte->device->call_forward[0] == -1) {
02972       send_text(TEXT_LINE0, TEXT_NORMAL, pte, "");
02973       send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Enter forward", pte));
02974       send_text_status(pte, ustmtext("Fwd    Cancel BackSp Erase", pte));
02975       if (pte->device->call_forward[1] != 0) {
02976          ast_copy_string(pte->device->phone_number, pte->device->call_forward + 1,
02977                      sizeof(pte->device->phone_number));
02978          show_phone_number(pte);
02979          send_led_update(pte, LED_BAR_OFF);
02980          return;
02981       }
02982    } else {
02983       if ((pte->device->output == OUTPUT_HANDSET) &&
02984          (pte->device->receiver_state == STATE_ONHOOK)) {
02985          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
02986       } else {
02987          send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
02988       }
02989       send_dial_tone(pte);
02990 
02991       if (pte->device->height > 1) {
02992          send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Enter the number to dial", pte));
02993          send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("and press Call", pte));
02994       }
02995       if (ast_strlen_zero(pte->device->redial_number)) {
02996          send_text_status(pte, ustmtext("Call          BackSp Erase", pte));
02997       } else {
02998          send_text_status(pte, ustmtext("Call   Redial BackSp Erase", pte));
02999       }
03000    }
03001 
03002    pte->device->size_phone_number = 0;
03003    pte->device->phone_number[0] = 0;
03004    show_phone_number(pte);
03005    change_favorite_icon(pte, FAV_ICON_PHONE_BLACK);
03006    send_icon(TEXT_LINE0, FAV_ICON_NONE, pte);
03007    pte->device->missed_call = 0;
03008    send_led_update(pte, LED_BAR_OFF);
03009    pte->device->lastmsgssent = -1;
03010    return;
03011 }
03012 
03013 static void swap_subs(struct unistim_subchannel *a, struct unistim_subchannel *b)
03014 {
03015    struct ast_rtp_instance *rtp;
03016    int fds;
03017 
03018    if (unistimdebug) {
03019       ast_verb(0, "Swapping %p and %p\n", a, b);
03020    }
03021    if ((!a->owner) || (!b->owner)) {
03022       ast_log(LOG_WARNING,
03023             "Attempted to swap subchannels with a null owner : sub #%p=%p sub #%p=%p\n",
03024             a, a->owner, b, b->owner);
03025       return;
03026    }
03027    rtp = a->rtp;
03028    a->rtp = b->rtp;
03029    b->rtp = rtp;
03030 
03031    fds = ast_channel_fd(a->owner, 0);
03032    ast_channel_internal_fd_set(a->owner, 0, ast_channel_fd(b->owner, 0));
03033    ast_channel_internal_fd_set(b->owner, 0, fds);
03034 
03035    fds = ast_channel_fd(a->owner, 1);
03036    ast_channel_internal_fd_set(a->owner, 1, ast_channel_fd(b->owner, 1));
03037    ast_channel_internal_fd_set(b->owner, 1, fds);
03038 }
03039 
03040 /* Step 1 : Music On Hold for peer, Dialing screen for us */
03041 static void transfer_call_step1(struct unistimsession *pte)
03042 {
03043    struct unistim_subchannel *sub /*, *sub_trans */;
03044    struct unistim_device *d = pte->device;
03045 
03046    sub = get_sub(d, SUB_REAL);
03047    /* sub_trans = get_sub(d, SUB_THREEWAY); */
03048 
03049    if (!sub || !sub->owner) {
03050       ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
03051       return;
03052    }
03053    /* Start music on hold if appropriate */
03054    if (sub->moh) {
03055       ast_log(LOG_WARNING, "Transfer with peer already listening music on hold\n");
03056    } else {
03057       ast_queue_hold(sub->owner, sub->parent->musicclass);
03058       sub->moh = 1;
03059       sub->subtype = SUB_THREEWAY;
03060    }
03061    sub_start_silence(pte, sub);
03062    handle_dial_page(pte);
03063 }
03064 
03065 static void transfer_cancel_step2(struct unistimsession *pte)
03066 {
03067    struct unistim_subchannel *sub, *sub_trans;
03068    struct unistim_device *d = pte->device;
03069 
03070    sub = get_sub(d, SUB_REAL);
03071    sub_trans = get_sub(d, SUB_THREEWAY);
03072 
03073    if (!sub || !sub->owner) {
03074       ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
03075       return;
03076    }
03077    if (sub_trans) {
03078       if (unistimdebug) {
03079          ast_verb(0, "Transfer canceled, hangup our threeway channel\n");
03080       }
03081       if (sub->owner) {
03082          swap_subs(sub, sub_trans);
03083          ast_queue_unhold(sub_trans->owner);
03084          sub_trans->moh = 0;
03085          sub_trans->subtype = SUB_REAL;
03086          sub->subtype = SUB_THREEWAY;
03087          ast_queue_hangup_with_cause(sub->owner, AST_CAUSE_NORMAL_CLEARING);
03088       } else {
03089          ast_log(LOG_WARNING, "Canceling a threeway channel without owner\n");
03090       }
03091       return;
03092    }
03093 }
03094 
03095 /* From phone to PBX */
03096 static void handle_call_outgoing(struct unistimsession *s)
03097 {
03098    struct ast_channel *c;
03099    struct unistim_subchannel *sub;
03100    int softkey;
03101 
03102    s->state = STATE_CALL;
03103 
03104    sub = get_sub(s->device, SUB_THREEWAY);
03105    if (sub) {
03106       /* If sub for threway call created than we use transfer behaviuor */
03107       struct unistim_subchannel *sub_trans = NULL;
03108       struct unistim_device *d = s->device;
03109 
03110       sub_trans = get_sub(d, SUB_REAL);
03111       if (sub_trans) {
03112          ast_log(LOG_WARNING, "Can't transfer while active subchannel exists!\n");
03113          return;
03114       }
03115       if (!sub->owner) {
03116          ast_log(LOG_WARNING, "Unable to find subchannel with music on hold\n");
03117          return;
03118       }
03119 
03120       sub_trans = unistim_alloc_sub(d, SUB_REAL);
03121       if (!sub_trans) {
03122          ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
03123          return;
03124       }
03125       sub_trans->parent = sub->parent;
03126       sub_stop_silence(s, sub);
03127       send_tone(s, 0, 0);
03128       /* Make new channel */
03129       c = unistim_new(sub_trans, AST_STATE_DOWN, NULL, NULL);
03130       if (!c) {
03131          ast_log(LOG_WARNING, "Cannot allocate new structure on channel %p\n", sub->parent);
03132          return;
03133       }
03134       /* Swap things around between the three-way and real call */
03135       swap_subs(sub, sub_trans);
03136       send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
03137       if (s->device->height == 1) {
03138          send_text(TEXT_LINE0, TEXT_NORMAL, s, s->device->phone_number);
03139       } else {
03140          send_text(TEXT_LINE0, TEXT_NORMAL, s, ustmtext("Calling (pre-transfer)", s));
03141          send_text(TEXT_LINE1, TEXT_NORMAL, s, s->device->phone_number);
03142          send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Dialing...", s));
03143       }
03144       send_text_status(s, ustmtext("TransfrCancel", s));
03145 
03146       if (ast_pthread_create(&sub->ss_thread, NULL, unistim_ss, c)) {
03147          ast_log(LOG_WARNING, "Unable to start simple switch on channel %p\n", c);
03148          sub->ss_thread = AST_PTHREADT_NULL;
03149          ast_hangup(c);
03150          return;
03151       }
03152       if (unistimdebug) {
03153          ast_verb(0, "Started three way call on channel %p (%s) subchan %u\n",
03154              sub_trans->owner, ast_channel_name(sub_trans->owner), sub_trans->subtype);
03155       }
03156       return;
03157    }
03158 
03159    softkey = get_avail_softkey(s, NULL);
03160    if (softkey == -1) {
03161       ast_log(LOG_WARNING, "Have no avail softkey for calling\n");
03162       return;
03163    }
03164    sub = get_sub(s->device, SUB_REAL);
03165    if (sub) { /* have already call assigned */
03166       sub_hold(s, sub); /* Need to put on hold */
03167    }
03168    if (!(sub = unistim_alloc_sub(s->device, SUB_REAL))) {
03169       ast_log(LOG_WARNING, "Unable to allocate subchannel!\n");
03170       return;
03171    }
03172    sub->parent = s->device->sline[softkey];
03173    s->device->ssub[softkey] = sub;
03174    sub->softkey = softkey;
03175 
03176    if (unistimdebug) {
03177       ast_verb(0, "Using softkey %d, line %p\n", sub->softkey, sub->parent);
03178    }
03179    send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, s);
03180    s->device->selected = -1;
03181    if (!sub->owner) {            /* A call is already in progress ? */
03182       RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
03183       const char *pickupexten;
03184 
03185       c = unistim_new(sub, AST_STATE_DOWN, NULL, NULL);   /* No, starting a new one */
03186       if (!sub->rtp) { /* Need to start RTP before calling ast_pbx_run */
03187          start_rtp(sub);
03188       }
03189       if (c) {
03190          ast_channel_lock(c);
03191          pickup_cfg = ast_get_chan_features_pickup_config(c);
03192          if (!pickup_cfg) {
03193             ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
03194             pickupexten = "";
03195          } else {
03196             pickupexten = ast_strdupa(pickup_cfg->pickupexten);
03197          }
03198          ast_channel_unlock(c);
03199       }
03200       if (c && !strcmp(s->device->phone_number, pickupexten)) {
03201          if (unistimdebug) {
03202             ast_verb(0, "Try to pickup in unistim_new\n");
03203          }
03204          send_text(TEXT_LINE0, TEXT_NORMAL, s, "");
03205          send_text_status(s, ustmtext("       Transf        Hangup", s));
03206          send_start_timer(s);
03207          if (ast_pickup_call(c)) {
03208             ast_log(LOG_NOTICE, "Nothing to pick up\n");
03209             ast_channel_hangupcause_set(c, AST_CAUSE_CALL_REJECTED);
03210          } else {
03211             ast_channel_hangupcause_set(c, AST_CAUSE_NORMAL_CLEARING);
03212          }
03213          ast_hangup(c);
03214          c = NULL;
03215                 } else if (c) {
03216          send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
03217          send_tone(s, 0, 0); /* Dialing empty number should also stop dial tone */
03218          if (s->device->height == 1) {
03219             if (strlen(s->device->phone_number) > 0) {
03220                send_text(TEXT_LINE0, TEXT_NORMAL, s, s->device->phone_number);
03221             } else {
03222                send_text(TEXT_LINE0, TEXT_NORMAL, s, ustmtext("Calling...", s));
03223             }
03224          } else {
03225             send_text(TEXT_LINE0, TEXT_NORMAL, s, ustmtext("Calling :", s));
03226             send_text(TEXT_LINE1, TEXT_NORMAL, s, s->device->phone_number);
03227             send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Dialing...", s));
03228          }
03229          send_text_status(s, ustmtext("                     Hangup", s));
03230 
03231          /* start switch */
03232          if (ast_pthread_create(&sub->ss_thread, NULL, unistim_ss, c)) {
03233             ast_log(LOG_WARNING, "Unable to create switch thread\n");
03234             sub->ss_thread = AST_PTHREADT_NULL;
03235             ast_queue_hangup_with_cause(c, AST_CAUSE_SWITCH_CONGESTION);
03236          }
03237       } else
03238          ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n",
03239                sub->parent->name, s->device->name);
03240    } else {
03241       ast_debug(1, "Current sub [%s] already has owner\n", ast_channel_name(sub->owner));
03242    }
03243    return;
03244 }
03245 
03246 /* From PBX to phone */
03247 static void handle_call_incoming(struct unistimsession *s)
03248 {
03249    struct unistim_subchannel *sub = NULL;
03250    int i;
03251 
03252    s->state = STATE_CALL;
03253    s->device->missed_call = 0;
03254    send_no_ring(s);
03255    sub = get_sub(s->device, SUB_RING); /* Put other SUB_REAL call on hold */
03256    if (!sub) {
03257       ast_log(LOG_WARNING, "No ringing lines on: %s\n", s->device->name);
03258       return;
03259    }
03260    /* Change icons for all ringing keys */
03261    for (i = 0; i < FAVNUM; i++) {
03262       if (!s->device->ssub[i]) { /* No sub assigned - skip */
03263          continue;
03264       }
03265       if (s->device->ssub[i]->subtype == SUB_REAL) {
03266          sub_hold(s, s->device->ssub[i]);
03267       }
03268       if (s->device->ssub[i] != sub) {
03269          continue;
03270       }
03271       if (sub->softkey == i) { /* If softkey assigned at this moment - do not erase */
03272          continue;
03273       }
03274       if (sub->softkey < 0) { /* If softkey not defined - first one used */
03275          sub->softkey = i;
03276          continue;
03277       }
03278       send_favorite_short(i, FAV_LINE_ICON, s);
03279       s->device->ssub[i] = NULL;
03280    }
03281    if (sub->softkey < 0) {
03282       ast_log(LOG_WARNING, "Can not assign softkey for incoming call on: %s\n", s->device->name);
03283       return;
03284    }
03285    send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, s);
03286    sub->parent = s->device->sline[sub->softkey];
03287    sub->subtype = SUB_REAL;
03288    if (unistimdebug) {
03289       ast_verb(0, "Handle Call Incoming for %s@%s\n", sub->parent->name,
03290                s->device->name);
03291    }
03292    start_rtp(sub);
03293    if (!sub->rtp) {
03294       ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name, s->device->name);
03295       return;
03296    }
03297    if (sub->owner) {
03298       ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
03299    }
03300    send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("is on-line", s));
03301    send_text_status(s, ustmtext("       Transf        Hangup", s));
03302    send_start_timer(s);
03303 
03304    if ((s->device->output == OUTPUT_HANDSET) &&
03305       (s->device->receiver_state == STATE_ONHOOK)) {
03306       send_select_output(s, OUTPUT_SPEAKER, s->device->volume, MUTE_OFF);
03307    } else {
03308       send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
03309    }
03310    write_history(s, 'i', 0);
03311    return;
03312 }
03313 
03314 static int unistim_do_senddigit(struct unistimsession *pte, char digit)
03315 {
03316    struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass.integer = digit, .src = "unistim" };
03317    struct unistim_subchannel *sub;
03318         int row, col;
03319 
03320    sub = get_sub(pte->device, SUB_REAL);
03321    if (!sub || !sub->owner || sub->alreadygone) {
03322       ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit\n");
03323       return -1;
03324    }
03325 
03326    /* Send DTMF indication _before_ playing sounds */
03327    ast_queue_frame(sub->owner, &f);
03328    if (unistimdebug) {
03329       ast_verb(0, "Send Digit %c (%i ms)\n", digit, pte->device->dtmfduration);
03330    }
03331    if (pte->device->dtmfduration > 0) {
03332       row = (digit - '1') % 3;
03333       col = (digit - '1' - row) / 3;
03334       if (digit >= '1' && digit <='9') {
03335          send_tone(pte, dtmf_row[row], dtmf_col[col]);
03336       } else if (digit >= 'A' && digit <= 'D') {
03337          send_tone(pte, dtmf_row[digit-'A'], dtmf_col[3]);
03338       } else if (digit == '*') {
03339          send_tone(pte, dtmf_row[3], dtmf_col[0]);
03340       } else if (digit == '0') {
03341          send_tone(pte, dtmf_row[3], dtmf_col[1]);
03342       } else if (digit == '#') {
03343          send_tone(pte, dtmf_row[3], dtmf_col[2]);
03344       } else {
03345          send_tone(pte, 500, 2000);
03346       }
03347       usleep(pte->device->dtmfduration * 1000);  /* XXX Less than perfect, blocking an important thread is not a good idea */
03348       send_tone(pte, 0, 0);
03349    }
03350    return 0;
03351 }
03352 
03353 static void handle_key_fav(struct unistimsession *pte, char keycode)
03354 {
03355    int keynum = keycode - KEY_FAV0;
03356    struct unistim_subchannel *sub;
03357 
03358    sub = get_sub(pte->device, SUB_REAL);
03359 
03360    /* Make an action on selected favorite key */
03361    if (!pte->device->ssub[keynum]) { /* Key have no assigned call */
03362       send_favorite_selected(FAV_LINE_ICON, pte);
03363       if (is_key_line(pte->device, keynum)) {
03364          if (unistimdebug) {
03365             ast_verb(0, "Handle line w/o sub - dialpage\n");
03366          }
03367          pte->device->selected = keynum;
03368          sub_hold(pte, sub); /* Put active call on hold */
03369          send_stop_timer(pte);
03370          handle_dial_page(pte);
03371       } else if (is_key_favorite(pte->device, keynum)) {
03372          /* Put active call on hold in handle_call_outgoing function, after preparation and
03373           checking if lines available for calling */
03374          if (unistimdebug) {
03375             ast_verb(0, "Handle favorite w/o sub - dialing\n");
03376          }
03377          if ((pte->device->output == OUTPUT_HANDSET) &&
03378             (pte->device->receiver_state == STATE_ONHOOK)) {
03379             send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
03380          } else {
03381             send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
03382          }
03383          key_favorite(pte, keycode);
03384       }
03385    } else {
03386       sub = pte->device->ssub[keynum];
03387       /* Favicon have assigned sub, activate it and put current on hold */
03388       if (sub->subtype == SUB_REAL) {
03389          sub_hold(pte, sub);
03390          show_main_page(pte);
03391       } else if (sub->subtype == SUB_RING) {
03392          sub->softkey = keynum;
03393          handle_call_incoming(pte);
03394       } else if (sub->subtype == SUB_ONHOLD) {
03395          if (pte->state == STATE_DIALPAGE){
03396             send_tone(pte, 0, 0);
03397          }
03398          send_callerid_screen(pte, sub);
03399          sub_unhold(pte, sub);
03400          pte->state = STATE_CALL;
03401       }
03402    }
03403 }
03404 
03405 static void key_call(struct unistimsession *pte, char keycode)
03406 {
03407    struct unistim_subchannel *sub = get_sub(pte->device, SUB_REAL);
03408    struct unistim_subchannel *sub_3way = get_sub(pte->device, SUB_THREEWAY);
03409 
03410    if (!sub) {
03411       return;
03412    }
03413    if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
03414       if (keycode == KEY_SHARP) {
03415          keycode = '#';
03416       } else if (keycode == KEY_STAR) {
03417          keycode = '*';
03418       } else {
03419          keycode -= 0x10;
03420       }
03421       unistim_do_senddigit(pte, keycode);
03422       return;
03423    }
03424    switch (keycode) {
03425    case KEY_FUNC1:
03426       if (sub->owner && ast_channel_state(sub->owner) == AST_STATE_UP) {
03427          if (sub_3way) {
03428             close_call(pte);
03429          }
03430       }
03431       break;
03432    case KEY_FUNC2:
03433       if (sub_3way) {
03434          transfer_cancel_step2(pte);
03435       } else if (ast_channel_state(sub->owner) == AST_STATE_UP) {
03436          transfer_call_step1(pte);
03437       }
03438       break;
03439    case KEY_HANGUP:
03440    case KEY_FUNC4:
03441       if (!sub_3way) {
03442          close_call(pte);
03443       }
03444       break;
03445    case KEY_FAV0:
03446    case KEY_FAV1:
03447    case KEY_FAV2:
03448    case KEY_FAV3:
03449    case KEY_FAV4:
03450    case KEY_FAV5:
03451       handle_key_fav(pte, keycode);
03452       break;
03453    case KEY_HEADPHN:
03454       if (pte->device->output == OUTPUT_HEADPHONE) {
03455          send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
03456       } else {
03457          send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
03458       }
03459       break;
03460    case KEY_LOUDSPK:
03461       if (pte->device->output != OUTPUT_SPEAKER)
03462          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
03463       else
03464          send_select_output(pte, pte->device->previous_output, pte->device->volume,
03465                       MUTE_OFF);
03466       break;
03467    case KEY_ONHOLD:
03468       if (!sub) {
03469          if(pte->device->ssub[pte->device->selected]) {
03470             sub_hold(pte, pte->device->ssub[pte->device->selected]);
03471          }
03472       } else {
03473          sub_hold(pte, sub);
03474       }
03475       break;
03476    }
03477    return;
03478 }
03479 
03480 static void key_ringing(struct unistimsession *pte, char keycode)
03481 {
03482    switch (keycode) {
03483    case KEY_FAV0:
03484    case KEY_FAV1:
03485    case KEY_FAV2:
03486    case KEY_FAV3:
03487    case KEY_FAV4:
03488    case KEY_FAV5:
03489       handle_key_fav(pte, keycode);
03490       break;
03491    case KEY_FUNC3:
03492       ignore_call(pte);
03493       break;
03494    case KEY_HANGUP:
03495    case KEY_FUNC4:
03496       discard_call(pte);
03497       break;
03498    case KEY_LOUDSPK:
03499       pte->device->output = OUTPUT_SPEAKER;
03500       handle_call_incoming(pte);
03501       break;
03502    case KEY_HEADPHN:
03503       pte->device->output = OUTPUT_HEADPHONE;
03504       handle_call_incoming(pte);
03505       break;
03506    case KEY_FUNC1:
03507       handle_call_incoming(pte);
03508       break;
03509    }
03510    return;
03511 }
03512 
03513 static void key_favorite(struct unistimsession *pte, char keycode)
03514 {
03515    int fav = keycode - KEY_FAV0;
03516    if (!is_key_favorite(pte->device, fav)) {
03517       ast_log(LOG_WARNING, "It's not a favorite key\n");
03518       return;
03519    }
03520    ast_copy_string(pte->device->phone_number, pte->device->softkeynumber[fav],
03521                sizeof(pte->device->phone_number));
03522    handle_call_outgoing(pte);
03523    return;
03524 }
03525 
03526 static void key_dial_page(struct unistimsession *pte, char keycode)
03527 {
03528    struct unistim_subchannel *sub = get_sub(pte->device, SUB_THREEWAY);
03529 
03530    pte->device->nextdial = 0;
03531    if (keycode == KEY_FUNC3) {
03532       if (pte->device->size_phone_number <= 1) {
03533          keycode = KEY_FUNC4;
03534       } else {
03535          pte->device->size_phone_number -= 2;
03536          keycode = pte->device->phone_number[pte->device->size_phone_number] + 0x10;
03537       }
03538    }
03539    if (keycode == KEY_SHARP && pte->device->sharp_dial == 1) {
03540       keycode = KEY_FUNC1;
03541    }
03542    if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
03543       int i = pte->device->size_phone_number;
03544 
03545       if (pte->device->size_phone_number == 0) {
03546          send_tone(pte, 0, 0);
03547       }
03548       if (keycode == KEY_SHARP) {
03549          keycode = '#';
03550       } else if (keycode == KEY_STAR) {
03551          keycode = '*';
03552       } else {
03553          keycode -= 0x10;
03554       }
03555       pte->device->phone_number[i] = keycode;
03556       pte->device->size_phone_number++;
03557       pte->device->phone_number[i + 1] = 0;
03558       show_phone_number(pte);
03559 
03560       if (ast_exists_extension(NULL, pte->device->context, pte->device->phone_number, 1, NULL) &&
03561          !ast_matchmore_extension(NULL, pte->device->context, pte->device->phone_number, 1, NULL)) {
03562          keycode = KEY_FUNC1;
03563       } else {
03564          if (pte->device->interdigit_timer) {
03565             pte->device->nextdial = get_tick_count() + pte->device->interdigit_timer;
03566          }
03567       }
03568    }
03569    if (keycode == KEY_FUNC4) {
03570       pte->device->size_phone_number = 0;
03571       show_phone_number(pte);
03572       return;
03573    }
03574 
03575    if (pte->device->call_forward[0] == -1) {
03576       if (keycode == KEY_FUNC1) {
03577          ast_copy_string(pte->device->call_forward, pte->device->phone_number,
03578                      sizeof(pte->device->call_forward));
03579          show_main_page(pte);
03580       } else if ((keycode == KEY_FUNC2) || (keycode == KEY_HANGUP)) {
03581          pte->device->call_forward[0] = '\0';
03582          send_led_update(pte, LED_SPEAKER_OFF);
03583          send_led_update(pte, LED_HEADPHONE_OFF);
03584          show_main_page(pte);
03585       }
03586       return;
03587    }
03588    switch (keycode) {
03589    case KEY_FUNC2:
03590       if (ast_strlen_zero(pte->device->redial_number)) {
03591          break;
03592       }
03593       ast_copy_string(pte->device->phone_number, pte->device->redial_number,
03594                   sizeof(pte->device->phone_number));
03595    case KEY_FUNC1:
03596       handle_call_outgoing(pte);
03597       break;
03598    case KEY_HANGUP:
03599       if (sub && sub->owner) {
03600          sub_stop_silence(pte, sub);
03601          send_tone(pte, 0, 0);
03602          ast_queue_unhold(sub->owner);
03603          sub->moh = 0;
03604          sub->subtype = SUB_REAL;
03605          pte->state = STATE_CALL;
03606 
03607          send_text_status(pte, ustmtext("       Transf        Hangup", pte));
03608          send_callerid_screen(pte, sub);
03609       } else {
03610          send_led_update(pte, LED_SPEAKER_OFF);
03611          send_led_update(pte, LED_HEADPHONE_OFF);
03612          show_main_page(pte);
03613       }
03614       break;
03615    case KEY_FAV0:
03616    case KEY_FAV1:
03617    case KEY_FAV2:
03618    case KEY_FAV3:
03619    case KEY_FAV4:
03620    case KEY_FAV5:
03621       send_favorite_selected(FAV_LINE_ICON, pte);
03622       pte->device->selected = -1;
03623       handle_key_fav(pte, keycode);
03624       break;
03625    case KEY_LOUDSPK:
03626       if (pte->device->output == OUTPUT_SPEAKER) {
03627          if (pte->device->receiver_state == STATE_OFFHOOK) {
03628             send_select_output(pte, pte->device->previous_output, pte->device->volume,
03629                          MUTE_OFF);
03630          } else {
03631             show_main_page(pte);
03632          }
03633       } else {
03634          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
03635       }
03636       break;
03637    case KEY_HEADPHN:
03638       if (pte->device->output == OUTPUT_HEADPHONE) {
03639          if (pte->device->receiver_state == STATE_OFFHOOK) {
03640             send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
03641          } else {
03642             show_main_page(pte);
03643          }
03644       } else {
03645          send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
03646       }
03647       break;
03648    }
03649    return;
03650 }
03651 
03652 static void handle_select_option(struct unistimsession *pte)
03653 {
03654    char tmp[128];
03655 
03656    if (pte->state != STATE_SELECTOPTION) {
03657       pte->state = STATE_SELECTOPTION;
03658       pte->size_buff_entry = 1;
03659       pte->buff_entry[0] = 0; /* Position in menu */
03660    }
03661    snprintf(tmp, sizeof(tmp), "%d. %s", pte->buff_entry[0] + 1, ustmtext(options_menu[(int)pte->buff_entry[0]].label, pte));
03662    send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmp);
03663    send_text_status(pte, ustmtext("Select               Cancel", pte));
03664    return;
03665 }
03666 
03667 static void key_select_option(struct unistimsession *pte, char keycode)
03668 {
03669    switch (keycode) {
03670    case KEY_DOWN:
03671       pte->buff_entry[0]++;
03672       if (options_menu[(int)pte->buff_entry[0]].label == NULL) {
03673          pte->buff_entry[0]--;
03674       }
03675       break;
03676    case KEY_UP:
03677       if (pte->buff_entry[0] > 0) {
03678          pte->buff_entry[0]--;
03679       }
03680       break;
03681    case KEY_FUNC1:
03682       options_menu[(int)pte->buff_entry[0]].handle_option(pte);
03683       return;
03684    case KEY_HANGUP:
03685    case KEY_FUNC4:
03686       show_main_page(pte);
03687       return;
03688    }
03689 
03690    handle_select_option(pte);
03691    return;
03692 }
03693 
03694 #define SELECTCODEC_START_ENTRY_POS 15
03695 #define SELECTCODEC_MAX_LENGTH 2
03696 #define SELECTCODEC_MSG "Codec number : .."
03697 static void handle_select_codec(struct unistimsession *pte)
03698 {
03699    char buf[30], buf2[5];
03700 
03701    pte->state = STATE_SELECTCODEC;
03702    ast_copy_string(buf, ustmtext("Using codec", pte), sizeof(buf));
03703    snprintf(buf2, sizeof(buf2), " %d", pte->device->codec_number);
03704    strcat(buf, buf2);
03705    strcat(buf, " (G711u=0,");
03706 
03707    send_text(TEXT_LINE0, TEXT_NORMAL, pte, buf);
03708    send_text(TEXT_LINE1, TEXT_NORMAL, pte, "G723=4,G711a=8,G729A=18)");
03709    send_text(TEXT_LINE2, TEXT_INVERSE, pte, SELECTCODEC_MSG);
03710    send_blink_cursor(pte);
03711    send_cursor_pos(pte, TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS);
03712    pte->size_buff_entry = 0;
03713    send_text_status(pte, ustmtext("Select BackSp Erase  Cancel", pte));
03714    return;
03715 }
03716 
03717 static void key_select_codec(struct unistimsession *pte, char keycode)
03718 {
03719    if (keycode == KEY_FUNC2) {
03720       if (pte->size_buff_entry <= 1) {
03721          keycode = KEY_FUNC3;
03722       } else {
03723          pte->size_buff_entry -= 2;
03724          keycode = pte->buff_entry[pte->size_buff_entry] + 0x10;
03725       }
03726    }
03727    if ((keycode >= KEY_0) && (keycode <= KEY_9)) {
03728       char tmpbuf[] = SELECTCODEC_MSG;
03729       int i = 0;
03730 
03731       if (pte->size_buff_entry >= SELECTCODEC_MAX_LENGTH) {
03732          return;
03733       }
03734       while (i < pte->size_buff_entry) {
03735          tmpbuf[i + SELECTCODEC_START_ENTRY_POS] = pte->buff_entry[i];
03736          i++;
03737       }
03738       tmpbuf[i + SELECTCODEC_START_ENTRY_POS] = keycode - 0x10;
03739       pte->buff_entry[i] = keycode - 0x10;
03740       pte->size_buff_entry++;
03741       send_text(TEXT_LINE2, TEXT_INVERSE, pte, tmpbuf);
03742       send_blink_cursor(pte);
03743       send_cursor_pos(pte,
03744                  (unsigned char) (TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS + 1 + i));
03745       return;
03746    }
03747 
03748    switch (keycode) {
03749    case KEY_FUNC1:
03750       if (pte->size_buff_entry == 1) {
03751          pte->device->codec_number = pte->buff_entry[0] - 48;
03752       } else if (pte->size_buff_entry == 2) {
03753          pte->device->codec_number =
03754             ((pte->buff_entry[0] - 48) * 10) + (pte->buff_entry[1] - 48);
03755       }
03756       show_main_page(pte);
03757       break;
03758    case KEY_FUNC3:
03759       pte->size_buff_entry = 0;
03760       send_text(TEXT_LINE2, TEXT_INVERSE, pte, SELECTCODEC_MSG);
03761       send_blink_cursor(pte);
03762       send_cursor_pos(pte, TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS);
03763       break;
03764    case KEY_HANGUP:
03765    case KEY_FUNC4:
03766       show_main_page(pte);
03767       break;
03768    }
03769    return;
03770 }
03771 
03772 static int find_language(const char* lang)
03773 {
03774    int i = 0;
03775    while (options_languages[i].lang_short != NULL) {
03776       if(!strcmp(options_languages[i].lang_short, lang)) {
03777          return i;
03778       }
03779       i++;
03780    }
03781    return 0;
03782 }
03783 
03784 static void handle_select_language(struct unistimsession *pte)
03785 {
03786    char tmp_language[40];
03787    struct unistim_languages lang;
03788 
03789    if (pte->state != STATE_SELECTLANGUAGE) {
03790       pte->state = STATE_SELECTLANGUAGE;
03791       pte->size_buff_entry = 1;
03792       pte->buff_entry[0] = find_language(pte->device->language);
03793    }
03794    lang = options_languages[(int)pte->buff_entry[0]];
03795    ast_copy_string(tmp_language, pte->device->language, sizeof(tmp_language));
03796    ast_copy_string(pte->device->language, lang.lang_short, sizeof(pte->device->language));
03797    send_charset_update(pte, lang.encoding);
03798    send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext(lang.label, pte));
03799 
03800    ast_copy_string(pte->device->language, tmp_language, sizeof(pte->device->language));
03801    lang = options_languages[find_language(pte->device->language)];
03802    send_charset_update(pte, lang.encoding);
03803    send_text_status(pte, ustmtext("Select               Cancel", pte));
03804    return;
03805 }
03806 
03807 static void key_select_language(struct unistimsession *pte, char keycode)
03808 {
03809    switch (keycode) {
03810    case KEY_DOWN:
03811       pte->buff_entry[0]++;
03812       if (options_languages[(int)pte->buff_entry[0]].label == NULL) {
03813          pte->buff_entry[0]--;
03814       }
03815       break;
03816    case KEY_UP:
03817       if (pte->buff_entry[0] > 0) {
03818          pte->buff_entry[0]--;
03819       }
03820       break;
03821    case KEY_FUNC1:
03822       ast_copy_string(pte->device->language, options_languages[(int)pte->buff_entry[0]].lang_short, sizeof(pte->device->language));
03823       send_charset_update(pte, options_languages[(int)pte->buff_entry[0]].encoding);
03824       refresh_all_favorite(pte);
03825       show_main_page(pte);
03826       return;
03827    case KEY_HANGUP:
03828    case KEY_FUNC4:
03829       handle_select_option(pte);
03830       return;
03831    }
03832 
03833    handle_select_language(pte);
03834    return;
03835 }
03836 
03837 
03838 #define SELECTEXTENSION_START_ENTRY_POS 0
03839 #define SELECTEXTENSION_MAX_LENGTH 10
03840 #define SELECTEXTENSION_MSG ".........."
03841 static void show_extension_page(struct unistimsession *pte)
03842 {
03843    pte->state = STATE_EXTENSION;
03844 
03845    send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Please enter a Terminal", pte));
03846    send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Number (TN) :", pte));
03847    send_text(TEXT_LINE2, TEXT_NORMAL, pte, SELECTEXTENSION_MSG);
03848    send_blink_cursor(pte);
03849    send_cursor_pos(pte, TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS);
03850    send_text_status(pte, ustmtext("Enter  BackSpcErase", pte));
03851    pte->size_buff_entry = 0;
03852    return;
03853 }
03854 
03855 static void key_select_extension(struct unistimsession *pte, char keycode)
03856 {
03857    if (keycode == KEY_FUNC2) {
03858       if (pte->size_buff_entry <= 1) {
03859          keycode = KEY_FUNC3;
03860       } else {
03861          pte->size_buff_entry -= 2;
03862          keycode = pte->buff_entry[pte->size_buff_entry] + 0x10;
03863       }
03864    }
03865    if ((keycode >= KEY_0) && (keycode <= KEY_9)) {
03866       char tmpbuf[] = SELECTEXTENSION_MSG;
03867       int i = 0;
03868 
03869       if (pte->size_buff_entry >= SELECTEXTENSION_MAX_LENGTH) {
03870          return;
03871       }
03872       while (i < pte->size_buff_entry) {
03873          tmpbuf[i + SELECTEXTENSION_START_ENTRY_POS] = pte->buff_entry[i];
03874          i++;
03875       }
03876       tmpbuf[i + SELECTEXTENSION_START_ENTRY_POS] = keycode - 0x10;
03877       pte->buff_entry[i] = keycode - 0x10;
03878       pte->size_buff_entry++;
03879       send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
03880       send_blink_cursor(pte);
03881       send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS + 1 + i));
03882       return;
03883    }
03884 
03885    switch (keycode) {
03886    case KEY_FUNC1:
03887       if (pte->size_buff_entry < 1) {
03888          return;
03889       }
03890       if (autoprovisioning == AUTOPROVISIONING_TN) {
03891          struct unistim_device *d;
03892 
03893          /* First step : looking for this TN in our device list */
03894          ast_mutex_lock(&devicelock);
03895          d = devices;
03896          pte->buff_entry[pte->size_buff_entry] = '\0';
03897          while (d) {
03898             if (d->id[0] == 'T') {  /* It's a TN device ? */
03899                /* It's the TN we're looking for ? */
03900                if (!strcmp((d->id) + 1, pte->buff_entry)) {
03901                   pte->device = d;
03902                   d->session = pte;
03903                   d->codec_number = DEFAULT_CODEC;
03904                   d->missed_call = 0;
03905                   d->receiver_state = STATE_ONHOOK;
03906                   strcpy(d->id, pte->macaddr);
03907                   pte->device->extension_number[0] = 'T';
03908                   pte->device->extension = EXTENSION_TN;
03909                   ast_copy_string((pte->device->extension_number) + 1,
03910                               pte->buff_entry, pte->size_buff_entry + 1);
03911                   ast_mutex_unlock(&devicelock);
03912                   show_main_page(pte);
03913                   refresh_all_favorite(pte);
03914                   return;
03915                }
03916             }
03917             d = d->next;
03918          }
03919          ast_mutex_unlock(&devicelock);
03920          send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Invalid Terminal Number.", pte));
03921          send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Please try again :", pte));
03922          send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS +
03923                                  pte->size_buff_entry));
03924          send_blink_cursor(pte);
03925       } else {
03926          ast_copy_string(pte->device->extension_number, pte->buff_entry,
03927                      pte->size_buff_entry + 1);
03928          if (register_extension(pte)) {
03929             send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Invalid extension.", pte));
03930             send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Please try again :", pte));
03931             send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 +
03932                                  SELECTEXTENSION_START_ENTRY_POS +
03933                                  pte->size_buff_entry));
03934             send_blink_cursor(pte);
03935          } else
03936             show_main_page(pte);
03937       }
03938       break;
03939    case KEY_FUNC3:
03940       pte->size_buff_entry = 0;
03941       send_text(TEXT_LINE2, TEXT_NORMAL, pte, SELECTEXTENSION_MSG);
03942       send_blink_cursor(pte);
03943       send_cursor_pos(pte, TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS);
03944       break;
03945    }
03946    return;
03947 }
03948 
03949 static void show_entry_history(struct unistimsession *pte, FILE ** f)
03950 {
03951    char line[TEXT_LENGTH_MAX + 1], status[STATUS_LENGTH_MAX + 1], func1[10], func2[10],
03952       func3[10];
03953 
03954    /* Display date/time and call status */
03955    if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
03956       display_last_error("Can't read history date entry");
03957       fclose(*f);
03958       return;
03959    }
03960    line[sizeof(line) - 1] = '\0';
03961    if (pte->device->height == 1) {
03962       if (pte->buff_entry[3] == 1) {
03963          send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03964       }
03965    } else {
03966       send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03967    }
03968    /* Display number */
03969    if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
03970       display_last_error("Can't read callerid entry");
03971       fclose(*f);
03972       return;
03973    }
03974    line[sizeof(line) - 1] = '\0';
03975    ast_copy_string(pte->device->lst_cid, line, sizeof(pte->device->lst_cid));
03976    ast_trim_blanks(pte->device->lst_cid);
03977    if (pte->device->height == 1) {
03978       if (pte->buff_entry[3] == 2) {
03979          send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03980       }
03981    } else {
03982       send_text(TEXT_LINE1, TEXT_NORMAL, pte, line);
03983    }
03984    /* Display name */
03985    if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
03986       display_last_error("Can't read callername entry");
03987       fclose(*f);
03988       return;
03989    }
03990    line[sizeof(line) - 1] = '\0';
03991    if (pte->device->height == 1) {
03992       if (pte->buff_entry[3] == 3) {
03993          send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03994       }
03995         } else {
03996                 send_text(TEXT_LINE2, TEXT_NORMAL, pte, line);
03997         }
03998    fclose(*f);
03999 
04000    snprintf(line, sizeof(line), "%s %03d/%03d", ustmtext("Call", pte), pte->buff_entry[2],
04001           pte->buff_entry[1]);
04002    send_texttitle(pte, line);
04003 
04004    if (pte->buff_entry[2] == 1) {
04005       ast_copy_string(func1, "       ", sizeof(func1));
04006    } else {
04007       ast_copy_string(func1, ustmtext("Prev   ", pte), sizeof(func1));
04008    }
04009    if (pte->buff_entry[2] >= pte->buff_entry[1]) {
04010       ast_copy_string(func2, "       ", sizeof(func2));
04011    } else {
04012       ast_copy_string(func2, ustmtext("Next   ", pte), sizeof(func2));
04013    }
04014    if (strlen(pte->device->lst_cid)) {
04015       ast_copy_string(func3, ustmtext("Redial ", pte), sizeof(func3));
04016    } else {
04017       ast_copy_string(func3, "       ", sizeof(func3));
04018    }
04019    snprintf(status, sizeof(status), "%s%s%s%s", func1, func2, func3, ustmtext("Cancel", pte));
04020    send_text_status(pte, status);
04021 }
04022 
04023 static char open_history(struct unistimsession *pte, char way, FILE ** f)
04024 {
04025    char tmp[AST_CONFIG_MAX_PATH];
04026    char count;
04027 
04028    snprintf(tmp, sizeof(tmp), "%s/%s/%s-%c.csv", ast_config_AST_LOG_DIR,
04029           USTM_LOG_DIR, pte->device->name, way);
04030    *f = fopen(tmp, "r");
04031    if (!*f) {
04032       display_last_error("Unable to open history file");
04033       return 0;
04034    }
04035    if (fread(&count, 1, 1, *f) != 1) {
04036       display_last_error("Unable to read history header - display.");
04037       fclose(*f);
04038       *f = NULL;
04039       return 0;
04040    }
04041    if (count > MAX_ENTRY_LOG) {
04042       ast_log(LOG_WARNING, "Invalid count in history header of %s (%d max %d)\n", tmp,
04043             count, MAX_ENTRY_LOG);
04044       fclose(*f);
04045       *f = NULL;
04046       return 0;
04047    }
04048    return count;
04049 }
04050 
04051 static void show_history(struct unistimsession *pte, char way)
04052 {
04053    FILE *f;
04054    char count;
04055 
04056    if (!pte->device) {
04057       return;
04058    }
04059    if (!pte->device->callhistory) {
04060       return;
04061    }
04062    count = open_history(pte, way, &f);
04063    if (!count) {
04064       return;
04065    }
04066    pte->buff_entry[0] = way;
04067    pte->buff_entry[1] = count;
04068    pte->buff_entry[2] = 1;
04069    pte->buff_entry[3] = 1;
04070    show_entry_history(pte, &f);
04071    pte->state = STATE_HISTORY;
04072 }
04073 
04074 static void show_main_page(struct unistimsession *pte)
04075 {
04076    char tmpbuf[TEXT_LENGTH_MAX + 1];
04077    const char *text;
04078 
04079    if ((pte->device->extension == EXTENSION_ASK) &&
04080       (ast_strlen_zero(pte->device->extension_number))) {
04081       show_extension_page(pte);
04082       return;
04083    }
04084 
04085    pte->state = STATE_MAINPAGE;
04086    send_led_update(pte, LED_BAR_OFF);
04087    pte->device->lastmsgssent = -1;
04088 
04089    send_tone(pte, 0, 0);
04090    send_stop_timer(pte); /* case of holding call */
04091    send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON_DISCRET);
04092    send_led_update(pte, LED_SPEAKER_OFF);
04093    send_led_update(pte, LED_HEADPHONE_OFF);
04094 
04095    if (!ast_strlen_zero(pte->device->call_forward)) {
04096       if (pte->device->height == 1) {
04097          char tmp_field[100];
04098          snprintf(tmp_field, sizeof(tmp_field), "%s %s", ustmtext("Fwd to:", pte), pte->device->call_forward);
04099          send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmp_field);
04100       } else {
04101          send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Call forwarded to :", pte));
04102          send_text(TEXT_LINE1, TEXT_NORMAL, pte, pte->device->call_forward);
04103       }
04104       send_icon(TEXT_LINE0, FAV_ICON_REFLECT + FAV_BLINK_SLOW, pte);
04105       if (ast_strlen_zero(pte->device->redial_number)) {
04106          send_text_status(pte, ustmtext("Dial          NoFwd  ", pte));
04107       } else {
04108          send_text_status(pte, ustmtext("Dial   Redial NoFwd  ", pte));
04109       }
04110    } else {
04111       if ((pte->device->extension == EXTENSION_ASK) || (pte->device->extension == EXTENSION_TN)) {
04112          if (ast_strlen_zero(pte->device->redial_number)) {
04113             send_text_status(pte, ustmtext("Dial          Fwd    Unregis", pte));
04114          } else {
04115             send_text_status(pte, ustmtext("Dial   Redial Fwd    Unregis", pte));
04116          }
04117       } else {
04118          if (ast_strlen_zero(pte->device->redial_number)) {
04119             send_text_status(pte, ustmtext("Dial          Fwd    Pickup", pte));
04120          } else {
04121             send_text_status(pte, ustmtext("Dial   Redial Fwd    Pickup", pte));
04122          }
04123       }
04124       send_text(TEXT_LINE1, TEXT_NORMAL, pte, pte->device->maintext1);
04125       if (pte->device->missed_call == 0) {
04126          send_date_time2(pte);
04127          send_idle_clock(pte);
04128          if (strlen(pte->device->maintext0)) {
04129             send_text(TEXT_LINE0, TEXT_NORMAL, pte, pte->device->maintext0);
04130          }
04131       } else {
04132          if (pte->device->missed_call == 1) {
04133             text = ustmtext("unanswered call", pte);
04134          } else {
04135             text = ustmtext("unanswered calls", pte);
04136          }
04137          snprintf(tmpbuf, sizeof(tmpbuf), "%d %s", pte->device->missed_call, text);
04138          send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmpbuf);
04139          send_icon(TEXT_LINE0, FAV_ICON_CALL_CENTER + FAV_BLINK_SLOW, pte);
04140       }
04141    }
04142    if (pte->device->height > 1) {
04143       if (ast_strlen_zero(pte->device->maintext2)) {
04144          strcpy(tmpbuf, "IP : ");
04145          strcat(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr));
04146          send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
04147       } else {
04148          send_text(TEXT_LINE2, TEXT_NORMAL, pte, pte->device->maintext2);
04149       }
04150    }
04151 
04152    send_texttitle(pte, pte->device->titledefault);
04153    change_favorite_icon(pte, FAV_LINE_ICON);
04154 }
04155 
04156 static void key_main_page(struct unistimsession *pte, char keycode)
04157 {
04158    if (pte->device->missed_call) {
04159       send_icon(TEXT_LINE0, FAV_ICON_NONE, pte);
04160       pte->device->missed_call = 0;
04161    }
04162    if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
04163       handle_dial_page(pte);
04164       key_dial_page(pte, keycode);
04165       return;
04166    }
04167    switch (keycode) {
04168    case KEY_FUNC1:
04169       pte->device->selected = get_avail_softkey(pte, NULL);
04170       handle_dial_page(pte);
04171       break;
04172    case KEY_FUNC2:
04173       if (ast_strlen_zero(pte->device->redial_number)) {
04174          break;
04175       }
04176       if ((pte->device->output == OUTPUT_HANDSET) &&
04177          (pte->device->receiver_state == STATE_ONHOOK)) {
04178          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
04179       } else {
04180          send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
04181       }
04182       ast_copy_string(pte->device->phone_number, pte->device->redial_number,
04183                   sizeof(pte->device->phone_number));
04184       handle_call_outgoing(pte);
04185       break;
04186    case KEY_FUNC3:
04187       if (!ast_strlen_zero(pte->device->call_forward)) {
04188          /* Cancel call forwarding */
04189          memmove(pte->device->call_forward + 1, pte->device->call_forward,
04190                sizeof(pte->device->call_forward) - 1);
04191          pte->device->call_forward[0] = '\0';
04192          send_icon(TEXT_LINE0, FAV_ICON_NONE, pte);
04193          pte->device->output = OUTPUT_HANDSET;   /* Seems to be reseted somewhere */
04194          show_main_page(pte);
04195          break;
04196       }
04197       pte->device->call_forward[0] = -1;
04198       handle_dial_page(pte);
04199       break;
04200    case KEY_FUNC4:
04201       if (pte->device->extension == EXTENSION_ASK) {
04202          unregister_extension(pte);
04203          pte->device->extension_number[0] = '\0';
04204          show_extension_page(pte);
04205       } else if (pte->device->extension == EXTENSION_TN) {
04206          ast_mutex_lock(&devicelock);
04207          strcpy(pte->device->id, pte->device->extension_number);
04208          pte->buff_entry[0] = '\0';
04209          pte->size_buff_entry = 0;
04210          pte->device->session = NULL;
04211          pte->device = NULL;
04212          ast_mutex_unlock(&devicelock);
04213          show_extension_page(pte);
04214       } else { /* Pickup function */
04215          /* XXX Is there a way to get a specific channel here? */
04216          RAII_VAR(struct ast_features_pickup_config *, pickup_cfg,
04217                ast_get_chan_features_pickup_config(NULL), ao2_cleanup);
04218 
04219          if (!pickup_cfg) {
04220             ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
04221             break;
04222          }
04223 
04224          pte->device->selected = -1;
04225          ast_copy_string(pte->device->phone_number, pickup_cfg->pickupexten,
04226                   sizeof(pte->device->phone_number));
04227          handle_call_outgoing(pte);
04228                 }
04229       break;
04230    case KEY_FAV0:
04231    case KEY_FAV1:
04232    case KEY_FAV2:
04233    case KEY_FAV3:
04234    case KEY_FAV4:
04235    case KEY_FAV5:
04236       handle_key_fav(pte, keycode);
04237       break;
04238    case KEY_CONF:
04239       handle_select_option(pte);
04240       break;
04241    case KEY_LOUDSPK:
04242       send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
04243       handle_dial_page(pte);
04244       break;
04245    case KEY_HEADPHN:
04246       send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
04247       handle_dial_page(pte);
04248       break;
04249    case KEY_SNDHIST:
04250       show_history(pte, 'o');
04251       break;
04252    case KEY_RCVHIST:
04253       show_history(pte, 'i');
04254       break;
04255    }
04256    return;
04257 }
04258 
04259 static void key_history(struct unistimsession *pte, char keycode)
04260 {
04261    FILE *f;
04262    char count;
04263    long offset;
04264    int flag = 0;
04265 
04266    switch (keycode) {
04267    case KEY_LEFT:
04268       if (pte->device->height == 1) {
04269          if (pte->buff_entry[3] <= 1) {
04270             return;
04271          }
04272          pte->buff_entry[3]--;
04273          flag = 1;
04274          break;
04275       }
04276    case KEY_UP:
04277    case KEY_FUNC1:
04278       if (pte->buff_entry[2] <= 1) {
04279          return;
04280       }
04281       pte->buff_entry[2]--;
04282       flag = 1;
04283       break;
04284    case KEY_RIGHT:
04285       if (pte->device->height == 1) {
04286          if (pte->buff_entry[3] == 3) {
04287             return;
04288          }
04289          pte->buff_entry[3]++;
04290          flag = 1;
04291          break;
04292       }
04293    case KEY_DOWN:
04294    case KEY_FUNC2:
04295       if (pte->buff_entry[2] >= pte->buff_entry[1]) {
04296          return;
04297       }
04298       pte->buff_entry[2]++;
04299       flag = 1;
04300       break;
04301    case KEY_FUNC3:
04302       if (ast_strlen_zero(pte->device->lst_cid)) {
04303          break;
04304       }
04305       ast_copy_string(pte->device->redial_number, pte->device->lst_cid,
04306                   sizeof(pte->device->redial_number));
04307       key_main_page(pte, KEY_FUNC2);
04308       break;
04309    case KEY_FUNC4:
04310    case KEY_HANGUP:
04311       show_main_page(pte);
04312       break;
04313    case KEY_SNDHIST:
04314       if (pte->buff_entry[0] == 'i') {
04315          show_history(pte, 'o');
04316       } else {
04317          show_main_page(pte);
04318       }
04319       break;
04320    case KEY_RCVHIST:
04321       if (pte->buff_entry[0] == 'i') {
04322          show_main_page(pte);
04323       } else {
04324          show_history(pte, 'i');
04325       }
04326       break;
04327    }
04328 
04329    if (flag) {
04330       count = open_history(pte, pte->buff_entry[0], &f);
04331       if (!count) {
04332          return;
04333       }
04334       offset = ((pte->buff_entry[2] - 1) * TEXT_LENGTH_MAX * 3);
04335       if (fseek(f, offset, SEEK_CUR)) {
04336          display_last_error("Unable to seek history entry.");
04337          fclose(f);
04338          return;
04339       }
04340       show_entry_history(pte, &f);
04341    }
04342 
04343    return;
04344 }
04345 
04346 static void init_phone_step2(struct unistimsession *pte)
04347 {
04348    BUFFSEND;
04349    if (unistimdebug) {
04350       ast_verb(0, "Sending S4\n");
04351    }
04352    memcpy(buffsend + SIZE_HEADER, packet_send_s4, sizeof(packet_send_s4));
04353    send_client(SIZE_HEADER + sizeof(packet_send_s4), buffsend, pte);
04354    send_date_time2(pte);
04355    send_date_time3(pte);
04356    if (unistimdebug) {
04357       ast_verb(0, "Sending S7\n");
04358    }
04359    memcpy(buffsend + SIZE_HEADER, packet_send_S7, sizeof(packet_send_S7));
04360    send_client(SIZE_HEADER + sizeof(packet_send_S7), buffsend, pte);
04361    if (unistimdebug) {
04362       ast_verb(0, "Sending Contrast\n");
04363    }
04364    memcpy(buffsend + SIZE_HEADER, packet_send_Contrast, sizeof(packet_send_Contrast));
04365    if (pte->device != NULL) {
04366       buffsend[9] = pte->device->contrast;
04367    }
04368    send_client(SIZE_HEADER + sizeof(packet_send_Contrast), buffsend, pte);
04369 
04370    if (unistimdebug) {
04371       ast_verb(0, "Sending S9\n");
04372    }
04373    memcpy(buffsend + SIZE_HEADER, packet_send_s9, sizeof(packet_send_s9));
04374    send_client(SIZE_HEADER + sizeof(packet_send_s9), buffsend, pte);
04375    send_no_ring(pte);
04376 
04377    if (unistimdebug) {
04378       ast_verb(0, "Sending S7\n");
04379    }
04380    memcpy(buffsend + SIZE_HEADER, packet_send_S7, sizeof(packet_send_S7));
04381    send_client(SIZE_HEADER + sizeof(packet_send_S7), buffsend, pte);
04382    send_led_update(pte, LED_BAR_OFF);
04383    send_ping(pte);
04384    if (unistimdebug) {
04385       ast_verb(0, "Sending init language\n");
04386    }
04387    if (pte->device) {
04388       send_charset_update(pte, options_languages[find_language(pte->device->language)].encoding);
04389    }
04390    if (pte->state < STATE_MAINPAGE) {
04391       if (autoprovisioning == AUTOPROVISIONING_TN) {
04392          show_extension_page(pte);
04393          return;
04394       } else {
04395          int i;
04396          char tmp[30];
04397 
04398          for (i = 1; i < FAVNUM; i++) {
04399             send_favorite(i, 0, pte, "");
04400          }
04401          send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Phone is not registered", pte));
04402          send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("in unistim.conf", pte));
04403          strcpy(tmp, "MAC = ");
04404          strcat(tmp, pte->macaddr);
04405          send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
04406          send_text_status(pte, "");
04407          send_texttitle(pte, "UNISTIM for*");
04408          return;
04409       }
04410    }
04411    show_main_page(pte);
04412    refresh_all_favorite(pte);
04413    if (unistimdebug) {
04414       ast_verb(0, "Sending arrow\n");
04415    }
04416    memcpy(buffsend + SIZE_HEADER, packet_send_arrow, sizeof(packet_send_arrow));
04417    send_client(SIZE_HEADER + sizeof(packet_send_arrow), buffsend, pte);
04418    return;
04419 }
04420 
04421 /* Toggles the state of microphone muting */
04422 static void microphone_mute_toggle(struct unistimsession *pte)
04423 {
04424    if (pte->device->microphone == MUTE_OFF) {
04425       pte->device->microphone = MUTE_ON;
04426       send_led_update(pte, LED_MUTE_ON);
04427    } else if (pte->device->microphone == MUTE_ON) {
04428       pte->device->microphone = MUTE_OFF;
04429       send_led_update(pte, LED_MUTE_OFF);
04430    }
04431    send_mute(pte, (pte->device->microphone & 0x01));
04432 }
04433 
04434 static void process_request(int size, unsigned char *buf, struct unistimsession *pte)
04435 {
04436    char tmpbuf[255];
04437    if (memcmp
04438       (buf + SIZE_HEADER, packet_recv_resume_connection_with_server,
04439        sizeof(packet_recv_resume_connection_with_server)) == 0) {
04440       rcv_resume_connection_with_server(pte);
04441       return;
04442    }
04443    if (memcmp(buf + SIZE_HEADER, packet_recv_firm_version, sizeof(packet_recv_firm_version)) == 0) {
04444       buf[size] = 0;
04445       if (unistimdebug) {
04446          ast_verb(0, "Got the firmware version : '%s'\n", buf + 13);
04447       }
04448       ast_copy_string(pte->firmware, (char *) (buf + 13), sizeof(pte->firmware));
04449       init_phone_step2(pte);
04450       return;
04451    }
04452    if (memcmp(buf + SIZE_HEADER, packet_recv_it_type, sizeof(packet_recv_it_type)) == 0) {
04453       char type = buf[13];
04454       if (unistimdebug) {
04455          ast_verb(0, "Got the equipment type: '%d'\n", type);
04456       }
04457       switch (type) {
04458       case 0x03: /* i2002 */
04459          if (pte->device) {
04460             pte->device->height = 1;
04461          }
04462          break;
04463       }
04464       return;
04465    }
04466    if (memcmp(buf + SIZE_HEADER, packet_recv_mac_addr, sizeof(packet_recv_mac_addr)) == 0) {
04467       rcv_mac_addr(pte, buf);
04468       return;
04469    }
04470    if (memcmp(buf + SIZE_HEADER, packet_recv_r2, sizeof(packet_recv_r2)) == 0) {
04471       if (unistimdebug) {
04472          ast_verb(0, "R2 received\n");
04473       }
04474       return;
04475    }
04476 
04477    if (pte->state < STATE_MAINPAGE) {
04478       if (unistimdebug) {
04479          ast_verb(0, "Request not authorized in this state\n");
04480       }
04481       return;
04482    }
04483    if (!memcmp(buf + SIZE_HEADER, packet_recv_expansion_pressed_key, sizeof(packet_recv_expansion_pressed_key))) {
04484       char keycode = buf[13];
04485       
04486       if (unistimdebug) {
04487          ast_verb(0, "Expansion key pressed: keycode = 0x%02hhx - current state: %s\n", (unsigned char)keycode,
04488                   ptestate_tostr(pte->state));
04489       }
04490    }
04491    if (!memcmp(buf + SIZE_HEADER, packet_recv_pressed_key, sizeof(packet_recv_pressed_key))) {
04492       char keycode = buf[13];
04493 
04494       if (unistimdebug) {
04495          ast_verb(0, "Key pressed: keycode = 0x%02hhx - current state: %s\n", (unsigned char)keycode,
04496                   ptestate_tostr(pte->state));
04497       }
04498       if (keycode == KEY_MUTE) {
04499          microphone_mute_toggle(pte);
04500       }
04501       switch (pte->state) {
04502       case STATE_INIT:
04503          if (unistimdebug) {
04504             ast_verb(0, "No keys allowed in the init state\n");
04505          }
04506          break;
04507       case STATE_AUTHDENY:
04508          if (unistimdebug) {
04509             ast_verb(0, "No keys allowed in authdeny state\n");
04510          }
04511          break;
04512       case STATE_MAINPAGE:
04513          key_main_page(pte, keycode);
04514          break;
04515       case STATE_DIALPAGE:
04516          key_dial_page(pte, keycode);
04517          break;
04518       case STATE_RINGING:
04519          key_ringing(pte, keycode);
04520          break;
04521       case STATE_CALL:
04522          key_call(pte, keycode);
04523          break;
04524       case STATE_EXTENSION:
04525          key_select_extension(pte, keycode);
04526          break;
04527       case STATE_SELECTOPTION:
04528          key_select_option(pte, keycode);
04529          break;
04530       case STATE_SELECTCODEC:
04531          key_select_codec(pte, keycode);
04532          break;
04533       case STATE_SELECTLANGUAGE:
04534          key_select_language(pte, keycode);
04535          break;
04536       case STATE_HISTORY:
04537          key_history(pte, keycode);
04538          break;
04539       default:
04540          ast_log(LOG_WARNING, "Key : Unknown state\n");
04541       }
04542       return;
04543    }
04544    if (memcmp(buf + SIZE_HEADER, packet_recv_pick_up, sizeof(packet_recv_pick_up)) == 0) {
04545       if (unistimdebug) {
04546          ast_verb(0, "Handset off hook, current state: %s\n", ptestate_tostr(pte->state));
04547       }
04548       if (!pte->device) {         /* We are not yet registered (asking for a TN in AUTOPROVISIONING_TN) */
04549          return;
04550       }
04551       pte->device->receiver_state = STATE_OFFHOOK;
04552       if (pte->device->output == OUTPUT_HEADPHONE) {
04553          send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
04554       } else {
04555          send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
04556       }
04557       if (pte->state == STATE_RINGING) {
04558          handle_call_incoming(pte);
04559       } else if ((pte->state == STATE_DIALPAGE) || (pte->state == STATE_CALL)) {
04560          send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
04561       } else if (pte->state == STATE_EXTENSION) { /* We must have a TN before calling */
04562          return;
04563       } else {
04564          pte->device->selected = get_avail_softkey(pte, NULL);
04565          send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
04566          handle_dial_page(pte);
04567       }
04568       return;
04569    }
04570    if (memcmp(buf + SIZE_HEADER, packet_recv_hangup, sizeof(packet_recv_hangup)) == 0) {
04571       if (unistimdebug) {
04572          ast_verb(0, "Handset on hook, current state: %s\n", ptestate_tostr(pte->state));
04573       }
04574       if (!pte->device) {
04575          return;
04576       }
04577       pte->device->receiver_state = STATE_ONHOOK;
04578       if (pte->state == STATE_CALL) {
04579          if (pte->device->output != OUTPUT_SPEAKER) {
04580             close_call(pte);
04581          }
04582       } else if (pte->state == STATE_EXTENSION) {
04583          return;
04584       } else {
04585          pte->device->nextdial = 0;
04586          show_main_page(pte);
04587       }
04588       return;
04589    }
04590    strcpy(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr));
04591    strcat(tmpbuf, " Unknown request packet\n");
04592    if (unistimdebug) {
04593       ast_debug(1, "%s", tmpbuf);
04594    }
04595    return;
04596 }
04597 
04598 static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
04599    struct sockaddr_in *addr_from)
04600 {
04601    unsigned short *sbuf = (unsigned short *) buf;
04602    unsigned short seq;
04603    char tmpbuf[255];
04604 
04605    strcpy(tmpbuf, ast_inet_ntoa(addr_from->sin_addr));
04606 
04607    if (size < 10) {
04608       if (size == 0) {
04609          ast_log(LOG_WARNING, "%s Read error\n", tmpbuf);
04610       } else {
04611          ast_log(LOG_NOTICE, "%s Packet too short - ignoring\n", tmpbuf);
04612       }
04613       return;
04614    }
04615    if (sbuf[0] == 0xffff) {   /* Starting with 0xffff ? *//* Yes, discovery packet ? */
04616       if (size != sizeof(packet_rcv_discovery)) {
04617          ast_log(LOG_NOTICE, "%s Invalid size of a discovery packet\n", tmpbuf);
04618       } else {
04619          if (memcmp(buf, packet_rcv_discovery, sizeof(packet_rcv_discovery)) == 0) {
04620             if (unistimdebug) {
04621                ast_verb(0, "Discovery packet received - Sending Discovery ACK\n");
04622             }
04623             if (pte) {        /* A session was already active for this IP ? */
04624                if (pte->state == STATE_INIT) { /* Yes, but it's a dupe */
04625                   if (unistimdebug) {
04626                      ast_verb(1, "Duplicated Discovery packet\n");
04627                   }
04628                   send_raw_client(sizeof(packet_send_discovery_ack),
04629                              packet_send_discovery_ack, addr_from, &pte->sout);
04630                   pte->seq_phone = (short) 0x0000; /* reset sequence number */
04631                } else { /* No, probably a reboot, phone side */
04632                   close_client(pte);       /* Cleanup the previous session */
04633                   if (create_client(addr_from)) {
04634                      send_raw_client(sizeof(packet_send_discovery_ack),
04635                                 packet_send_discovery_ack, addr_from, &pte->sout);
04636                   }
04637                }
04638             } else {
04639                /* Creating new entry in our phone list */
04640                if ((pte = create_client(addr_from))) {
04641                   send_raw_client(sizeof(packet_send_discovery_ack),
04642                              packet_send_discovery_ack, addr_from, &pte->sout);
04643                }
04644             }
04645             return;
04646          }
04647          ast_log(LOG_NOTICE, "%s Invalid discovery packet\n", tmpbuf);
04648       }
04649       return;
04650    }
04651    if (!pte) {
04652       if (unistimdebug) {
04653          ast_verb(0, "%s Not a discovery packet from an unknown source : ignoring\n", tmpbuf);
04654       }
04655       return;
04656    }
04657 
04658    if (sbuf[0] != 0) {          /* Starting with something else than 0x0000 ? */
04659       ast_log(LOG_NOTICE, "Unknown packet received - ignoring\n");
04660       return;
04661    }
04662    if (buf[5] != 2) {
04663       ast_log(LOG_NOTICE, "%s Wrong direction : got 0x%02hhx expected 0x02\n", tmpbuf, buf[5]);
04664       return;
04665    }
04666    seq = ntohs(sbuf[1]);
04667    if (buf[4] == 1) {
04668       ast_mutex_lock(&pte->lock);
04669       if (unistimdebug) {
04670          ast_verb(0, "ACK received for packet #0x%04x\n", (unsigned)seq);
04671       }
04672       pte->nb_retransmit = 0;
04673 
04674       if ((pte->last_seq_ack) + 1 == seq) {
04675          pte->last_seq_ack++;
04676          check_send_queue(pte);
04677          ast_mutex_unlock(&pte->lock);
04678          return;
04679       }
04680       if (pte->last_seq_ack > seq) {
04681          if (pte->last_seq_ack == 0xffff) {
04682             ast_verb(0, "ACK at 0xffff, restarting counter.\n");
04683             pte->last_seq_ack = 0;
04684          } else {
04685             ast_log(LOG_NOTICE,
04686                   "%s Warning : ACK received for an already ACKed packet : #0x%04x we are at #0x%04x\n",
04687                   tmpbuf, (unsigned)seq, (unsigned)pte->last_seq_ack);
04688          }
04689          ast_mutex_unlock(&pte->lock);
04690          return;
04691       }
04692       if (pte->seq_server < seq) {
04693          ast_log(LOG_NOTICE,
04694                "%s Error : ACK received for a non-existent packet : #0x%04x\n",
04695                tmpbuf, (unsigned)pte->seq_server);
04696          ast_mutex_unlock(&pte->lock);
04697          return;
04698       }
04699       if (unistimdebug) {
04700          ast_verb(0, "%s ACK gap : Received ACK #0x%04x, previous was #0x%04x\n",
04701                   tmpbuf, (unsigned)seq, (unsigned)pte->last_seq_ack);
04702       }
04703       pte->last_seq_ack = seq;
04704       check_send_queue(pte);
04705       ast_mutex_unlock(&pte->lock);
04706       return;
04707    }
04708    if (buf[4] == 2) {
04709       if (unistimdebug) {
04710          ast_verb(0, "Request received\n");
04711       }
04712       if (pte->seq_phone == seq) {
04713          /* Send ACK */
04714          buf[4] = 1;
04715          buf[5] = 1;
04716          send_raw_client(SIZE_HEADER, buf, addr_from, &pte->sout);
04717          pte->seq_phone++;
04718 
04719          process_request(size, buf, pte);
04720          return;
04721       }
04722       if (pte->seq_phone > seq) {
04723          ast_log(LOG_NOTICE,
04724                "%s Warning : received a retransmitted packet : #0x%04x (we are at #0x%04x)\n",
04725                tmpbuf, (unsigned)seq, (unsigned)pte->seq_phone);
04726          /* BUG ? pte->device->seq_phone = seq; */
04727          /* Send ACK */
04728          buf[4] = 1;
04729          buf[5] = 1;
04730          send_raw_client(SIZE_HEADER, buf, addr_from, &pte->sout);
04731          return;
04732       }
04733       ast_log(LOG_NOTICE,
04734             "%s Warning : we lost a packet : received #0x%04x (we are at #0x%04x)\n",
04735             tmpbuf, (unsigned)seq, (unsigned)pte->seq_phone);
04736       return;
04737    }
04738    if (buf[4] == 0) {
04739       ast_log(LOG_NOTICE, "%s Retransmit request for packet #0x%04x\n", tmpbuf, (unsigned)seq);
04740       if (pte->last_seq_ack > seq) {
04741          ast_log(LOG_NOTICE,
04742                "%s Error : received a request for an already ACKed packet : #0x%04x\n",
04743                tmpbuf, (unsigned)pte->last_seq_ack);
04744          return;
04745       }
04746       if (pte->seq_server < seq) {
04747          ast_log(LOG_NOTICE,
04748                "%s Error : received a request for a non-existent packet : #0x%04x\n",
04749                tmpbuf, (unsigned)pte->seq_server);
04750          return;
04751       }
04752       send_retransmit(pte);
04753       return;
04754    }
04755    ast_log(LOG_NOTICE, "%s Unknown request : got 0x%02hhx expected 0x00,0x01 or 0x02\n", tmpbuf, buf[4]);
04756    return;
04757 }
04758 
04759 static struct unistimsession *channel_to_session(struct ast_channel *ast)
04760 {
04761    struct unistim_subchannel *sub;
04762    if (!ast) {
04763       ast_log(LOG_WARNING, "Unistim callback function called with a null channel\n");
04764       return NULL;
04765    }
04766    if (!ast_channel_tech_pvt(ast)) {
04767       ast_log(LOG_WARNING, "Unistim callback function called without a tech_pvt\n");
04768       return NULL;
04769    }
04770    sub = ast_channel_tech_pvt(ast);
04771 
04772    if (!sub->parent) {
04773       ast_log(LOG_WARNING, "Unistim callback function called without a line\n");
04774       return NULL;
04775    }
04776    if (!sub->parent->parent) {
04777       ast_log(LOG_WARNING, "Unistim callback function called without a device\n");
04778       return NULL;
04779    }
04780    ast_mutex_lock(&sub->parent->parent->lock);
04781    if (!sub->parent->parent->session) {
04782       ast_log(LOG_WARNING, "Unistim callback function called without a session\n");
04783       ast_mutex_unlock(&sub->parent->parent->lock);
04784       return NULL;
04785    }
04786    ast_mutex_unlock(&sub->parent->parent->lock);
04787    return sub->parent->parent->session;
04788 }
04789 
04790 static void send_callerid_screen(struct unistimsession *pte, struct unistim_subchannel *sub)
04791 {
04792    char *cidname_str;
04793    char *cidnum_str;
04794 
04795    if (!sub) {
04796       return;
04797    }
04798    if (sub->owner) {
04799       if (ast_channel_connected(sub->owner)->id.number.valid && ast_channel_connected(sub->owner)->id.number.str) {
04800          cidnum_str = ast_channel_connected(sub->owner)->id.number.str;
04801       } else {
04802          cidnum_str = DEFAULTCALLERID;
04803       }
04804       change_callerid(pte, 0, cidnum_str);
04805       if (strlen(cidnum_str) == 0) {
04806          cidnum_str = DEFAULTCALLERID;
04807       }
04808 
04809       if (ast_channel_connected(sub->owner)->id.name.valid && ast_channel_connected(sub->owner)->id.name.str) {
04810          cidname_str = ast_channel_connected(sub->owner)->id.name.str;
04811       } else {
04812          cidname_str = DEFAULTCALLERNAME;
04813       }
04814       change_callerid(pte, 1, cidname_str);
04815       if (strlen(cidname_str) == 0) {
04816          cidname_str = DEFAULTCALLERNAME;
04817       }
04818 
04819       if (pte->device->height == 1) {
04820          char tmpstr[256];
04821          snprintf(tmpstr, sizeof(tmpstr), "%s %s", cidnum_str, ustmtext(cidname_str, pte));
04822          send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmpstr);
04823       } else {
04824          send_text(TEXT_LINE0, TEXT_NORMAL, pte, cidname_str);
04825          send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext(cidnum_str, pte));
04826       }
04827    }
04828 }
04829 
04830 /*--- unistim_call: Initiate UNISTIM call from PBX ---*/
04831 /*      used from the dial() application      */
04832 static int unistim_call(struct ast_channel *ast, const char *dest, int timeout)
04833 {
04834    int res = 0, i;
04835    struct unistim_subchannel *sub, *sub_real;
04836    struct unistimsession *session;
04837    char ringstyle, ringvolume;
04838 
04839    session = channel_to_session(ast);
04840    if (!session) {
04841       ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
04842       return -1;
04843    }
04844    sub = ast_channel_tech_pvt(ast);
04845    sub_real = get_sub(session->device, SUB_REAL);
04846    if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
04847       ast_log(LOG_WARNING, "unistim_call called on %s, neither down nor reserved\n",
04848             ast_channel_name(ast));
04849       return -1;
04850    }
04851 
04852    if (unistimdebug) {
04853       ast_verb(3, "unistim_call(%s)\n", ast_channel_name(ast));
04854    }
04855    session->state = STATE_RINGING;
04856    send_callerid_screen(session, sub);
04857    if (ast_strlen_zero(ast_channel_call_forward(ast))) { /* Send ring only if no call forward, otherwise short ring will apear */
04858       send_text(TEXT_LINE2, TEXT_NORMAL, session, ustmtext("is calling you.", session));
04859       send_text_status(session, ustmtext("Accept        Ignore Hangup", session));
04860 
04861       if (sub_real) {
04862          ringstyle = session->device->cwstyle;
04863          ringvolume = session->device->cwvolume;
04864       } else {
04865          ringstyle = (sub->ringstyle == -1) ? session->device->ringstyle : sub->ringstyle;
04866          ringvolume = (sub->ringvolume == -1) ? session->device->ringvolume : sub->ringvolume;
04867       }
04868       send_ring(session, ringvolume, ringstyle);
04869       change_favorite_icon(session, FAV_ICON_SPEAKER_ONHOOK_BLACK + FAV_BLINK_FAST);
04870       /* Send call identification to all */
04871       for (i = 0; i < FAVNUM; i++) {
04872          if (!soft_key_visible(session->device, i)) {
04873             continue;
04874          }
04875          if (session->device->ssub[i]) {
04876             continue;
04877          }
04878          if (is_key_line(session->device, i) && !strcmp(sub->parent->name, session->device->sline[i]->name)) {
04879             if (unistimdebug) {
04880                ast_verb(0, "Found softkey %d for line %s\n", i, sub->parent->name);
04881             }
04882             send_favorite_short(i, FAV_ICON_SPEAKER_ONHOOK_BLACK + FAV_BLINK_FAST, session);
04883             session->device->ssub[i] = sub;
04884          }
04885       }
04886    }
04887    ast_setstate(ast, AST_STATE_RINGING);
04888    ast_queue_control(ast, AST_CONTROL_RINGING);
04889    return res;
04890 }
04891 
04892 static int unistim_hangup_clean(struct ast_channel *ast, struct unistim_subchannel *sub) {
04893    ast_mutex_lock(&sub->lock);
04894    ast_channel_tech_pvt_set(ast, NULL);
04895    unistim_set_owner(sub, NULL);
04896    sub->alreadygone = 0;
04897    ast_mutex_unlock(&sub->lock);
04898    if (sub->rtp) {
04899       if (unistimdebug) {
04900          ast_verb(0, "Destroying RTP session\n");
04901       }
04902       ast_rtp_instance_destroy(sub->rtp);
04903       sub->rtp = NULL;
04904    }
04905    return 0;
04906 }
04907 
04908 /*--- unistim_hangup: Hangup UNISTIM call */
04909 static int unistim_hangup(struct ast_channel *ast)
04910 {
04911    struct unistim_subchannel *sub = NULL, *sub_real = NULL, *sub_trans = NULL;
04912    struct unistim_line *l;
04913    struct unistim_device *d;
04914    struct unistimsession *s;
04915    int i,end_call = 1;
04916 
04917    s = channel_to_session(ast);
04918    sub = ast_channel_tech_pvt(ast);
04919    l = sub->parent;
04920    d = l->parent;
04921    if (!s) {
04922       ast_debug(1, "Asked to hangup channel not connected\n");
04923       unistim_hangup_clean(ast, sub);
04924       return 0;
04925    }
04926    if (unistimdebug) {
04927       ast_verb(0, "unistim_hangup(%s) on %s@%s (STATE_%s)\n", ast_channel_name(ast), l->name, l->parent->name, ptestate_tostr(s->state));
04928    }
04929    sub_trans = get_sub(d, SUB_THREEWAY);
04930    sub_real = get_sub(d, SUB_REAL);
04931    if (sub_trans && (sub_trans->owner) && (sub->subtype == SUB_REAL)) { /* 3rd party busy or congested and transfer_cancel_step2 does not called */
04932       if (unistimdebug) {
04933          ast_verb(0, "Threeway call disconnected, switching to real call\n");
04934       }
04935       ast_queue_unhold(sub_trans->owner);
04936       sub_trans->moh = 0;
04937       sub_trans->subtype = SUB_REAL;
04938       swap_subs(sub_trans, sub);
04939       send_text_status(s, ustmtext("       Transf        Hangup", s));
04940       send_callerid_screen(s, sub_trans);
04941       unistim_hangup_clean(ast, sub);
04942       unistim_unalloc_sub(d, sub);
04943       return 0;
04944    }
04945    if (sub_real && (sub_real->owner) && (sub->subtype == SUB_THREEWAY) && (s->state == STATE_CALL)) { /* 3way call cancelled by softkey pressed */
04946       if (unistimdebug) {
04947          ast_verb(0, "Real call disconnected, stay in call\n");
04948       }
04949       send_text_status(s, ustmtext("       Transf        Hangup", s));
04950       send_callerid_screen(s, sub_real);
04951       unistim_hangup_clean(ast, sub);
04952       unistim_unalloc_sub(d, sub);
04953       return 0;
04954    }
04955    if (sub->subtype == SUB_REAL) {
04956       sub_stop_silence(s, sub);
04957    } else if (sub->subtype == SUB_RING) {
04958       send_no_ring(s);
04959       for (i = 0; i < FAVNUM; i++) {
04960          if (!soft_key_visible(s->device, i)) {
04961             continue;
04962          }
04963          if (d->ssub[i] != sub) {
04964             if (d->ssub[i] != NULL) { /* Found other subchannel active other then hangup'ed one */
04965                end_call = 0;
04966             }
04967             continue;
04968          }
04969          if (is_key_line(d, i) && !strcmp(l->name, d->sline[i]->name)) {
04970             send_favorite_short(i, FAV_LINE_ICON, s);
04971             d->ssub[i] = NULL;
04972             continue;
04973          }
04974       }
04975    }
04976    if (end_call) {
04977       send_end_call(s); /* Send end call packet only if ending active call, in other way sound should be loosed */
04978    }
04979    sub->moh = 0;
04980    if (sub->softkey >= 0) {
04981       send_favorite_short(sub->softkey, FAV_LINE_ICON, s);
04982    }
04983    /* Delete assign sub to softkey */
04984    for (i = 0; i < FAVNUM; i++) {
04985       if (d->ssub[i] == sub) {
04986          d->ssub[i] = NULL;
04987          break;
04988       }
04989    }
04990    /*refresh_all_favorite(s); */ /* TODO: Update favicons in case of DND keys */
04991    if (s->state == STATE_RINGING && sub->subtype == SUB_RING) {
04992       send_no_ring(s);
04993       if (ast_channel_hangupcause(ast) != AST_CAUSE_ANSWERED_ELSEWHERE) {
04994          d->missed_call++;
04995          write_history(s, 'i', 1);
04996       }
04997       if (!sub_real) {
04998          show_main_page(s);
04999       } else { /* hangup on a ringing line: reset status to reflect that we're still on an active call */
05000             s->state = STATE_CALL;
05001             send_callerid_screen(s, sub_real);
05002             send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("is on-line", s));
05003             send_text_status(s, ustmtext("       Transf        Hangup", s));
05004             send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, s);
05005 
05006       }
05007    }
05008    if (s->state == STATE_CALL && sub->subtype == SUB_REAL) {
05009       close_call(s);
05010    }
05011    sub->softkey = -1;
05012    unistim_hangup_clean(ast, sub);
05013    unistim_unalloc_sub(d, sub);
05014    return 0;
05015 }
05016 
05017 /*--- unistim_answer: Answer UNISTIM call */
05018 static int unistim_answer(struct ast_channel *ast)
05019 {
05020    int res = 0;
05021    struct unistim_subchannel *sub;
05022    struct unistim_line *l;
05023    struct unistim_device *d;
05024    struct unistimsession *s;
05025 
05026    s = channel_to_session(ast);
05027    if (!s) {
05028       ast_log(LOG_WARNING, "unistim_answer on a disconnected device ?\n");
05029       return -1;
05030    }
05031    sub = ast_channel_tech_pvt(ast);
05032    l = sub->parent;
05033    d = l->parent;
05034 
05035    if (unistimdebug) {
05036       ast_verb(0, "unistim_answer(%s) on %s@%s-%d\n", ast_channel_name(ast), l->name,
05037                l->parent->name, sub->softkey);
05038    }
05039    send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("is now on-line", s));
05040    if (get_sub(d, SUB_THREEWAY)) {
05041       send_text_status(s, ustmtext("Transf Cancel", s));
05042    } else {
05043       send_text_status(s, ustmtext("       Transf        Hangup", s));
05044    }
05045    send_start_timer(s);
05046    if (ast_channel_state(ast) != AST_STATE_UP)
05047       ast_setstate(ast, AST_STATE_UP);
05048    return res;
05049 }
05050 
05051 /*--- unistimsock_read: Read data from UNISTIM socket ---*/
05052 /*    Successful messages is connected to UNISTIM call and forwarded to parsing() */
05053 static int unistimsock_read(int *id, int fd, short events, void *ignore)
05054 {
05055    struct sockaddr_in addr_from = { 0, };
05056    struct unistimsession *cur = NULL;
05057    int found = 0;
05058    int tmp = 0;
05059    int dw_num_bytes_rcvd;
05060    unsigned int size_addr_from;
05061 #ifdef DUMP_PACKET
05062    int dw_num_bytes_rcvdd;
05063 #endif
05064 
05065    size_addr_from = sizeof(addr_from);
05066    dw_num_bytes_rcvd =
05067       recvfrom(unistimsock, buff, SIZE_PAGE, 0, (struct sockaddr *) &addr_from,
05068              &size_addr_from);
05069    if (dw_num_bytes_rcvd == -1) {
05070       if (errno == EAGAIN) {
05071          ast_log(LOG_NOTICE, "UNISTIM: Received packet with bad UDP checksum\n");
05072       } else if (errno != ECONNREFUSED) {
05073          ast_log(LOG_WARNING, "Recv error %d (%s)\n", errno, strerror(errno));
05074       }
05075       return 1;
05076    }
05077 
05078    /* Looking in the phone list if we already have a registration for him */
05079    ast_mutex_lock(&sessionlock);
05080    cur = sessions;
05081    while (cur) {
05082       if (cur->sin.sin_addr.s_addr == addr_from.sin_addr.s_addr) {
05083          found = 1;
05084          break;
05085       }
05086       tmp++;
05087       cur = cur->next;
05088    }
05089    ast_mutex_unlock(&sessionlock);
05090 
05091 #ifdef DUMP_PACKET
05092    if (unistimdebug)
05093       ast_verb(0, "\n*** Dump %d bytes from %s - phone_table[%d] ***\n",
05094                dw_num_bytes_rcvd, ast_inet_ntoa(addr_from.sin_addr), tmp);
05095    for (dw_num_bytes_rcvdd = 0; dw_num_bytes_rcvdd < dw_num_bytes_rcvd;
05096        dw_num_bytes_rcvdd++)
05097       ast_verb(0, "%02hhx ", buff[dw_num_bytes_rcvdd]);
05098    ast_verb(0, "\n******************************************\n");
05099 #endif
05100 
05101    if (!found) {
05102       if (unistimdebug) {
05103          ast_verb(0, "Received a packet from an unknown source\n");
05104       }
05105       parsing(dw_num_bytes_rcvd, buff, NULL, (struct sockaddr_in *) &addr_from);
05106 
05107    } else {
05108       parsing(dw_num_bytes_rcvd, buff, cur, (struct sockaddr_in *) &addr_from);
05109    }
05110    return 1;
05111 }
05112 
05113 static struct ast_frame *unistim_rtp_read(const struct ast_channel *ast,
05114    const struct unistim_subchannel *sub)
05115 {
05116    /* Retrieve audio/etc from channel.  Assumes sub->lock is already held. */
05117    struct ast_frame *f;
05118 
05119    if (!ast) {
05120       ast_log(LOG_WARNING, "Channel NULL while reading\n");
05121       return &ast_null_frame;
05122    }
05123 
05124    if (!sub->rtp) {
05125       ast_log(LOG_WARNING, "RTP handle NULL while reading on subchannel %u\n",
05126             sub->subtype);
05127       return &ast_null_frame;
05128    }
05129 
05130    switch (ast_channel_fdno(ast)) {
05131    case 0:
05132       f = ast_rtp_instance_read(sub->rtp, 0);     /* RTP Audio */
05133       break;
05134    case 1:
05135       f = ast_rtp_instance_read(sub->rtp, 1);    /* RTCP Control Channel */
05136       break;
05137    default:
05138       f = &ast_null_frame;
05139    }
05140 
05141    if (sub->owner) {
05142       /* We already hold the channel lock */
05143       if (f->frametype == AST_FRAME_VOICE) {
05144          if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
05145             struct ast_str *cap_buf = ast_str_alloca(64);
05146             struct ast_format_cap *caps;
05147 
05148             ast_debug(1,
05149                   "Oooh, format changed from %s to %s\n",
05150                   ast_format_cap_get_names(ast_channel_nativeformats(sub->owner), &cap_buf),
05151                   ast_format_get_name(f->subclass.format));
05152 
05153             caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
05154             if (caps) {
05155                ast_format_cap_append(caps, f->subclass.format, 0);
05156                ast_channel_nativeformats_set(sub->owner, caps);
05157                ao2_ref(caps, -1);
05158             }
05159             ast_set_read_format(sub->owner, ast_channel_readformat(sub->owner));
05160             ast_set_write_format(sub->owner, ast_channel_writeformat(sub->owner));
05161          }
05162       }
05163    }
05164 
05165    return f;
05166 }
05167 
05168 static struct ast_frame *unistim_read(struct ast_channel *ast)
05169 {
05170    struct ast_frame *fr;
05171    struct unistim_subchannel *sub = ast_channel_tech_pvt(ast);
05172 
05173    ast_mutex_lock(&sub->lock);
05174    fr = unistim_rtp_read(ast, sub);
05175    ast_mutex_unlock(&sub->lock);
05176 
05177    return fr;
05178 }
05179 
05180 static int unistim_write(struct ast_channel *ast, struct ast_frame *frame)
05181 {
05182    struct unistim_subchannel *sub = ast_channel_tech_pvt(ast);
05183    int res = 0;
05184 
05185    if (frame->frametype != AST_FRAME_VOICE) {
05186       if (frame->frametype == AST_FRAME_IMAGE) {
05187          return 0;
05188       } else {
05189          ast_log(LOG_WARNING, "Can't send %u type frames with unistim_write\n",
05190                frame->frametype);
05191          return 0;
05192       }
05193    } else {
05194       if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
05195          struct ast_str *cap_buf = ast_str_alloca(64);
05196 
05197          ast_log(LOG_WARNING,
05198                "Asked to transmit frame type %s, while native formats is %s (read/write = (%s/%s)\n",
05199                ast_format_get_name(frame->subclass.format),
05200                ast_format_cap_get_names(ast_channel_nativeformats(ast), &cap_buf),
05201                ast_format_get_name(ast_channel_readformat(ast)),
05202                ast_format_get_name(ast_channel_writeformat(ast)));
05203          return -1;
05204       }
05205    }
05206 
05207    if (sub) {
05208       ast_mutex_lock(&sub->lock);
05209       if (sub->rtp) {
05210          res = ast_rtp_instance_write(sub->rtp, frame);
05211       }
05212       ast_mutex_unlock(&sub->lock);
05213    }
05214 
05215    return res;
05216 }
05217 
05218 static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
05219 {
05220    struct unistim_subchannel *p = ast_channel_tech_pvt(newchan);
05221    struct unistim_line *l = p->parent;
05222 
05223    ast_mutex_lock(&p->lock);
05224 
05225    ast_debug(1, "New owner for channel USTM/%s@%s-%u is %s\n", l->name,
05226          l->parent->name, p->subtype, ast_channel_name(newchan));
05227 
05228    if (p->owner != oldchan) {
05229       ast_log(LOG_WARNING, "old channel wasn't %s (%p) but was %s (%p)\n",
05230             ast_channel_name(oldchan), oldchan, ast_channel_name(p->owner), p->owner);
05231       ast_mutex_unlock(&p->lock);
05232       return -1;
05233    }
05234 
05235    unistim_set_owner(p, newchan);
05236 
05237    ast_mutex_unlock(&p->lock);
05238 
05239    return 0;
05240 
05241 }
05242 
05243 static char *control2str(int ind)
05244 {
05245    switch (ind) {
05246    case AST_CONTROL_HANGUP:
05247       return "Other end has hungup";
05248    case AST_CONTROL_RING:
05249       return "Local ring";
05250    case AST_CONTROL_RINGING:
05251       return "Remote end is ringing";
05252    case AST_CONTROL_ANSWER:
05253       return "Remote end has answered";
05254    case AST_CONTROL_BUSY:
05255       return "Remote end is busy";
05256    case AST_CONTROL_TAKEOFFHOOK:
05257       return "Make it go off hook";
05258    case AST_CONTROL_OFFHOOK:
05259       return "Line is off hook";
05260    case AST_CONTROL_CONGESTION:
05261       return "Congestion (circuits busy)";
05262    case AST_CONTROL_FLASH:
05263       return "Flash hook";
05264    case AST_CONTROL_WINK:
05265       return "Wink";
05266    case AST_CONTROL_OPTION:
05267       return "Set a low-level option";
05268    case AST_CONTROL_RADIO_KEY:
05269       return "Key Radio";
05270    case AST_CONTROL_RADIO_UNKEY:
05271       return "Un-Key Radio";
05272    case AST_CONTROL_CONNECTED_LINE:
05273       return "Remote end changed";
05274    case AST_CONTROL_SRCCHANGE:
05275       return "RTP source updated";
05276    case AST_CONTROL_SRCUPDATE:
05277       return "Source of media changed";
05278    case -1:
05279       return "Stop tone";
05280    }
05281    return "UNKNOWN";
05282 }
05283 
05284 static void in_band_indication(struct ast_channel *ast, const struct ast_tone_zone *tz,
05285    const char *indication)
05286 {
05287    struct ast_tone_zone_sound *ts = NULL;
05288 
05289    if ((ts = ast_get_indication_tone(tz, indication))) {
05290       ast_playtones_start(ast, 0, ts->data, 1);
05291       ts = ast_tone_zone_sound_unref(ts);
05292    } else {
05293       ast_log(LOG_WARNING, "Unable to get indication tone for %s\n", indication);
05294    }
05295 }
05296 
05297 static int unistim_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
05298 {
05299    struct unistim_subchannel *sub;
05300    struct unistim_line *l;
05301    struct unistimsession *s;
05302 
05303    if (unistimdebug) {
05304       ast_verb(3, "Asked to indicate '%s' (%d) condition on channel %s\n",
05305                control2str(ind), ind, ast_channel_name(ast));
05306    }
05307 
05308    s = channel_to_session(ast);
05309    if (!s) {
05310       return -1;
05311    }
05312    sub = ast_channel_tech_pvt(ast);
05313    l = sub->parent;
05314 
05315    switch (ind) {
05316    case AST_CONTROL_RINGING:
05317       if (ast_channel_state(ast) != AST_STATE_UP) {
05318          send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Ringing...", s));
05319          in_band_indication(ast, l->parent->tz, "ring");
05320          s->device->missed_call = -1;
05321          break;
05322       }
05323       return -1;
05324    case AST_CONTROL_BUSY:
05325       if (ast_channel_state(ast) != AST_STATE_UP) {
05326          sub->alreadygone = 1;
05327          send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Busy", s));
05328          in_band_indication(ast, l->parent->tz, "busy");
05329          s->device->missed_call = -1;
05330          break;
05331       }
05332       return -1;
05333    case AST_CONTROL_INCOMPLETE:
05334       /* Overlapped dialing is not currently supported for UNIStim.  Treat an indication
05335        * of incomplete as congestion
05336        */
05337    case AST_CONTROL_CONGESTION:
05338       if (ast_channel_state(ast) != AST_STATE_UP) {
05339          sub->alreadygone = 1;
05340          send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Congestion", s));
05341          in_band_indication(ast, l->parent->tz, "congestion");
05342          s->device->missed_call = -1;
05343          break;
05344       }
05345       return -1;
05346    case AST_CONTROL_HOLD:
05347       ast_moh_start(ast, data, NULL);
05348       break;
05349    case AST_CONTROL_UNHOLD:
05350       ast_moh_stop(ast);
05351       break;
05352    case AST_CONTROL_PROGRESS:
05353    case AST_CONTROL_SRCUPDATE:
05354    case AST_CONTROL_PROCEEDING:
05355    case AST_CONTROL_UPDATE_RTP_PEER:
05356       break;
05357    case -1:
05358       ast_playtones_stop(ast);
05359       s->device->missed_call = 0;
05360       break;
05361         case AST_CONTROL_CONNECTED_LINE:
05362       ast_log(LOG_NOTICE, "Connected party is now %s <%s>\n",
05363       S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, ""),
05364       S_COR(ast_channel_connected(ast)->id.number.valid, ast_channel_connected(ast)->id.number.str, ""));
05365       if (sub->subtype == SUB_REAL) {
05366          send_callerid_screen(s, sub);
05367       }
05368       break;
05369    case AST_CONTROL_SRCCHANGE:
05370       if (sub->rtp) {
05371          ast_rtp_instance_change_source(sub->rtp);
05372       }
05373       break;
05374    default:
05375       ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
05376       /* fallthrough */
05377    case AST_CONTROL_PVT_CAUSE_CODE:
05378    case AST_CONTROL_MASQUERADE_NOTIFY:
05379       return -1;
05380    }
05381 
05382    return 0;
05383 }
05384 
05385 static struct unistim_subchannel *find_subchannel_by_name(const char *dest)
05386 {
05387    struct unistim_line *l;
05388    struct unistim_device *d;
05389    struct unistim_subchannel *sub = NULL;
05390    char line[256];
05391    char *at;
05392    char *device;
05393 
05394    ast_copy_string(line, dest, sizeof(line));
05395    at = strchr(line, '@');
05396    if (!at) {
05397       ast_log(LOG_NOTICE, "Device '%s' has no @ (at) sign!\n", dest);
05398       return NULL;
05399    }
05400    *at = '\0';
05401    at++;
05402    device = at;
05403    ast_mutex_lock(&devicelock);
05404    d = devices;
05405    at = strchr(device, '/');       /* Extra options ? */
05406    if (at) {
05407       *at = '\0';
05408    }
05409    while (d) {
05410       if (!strcasecmp(d->name, device)) {
05411          if (unistimdebug) {
05412             ast_verb(0, "Found device: %s\n", d->name);
05413          }
05414          /* Found the device */
05415          AST_LIST_LOCK(&d->lines);
05416          AST_LIST_TRAVERSE(&d->lines, l, list) {
05417             /* Search for the right line */
05418             if (!strcasecmp(l->name, line)) {
05419                if (unistimdebug) {
05420                   ast_verb(0, "Found line: %s\n", l->name);
05421                }
05422                sub = get_sub(d, SUB_REAL);
05423                if (!sub) {
05424                   sub = unistim_alloc_sub(d, SUB_REAL);
05425                }
05426                if (sub->owner) {
05427                   /* Allocate additional channel if asterisk channel already here */
05428                   sub = unistim_alloc_sub(d, SUB_ONHOLD);
05429                }
05430                sub->ringvolume = -1;
05431                sub->ringstyle = -1;
05432                if (at) {       /* Other options ? */
05433                   at++;   /* Skip slash */
05434                   if (*at == 'r') {       /* distinctive ring */
05435                      at++;
05436                      if ((*at < '0') || (*at > '7')) { /* ring style */
05437                         ast_log(LOG_WARNING, "Invalid ring selection (%s)", at);
05438                      } else {
05439                         char ring_volume = -1;
05440                         char ring_style = *at - '0';
05441                         at++;
05442                         if ((*at >= '0') && (*at <= '3')) {      /* ring volume */
05443                            ring_volume = *at - '0';
05444                         }
05445                         if (unistimdebug) {
05446                            ast_verb(0, "Distinctive ring: style #%d volume %d\n",
05447                                ring_style, ring_volume);
05448                         }
05449                         sub->ringvolume = ring_volume;
05450                         sub->ringstyle = ring_style;
05451                      }
05452                   }
05453                }
05454                sub->parent = l;
05455                break;
05456             }
05457          }
05458          AST_LIST_UNLOCK(&d->lines);
05459          if (sub) {
05460             ast_mutex_unlock(&devicelock);
05461             return sub;
05462          }
05463       }
05464       d = d->next;
05465    }
05466    /* Device not found */
05467    ast_mutex_unlock(&devicelock);
05468 
05469    return NULL;
05470 }
05471 
05472 static int unistim_senddigit_begin(struct ast_channel *ast, char digit)
05473 {
05474    struct unistimsession *pte = channel_to_session(ast);
05475 
05476    if (!pte) {
05477       return -1;
05478    }
05479    return unistim_do_senddigit(pte, digit);
05480 }
05481 
05482 static int unistim_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
05483 {
05484    struct unistimsession *pte = channel_to_session(ast);
05485    struct ast_frame f = { 0, };
05486    struct unistim_subchannel *sub;
05487 
05488    sub = get_sub(pte->device, SUB_REAL);
05489 
05490    if (!sub || !sub->owner || sub->alreadygone) {
05491       ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit_end\n");
05492       return -1;
05493    }
05494 
05495    if (unistimdebug) {
05496       ast_verb(0, "Send Digit off %c\n", digit);
05497    }
05498    if (!pte) {
05499       return -1;
05500    }
05501    send_tone(pte, 0, 0);
05502    f.frametype = AST_FRAME_DTMF;
05503    f.subclass.integer = digit;
05504    f.src = "unistim";
05505    ast_queue_frame(sub->owner, &f);
05506 
05507    return 0;
05508 }
05509 
05510 /*--- unistim_sendtext: Display a text on the phone screen ---*/
05511 /*      Called from PBX core text message functions */
05512 static int unistim_sendtext(struct ast_channel *ast, const char *text)
05513 {
05514    struct unistimsession *pte = channel_to_session(ast);
05515    int size;
05516    char tmp[TEXT_LENGTH_MAX + 1];
05517 
05518    if (unistimdebug) {
05519       ast_verb(0, "unistim_sendtext called\n");
05520    }
05521    if (!text) {
05522       ast_log(LOG_WARNING, "unistim_sendtext called with a null text\n");
05523       return -1;
05524    }
05525 
05526    if (!pte) {
05527       return -1;
05528    }
05529 
05530    size = strlen(text);
05531    if (text[0] == '@') {
05532       int pos = 0, i = 1, tok = 0, sz = 0;
05533       char label[11];
05534       char number[16];
05535       char icon = '\0';
05536       char cur = '\0';
05537 
05538       memset(label, 0, 11);
05539       memset(number, 0, 16);
05540       while (text[i]) {
05541          cur = text[i++];
05542          switch (tok) {
05543          case 0:
05544             if ((cur < '0') && (cur > '5')) {
05545                ast_log(LOG_WARNING,
05546                      "sendtext failed : position must be a number beetween 0 and 5\n");
05547                return 1;
05548             }
05549             pos = cur - '0';
05550             tok = 1;
05551             continue;
05552          case 1:
05553             if (cur != '@') {
05554                ast_log(LOG_WARNING, "sendtext failed : invalid position\n");
05555                return 1;
05556             }
05557             tok = 2;
05558             continue;
05559          case 2:
05560             if ((cur < '3') && (cur > '6')) {
05561                ast_log(LOG_WARNING,
05562                      "sendtext failed : icon must be a number beetween 32 and 63 (first digit invalid)\n");
05563                return 1;
05564             }
05565             icon = (cur - '0') * 10;
05566             tok = 3;
05567             continue;
05568          case 3:
05569             if ((cur < '0') && (cur > '9')) {
05570                ast_log(LOG_WARNING,
05571                      "sendtext failed : icon must be a number beetween 32 and 63 (second digit invalid)\n");
05572                return 1;
05573             }
05574             icon += (cur - '0');
05575             tok = 4;
05576             continue;
05577          case 4:
05578             if (cur != '@') {
05579                ast_log(LOG_WARNING,
05580                      "sendtext failed : icon must be a number beetween 32 and 63 (too many digits)\n");
05581                return 1;
05582             }
05583             tok = 5;
05584             continue;
05585          case 5:
05586             if (cur == '@') {
05587                tok = 6;
05588                sz = 0;
05589                continue;
05590             }
05591             if (sz > 10) {
05592                continue;
05593             }
05594             label[sz] = cur;
05595             sz++;
05596             continue;
05597          case 6:
05598             if (sz > 15) {
05599                ast_log(LOG_WARNING,
05600                      "sendtext failed : extension too long = %d (15 car max)\n",
05601                      sz);
05602                return 1;
05603             }
05604             number[sz] = cur;
05605             sz++;
05606             continue;
05607          }
05608       }
05609       if (tok != 6) {
05610          ast_log(LOG_WARNING, "sendtext failed : incomplet command\n");
05611          return 1;
05612       }
05613       if (!pte->device) {
05614          ast_log(LOG_WARNING, "sendtext failed : no device ?\n");
05615          return 1;
05616       }
05617       strcpy(pte->device->softkeylabel[pos], label);
05618       strcpy(pte->device->softkeynumber[pos], number);
05619       pte->device->softkeyicon[pos] = icon;
05620       send_favorite(pos, icon, pte, label);
05621       return 0;
05622    }
05623 
05624    if (size <= TEXT_LENGTH_MAX * 2) {
05625       if (pte->device->height == 1) {
05626          send_text(TEXT_LINE0, TEXT_NORMAL, pte, text);
05627       } else {
05628          send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Message :", pte));
05629          send_text(TEXT_LINE1, TEXT_NORMAL, pte, text);
05630       }
05631       if (size <= TEXT_LENGTH_MAX) {
05632          send_text(TEXT_LINE2, TEXT_NORMAL, pte, "");
05633          return 0;
05634       }
05635       memcpy(tmp, text + TEXT_LENGTH_MAX, TEXT_LENGTH_MAX);
05636       tmp[sizeof(tmp) - 1] = '\0';
05637       send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
05638       return 0;
05639    }
05640    send_text(TEXT_LINE0, TEXT_NORMAL, pte, text);
05641    memcpy(tmp, text + TEXT_LENGTH_MAX, TEXT_LENGTH_MAX);
05642    tmp[sizeof(tmp) - 1] = '\0';
05643    send_text(TEXT_LINE1, TEXT_NORMAL, pte, tmp);
05644    memcpy(tmp, text + TEXT_LENGTH_MAX * 2, TEXT_LENGTH_MAX);
05645    tmp[sizeof(tmp) - 1] = '\0';
05646    send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
05647    return 0;
05648 }
05649 
05650 /*--- unistim_send_mwi_to_peer: Send message waiting indication ---*/
05651 static int unistim_send_mwi_to_peer(struct unistim_line *peer, unsigned int tick)
05652 {
05653    int new;
05654    RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
05655 
05656    msg = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), peer->mailbox);
05657    if (msg) {
05658       struct ast_mwi_state *mwi_state = stasis_message_data(msg);
05659       new = mwi_state->new_msgs;
05660    } else { /* Fall back on checking the mailbox directly */
05661       new = ast_app_has_voicemail(peer->mailbox, NULL);
05662    }
05663    ast_debug(3, "MWI Status for mailbox %s is %d, lastmsgsent:%d\n",
05664       peer->mailbox, new, peer->parent->lastmsgssent);
05665    peer->parent->nextmsgcheck = tick + TIMER_MWI;
05666 
05667    /* Return now if it's the same thing we told them last time */
05668    if ((peer->parent->session->state != STATE_MAINPAGE) || (new == peer->parent->lastmsgssent)) {
05669       return 0;
05670    }
05671 
05672    peer->parent->lastmsgssent = new;
05673    send_led_update(peer->parent->session, (new > 0)?LED_BAR_ON:LED_BAR_OFF);
05674 
05675    return 0;
05676 }
05677 
05678 /*--- unistim_new: Initiate a call in the UNISTIM channel */
05679 /*      called from unistim_request (calls from the pbx ) */
05680 static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
05681 {
05682    struct ast_format_cap *caps;
05683    struct ast_channel *tmp;
05684    struct unistim_line *l;
05685    struct ast_format *tmpfmt;
05686 
05687    if (!sub) {
05688       ast_log(LOG_WARNING, "subchannel null in unistim_new\n");
05689       return NULL;
05690    }
05691    if (!sub->parent) {
05692       ast_log(LOG_WARNING, "no line for subchannel %p\n", sub);
05693       return NULL;
05694    }
05695 
05696    caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
05697    if (!caps) {
05698       return NULL;
05699    }
05700 
05701    l = sub->parent;
05702    tmp = ast_channel_alloc(1, state, l->cid_num, NULL, l->accountcode, l->exten,
05703       l->parent->context, assignedids, requestor, l->amaflags, "USTM/%s@%s-%p", l->name, l->parent->name, sub);
05704    if (unistimdebug) {
05705       ast_verb(0, "unistim_new sub=%u (%p) chan=%p line=%s\n", sub->subtype, sub, tmp, l->name);
05706    }
05707    if (!tmp) {
05708       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
05709       ao2_ref(caps, -1);
05710       return NULL;
05711    }
05712 
05713    ast_channel_stage_snapshot(tmp);
05714 
05715    if (ast_format_cap_count(l->cap)) {
05716       ast_format_cap_append_from_cap(caps, l->cap, AST_MEDIA_TYPE_UNKNOWN);
05717    } else {
05718       ast_format_cap_append_from_cap(caps, global_cap, AST_MEDIA_TYPE_UNKNOWN);
05719    }
05720    ast_channel_nativeformats_set(tmp, caps);
05721    ao2_ref(caps, -1);
05722 
05723    tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(tmp), 0);
05724 
05725    if (unistimdebug) {
05726       struct ast_str *native_buf = ast_str_alloca(64);
05727       struct ast_str *cap_buf = ast_str_alloca(64);
05728       struct ast_str *global_buf = ast_str_alloca(64);
05729 
05730       ast_verb(0, "Best codec = %s from nativeformats %s (line cap=%s global=%s)\n",
05731          ast_format_get_name(tmpfmt),
05732          ast_format_cap_get_names(ast_channel_nativeformats(tmp), &native_buf),
05733          ast_format_cap_get_names(l->cap, &cap_buf),
05734          ast_format_cap_get_names(global_cap, &global_buf));
05735    }
05736    if ((sub->rtp) && (sub->subtype == 0)) {
05737       if (unistimdebug) {
05738          ast_verb(0, "New unistim channel with a previous rtp handle ?\n");
05739       }
05740       ast_channel_internal_fd_set(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
05741       ast_channel_internal_fd_set(tmp, 1, ast_rtp_instance_fd(sub->rtp, 1));
05742    }
05743    if (sub->rtp) {
05744       ast_jb_configure(tmp, &global_jbconf);
05745    }
05746 /*      tmp->type = type; */
05747    ast_setstate(tmp, state);
05748    if (state == AST_STATE_RING) {
05749       ast_channel_rings_set(tmp, 1);
05750    }
05751    ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
05752 
05753    ast_channel_set_writeformat(tmp, tmpfmt);
05754    ast_channel_set_rawwriteformat(tmp, tmpfmt);
05755    ast_channel_set_readformat(tmp, tmpfmt);
05756    ast_channel_set_rawreadformat(tmp, tmpfmt);
05757    ao2_ref(tmpfmt, -1);
05758 
05759    ast_channel_tech_pvt_set(tmp, sub);
05760    ast_channel_tech_set(tmp, &unistim_tech);
05761 
05762    if (!ast_strlen_zero(l->parent->language)) {
05763       ast_channel_language_set(tmp, l->parent->language);
05764    }
05765    unistim_set_owner(sub, tmp);
05766    ast_update_use_count();
05767    ast_channel_callgroup_set(tmp, l->callgroup);
05768    ast_channel_pickupgroup_set(tmp, l->pickupgroup);
05769    ast_channel_call_forward_set(tmp, l->parent->call_forward);
05770    if (!ast_strlen_zero(l->cid_num)) {
05771       char *name, *loc, *instr;
05772       instr = ast_strdup(l->cid_num);
05773       if (instr) {
05774          ast_callerid_parse(instr, &name, &loc);
05775          ast_channel_caller(tmp)->id.number.valid = 1;
05776          ast_free(ast_channel_caller(tmp)->id.number.str);
05777          ast_channel_caller(tmp)->id.number.str = ast_strdup(loc);
05778          ast_channel_caller(tmp)->id.name.valid = 1;
05779          ast_free(ast_channel_caller(tmp)->id.name.str);
05780          ast_channel_caller(tmp)->id.name.str = ast_strdup(name);
05781          ast_free(instr);
05782       }
05783    }
05784    ast_channel_priority_set(tmp, 1);
05785 
05786    ast_channel_stage_snapshot_done(tmp);
05787    ast_channel_unlock(tmp);
05788 
05789    if (state != AST_STATE_DOWN) {
05790       if (unistimdebug) {
05791          ast_verb(0, "Starting pbx in unistim_new\n");
05792       }
05793       if (ast_pbx_start(tmp)) {
05794          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
05795          ast_hangup(tmp);
05796          tmp = NULL;
05797       }
05798    }
05799 
05800    return tmp;
05801 }
05802 
05803 static void unistim_set_owner(struct unistim_subchannel *sub, struct ast_channel *chan)
05804 {
05805    sub->owner = chan;
05806    if (sub->rtp) {
05807       ast_rtp_instance_set_channel_id(sub->rtp, sub->owner ? ast_channel_uniqueid(sub->owner) : "");
05808    }
05809 }
05810 
05811 static void *do_monitor(void *data)
05812 {
05813    struct unistimsession *cur = NULL;
05814    unsigned int dw_timeout = 0;
05815    unsigned int tick;
05816    int res;
05817    int reloading;
05818 
05819    /* Add an I/O event to our UDP socket */
05820    if (unistimsock > -1) {
05821       ast_io_add(io, unistimsock, unistimsock_read, AST_IO_IN, NULL);
05822    }
05823    /* This thread monitors our UDP socket and timers */
05824    for (;;) {
05825       /* This loop is executed at least every IDLE_WAITus (1s) or every time a packet is received */
05826       /* Looking for the smallest time-out value */
05827       tick = get_tick_count();
05828       dw_timeout = UINT_MAX;
05829       ast_mutex_lock(&sessionlock);
05830       cur = sessions;
05831       DEBUG_TIMER("checking timeout for session %p with tick = %u\n", cur, tick);
05832       while (cur) {
05833          DEBUG_TIMER("checking timeout for session %p timeout = %u\n", cur,
05834                   cur->timeout);
05835          /* Check if we have miss something */
05836          if (cur->timeout <= tick) {
05837             DEBUG_TIMER("Event for session %p\n", cur);
05838             /* If the queue is empty, send a ping */
05839             if (cur->last_buf_available == 0) {
05840                send_ping(cur);
05841             } else {
05842                if (send_retransmit(cur)) {
05843                   DEBUG_TIMER("The chained link was modified, restarting...\n");
05844                   cur = sessions;
05845                   dw_timeout = UINT_MAX;
05846                   continue;
05847                }
05848             }
05849          }
05850          if (dw_timeout >