Sat Apr 26 2014 22:01:34

Asterisk developer's documentation


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