Wed Jan 27 20:02:09 2016

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

Generated on 27 Jan 2016 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1