Sat Jul 12 2014 17:18:30

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: 414677 $")
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 : (%d) %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", (unsigned)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, (unsigned)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, (unsigned)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 %u 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, (unsigned)pte->seq_server, (unsigned)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                   (unsigned)seq, (unsigned)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", (unsigned)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",
01542          (unsigned)output, (unsigned)volume, (unsigned)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 %u 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) 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 = %u\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 : %u\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       send_tone(pte, tone_data.freq1, tone_data.freq2);
02829       if (unistimdebug) {
02830          ast_verb(0, "Country code found (%s), freq1=%u freq2=%u\n",
02831                      pte->device->tz->country, tone_data.freq1, tone_data.freq2);
02832       }
02833       ts = ast_tone_zone_sound_unref(ts);
02834    }
02835 }
02836 
02837 static void show_phone_number(struct unistimsession *pte)
02838 {
02839    char tmp[TEXT_LENGTH_MAX + 1];
02840    const char *tmp_number = ustmtext("Number:", pte);
02841    int line, tmp_copy, offset = 0, i;
02842 
02843    pte->device->phone_number[pte->device->size_phone_number] = '\0';
02844    if  (pte->device->size_phone_number > MAX_SCREEN_NUMBER) {
02845       offset = pte->device->size_phone_number - MAX_SCREEN_NUMBER - 1;
02846       if (offset > strlen(tmp_number)) {
02847          offset = strlen(tmp_number);
02848       }
02849       tmp_copy = strlen(tmp_number) - offset + 1;
02850       if (tmp_copy > sizeof(tmp)) {
02851          tmp_copy = sizeof(tmp);
02852       }
02853       memcpy(tmp, tmp_number + offset, tmp_copy);
02854    } else {
02855       ast_copy_string(tmp, tmp_number, sizeof(tmp));
02856    }
02857 
02858    offset = (pte->device->size_phone_number >= TEXT_LENGTH_MAX) ? (pte->device->size_phone_number - TEXT_LENGTH_MAX +1) : 0;
02859    if (pte->device->size_phone_number) {
02860       memcpy(tmp + strlen(tmp), pte->device->phone_number + offset, pte->device->size_phone_number - offset + 1);
02861    }
02862    offset = strlen(tmp);
02863 
02864    for (i = strlen(tmp); i < TEXT_LENGTH_MAX; i++) {
02865       tmp[i] = '.';
02866    }
02867    tmp[i] = '\0';
02868 
02869    line = (pte->device->height == 1) ? TEXT_LINE0 : TEXT_LINE2;
02870    send_text(line, TEXT_NORMAL, pte, tmp);
02871    send_blink_cursor(pte);
02872    send_cursor_pos(pte, (unsigned char) (line + offset));
02873    send_led_update(pte, 0);
02874 }
02875 
02876 static void handle_dial_page(struct unistimsession *pte)
02877 {
02878    pte->state = STATE_DIALPAGE;
02879    if (pte->device->call_forward[0] == -1) {
02880       send_text(TEXT_LINE0, TEXT_NORMAL, pte, "");
02881       send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Enter forward", pte));
02882       send_text_status(pte, ustmtext("Fwd    Cancel BackSp Erase", pte));
02883       if (pte->device->call_forward[1] != 0) {
02884          ast_copy_string(pte->device->phone_number, pte->device->call_forward + 1,
02885                      sizeof(pte->device->phone_number));
02886          show_phone_number(pte);
02887          send_led_update(pte, 0);
02888          return;
02889       }
02890    } else {
02891       if ((pte->device->output == OUTPUT_HANDSET) &&
02892          (pte->device->receiver_state == STATE_ONHOOK)) {
02893          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
02894       } else {
02895          send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
02896       }
02897       send_dial_tone(pte);
02898 
02899       if (pte->device->height > 1) {
02900          send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Enter the number to dial", pte));
02901          send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("and press Call", pte));
02902       }
02903       if (ast_strlen_zero(pte->device->redial_number)) {
02904          send_text_status(pte, ustmtext("Call          BackSp Erase", pte));
02905       } else {
02906          send_text_status(pte, ustmtext("Call   Redial BackSp Erase", pte));
02907       }
02908    }
02909 
02910    pte->device->size_phone_number = 0;
02911    pte->device->phone_number[0] = 0;
02912    show_phone_number(pte);
02913    change_favorite_icon(pte, FAV_ICON_PHONE_BLACK);
02914    send_icon(TEXT_LINE0, FAV_ICON_NONE, pte);
02915    pte->device->missed_call = 0;
02916    send_led_update(pte, 0);
02917    pte->device->lastmsgssent = -1;
02918    return;
02919 }
02920 
02921 static void swap_subs(struct unistim_subchannel *a, struct unistim_subchannel *b)
02922 {
02923    struct ast_rtp_instance *rtp;
02924    int fds;
02925 
02926    if (unistimdebug) {
02927       ast_verb(0, "Swapping %p and %p\n", a, b);
02928    }
02929    if ((!a->owner) || (!b->owner)) {
02930       ast_log(LOG_WARNING,
02931             "Attempted to swap subchannels with a null owner : sub #%p=%p sub #%p=%p\n",
02932             a, a->owner, b, b->owner);
02933       return;
02934    }
02935    rtp = a->rtp;
02936    a->rtp = b->rtp;
02937    b->rtp = rtp;
02938 
02939    fds = ast_channel_fd(a->owner, 0);
02940    ast_channel_internal_fd_set(a->owner, 0, ast_channel_fd(b->owner, 0));
02941    ast_channel_internal_fd_set(b->owner, 0, fds);
02942 
02943    fds = ast_channel_fd(a->owner, 1);
02944    ast_channel_internal_fd_set(a->owner, 1, ast_channel_fd(b->owner, 1));
02945    ast_channel_internal_fd_set(b->owner, 1, fds);
02946 }
02947 
02948 /* Step 1 : Music On Hold for peer, Dialing screen for us */
02949 static void transfer_call_step1(struct unistimsession *pte)
02950 {
02951    struct unistim_subchannel *sub /*, *sub_trans */;
02952    struct unistim_device *d = pte->device;
02953 
02954    sub = get_sub(d, SUB_REAL);
02955    /* sub_trans = get_sub(d, SUB_THREEWAY); */
02956 
02957    if (!sub || !sub->owner) {
02958       ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
02959       return;
02960    }
02961    /* Start music on hold if appropriate */
02962    if (sub->moh) {
02963       ast_log(LOG_WARNING, "Transfer with peer already listening music on hold\n");
02964    } else {
02965       if (ast_bridged_channel(sub->owner)) {
02966          ast_moh_start(ast_bridged_channel(sub->owner),
02967                     sub->parent->musicclass, NULL);
02968          sub->moh = 1;
02969          sub->subtype = SUB_THREEWAY;
02970       } else {
02971          ast_log(LOG_WARNING, "Unable to find peer subchannel for music on hold\n");
02972          return;
02973       }
02974    }
02975    sub_start_silence(pte, sub);
02976    handle_dial_page(pte);
02977 }
02978 
02979 static void transfer_cancel_step2(struct unistimsession *pte)
02980 {
02981    struct unistim_subchannel *sub, *sub_trans;
02982    struct unistim_device *d = pte->device;
02983 
02984    sub = get_sub(d, SUB_REAL);
02985    sub_trans = get_sub(d, SUB_THREEWAY);
02986 
02987    if (!sub || !sub->owner) {
02988       ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
02989       return;
02990    }
02991    if (sub_trans) {
02992       if (unistimdebug) {
02993          ast_verb(0, "Transfer canceled, hangup our threeway channel\n");
02994       }
02995       if (sub->owner) {
02996          swap_subs(sub, sub_trans);
02997          ast_moh_stop(ast_bridged_channel(sub_trans->owner));
02998          sub_trans->moh = 0;
02999          sub_trans->subtype = SUB_REAL;
03000          sub->subtype = SUB_THREEWAY;
03001          ast_queue_hangup_with_cause(sub->owner, AST_CAUSE_NORMAL_CLEARING);
03002       } else {
03003          ast_log(LOG_WARNING, "Canceling a threeway channel without owner\n");
03004       }
03005       return;
03006    }
03007 }
03008 
03009 /* From phone to PBX */
03010 static void handle_call_outgoing(struct unistimsession *s)
03011 {
03012    struct ast_channel *c;
03013    struct unistim_subchannel *sub;
03014    int softkey;
03015 
03016    s->state = STATE_CALL;
03017 
03018    sub = get_sub(s->device, SUB_THREEWAY);
03019    if (sub) {
03020       /* If sub for threway call created than we use transfer behaviuor */
03021       struct unistim_subchannel *sub_trans = NULL;
03022       struct unistim_device *d = s->device;
03023 
03024       sub_trans = get_sub(d, SUB_REAL);
03025       if (sub_trans) {
03026          ast_log(LOG_WARNING, "Can't transfer while active subchannel exists!\n");
03027          return;
03028       }
03029       if (!sub->owner) {
03030          ast_log(LOG_WARNING, "Unable to find subchannel with music on hold\n");
03031          return;
03032       }
03033 
03034       sub_trans = unistim_alloc_sub(d, SUB_REAL);
03035       if (!sub_trans) {
03036          ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
03037          return;
03038       }
03039       sub_trans->parent = sub->parent;
03040       sub_stop_silence(s, sub);
03041       send_tone(s, 0, 0);
03042       /* Make new channel */
03043       c = unistim_new(sub_trans, AST_STATE_DOWN, NULL);
03044       if (!c) {
03045          ast_log(LOG_WARNING, "Cannot allocate new structure on channel %p\n", sub->parent);
03046          return;
03047       }
03048       /* Swap things around between the three-way and real call */
03049       swap_subs(sub, sub_trans);
03050       send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
03051       if (s->device->height == 1) {
03052          send_text(TEXT_LINE0, TEXT_NORMAL, s, s->device->phone_number);
03053       } else {
03054          send_text(TEXT_LINE0, TEXT_NORMAL, s, ustmtext("Calling (pre-transfer)", s));
03055          send_text(TEXT_LINE1, TEXT_NORMAL, s, s->device->phone_number);
03056          send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Dialing...", s));
03057       }
03058       send_text_status(s, ustmtext("TransfrCancel", s));
03059 
03060       if (ast_pthread_create(&sub->ss_thread, NULL, unistim_ss, c)) {
03061          ast_log(LOG_WARNING, "Unable to start simple switch on channel %p\n", c);
03062          sub->ss_thread = AST_PTHREADT_NULL;
03063          ast_hangup(c);
03064          return;
03065       }
03066       if (unistimdebug) {
03067          ast_verb(0, "Started three way call on channel %p (%s) subchan %u\n",
03068              sub_trans->owner, ast_channel_name(sub_trans->owner), sub_trans->subtype);
03069       }
03070       return;
03071    }
03072 
03073    softkey = get_avail_softkey(s, NULL);
03074    if (softkey == -1) {
03075       ast_log(LOG_WARNING, "Have no avail softkey for calling\n");
03076       return;
03077    }
03078    sub = get_sub(s->device, SUB_REAL);
03079    if (sub) { /* have already call assigned */
03080       sub_hold(s, sub); /* Need to put on hold */
03081    }
03082    if (!(sub = unistim_alloc_sub(s->device, SUB_REAL))) {
03083       ast_log(LOG_WARNING, "Unable to allocate subchannel!\n");
03084       return;      
03085    }
03086    sub->parent = s->device->sline[softkey];
03087    s->device->ssub[softkey] = sub;
03088    sub->softkey = softkey;
03089 
03090    if (unistimdebug) {
03091       ast_verb(0, "Using softkey %d, line %p\n", sub->softkey, sub->parent);
03092    }
03093    send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, s);
03094    s->device->selected = -1;
03095    if (!sub->owner) {            /* A call is already in progress ? */
03096       c = unistim_new(sub, AST_STATE_DOWN, NULL);   /* No, starting a new one */
03097       if (!sub->rtp) { /* Need to start RTP before calling ast_pbx_run */
03098          start_rtp(sub);
03099       }
03100       if (c && !strcmp(s->device->phone_number, ast_pickup_ext())) {
03101          if (unistimdebug) {
03102             ast_verb(0, "Try to pickup in unistim_new\n");
03103          }
03104          send_text(TEXT_LINE0, TEXT_NORMAL, s, "");
03105          send_text_status(s, ustmtext("       Transf        Hangup", s));
03106          send_start_timer(s);
03107          if (ast_pickup_call(c)) {
03108             ast_log(LOG_NOTICE, "Nothing to pick up\n");
03109             ast_channel_hangupcause_set(c, AST_CAUSE_CALL_REJECTED);
03110          } else {
03111             ast_channel_hangupcause_set(c, AST_CAUSE_NORMAL_CLEARING);
03112          }
03113          ast_hangup(c);
03114          c = NULL;
03115                 } else if (c) {
03116          send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
03117          send_tone(s, 0, 0); /* Dialing empty number should also stop dial tone */
03118          if (s->device->height == 1) {
03119             if (strlen(s->device->phone_number) > 0) {
03120                send_text(TEXT_LINE0, TEXT_NORMAL, s, s->device->phone_number);
03121             } else {
03122                send_text(TEXT_LINE0, TEXT_NORMAL, s, ustmtext("Calling...", s));
03123             }
03124          } else {
03125             send_text(TEXT_LINE0, TEXT_NORMAL, s, ustmtext("Calling :", s));
03126             send_text(TEXT_LINE1, TEXT_NORMAL, s, s->device->phone_number);
03127             send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Dialing...", s));
03128          }
03129          send_text_status(s, ustmtext("                     Hangup", s));
03130 
03131          /* start switch */
03132          if (ast_pthread_create(&sub->ss_thread, NULL, unistim_ss, c)) {
03133             ast_log(LOG_WARNING, "Unable to create switch thread\n");
03134             sub->ss_thread = AST_PTHREADT_NULL;
03135             ast_queue_hangup_with_cause(c, AST_CAUSE_SWITCH_CONGESTION);
03136          }
03137       } else
03138          ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n",
03139                sub->parent->name, s->device->name);
03140    } else {
03141       ast_debug(1, "Current sub [%s] already has owner\n", ast_channel_name(sub->owner));
03142    }
03143    return;
03144 }
03145 
03146 /* From PBX to phone */
03147 static void handle_call_incoming(struct unistimsession *s)
03148 {
03149    struct unistim_subchannel *sub = NULL;
03150    int i;
03151 
03152    s->state = STATE_CALL;
03153    s->device->missed_call = 0;
03154    send_no_ring(s);
03155    sub = get_sub(s->device, SUB_RING); /* Put other SUB_REAL call on hold */
03156    if (!sub) {
03157       ast_log(LOG_WARNING, "No ringing lines on: %s\n", s->device->name);
03158       return;
03159    }
03160    /* Change icons for all ringing keys */
03161    for (i = 0; i < FAVNUM; i++) {
03162       if (!s->device->ssub[i]) { /* No sub assigned - skip */
03163          continue;
03164       }
03165       if (s->device->ssub[i]->subtype == SUB_REAL) {
03166          sub_hold(s, s->device->ssub[i]);
03167       }
03168       if (s->device->ssub[i] != sub) {
03169          continue;
03170       }
03171       if (sub->softkey == i) { /* If softkey assigned at this moment - do not erase */
03172          continue;
03173       }
03174       if (sub->softkey < 0) { /* If softkey not defined - first one used */
03175          sub->softkey = i;
03176          continue;
03177       }
03178       send_favorite_short(i, FAV_LINE_ICON, s);
03179       s->device->ssub[i] = NULL;
03180    }
03181    if (sub->softkey < 0) {
03182       ast_log(LOG_WARNING, "Can not assign softkey for incoming call on: %s\n", s->device->name);
03183       return;
03184    }
03185    send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, s);
03186    sub->parent = s->device->sline[sub->softkey];
03187    sub->subtype = SUB_REAL;
03188    if (unistimdebug) {
03189       ast_verb(0, "Handle Call Incoming for %s@%s\n", sub->parent->name,
03190                s->device->name);
03191    }
03192    start_rtp(sub);
03193    if (!sub->rtp) {
03194       ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name, s->device->name);
03195       return;
03196    }
03197    if (sub->owner) {
03198       ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
03199    }
03200    send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("is on-line", s));
03201    send_text_status(s, ustmtext("       Transf        Hangup", s));
03202    send_start_timer(s);
03203 
03204    if ((s->device->output == OUTPUT_HANDSET) &&
03205       (s->device->receiver_state == STATE_ONHOOK)) {
03206       send_select_output(s, OUTPUT_SPEAKER, s->device->volume, MUTE_OFF);
03207    } else {
03208       send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
03209    }
03210    write_history(s, 'i', 0);
03211    return;
03212 }
03213 
03214 static int unistim_do_senddigit(struct unistimsession *pte, char digit)
03215 {
03216    struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass.integer = digit, .src = "unistim" };
03217    struct unistim_subchannel *sub;
03218         int row, col;
03219 
03220    sub = get_sub(pte->device, SUB_REAL);
03221    if (!sub || !sub->owner || sub->alreadygone) {
03222       ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit\n");
03223       return -1;
03224    }
03225 
03226    /* Send DTMF indication _before_ playing sounds */
03227    ast_queue_frame(sub->owner, &f);
03228 
03229    if (unistimdebug) {
03230       ast_verb(0, "Send Digit %c\n", digit);
03231    }
03232    row = (digit - '1') % 3;
03233    col = (digit - '1' - row) / 3;
03234    if (digit >= '1' && digit <='9') {
03235       send_tone(pte, dtmf_row[row], dtmf_col[col]);
03236    } else if (digit >= 'A' && digit <= 'D') {
03237       send_tone(pte, dtmf_row[digit-'A'], dtmf_col[3]);
03238    } else if (digit == '*') {
03239       send_tone(pte, dtmf_row[3], dtmf_col[0]);
03240    } else if (digit == '0') {
03241       send_tone(pte, dtmf_row[3], dtmf_col[1]);
03242    } else if (digit == '#') {
03243       send_tone(pte, dtmf_row[3], dtmf_col[2]);
03244    } else {
03245       send_tone(pte, 500, 2000);
03246    }
03247    usleep(150000);          /* XXX Less than perfect, blocking an important thread is not a good idea */
03248    send_tone(pte, 0, 0);
03249    return 0;
03250 }
03251 
03252 static void handle_key_fav(struct unistimsession *pte, char keycode)
03253 {
03254    int keynum = keycode - KEY_FAV0;
03255    struct unistim_subchannel *sub;
03256 
03257    sub = get_sub(pte->device, SUB_REAL);
03258 
03259    /* Make an action on selected favorite key */
03260    if (!pte->device->ssub[keynum]) { /* Key have no assigned call */
03261       send_favorite_selected(FAV_LINE_ICON, pte);
03262       if (is_key_line(pte->device, keynum)) {
03263          if (unistimdebug) {
03264             ast_verb(0, "Handle line w/o sub - dialpage\n");
03265          }
03266          pte->device->selected = keynum;
03267          sub_hold(pte, sub); /* Put active call on hold */
03268          send_stop_timer(pte);
03269          handle_dial_page(pte);
03270       } else if (is_key_favorite(pte->device, keynum)) {
03271          /* Put active call on hold in handle_call_outgoing function, after preparation and
03272           checking if lines available for calling */
03273          if (unistimdebug) {
03274             ast_verb(0, "Handle favorite w/o sub - dialing\n");
03275          }
03276          if ((pte->device->output == OUTPUT_HANDSET) &&
03277             (pte->device->receiver_state == STATE_ONHOOK)) {
03278             send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
03279          } else {
03280             send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
03281          }
03282          key_favorite(pte, keycode);
03283       }
03284    } else {
03285       sub = pte->device->ssub[keynum];
03286       /* Favicon have assigned sub, activate it and put current on hold */
03287       if (sub->subtype == SUB_REAL) {
03288          sub_hold(pte, sub);
03289          show_main_page(pte);
03290       } else if (sub->subtype == SUB_RING) {
03291          sub->softkey = keynum;
03292          handle_call_incoming(pte);
03293       } else if (sub->subtype == SUB_ONHOLD) {
03294          if (pte->state == STATE_DIALPAGE){
03295             send_tone(pte, 0, 0);
03296          }
03297          send_callerid_screen(pte, sub);
03298          sub_unhold(pte, sub);
03299          pte->state = STATE_CALL;
03300       }
03301    }
03302 }
03303 
03304 static void key_call(struct unistimsession *pte, char keycode)
03305 {
03306    struct unistim_subchannel *sub = get_sub(pte->device, SUB_REAL);
03307    struct unistim_subchannel *sub_3way = get_sub(pte->device, SUB_THREEWAY);
03308 
03309    if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
03310       if (keycode == KEY_SHARP) {
03311          keycode = '#';
03312       } else if (keycode == KEY_STAR) {
03313          keycode = '*';
03314       } else {
03315          keycode -= 0x10;
03316       }
03317       unistim_do_senddigit(pte, keycode);
03318       return;
03319    }
03320    switch (keycode) {
03321    case KEY_FUNC1:
03322       if (ast_channel_state(sub->owner) == AST_STATE_UP) {
03323          if (sub_3way) {
03324             close_call(pte);
03325          }
03326       }
03327       break;
03328    case KEY_FUNC2:
03329       if (sub_3way) {
03330          transfer_cancel_step2(pte);
03331       } else if (ast_channel_state(sub->owner) == AST_STATE_UP) {
03332          transfer_call_step1(pte);
03333       }
03334       break;
03335    case KEY_HANGUP:
03336    case KEY_FUNC4:
03337       if (!sub_3way) {
03338          close_call(pte);
03339       }
03340       break;
03341    case KEY_FAV0:
03342    case KEY_FAV1:
03343    case KEY_FAV2:
03344    case KEY_FAV3:
03345    case KEY_FAV4:
03346    case KEY_FAV5:
03347       handle_key_fav(pte, keycode);
03348       break;
03349    case KEY_HEADPHN:
03350       if (pte->device->output == OUTPUT_HEADPHONE) {
03351          send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
03352       } else {
03353          send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
03354       }
03355       break;
03356    case KEY_LOUDSPK:
03357       if (pte->device->output != OUTPUT_SPEAKER)
03358          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
03359       else
03360          send_select_output(pte, pte->device->previous_output, pte->device->volume,
03361                       MUTE_OFF);
03362       break;
03363    case KEY_MUTE:
03364       if (!sub || !sub->owner) {
03365          ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
03366          return;
03367       }
03368       if (!sub->moh) {
03369          if (pte->device->mute == MUTE_ON) {
03370             send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
03371          } else {
03372             send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON);
03373          }
03374          break;
03375       }
03376       break;
03377    case KEY_ONHOLD:
03378       if (!sub) {
03379          if(pte->device->ssub[pte->device->selected]) {
03380             sub_hold(pte, pte->device->ssub[pte->device->selected]);
03381          }
03382       } else {
03383          sub_hold(pte, sub);
03384       }
03385       break;
03386    }
03387    return;
03388 }
03389 
03390 static void key_ringing(struct unistimsession *pte, char keycode)
03391 {
03392    switch (keycode) {
03393    case KEY_FAV0:
03394    case KEY_FAV1:
03395    case KEY_FAV2:
03396    case KEY_FAV3:
03397    case KEY_FAV4:
03398    case KEY_FAV5:
03399       handle_key_fav(pte, keycode);
03400       break;
03401    case KEY_FUNC3:
03402       ignore_call(pte);
03403       break;
03404    case KEY_HANGUP:
03405    case KEY_FUNC4:
03406       discard_call(pte);
03407       break;
03408    case KEY_LOUDSPK:
03409       pte->device->output = OUTPUT_SPEAKER;
03410       handle_call_incoming(pte);
03411       break;
03412    case KEY_HEADPHN:
03413       pte->device->output = OUTPUT_HEADPHONE;
03414       handle_call_incoming(pte);
03415       break;
03416    case KEY_FUNC1:
03417       handle_call_incoming(pte);
03418       break;
03419    }
03420    return;
03421 }
03422 
03423 static void key_favorite(struct unistimsession *pte, char keycode)
03424 {
03425    int fav = keycode - KEY_FAV0;
03426    if (!is_key_favorite(pte->device, fav)) {
03427       ast_log(LOG_WARNING, "It's not a favorite key\n");
03428       return;
03429    }
03430    ast_copy_string(pte->device->phone_number, pte->device->softkeynumber[fav],
03431                sizeof(pte->device->phone_number));
03432    handle_call_outgoing(pte);
03433    return;
03434 }
03435 
03436 static void key_dial_page(struct unistimsession *pte, char keycode)
03437 {
03438    struct unistim_subchannel *sub = get_sub(pte->device, SUB_THREEWAY);
03439 
03440    pte->device->nextdial = 0;
03441    if (keycode == KEY_FUNC3) {
03442       if (pte->device->size_phone_number <= 1) {
03443          keycode = KEY_FUNC4;
03444       } else {
03445          pte->device->size_phone_number -= 2;
03446          keycode = pte->device->phone_number[pte->device->size_phone_number] + 0x10;
03447       }
03448    }
03449    if (keycode == KEY_SHARP && pte->device->sharp_dial == 1) {
03450       keycode = KEY_FUNC1;
03451    }
03452    if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
03453       int i = pte->device->size_phone_number;
03454 
03455       if (pte->device->size_phone_number == 0) {
03456          send_tone(pte, 0, 0);
03457       }
03458       if (keycode == KEY_SHARP) {
03459          keycode = '#';
03460       } else if (keycode == KEY_STAR) {
03461          keycode = '*';
03462       } else {
03463          keycode -= 0x10;
03464       }
03465       pte->device->phone_number[i] = keycode;
03466       pte->device->size_phone_number++;
03467       pte->device->phone_number[i + 1] = 0;
03468       show_phone_number(pte);
03469 
03470       if (ast_exists_extension(NULL, pte->device->context, pte->device->phone_number, 1, NULL) && 
03471          !ast_matchmore_extension(NULL, pte->device->context, pte->device->phone_number, 1, NULL)) {
03472           keycode = KEY_FUNC1;
03473       } else {
03474          if (pte->device->interdigit_timer) {
03475             pte->device->nextdial = get_tick_count() + pte->device->interdigit_timer;
03476          }
03477       }
03478    }
03479    if (keycode == KEY_FUNC4) {
03480       pte->device->size_phone_number = 0;
03481       show_phone_number(pte);
03482       return;
03483    }
03484 
03485    if (pte->device->call_forward[0] == -1) {
03486       if (keycode == KEY_FUNC1) {
03487          ast_copy_string(pte->device->call_forward, pte->device->phone_number,
03488                      sizeof(pte->device->call_forward));
03489          show_main_page(pte);
03490       } else if ((keycode == KEY_FUNC2) || (keycode == KEY_HANGUP)) {
03491          pte->device->call_forward[0] = '\0';
03492          send_led_update(pte, 0x08);
03493          send_led_update(pte, 0x10);
03494          show_main_page(pte);
03495       }
03496       return;
03497    }
03498    switch (keycode) {
03499    case KEY_FUNC2:
03500       if (ast_strlen_zero(pte->device->redial_number)) {
03501          break;
03502       }
03503       ast_copy_string(pte->device->phone_number, pte->device->redial_number,
03504                   sizeof(pte->device->phone_number));
03505    case KEY_FUNC1:
03506       handle_call_outgoing(pte);
03507       break;
03508    case KEY_HANGUP:
03509       if (sub && sub->owner) {
03510          struct ast_channel *bridgepeer = NULL;
03511 
03512          sub_stop_silence(pte, sub);
03513          send_tone(pte, 0, 0);
03514          if ((bridgepeer = ast_bridged_channel(sub->owner))) {
03515             ast_moh_stop(bridgepeer);
03516          }
03517          sub->moh = 0;
03518          sub->subtype = SUB_REAL;
03519          pte->state = STATE_CALL;
03520 
03521          send_text_status(pte, ustmtext("       Transf        Hangup", pte));
03522          send_callerid_screen(pte, sub);
03523       } else {
03524          send_led_update(pte, 0x08);
03525          send_led_update(pte, 0x10);
03526          show_main_page(pte);
03527                 }
03528       break;
03529    case KEY_FAV0:
03530    case KEY_FAV1:
03531    case KEY_FAV2:
03532    case KEY_FAV3:
03533    case KEY_FAV4:
03534    case KEY_FAV5:
03535       send_favorite_selected(FAV_LINE_ICON, pte);
03536       pte->device->selected = -1;
03537       handle_key_fav(pte, keycode);
03538       break;
03539    case KEY_LOUDSPK:
03540       if (pte->device->output == OUTPUT_SPEAKER) {
03541          if (pte->device->receiver_state == STATE_OFFHOOK) {
03542             send_select_output(pte, pte->device->previous_output, pte->device->volume,
03543                          MUTE_OFF);
03544          } else {
03545             show_main_page(pte);
03546          }
03547       } else {
03548          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
03549       }
03550       break;
03551    case KEY_HEADPHN:
03552       if (pte->device->output == OUTPUT_HEADPHONE) {
03553          if (pte->device->receiver_state == STATE_OFFHOOK) {
03554             send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
03555          } else {
03556             show_main_page(pte);
03557          }
03558       } else {
03559          send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
03560       }
03561       break;
03562    }
03563    return;
03564 }
03565 
03566 static void handle_select_option(struct unistimsession *pte)
03567 {
03568    char tmp[128];
03569 
03570    if (pte->state != STATE_SELECTOPTION) {
03571       pte->state = STATE_SELECTOPTION;
03572       pte->size_buff_entry = 1;
03573       pte->buff_entry[0] = 0; /* Position in menu */
03574    }
03575    snprintf(tmp, sizeof(tmp), "%d. %s", pte->buff_entry[0] + 1, ustmtext(options_menu[(int)pte->buff_entry[0]].label, pte));
03576    send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmp);
03577    send_text_status(pte, ustmtext("Select               Cancel", pte));
03578    return;
03579 }
03580 
03581 static void key_select_option(struct unistimsession *pte, char keycode)
03582 {
03583    switch (keycode) {
03584    case KEY_DOWN:
03585       pte->buff_entry[0]++;
03586       if (options_menu[(int)pte->buff_entry[0]].label == NULL) {
03587          pte->buff_entry[0]--;
03588       }
03589       break;
03590    case KEY_UP:
03591       if (pte->buff_entry[0] > 0) {
03592          pte->buff_entry[0]--;
03593       }
03594       break;
03595    case KEY_FUNC1:
03596       options_menu[(int)pte->buff_entry[0]].handle_option(pte);
03597       return;
03598    case KEY_HANGUP:
03599    case KEY_FUNC4:
03600       show_main_page(pte);
03601       return;
03602    }
03603 
03604    handle_select_option(pte);
03605    return;
03606 }
03607 
03608 #define SELECTCODEC_START_ENTRY_POS 15
03609 #define SELECTCODEC_MAX_LENGTH 2
03610 #define SELECTCODEC_MSG "Codec number : .."
03611 static void handle_select_codec(struct unistimsession *pte)
03612 {
03613    char buf[30], buf2[5];
03614 
03615    pte->state = STATE_SELECTCODEC;
03616    ast_copy_string(buf, ustmtext("Using codec", pte), sizeof(buf));
03617    snprintf(buf2, sizeof(buf2), " %d", pte->device->codec_number);
03618    strcat(buf, buf2);
03619    strcat(buf, " (G711u=0,");
03620 
03621    send_text(TEXT_LINE0, TEXT_NORMAL, pte, buf);
03622    send_text(TEXT_LINE1, TEXT_NORMAL, pte, "G723=4,G711a=8,G729A=18)");
03623    send_text(TEXT_LINE2, TEXT_INVERSE, pte, SELECTCODEC_MSG);
03624    send_blink_cursor(pte);
03625    send_cursor_pos(pte, TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS);
03626    pte->size_buff_entry = 0;
03627    send_text_status(pte, ustmtext("Select BackSp Erase  Cancel", pte));
03628    return;
03629 }
03630 
03631 static void key_select_codec(struct unistimsession *pte, char keycode)
03632 {
03633    if (keycode == KEY_FUNC2) {
03634       if (pte->size_buff_entry <= 1) {
03635          keycode = KEY_FUNC3;
03636       } else {
03637          pte->size_buff_entry -= 2;
03638          keycode = pte->buff_entry[pte->size_buff_entry] + 0x10;
03639       }
03640    }
03641    if ((keycode >= KEY_0) && (keycode <= KEY_9)) {
03642       char tmpbuf[] = SELECTCODEC_MSG;
03643       int i = 0;
03644 
03645       if (pte->size_buff_entry >= SELECTCODEC_MAX_LENGTH) {
03646          return;
03647       }
03648       while (i < pte->size_buff_entry) {
03649          tmpbuf[i + SELECTCODEC_START_ENTRY_POS] = pte->buff_entry[i];
03650          i++;
03651       }
03652       tmpbuf[i + SELECTCODEC_START_ENTRY_POS] = keycode - 0x10;
03653       pte->buff_entry[i] = keycode - 0x10;
03654       pte->size_buff_entry++;
03655       send_text(TEXT_LINE2, TEXT_INVERSE, pte, tmpbuf);
03656       send_blink_cursor(pte);
03657       send_cursor_pos(pte,
03658                  (unsigned char) (TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS + 1 + i));
03659       return;
03660    }
03661 
03662    switch (keycode) {
03663    case KEY_FUNC1:
03664       if (pte->size_buff_entry == 1) {
03665          pte->device->codec_number = pte->buff_entry[0] - 48;
03666       } else if (pte->size_buff_entry == 2) {
03667          pte->device->codec_number =
03668             ((pte->buff_entry[0] - 48) * 10) + (pte->buff_entry[1] - 48);
03669       }
03670       show_main_page(pte);
03671       break;
03672    case KEY_FUNC3:
03673       pte->size_buff_entry = 0;
03674       send_text(TEXT_LINE2, TEXT_INVERSE, pte, SELECTCODEC_MSG);
03675       send_blink_cursor(pte);
03676       send_cursor_pos(pte, TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS);
03677       break;
03678    case KEY_HANGUP:
03679    case KEY_FUNC4:
03680       show_main_page(pte);
03681       break;
03682    }
03683    return;
03684 }
03685 
03686 static int find_language(const char* lang)
03687 {
03688    int i = 0;
03689    while (options_languages[i].lang_short != NULL) {
03690       if(!strcmp(options_languages[i].lang_short, lang)) {
03691          return i;
03692       }
03693       i++;
03694    }
03695    return 0;
03696 }
03697 
03698 static void handle_select_language(struct unistimsession *pte)
03699 {
03700    char tmp_language[40];
03701    struct unistim_languages lang;
03702 
03703    if (pte->state != STATE_SELECTLANGUAGE) {
03704       pte->state = STATE_SELECTLANGUAGE;
03705       pte->size_buff_entry = 1;
03706       pte->buff_entry[0] = find_language(pte->device->language);
03707    }
03708    lang = options_languages[(int)pte->buff_entry[0]];
03709    ast_copy_string(tmp_language, pte->device->language, sizeof(tmp_language));
03710    ast_copy_string(pte->device->language, lang.lang_short, sizeof(pte->device->language));
03711    send_charset_update(pte, lang.encoding);
03712    send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext(lang.label, pte));
03713 
03714    ast_copy_string(pte->device->language, tmp_language, sizeof(pte->device->language));
03715    lang = options_languages[find_language(pte->device->language)];
03716    send_charset_update(pte, lang.encoding);
03717    send_text_status(pte, ustmtext("Select               Cancel", pte));
03718    return;
03719 }
03720 
03721 static void key_select_language(struct unistimsession *pte, char keycode)
03722 {
03723    switch (keycode) {
03724    case KEY_DOWN:
03725       pte->buff_entry[0]++;
03726       if (options_languages[(int)pte->buff_entry[0]].label == NULL) {
03727          pte->buff_entry[0]--;
03728       }
03729       break;
03730    case KEY_UP:
03731       if (pte->buff_entry[0] > 0) {
03732          pte->buff_entry[0]--;
03733       }
03734       break;
03735    case KEY_FUNC1:
03736       ast_copy_string(pte->device->language, options_languages[(int)pte->buff_entry[0]].lang_short, sizeof(pte->device->language));
03737       send_charset_update(pte, options_languages[(int)pte->buff_entry[0]].encoding);
03738       refresh_all_favorite(pte);
03739       show_main_page(pte);
03740       return;
03741    case KEY_HANGUP:
03742    case KEY_FUNC4:
03743       handle_select_option(pte);
03744       return;
03745    }
03746 
03747    handle_select_language(pte);
03748    return;
03749 }
03750 
03751 
03752 #define SELECTEXTENSION_START_ENTRY_POS 0
03753 #define SELECTEXTENSION_MAX_LENGTH 10
03754 #define SELECTEXTENSION_MSG ".........."
03755 static void show_extension_page(struct unistimsession *pte)
03756 {
03757    pte->state = STATE_EXTENSION;
03758 
03759    send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Please enter a Terminal", pte));
03760    send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Number (TN) :", pte));
03761    send_text(TEXT_LINE2, TEXT_NORMAL, pte, SELECTEXTENSION_MSG);
03762    send_blink_cursor(pte);
03763    send_cursor_pos(pte, TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS);
03764    send_text_status(pte, ustmtext("Enter  BackSpcErase", pte));
03765    pte->size_buff_entry = 0;
03766    return;
03767 }
03768 
03769 static void key_select_extension(struct unistimsession *pte, char keycode)
03770 {
03771    if (keycode == KEY_FUNC2) {
03772       if (pte->size_buff_entry <= 1) {
03773          keycode = KEY_FUNC3;
03774       } else {
03775          pte->size_buff_entry -= 2;
03776          keycode = pte->buff_entry[pte->size_buff_entry] + 0x10;
03777       }
03778    }
03779    if ((keycode >= KEY_0) && (keycode <= KEY_9)) {
03780       char tmpbuf[] = SELECTEXTENSION_MSG;
03781       int i = 0;
03782 
03783       if (pte->size_buff_entry >= SELECTEXTENSION_MAX_LENGTH) {
03784          return;
03785       }
03786       while (i < pte->size_buff_entry) {
03787          tmpbuf[i + SELECTEXTENSION_START_ENTRY_POS] = pte->buff_entry[i];
03788          i++;
03789       }
03790       tmpbuf[i + SELECTEXTENSION_START_ENTRY_POS] = keycode - 0x10;
03791       pte->buff_entry[i] = keycode - 0x10;
03792       pte->size_buff_entry++;
03793       send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
03794       send_blink_cursor(pte);
03795       send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS + 1 + i));
03796       return;
03797    }
03798 
03799    switch (keycode) {
03800    case KEY_FUNC1:
03801       if (pte->size_buff_entry < 1) {
03802          return;
03803       }
03804       if (autoprovisioning == AUTOPROVISIONING_TN) {
03805          struct unistim_device *d;
03806 
03807          /* First step : looking for this TN in our device list */
03808          ast_mutex_lock(&devicelock);
03809          d = devices;
03810          pte->buff_entry[pte->size_buff_entry] = '\0';
03811          while (d) {
03812             if (d->id[0] == 'T') {  /* It's a TN device ? */
03813                /* It's the TN we're looking for ? */
03814                if (!strcmp((d->id) + 1, pte->buff_entry)) {
03815                   pte->device = d;
03816                   d->session = pte;
03817                   d->codec_number = DEFAULT_CODEC;
03818                   d->missed_call = 0;
03819                   d->receiver_state = STATE_ONHOOK;
03820                   strcpy(d->id, pte->macaddr);
03821                   pte->device->extension_number[0] = 'T';
03822                   pte->device->extension = EXTENSION_TN;
03823                   ast_copy_string((pte->device->extension_number) + 1,
03824                               pte->buff_entry, pte->size_buff_entry + 1);
03825                   ast_mutex_unlock(&devicelock);
03826                   show_main_page(pte);
03827                   refresh_all_favorite(pte);
03828                   return;
03829                }
03830             }
03831             d = d->next;
03832          }
03833          ast_mutex_unlock(&devicelock);
03834          send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Invalid Terminal Number.", pte));
03835          send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Please try again :", pte));
03836          send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS +
03837                                  pte->size_buff_entry));
03838          send_blink_cursor(pte);
03839       } else {
03840          ast_copy_string(pte->device->extension_number, pte->buff_entry,
03841                      pte->size_buff_entry + 1);
03842          if (register_extension(pte)) {
03843             send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Invalid extension.", pte));
03844             send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("Please try again :", pte));
03845             send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 +
03846                                  SELECTEXTENSION_START_ENTRY_POS +
03847                                  pte->size_buff_entry));
03848             send_blink_cursor(pte);
03849          } else
03850             show_main_page(pte);
03851       }
03852       break;
03853    case KEY_FUNC3:
03854       pte->size_buff_entry = 0;
03855       send_text(TEXT_LINE2, TEXT_NORMAL, pte, SELECTEXTENSION_MSG);
03856       send_blink_cursor(pte);
03857       send_cursor_pos(pte, TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS);
03858       break;
03859    }
03860    return;
03861 }
03862 
03863 static void show_entry_history(struct unistimsession *pte, FILE ** f)
03864 {
03865    char line[TEXT_LENGTH_MAX + 1], status[STATUS_LENGTH_MAX + 1], func1[10], func2[10],
03866       func3[10];
03867 
03868    /* Display date/time and call status */
03869    if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
03870       display_last_error("Can't read history date entry");
03871       fclose(*f);
03872       return;
03873    }
03874    line[sizeof(line) - 1] = '\0';
03875    if (pte->device->height == 1) {
03876       if (pte->buff_entry[3] == 1) {
03877          send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03878       }
03879    } else {
03880       send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03881    }
03882    /* Display number */
03883    if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
03884       display_last_error("Can't read callerid entry");
03885       fclose(*f);
03886       return;
03887    }
03888    line[sizeof(line) - 1] = '\0';
03889    ast_copy_string(pte->device->lst_cid, line, sizeof(pte->device->lst_cid));
03890    ast_trim_blanks(pte->device->lst_cid);
03891    if (pte->device->height == 1) {
03892       if (pte->buff_entry[3] == 2) {
03893          send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03894       }
03895    } else {
03896       send_text(TEXT_LINE1, TEXT_NORMAL, pte, line);
03897    }
03898    /* Display name */
03899    if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
03900       display_last_error("Can't read callername entry");
03901       fclose(*f);
03902       return;
03903    }
03904    line[sizeof(line) - 1] = '\0';
03905    if (pte->device->height == 1) {
03906       if (pte->buff_entry[3] == 3) {
03907          send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03908       }
03909         } else {
03910                 send_text(TEXT_LINE2, TEXT_NORMAL, pte, line);
03911         }
03912    fclose(*f);
03913 
03914    snprintf(line, sizeof(line), "%s %03d/%03d", ustmtext("Call", pte), pte->buff_entry[2],
03915           pte->buff_entry[1]);
03916    send_texttitle(pte, line);
03917 
03918    if (pte->buff_entry[2] == 1) {
03919       ast_copy_string(func1, "       ", sizeof(func1));
03920    } else {
03921       ast_copy_string(func1, ustmtext("Prev   ", pte), sizeof(func1));
03922    }
03923    if (pte->buff_entry[2] >= pte->buff_entry[1]) {
03924       ast_copy_string(func2, "       ", sizeof(func2));
03925    } else {
03926       ast_copy_string(func2, ustmtext("Next   ", pte), sizeof(func2));
03927    }
03928    if (strlen(pte->device->lst_cid)) {
03929       ast_copy_string(func3, ustmtext("Redial ", pte), sizeof(func3));
03930    } else {
03931       ast_copy_string(func3, "       ", sizeof(func3));
03932    }
03933    snprintf(status, sizeof(status), "%s%s%s%s", func1, func2, func3, ustmtext("Cancel", pte));
03934    send_text_status(pte, status);
03935 }
03936 
03937 static char open_history(struct unistimsession *pte, char way, FILE ** f)
03938 {
03939    char tmp[AST_CONFIG_MAX_PATH];
03940    char count;
03941 
03942    snprintf(tmp, sizeof(tmp), "%s/%s/%s-%c.csv", ast_config_AST_LOG_DIR,
03943           USTM_LOG_DIR, pte->device->name, way);
03944    *f = fopen(tmp, "r");
03945    if (!*f) {
03946       display_last_error("Unable to open history file");
03947       return 0;
03948    }
03949    if (fread(&count, 1, 1, *f) != 1) {
03950       display_last_error("Unable to read history header - display.");
03951       fclose(*f);
03952       *f = NULL;
03953       return 0;
03954    }
03955    if (count > MAX_ENTRY_LOG) {
03956       ast_log(LOG_WARNING, "Invalid count in history header of %s (%d max %d)\n", tmp,
03957             count, MAX_ENTRY_LOG);
03958       fclose(*f);
03959       *f = NULL;
03960       return 0;
03961    }
03962    return count;
03963 }
03964 
03965 static void show_history(struct unistimsession *pte, char way)
03966 {
03967    FILE *f;
03968    char count;
03969 
03970    if (!pte->device) {
03971       return;
03972    }
03973    if (!pte->device->callhistory) {
03974       return;
03975    }
03976    count = open_history(pte, way, &f);
03977    if (!count) {
03978       return;
03979    }
03980    pte->buff_entry[0] = way;
03981    pte->buff_entry[1] = count;
03982    pte->buff_entry[2] = 1;
03983    pte->buff_entry[3] = 1;
03984    show_entry_history(pte, &f);
03985    pte->state = STATE_HISTORY;
03986 }
03987 
03988 static void show_main_page(struct unistimsession *pte)
03989 {
03990    char tmpbuf[TEXT_LENGTH_MAX + 1];
03991    const char *text;
03992 
03993    if ((pte->device->extension == EXTENSION_ASK) &&
03994       (ast_strlen_zero(pte->device->extension_number))) {
03995       show_extension_page(pte);
03996       return;
03997    }
03998 
03999    pte->state = STATE_MAINPAGE;
04000    send_led_update(pte, 0);
04001    pte->device->lastmsgssent = -1;
04002 
04003    send_tone(pte, 0, 0);
04004    send_stop_timer(pte); /* case of holding call */
04005    send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON_DISCRET);
04006    send_led_update(pte, 0x08);
04007    send_led_update(pte, 0x10);
04008 
04009    if (!ast_strlen_zero(pte->device->call_forward)) {
04010       if (pte->device->height == 1) {
04011          char tmp_field[100];
04012          snprintf(tmp_field, sizeof(tmp_field), "%s %s", ustmtext("Fwd to:", pte), pte->device->call_forward);
04013          send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmp_field);
04014       } else {
04015          send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Call forwarded to :", pte));
04016          send_text(TEXT_LINE1, TEXT_NORMAL, pte, pte->device->call_forward);
04017       }
04018       send_icon(TEXT_LINE0, FAV_ICON_REFLECT + FAV_BLINK_SLOW, pte);
04019       if (ast_strlen_zero(pte->device->redial_number)) {
04020          send_text_status(pte, ustmtext("Dial          NoFwd  ", pte));
04021       } else {
04022          send_text_status(pte, ustmtext("Dial   Redial NoFwd  ", pte));
04023       }
04024    } else {
04025       if ((pte->device->extension == EXTENSION_ASK) || (pte->device->extension == EXTENSION_TN)) {
04026          if (ast_strlen_zero(pte->device->redial_number)) {
04027             send_text_status(pte, ustmtext("Dial          Fwd    Unregis", pte));
04028          } else {
04029             send_text_status(pte, ustmtext("Dial   Redial Fwd    Unregis", pte));
04030          }
04031       } else {
04032          if (ast_strlen_zero(pte->device->redial_number)) {
04033             send_text_status(pte, ustmtext("Dial          Fwd    Pickup", pte));
04034          } else {
04035             send_text_status(pte, ustmtext("Dial   Redial Fwd    Pickup", pte));
04036          }
04037       }
04038       send_text(TEXT_LINE1, TEXT_NORMAL, pte, pte->device->maintext1);
04039       if (pte->device->missed_call == 0) {
04040          send_date_time2(pte);
04041          send_idle_clock(pte);
04042          if (strlen(pte->device->maintext0)) {
04043             send_text(TEXT_LINE0, TEXT_NORMAL, pte, pte->device->maintext0);
04044          }
04045       } else {
04046          if (pte->device->missed_call == 1) {
04047             text = ustmtext("unanswered call", pte);
04048          } else {
04049             text = ustmtext("unanswered calls", pte);
04050          }
04051          snprintf(tmpbuf, sizeof(tmpbuf), "%d %s", pte->device->missed_call, text);
04052          send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmpbuf);
04053          send_icon(TEXT_LINE0, FAV_ICON_CALL_CENTER + FAV_BLINK_SLOW, pte);
04054       }
04055    }
04056    if (pte->device->height > 1) {
04057       if (ast_strlen_zero(pte->device->maintext2)) {
04058          strcpy(tmpbuf, "IP : ");
04059          strcat(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr));
04060          send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
04061       } else {
04062          send_text(TEXT_LINE2, TEXT_NORMAL, pte, pte->device->maintext2);
04063       }
04064    }
04065 
04066    send_texttitle(pte, pte->device->titledefault);
04067    change_favorite_icon(pte, FAV_LINE_ICON);
04068 }
04069 
04070 static void key_main_page(struct unistimsession *pte, char keycode)
04071 {
04072    if (pte->device->missed_call) {
04073       send_icon(TEXT_LINE0, FAV_ICON_NONE, pte);
04074       pte->device->missed_call = 0;
04075    }
04076    if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
04077       handle_dial_page(pte);
04078       key_dial_page(pte, keycode);
04079       return;
04080    }
04081    switch (keycode) {
04082    case KEY_FUNC1:
04083       pte->device->selected = get_avail_softkey(pte, NULL);
04084       handle_dial_page(pte);
04085       break;
04086    case KEY_FUNC2:
04087       if (ast_strlen_zero(pte->device->redial_number)) {
04088          break;
04089       }
04090       if ((pte->device->output == OUTPUT_HANDSET) &&
04091          (pte->device->receiver_state == STATE_ONHOOK)) {
04092          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
04093       } else {
04094          send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
04095       }
04096       ast_copy_string(pte->device->phone_number, pte->device->redial_number,
04097                   sizeof(pte->device->phone_number));
04098       handle_call_outgoing(pte);
04099       break;
04100    case KEY_FUNC3:
04101       if (!ast_strlen_zero(pte->device->call_forward)) {
04102          /* Cancel call forwarding */
04103          memmove(pte->device->call_forward + 1, pte->device->call_forward,
04104                sizeof(pte->device->call_forward) - 1);
04105          pte->device->call_forward[0] = '\0';
04106          send_icon(TEXT_LINE0, FAV_ICON_NONE, pte);
04107          pte->device->output = OUTPUT_HANDSET;   /* Seems to be reseted somewhere */
04108          show_main_page(pte);
04109          break;
04110       }
04111       pte->device->call_forward[0] = -1;
04112       handle_dial_page(pte);
04113       break;
04114    case KEY_FUNC4:
04115       if (pte->device->extension == EXTENSION_ASK) {
04116          unregister_extension(pte);
04117          pte->device->extension_number[0] = '\0';
04118          show_extension_page(pte);
04119       } else if (pte->device->extension == EXTENSION_TN) {
04120          ast_mutex_lock(&devicelock);
04121          strcpy(pte->device->id, pte->device->extension_number);
04122          pte->buff_entry[0] = '\0';
04123          pte->size_buff_entry = 0;
04124          pte->device->session = NULL;
04125          pte->device = NULL;
04126          ast_mutex_unlock(&devicelock);
04127          show_extension_page(pte);
04128       } else { /* Pickup function */
04129          pte->device->selected = -1;
04130          ast_copy_string(pte->device->phone_number, ast_pickup_ext(),
04131                   sizeof(pte->device->phone_number));
04132          handle_call_outgoing(pte);
04133                 }
04134       break;
04135    case KEY_FAV0:
04136    case KEY_FAV1:
04137    case KEY_FAV2:
04138    case KEY_FAV3:
04139    case KEY_FAV4:
04140    case KEY_FAV5:
04141       handle_key_fav(pte, keycode);
04142       break;
04143    case KEY_CONF:
04144       handle_select_option(pte);
04145       break;
04146    case KEY_LOUDSPK:
04147       send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
04148       handle_dial_page(pte);
04149       break;
04150    case KEY_HEADPHN:
04151       send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
04152       handle_dial_page(pte);
04153       break;
04154    case KEY_SNDHIST:
04155       show_history(pte, 'o');
04156       break;
04157    case KEY_RCVHIST:
04158       show_history(pte, 'i');
04159       break;
04160    }
04161    return;
04162 }
04163 
04164 static void key_history(struct unistimsession *pte, char keycode)
04165 {
04166    FILE *f;
04167    char count;
04168    long offset;
04169    int flag = 0;
04170 
04171    switch (keycode) {
04172    case KEY_LEFT:
04173       if (pte->device->height == 1) {
04174          if (pte->buff_entry[3] <= 1) {
04175             return;
04176          }
04177          pte->buff_entry[3]--;
04178          flag = 1;
04179          break;
04180       }
04181    case KEY_UP:
04182    case KEY_FUNC1:
04183       if (pte->buff_entry[2] <= 1) {
04184          return;
04185       }
04186       pte->buff_entry[2]--;
04187       flag = 1;
04188       break;
04189    case KEY_RIGHT:
04190       if (pte->device->height == 1) {
04191          if (pte->buff_entry[3] == 3) {
04192             return;
04193          }
04194          pte->buff_entry[3]++;
04195          flag = 1;
04196          break;
04197       }
04198    case KEY_DOWN:
04199    case KEY_FUNC2:
04200       if (pte->buff_entry[2] >= pte->buff_entry[1]) {
04201          return;
04202       }
04203       pte->buff_entry[2]++;
04204       flag = 1;
04205       break;
04206    case KEY_FUNC3:
04207       if (ast_strlen_zero(pte->device->lst_cid)) {
04208          break;
04209       }
04210       ast_copy_string(pte->device->redial_number, pte->device->lst_cid,
04211                   sizeof(pte->device->redial_number));
04212       key_main_page(pte, KEY_FUNC2);
04213       break;
04214    case KEY_FUNC4:
04215    case KEY_HANGUP:
04216       show_main_page(pte);
04217       break;
04218    case KEY_SNDHIST:
04219       if (pte->buff_entry[0] == 'i') {
04220          show_history(pte, 'o');
04221       } else {
04222          show_main_page(pte);
04223       }
04224       break;
04225    case KEY_RCVHIST:
04226       if (pte->buff_entry[0] == 'i') {
04227          show_main_page(pte);
04228       } else {
04229          show_history(pte, 'i');
04230       }
04231       break;
04232    }
04233 
04234    if (flag) {
04235       count = open_history(pte, pte->buff_entry[0], &f);
04236       if (!count) {
04237          return;
04238       }
04239       offset = ((pte->buff_entry[2] - 1) * TEXT_LENGTH_MAX * 3);
04240       if (fseek(f, offset, SEEK_CUR)) {
04241          display_last_error("Unable to seek history entry.");
04242          fclose(f);
04243          return;
04244       }
04245       show_entry_history(pte, &f);
04246    }
04247 
04248    return;
04249 }
04250 
04251 static void init_phone_step2(struct unistimsession *pte)
04252 {
04253    BUFFSEND;
04254    if (unistimdebug) {
04255       ast_verb(0, "Sending S4\n");
04256    }
04257    memcpy(buffsend + SIZE_HEADER, packet_send_s4, sizeof(packet_send_s4));
04258    send_client(SIZE_HEADER + sizeof(packet_send_s4), buffsend, pte);
04259    send_date_time2(pte);
04260    send_date_time3(pte);
04261    if (unistimdebug) {
04262       ast_verb(0, "Sending S7\n");
04263    }
04264    memcpy(buffsend + SIZE_HEADER, packet_send_S7, sizeof(packet_send_S7));
04265    send_client(SIZE_HEADER + sizeof(packet_send_S7), buffsend, pte);
04266    if (unistimdebug) {
04267       ast_verb(0, "Sending Contrast\n");
04268    }
04269    memcpy(buffsend + SIZE_HEADER, packet_send_Contrast, sizeof(packet_send_Contrast));
04270    if (pte->device != NULL) {
04271       buffsend[9] = pte->device->contrast;
04272    }
04273    send_client(SIZE_HEADER + sizeof(packet_send_Contrast), buffsend, pte);
04274 
04275    if (unistimdebug) {
04276       ast_verb(0, "Sending S9\n");
04277    }
04278    memcpy(buffsend + SIZE_HEADER, packet_send_s9, sizeof(packet_send_s9));
04279    send_client(SIZE_HEADER + sizeof(packet_send_s9), buffsend, pte);
04280    send_no_ring(pte);
04281 
04282    if (unistimdebug) {
04283       ast_verb(0, "Sending S7\n");
04284    }
04285    memcpy(buffsend + SIZE_HEADER, packet_send_S7, sizeof(packet_send_S7));
04286    send_client(SIZE_HEADER + sizeof(packet_send_S7), buffsend, pte);
04287    send_led_update(pte, 0);
04288    send_ping(pte);
04289    if (unistimdebug) {
04290       ast_verb(0, "Sending init language\n");
04291    }
04292    if (pte->device) {
04293       send_charset_update(pte, options_languages[find_language(pte->device->language)].encoding);
04294    }
04295    if (pte->state < STATE_MAINPAGE) {
04296       if (autoprovisioning == AUTOPROVISIONING_TN) {
04297          show_extension_page(pte);
04298          return;
04299       } else {
04300          int i;
04301          char tmp[30];
04302 
04303          for (i = 1; i < FAVNUM; i++) {
04304             send_favorite(i, 0, pte, "");
04305          }
04306          send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Phone is not registered", pte));
04307          send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext("in unistim.conf", pte));
04308          strcpy(tmp, "MAC = ");
04309          strcat(tmp, pte->macaddr);
04310          send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
04311          send_text_status(pte, "");
04312          send_texttitle(pte, "UNISTIM for*");
04313          return;
04314       }
04315    }
04316    show_main_page(pte);
04317    refresh_all_favorite(pte);
04318    if (unistimdebug) {
04319       ast_verb(0, "Sending arrow\n");
04320    }
04321    memcpy(buffsend + SIZE_HEADER, packet_send_arrow, sizeof(packet_send_arrow));
04322    send_client(SIZE_HEADER + sizeof(packet_send_arrow), buffsend, pte);
04323    return;
04324 }
04325 
04326 static void process_request(int size, unsigned char *buf, struct unistimsession *pte)
04327 {
04328    char tmpbuf[255];
04329    if (memcmp
04330       (buf + SIZE_HEADER, packet_recv_resume_connection_with_server,
04331        sizeof(packet_recv_resume_connection_with_server)) == 0) {
04332       rcv_resume_connection_with_server(pte);
04333       return;
04334    }
04335    if (memcmp(buf + SIZE_HEADER, packet_recv_firm_version, sizeof(packet_recv_firm_version)) == 0) {
04336       buf[size] = 0;
04337       if (unistimdebug) {
04338          ast_verb(0, "Got the firmware version : '%s'\n", buf + 13);
04339       }
04340       init_phone_step2(pte);
04341       return;
04342    }
04343    if (memcmp(buf + SIZE_HEADER, packet_recv_it_type, sizeof(packet_recv_it_type)) == 0) {
04344       char type = buf[13];
04345       if (unistimdebug) {
04346          ast_verb(0, "Got the equipment type: '%d'\n", type);
04347       }
04348       switch (type) {
04349       case 0x03: /* i2002 */
04350          if (pte->device) {
04351             pte->device->height = 1;
04352          }
04353          break;
04354       }
04355       return;
04356    }
04357    if (memcmp(buf + SIZE_HEADER, packet_recv_mac_addr, sizeof(packet_recv_mac_addr)) == 0) {
04358       rcv_mac_addr(pte, buf);
04359       return;
04360    }
04361    if (memcmp(buf + SIZE_HEADER, packet_recv_r2, sizeof(packet_recv_r2)) == 0) {
04362       if (unistimdebug) {
04363          ast_verb(0, "R2 received\n");
04364       }
04365       return;
04366    }
04367 
04368    if (pte->state < STATE_MAINPAGE) {
04369       if (unistimdebug) {
04370          ast_verb(0, "Request not authorized in this state\n");
04371       }
04372       return;
04373    }
04374    if (!memcmp(buf + SIZE_HEADER, packet_recv_pressed_key, sizeof(packet_recv_pressed_key))) {
04375       char keycode = buf[13];
04376 
04377       if (unistimdebug) {
04378          ast_verb(0, "Key pressed: keycode = 0x%.2x - current state: %s\n", (unsigned)keycode,
04379                   ptestate_tostr(pte->state));
04380       }
04381       switch (pte->state) {
04382       case STATE_INIT:
04383          if (unistimdebug) {
04384             ast_verb(0, "No keys allowed in the init state\n");
04385          }
04386          break;
04387       case STATE_AUTHDENY:
04388          if (unistimdebug) {
04389             ast_verb(0, "No keys allowed in authdeny state\n");
04390          }
04391          break;
04392       case STATE_MAINPAGE:
04393          key_main_page(pte, keycode);
04394          break;
04395       case STATE_DIALPAGE:
04396          key_dial_page(pte, keycode);
04397          break;
04398       case STATE_RINGING:
04399          key_ringing(pte, keycode);
04400          break;
04401       case STATE_CALL:
04402          key_call(pte, keycode);
04403          break;
04404       case STATE_EXTENSION:
04405          key_select_extension(pte, keycode);
04406          break;
04407       case STATE_SELECTOPTION:
04408          key_select_option(pte, keycode);
04409          break;
04410       case STATE_SELECTCODEC:
04411          key_select_codec(pte, keycode);
04412          break;
04413       case STATE_SELECTLANGUAGE:
04414          key_select_language(pte, keycode);
04415          break;
04416       case STATE_HISTORY:
04417          key_history(pte, keycode);
04418          break;
04419       default:
04420          ast_log(LOG_WARNING, "Key : Unknown state\n");
04421       }
04422       return;
04423    }
04424    if (memcmp(buf + SIZE_HEADER, packet_recv_pick_up, sizeof(packet_recv_pick_up)) == 0) {
04425       if (unistimdebug) {
04426          ast_verb(0, "Handset off hook, current state: %s\n", ptestate_tostr(pte->state));
04427       }
04428       if (!pte->device) {         /* We are not yet registered (asking for a TN in AUTOPROVISIONING_TN) */
04429          return;
04430       }
04431       pte->device->receiver_state = STATE_OFFHOOK;
04432       if (pte->device->output == OUTPUT_HEADPHONE) {
04433          send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
04434       } else {
04435          send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
04436       }
04437       if (pte->state == STATE_RINGING) {
04438          handle_call_incoming(pte);
04439       } else if ((pte->state == STATE_DIALPAGE) || (pte->state == STATE_CALL)) {
04440          send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
04441       } else if (pte->state == STATE_EXTENSION) { /* We must have a TN before calling */
04442          return;
04443       } else {
04444          pte->device->selected = get_avail_softkey(pte, NULL);
04445          send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
04446          handle_dial_page(pte);
04447       }
04448       return;
04449    }
04450    if (memcmp(buf + SIZE_HEADER, packet_recv_hangup, sizeof(packet_recv_hangup)) == 0) {
04451       if (unistimdebug) {
04452          ast_verb(0, "Handset on hook, current state: %s\n", ptestate_tostr(pte->state));
04453       }
04454       if (!pte->device) {
04455          return;
04456       }
04457       pte->device->receiver_state = STATE_ONHOOK;
04458       if (pte->state == STATE_CALL) {
04459          if (pte->device->output != OUTPUT_SPEAKER) {
04460             close_call(pte);
04461          }
04462       } else if (pte->state == STATE_EXTENSION) {
04463          return;
04464       } else {
04465          pte->device->nextdial = 0;
04466          show_main_page(pte);
04467       }
04468       return;
04469    }
04470    strcpy(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr));
04471    strcat(tmpbuf, " Unknown request packet\n");
04472    if (unistimdebug) {
04473       ast_debug(1, "%s", tmpbuf);
04474    }
04475    return;
04476 }
04477 
04478 static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
04479    struct sockaddr_in *addr_from)
04480 {
04481    unsigned short *sbuf = (unsigned short *) buf;
04482    unsigned short seq;
04483    char tmpbuf[255];
04484 
04485    strcpy(tmpbuf, ast_inet_ntoa(addr_from->sin_addr));
04486 
04487    if (size < 10) {
04488       if (size == 0) {
04489          ast_log(LOG_WARNING, "%s Read error\n", tmpbuf);
04490       } else {
04491          ast_log(LOG_NOTICE, "%s Packet too short - ignoring\n", tmpbuf);
04492       }
04493       return;
04494    }
04495    if (sbuf[0] == 0xffff) {   /* Starting with 0xffff ? *//* Yes, discovery packet ? */
04496       if (size != sizeof(packet_rcv_discovery)) {
04497          ast_log(LOG_NOTICE, "%s Invalid size of a discovery packet\n", tmpbuf);
04498       } else {
04499          if (memcmp(buf, packet_rcv_discovery, sizeof(packet_rcv_discovery)) == 0) {
04500             if (unistimdebug) {
04501                ast_verb(0, "Discovery packet received - Sending Discovery ACK\n");
04502             }
04503             if (pte) {        /* A session was already active for this IP ? */
04504                if (pte->state == STATE_INIT) { /* Yes, but it's a dupe */
04505                   if (unistimdebug) {
04506                      ast_verb(1, "Duplicated Discovery packet\n");
04507                   }
04508                   send_raw_client(sizeof(packet_send_discovery_ack),
04509                              packet_send_discovery_ack, addr_from, &pte->sout);
04510                   pte->seq_phone = (short) 0x0000; /* reset sequence number */
04511                } else { /* No, probably a reboot, phone side */
04512                   close_client(pte);       /* Cleanup the previous session */
04513                   if (create_client(addr_from)) {
04514                      send_raw_client(sizeof(packet_send_discovery_ack),
04515                                 packet_send_discovery_ack, addr_from, &pte->sout);
04516                   }
04517                }
04518             } else {
04519                /* Creating new entry in our phone list */
04520                if ((pte = create_client(addr_from))) {
04521                   send_raw_client(sizeof(packet_send_discovery_ack),
04522                              packet_send_discovery_ack, addr_from, &pte->sout);
04523                }
04524             }
04525             return;
04526          }
04527          ast_log(LOG_NOTICE, "%s Invalid discovery packet\n", tmpbuf);
04528       }
04529       return;
04530    }
04531    if (!pte) {
04532       if (unistimdebug) {
04533          ast_verb(0, "%s Not a discovery packet from an unknown source : ignoring\n", tmpbuf);
04534       }
04535       return;
04536    }
04537 
04538    if (sbuf[0] != 0) {          /* Starting with something else than 0x0000 ? */
04539       ast_log(LOG_NOTICE, "Unknown packet received - ignoring\n");
04540       return;
04541    }
04542    if (buf[5] != 2) {
04543       ast_log(LOG_NOTICE, "%s Wrong direction : got 0x%.2x expected 0x02\n", tmpbuf,
04544             (unsigned)buf[5]);
04545       return;
04546    }
04547    seq = ntohs(sbuf[1]);
04548    if (buf[4] == 1) {
04549       ast_mutex_lock(&pte->lock);
04550       if (unistimdebug) {
04551          ast_verb(6, "ACK received for packet #0x%.4x\n", (unsigned)seq);
04552       }
04553       pte->nb_retransmit = 0;
04554 
04555       if ((pte->last_seq_ack) + 1 == seq) {
04556          pte->last_seq_ack++;
04557          check_send_queue(pte);
04558          ast_mutex_unlock(&pte->lock);
04559          return;
04560       }
04561       if (pte->last_seq_ack > seq) {
04562          if (pte->last_seq_ack == 0xffff) {
04563             ast_verb(0, "ACK at 0xffff, restarting counter.\n");
04564             pte->last_seq_ack = 0;
04565          } else {
04566             ast_log(LOG_NOTICE,
04567                   "%s Warning : ACK received for an already ACKed packet : #0x%.4x we are at #0x%.4x\n",
04568                   tmpbuf, (unsigned)seq, (unsigned)pte->last_seq_ack);
04569          }
04570          ast_mutex_unlock(&pte->lock);
04571          return;
04572       }
04573       if (pte->seq_server < seq) {
04574          ast_log(LOG_NOTICE,
04575                "%s Error : ACK received for a non-existent packet : #0x%.4x\n",
04576                tmpbuf, (unsigned)pte->seq_server);
04577          ast_mutex_unlock(&pte->lock);
04578          return;
04579       }
04580       if (unistimdebug) {
04581          ast_verb(0, "%s ACK gap : Received ACK #0x%.4x, previous was #0x%.4x\n",
04582                   tmpbuf, (unsigned)seq, (unsigned)pte->last_seq_ack);
04583       }
04584       pte->last_seq_ack = seq;
04585       check_send_queue(pte);
04586       ast_mutex_unlock(&pte->lock);
04587       return;
04588    }
04589    if (buf[4] == 2) {
04590       if (unistimdebug) {
04591          ast_verb(0, "Request received\n");
04592       }
04593       if (pte->seq_phone == seq) {
04594          /* Send ACK */
04595          buf[4] = 1;
04596          buf[5] = 1;
04597          send_raw_client(SIZE_HEADER, buf, addr_from, &pte->sout);
04598          pte->seq_phone++;
04599 
04600          process_request(size, buf, pte);
04601          return;
04602       }
04603       if (pte->seq_phone > seq) {
04604          ast_log(LOG_NOTICE,
04605                "%s Warning : received a retransmitted packet : #0x%.4x (we are at #0x%.4x)\n",
04606                tmpbuf, (unsigned)seq, (unsigned)pte->seq_phone);
04607          /* BUG ? pte->device->seq_phone = seq; */
04608          /* Send ACK */
04609          buf[4] = 1;
04610          buf[5] = 1;
04611          send_raw_client(SIZE_HEADER, buf, addr_from, &pte->sout);
04612          return;
04613       }
04614       ast_log(LOG_NOTICE,
04615             "%s Warning : we lost a packet : received #0x%.4x (we are at #0x%.4x)\n",
04616             tmpbuf, (unsigned)seq, (unsigned)pte->seq_phone);
04617       return;
04618    }
04619    if (buf[4] == 0) {
04620       ast_log(LOG_NOTICE, "%s Retransmit request for packet #0x%.4x\n", tmpbuf, (unsigned)seq);
04621       if (pte->last_seq_ack > seq) {
04622          ast_log(LOG_NOTICE,
04623                "%s Error : received a request for an already ACKed packet : #0x%.4x\n",
04624                tmpbuf, (unsigned)pte->last_seq_ack);
04625          return;
04626       }
04627       if (pte->seq_server < seq) {
04628          ast_log(LOG_NOTICE,
04629                "%s Error : received a request for a non-existent packet : #0x%.4x\n",
04630                tmpbuf, (unsigned)pte->seq_server);
04631          return;
04632       }
04633       send_retransmit(pte);
04634       return;
04635    }
04636    ast_log(LOG_NOTICE, "%s Unknown request : got 0x%.2x expected 0x00,0x01 or 0x02\n",
04637          tmpbuf, (unsigned)buf[4]);
04638    return;
04639 }
04640 
04641 static struct unistimsession *channel_to_session(struct ast_channel *ast)
04642 {
04643    struct unistim_subchannel *sub;
04644    if (!ast) {
04645       ast_log(LOG_WARNING, "Unistim callback function called with a null channel\n");
04646       return NULL;
04647    }
04648    if (!ast_channel_tech_pvt(ast)) {
04649       ast_log(LOG_WARNING, "Unistim callback function called without a tech_pvt\n");
04650       return NULL;
04651    }
04652    sub = ast_channel_tech_pvt(ast);
04653 
04654    if (!sub->parent) {
04655       ast_log(LOG_WARNING, "Unistim callback function called without a line\n");
04656       return NULL;
04657    }
04658    if (!sub->parent->parent) {
04659       ast_log(LOG_WARNING, "Unistim callback function called without a device\n");
04660       return NULL;
04661    }
04662    ast_mutex_lock(&sub->parent->parent->lock);
04663    if (!sub->parent->parent->session) {
04664       ast_log(LOG_WARNING, "Unistim callback function called without a session\n");
04665       ast_mutex_unlock(&sub->parent->parent->lock);
04666       return NULL;
04667    }
04668    ast_mutex_unlock(&sub->parent->parent->lock);
04669    return sub->parent->parent->session;
04670 }
04671 
04672 static void send_callerid_screen(struct unistimsession *pte, struct unistim_subchannel *sub)
04673 {
04674    char *cidname_str;
04675    char *cidnum_str;
04676 
04677    if (!sub) {
04678       return;
04679    }
04680    if (sub->owner) {
04681       if (ast_channel_connected(sub->owner)->id.number.valid && ast_channel_connected(sub->owner)->id.number.str) {
04682          cidnum_str = ast_channel_connected(sub->owner)->id.number.str;
04683       } else {
04684          cidnum_str = DEFAULTCALLERID;
04685       }
04686       change_callerid(pte, 0, cidnum_str);
04687       if (strlen(cidnum_str) == 0) {
04688          cidnum_str = DEFAULTCALLERID;
04689       }
04690 
04691       if (ast_channel_connected(sub->owner)->id.name.valid && ast_channel_connected(sub->owner)->id.name.str) {
04692          cidname_str = ast_channel_connected(sub->owner)->id.name.str;
04693       } else {
04694          cidname_str = DEFAULTCALLERNAME;
04695       }
04696       change_callerid(pte, 1, cidname_str);
04697       if (strlen(cidname_str) == 0) {
04698          cidname_str = DEFAULTCALLERNAME;
04699       }
04700 
04701       if (pte->device->height == 1) {
04702          char tmpstr[256];
04703          snprintf(tmpstr, sizeof(tmpstr), "%s %s", cidnum_str, ustmtext(cidname_str, pte));
04704          send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmpstr);
04705       } else {
04706          send_text(TEXT_LINE0, TEXT_NORMAL, pte, cidname_str);
04707          send_text(TEXT_LINE1, TEXT_NORMAL, pte, ustmtext(cidnum_str, pte));
04708       }
04709    }
04710 }
04711 
04712 /*--- unistim_call: Initiate UNISTIM call from PBX ---*/
04713 /*      used from the dial() application      */
04714 static int unistim_call(struct ast_channel *ast, const char *dest, int timeout)
04715 {
04716    int res = 0, i;
04717    struct unistim_subchannel *sub, *sub_real;
04718    struct unistimsession *session;
04719    char ringstyle, ringvolume;
04720 
04721    session = channel_to_session(ast);
04722    if (!session) {
04723       ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
04724       return -1;
04725    }
04726    sub = ast_channel_tech_pvt(ast);
04727    sub_real = get_sub(session->device, SUB_REAL);
04728    if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
04729       ast_log(LOG_WARNING, "unistim_call called on %s, neither down nor reserved\n",
04730             ast_channel_name(ast));
04731       return -1;
04732    }
04733 
04734    if (unistimdebug) {
04735       ast_verb(3, "unistim_call(%s)\n", ast_channel_name(ast));
04736    }
04737    session->state = STATE_RINGING;
04738    send_callerid_screen(session, sub);
04739    if (ast_strlen_zero(ast_channel_call_forward(ast))) { /* Send ring only if no call forward, otherwise short ring will apear */
04740       send_text(TEXT_LINE2, TEXT_NORMAL, session, ustmtext("is calling you.", session));
04741       send_text_status(session, ustmtext("Accept        Ignore Hangup", session));
04742 
04743       if (sub_real) {
04744          ringstyle = session->device->cwstyle;
04745          ringvolume = session->device->cwvolume;
04746       } else {
04747          ringstyle = (sub->ringstyle == -1) ? session->device->ringstyle : sub->ringstyle;
04748          ringvolume = (sub->ringvolume == -1) ? session->device->ringvolume : sub->ringvolume;
04749       }
04750       send_ring(session, ringvolume, ringstyle);
04751       change_favorite_icon(session, FAV_ICON_SPEAKER_ONHOOK_BLACK + FAV_BLINK_FAST);
04752       /* Send call identification to all */
04753       for (i = 0; i < FAVNUM; i++) {
04754          if (!soft_key_visible(session->device, i)) {
04755             continue;
04756          }
04757          if (session->device->ssub[i]) {
04758             continue;
04759          }
04760          if (is_key_line(session->device, i) && !strcmp(sub->parent->name, session->device->sline[i]->name)) {
04761             if (unistimdebug) {
04762                ast_verb(0, "Found softkey %d for line %s\n", i, sub->parent->name);
04763             }
04764             send_favorite_short(i, FAV_ICON_SPEAKER_ONHOOK_BLACK + FAV_BLINK_FAST, session);
04765             session->device->ssub[i] = sub;
04766          }
04767       }
04768    }
04769    ast_setstate(ast, AST_STATE_RINGING);
04770    ast_queue_control(ast, AST_CONTROL_RINGING);
04771    return res;
04772 }
04773 
04774 static int unistim_hangup_clean(struct ast_channel *ast, struct unistim_subchannel *sub) {
04775    ast_mutex_lock(&sub->lock);
04776    ast_channel_tech_pvt_set(ast, NULL);
04777    sub->owner = NULL;
04778    sub->alreadygone = 0;
04779    ast_mutex_unlock(&sub->lock);
04780    if (sub->rtp) {
04781       if (unistimdebug) {
04782          ast_verb(0, "Destroying RTP session\n");
04783       }
04784       ast_rtp_instance_destroy(sub->rtp);
04785       sub->rtp = NULL;
04786    }
04787    return 0;
04788 }
04789 
04790 /*--- unistim_hangup: Hangup UNISTIM call */
04791 static int unistim_hangup(struct ast_channel *ast)
04792 {
04793    struct unistim_subchannel *sub = NULL, *sub_real = NULL, *sub_trans = NULL;
04794    struct unistim_line *l;
04795    struct unistim_device *d;
04796    struct unistimsession *s;
04797    int i,end_call = 1;
04798 
04799    s = channel_to_session(ast);
04800    sub = ast_channel_tech_pvt(ast);
04801    l = sub->parent;
04802    d = l->parent;
04803    if (!s) {
04804       ast_debug(1, "Asked to hangup channel not connected\n");
04805       unistim_hangup_clean(ast, sub);
04806       return 0;
04807    }
04808    if (unistimdebug) {
04809       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));
04810    }
04811    sub_trans = get_sub(d, SUB_THREEWAY);
04812    sub_real = get_sub(d, SUB_REAL);
04813    if (sub_trans && (sub_trans->owner) && (sub->subtype == SUB_REAL)) { /* 3rd party busy or congested and transfer_cancel_step2 does not called */
04814       if (unistimdebug) {
04815          ast_verb(0, "Threeway call disconnected, switching to real call\n");
04816       }
04817       if (ast_bridged_channel(sub_trans->owner)) {
04818          ast_moh_stop(ast_bridged_channel(sub_trans->owner));
04819       }
04820       sub_trans->moh = 0;
04821       sub_trans->subtype = SUB_REAL;
04822       swap_subs(sub_trans, sub);
04823       send_text_status(s, ustmtext("       Transf        Hangup", s));
04824       send_callerid_screen(s, sub_trans);
04825       unistim_hangup_clean(ast, sub);
04826       unistim_unalloc_sub(d, sub);
04827       return 0;
04828    }
04829    if (sub_real && (sub_real->owner) && (sub->subtype == SUB_THREEWAY) && (s->state == STATE_CALL)) { /* 3way call cancelled by softkey pressed */
04830       if (unistimdebug) {
04831          ast_verb(0, "Real call disconnected, stay in call\n");
04832       }
04833       send_text_status(s, ustmtext("       Transf        Hangup", s));
04834       send_callerid_screen(s, sub_real);
04835       unistim_hangup_clean(ast, sub);
04836       unistim_unalloc_sub(d, sub);
04837       return 0;
04838    }
04839    if (sub->subtype == SUB_REAL) {
04840       sub_stop_silence(s, sub);
04841    } else if (sub->subtype == SUB_RING) {
04842       send_no_ring(s);
04843       for (i = 0; i < FAVNUM; i++) {
04844          if (!soft_key_visible(s->device, i))
04845             continue;
04846          if (d->ssub[i] != sub)
04847             continue;
04848          if (is_key_line(d, i) && !strcmp(l->name, d->sline[i]->name)) {
04849             send_favorite_short(i, FAV_LINE_ICON, s);
04850             d->ssub[i] = NULL;
04851             continue;
04852          }
04853          if (d->ssub[i] != NULL) { /* Found other subchannel active other then hangup'ed one */
04854             end_call = 0;
04855          }
04856       }
04857    }
04858    if (end_call) {
04859       send_end_call(s); /* Send end call packet only if ending active call, in other way sound should be loosed */
04860    }
04861    sub->moh = 0;
04862    if (sub->softkey >= 0) {
04863       send_favorite_short(sub->softkey, FAV_LINE_ICON, s);
04864    }
04865    /* Delete assign sub to softkey */
04866    for (i = 0; i < FAVNUM; i++) {
04867       if (d->ssub[i] == sub) {
04868          d->ssub[i] = NULL;
04869          break;
04870       }
04871    }
04872    /*refresh_all_favorite(s); */ /* TODO: Update favicons in case of DND keys */
04873    if (s->state == STATE_RINGING && sub->subtype == SUB_RING) {
04874       send_no_ring(s);
04875       if (ast_channel_hangupcause(ast) != AST_CAUSE_ANSWERED_ELSEWHERE) {
04876          d->missed_call++;
04877          write_history(s, 'i', 1);
04878       }
04879       if (!sub_real) {
04880          show_main_page(s);
04881       } else { /* hangup on a ringing line: reset status to reflect that we're still on an active call */
04882             s->state = STATE_CALL;
04883             send_callerid_screen(s, sub_real);
04884             send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("is on-line", s));
04885             send_text_status(s, ustmtext("       Transf        Hangup", s));
04886             send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, s);
04887          
04888       }
04889    }
04890    if (s->state == STATE_CALL && sub->subtype == SUB_REAL) {
04891       close_call(s);
04892    }
04893    sub->softkey = -1;
04894    unistim_hangup_clean(ast, sub);
04895    unistim_unalloc_sub(d, sub);
04896    return 0;
04897 }
04898 
04899 /*--- unistim_answer: Answer UNISTIM call */
04900 static int unistim_answer(struct ast_channel *ast)
04901 {
04902    int res = 0;
04903    struct unistim_subchannel *sub;
04904    struct unistim_line *l;
04905    struct unistim_device *d;
04906    struct unistimsession *s;
04907 
04908    s = channel_to_session(ast);
04909    if (!s) {
04910       ast_log(LOG_WARNING, "unistim_answer on a disconnected device ?\n");
04911       return -1;
04912    }
04913    sub = ast_channel_tech_pvt(ast);
04914    l = sub->parent;
04915    d = l->parent;
04916 
04917    if (unistimdebug) {
04918       ast_verb(0, "unistim_answer(%s) on %s@%s-%d\n", ast_channel_name(ast), l->name,
04919                l->parent->name, sub->softkey);
04920    }
04921    send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("is now on-line", s));
04922    if (get_sub(d, SUB_THREEWAY)) {
04923       send_text_status(s, ustmtext("Transf Cancel", s));
04924    } else {
04925       send_text_status(s, ustmtext("       Transf        Hangup", s));
04926    }
04927    send_start_timer(s);
04928    if (ast_channel_state(ast) != AST_STATE_UP)
04929       ast_setstate(ast, AST_STATE_UP);
04930    return res;
04931 }
04932 
04933 /*--- unistimsock_read: Read data from UNISTIM socket ---*/
04934 /*    Successful messages is connected to UNISTIM call and forwarded to parsing() */
04935 static int unistimsock_read(int *id, int fd, short events, void *ignore)
04936 {
04937    struct sockaddr_in addr_from = { 0, };
04938    struct unistimsession *cur = NULL;
04939    int found = 0;
04940    int tmp = 0;
04941    int dw_num_bytes_rcvd;
04942    unsigned int size_addr_from;
04943 #ifdef DUMP_PACKET
04944    int dw_num_bytes_rcvdd;
04945 #endif
04946 
04947    size_addr_from = sizeof(addr_from);
04948    dw_num_bytes_rcvd =
04949       recvfrom(unistimsock, buff, SIZE_PAGE, 0, (struct sockaddr *) &addr_from,
04950              &size_addr_from);
04951    if (dw_num_bytes_rcvd == -1) {
04952       if (errno == EAGAIN) {
04953          ast_log(LOG_NOTICE, "UNISTIM: Received packet with bad UDP checksum\n");
04954       } else if (errno != ECONNREFUSED) {
04955          ast_log(LOG_WARNING, "Recv error %d (%s)\n", errno, strerror(errno));
04956       }
04957       return 1;
04958    }
04959 
04960    /* Looking in the phone list if we already have a registration for him */
04961    ast_mutex_lock(&sessionlock);
04962    cur = sessions;
04963    while (cur) {
04964       if (cur->sin.sin_addr.s_addr == addr_from.sin_addr.s_addr) {
04965          found = 1;
04966          break;
04967       }
04968       tmp++;
04969       cur = cur->next;
04970    }
04971    ast_mutex_unlock(&sessionlock);
04972 
04973 #ifdef DUMP_PACKET
04974    if (unistimdebug)
04975       ast_verb(0, "\n*** Dump %d bytes from %s - phone_table[%d] ***\n",
04976                dw_num_bytes_rcvd, ast_inet_ntoa(addr_from.sin_addr), tmp);
04977    for (dw_num_bytes_rcvdd = 0; dw_num_bytes_rcvdd < dw_num_bytes_rcvd;
04978        dw_num_bytes_rcvdd++)
04979       ast_verb(0, "%.2x ", (unsigned char) buff[dw_num_bytes_rcvdd]);
04980    ast_verb(0, "\n******************************************\n");
04981 #endif
04982 
04983    if (!found) {
04984       if (unistimdebug) {
04985          ast_verb(0, "Received a packet from an unknown source\n");
04986       }
04987       parsing(dw_num_bytes_rcvd, buff, NULL, (struct sockaddr_in *) &addr_from);
04988 
04989    } else {
04990       parsing(dw_num_bytes_rcvd, buff, cur, (struct sockaddr_in *) &addr_from);
04991    }
04992    return 1;
04993 }
04994 
04995 static struct ast_frame *unistim_rtp_read(const struct ast_channel *ast,
04996    const struct unistim_subchannel *sub)
04997 {
04998    /* Retrieve audio/etc from channel.  Assumes sub->lock is already held. */
04999    struct ast_frame *f;
05000 
05001    if (!ast) {
05002       ast_log(LOG_WARNING, "Channel NULL while reading\n");
05003       return &ast_null_frame;
05004    }
05005 
05006    if (!sub->rtp) {
05007       ast_log(LOG_WARNING, "RTP handle NULL while reading on subchannel %u\n",
05008             sub->subtype);
05009       return &ast_null_frame;
05010    }
05011 
05012    switch (ast_channel_fdno(ast)) {
05013    case 0:
05014       f = ast_rtp_instance_read(sub->rtp, 0);     /* RTP Audio */
05015       break;
05016    case 1:
05017       f = ast_rtp_instance_read(sub->rtp, 1);    /* RTCP Control Channel */
05018       break;
05019    default:
05020       f = &ast_null_frame;
05021    }
05022 
05023    if (sub->owner) {
05024       /* We already hold the channel lock */
05025       if (f->frametype == AST_FRAME_VOICE) {
05026          if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(sub->owner), &f->subclass.format))) {
05027             char tmp[256];
05028             ast_debug(1,
05029                   "Oooh, format changed from %s to %s\n",
05030                   ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(sub->owner)),
05031                   ast_getformatname(&f->subclass.format));
05032 
05033             ast_format_cap_set(ast_channel_nativeformats(sub->owner), &f->subclass.format);
05034             ast_set_read_format(sub->owner, ast_channel_readformat(sub->owner));
05035             ast_set_write_format(sub->owner, ast_channel_writeformat(sub->owner));
05036          }
05037       }
05038    }
05039 
05040    return f;
05041 }
05042 
05043 static struct ast_frame *unistim_read(struct ast_channel *ast)
05044 {
05045    struct ast_frame *fr;
05046    struct unistim_subchannel *sub = ast_channel_tech_pvt(ast);
05047 
05048    ast_mutex_lock(&sub->lock);
05049    fr = unistim_rtp_read(ast, sub);
05050    ast_mutex_unlock(&sub->lock);
05051 
05052    return fr;
05053 }
05054 
05055 static int unistim_write(struct ast_channel *ast, struct ast_frame *frame)
05056 {
05057    struct unistim_subchannel *sub = ast_channel_tech_pvt(ast);
05058    int res = 0;
05059 
05060    if (frame->frametype != AST_FRAME_VOICE) {
05061       if (frame->frametype == AST_FRAME_IMAGE) {
05062          return 0;
05063       } else {
05064          ast_log(LOG_WARNING, "Can't send %u type frames with unistim_write\n",
05065                frame->frametype);
05066          return 0;
05067       }
05068    } else {
05069       if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
05070          char tmp[256];
05071          ast_log(LOG_WARNING,
05072                "Asked to transmit frame type %s, while native formats is %s (read/write = (%s/%s)\n",
05073                ast_getformatname(&frame->subclass.format),
05074                ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(ast)),
05075                ast_getformatname(ast_channel_readformat(ast)),
05076                ast_getformatname(ast_channel_writeformat(ast)));
05077          return -1;
05078       }
05079    }
05080 
05081    if (sub) {
05082       ast_mutex_lock(&sub->lock);
05083       if (sub->rtp) {
05084          res = ast_rtp_instance_write(sub->rtp, frame);
05085       }
05086       ast_mutex_unlock(&sub->lock);
05087    }
05088 
05089    return res;
05090 }
05091 
05092 static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
05093 {
05094    struct unistim_subchannel *p = ast_channel_tech_pvt(newchan);
05095    struct unistim_line *l = p->parent;
05096 
05097    ast_mutex_lock(&p->lock);
05098 
05099    ast_debug(1, "New owner for channel USTM/%s@%s-%u is %s\n", l->name,
05100          l->parent->name, p->subtype, ast_channel_name(newchan));
05101 
05102    if (p->owner != oldchan) {
05103       ast_log(LOG_WARNING, "old channel wasn't %s (%p) but was %s (%p)\n",
05104             ast_channel_name(oldchan), oldchan, ast_channel_name(p->owner), p->owner);
05105       ast_mutex_unlock(&p->lock);
05106       return -1;
05107    }
05108 
05109    p->owner = newchan;
05110 
05111    ast_mutex_unlock(&p->lock);
05112 
05113    return 0;
05114 
05115 }
05116 
05117 static char *control2str(int ind)
05118 {
05119    switch (ind) {
05120    case AST_CONTROL_HANGUP:
05121       return "Other end has hungup";
05122    case AST_CONTROL_RING:
05123       return "Local ring";
05124    case AST_CONTROL_RINGING:
05125       return "Remote end is ringing";
05126    case AST_CONTROL_ANSWER:
05127       return "Remote end has answered";
05128    case AST_CONTROL_BUSY:
05129       return "Remote end is busy";
05130    case AST_CONTROL_TAKEOFFHOOK:
05131       return "Make it go off hook";
05132    case AST_CONTROL_OFFHOOK:
05133       return "Line is off hook";
05134    case AST_CONTROL_CONGESTION:
05135       return "Congestion (circuits busy)";
05136    case AST_CONTROL_FLASH:
05137       return "Flash hook";
05138    case AST_CONTROL_WINK:
05139       return "Wink";
05140    case AST_CONTROL_OPTION:
05141       return "Set a low-level option";
05142    case AST_CONTROL_RADIO_KEY:
05143       return "Key Radio";
05144    case AST_CONTROL_RADIO_UNKEY:
05145       return "Un-Key Radio";
05146    case AST_CONTROL_CONNECTED_LINE:
05147       return "Remote end changed";
05148    case AST_CONTROL_SRCCHANGE:
05149       return "RTP source updated";
05150    case AST_CONTROL_SRCUPDATE:
05151       return "Source of media changed";
05152    case -1:
05153       return "Stop tone";
05154    }
05155    return "UNKNOWN";
05156 }
05157 
05158 static void in_band_indication(struct ast_channel *ast, const struct ast_tone_zone *tz,
05159    const char *indication)
05160 {
05161    struct ast_tone_zone_sound *ts = NULL;
05162 
05163    if ((ts = ast_get_indication_tone(tz, indication))) {
05164       ast_playtones_start(ast, 0, ts->data, 1);
05165       ts = ast_tone_zone_sound_unref(ts);
05166    } else {
05167       ast_log(LOG_WARNING, "Unable to get indication tone for %s\n", indication);
05168    }
05169 }
05170 
05171 static int unistim_indicate(struct ast_channel *ast, int ind, const void *data, 
05172    size_t datalen)
05173 {
05174    struct unistim_subchannel *sub;
05175    struct unistim_line *l;
05176    struct unistimsession *s;
05177 
05178    if (unistimdebug) {
05179       ast_verb(3, "Asked to indicate '%s' (%d) condition on channel %s\n",
05180                control2str(ind), ind, ast_channel_name(ast));
05181    }
05182 
05183    s = channel_to_session(ast);
05184    if (!s) {
05185       return -1;
05186    }
05187    sub = ast_channel_tech_pvt(ast);
05188    l = sub->parent;
05189 
05190    switch (ind) {
05191    case AST_CONTROL_RINGING:
05192       if (ast_channel_state(ast) != AST_STATE_UP) {
05193          send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Ringing...", s));
05194          in_band_indication(ast, l->parent->tz, "ring");
05195          s->device->missed_call = -1;
05196          break;
05197       }
05198       return -1;
05199    case AST_CONTROL_BUSY:
05200       if (ast_channel_state(ast) != AST_STATE_UP) {
05201          sub->alreadygone = 1;
05202          send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Busy", s));
05203          in_band_indication(ast, l->parent->tz, "busy");
05204          s->device->missed_call = -1;
05205          break;
05206       }
05207       return -1;
05208    case AST_CONTROL_INCOMPLETE:
05209       /* Overlapped dialing is not currently supported for UNIStim.  Treat an indication
05210        * of incomplete as congestion
05211        */
05212    case AST_CONTROL_CONGESTION:
05213       if (ast_channel_state(ast) != AST_STATE_UP) {
05214          sub->alreadygone = 1;
05215          send_text(TEXT_LINE2, TEXT_NORMAL, s, ustmtext("Congestion", s));
05216          in_band_indication(ast, l->parent->tz, "congestion");
05217          s->device->missed_call = -1;
05218          break;
05219       }
05220       return -1;
05221    case AST_CONTROL_HOLD:
05222       ast_moh_start(ast, data, NULL);
05223       break;
05224    case AST_CONTROL_UNHOLD:
05225       ast_moh_stop(ast);
05226       break;
05227    case AST_CONTROL_PROGRESS:
05228    case AST_CONTROL_SRCUPDATE:
05229    case AST_CONTROL_PROCEEDING:
05230       break;
05231    case -1:
05232       ast_playtones_stop(ast);
05233       s->device->missed_call = 0;
05234       break;
05235         case AST_CONTROL_CONNECTED_LINE:
05236       ast_log(LOG_NOTICE, "Connected party is now %s <%s>\n",
05237       S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, ""),
05238       S_COR(ast_channel_connected(ast)->id.number.valid, ast_channel_connected(ast)->id.number.str, ""));
05239       if (sub->subtype == SUB_REAL) {
05240          send_callerid_screen(s, sub);
05241       }
05242    case AST_CONTROL_UPDATE_RTP_PEER:
05243       break;
05244    case AST_CONTROL_SRCCHANGE:
05245       if (sub->rtp) {
05246          ast_rtp_instance_change_source(sub->rtp);
05247       }
05248       break;
05249    default:
05250       ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
05251       /* fallthrough */
05252    case AST_CONTROL_PVT_CAUSE_CODE:
05253       return -1;
05254    }
05255 
05256    return 0;
05257 }
05258 
05259 static struct unistim_subchannel *find_subchannel_by_name(const char *dest)
05260 {
05261    struct unistim_line *l;
05262    struct unistim_device *d;
05263    struct unistim_subchannel *sub = NULL;
05264    char line[256];
05265    char *at;
05266    char *device;
05267 
05268    ast_copy_string(line, dest, sizeof(line));
05269    at = strchr(line, '@');
05270    if (!at) {
05271       ast_log(LOG_NOTICE, "Device '%s' has no @ (at) sign!\n", dest);
05272       return NULL;
05273    }
05274    *at = '\0';
05275    at++;
05276    device = at;
05277    ast_mutex_lock(&devicelock);
05278    d = devices;
05279    at = strchr(device, '/');       /* Extra options ? */
05280    if (at) {
05281       *at = '\0';
05282    }
05283    while (d) {
05284       if (!strcasecmp(d->name, device)) {
05285          if (unistimdebug) {
05286             ast_verb(0, "Found device: %s\n", d->name);
05287          }
05288          /* Found the device */
05289          AST_LIST_LOCK(&d->lines);
05290          AST_LIST_TRAVERSE(&d->lines, l, list) {
05291             /* Search for the right line */
05292             if (!strcasecmp(l->name, line)) {
05293                if (unistimdebug) {
05294                   ast_verb(0, "Found line: %s\n", l->name);
05295                }
05296                sub = get_sub(d, SUB_REAL);
05297                if (!sub) {
05298                   sub = unistim_alloc_sub(d, SUB_REAL);
05299                }
05300                if (sub->owner) {
05301                   /* Allocate additional channel if asterisk channel already here */
05302                   sub = unistim_alloc_sub(d, SUB_ONHOLD);
05303                }
05304                sub->ringvolume = -1;
05305                sub->ringstyle = -1;
05306                if (at) {       /* Other options ? */
05307                   at++;   /* Skip slash */
05308                   if (*at == 'r') {       /* distinctive ring */
05309                      at++;
05310                      if ((*at < '0') || (*at > '7')) { /* ring style */
05311                         ast_log(LOG_WARNING, "Invalid ring selection (%s)", at);
05312                      } else {
05313                         char ring_volume = -1;
05314                         char ring_style = *at - '0';
05315                         at++;
05316                         if ((*at >= '0') && (*at <= '3')) {      /* ring volume */
05317                            ring_volume = *at - '0';
05318                         }
05319                         if (unistimdebug) {
05320                            ast_verb(0, "Distinctive ring: style #%d volume %d\n",
05321                                ring_style, ring_volume);
05322                         }
05323                         sub->ringvolume = ring_volume;
05324                         sub->ringstyle = ring_style;
05325                      }
05326                   }
05327                }
05328                sub->parent = l;
05329                break;
05330             }
05331          }
05332          AST_LIST_UNLOCK(&d->lines);
05333          if (sub) {
05334             ast_mutex_unlock(&devicelock);
05335             return sub;
05336          }
05337       }
05338       d = d->next;
05339    }
05340    /* Device not found */
05341    ast_mutex_unlock(&devicelock);
05342 
05343    return NULL;
05344 }
05345 
05346 static int unistim_senddigit_begin(struct ast_channel *ast, char digit)
05347 {
05348    struct unistimsession *pte = channel_to_session(ast);
05349 
05350    if (!pte) {
05351       return -1;
05352    }
05353    return unistim_do_senddigit(pte, digit);
05354 }
05355 
05356 static int unistim_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
05357 {
05358    struct unistimsession *pte = channel_to_session(ast);
05359    struct ast_frame f = { 0, };
05360    struct unistim_subchannel *sub;
05361 
05362    sub = get_sub(pte->device, SUB_REAL);
05363 
05364    if (!sub || !sub->owner || sub->alreadygone) {
05365       ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit_end\n");
05366       return -1;
05367    }
05368 
05369    if (unistimdebug) {
05370       ast_verb(0, "Send Digit off %c\n", digit);
05371    }
05372    if (!pte) {
05373       return -1;
05374    }
05375    send_tone(pte, 0, 0);
05376    f.frametype = AST_FRAME_DTMF;
05377    f.subclass.integer = digit;
05378    f.src = "unistim";
05379    ast_queue_frame(sub->owner, &f);
05380 
05381    return 0;
05382 }
05383 
05384 /*--- unistim_sendtext: Display a text on the phone screen ---*/
05385 /*      Called from PBX core text message functions */
05386 static int unistim_sendtext(struct ast_channel *ast, const char *text)
05387 {
05388    struct unistimsession *pte = channel_to_session(ast);
05389    int size;
05390    char tmp[TEXT_LENGTH_MAX + 1];
05391 
05392    if (unistimdebug) {
05393       ast_verb(0, "unistim_sendtext called\n");
05394    }
05395    if (!text) {
05396       ast_log(LOG_WARNING, "unistim_sendtext called with a null text\n");
05397       return -1;
05398    }
05399 
05400    if (!pte) {
05401       return -1;
05402    }
05403 
05404    size = strlen(text);
05405    if (text[0] == '@') {
05406       int pos = 0, i = 1, tok = 0, sz = 0;
05407       char label[11];
05408       char number[16];
05409       char icon = '\0';
05410       char cur = '\0';
05411 
05412       memset(label, 0, 11);
05413       memset(number, 0, 16);
05414       while (text[i]) {
05415          cur = text[i++];
05416          switch (tok) {
05417          case 0:
05418             if ((cur < '0') && (cur > '5')) {
05419                ast_log(LOG_WARNING,
05420                      "sendtext failed : position must be a number beetween 0 and 5\n");
05421                return 1;
05422             }
05423             pos = cur - '0';
05424             tok = 1;
05425             continue;
05426          case 1:
05427             if (cur != '@') {
05428                ast_log(LOG_WARNING, "sendtext failed : invalid position\n");
05429                return 1;
05430             }
05431             tok = 2;
05432             continue;
05433          case 2:
05434             if ((cur < '3') && (cur > '6')) {
05435                ast_log(LOG_WARNING,
05436                      "sendtext failed : icon must be a number beetween 32 and 63 (first digit invalid)\n");
05437                return 1;
05438             }
05439             icon = (cur - '0') * 10;
05440             tok = 3;
05441             continue;
05442          case 3:
05443             if ((cur < '0') && (cur > '9')) {
05444                ast_log(LOG_WARNING,
05445                      "sendtext failed : icon must be a number beetween 32 and 63 (second digit invalid)\n");
05446                return 1;
05447             }
05448             icon += (cur - '0');
05449             tok = 4;
05450             continue;
05451          case 4:
05452             if (cur != '@') {
05453                ast_log(LOG_WARNING,
05454                      "sendtext failed : icon must be a number beetween 32 and 63 (too many digits)\n");
05455                return 1;
05456             }
05457             tok = 5;
05458             continue;
05459          case 5:
05460             if (cur == '@') {
05461                tok = 6;
05462                sz = 0;
05463                continue;
05464             }
05465             if (sz > 10) {
05466                continue;
05467             }
05468             label[sz] = cur;
05469             sz++;
05470             continue;
05471          case 6:
05472             if (sz > 15) {
05473                ast_log(LOG_WARNING,
05474                      "sendtext failed : extension too long = %d (15 car max)\n",
05475                      sz);
05476                return 1;
05477             }
05478             number[sz] = cur;
05479             sz++;
05480             continue;
05481          }
05482       }
05483       if (tok != 6) {
05484          ast_log(LOG_WARNING, "sendtext failed : incomplet command\n");
05485          return 1;
05486       }
05487       if (!pte->device) {
05488          ast_log(LOG_WARNING, "sendtext failed : no device ?\n");
05489          return 1;
05490       }
05491       strcpy(pte->device->softkeylabel[pos], label);
05492       strcpy(pte->device->softkeynumber[pos], number);
05493       pte->device->softkeyicon[pos] = icon;
05494       send_favorite(pos, icon, pte, label);
05495       return 0;
05496    }
05497 
05498    if (size <= TEXT_LENGTH_MAX * 2) {
05499       if (pte->device->height == 1) {
05500          send_text(TEXT_LINE0, TEXT_NORMAL, pte, text);
05501       } else {
05502          send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext("Message :", pte));
05503          send_text(TEXT_LINE1, TEXT_NORMAL, pte, text);
05504       }
05505       if (size <= TEXT_LENGTH_MAX) {
05506          send_text(TEXT_LINE2, TEXT_NORMAL, pte, "");
05507          return 0;
05508       }
05509       memcpy(tmp, text + TEXT_LENGTH_MAX, TEXT_LENGTH_MAX);
05510       tmp[sizeof(tmp) - 1] = '\0';
05511       send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
05512       return 0;
05513    }
05514    send_text(TEXT_LINE0, TEXT_NORMAL, pte, text);
05515    memcpy(tmp, text + TEXT_LENGTH_MAX, TEXT_LENGTH_MAX);
05516    tmp[sizeof(tmp) - 1] = '\0';
05517    send_text(TEXT_LINE1, TEXT_NORMAL, pte, tmp);
05518    memcpy(tmp, text + TEXT_LENGTH_MAX * 2, TEXT_LENGTH_MAX);
05519    tmp[sizeof(tmp) - 1] = '\0';
05520    send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
05521    return 0;
05522 }
05523 
05524 /*--- unistim_send_mwi_to_peer: Send message waiting indication ---*/
05525 static int unistim_send_mwi_to_peer(struct unistim_line *peer, unsigned int tick)
05526 {
05527    struct ast_event *event;
05528    int new;
05529    char *mailbox, *context;
05530 
05531    context = mailbox = ast_strdupa(peer->mailbox);
05532    strsep(&context, "@");
05533    if (ast_strlen_zero(context)) {
05534       context = "default";
05535    }
05536    event = ast_event_get_cached(AST_EVENT_MWI,
05537       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
05538       AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
05539       AST_EVENT_IE_END);
05540 
05541    if (event) {
05542       new = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
05543       ast_event_destroy(event);
05544    } else { /* Fall back on checking the mailbox directly */
05545       new = ast_app_has_voicemail(peer->mailbox, "INBOX");
05546    }
05547    ast_debug(3, "MWI Status for mailbox %s is %d, lastmsgsent:%d\n",mailbox,new,peer->parent->lastmsgssent);
05548    peer->parent->nextmsgcheck = tick + TIMER_MWI;
05549 
05550    /* Return now if it's the same thing we told them last time */
05551    if ((peer->parent->session->state != STATE_MAINPAGE) || (new == peer->parent->lastmsgssent)) {
05552       return 0;
05553    }
05554 
05555    peer->parent->lastmsgssent = new;
05556    send_led_update(peer->parent->session, (new > 0));
05557 
05558    return 0;
05559 }
05560 
05561 /*--- unistim_new: Initiate a call in the UNISTIM channel */
05562 /*      called from unistim_request (calls from the pbx ) */
05563 static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const char *linkedid)
05564 {
05565    struct ast_channel *tmp;
05566    struct unistim_line *l;
05567    struct ast_format tmpfmt;
05568 
05569    if (!sub) {
05570       ast_log(LOG_WARNING, "subchannel null in unistim_new\n");
05571       return NULL;
05572    }
05573    if (!sub->parent) {
05574       ast_log(LOG_WARNING, "no line for subchannel %p\n", sub);
05575       return NULL;
05576    }
05577    l = sub->parent;
05578    tmp = ast_channel_alloc(1, state, l->cid_num, NULL, l->accountcode, l->exten,
05579       l->parent->context, linkedid, l->amaflags, "USTM/%s@%s-%p", l->name, l->parent->name, sub);
05580    if (unistimdebug) {
05581       ast_verb(0, "unistim_new sub=%u (%p) chan=%p line=%s\n", sub->subtype, sub, tmp, l->name);
05582    }
05583    if (!tmp) {
05584       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
05585       return NULL;
05586    }
05587 
05588    ast_format_cap_copy(ast_channel_nativeformats(tmp), l->cap);
05589    if (ast_format_cap_is_empty(ast_channel_nativeformats(tmp))) {
05590       ast_format_cap_copy(ast_channel_nativeformats(tmp), global_cap);
05591    }
05592    ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
05593 
05594    if (unistimdebug) {
05595       char tmp1[256], tmp2[256], tmp3[256];
05596       ast_verb(0, "Best codec = %s from nativeformats %s (line cap=%s global=%s)\n",
05597          ast_getformatname(&tmpfmt),
05598          ast_getformatname_multiple(tmp1, sizeof(tmp1), ast_channel_nativeformats(tmp)),
05599          ast_getformatname_multiple(tmp2, sizeof(tmp2), l->cap),
05600          ast_getformatname_multiple(tmp3, sizeof(tmp3), global_cap));
05601    }
05602    if ((sub->rtp) && (sub->subtype == 0)) {
05603       if (unistimdebug) {
05604          ast_verb(0, "New unistim channel with a previous rtp handle ?\n");
05605       }
05606       ast_channel_internal_fd_set(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
05607       ast_channel_internal_fd_set(tmp, 1, ast_rtp_instance_fd(sub->rtp, 1));
05608    }
05609    if (sub->rtp) {
05610       ast_jb_configure(tmp, &global_jbconf);
05611    }
05612 /*      tmp->type = type; */
05613    ast_setstate(tmp, state);
05614    if (state == AST_STATE_RING) {
05615       ast_channel_rings_set(tmp, 1);
05616    }
05617    ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
05618    ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
05619    ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
05620    ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
05621    ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
05622    ast_channel_tech_pvt_set(tmp, sub);
05623    ast_channel_tech_set(tmp, &unistim_tech);
05624 
05625    if (!ast_strlen_zero(l->parent->language)) {
05626       ast_channel_language_set(tmp, l->parent->language);
05627    }
05628    sub->owner = tmp;
05629    ast_update_use_count();
05630    ast_channel_callgroup_set(tmp, l->callgroup);
05631    ast_channel_pickupgroup_set(tmp, l->pickupgroup);
05632    ast_channel_call_forward_set(tmp, l->parent->call_forward);
05633    if (!ast_strlen_zero(l->cid_num)) {
05634       char *name, *loc, *instr;
05635       instr = ast_strdup(l->cid_num);
05636       if (instr) {
05637          ast_callerid_parse(instr, &name, &loc);
05638          ast_channel_caller(tmp)->id.number.valid = 1;
05639          ast_free(ast_channel_caller(tmp)->id.number.str);
05640          ast_channel_caller(tmp)->id.number.str = ast_strdup(loc);
05641          ast_channel_caller(tmp)->id.name.valid = 1;
05642          ast_free(ast_channel_caller(tmp)->id.name.str);
05643          ast_channel_caller(tmp)->id.name.str = ast_strdup(name);
05644          ast_free(instr);
05645       }
05646    }
05647    ast_channel_priority_set(tmp, 1);
05648    if (state != AST_STATE_DOWN) {
05649       if (unistimdebug) {
05650          ast_verb(0, "Starting pbx in unistim_new\n");
05651       }
05652       if (ast_pbx_start(tmp)) {
05653          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
05654          ast_hangup(tmp);
05655          tmp = NULL;
05656       }
05657    }
05658 
05659    return tmp;
05660 }
05661 
05662 static void *do_monitor(void *data)
05663 {
05664    struct unistimsession *cur = NULL;
05665    unsigned int dw_timeout = 0;
05666    unsigned int tick;
05667    int res;
05668    int reloading;
05669 
05670    /* Add an I/O event to our UDP socket */
05671    if (unistimsock > -1) {
05672       ast_io_add(io, unistimsock, unistimsock_read, AST_IO_IN, NULL);
05673    }
05674    /* This thread monitors our UDP socket and timers */
05675    for (;;) {
05676       /* This loop is executed at least every IDLE_WAITus (1s) or every time a packet is received */
05677       /* Looking for the smallest time-out value */
05678       tick = get_tick_count();
05679       dw_timeout = UINT_MAX;
05680       ast_mutex_lock(&sessionlock);
05681       cur = sessions;
05682       DEBUG_TIMER("checking timeout for session %p with tick = %u\n", cur, tick);
05683       while (cur) {
05684          DEBUG_TIMER("checking timeout for session %p timeout = %u\n", cur,
05685                   cur->timeout);
05686          /* Check if we have miss something */
05687          if (cur->timeout <= tick) {
05688             DEBUG_TIMER("Event for session %p\n", cur);
05689             /* If the queue is empty, send a ping */
05690             if (cur->last_buf_available == 0) {
05691                send_ping(cur);
05692             } else {
05693                if (send_retransmit(cur)) {
05694                   DEBUG_TIMER("The chained link was modified, restarting...\n");
05695                   cur = sessions;
05696                   dw_timeout = UINT_MAX;
05697                   continue;
05698                }
05699             }
05700          }
05701          if (dw_timeout > cur->timeout - tick) {
05702             dw_timeout = cur->timeout - tick;
05703          }
05704          /* Checking if the phone is logged on for a new MWI */
05705          if (cur->device) {
05706             struct unistim_line *l;
05707             AST_LIST_LOCK(&cur->device->lines);
05708             AST_LIST_TRAVERSE(&cur->device->lines, l, list) {
05709                if ((!ast_strlen_zero(l->mailbox)) && (tick >= l->parent->nextmsgcheck)) {
05710                   DEBUG_TIMER("Checking mailbox for MWI\n");
05711                   unistim_send_mwi_to_peer(l, tick);
05712                   break;
05713                }
05714             }
05715             AST_LIST_UNLOCK(&cur->device->lines);
05716             if (cur->device->nextdial && tick >= cur->device->nextdial) {
05717                handle_call_outgoing(cur);
05718                cur->device->nextdial = 0;
05719             }
05720          }
05721          cur = cur->next;
05722       }
05723       ast_mutex_unlock(&sessionlock);
05724       DEBUG_TIMER("Waiting for %dus\n", dw_timeout);
05725       res = dw_timeout;
05726       /* We should not wait more than IDLE_WAIT */
05727       if ((res < 0) || (res > IDLE_WAIT)) {
05728          res = IDLE_WAIT;
05729       }
05730       /* Wait for UDP messages for a maximum of res us */
05731       res = ast_io_wait(io, res);     /* This function will call unistimsock_read if a packet is received */
05732       /* Check for a reload request */
05733       ast_mutex_lock(&unistim_reload_lock);
05734       reloading = unistim_reloading;
05735       unistim_reloading = 0;
05736       ast_mutex_unlock(&unistim_reload_lock);
05737       if (reloading) {
05738          ast_verb(1, "Reloading unistim.conf...\n");
05739          reload_config();
05740       }
05741       pthread_testcancel();
05742    }
05743    /* Never reached */
05744    return NULL;
05745 }
05746 
05747 /*--- restart_monitor: Start the channel monitor thread ---*/
05748 static int restart_monitor(void)
05749 {
05750    pthread_attr_t attr;
05751    /* If we're supposed to be stopped -- stay stopped */
05752    if (monitor_thread == AST_PTHREADT_STOP) {
05753       return 0;
05754    }
05755    if (ast_mutex_lock(&monlock)) {
05756       ast_log(LOG_WARNING, "Unable to lock monitor\n");
05757       return -1;
05758    }
05759    if (monitor_thread == pthread_self()) {
05760       ast_mutex_unlock(&monlock);
05761       ast_log(LOG_WARNING, "Cannot kill myself\n");
05762       return -1;
05763    }
05764    if (monitor_thread != AST_PTHREADT_NULL) {
05765       /* Wake up the thread */
05766       pthread_kill(monitor_thread, SIGURG);
05767    } else {
05768       pthread_attr_init(&attr);
05769       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
05770       /* Start a new monitor */
05771       if (ast_pthread_create(&monitor_thread, &attr, do_monitor, NULL) < 0) {
05772          ast_mutex_unlock(&monlock);
05773          ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
05774          return -1;
05775       }
05776    }
05777    ast_mutex_unlock(&monlock);
05778    return 0;
05779 }
05780 
05781 /*--- unistim_request: PBX interface function ---*/
05782 /* UNISTIM calls initiated by the PBX arrive here */
05783 static struct ast_channel *unistim_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest,
05784                                  int *cause)
05785 {
05786    struct unistim_subchannel *sub, *sub_ring, *sub_trans;
05787    struct unistim_device *d;
05788    struct ast_channel *tmpc = NULL;
05789    char tmp[256];
05790    char tmp2[256];
05791 
05792    if (!(ast_format_cap_has_joint(cap, global_cap))) {
05793       ast_log(LOG_NOTICE,
05794             "Asked to get a channel of unsupported format %s while capability is %s\n",
05795             ast_getformatname_multiple(tmp2, sizeof(tmp2), cap), ast_getformatname_multiple(tmp, sizeof(tmp), global_cap));
05796       return NULL;
05797    }
05798 
05799    ast_copy_string(tmp, dest, sizeof(tmp));
05800    if (ast_strlen_zero(tmp)) {
05801       ast_log(LOG_NOTICE, "Unistim channels require a device\n");
05802       return NULL;
05803    }
05804    sub = find_subchannel_by_name(tmp);
05805    if (!sub) {
05806       ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
05807       *cause = AST_CAUSE_CONGESTION;
05808       return NULL;
05809    }
05810    d = sub->parent->parent;
05811    sub_ring = get_sub(d, SUB_RING);
05812    sub_trans = get_sub(d, SUB_THREEWAY);
05813    /* Another request already in progress */
05814    if (!d->session) {
05815       unistim_unalloc_sub(d, sub);
05816       *cause = AST_CAUSE_CONGESTION;
05817       return NULL;
05818    }
05819    if (sub_ring || sub_trans) {
05820       if (unistimdebug) {
05821          ast_verb(0, "Can't create channel, request already in progress: Busy!\n");
05822       }
05823       unistim_unalloc_sub(d, sub);
05824       *cause = AST_CAUSE_BUSY;
05825       return NULL;
05826    }
05827    if (d->session->state == STATE_DIALPAGE) {
05828       if (unistimdebug) {
05829          ast_verb(0, "Can't create channel, user on dialpage: Busy!\n");
05830       }
05831       unistim_unalloc_sub(d, sub);
05832       *cause = AST_CAUSE_BUSY;
05833       return NULL;
05834    }
05835 
05836         if (get_avail_softkey(d->session, sub->parent->name) == -1) {
05837       if (unistimdebug) {
05838          ast_verb(0, "Can't create channel for line %s, all lines busy\n", sub->parent->name);
05839       }
05840       unistim_unalloc_sub(d, sub);
05841       *cause = AST_CAUSE_BUSY;
05842       return NULL;
05843    }
05844    sub->subtype = SUB_RING;
05845    sub->softkey = -1;
05846    ast_format_cap_copy(sub->parent->cap, cap);
05847    tmpc = unistim_new(sub, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
05848    if (!tmpc) {
05849       ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
05850    }
05851    if (unistimdebug) {
05852       ast_verb(0, "unistim_request owner = %p\n", sub->owner);
05853    }
05854    restart_monitor();
05855    /* and finish */
05856    return tmpc;
05857 }
05858 
05859 static char *unistim_show_info(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05860 {
05861    struct unistim_device *device = devices;
05862    struct unistim_line *line;
05863    struct unistim_subchannel *sub;
05864    struct unistimsession *s;
05865    struct ast_channel *tmp;
05866 
05867    switch (cmd) {
05868    case CLI_INIT:
05869       e->command = "unistim show info";
05870       e->usage =
05871          "Usage: unistim show info\n"
05872          "       Dump internal structures.\n\n"
05873          "       device\n"
05874          "       ->line\n"
05875          "       -->sub\n"
05876          "       ==>key\n";
05877       return NULL;
05878 
05879    case CLI_GENERATE:
05880       return NULL;   /* no completion */
05881    }
05882 
05883    if (a->argc != e->args) {
05884       return CLI_SHOWUSAGE;
05885    }
05886    ast_cli(a->fd, "Dumping internal structures:\n");
05887    ast_mutex_lock(&devicelock);
05888    while (device) {
05889       int i;
05890 
05891       ast_cli(a->fd, "\nname=%s id=%s ha=%p sess=%p device=%p selected=%d height=%d\n",
05892             device->name, device->id, device->ha, device->session,
05893             device, device->selected, device->height);
05894       AST_LIST_LOCK(&device->lines);
05895       AST_LIST_TRAVERSE(&device->lines,line,list) {
05896          char tmp2[256];
05897          ast_cli(a->fd,
05898                "->name=%s fullname=%s exten=%s callid=%s cap=%s line=%p\n",
05899                line->name, line->fullname, line->exten, line->cid_num,
05900                ast_getformatname_multiple(tmp2, sizeof(tmp2), line->cap), line);
05901       }
05902       AST_LIST_UNLOCK(&device->lines);
05903 
05904       AST_LIST_LOCK(&device->subs);
05905       AST_LIST_TRAVERSE(&device->subs, sub, list) {
05906          if (!sub) {
05907             continue;
05908          }
05909          if (!sub->owner) {
05910             tmp = (void *) -42;
05911          } else {
05912             tmp = ast_channel_internal_bridged_channel(sub->owner);
05913          }
05914          ast_cli(a->fd,
05915                "-->subtype=%s chan=%p rtp=%p bridge=%p line=%p alreadygone=%d softkey=%d\n",
05916                subtype_tostr(sub->subtype), sub->owner, sub->rtp, tmp, sub->parent,
05917                sub->alreadygone, sub->softkey);
05918       }
05919       AST_LIST_UNLOCK(&device->subs);
05920 
05921       for (i = 0; i < FAVNUM; i++) {
05922          if (!soft_key_visible(device, i)) {
05923             continue;
05924          }
05925          ast_cli(a->fd, "==> %d. dev=%s icon=%#-4x label=%-10s number=%-5s sub=%p line=%p\n",
05926             i, device->softkeydevice[i], (unsigned)device->softkeyicon[i], device->softkeylabel[i], device->softkeynumber[i],
05927             device->ssub[i], device->sline[i]);
05928       }
05929       device = device->next;
05930    }
05931    ast_mutex_unlock(&devicelock);
05932    ast_cli(a->fd, "\nSessions:\n");
05933    ast_mutex_lock(&sessionlock);
05934    s = sessions;
05935    while (s) {
05936       ast_cli(a->fd,
05937             "sin=%s timeout=%d state=%s macaddr=%s device=%p session=%p\n",
05938             ast_inet_ntoa(s->sin.sin_addr), s->timeout, ptestate_tostr(s->state), s->macaddr,
05939             s->device, s);
05940       s = s->next;
05941    }
05942    ast_mutex_unlock(&sessionlock);
05943 
05944    return CLI_SUCCESS;
05945 }
05946 
05947 static char *unistim_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05948 {
05949    struct unistim_device *device = devices;
05950 
05951    switch (cmd) {
05952    case CLI_INIT:
05953       e->command = "unistim show devices";
05954       e->usage =
05955          "Usage: unistim show devices\n"
05956          "       Lists all known Unistim devices.\n";
05957       return NULL;
05958    case CLI_GENERATE:
05959       return NULL;   /* no completion */
05960    }
05961 
05962    if (a->argc != e->args)
05963       return CLI_SHOWUSAGE;
05964 
05965    ast_cli(a->fd, "%-20.20s %-20.20s %-15.15s %s\n", "Name/username", "MAC", "Host", "Status");
05966    ast_mutex_lock(&devicelock);
05967    while (device) {
05968       ast_cli(a->fd, "%-20.20s %-20.20s %-15.15s %s\n",
05969          device->name, device->id,
05970          (!device->session) ? "(Unspecified)" : ast_inet_ntoa(device->session->sin.sin_addr),
05971          (!device->session) ? "UNKNOWN" : "OK");
05972       device = device->next;
05973    }
05974    ast_mutex_unlock(&devicelock);
05975 
05976    return CLI_SUCCESS;
05977 }
05978 
05979 static char *unistim_sp(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05980 {
05981    BUFFSEND;
05982    struct unistim_subchannel *sub;
05983    int i, j = 0, len;
05984    unsigned char c, cc;
05985    char tmp[256];
05986 
05987    switch (cmd) {
05988    case CLI_INIT:
05989       e->command = "unistim send packet";
05990       e->usage =
05991          "Usage: unistim send packet USTM/line@name hexa\n"
05992          "       unistim send packet USTM/1000@hans 19040004\n";
05993       return NULL;
05994 
05995    case CLI_GENERATE:
05996       return NULL;   /* no completion */
05997    }
05998 
05999    if (a->argc < 5) {
06000       return CLI_SHOWUSAGE;
06001    }
06002    if (strlen(a->argv[3]) < 9) {
06003       return CLI_SHOWUSAGE;
06004    }
06005    len = strlen(a->argv[4]);
06006    if (len % 2) {
06007       return CLI_SHOWUSAGE;
06008    }
06009    ast_copy_string(tmp, a->argv[3] + 5, sizeof(tmp));
06010    sub = find_subchannel_by_name(tmp);
06011    if (!sub) {
06012       ast_cli(a->fd, "Can't find '%s'\n", tmp);
06013       return CLI_SUCCESS;
06014    }
06015    if (!sub->parent->parent->session) {
06016       ast_cli(a->fd, "'%s' is not connected\n", tmp);
06017       return CLI_SUCCESS;
06018    }
06019    ast_cli(a->fd, "Sending '%s' to %s (%p)\n", a->argv[4], tmp, sub->parent->parent->session);
06020    for (i = 0; i < len; i++) {
06021       c = a->argv[4][i];
06022       if (c >= 'a') {
06023          c -= 'a' - 10;
06024       } else {
06025          c -= '0';
06026       }
06027       i++;
06028       cc = a->argv[4][i];
06029       if (cc >= 'a') {
06030          cc -= 'a' - 10;
06031       } else {
06032          cc -= '0';
06033       }
06034       tmp[j++] = (c << 4) | cc;
06035    }
06036    memcpy(buffsend + SIZE_HEADER, tmp, j);
06037    send_client(SIZE_HEADER + j, buffsend, sub->parent->parent->session);
06038    return CLI_SUCCESS;
06039 }
06040 
06041 static char *unistim_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06042 {
06043    switch (cmd) {
06044    case CLI_INIT:
06045       e->command = "unistim set debug {on|off}";
06046       e->usage =
06047          "Usage: unistim set debug\n" 
06048          "       Display debug messages.\n";
06049       return NULL;
06050 
06051    case CLI_GENERATE:
06052       return NULL;   /* no completion */
06053    }
06054 
06055    if (a->argc != e->args) {
06056       return CLI_SHOWUSAGE;
06057    }
06058    if (!strcasecmp(a->argv[3], "on")) {
06059       unistimdebug = 1;
06060       ast_cli(a->fd, "UNISTIM Debugging Enabled\n");
06061    } else if (!strcasecmp(a->argv[3], "off")) {
06062       unistimdebug = 0;
06063       ast_cli(a->fd, "UNISTIM Debugging Disabled\n");
06064    } else {
06065       return CLI_SHOWUSAGE;
06066    }
06067    return CLI_SUCCESS;
06068 }
06069 
06070 /*! \brief --- unistim_reload: Force reload of module from cli ---
06071  * Runs in the asterisk main thread, so don't do anything useful
06072  * but setting a flag and waiting for do_monitor to do the job
06073  * in our thread */
06074 static char *unistim_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06075 {
06076    switch (cmd) {
06077    case CLI_INIT:
06078       e->command = "unistim reload";
06079       e->usage =
06080          "Usage: unistim reload\n" 
06081          "       Reloads UNISTIM configuration from unistim.conf\n";
06082       return NULL;
06083 
06084    case CLI_GENERATE:
06085       return NULL;   /* no completion */
06086    }
06087 
06088    if (e && a && a->argc != e->args) {
06089       return CLI_SHOWUSAGE;
06090    }
06091    reload();
06092 
06093    return CLI_SUCCESS;
06094 }
06095 
06096 static struct ast_cli_entry unistim_cli[] = {
06097    AST_CLI_DEFINE(unistim_reload, "Reload UNISTIM configuration"),
06098    AST_CLI_DEFINE(unistim_show_info, "Show UNISTIM info"),
06099    AST_CLI_DEFINE(unistim_show_devices, "Show UNISTIM devices"),
06100    AST_CLI_DEFINE(unistim_sp, "Send packet (for reverse engineering)"),
06101    AST_CLI_DEFINE(unistim_do_debug, "Toggle UNITSTIM debugging"),
06102 };
06103 
06104 static void unquote(char *out, const char *src, int maxlen)
06105 {
06106    int len = strlen(src);
06107    if (!len) {
06108       return;
06109    }
06110    if ((len > 1) && src[0] == '\"') {
06111       /* This is a quoted string */
06112       src++;
06113       /* Don't take more than what's there */
06114       len--;
06115       if (maxlen > len - 1) {
06116          maxlen = len - 1;
06117       }
06118       memcpy(out, src, maxlen);
06119       ((char *) out)[maxlen] = '\0';
06120    } else {
06121       memcpy(out, src, maxlen);
06122    }
06123    return;
06124 }
06125 
06126 static int parse_bookmark(const char *text, struct unistim_device *d)
06127 {
06128    char line[256];
06129    char *at;
06130    char *number;
06131    char *icon;
06132    int p;
06133    int len = strlen(text);
06134 
06135    ast_copy_string(line, text, sizeof(line));
06136    /* Position specified ? */
06137    if ((len > 2) && (line[1] == '@')) {
06138       p = line[0];
06139       if ((p >= '0') && (p <= '5')) {
06140          p -= '0';
06141       } else {
06142          ast_log(LOG_WARNING,
06143                "Invalid position for bookmark : must be between 0 and 5\n");
06144          return 0;
06145       }
06146       if (d->softkeyicon[p] != 0) {
06147          ast_log(LOG_WARNING, "Invalid position %d for bookmark : already used:\n", p);
06148          return 0;
06149       }
06150       memmove(line, line + 2, sizeof(line) - 2);
06151    } else {
06152       /* No position specified, looking for a free slot */
06153       for (p = 0; p <= 5; p++) {
06154          if (!d->softkeyicon[p]) {
06155             break;
06156          }
06157       }
06158       if (p > 5) {
06159          ast_log(LOG_WARNING, "No more free bookmark position\n");
06160          return 0;
06161       }
06162    }
06163    at = strchr(line, '@');
06164    if (!at) {
06165       ast_log(LOG_NOTICE, "Bookmark entry '%s' has no @ (at) sign!\n", text);
06166       return 0;
06167    }
06168    *at = '\0';
06169    at++;
06170    number = at;
06171    at = strchr(at, '@');
06172    if (ast_strlen_zero(number)) {
06173       ast_log(LOG_NOTICE, "Bookmark entry '%s' has no number\n", text);
06174       return 0;
06175    }
06176    if (ast_strlen_zero(line)) {
06177       ast_log(LOG_NOTICE, "Bookmark entry '%s' has no description\n", text);
06178       return 0;
06179    }
06180 
06181    at = strchr(number, '@');
06182    if (!at) {
06183       d->softkeyicon[p] = FAV_ICON_SHARP;     /* default icon */
06184    } else {
06185       *at = '\0';
06186       at++;
06187       icon = at;
06188       if (ast_strlen_zero(icon)) {
06189          ast_log(LOG_NOTICE, "Bookmark entry '%s' has no icon value\n", text);
06190          return 0;
06191       }
06192       if (strncmp(icon, "USTM/", 5)) {
06193          d->softkeyicon[p] = atoi(icon);
06194       } else {
06195          d->softkeyicon[p] = 1;
06196          ast_copy_string(d->softkeydevice[p], icon + 5, sizeof(d->softkeydevice[p]));
06197       }
06198    }
06199    ast_copy_string(d->softkeylabel[p], line, sizeof(d->softkeylabel[p]));
06200    ast_copy_string(d->softkeynumber[p], number, sizeof(d->softkeynumber[p]));
06201    if (unistimdebug) {
06202       ast_verb(0, "New bookmark at pos %d label='%s' number='%s' icon=%#x\n",
06203                p, d->softkeylabel[p], d->softkeynumber[p], (unsigned)d->softkeyicon[p]);
06204    }
06205    return 1;
06206 }
06207 
06208 /* Looking for dynamic icons entries in bookmarks */
06209 static void finish_bookmark(void)
06210 {
06211    struct unistim_device *d = devices;
06212    int i;
06213    ast_mutex_lock(&devicelock);
06214    while (d) {
06215       for (i = 0; i < 6; i++) {
06216          if (d->softkeyicon[i] == 1) {   /* Something for us */
06217             struct unistim_device *d2 = devices;
06218             while (d2) {
06219                if (!strcmp(d->softkeydevice[i], d2->name)) {
06220                   d->sp[i] = d2;
06221                   d->softkeyicon[i] = 0;
06222                   break;
06223                }
06224                d2 = d2->next;
06225             }
06226             if (d->sp[i] == NULL) {
06227                ast_log(LOG_NOTICE, "Bookmark entry with device %s not found\n",
06228                      d->softkeydevice[i]);
06229             }
06230          }
06231       }
06232       d = d->next;
06233    }
06234    ast_mutex_unlock(&devicelock);
06235 }
06236 
06237 static struct unistim_line *find_line_by_number(struct unistim_device *d, const char *val) {
06238    struct unistim_line *l, *ret = NULL;
06239 
06240    AST_LIST_LOCK(&d->lines);
06241    AST_LIST_TRAVERSE(&d->lines, l, list) {
06242       if (!strcmp(l->name, val)) {
06243          ret = l;
06244          break;
06245       }
06246    }
06247    AST_LIST_UNLOCK(&d->lines);
06248    return ret;
06249 }
06250 
06251 static struct unistim_device *build_device(const char *cat, const struct ast_variable *v)
06252 {
06253    struct unistim_device *d;
06254    struct unistim_line *l = NULL, *lt = NULL;
06255    int create = 1;
06256    int nbsoftkey, dateformat, timeformat, callhistory, sharpdial, linecnt;
06257    char linelabel[AST_MAX_EXTENSION];
06258    char ringvolume, ringstyle, cwvolume, cwstyle;
06259 
06260    /* First, we need to know if we already have this name in our list */
06261    /* Get a lock for the device chained list */
06262    ast_mutex_lock(&devicelock);
06263    d = devices;
06264    while (d) {
06265       if (!strcmp(d->name, cat)) {
06266          /* Yep, we alreay have this one */
06267          if (unistimsock < 0) {
06268             /* It's a dupe */
06269             ast_log(LOG_WARNING, "Duplicate entry found (%s), ignoring.\n", cat);
06270             ast_mutex_unlock(&devicelock);
06271             return NULL;
06272          }
06273          /* we're reloading right now */
06274          create = 0;
06275          break;
06276       }
06277       d = d->next;
06278    }
06279    ast_mutex_unlock(&devicelock);
06280    if (!(lt = ast_calloc(1, sizeof(*lt)))) {
06281       return NULL;
06282    }
06283    if (create) {
06284       if (!(d = ast_calloc(1, sizeof(*d)))) {
06285          return NULL;
06286       }
06287       ast_mutex_init(&d->lock);
06288       ast_copy_string(d->name, cat, sizeof(d->name));
06289       d->contrast = -1;
06290       d->output = OUTPUT_HANDSET;
06291       d->previous_output = OUTPUT_HANDSET;
06292       d->volume = VOLUME_LOW;
06293       d->mute = MUTE_OFF;
06294       d->height = DEFAULTHEIGHT;
06295       d->selected = -1;
06296    } else {
06297       /* Delete existing line information */
06298       AST_LIST_LOCK(&d->lines);
06299       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->lines, l, list){
06300          AST_LIST_REMOVE_CURRENT(list);
06301          unistim_line_destroy(l);
06302       }
06303       AST_LIST_TRAVERSE_SAFE_END
06304       AST_LIST_UNLOCK(&d->lines);
06305 
06306       /* reset bookmarks */
06307       memset(d->softkeylabel, 0, sizeof(d->softkeylabel));
06308       memset(d->softkeynumber, 0, sizeof(d->softkeynumber));
06309       memset(d->softkeyicon, 0, sizeof(d->softkeyicon));
06310       memset(d->softkeydevice, 0, sizeof(d->softkeydevice));
06311       memset(d->ssub, 0, sizeof(d->ssub));
06312       memset(d->sline, 0, sizeof(d->sline));
06313       memset(d->sp, 0, sizeof(d->sp));
06314    }
06315    ast_copy_string(d->context, DEFAULTCONTEXT, sizeof(d->context));
06316    d->selected = -1;
06317    d->interdigit_timer = DEFAULT_INTERDIGIT_TIMER;
06318    linelabel[0] = '\0';
06319    dateformat = 1;
06320    timeformat = 1;
06321    ringvolume = 2;
06322    cwvolume = 1;
06323    callhistory = 1;
06324    sharpdial = 0;
06325    ringstyle = 3;
06326    cwstyle = 2;
06327    nbsoftkey = 0;
06328    linecnt = 0;
06329    while (v) {
06330       if (!strcasecmp(v->name, "rtp_port")) {
06331          d->rtp_port = atoi(v->value);
06332       } else if (!strcasecmp(v->name, "rtp_method")) {
06333          d->rtp_method = atoi(v->value);
06334       } else if (!strcasecmp(v->name, "status_method")) {
06335          d->status_method = atoi(v->value);
06336       } else if (!strcasecmp(v->name, "device")) {
06337          ast_copy_string(d->id, v->value, sizeof(d->id));
06338       } else if (!strcasecmp(v->name, "tn")) {
06339          ast_copy_string(d->extension_number, v->value, sizeof(d->extension_number));
06340       } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
06341          d->ha = ast_append_ha(v->name, v->value, d->ha, NULL);
06342       } else if (!strcasecmp(v->name, "context")) {
06343          ast_copy_string(d->context, v->value, sizeof(d->context));
06344       } else if (!strcasecmp(v->name, "maintext0")) {
06345          unquote(d->maintext0, v->value, sizeof(d->maintext0) - 1);
06346       } else if (!strcasecmp(v->name, "maintext1")) {
06347          unquote(d->maintext1, v->value, sizeof(d->maintext1) - 1);
06348       } else if (!strcasecmp(v->name, "maintext2")) {
06349          unquote(d->maintext2, v->value, sizeof(d->maintext2) - 1);
06350       } else if (!strcasecmp(v->name, "titledefault")) {
06351          unquote(d->titledefault, v->value, sizeof(d->titledefault) - 1);
06352       } else if (!strcasecmp(v->name, "dateformat")) {
06353          dateformat = atoi(v->value);
06354       } else if (!strcasecmp(v->name, "timeformat")) {
06355          timeformat = atoi(v->value);
06356       } else if (!strcasecmp(v->name, "contrast")) {
06357          d->contrast = atoi(v->value);
06358          if ((d->contrast < 0) || (d->contrast > 15)) {
06359             ast_log(LOG_WARNING, "contrast must be beetween 0 and 15\n");
06360             d->contrast = 8;
06361          }
06362       } else if (!strcasecmp(v->name, "nat")) {
06363          d->nat = ast_true(v->value);
06364       } else if (!strcasecmp(v->name, "ringvolume")) {
06365          ringvolume = atoi(v->value);
06366       } else if (!strcasecmp(v->name, "ringstyle")) {
06367          ringstyle = atoi(v->value);
06368       } else if (!strcasecmp(v->name, "cwvolume")) {
06369          cwvolume = atoi(v->value);
06370       } else if (!strcasecmp(v->name, "cwstyle")) {
06371          cwstyle = atoi(v->value);
06372       } else if (!strcasecmp(v->name, "callhistory")) {
06373          callhistory = atoi(v->value);
06374       } else if (!strcasecmp(v->name, "sharpdial")) {
06375          sharpdial = ast_true(v->value) ? 1 : 0;
06376       } else if (!strcasecmp(v->name, "interdigit_timer")) {
06377          d->interdigit_timer = atoi(v->value);
06378       } else if (!strcasecmp(v->name, "callerid")) {
06379          if (!strcasecmp(v->value, "asreceived")) {
06380             lt->cid_num[0] = '\0';
06381          } else {
06382             ast_copy_string(lt->cid_num, v->value, sizeof(lt->cid_num));
06383          }
06384       } else if (!strcasecmp(v->name, "language")) {
06385          ast_copy_string(d->language, v->value, sizeof(d->language));
06386       } else if (!strcasecmp(v->name, "country")) {
06387          ast_copy_string(d->country, v->value, sizeof(d->country));
06388       } else if (!strcasecmp(v->name, "accountcode")) {
06389          ast_copy_string(lt->accountcode, v->value, sizeof(lt->accountcode));
06390       } else if (!strcasecmp(v->name, "amaflags")) {
06391          int y;
06392          y = ast_cdr_amaflags2int(v->value);
06393          if (y < 0) {
06394             ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value,
06395                   v->lineno);
06396          } else {
06397             lt->amaflags = y;
06398          }
06399       } else if (!strcasecmp(v->name, "musiconhold")) {
06400          ast_copy_string(lt->musicclass, v->value, sizeof(lt->musicclass));
06401       } else if (!strcasecmp(v->name, "callgroup")) {
06402          lt->callgroup = ast_get_group(v->value);
06403       } else if (!strcasecmp(v->name, "pickupgroup")) {
06404          lt->pickupgroup = ast_get_group(v->value);
06405       } else if (!strcasecmp(v->name, "mailbox")) {
06406          ast_copy_string(lt->mailbox, v->value, sizeof(lt->mailbox));
06407       } else if (!strcasecmp(v->name, "parkinglot")) {
06408          ast_copy_string(lt->parkinglot, v->value, sizeof(lt->parkinglot));
06409       } else if (!strcasecmp(v->name, "linelabel")) {
06410          unquote(linelabel, v->value, sizeof(linelabel) - 1);
06411       } else if (!strcasecmp(v->name, "extension")) {
06412          if (!strcasecmp(v->value, "none")) {
06413             d->extension = EXTENSION_NONE;
06414          } else if (!strcasecmp(v->value, "ask")) {
06415             d->extension = EXTENSION_ASK;
06416          } else if (!strcasecmp(v->value, "line")) {
06417             d->extension = EXTENSION_LINE;
06418          } else {
06419             ast_log(LOG_WARNING, "Unknown extension option.\n");
06420          }
06421       } else if (!strcasecmp(v->name, "bookmark")) {
06422          if (nbsoftkey > 5) {
06423             ast_log(LOG_WARNING,
06424                   "More than 6 softkeys defined. Ignoring new entries.\n");
06425          } else {
06426             if (parse_bookmark(v->value, d)) {
06427                nbsoftkey++;
06428             }
06429          }
06430       } else if (!strcasecmp(v->name, "line")) {
06431          int len = strlen(linelabel);
06432          int create_line = 0;
06433 
06434          l = find_line_by_number(d, v->value);
06435          if (!l) { /* If line still not exists */
06436             if (!(l = unistim_line_alloc())) {
06437                ast_free(d);
06438                ast_free(lt);
06439                return NULL;
06440             }
06441             lt->cap = l->cap;
06442             memcpy(l, lt, sizeof(*l));
06443             ast_mutex_init(&l->lock);
06444             create_line = 1;
06445          }
06446          d->to_delete = 0;
06447 
06448          /* Set softkey info for new line*/
06449          d->sline[nbsoftkey] = l;
06450          d->softkeyicon[nbsoftkey] = FAV_LINE_ICON;
06451          if (!len) {       /* label is undefined ? */
06452             ast_copy_string(d->softkeylabel[nbsoftkey], v->value, sizeof(d->softkeylabel[nbsoftkey]));
06453          } else {
06454             int softkeylinepos = 0;
06455             if ((len > 2) && (linelabel[1] == '@')) {
06456                softkeylinepos = linelabel[0];
06457                if ((softkeylinepos >= '0') && (softkeylinepos <= '5')) {
06458                   softkeylinepos -= '0';
06459                   d->softkeyicon[nbsoftkey] = FAV_ICON_NONE;
06460                } else {
06461                   ast_log(LOG_WARNING,
06462                         "Invalid position for linelabel : must be between 0 and 5\n");
06463                }
06464                ast_copy_string(d->softkeylabel[softkeylinepos], linelabel + 2,
06465                            sizeof(d->softkeylabel[softkeylinepos]));
06466                d->softkeyicon[softkeylinepos] = FAV_LINE_ICON;
06467             } else {
06468                ast_copy_string(d->softkeylabel[nbsoftkey], linelabel,
06469                            sizeof(d->softkeylabel[nbsoftkey]));
06470             }
06471          }
06472          nbsoftkey++;
06473 
06474          if (create_line) {
06475             ast_copy_string(l->name, v->value, sizeof(l->name));
06476             snprintf(l->fullname, sizeof(l->fullname), "USTM/%s@%s", l->name, d->name);
06477             if (!ast_strlen_zero(l->mailbox)) {
06478                if (unistimdebug) {
06479                   ast_verb(3, "Setting mailbox '%s' on %s@%s\n", l->mailbox, d->name, l->name);
06480                }
06481             }
06482             ast_format_cap_copy(l->cap, global_cap);
06483             l->parent = d;
06484             linecnt++;
06485             AST_LIST_LOCK(&d->lines);
06486             AST_LIST_INSERT_TAIL(&d->lines, l, list);
06487             AST_LIST_UNLOCK(&d->lines);
06488          }
06489       } else if (!strcasecmp(v->name, "height")) {
06490          /* Allow the user to lower the expected display lines on the phone
06491           * For example the Nortel i2001 and i2002 only have one ! */
06492          d->height = atoi(v->value);
06493       } else
06494          ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name,
06495                v->lineno);
06496       v = v->next;
06497    }
06498    ast_free(lt);
06499    if (linecnt == 0) {
06500       ast_log(LOG_ERROR, "An Unistim device must have at least one line!\n");
06501       ast_free(d);
06502       return NULL;
06503    }
06504    d->ringvolume = ringvolume;
06505    d->ringstyle = ringstyle;
06506    d->cwvolume = cwvolume;
06507    d->cwstyle = cwstyle;
06508    d->callhistory = callhistory;
06509    d->sharp_dial = sharpdial;
06510    d->tz = ast_get_indication_zone(d->country);
06511    if ((d->tz == NULL) && !ast_strlen_zero(d->country)) {
06512       ast_log(LOG_WARNING, "Country '%s' was not found in indications.conf\n",
06513             d->country);
06514    }
06515    d->datetimeformat = 56 + (dateformat * 4);
06516    d->datetimeformat += timeformat;
06517    if ((autoprovisioning == AUTOPROVISIONING_TN) &&
06518       (!ast_strlen_zero(d->extension_number))) {
06519       d->extension = EXTENSION_TN;
06520       if (!ast_strlen_zero(d->id)) {
06521          ast_log(LOG_WARNING,
06522                "tn= and device= can't be used together. Ignoring device= entry\n");
06523       }
06524       d->id[0] = 'T';       /* magic : this is a tn entry */
06525       ast_copy_string((d->id) + 1, d->extension_number, sizeof(d->id) - 1);
06526       d->extension_number[0] = '\0';
06527    } else if (ast_strlen_zero(d->id)) {
06528       if (strcmp(d->name, "template")) {
06529          ast_log(LOG_ERROR, "You must specify the mac address with device=\n");
06530          if (d->tz) {
06531             d->tz = ast_tone_zone_unref(d->tz);
06532          }
06533          ast_free(d);
06534          return NULL;
06535       } else {
06536          strcpy(d->id, "000000000000");
06537       }
06538    }
06539    if (!d->rtp_port) {
06540       d->rtp_port = 10000;
06541    }
06542    if (d->contrast == -1) {
06543       d->contrast = 8;
06544    }
06545    if (ast_strlen_zero(d->maintext1)) {
06546       strcpy(d->maintext1, d->name);
06547    }
06548    if (ast_strlen_zero(d->titledefault)) {
06549       struct ast_tm tm = { 0, };
06550       struct timeval cur_time = ast_tvnow();
06551 
06552       if ((ast_localtime(&cur_time, &tm, 0)) == 0 || ast_strlen_zero(tm.tm_zone)) {
06553          ast_log(LOG_WARNING, "Error in ast_localtime()\n");
06554          ast_copy_string(d->titledefault, "UNISTIM for*", 12);
06555       } else {
06556          if (strlen(tm.tm_zone) < 4) {
06557             strcpy(d->titledefault, "TimeZone ");
06558             strcat(d->titledefault, tm.tm_zone);
06559          } else if (strlen(tm.tm_zone) < 9) {
06560             strcpy(d->titledefault, "TZ ");
06561             strcat(d->titledefault, tm.tm_zone);
06562          } else {
06563             ast_copy_string(d->titledefault, tm.tm_zone, 12);
06564          }
06565       }
06566    }
06567    /* Update the chained link if it's a new device */
06568    if (create) {
06569       ast_mutex_lock(&devicelock);
06570       d->next = devices;
06571       devices = d;
06572       ast_mutex_unlock(&devicelock);
06573       ast_verb(3, "Added device '%s'\n", d->name);
06574    } else {
06575       ast_verb(3, "Device '%s' reloaded\n", d->name);
06576    }
06577    return d;
06578 }
06579 
06580 /*--- reload_config: Re-read unistim.conf config file ---*/
06581 static int reload_config(void)
06582 {
06583    struct ast_config *cfg;
06584    struct ast_variable *v;
06585    struct ast_hostent ahp;
06586    struct hostent *hp;
06587    struct sockaddr_in bindaddr = { 0, };
06588    char *config = "unistim.conf";
06589    char *cat;
06590    struct unistim_device *d;
06591    const int reuseFlag = 1;
06592    struct unistimsession *s;
06593    struct ast_flags config_flags = { 0, };
06594 
06595    cfg = ast_config_load(config, config_flags);
06596    /* We *must* have a config file otherwise stop immediately */
06597    if (!cfg) {
06598       ast_log(LOG_ERROR, "Unable to load config %s\n", config);
06599       return -1;
06600    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06601       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
06602       return -1;
06603    }
06604    
06605    /* Copy the default jb config over global_jbconf */
06606    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
06607 
06608    unistim_keepalive = 120;
06609    unistim_port = 0;
06610    v = ast_variable_browse(cfg, "general");
06611    while (v) {
06612       /* handle jb conf */
06613       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
06614          continue;
06615       }
06616       if (!strcasecmp(v->name, "keepalive")) {
06617          unistim_keepalive = atoi(v->value);
06618       } else if (!strcasecmp(v->name, "port")) {
06619          unistim_port = atoi(v->value);
06620       } else if (!strcasecmp(v->name, "tos")) {
06621                         if (ast_str2tos(v->value, &qos.tos)) {
06622                             ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
06623          }
06624                 } else if (!strcasecmp(v->name, "tos_audio")) {
06625                         if (ast_str2tos(v->value, &qos.tos_audio)) {
06626                             ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
06627          }
06628                 } else if (!strcasecmp(v->name, "cos")) {
06629                         if (ast_str2cos(v->value, &qos.cos)) {
06630                             ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
06631          }
06632                 } else if (!strcasecmp(v->name, "cos_audio")) {
06633                         if (ast_str2cos(v->value, &qos.cos_audio)) {
06634                             ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
06635          }
06636       } else if (!strcasecmp(v->name, "debug")) {
06637          if (!strcasecmp(v->value, "no")) {
06638             unistimdebug = 0;
06639          } else if (!strcasecmp(v->value, "yes")) {
06640             unistimdebug = 1;
06641          }
06642       } else if (!strcasecmp(v->name, "autoprovisioning")) {
06643          if (!strcasecmp(v->value, "no")) {
06644             autoprovisioning = AUTOPROVISIONING_NO;
06645          } else if (!strcasecmp(v->value, "yes")) {
06646             autoprovisioning = AUTOPROVISIONING_YES;
06647          } else if (!strcasecmp(v->value, "tn")) {
06648             autoprovisioning = AUTOPROVISIONING_TN;
06649          } else {
06650             ast_log(LOG_WARNING, "Unknown autoprovisioning option.\n");
06651          }
06652       } else if (!strcasecmp(v->name, "public_ip")) {
06653          if (!ast_strlen_zero(v->value)) {
06654             if (!(hp = ast_gethostbyname(v->value, &ahp))) {
06655                ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
06656             } else {
06657                memcpy(&public_ip.sin_addr, hp->h_addr, sizeof(public_ip.sin_addr));
06658                public_ip.sin_family = AF_INET;
06659             }
06660          }
06661       }
06662       v = v->next;
06663    }
06664    if ((unistim_keepalive < 10) ||
06665       (unistim_keepalive >
06666        255 - (((NB_MAX_RETRANSMIT + 1) * RETRANSMIT_TIMER) / 1000))) {
06667       ast_log(LOG_ERROR, "keepalive is invalid in %s\n", config);
06668       ast_config_destroy(cfg);
06669       return -1;
06670    }
06671    packet_send_ping[4] =
06672       unistim_keepalive + (((NB_MAX_RETRANSMIT + 1) * RETRANSMIT_TIMER) / 1000);
06673    if ((unistim_port < 1) || (unistim_port > 65535)) {
06674       ast_log(LOG_ERROR, "port is not set or invalid in %s\n", config);
06675       ast_config_destroy(cfg);
06676       return -1;
06677    }
06678    unistim_keepalive *= 1000;
06679 
06680    ast_mutex_lock(&devicelock);
06681    d = devices;
06682    while (d) {
06683       if (d->to_delete >= 0) {
06684          d->to_delete = 1;
06685       }
06686       d = d->next;
06687    }
06688    ast_mutex_unlock(&devicelock);
06689    /* load the device sections */
06690    cat = ast_category_browse(cfg, NULL);
06691    while (cat) {
06692       if (strcasecmp(cat, "general")) {
06693          d = build_device(cat, ast_variable_browse(cfg, cat));
06694       }
06695       cat = ast_category_browse(cfg, cat);
06696    }
06697    ast_mutex_lock(&devicelock);
06698    d = devices;
06699    while (d) {
06700       if (d->to_delete) {
06701          struct unistim_line *l;
06702          struct unistim_subchannel *sub;
06703 
06704          if (unistimdebug) {
06705             ast_verb(0, "Removing device '%s'\n", d->name);
06706          }
06707          AST_LIST_LOCK(&d->subs);
06708          AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, sub, list){
06709             if (sub->subtype == SUB_REAL) {
06710                if (!sub) {
06711                   ast_log(LOG_ERROR, "Device '%s' without a subchannel !, aborting\n",
06712                         d->name);
06713                   ast_config_destroy(cfg);
06714                   return 0;
06715                }
06716                if (sub->owner) {
06717                   ast_log(LOG_WARNING,
06718                         "Device '%s' was not deleted : a call is in progress. Try again later.\n",
06719                         d->name);
06720                   d = d->next;
06721                   continue;
06722                }
06723             }
06724             if (sub->subtype == SUB_THREEWAY) {
06725                ast_log(LOG_WARNING,
06726                      "Device '%s' with threeway call subchannels allocated, aborting.\n",
06727                      d->name);
06728                break;
06729             }
06730             AST_LIST_REMOVE_CURRENT(list);
06731             ast_mutex_destroy(&sub->lock);
06732             ast_free(sub);
06733          }
06734          AST_LIST_TRAVERSE_SAFE_END
06735          AST_LIST_UNLOCK(&d->subs);
06736 
06737 
06738          AST_LIST_LOCK(&d->lines);
06739          AST_LIST_TRAVERSE_SAFE_BEGIN(&d->lines, l, list){
06740             AST_LIST_REMOVE_CURRENT(list);
06741             ast_mutex_destroy(&l->lock);
06742             unistim_line_destroy(l);
06743          }
06744          AST_LIST_TRAVERSE_SAFE_END
06745          AST_LIST_UNLOCK(&d->lines);
06746 
06747          if (d->session) {
06748             if (sessions == d->session) {
06749                sessions = d->session->next;
06750             } else {
06751                s = sessions;
06752                while (s) {
06753                   if (s->next == d->session) {
06754                      s->next = d->session->next;
06755                      break;
06756                   }
06757                   s = s->next;
06758                }
06759             }
06760             ast_mutex_destroy(&d->session->lock);
06761             ast_free(d->session);
06762          }
06763          if (devices == d) {
06764             devices = d->next;
06765          } else {
06766             struct unistim_device *d2 = devices;
06767             while (d2) {
06768                if (d2->next == d) {
06769                   d2->next = d->next;
06770                   break;
06771                }
06772                d2 = d2->next;
06773             }
06774          }
06775          if (d->tz) {
06776             d->tz = ast_tone_zone_unref(d->tz);
06777          }
06778          ast_mutex_destroy(&d->lock);
06779          ast_free(d);
06780          d = devices;
06781          continue;
06782       }
06783       d = d->next;
06784    }
06785    finish_bookmark();
06786    ast_mutex_unlock(&devicelock);
06787    ast_config_destroy(cfg);
06788    ast_mutex_lock(&sessionlock);
06789    s = sessions;
06790    while (s) {
06791       if (s->device) {
06792          refresh_all_favorite(s);
06793          if (ast_strlen_zero(s->device->language)) {
06794             struct unistim_languages lang;
06795             lang = options_languages[find_language(s->device->language)];
06796             send_charset_update(s, lang.encoding);
06797          }
06798       }
06799       s = s->next;
06800    }
06801    ast_mutex_unlock(&sessionlock);
06802    /* We don't recreate a socket when reloading (locks would be necessary). */
06803    if (unistimsock > -1) {
06804       return 0;
06805    }
06806    bindaddr.sin_addr.s_addr = INADDR_ANY;
06807    bindaddr.sin_port = htons(unistim_port);
06808    bindaddr.sin_family = AF_INET;
06809    unistimsock = socket(AF_INET, SOCK_DGRAM, 0);
06810    if (unistimsock < 0) {
06811       ast_log(LOG_WARNING, "Unable to create UNISTIM socket: %s\n", strerror(errno));
06812       return -1;
06813    }
06814 #ifdef HAVE_PKTINFO
06815    {
06816       const int pktinfoFlag = 1;
06817       setsockopt(unistimsock, IPPROTO_IP, IP_PKTINFO, &pktinfoFlag,
06818                sizeof(pktinfoFlag));
06819    }
06820 #else
06821    if (public_ip.sin_family == 0) {
06822       ast_log(LOG_WARNING,
06823             "Your OS does not support IP_PKTINFO, you must set public_ip.\n");
06824       unistimsock = -1;
06825       return -1;
06826    }
06827 #endif
06828    setsockopt(unistimsock, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuseFlag,
06829             sizeof(reuseFlag));
06830    if (bind(unistimsock, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) < 0) {
06831       ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
06832             ast_inet_ntoa(bindaddr.sin_addr), htons(bindaddr.sin_port),
06833             strerror(errno));
06834       close(unistimsock);
06835       unistimsock = -1;
06836    } else {
06837       ast_verb(2, "UNISTIM Listening on %s:%d\n", ast_inet_ntoa(bindaddr.sin_addr), htons(bindaddr.sin_port));
06838       ast_set_qos(unistimsock, qos.tos, qos.cos, "UNISTIM");
06839    }
06840    return 0;
06841 }
06842 
06843 static enum ast_rtp_glue_result unistim_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
06844 {
06845    struct unistim_subchannel *sub = ast_channel_tech_pvt(chan);
06846 
06847    if (!sub) {
06848       return AST_RTP_GLUE_RESULT_FORBID;
06849    }
06850    if (!sub->rtp) {
06851       return AST_RTP_GLUE_RESULT_FORBID;
06852    }
06853 
06854    ao2_ref(sub->rtp, +1);
06855    *instance = sub->rtp;
06856 
06857    return AST_RTP_GLUE_RESULT_LOCAL;
06858 }
06859 
06860 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)
06861 {
06862    struct unistim_subchannel *sub;
06863    struct sockaddr_in them = { 0, };
06864    struct sockaddr_in us = { 0, };
06865 
06866    if (!rtp) {
06867       return 0;
06868    }
06869    
06870    sub = ast_channel_tech_pvt(chan);
06871    if (!sub) {
06872       ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
06873       return -1;
06874    }
06875    {
06876       struct ast_sockaddr tmp;
06877       ast_rtp_instance_get_remote_address(rtp, &tmp);
06878       ast_sockaddr_to_sin(&tmp, &them);
06879       ast_rtp_instance_get_local_address(rtp, &tmp);
06880       ast_sockaddr_to_sin(&tmp, &us);
06881    }
06882    
06883    /* TODO: Set rtp on phone in case of direct rtp (not implemented) */
06884    
06885    return 0;
06886 }
06887 
06888 static struct ast_rtp_glue unistim_rtp_glue = {
06889    .type = channel_type,
06890    .get_rtp_info = unistim_get_rtp_peer,
06891    .update_peer = unistim_set_rtp_peer,
06892 };
06893 
06894 /*--- load_module: PBX load module - initialization ---*/
06895 int load_module(void)
06896 {
06897    int res;
06898    struct ast_format tmpfmt;
06899    if (!(global_cap = ast_format_cap_alloc())) {
06900       goto buff_failed;
06901    }
06902    if (!(unistim_tech.capabilities = ast_format_cap_alloc())) {
06903       goto buff_failed;
06904    }
06905 
06906    ast_format_cap_add(global_cap, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
06907    ast_format_cap_add(global_cap, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
06908    ast_format_cap_copy(unistim_tech.capabilities, global_cap);
06909    if (!(buff = ast_malloc(SIZE_PAGE))) {
06910       goto buff_failed;
06911    }
06912 
06913    io = io_context_create();
06914    if (!io) {
06915       ast_log(LOG_ERROR, "Failed to allocate IO context\n");
06916       goto io_failed;
06917    }
06918 
06919    sched = ast_sched_context_create();
06920    if (!sched) {
06921       ast_log(LOG_ERROR, "Failed to allocate scheduler context\n");
06922       goto sched_failed;
06923    }
06924 
06925    res = reload_config();
06926    if (res) {
06927       return AST_MODULE_LOAD_DECLINE;
06928    }
06929    /* Make sure we can register our unistim channel type */
06930    if (ast_channel_register(&unistim_tech)) {
06931       ast_log(LOG_ERROR, "Unable to register channel type '%s'\n", channel_type);
06932       goto chanreg_failed;
06933    }
06934 
06935    ast_rtp_glue_register(&unistim_rtp_glue);
06936 
06937    ast_cli_register_multiple(unistim_cli, ARRAY_LEN(unistim_cli));
06938 
06939    restart_monitor();
06940 
06941    return AST_MODULE_LOAD_SUCCESS;
06942 
06943 chanreg_failed:
06944    /*! XXX \todo Leaking anything allocated by reload_config() ... */
06945    ast_sched_context_destroy(sched);
06946    sched = NULL;
06947 sched_failed:
06948    io_context_destroy(io);
06949    io = NULL;
06950 io_failed:
06951    ast_free(buff);
06952    buff = NULL;
06953    global_cap = ast_format_cap_destroy(global_cap);
06954    unistim_tech.capabilities = ast_format_cap_destroy(unistim_tech.capabilities);
06955 buff_failed:
06956    return AST_MODULE_LOAD_FAILURE;
06957 }
06958 
06959 static int unload_module(void)
06960 {
06961    /* First, take us out of the channel loop */
06962    if (sched) {
06963       ast_sched_context_destroy(sched);
06964    }
06965 
06966    ast_cli_unregister_multiple(unistim_cli, ARRAY_LEN(unistim_cli));
06967 
06968    ast_channel_unregister(&unistim_tech);
06969    ast_rtp_glue_unregister(&unistim_rtp_glue);
06970 
06971    ast_mutex_lock(&monlock);
06972    if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
06973       pthread_cancel(monitor_thread);
06974       pthread_kill(monitor_thread, SIGURG);
06975       pthread_join(monitor_thread, NULL);
06976    }
06977    monitor_thread = AST_PTHREADT_STOP;
06978    ast_mutex_unlock(&monlock);
06979 
06980    if (buff) {
06981       ast_free(buff);
06982    }
06983    if (unistimsock > -1) {
06984       close(unistimsock);
06985    }
06986    global_cap = ast_format_cap_destroy(global_cap);
06987    unistim_tech.capabilities = ast_format_cap_destroy(unistim_tech.capabilities);
06988 
06989    return 0;
06990 }
06991 
06992 /*! reload: Part of Asterisk module interface ---*/
06993 int reload(void)
06994 {
06995    if (unistimdebug) {
06996       ast_verb(0, "reload unistim\n");
06997    }
06998    ast_mutex_lock(&unistim_reload_lock);
06999    if (!unistim_reloading) {
07000       unistim_reloading = 1;
07001    }
07002    ast_mutex_unlock(&unistim_reload_lock);
07003 
07004    restart_monitor();
07005 
07006    return 0;
07007 }
07008 
07009 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "UNISTIM Protocol (USTM)",
07010     .load = load_module,
07011     .unload = unload_module,
07012     .reload = reload,
07013 );