Wed May 16 06:33:30 2012

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

Generated on Wed May 16 06:33:30 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6