Sun Oct 16 2011 08:41:37

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: 328209 $")
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 : (%u) %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 *sdata = (unsigned short *) data;
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    sdata[1] = ntohs(++(pte->seq_server));
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", 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    if (unistimdebug) {
00886       ast_verb(0, "Creating a new entry for the phone from %s received via server ip %s\n",
00887           ast_inet_ntoa(addr_from->sin_addr), ast_inet_ntoa(s->sout.sin_addr));
00888    }
00889    ast_mutex_init(&s->lock);
00890    ast_mutex_lock(&sessionlock);
00891    s->next = sessions;
00892    sessions = s;
00893 
00894    s->timeout = get_tick_count() + RETRANSMIT_TIMER;
00895    s->seq_phone = (short) 0x0000;
00896    s->seq_server = (short) 0x0000;
00897    s->last_seq_ack = (short) 0x000;
00898    s->last_buf_available = 0;
00899    s->nb_retransmit = 0;
00900    s->state = STATE_INIT;
00901    s->tick_next_ping = get_tick_count() + unistim_keepalive;
00902    /* Initialize struct wsabuf  */
00903    for (tmp = 0; tmp < MAX_BUF_NUMBER; tmp++) {
00904       s->wsabufsend[tmp].buf = s->buf[tmp];
00905    }
00906    ast_mutex_unlock(&sessionlock);
00907    return s;
00908 }
00909 
00910 static void send_end_call(struct unistimsession *pte)
00911 {
00912    BUFFSEND;
00913    if (unistimdebug)
00914       ast_verb(0, "Sending end call\n");
00915    memcpy(buffsend + SIZE_HEADER, packet_send_end_call, sizeof(packet_send_end_call));
00916    send_client(SIZE_HEADER + sizeof(packet_send_end_call), buffsend, pte);
00917 }
00918 
00919 static void set_ping_timer(struct unistimsession *pte)
00920 {
00921    unsigned int tick = 0;  /* XXX what is this for, anyways */
00922 
00923    pte->timeout = pte->tick_next_ping;
00924    DEBUG_TIMER("tick = %u next ping at %u tick\n", tick, pte->timeout);
00925    return;
00926 }
00927 
00928 /* Checking if our send queue is empty,
00929  * if true, setting up a timer for keepalive */
00930 static void check_send_queue(struct unistimsession *pte)
00931 {
00932    /* Check if our send queue contained only one element */
00933    if (pte->last_buf_available == 1) {
00934       if (unistimdebug)
00935          ast_verb(6, "Our single packet was ACKed.\n");
00936       pte->last_buf_available--;
00937       set_ping_timer(pte);
00938       return;
00939    }
00940    /* Check if this ACK catch up our latest packet */
00941    else if (pte->last_seq_ack + 1 == pte->seq_server + 1) {
00942       if (unistimdebug)
00943          ast_verb(6, "Our send queue is completely ACKed.\n");
00944       pte->last_buf_available = 0;    /* Purge the send queue */
00945       set_ping_timer(pte);
00946       return;
00947    }
00948    if (unistimdebug)
00949       ast_verb(6, "We still have packets in our send queue\n");
00950    return;
00951 }
00952 
00953 static void send_start_timer(struct unistimsession *pte)
00954 {
00955    BUFFSEND;
00956    if (unistimdebug)
00957       ast_verb(0, "Sending start timer\n");
00958    memcpy(buffsend + SIZE_HEADER, packet_send_StartTimer, sizeof(packet_send_StartTimer));
00959    send_client(SIZE_HEADER + sizeof(packet_send_StartTimer), buffsend, pte);
00960 }
00961 
00962 static void send_stop_timer(struct unistimsession *pte)
00963 {
00964    BUFFSEND;
00965    if (unistimdebug)
00966       ast_verb(0, "Sending stop timer\n");
00967    memcpy(buffsend + SIZE_HEADER, packet_send_stop_timer, sizeof(packet_send_stop_timer));
00968    send_client(SIZE_HEADER + sizeof(packet_send_stop_timer), buffsend, pte);
00969 }
00970 
00971 static void Sendicon(unsigned char pos, unsigned char status, struct unistimsession *pte)
00972 {
00973    BUFFSEND;
00974    if (unistimdebug)
00975       ast_verb(0, "Sending icon pos %d with status 0x%.2x\n", pos, status);
00976    memcpy(buffsend + SIZE_HEADER, packet_send_icon, sizeof(packet_send_icon));
00977    buffsend[9] = pos;
00978    buffsend[10] = status;
00979    send_client(SIZE_HEADER + sizeof(packet_send_icon), buffsend, pte);
00980 }
00981 
00982 static void send_tone(struct unistimsession *pte, uint16_t tone1, uint16_t tone2)
00983 {
00984    BUFFSEND;
00985    if (!tone1) {
00986       if (unistimdebug)
00987          ast_verb(0, "Sending Stream Based Tone Off\n");
00988       memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_off,
00989             sizeof(packet_send_stream_based_tone_off));
00990       send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_off), buffsend, pte);
00991       return;
00992    }
00993    /* Since most of the world use a continuous tone, it's useless
00994       if (unistimdebug)
00995       ast_verb(0, "Sending Stream Based Tone Cadence Download\n");
00996       memcpy (buffsend + SIZE_HEADER, packet_send_StreamBasedToneCad, sizeof (packet_send_StreamBasedToneCad));
00997       send_client (SIZE_HEADER + sizeof (packet_send_StreamBasedToneCad), buffsend, pte); */
00998    if (unistimdebug)
00999       ast_verb(0, "Sending Stream Based Tone Frequency Component List Download %d %d\n", tone1, tone2);
01000    tone1 *= 8;
01001    if (!tone2) {
01002       memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_single_freq,
01003             sizeof(packet_send_stream_based_tone_single_freq));
01004       buffsend[10] = (tone1 & 0xff00) >> 8;
01005       buffsend[11] = (tone1 & 0x00ff);
01006       send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_single_freq), buffsend,
01007                pte);
01008    } else {
01009       tone2 *= 8;
01010       memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_dial_freq,
01011             sizeof(packet_send_stream_based_tone_dial_freq));
01012       buffsend[10] = (tone1 & 0xff00) >> 8;
01013       buffsend[11] = (tone1 & 0x00ff);
01014       buffsend[12] = (tone2 & 0xff00) >> 8;
01015       buffsend[13] = (tone2 & 0x00ff);
01016       send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_dial_freq), buffsend,
01017                pte);
01018    }
01019 
01020    if (unistimdebug)
01021       ast_verb(0, "Sending Stream Based Tone On\n");
01022    memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_on,
01023          sizeof(packet_send_stream_based_tone_on));
01024    send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_on), buffsend, pte);
01025 }
01026 
01027 /* Positions for favorites
01028  |--------------------|
01029  |  5     2    |
01030  |  4     1    |
01031  |  3     0    |
01032 */
01033 
01034 /* status (icons) : 00 = nothing, 2x/3x = see parser.h, 4x/5x = blink fast, 6x/7x = blink slow */
01035 static void
01036 send_favorite(unsigned char pos, unsigned char status, struct unistimsession *pte,
01037           const char *text)
01038 {
01039    BUFFSEND;
01040    int i;
01041 
01042    if (unistimdebug)
01043       ast_verb(0, "Sending favorite pos %d with status 0x%.2x\n", pos, status);
01044    memcpy(buffsend + SIZE_HEADER, packet_send_favorite, sizeof(packet_send_favorite));
01045    buffsend[10] = pos;
01046    buffsend[24] = pos;
01047    buffsend[25] = status;
01048    i = strlen(text);
01049    if (i > FAV_MAX_LENGTH)
01050       i = FAV_MAX_LENGTH;
01051    memcpy(buffsend + FAV_MAX_LENGTH + 1, text, i);
01052    send_client(SIZE_HEADER + sizeof(packet_send_favorite), buffsend, pte);
01053 }
01054 
01055 static void refresh_all_favorite(struct unistimsession *pte)
01056 {
01057    int i = 0;
01058 
01059    if (unistimdebug)
01060       ast_verb(0, "Refreshing all favorite\n");
01061    for (i = 0; i < 6; i++) {
01062       if ((pte->device->softkeyicon[i] <= FAV_ICON_HEADPHONES_ONHOLD) &&
01063          (pte->device->softkeylinepos != i))
01064          send_favorite((unsigned char) i, pte->device->softkeyicon[i] + 1, pte,
01065                    pte->device->softkeylabel[i]);
01066       else
01067          send_favorite((unsigned char) i, pte->device->softkeyicon[i], pte,
01068                    pte->device->softkeylabel[i]);
01069 
01070    }
01071 }
01072 
01073 /* Change the status for this phone (pte) and update for each phones where pte is bookmarked
01074  * use FAV_ICON_*_BLACK constant in status parameters */
01075 static void change_favorite_icon(struct unistimsession *pte, unsigned char status)
01076 {
01077    struct unistim_device *d = devices;
01078    int i;
01079    /* Update the current phone */
01080    if (pte->state != STATE_CLEANING)
01081       send_favorite(pte->device->softkeylinepos, status, pte,
01082                 pte->device->softkeylabel[pte->device->softkeylinepos]);
01083    /* Notify other phones if we're in their bookmark */
01084    while (d) {
01085       for (i = 0; i < 6; i++) {
01086          if (d->sp[i] == pte->device) {  /* It's us ? */
01087             if (d->softkeyicon[i] != status) {      /* Avoid resending the same icon */
01088                d->softkeyicon[i] = status;
01089                if (d->session)
01090                   send_favorite(i, status + 1, d->session, d->softkeylabel[i]);
01091             }
01092          }
01093       }
01094       d = d->next;
01095    }
01096 }
01097 
01098 static int RegisterExtension(const struct unistimsession *pte)
01099 {
01100    if (unistimdebug)
01101       ast_verb(0, "Trying to register extension '%s' into context '%s' to %s\n",
01102                pte->device->extension_number, pte->device->lines->context,
01103                pte->device->lines->fullname);
01104    return ast_add_extension(pte->device->lines->context, 0,
01105                       pte->device->extension_number, 1, NULL, NULL, "Dial",
01106                       pte->device->lines->fullname, 0, "Unistim");
01107 }
01108 
01109 static int UnregisterExtension(const struct unistimsession *pte)
01110 {
01111    if (unistimdebug)
01112       ast_verb(0, "Trying to unregister extension '%s' context '%s'\n",
01113                pte->device->extension_number, pte->device->lines->context);
01114    return ast_context_remove_extension(pte->device->lines->context,
01115                               pte->device->extension_number, 1, "Unistim");
01116 }
01117 
01118 /* Free memory allocated for a phone */
01119 static void close_client(struct unistimsession *s)
01120 {
01121    struct unistim_subchannel *sub;
01122    struct unistimsession *cur, *prev = NULL;
01123    ast_mutex_lock(&sessionlock);
01124    cur = sessions;
01125    /* Looking for the session in the linked chain */
01126    while (cur) {
01127       if (cur == s)
01128          break;
01129       prev = cur;
01130       cur = cur->next;
01131    }
01132    if (cur) {                 /* Session found ? */
01133       if (cur->device) {         /* This session was registered ? */
01134          s->state = STATE_CLEANING;
01135          if (unistimdebug)
01136             ast_verb(0, "close_client session %p device %p lines %p sub %p\n",
01137                      s, s->device, s->device->lines,
01138                      s->device->lines->subs[SUB_REAL]);
01139          change_favorite_icon(s, FAV_ICON_NONE);
01140          sub = s->device->lines->subs[SUB_REAL];
01141          if (sub) {
01142             if (sub->owner) {       /* Call in progress ? */
01143                if (unistimdebug)
01144                   ast_verb(0, "Aborting call\n");
01145                ast_queue_hangup_with_cause(sub->owner, AST_CAUSE_NETWORK_OUT_OF_ORDER);
01146             }
01147          } else
01148             ast_log(LOG_WARNING, "Freeing a client with no subchannel !\n");
01149          if (!ast_strlen_zero(s->device->extension_number))
01150             UnregisterExtension(s);
01151          cur->device->session = NULL;
01152       } else {
01153          if (unistimdebug)
01154             ast_verb(0, "Freeing an unregistered client\n");
01155       }
01156       if (prev)
01157          prev->next = cur->next;
01158       else
01159          sessions = cur->next;
01160       ast_mutex_destroy(&s->lock);
01161       ast_free(s);
01162    } else
01163       ast_log(LOG_WARNING, "Trying to delete non-existent session %p?\n", s);
01164    ast_mutex_unlock(&sessionlock);
01165    return;
01166 }
01167 
01168 /* Return 1 if the session chained link was modified */
01169 static int send_retransmit(struct unistimsession *pte)
01170 {
01171    int i;
01172 
01173    ast_mutex_lock(&pte->lock);
01174    if (++pte->nb_retransmit >= NB_MAX_RETRANSMIT) {
01175       if (unistimdebug)
01176          ast_verb(0, "Too many retransmit - freeing client\n");
01177       ast_mutex_unlock(&pte->lock);
01178       close_client(pte);
01179       return 1;
01180    }
01181    pte->timeout = get_tick_count() + RETRANSMIT_TIMER;
01182 
01183    for (i = pte->last_buf_available - (pte->seq_server - pte->last_seq_ack);
01184        i < pte->last_buf_available; i++) {
01185       if (i < 0) {
01186          ast_log(LOG_WARNING,
01187                "Asked to retransmit an ACKed slot ! last_buf_available=%d, seq_server = #0x%.4x last_seq_ack = #0x%.4x\n",
01188                pte->last_buf_available, pte->seq_server, pte->last_seq_ack);
01189          continue;
01190       }
01191 
01192       if (unistimdebug) {
01193          unsigned short *sbuf = (unsigned short *) pte->wsabufsend[i].buf;
01194          unsigned short seq;
01195 
01196          seq = ntohs(sbuf[1]);
01197          ast_verb(0, "Retransmit slot #%d (seq=#0x%.4x), last ack was #0x%.4x\n", i,
01198                   seq, pte->last_seq_ack);
01199       }
01200       send_raw_client(pte->wsabufsend[i].len, pte->wsabufsend[i].buf, &pte->sin,
01201                  &pte->sout);
01202    }
01203    ast_mutex_unlock(&pte->lock);
01204    return 0;
01205 }
01206 
01207 /* inverse : TEXT_INVERSE : yes, TEXT_NORMAL  : no */
01208 static void
01209 send_text(unsigned char pos, unsigned char inverse, struct unistimsession *pte,
01210        const char *text)
01211 {
01212    int i;
01213    BUFFSEND;
01214    if (unistimdebug)
01215       ast_verb(0, "Sending text at pos %d, inverse flag %d\n", pos, inverse);
01216    memcpy(buffsend + SIZE_HEADER, packet_send_text, sizeof(packet_send_text));
01217    buffsend[10] = pos;
01218    buffsend[11] = inverse;
01219    i = strlen(text);
01220    if (i > TEXT_LENGTH_MAX)
01221       i = TEXT_LENGTH_MAX;
01222    memcpy(buffsend + 12, text, i);
01223    send_client(SIZE_HEADER + sizeof(packet_send_text), buffsend, pte);
01224 }
01225 
01226 static void send_text_status(struct unistimsession *pte, const char *text)
01227 {
01228    BUFFSEND;
01229    int i;
01230    if (unistimdebug)
01231       ast_verb(0, "Sending status text\n");
01232    if (pte->device) {
01233       if (pte->device->status_method == 1) {  /* For new firmware and i2050 soft phone */
01234          int n = strlen(text);
01235          /* Must send individual button separately */
01236          int j;
01237          for (i = 0, j = 0; i < 4; i++, j += 7) {
01238             int pos = 0x08 + (i * 0x20);
01239             memcpy(buffsend + SIZE_HEADER, packet_send_status2,
01240                   sizeof(packet_send_status2));
01241 
01242             buffsend[9] = pos;
01243             memcpy(buffsend + 10, (j < n) ? (text + j) : "       ", 7);
01244             send_client(SIZE_HEADER + sizeof(packet_send_status2), buffsend, pte);
01245          }
01246          return;
01247       }
01248    }
01249 
01250 
01251    memcpy(buffsend + SIZE_HEADER, packet_send_status, sizeof(packet_send_status));
01252    i = strlen(text);
01253    if (i > STATUS_LENGTH_MAX)
01254       i = STATUS_LENGTH_MAX;
01255    memcpy(buffsend + 10, text, i);
01256    send_client(SIZE_HEADER + sizeof(packet_send_status), buffsend, pte);
01257 
01258 }
01259 
01260 /* led values in hexa : 0 = bar off, 1 = bar on, 2 = bar 1s on/1s off, 3 = bar 2.5s on/0.5s off
01261  * 4 = bar 0.6s on/0.3s off, 5 = bar 0.5s on/0.5s off, 6 = bar 2s on/0.5s off
01262  * 7 = bar off, 8 = speaker off, 9 = speaker on, 10 = headphone off, 11 = headphone on
01263  * 18 = mute off, 19 mute on */
01264 static void send_led_update(struct unistimsession *pte, unsigned char led)
01265 {
01266    BUFFSEND;
01267    if (unistimdebug)
01268       ast_verb(0, "Sending led_update (%x)\n", led);
01269    memcpy(buffsend + SIZE_HEADER, packet_send_led_update, sizeof(packet_send_led_update));
01270    buffsend[9] = led;
01271    send_client(SIZE_HEADER + sizeof(packet_send_led_update), buffsend, pte);
01272 }
01273 
01274 /* output = OUTPUT_HANDSET, OUTPUT_HEADPHONE or OUTPUT_SPEAKER
01275  * volume = VOLUME_LOW, VOLUME_NORMAL, VOLUME_INSANELY_LOUD
01276  * mute = MUTE_OFF, MUTE_ON */
01277 static void
01278 send_select_output(struct unistimsession *pte, unsigned char output, unsigned char volume,
01279              unsigned char mute)
01280 {
01281    BUFFSEND;
01282    if (unistimdebug)
01283       ast_verb(0, "Sending select output packet output=%x volume=%x mute=%x\n", output,
01284                volume, mute);
01285    memcpy(buffsend + SIZE_HEADER, packet_send_select_output,
01286          sizeof(packet_send_select_output));
01287    buffsend[9] = output;
01288    if (output == OUTPUT_SPEAKER)
01289       volume = VOLUME_LOW_SPEAKER;
01290    else
01291       volume = VOLUME_LOW;
01292    buffsend[10] = volume;
01293    if (mute == MUTE_ON_DISCRET)
01294       buffsend[11] = MUTE_ON;
01295    else
01296       buffsend[11] = mute;
01297    send_client(SIZE_HEADER + sizeof(packet_send_select_output), buffsend, pte);
01298    if (mute == MUTE_OFF)
01299       send_led_update(pte, 0x18);
01300    else if (mute == MUTE_ON)
01301       send_led_update(pte, 0x19);
01302    pte->device->mute = mute;
01303    if (output == OUTPUT_HANDSET) {
01304       if (mute == MUTE_ON)
01305          change_favorite_icon(pte, FAV_ICON_ONHOLD_BLACK);
01306       else
01307          change_favorite_icon(pte, FAV_ICON_OFFHOOK_BLACK);
01308       send_led_update(pte, 0x08);
01309       send_led_update(pte, 0x10);
01310    } else if (output == OUTPUT_HEADPHONE) {
01311       if (mute == MUTE_ON)
01312          change_favorite_icon(pte, FAV_ICON_HEADPHONES_ONHOLD);
01313       else
01314          change_favorite_icon(pte, FAV_ICON_HEADPHONES);
01315       send_led_update(pte, 0x08);
01316       send_led_update(pte, 0x11);
01317    } else if (output == OUTPUT_SPEAKER) {
01318       send_led_update(pte, 0x10);
01319       send_led_update(pte, 0x09);
01320       if (pte->device->receiver_state == STATE_OFFHOOK) {
01321          if (mute == MUTE_ON)
01322             change_favorite_icon(pte, FAV_ICON_SPEAKER_ONHOLD_BLACK);
01323          else
01324             change_favorite_icon(pte, FAV_ICON_SPEAKER_ONHOOK_BLACK);
01325       } else {
01326          if (mute == MUTE_ON)
01327             change_favorite_icon(pte, FAV_ICON_SPEAKER_ONHOLD_BLACK);
01328          else
01329             change_favorite_icon(pte, FAV_ICON_SPEAKER_OFFHOOK_BLACK);
01330       }
01331    } else
01332       ast_log(LOG_WARNING, "Invalid output (%d)\n", output);
01333    if (output != pte->device->output)
01334       pte->device->previous_output = pte->device->output;
01335    pte->device->output = output;
01336 }
01337 
01338 static void send_ring(struct unistimsession *pte, char volume, char style)
01339 {
01340    BUFFSEND;
01341    if (unistimdebug)
01342       ast_verb(0, "Sending ring packet\n");
01343    memcpy(buffsend + SIZE_HEADER, packet_send_ring, sizeof(packet_send_ring));
01344    buffsend[24] = style + 0x10;
01345    buffsend[29] = volume * 0x10;
01346    send_client(SIZE_HEADER + sizeof(packet_send_ring), buffsend, pte);
01347 }
01348 
01349 static void send_no_ring(struct unistimsession *pte)
01350 {
01351    BUFFSEND;
01352    if (unistimdebug)
01353       ast_verb(0, "Sending no ring packet\n");
01354    memcpy(buffsend + SIZE_HEADER, packet_send_no_ring, sizeof(packet_send_no_ring));
01355    send_client(SIZE_HEADER + sizeof(packet_send_no_ring), buffsend, pte);
01356 }
01357 
01358 static void send_texttitle(struct unistimsession *pte, const char *text)
01359 {
01360    BUFFSEND;
01361    int i;
01362    if (unistimdebug)
01363       ast_verb(0, "Sending title text\n");
01364    memcpy(buffsend + SIZE_HEADER, packet_send_title, sizeof(packet_send_title));
01365    i = strlen(text);
01366    if (i > 12)
01367       i = 12;
01368    memcpy(buffsend + 10, text, i);
01369    send_client(SIZE_HEADER + sizeof(packet_send_title), buffsend, pte);
01370 
01371 }
01372 
01373 static void send_date_time(struct unistimsession *pte)
01374 {
01375    BUFFSEND;
01376    struct timeval now = ast_tvnow();
01377    struct ast_tm atm = { 0, };
01378 
01379    if (unistimdebug)
01380       ast_verb(0, "Sending Time & Date\n");
01381    memcpy(buffsend + SIZE_HEADER, packet_send_date_time, sizeof(packet_send_date_time));
01382    ast_localtime(&now, &atm, NULL);
01383    buffsend[10] = (unsigned char) atm.tm_mon + 1;
01384    buffsend[11] = (unsigned char) atm.tm_mday;
01385    buffsend[12] = (unsigned char) atm.tm_hour;
01386    buffsend[13] = (unsigned char) atm.tm_min;
01387    send_client(SIZE_HEADER + sizeof(packet_send_date_time), buffsend, pte);
01388 }
01389 
01390 static void send_date_time2(struct unistimsession *pte)
01391 {
01392    BUFFSEND;
01393    struct timeval now = ast_tvnow();
01394    struct ast_tm atm = { 0, };
01395 
01396    if (unistimdebug)
01397       ast_verb(0, "Sending Time & Date #2\n");
01398    memcpy(buffsend + SIZE_HEADER, packet_send_date_time2, sizeof(packet_send_date_time2));
01399    ast_localtime(&now, &atm, NULL);
01400    if (pte->device)
01401       buffsend[9] = pte->device->datetimeformat;
01402    else
01403       buffsend[9] = 61;
01404    buffsend[14] = (unsigned char) atm.tm_mon + 1;
01405    buffsend[15] = (unsigned char) atm.tm_mday;
01406    buffsend[16] = (unsigned char) atm.tm_hour;
01407    buffsend[17] = (unsigned char) atm.tm_min;
01408    send_client(SIZE_HEADER + sizeof(packet_send_date_time2), buffsend, pte);
01409 }
01410 
01411 static void send_date_time3(struct unistimsession *pte)
01412 {
01413    BUFFSEND;
01414    struct timeval now = ast_tvnow();
01415    struct ast_tm atm = { 0, };
01416 
01417    if (unistimdebug)
01418       ast_verb(0, "Sending Time & Date #3\n");
01419    memcpy(buffsend + SIZE_HEADER, packet_send_date_time3, sizeof(packet_send_date_time3));
01420    ast_localtime(&now, &atm, NULL);
01421    buffsend[10] = (unsigned char) atm.tm_mon + 1;
01422    buffsend[11] = (unsigned char) atm.tm_mday;
01423    buffsend[12] = (unsigned char) atm.tm_hour;
01424    buffsend[13] = (unsigned char) atm.tm_min;
01425    send_client(SIZE_HEADER + sizeof(packet_send_date_time3), buffsend, pte);
01426 }
01427 
01428 static void send_blink_cursor(struct unistimsession *pte)
01429 {
01430    BUFFSEND;
01431    if (unistimdebug)
01432       ast_verb(0, "Sending set blink\n");
01433    memcpy(buffsend + SIZE_HEADER, packet_send_blink_cursor, sizeof(packet_send_blink_cursor));
01434    send_client(SIZE_HEADER + sizeof(packet_send_blink_cursor), buffsend, pte);
01435    return;
01436 }
01437 
01438 /* pos : 0xab (a=0/2/4 = line ; b = row) */
01439 static void send_cursor_pos(struct unistimsession *pte, unsigned char pos)
01440 {
01441    BUFFSEND;
01442    if (unistimdebug)
01443       ast_verb(0, "Sending set cursor position\n");
01444    memcpy(buffsend + SIZE_HEADER, packet_send_set_pos_cursor,
01445          sizeof(packet_send_set_pos_cursor));
01446    buffsend[11] = pos;
01447    send_client(SIZE_HEADER + sizeof(packet_send_set_pos_cursor), buffsend, pte);
01448    return;
01449 }
01450 
01451 static void rcv_resume_connection_with_server(struct unistimsession *pte)
01452 {
01453    BUFFSEND;
01454    if (unistimdebug) {
01455       ast_verb(0, "ResumeConnectionWithServer received\n");
01456       ast_verb(0, "Sending packet_send_query_mac_address\n");
01457    }
01458    memcpy(buffsend + SIZE_HEADER, packet_send_query_mac_address,
01459          sizeof(packet_send_query_mac_address));
01460    send_client(SIZE_HEADER + sizeof(packet_send_query_mac_address), buffsend, pte);
01461    return;
01462 }
01463 
01464 static int unistim_register(struct unistimsession *s)
01465 {
01466    struct unistim_device *d;
01467 
01468    ast_mutex_lock(&devicelock);
01469    d = devices;
01470    while (d) {
01471       if (!strcasecmp(s->macaddr, d->id)) {
01472          /* XXX Deal with IP authentication */
01473          s->device = d;
01474          d->session = s;
01475          d->codec_number = DEFAULT_CODEC;
01476          d->pos_fav = 0;
01477          d->missed_call = 0;
01478          d->receiver_state = STATE_ONHOOK;
01479          break;
01480       }
01481       d = d->next;
01482    }
01483    ast_mutex_unlock(&devicelock);
01484 
01485    if (!d)
01486       return 0;
01487 
01488    return 1;
01489 }
01490 
01491 static int alloc_sub(struct unistim_line *l, int x)
01492 {
01493    struct unistim_subchannel *sub;
01494    if (!(sub = ast_calloc(1, sizeof(*sub))))
01495       return 0;
01496 
01497    if (unistimdebug)
01498       ast_verb(3, "Allocating UNISTIM subchannel #%d on %s@%s ptr=%p\n", x, l->name, l->parent->name, sub);
01499    sub->parent = l;
01500    sub->subtype = x;
01501    l->subs[x] = sub;
01502    ast_mutex_init(&sub->lock);
01503    return 1;
01504 }
01505 
01506 static int unalloc_sub(struct unistim_line *p, int x)
01507 {
01508    if (!x) {
01509       ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name,
01510             p->parent->name);
01511       return -1;
01512    }
01513    if (unistimdebug)
01514       ast_debug(1, "Released sub %d of channel %s@%s\n", x, p->name,
01515             p->parent->name);
01516    ast_mutex_destroy(&p->lock);
01517    ast_free(p->subs[x]);
01518    p->subs[x] = 0;
01519    return 0;
01520 }
01521 
01522 static void rcv_mac_addr(struct unistimsession *pte, const unsigned char *buf)
01523 {
01524    BUFFSEND;
01525    int tmp, i = 0;
01526    char addrmac[19];
01527    int res = 0;
01528    if (unistimdebug)
01529       ast_verb(0, "Mac Address received : ");
01530    for (tmp = 15; tmp < 15 + SIZE_HEADER; tmp++) {
01531       sprintf(&addrmac[i], "%.2x", (unsigned char) buf[tmp]);
01532       i += 2;
01533    }
01534    if (unistimdebug)
01535       ast_verb(0, "%s\n", addrmac);
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 = %d\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 : %d\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 (peera->cdr && peerb->cdr) {
01928          peerb->cdr = ast_cdr_append(peerb->cdr, peera->cdr);
01929       } else if (peera->cdr) {
01930          peerb->cdr = peera->cdr;
01931       }
01932       peera->cdr = NULL;
01933 
01934       if (peerb->cdr && peerc->cdr) {
01935          peerb->cdr = ast_cdr_append(peerb->cdr, peerc->cdr);
01936       } else if (peerc->cdr) {
01937          peerb->cdr = peerc->cdr;
01938       }
01939       peerc->cdr = NULL;
01940 
01941       if (ast_channel_masquerade(peerb, peerc)) {
01942          ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", peerb->name,
01943                peerc->name);
01944          res = -1;
01945       }
01946       return res;
01947    } else {
01948       ast_log(LOG_NOTICE,
01949             "Transfer attempted with no appropriate bridged calls to transfer\n");
01950       if (chana)
01951          ast_softhangup_nolock(chana, AST_SOFTHANGUP_DEV);
01952       if (chanb)
01953          ast_softhangup_nolock(chanb, AST_SOFTHANGUP_DEV);
01954       return -1;
01955    }
01956    return 0;
01957 }
01958 
01959 void change_callerid(struct unistimsession *pte, int type, char *callerid)
01960 {
01961    char *data;
01962    int size;
01963 
01964    if (type)
01965       data = pte->device->lst_cnm;
01966    else
01967       data = pte->device->lst_cid;
01968 
01969    /* This is very nearly strncpy(), except that the remaining buffer
01970     * is padded with ' ', instead of '\0' */
01971    memset(data, ' ', TEXT_LENGTH_MAX);
01972    size = strlen(callerid);
01973    if (size > TEXT_LENGTH_MAX)
01974       size = TEXT_LENGTH_MAX;
01975    memcpy(data, callerid, size);
01976 }
01977 
01978 static void close_call(struct unistimsession *pte)
01979 {
01980    struct unistim_subchannel *sub;
01981    struct unistim_line *l = pte->device->lines;
01982 
01983    sub = pte->device->lines->subs[SUB_REAL];
01984    send_stop_timer(pte);
01985    if (sub->owner) {
01986       sub->alreadygone = 1;
01987       if (l->subs[SUB_THREEWAY]) {
01988          l->subs[SUB_THREEWAY]->alreadygone = 1;
01989          if (attempt_transfer(sub, l->subs[SUB_THREEWAY]) < 0)
01990             ast_verb(0, "attempt_transfer failed.\n");
01991       } else
01992          ast_queue_hangup(sub->owner);
01993    } else {
01994       if (l->subs[SUB_THREEWAY]) {
01995          if (l->subs[SUB_THREEWAY]->owner)
01996             ast_queue_hangup_with_cause(l->subs[SUB_THREEWAY]->owner, AST_CAUSE_NORMAL_CLEARING);
01997          else
01998             ast_log(LOG_WARNING, "threeway sub without owner\n");
01999       } else
02000          ast_verb(0, "USTM(%s@%s-%d) channel already destroyed\n", sub->parent->name,
02001                   sub->parent->parent->name, sub->subtype);
02002    }
02003    change_callerid(pte, 0, pte->device->redial_number);
02004    change_callerid(pte, 1, "");
02005    write_history(pte, 'o', pte->device->missed_call);
02006    pte->device->missed_call = 0;
02007    show_main_page(pte);
02008    return;
02009 }
02010 
02011 static void IgnoreCall(struct unistimsession *pte)
02012 {
02013    send_no_ring(pte);
02014    return;
02015 }
02016 
02017 static void *unistim_ss(void *data)
02018 {
02019    struct ast_channel *chan = data;
02020    struct unistim_subchannel *sub = chan->tech_pvt;
02021    struct unistim_line *l = sub->parent;
02022    struct unistimsession *s = l->parent->session;
02023    int res;
02024 
02025    ast_verb(3, "Starting switch on '%s@%s-%d' to %s\n", l->name, l->parent->name, sub->subtype, s->device->phone_number);
02026    ast_copy_string(chan->exten, s->device->phone_number, sizeof(chan->exten));
02027    ast_copy_string(s->device->redial_number, s->device->phone_number,
02028                sizeof(s->device->redial_number));
02029    ast_setstate(chan, AST_STATE_RING);
02030    res = ast_pbx_run(chan);
02031    if (res) {
02032       ast_log(LOG_WARNING, "PBX exited non-zero\n");
02033       send_tone(s, 1000, 0);;
02034    }
02035    return NULL;
02036 }
02037 
02038 static void start_rtp(struct unistim_subchannel *sub)
02039 {
02040    BUFFSEND;
02041    struct sockaddr_in us = { 0, };
02042    struct sockaddr_in public = { 0, };
02043    struct sockaddr_in sin = { 0, };
02044    format_t codec;
02045    struct sockaddr_in sout = { 0, };
02046    struct ast_sockaddr us_tmp;
02047    struct ast_sockaddr sin_tmp;
02048    struct ast_sockaddr sout_tmp;
02049 
02050    /* Sanity checks */
02051    if (!sub) {
02052       ast_log(LOG_WARNING, "start_rtp with a null subchannel !\n");
02053       return;
02054    }
02055    if (!sub->parent) {
02056       ast_log(LOG_WARNING, "start_rtp with a null line !\n");
02057       return;
02058    }
02059    if (!sub->parent->parent) {
02060       ast_log(LOG_WARNING, "start_rtp with a null device !\n");
02061       return;
02062    }
02063    if (!sub->parent->parent->session) {
02064       ast_log(LOG_WARNING, "start_rtp with a null session !\n");
02065       return;
02066    }
02067    sout = sub->parent->parent->session->sout;
02068 
02069    ast_mutex_lock(&sub->lock);
02070    /* Allocate the RTP */
02071    if (unistimdebug)
02072       ast_verb(0, "Starting RTP. Bind on %s\n", ast_inet_ntoa(sout.sin_addr));
02073    ast_sockaddr_from_sin(&sout_tmp, &sout);
02074    sub->rtp = ast_rtp_instance_new("asterisk", sched, &sout_tmp, NULL);
02075    if (!sub->rtp) {
02076       ast_log(LOG_WARNING, "Unable to create RTP session: %s binaddr=%s\n",
02077             strerror(errno), ast_inet_ntoa(sout.sin_addr));
02078       ast_mutex_unlock(&sub->lock);
02079       return;
02080    }
02081    ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_RTCP, 1);
02082    if (sub->owner) {
02083       sub->owner->fds[0] = ast_rtp_instance_fd(sub->rtp, 0);
02084       sub->owner->fds[1] = ast_rtp_instance_fd(sub->rtp, 1);
02085    }
02086    ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "UNISTIM RTP");
02087    ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, sub->parent->parent->nat);
02088 
02089    /* Create the RTP connection */
02090    ast_rtp_instance_get_local_address(sub->rtp, &us_tmp);
02091    ast_sockaddr_to_sin(&us_tmp, &us);
02092    sin.sin_family = AF_INET;
02093    /* Setting up RTP for our side */
02094    memcpy(&sin.sin_addr, &sub->parent->parent->session->sin.sin_addr,
02095          sizeof(sin.sin_addr));
02096    sin.sin_port = htons(sub->parent->parent->rtp_port);
02097    ast_sockaddr_from_sin(&sin_tmp, &sin);
02098    ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
02099    if (!(sub->owner->nativeformats & sub->owner->readformat)) {
02100       format_t fmt;
02101       char tmp[256];
02102       fmt = ast_best_codec(sub->owner->nativeformats);
02103       ast_log(LOG_WARNING,
02104             "Our read/writeformat has been changed to something incompatible: %s, using %s best codec from %s\n",
02105             ast_getformatname(sub->owner->readformat),
02106             ast_getformatname(fmt),
02107             ast_getformatname_multiple(tmp, sizeof(tmp), sub->owner->nativeformats));
02108       sub->owner->readformat = fmt;
02109       sub->owner->writeformat = fmt;
02110    }
02111    codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, sub->owner->readformat);
02112    /* Setting up RTP of the phone */
02113    if (public_ip.sin_family == 0)  /* NAT IP override ?   */
02114       memcpy(&public, &us, sizeof(public));   /* No defined, using IP from recvmsg  */
02115    else
02116       memcpy(&public, &public_ip, sizeof(public));    /* override  */
02117    if (unistimdebug) {
02118       ast_verb(0, "RTP started : Our IP/port is : %s:%hd with codec %s\n",
02119           ast_inet_ntoa(us.sin_addr),
02120           htons(us.sin_port), ast_getformatname(sub->owner->readformat));
02121       ast_verb(0, "Starting phone RTP stack. Our public IP is %s\n",
02122                ast_inet_ntoa(public.sin_addr));
02123    }
02124    if ((sub->owner->readformat == AST_FORMAT_ULAW) ||
02125       (sub->owner->readformat == AST_FORMAT_ALAW)) {
02126       if (unistimdebug)
02127          ast_verb(0, "Sending packet_send_rtp_packet_size for codec %s\n", ast_getformatname(codec));
02128       memcpy(buffsend + SIZE_HEADER, packet_send_rtp_packet_size,
02129             sizeof(packet_send_rtp_packet_size));
02130       buffsend[10] = (int) codec & 0xffffffffLL;
02131       send_client(SIZE_HEADER + sizeof(packet_send_rtp_packet_size), buffsend,
02132                sub->parent->parent->session);
02133    }
02134    if (unistimdebug)
02135       ast_verb(0, "Sending Jitter Buffer Parameters Configuration\n");
02136    memcpy(buffsend + SIZE_HEADER, packet_send_jitter_buffer_conf,
02137          sizeof(packet_send_jitter_buffer_conf));
02138    send_client(SIZE_HEADER + sizeof(packet_send_jitter_buffer_conf), buffsend,
02139             sub->parent->parent->session);
02140    if (sub->parent->parent->rtp_method != 0) {
02141       uint16_t rtcpsin_port = htons(us.sin_port) + 1; /* RTCP port is RTP + 1 */
02142 
02143       if (unistimdebug)
02144          ast_verb(0, "Sending OpenAudioStreamTX using method #%d\n",
02145                   sub->parent->parent->rtp_method);
02146       if (sub->parent->parent->rtp_method == 3)
02147          memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_tx3,
02148                sizeof(packet_send_open_audio_stream_tx3));
02149       else
02150          memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_tx,
02151                sizeof(packet_send_open_audio_stream_tx));
02152       if (sub->parent->parent->rtp_method != 2) {
02153          memcpy(buffsend + 28, &public.sin_addr, sizeof(public.sin_addr));
02154          buffsend[20] = (htons(sin.sin_port) & 0xff00) >> 8;
02155          buffsend[21] = (htons(sin.sin_port) & 0x00ff);
02156          buffsend[23] = (rtcpsin_port & 0x00ff);
02157          buffsend[22] = (rtcpsin_port & 0xff00) >> 8;
02158          buffsend[25] = (us.sin_port & 0xff00) >> 8;
02159          buffsend[24] = (us.sin_port & 0x00ff);
02160          buffsend[27] = (rtcpsin_port & 0x00ff);
02161          buffsend[26] = (rtcpsin_port & 0xff00) >> 8;
02162       } else {
02163          memcpy(buffsend + 23, &public.sin_addr, sizeof(public.sin_addr));
02164          buffsend[15] = (htons(sin.sin_port) & 0xff00) >> 8;
02165          buffsend[16] = (htons(sin.sin_port) & 0x00ff);
02166          buffsend[20] = (us.sin_port & 0xff00) >> 8;
02167          buffsend[19] = (us.sin_port & 0x00ff);
02168          buffsend[11] = codec;
02169       }
02170       buffsend[12] = codec;
02171       send_client(SIZE_HEADER + sizeof(packet_send_open_audio_stream_tx), buffsend,
02172                sub->parent->parent->session);
02173 
02174       if (unistimdebug)
02175          ast_verb(0, "Sending OpenAudioStreamRX\n");
02176       if (sub->parent->parent->rtp_method == 3)
02177          memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_rx3,
02178                sizeof(packet_send_open_audio_stream_rx3));
02179       else
02180          memcpy(buffsend + SIZE_HEADER, packet_send_open_audio_stream_rx,
02181                sizeof(packet_send_open_audio_stream_rx));
02182       if (sub->parent->parent->rtp_method != 2) {
02183          memcpy(buffsend + 28, &public.sin_addr, sizeof(public.sin_addr));
02184          buffsend[20] = (htons(sin.sin_port) & 0xff00) >> 8;
02185          buffsend[21] = (htons(sin.sin_port) & 0x00ff);
02186          buffsend[23] = (rtcpsin_port & 0x00ff);
02187          buffsend[22] = (rtcpsin_port & 0xff00) >> 8;
02188          buffsend[25] = (us.sin_port & 0xff00) >> 8;
02189          buffsend[24] = (us.sin_port & 0x00ff);
02190          buffsend[27] = (rtcpsin_port & 0x00ff);
02191          buffsend[26] = (rtcpsin_port & 0xff00) >> 8;
02192       } else {
02193          memcpy(buffsend + 23, &public.sin_addr, sizeof(public.sin_addr));
02194          buffsend[15] = (htons(sin.sin_port) & 0xff00) >> 8;
02195          buffsend[16] = (htons(sin.sin_port) & 0x00ff);
02196          buffsend[20] = (us.sin_port & 0xff00) >> 8;
02197          buffsend[19] = (us.sin_port & 0x00ff);
02198          buffsend[12] = codec;
02199       }
02200       buffsend[11] = codec;
02201       send_client(SIZE_HEADER + sizeof(packet_send_open_audio_stream_rx), buffsend,
02202                sub->parent->parent->session);
02203    } else {
02204       uint16_t rtcpsin_port = htons(us.sin_port) + 1; /* RTCP port is RTP + 1 */
02205 
02206       if (unistimdebug)
02207          ast_verb(0, "Sending packet_send_call default method\n");
02208 
02209       memcpy(buffsend + SIZE_HEADER, packet_send_call, sizeof(packet_send_call));
02210       memcpy(buffsend + 53, &public.sin_addr, sizeof(public.sin_addr));
02211       /* Destination port when sending RTP */
02212       buffsend[49] = (us.sin_port & 0x00ff);
02213       buffsend[50] = (us.sin_port & 0xff00) >> 8;
02214       /* Destination port when sending RTCP */
02215       buffsend[52] = (rtcpsin_port & 0x00ff);
02216       buffsend[51] = (rtcpsin_port & 0xff00) >> 8;
02217       /* Codec */
02218       buffsend[40] = codec;
02219       buffsend[41] = codec;
02220       if (sub->owner->readformat == AST_FORMAT_ULAW)
02221          buffsend[42] = 1;       /* 1 = 20ms (160 bytes), 2 = 40ms (320 bytes) */
02222       else if (sub->owner->readformat == AST_FORMAT_ALAW)
02223          buffsend[42] = 1;       /* 1 = 20ms (160 bytes), 2 = 40ms (320 bytes) */
02224       else if (sub->owner->readformat == AST_FORMAT_G723_1)
02225          buffsend[42] = 2;       /* 1 = 30ms (24 bytes), 2 = 60 ms (48 bytes) */
02226       else if (sub->owner->readformat == AST_FORMAT_G729A)
02227          buffsend[42] = 2;       /* 1 = 10ms (10 bytes), 2 = 20ms (20 bytes) */
02228       else
02229          ast_log(LOG_WARNING, "Unsupported codec %s!\n",
02230                ast_getformatname(sub->owner->readformat));
02231       /* Source port for transmit RTP and Destination port for receiving RTP */
02232       buffsend[45] = (htons(sin.sin_port) & 0xff00) >> 8;
02233       buffsend[46] = (htons(sin.sin_port) & 0x00ff);
02234       buffsend[47] = (rtcpsin_port & 0xff00) >> 8;
02235       buffsend[48] = (rtcpsin_port & 0x00ff);
02236       send_client(SIZE_HEADER + sizeof(packet_send_call), buffsend,
02237                sub->parent->parent->session);
02238    }
02239    ast_mutex_unlock(&sub->lock);
02240 }
02241 
02242 static void SendDialTone(struct unistimsession *pte)
02243 {
02244    int i;
02245    /* No country defined ? Using US tone */
02246    if (ast_strlen_zero(pte->device->country)) {
02247       if (unistimdebug)
02248          ast_verb(0, "No country defined, using US tone\n");
02249       send_tone(pte, 350, 440);
02250       return;
02251    }
02252    if (strlen(pte->device->country) != 2) {
02253       if (unistimdebug)
02254          ast_verb(0, "Country code != 2 char, using US tone\n");
02255       send_tone(pte, 350, 440);
02256       return;
02257    }
02258    i = 0;
02259    while (frequency[i].freq1) {
02260       if ((frequency[i].country[0] == pte->device->country[0]) &&
02261          (frequency[i].country[1] == pte->device->country[1])) {
02262          if (unistimdebug)
02263             ast_verb(0, "Country code found (%s), freq1=%d freq2=%d\n",
02264                      frequency[i].country, frequency[i].freq1, frequency[i].freq2);
02265          send_tone(pte, frequency[i].freq1, frequency[i].freq2);
02266       }
02267       i++;
02268    }
02269 }
02270 
02271 static void handle_dial_page(struct unistimsession *pte)
02272 {
02273    pte->state = STATE_DIALPAGE;
02274    if (pte->device->call_forward[0] == -1) {
02275       send_text(TEXT_LINE0, TEXT_NORMAL, pte, "");
02276       send_text(TEXT_LINE1, TEXT_NORMAL, pte, "Enter forward");
02277       send_text_status(pte, "ForwardCancel BackSpcErase");
02278       if (pte->device->call_forward[1] != 0) {
02279          char tmp[TEXT_LENGTH_MAX + 1];
02280 
02281          ast_copy_string(pte->device->phone_number, pte->device->call_forward + 1,
02282                      sizeof(pte->device->phone_number));
02283          pte->device->size_phone_number = strlen(pte->device->phone_number);
02284          if (pte->device->size_phone_number > 15)
02285             pte->device->size_phone_number = 15;
02286          strcpy(tmp, "Number : ...............");
02287          memcpy(tmp + 9, pte->device->phone_number, pte->device->size_phone_number);
02288 
02289          if (pte->device->height == 1) {
02290             send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmp);
02291             send_blink_cursor(pte);
02292             send_cursor_pos(pte,
02293                     (unsigned char) (TEXT_LINE0 + 0x09 +
02294                                  pte->device->size_phone_number));
02295          } else {
02296             send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
02297             send_blink_cursor(pte);
02298             send_cursor_pos(pte,
02299                     (unsigned char) (TEXT_LINE2 + 0x09 +
02300                                  pte->device->size_phone_number));
02301          }
02302 
02303          send_led_update(pte, 0);
02304          return;
02305       }
02306    } else {
02307       if ((pte->device->output == OUTPUT_HANDSET) &&
02308          (pte->device->receiver_state == STATE_ONHOOK))
02309          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
02310       else
02311          send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
02312       SendDialTone(pte);
02313 
02314       if (pte->device->height > 1) {
02315          send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Enter the number to dial");
02316          send_text(TEXT_LINE1, TEXT_NORMAL, pte, "and press Call");
02317       }
02318       send_text_status(pte, "Call   Redial BackSpcErase");
02319    }
02320 
02321    if (pte->device->height == 1) {
02322       send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Number : ...............");
02323       send_blink_cursor(pte);
02324       send_cursor_pos(pte, TEXT_LINE0 + 0x09);
02325    } else {
02326       send_text(TEXT_LINE2, TEXT_NORMAL, pte, "Number : ...............");
02327       send_blink_cursor(pte);
02328       send_cursor_pos(pte, TEXT_LINE2 + 0x09);
02329    }
02330    pte->device->size_phone_number = 0;
02331    pte->device->phone_number[0] = 0;
02332    change_favorite_icon(pte, FAV_ICON_PHONE_BLACK);
02333    Sendicon(TEXT_LINE0, FAV_ICON_NONE, pte);
02334    pte->device->missed_call = 0;
02335    send_led_update(pte, 0);
02336    return;
02337 }
02338 
02339 /* Step 1 : Music On Hold for peer, Dialing screen for us */
02340 static void TransferCallStep1(struct unistimsession *pte)
02341 {
02342    struct unistim_subchannel *sub;
02343    struct unistim_line *p = pte->device->lines;
02344 
02345    sub = p->subs[SUB_REAL];
02346 
02347    if (!sub->owner) {
02348       ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
02349       return;
02350    }
02351    if (p->subs[SUB_THREEWAY]) {
02352       if (unistimdebug)
02353          ast_verb(0, "Transfer canceled, hangup our threeway channel\n");
02354       if (p->subs[SUB_THREEWAY]->owner)
02355          ast_queue_hangup_with_cause(p->subs[SUB_THREEWAY]->owner, AST_CAUSE_NORMAL_CLEARING);
02356       else
02357          ast_log(LOG_WARNING, "Canceling a threeway channel without owner\n");
02358       return;
02359    }
02360    /* Start music on hold if appropriate */
02361    if (pte->device->moh)
02362       ast_log(LOG_WARNING, "Transfer with peer already listening music on hold\n");
02363    else {
02364       if (ast_bridged_channel(p->subs[SUB_REAL]->owner)) {
02365          ast_moh_start(ast_bridged_channel(p->subs[SUB_REAL]->owner),
02366                     pte->device->lines->musicclass, NULL);
02367          pte->device->moh = 1;
02368       } else {
02369          ast_log(LOG_WARNING, "Unable to find peer subchannel for music on hold\n");
02370          return;
02371       }
02372    }
02373    /* Silence our channel */
02374    if (!pte->device->silence_generator) {
02375       pte->device->silence_generator =
02376          ast_channel_start_silence_generator(p->subs[SUB_REAL]->owner);
02377       if (pte->device->silence_generator == NULL)
02378          ast_log(LOG_WARNING, "Unable to start a silence generator.\n");
02379       else if (unistimdebug)
02380          ast_verb(0, "Starting silence generator\n");
02381    }
02382    handle_dial_page(pte);
02383 }
02384 
02385 /* From phone to PBX */
02386 static void HandleCallOutgoing(struct unistimsession *s)
02387 {
02388    struct ast_channel *c;
02389    struct unistim_subchannel *sub;
02390    pthread_t t;
02391    s->state = STATE_CALL;
02392    sub = s->device->lines->subs[SUB_REAL];
02393    if (!sub) {
02394       ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
02395       return;
02396    }
02397    if (!sub->owner) {            /* A call is already in progress ? */
02398       c = unistim_new(sub, AST_STATE_DOWN, NULL);   /* No, starting a new one */
02399       if (c) {
02400          /* Need to start RTP before calling ast_pbx_run */
02401          if (!sub->rtp)
02402             start_rtp(sub);
02403          send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
02404 
02405          if (s->device->height == 1) {
02406             send_text(TEXT_LINE0, TEXT_NORMAL, s, s->device->phone_number);
02407          } else {
02408             send_text(TEXT_LINE0, TEXT_NORMAL, s, "Calling :");
02409             send_text(TEXT_LINE1, TEXT_NORMAL, s, s->device->phone_number);
02410             send_text(TEXT_LINE2, TEXT_NORMAL, s, "Dialing...");
02411          }
02412          send_text_status(s, "Hangup");
02413 
02414          /* start switch */
02415          if (ast_pthread_create(&t, NULL, unistim_ss, c)) {
02416             display_last_error("Unable to create switch thread");
02417             ast_queue_hangup_with_cause(c, AST_CAUSE_SWITCH_CONGESTION);
02418          }
02419       } else
02420          ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n",
02421                sub->parent->name, s->device->name);
02422    } else {             /* We already have a call, so we switch in a threeway call */
02423 
02424       if (s->device->moh) {
02425          struct unistim_subchannel *subchannel;
02426          struct unistim_line *p = s->device->lines;
02427          subchannel = p->subs[SUB_REAL];
02428 
02429          if (!subchannel->owner) {
02430             ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
02431             return;
02432          }
02433          if (p->subs[SUB_THREEWAY]) {
02434             ast_log(LOG_WARNING,
02435                   "Can't transfer while an another transfer is taking place\n");
02436             return;
02437          }
02438          if (!alloc_sub(p, SUB_THREEWAY)) {
02439             ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
02440             return;
02441          }
02442          /* Stop the silence generator */
02443          if (s->device->silence_generator) {
02444             if (unistimdebug)
02445                ast_verb(0, "Stopping silence generator\n");
02446             ast_channel_stop_silence_generator(subchannel->owner,
02447                                        s->device->silence_generator);
02448             s->device->silence_generator = NULL;
02449          }
02450          send_tone(s, 0, 0);
02451          /* Make new channel */
02452          c = unistim_new(p->subs[SUB_THREEWAY], AST_STATE_DOWN, NULL);
02453          if (!c) {
02454             ast_log(LOG_WARNING, "Cannot allocate new structure on channel %p\n", p);
02455             return;
02456          }
02457          /* Swap things around between the three-way and real call */
02458          swap_subs(p, SUB_THREEWAY, SUB_REAL);
02459          send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
02460 
02461          if (s->device->height == 1) {
02462             send_text(TEXT_LINE0, TEXT_NORMAL, s, s->device->phone_number);
02463          } else {
02464             send_text(TEXT_LINE0, TEXT_NORMAL, s, "Calling (pre-transfer)");
02465             send_text(TEXT_LINE1, TEXT_NORMAL, s, s->device->phone_number);
02466             send_text(TEXT_LINE2, TEXT_NORMAL, s, "Dialing...");
02467          }
02468          send_text_status(s, "TransfrCancel");
02469 
02470          if (ast_pthread_create(&t, NULL, unistim_ss, p->subs[SUB_THREEWAY]->owner)) {
02471             ast_log(LOG_WARNING, "Unable to start simple switch on channel %p\n", p);
02472             ast_hangup(c);
02473             return;
02474          }
02475          if (unistimdebug)
02476             ast_verb(0, "Started three way call on channel %p (%s) subchan %d\n",
02477                 p->subs[SUB_THREEWAY]->owner, p->subs[SUB_THREEWAY]->owner->name,
02478                 p->subs[SUB_THREEWAY]->subtype);
02479       } else
02480          ast_debug(1, "Current sub [%s] already has owner\n", sub->owner->name);
02481    }
02482    return;
02483 }
02484 
02485 /* From PBX to phone */
02486 static void HandleCallIncoming(struct unistimsession *s)
02487 {
02488    struct unistim_subchannel *sub;
02489    s->state = STATE_CALL;
02490    s->device->missed_call = 0;
02491    send_no_ring(s);
02492    sub = s->device->lines->subs[SUB_REAL];
02493    if (!sub) {
02494       ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
02495       return;
02496    } else if (unistimdebug)
02497       ast_verb(0, "Handle Call Incoming for %s@%s\n", sub->parent->name,
02498                s->device->name);
02499    start_rtp(sub);
02500    if (!sub->rtp)
02501       ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name,
02502             s->device->name);
02503    ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
02504    send_text(TEXT_LINE2, TEXT_NORMAL, s, "is on-line");
02505    send_text_status(s, "Hangup Transf");
02506    send_start_timer(s);
02507 
02508    if ((s->device->output == OUTPUT_HANDSET) &&
02509       (s->device->receiver_state == STATE_ONHOOK))
02510       send_select_output(s, OUTPUT_SPEAKER, s->device->volume, MUTE_OFF);
02511    else
02512       send_select_output(s, s->device->output, s->device->volume, MUTE_OFF);
02513    s->device->start_call_timestamp = time(0);
02514    write_history(s, 'i', 0);
02515    return;
02516 }
02517 
02518 static int unistim_do_senddigit(struct unistimsession *pte, char digit)
02519 {
02520    struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass.integer = digit, .src = "unistim" };
02521    struct unistim_subchannel *sub;
02522    sub = pte->device->lines->subs[SUB_REAL];
02523    if (!sub->owner || sub->alreadygone) {
02524       ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit\n");
02525       return -1;
02526    }
02527 
02528    /* Send DTMF indication _before_ playing sounds */
02529    ast_queue_frame(sub->owner, &f);
02530 
02531    if (unistimdebug)
02532       ast_verb(0, "Send Digit %c\n", digit);
02533    switch (digit) {
02534    case '0':
02535       send_tone(pte, 941, 1336);
02536       break;
02537    case '1':
02538       send_tone(pte, 697, 1209);
02539       break;
02540    case '2':
02541       send_tone(pte, 697, 1336);
02542       break;
02543    case '3':
02544       send_tone(pte, 697, 1477);
02545       break;
02546    case '4':
02547       send_tone(pte, 770, 1209);
02548       break;
02549    case '5':
02550       send_tone(pte, 770, 1336);
02551       break;
02552    case '6':
02553       send_tone(pte, 770, 1477);
02554       break;
02555    case '7':
02556       send_tone(pte, 852, 1209);
02557       break;
02558    case '8':
02559       send_tone(pte, 852, 1336);
02560       break;
02561    case '9':
02562       send_tone(pte, 852, 1477);
02563       break;
02564    case 'A':
02565       send_tone(pte, 697, 1633);
02566       break;
02567    case 'B':
02568       send_tone(pte, 770, 1633);
02569       break;
02570    case 'C':
02571       send_tone(pte, 852, 1633);
02572       break;
02573    case 'D':
02574       send_tone(pte, 941, 1633);
02575       break;
02576    case '*':
02577       send_tone(pte, 941, 1209);
02578       break;
02579    case '#':
02580       send_tone(pte, 941, 1477);
02581       break;
02582    default:
02583       send_tone(pte, 500, 2000);
02584    }
02585    usleep(150000);          /* XXX Less than perfect, blocking an important thread is not a good idea */
02586    send_tone(pte, 0, 0);
02587    return 0;
02588 }
02589 
02590 static void key_call(struct unistimsession *pte, char keycode)
02591 {
02592    if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
02593       if (keycode == KEY_SHARP)
02594          keycode = '#';
02595       else if (keycode == KEY_STAR)
02596          keycode = '*';
02597       else
02598          keycode -= 0x10;
02599       unistim_do_senddigit(pte, keycode);
02600       return;
02601    }
02602    switch (keycode) {
02603    case KEY_HANGUP:
02604    case KEY_FUNC1:
02605       close_call(pte);
02606       break;
02607    case KEY_FUNC2:
02608       TransferCallStep1(pte);
02609       break;
02610    case KEY_HEADPHN:
02611       if (pte->device->output == OUTPUT_HEADPHONE)
02612          send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
02613       else
02614          send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
02615       break;
02616    case KEY_LOUDSPK:
02617       if (pte->device->output != OUTPUT_SPEAKER)
02618          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
02619       else
02620          send_select_output(pte, pte->device->previous_output, pte->device->volume,
02621                       MUTE_OFF);
02622       break;
02623    case KEY_MUTE:
02624       if (!pte->device->moh) {
02625          if (pte->device->mute == MUTE_ON)
02626             send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
02627          else
02628             send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON);
02629          break;
02630       }
02631    case KEY_ONHOLD:
02632       {
02633          struct unistim_subchannel *sub;
02634          struct ast_channel *bridgepeer = NULL;
02635          sub = pte->device->lines->subs[SUB_REAL];
02636          if (!sub->owner) {
02637             ast_log(LOG_WARNING, "Unable to find subchannel for music on hold\n");
02638             return;
02639          }
02640          if ((bridgepeer = ast_bridged_channel(sub->owner))) {
02641             if (pte->device->moh) {
02642                ast_moh_stop(bridgepeer);
02643                pte->device->moh = 0;
02644                send_select_output(pte, pte->device->output, pte->device->volume,
02645                             MUTE_OFF);
02646             } else {
02647                ast_moh_start(bridgepeer, pte->device->lines->musicclass, NULL);
02648                pte->device->moh = 1;
02649                send_select_output(pte, pte->device->output, pte->device->volume,
02650                             MUTE_ON);
02651             }
02652          } else
02653             ast_log(LOG_WARNING,
02654                   "Unable to find peer subchannel for music on hold\n");
02655          break;
02656       }
02657    }
02658    return;
02659 }
02660 
02661 static void key_ringing(struct unistimsession *pte, char keycode)
02662 {
02663    if (keycode == KEY_FAV0 + pte->device->softkeylinepos) {
02664       HandleCallIncoming(pte);
02665       return;
02666    }
02667    switch (keycode) {
02668    case KEY_HANGUP:
02669    case KEY_FUNC4:
02670       IgnoreCall(pte);
02671       break;
02672    case KEY_FUNC1:
02673       HandleCallIncoming(pte);
02674       break;
02675    }
02676    return;
02677 }
02678 
02679 static void Keyfavorite(struct unistimsession *pte, char keycode)
02680 {
02681    int fav;
02682 
02683    if ((keycode < KEY_FAV1) && (keycode > KEY_FAV5)) {
02684       ast_log(LOG_WARNING, "It's not a favorite key\n");
02685       return;
02686    }
02687    if (keycode == KEY_FAV0)
02688       return;
02689    fav = keycode - KEY_FAV0;
02690    if (pte->device->softkeyicon[fav] == 0)
02691       return;
02692    ast_copy_string(pte->device->phone_number, pte->device->softkeynumber[fav],
02693                sizeof(pte->device->phone_number));
02694    HandleCallOutgoing(pte);
02695    return;
02696 }
02697 
02698 static void key_dial_page(struct unistimsession *pte, char keycode)
02699 {
02700    if (keycode == KEY_FUNC3) {
02701       if (pte->device->size_phone_number <= 1)
02702          keycode = KEY_FUNC4;
02703       else {
02704          pte->device->size_phone_number -= 2;
02705          keycode = pte->device->phone_number[pte->device->size_phone_number] + 0x10;
02706       }
02707    }
02708    if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
02709       char tmpbuf[] = "Number : ...............";
02710       int i = 0;
02711 
02712       if (pte->device->size_phone_number >= 15)
02713          return;
02714       if (pte->device->size_phone_number == 0)
02715          send_tone(pte, 0, 0);
02716       while (i < pte->device->size_phone_number) {
02717          tmpbuf[i + 9] = pte->device->phone_number[i];
02718          i++;
02719       }
02720       if (keycode == KEY_SHARP)
02721          keycode = '#';
02722       else if (keycode == KEY_STAR)
02723          keycode = '*';
02724       else
02725          keycode -= 0x10;
02726       tmpbuf[i + 9] = keycode;
02727       pte->device->phone_number[i] = keycode;
02728       pte->device->size_phone_number++;
02729       pte->device->phone_number[i + 1] = 0;
02730       if (pte->device->height == 1) {
02731          send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmpbuf);
02732       } else {
02733          send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
02734       }
02735       send_blink_cursor(pte);
02736       send_cursor_pos(pte, (unsigned char) (TEXT_LINE2 + 0x0a + i));
02737       return;
02738    }
02739    if (keycode == KEY_FUNC4) {
02740 
02741       pte->device->size_phone_number = 0;
02742       if (pte->device->height == 1) {
02743          send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Number : ...............");
02744          send_blink_cursor(pte);
02745          send_cursor_pos(pte, TEXT_LINE0 + 0x09);
02746       } else {
02747          send_text(TEXT_LINE2, TEXT_NORMAL, pte, "Number : ...............");
02748          send_blink_cursor(pte);
02749          send_cursor_pos(pte, TEXT_LINE2 + 0x09);
02750       }
02751       return;
02752    }
02753 
02754    if (pte->device->call_forward[0] == -1) {
02755       if (keycode == KEY_FUNC1) {
02756          ast_copy_string(pte->device->call_forward, pte->device->phone_number,
02757                      sizeof(pte->device->call_forward));
02758          show_main_page(pte);
02759       } else if ((keycode == KEY_FUNC2) || (keycode == KEY_HANGUP)) {
02760          pte->device->call_forward[0] = '\0';
02761          show_main_page(pte);
02762       }
02763       return;
02764    }
02765    switch (keycode) {
02766    case KEY_FUNC2:
02767       if (ast_strlen_zero(pte->device->redial_number))
02768          break;
02769       ast_copy_string(pte->device->phone_number, pte->device->redial_number,
02770                   sizeof(pte->device->phone_number));
02771    case KEY_FUNC1:
02772       HandleCallOutgoing(pte);
02773       break;
02774    case KEY_HANGUP:
02775       if (pte->device->lines->subs[SUB_REAL]->owner) {
02776          /* Stop the silence generator */
02777          if (pte->device->silence_generator) {
02778             if (unistimdebug)
02779                ast_verb(0, "Stopping silence generator\n");
02780             ast_channel_stop_silence_generator(pte->device->lines->subs[SUB_REAL]->
02781                                        owner, pte->device->silence_generator);
02782             pte->device->silence_generator = NULL;
02783          }
02784          send_tone(pte, 0, 0);
02785          ast_moh_stop(ast_bridged_channel(pte->device->lines->subs[SUB_REAL]->owner));
02786          pte->device->moh = 0;
02787          pte->state = STATE_CALL;
02788 
02789          if (pte->device->height == 1) {
02790             send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Dial Cancel,back to priv. call.");
02791          } else {
02792             send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Dialing canceled,");
02793             send_text(TEXT_LINE1, TEXT_NORMAL, pte, "switching back to");
02794             send_text(TEXT_LINE2, TEXT_NORMAL, pte, "previous call.");
02795          }
02796          send_text_status(pte, "Hangup Transf");
02797       } else
02798          show_main_page(pte);
02799       break;
02800    case KEY_FAV1:
02801    case KEY_FAV2:
02802    case KEY_FAV3:
02803    case KEY_FAV4:
02804    case KEY_FAV5:
02805       Keyfavorite(pte, keycode);
02806       break;
02807    case KEY_LOUDSPK:
02808       if (pte->device->output == OUTPUT_SPEAKER) {
02809          if (pte->device->receiver_state == STATE_OFFHOOK)
02810             send_select_output(pte, pte->device->previous_output, pte->device->volume,
02811                          MUTE_OFF);
02812          else
02813             show_main_page(pte);
02814       } else
02815          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
02816       break;
02817    case KEY_HEADPHN:
02818       if (pte->device->output == OUTPUT_HEADPHONE) {
02819          if (pte->device->receiver_state == STATE_OFFHOOK)
02820             send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
02821          else
02822             show_main_page(pte);
02823       } else
02824          send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
02825       break;
02826    }
02827    return;
02828 }
02829 
02830 #define SELECTCODEC_START_ENTRY_POS 15
02831 #define SELECTCODEC_MAX_LENGTH 2
02832 #define SELECTCODEC_MSG "Codec number : .."
02833 static void HandleSelectCodec(struct unistimsession *pte)
02834 {
02835    char buf[30], buf2[5];
02836 
02837    pte->state = STATE_SELECTCODEC;
02838    strcpy(buf, "Using codec ");
02839    sprintf(buf2, "%d", pte->device->codec_number);
02840    strcat(buf, buf2);
02841    strcat(buf, " (G711u=0,");
02842 
02843    send_text(TEXT_LINE0, TEXT_NORMAL, pte, buf);
02844    send_text(TEXT_LINE1, TEXT_NORMAL, pte, "G723=4,G711a=8,G729A=18)");
02845    send_text(TEXT_LINE2, TEXT_INVERSE, pte, SELECTCODEC_MSG);
02846    send_blink_cursor(pte);
02847    send_cursor_pos(pte, TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS);
02848    pte->size_buff_entry = 0;
02849    send_text_status(pte, "Select BackSpcErase  Cancel");
02850    return;
02851 }
02852 
02853 static void key_select_codec(struct unistimsession *pte, char keycode)
02854 {
02855    if (keycode == KEY_FUNC2) {
02856       if (pte->size_buff_entry <= 1)
02857          keycode = KEY_FUNC3;
02858       else {
02859          pte->size_buff_entry -= 2;
02860          keycode = pte->buff_entry[pte->size_buff_entry] + 0x10;
02861       }
02862    }
02863    if ((keycode >= KEY_0) && (keycode <= KEY_9)) {
02864       char tmpbuf[] = SELECTCODEC_MSG;
02865       int i = 0;
02866 
02867       if (pte->size_buff_entry >= SELECTCODEC_MAX_LENGTH)
02868          return;
02869 
02870       while (i < pte->size_buff_entry) {
02871          tmpbuf[i + SELECTCODEC_START_ENTRY_POS] = pte->buff_entry[i];
02872          i++;
02873       }
02874       tmpbuf[i + SELECTCODEC_START_ENTRY_POS] = keycode - 0x10;
02875       pte->buff_entry[i] = keycode - 0x10;
02876       pte->size_buff_entry++;
02877       send_text(TEXT_LINE2, TEXT_INVERSE, pte, tmpbuf);
02878       send_blink_cursor(pte);
02879       send_cursor_pos(pte,
02880                  (unsigned char) (TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS + 1 + i));
02881       return;
02882    }
02883 
02884    switch (keycode) {
02885    case KEY_FUNC1:
02886       if (pte->size_buff_entry == 1)
02887          pte->device->codec_number = pte->buff_entry[0] - 48;
02888       else if (pte->size_buff_entry == 2)
02889          pte->device->codec_number =
02890             ((pte->buff_entry[0] - 48) * 10) + (pte->buff_entry[1] - 48);
02891       show_main_page(pte);
02892       break;
02893    case KEY_FUNC3:
02894       pte->size_buff_entry = 0;
02895       send_text(TEXT_LINE2, TEXT_INVERSE, pte, SELECTCODEC_MSG);
02896       send_blink_cursor(pte);
02897       send_cursor_pos(pte, TEXT_LINE2 + SELECTCODEC_START_ENTRY_POS);
02898       break;
02899    case KEY_HANGUP:
02900    case KEY_FUNC4:
02901       show_main_page(pte);
02902       break;
02903    }
02904    return;
02905 }
02906 
02907 #define SELECTEXTENSION_START_ENTRY_POS 0
02908 #define SELECTEXTENSION_MAX_LENGTH 10
02909 #define SELECTEXTENSION_MSG ".........."
02910 static void ShowExtensionPage(struct unistimsession *pte)
02911 {
02912    pte->state = STATE_EXTENSION;
02913 
02914    send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Please enter a Terminal");
02915    send_text(TEXT_LINE1, TEXT_NORMAL, pte, "Number (TN) :");
02916    send_text(TEXT_LINE2, TEXT_NORMAL, pte, SELECTEXTENSION_MSG);
02917    send_blink_cursor(pte);
02918    send_cursor_pos(pte, TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS);
02919    send_text_status(pte, "Enter  BackSpcErase");
02920    pte->size_buff_entry = 0;
02921    return;
02922 }
02923 
02924 static void key_select_extension(struct unistimsession *pte, char keycode)
02925 {
02926    if (keycode == KEY_FUNC2) {
02927       if (pte->size_buff_entry <= 1)
02928          keycode = KEY_FUNC3;
02929       else {
02930          pte->size_buff_entry -= 2;
02931          keycode = pte->buff_entry[pte->size_buff_entry] + 0x10;
02932       }
02933    }
02934    if ((keycode >= KEY_0) && (keycode <= KEY_9)) {
02935       char tmpbuf[] = SELECTEXTENSION_MSG;
02936       int i = 0;
02937 
02938       if (pte->size_buff_entry >= SELECTEXTENSION_MAX_LENGTH)
02939          return;
02940 
02941       while (i < pte->size_buff_entry) {
02942          tmpbuf[i + SELECTEXTENSION_START_ENTRY_POS] = pte->buff_entry[i];
02943          i++;
02944       }
02945       tmpbuf[i + SELECTEXTENSION_START_ENTRY_POS] = keycode - 0x10;
02946       pte->buff_entry[i] = keycode - 0x10;
02947       pte->size_buff_entry++;
02948       send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
02949       send_blink_cursor(pte);
02950       send_cursor_pos(pte,
02951                  (unsigned char) (TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS + 1 +
02952                               i));
02953       return;
02954    }
02955 
02956    switch (keycode) {
02957    case KEY_FUNC1:
02958       if (pte->size_buff_entry < 1)
02959          return;
02960       if (autoprovisioning == AUTOPROVISIONING_TN) {
02961          struct unistim_device *d;
02962 
02963          /* First step : looking for this TN in our device list */
02964          ast_mutex_lock(&devicelock);
02965          d = devices;
02966          pte->buff_entry[pte->size_buff_entry] = '\0';
02967          while (d) {
02968             if (d->id[0] == 'T') {  /* It's a TN device ? */
02969                /* It's the TN we're looking for ? */
02970                if (!strcmp((d->id) + 1, pte->buff_entry)) {
02971                   pte->device = d;
02972                   d->session = pte;
02973                   d->codec_number = DEFAULT_CODEC;
02974                   d->pos_fav = 0;
02975                   d->missed_call = 0;
02976                   d->receiver_state = STATE_ONHOOK;
02977                   strcpy(d->id, pte->macaddr);
02978                   pte->device->extension_number[0] = 'T';
02979                   pte->device->extension = EXTENSION_TN;
02980                   ast_copy_string((pte->device->extension_number) + 1,
02981                               pte->buff_entry, pte->size_buff_entry + 1);
02982                   ast_mutex_unlock(&devicelock);
02983                   show_main_page(pte);
02984                   refresh_all_favorite(pte);
02985                   return;
02986                }
02987             }
02988             d = d->next;
02989          }
02990          ast_mutex_unlock(&devicelock);
02991          send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Invalid Terminal Number.");
02992          send_text(TEXT_LINE1, TEXT_NORMAL, pte, "Please try again :");
02993          send_cursor_pos(pte,
02994                     (unsigned char) (TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS +
02995                                  pte->size_buff_entry));
02996          send_blink_cursor(pte);
02997       } else {
02998          ast_copy_string(pte->device->extension_number, pte->buff_entry,
02999                      pte->size_buff_entry + 1);
03000          if (RegisterExtension(pte)) {
03001             send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Invalid extension.");
03002             send_text(TEXT_LINE1, TEXT_NORMAL, pte, "Please try again :");
03003             send_cursor_pos(pte,
03004                        (unsigned char) (TEXT_LINE2 +
03005                                     SELECTEXTENSION_START_ENTRY_POS +
03006                                     pte->size_buff_entry));
03007             send_blink_cursor(pte);
03008          } else
03009             show_main_page(pte);
03010       }
03011       break;
03012    case KEY_FUNC3:
03013       pte->size_buff_entry = 0;
03014       send_text(TEXT_LINE2, TEXT_NORMAL, pte, SELECTEXTENSION_MSG);
03015       send_blink_cursor(pte);
03016       send_cursor_pos(pte, TEXT_LINE2 + SELECTEXTENSION_START_ENTRY_POS);
03017       break;
03018    }
03019    return;
03020 }
03021 
03022 static int ReformatNumber(char *number)
03023 {
03024    int pos = 0, i = 0, size = strlen(number);
03025 
03026    for (; i < size; i++) {
03027       if ((number[i] >= '0') && (number[i] <= '9')) {
03028          if (i == pos) {
03029             pos++;
03030             continue;
03031          }
03032          number[pos] = number[i];
03033          pos++;
03034       }
03035    }
03036    number[pos] = 0;
03037    return pos;
03038 }
03039 
03040 static void show_entry_history(struct unistimsession *pte, FILE ** f)
03041 {
03042    char line[TEXT_LENGTH_MAX + 1], status[STATUS_LENGTH_MAX + 1], func1[10], func2[10],
03043       func3[10];
03044 
03045    if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
03046       display_last_error("Can't read history date entry");
03047       fclose(*f);
03048       return;
03049    }
03050    line[sizeof(line) - 1] = '\0';
03051    send_text(TEXT_LINE0, TEXT_NORMAL, pte, line);
03052    if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
03053       display_last_error("Can't read callerid entry");
03054       fclose(*f);
03055       return;
03056    }
03057    line[sizeof(line) - 1] = '\0';
03058    ast_copy_string(pte->device->lst_cid, line, sizeof(pte->device->lst_cid));
03059    send_text(TEXT_LINE1, TEXT_NORMAL, pte, line);
03060    if (fread(line, TEXT_LENGTH_MAX, 1, *f) != 1) {
03061       display_last_error("Can't read callername entry");
03062       fclose(*f);
03063       return;
03064    }
03065    line[sizeof(line) - 1] = '\0';
03066    send_text(TEXT_LINE2, TEXT_NORMAL, pte, line);
03067    fclose(*f);
03068 
03069    snprintf(line, sizeof(line), "Call %03d/%03d", pte->buff_entry[2],
03070           pte->buff_entry[1]);
03071    send_texttitle(pte, line);
03072 
03073    if (pte->buff_entry[2] == 1)
03074       strcpy(func1, "       ");
03075    else
03076       strcpy(func1, "Prvious");
03077    if (pte->buff_entry[2] >= pte->buff_entry[1])
03078       strcpy(func2, "       ");
03079    else
03080       strcpy(func2, "Next   ");
03081    if (ReformatNumber(pte->device->lst_cid))
03082       strcpy(func3, "Redial ");
03083    else
03084       strcpy(func3, "       ");
03085    snprintf(status, sizeof(status), "%s%s%sCancel", func1, func2, func3);
03086    send_text_status(pte, status);
03087 }
03088 
03089 static char OpenHistory(struct unistimsession *pte, char way, FILE ** f)
03090 {
03091    char tmp[AST_CONFIG_MAX_PATH];
03092    char count;
03093 
03094    snprintf(tmp, sizeof(tmp), "%s/%s/%s-%c.csv", ast_config_AST_LOG_DIR,
03095           USTM_LOG_DIR, pte->device->name, way);
03096    *f = fopen(tmp, "r");
03097    if (!*f) {
03098       display_last_error("Unable to open history file");
03099       return 0;
03100    }
03101    if (fread(&count, 1, 1, *f) != 1) {
03102       display_last_error("Unable to read history header - display.");
03103       fclose(*f);
03104       return 0;
03105    }
03106    if (count > MAX_ENTRY_LOG) {
03107       ast_log(LOG_WARNING, "Invalid count in history header of %s (%d max %d)\n", tmp,
03108             count, MAX_ENTRY_LOG);
03109       fclose(*f);
03110       return 0;
03111    }
03112    return count;
03113 }
03114 
03115 static void show_history(struct unistimsession *pte, char way)
03116 {
03117    FILE *f;
03118    char count;
03119 
03120    if (!pte->device)
03121       return;
03122    if (!pte->device->callhistory)
03123       return;
03124    count = OpenHistory(pte, way, &f);
03125    if (!count)
03126       return;
03127    pte->buff_entry[0] = way;
03128    pte->buff_entry[1] = count;
03129    pte->buff_entry[2] = 1;
03130    show_entry_history(pte, &f);
03131    pte->state = STATE_HISTORY;
03132 }
03133 
03134 static void show_main_page(struct unistimsession *pte)
03135 {
03136    char tmpbuf[TEXT_LENGTH_MAX + 1];
03137 
03138 
03139    if ((pte->device->extension == EXTENSION_ASK) &&
03140       (ast_strlen_zero(pte->device->extension_number))) {
03141       ShowExtensionPage(pte);
03142       return;
03143    }
03144 
03145    pte->state = STATE_MAINPAGE;
03146 
03147    send_tone(pte, 0, 0);
03148    send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON_DISCRET);
03149    pte->device->lines->lastmsgssent = 0;
03150    send_favorite(pte->device->softkeylinepos, FAV_ICON_ONHOOK_BLACK, pte,
03151              pte->device->softkeylabel[pte->device->softkeylinepos]);
03152    if (!ast_strlen_zero(pte->device->call_forward)) {
03153       if (pte->device->height == 1) {
03154          send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Forwarding ON");
03155       } else {
03156          send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Call forwarded to :");
03157          send_text(TEXT_LINE1, TEXT_NORMAL, pte, pte->device->call_forward);
03158       }
03159       Sendicon(TEXT_LINE0, FAV_ICON_REFLECT + FAV_BLINK_SLOW, pte);
03160       send_text_status(pte, "Dial   Redial NoForwd");
03161    } else {
03162       if ((pte->device->extension == EXTENSION_ASK) ||
03163          (pte->device->extension == EXTENSION_TN))
03164          send_text_status(pte, "Dial   Redial ForwardUnregis");
03165       else
03166          send_text_status(pte, "Dial   Redial Forward");
03167 
03168       send_text(TEXT_LINE1, TEXT_NORMAL, pte, pte->device->maintext1);
03169       if (pte->device->missed_call == 0)
03170          send_text(TEXT_LINE0, TEXT_NORMAL, pte, pte->device->maintext0);
03171       else {
03172          sprintf(tmpbuf, "%d unanswered call(s)", pte->device->missed_call);
03173          send_text(TEXT_LINE0, TEXT_NORMAL, pte, tmpbuf);
03174          Sendicon(TEXT_LINE0, FAV_ICON_CALL_CENTER + FAV_BLINK_SLOW, pte);
03175       }
03176    }
03177    if (ast_strlen_zero(pte->device->maintext2)) {
03178       strcpy(tmpbuf, "IP : ");
03179       strcat(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr));
03180       send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
03181    } else
03182       send_text(TEXT_LINE2, TEXT_NORMAL, pte, pte->device->maintext2);
03183    send_texttitle(pte, pte->device->titledefault);
03184    change_favorite_icon(pte, FAV_ICON_ONHOOK_BLACK);
03185 }
03186 
03187 static void key_main_page(struct unistimsession *pte, char keycode)
03188 {
03189    if (pte->device->missed_call) {
03190       Sendicon(TEXT_LINE0, FAV_ICON_NONE, pte);
03191       pte->device->missed_call = 0;
03192    }
03193    if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
03194       handle_dial_page(pte);
03195       key_dial_page(pte, keycode);
03196       return;
03197    }
03198    switch (keycode) {
03199    case KEY_FUNC1:
03200       handle_dial_page(pte);
03201       break;
03202    case KEY_FUNC2:
03203       if (ast_strlen_zero(pte->device->redial_number))
03204          break;
03205       if ((pte->device->output == OUTPUT_HANDSET) &&
03206          (pte->device->receiver_state == STATE_ONHOOK))
03207          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
03208       else
03209          send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
03210 
03211       ast_copy_string(pte->device->phone_number, pte->device->redial_number,
03212                   sizeof(pte->device->phone_number));
03213       HandleCallOutgoing(pte);
03214       break;
03215    case KEY_FUNC3:
03216       if (!ast_strlen_zero(pte->device->call_forward)) {
03217          /* Cancel call forwarding */
03218          memmove(pte->device->call_forward + 1, pte->device->call_forward,
03219                sizeof(pte->device->call_forward));
03220          pte->device->call_forward[0] = '\0';
03221          Sendicon(TEXT_LINE0, FAV_ICON_NONE, pte);
03222          pte->device->output = OUTPUT_HANDSET;   /* Seems to be reseted somewhere */
03223          show_main_page(pte);
03224          break;
03225       }
03226       pte->device->call_forward[0] = -1;
03227       handle_dial_page(pte);
03228       break;
03229    case KEY_FUNC4:
03230       if (pte->device->extension == EXTENSION_ASK) {
03231          UnregisterExtension(pte);
03232          pte->device->extension_number[0] = '\0';
03233          ShowExtensionPage(pte);
03234       } else if (pte->device->extension == EXTENSION_TN) {
03235          ast_mutex_lock(&devicelock);
03236          strcpy(pte->device->id, pte->device->extension_number);
03237          pte->buff_entry[0] = '\0';
03238          pte->size_buff_entry = 0;
03239          pte->device->session = NULL;
03240          pte->device = NULL;
03241          ast_mutex_unlock(&devicelock);
03242          ShowExtensionPage(pte);
03243       }
03244       break;
03245    case KEY_FAV0:
03246       handle_dial_page(pte);
03247       break;
03248    case KEY_FAV1:
03249    case KEY_FAV2:
03250    case KEY_FAV3:
03251    case KEY_FAV4:
03252    case KEY_FAV5:
03253       if ((pte->device->output == OUTPUT_HANDSET) &&
03254          (pte->device->receiver_state == STATE_ONHOOK))
03255          send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
03256       else
03257          send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
03258       Keyfavorite(pte, keycode);
03259       break;
03260    case KEY_CONF:
03261       HandleSelectCodec(pte);
03262       break;
03263    case KEY_LOUDSPK:
03264       send_select_output(pte, OUTPUT_SPEAKER, pte->device->volume, MUTE_OFF);
03265       handle_dial_page(pte);
03266       break;
03267    case KEY_HEADPHN:
03268       send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
03269       handle_dial_page(pte);
03270       break;
03271    case KEY_SNDHIST:
03272       show_history(pte, 'o');
03273       break;
03274    case KEY_RCVHIST:
03275       show_history(pte, 'i');
03276       break;
03277    }
03278    return;
03279 }
03280 
03281 static void key_history(struct unistimsession *pte, char keycode)
03282 {
03283    FILE *f;
03284    char count;
03285    long offset;
03286 
03287    switch (keycode) {
03288    case KEY_UP:
03289    case KEY_LEFT:
03290    case KEY_FUNC1:
03291       if (pte->buff_entry[2] <= 1)
03292          return;
03293       pte->buff_entry[2]--;
03294       count = OpenHistory(pte, pte->buff_entry[0], &f);
03295       if (!count)
03296          return;
03297       offset = ((pte->buff_entry[2] - 1) * TEXT_LENGTH_MAX * 3);
03298       if (fseek(f, offset, SEEK_CUR)) {
03299          display_last_error("Unable to seek history entry.");
03300          fclose(f);
03301          return;
03302       }
03303       show_entry_history(pte, &f);
03304       break;
03305    case KEY_DOWN:
03306    case KEY_RIGHT:
03307    case KEY_FUNC2:
03308       if (pte->buff_entry[2] >= pte->buff_entry[1])
03309          return;
03310       pte->buff_entry[2]++;
03311       count = OpenHistory(pte, pte->buff_entry[0], &f);
03312       if (!count)
03313          return;
03314       offset = ((pte->buff_entry[2] - 1) * TEXT_LENGTH_MAX * 3);
03315       if (fseek(f, offset, SEEK_CUR)) {
03316          display_last_error("Unable to seek history entry.");
03317          fclose(f);
03318          return;
03319       }
03320       show_entry_history(pte, &f);
03321       break;
03322    case KEY_FUNC3:
03323       if (!ReformatNumber(pte->device->lst_cid))
03324          break;
03325       ast_copy_string(pte->device->redial_number, pte->device->lst_cid,
03326                   sizeof(pte->device->redial_number));
03327       key_main_page(pte, KEY_FUNC2);
03328       break;
03329    case KEY_FUNC4:
03330    case KEY_HANGUP:
03331       show_main_page(pte);
03332       break;
03333    case KEY_SNDHIST:
03334       if (pte->buff_entry[0] == 'i')
03335          show_history(pte, 'o');
03336       else
03337          show_main_page(pte);
03338       break;
03339    case KEY_RCVHIST:
03340       if (pte->buff_entry[0] == 'i')
03341          show_main_page(pte);
03342       else
03343          show_history(pte, 'i');
03344       break;
03345    }
03346    return;
03347 }
03348 
03349 static void init_phone_step2(struct unistimsession *pte)
03350 {
03351    BUFFSEND;
03352    if (unistimdebug)
03353       ast_verb(0, "Sending S4\n");
03354    memcpy(buffsend + SIZE_HEADER, packet_send_s4, sizeof(packet_send_s4));
03355    send_client(SIZE_HEADER + sizeof(packet_send_s4), buffsend, pte);
03356    send_date_time2(pte);
03357    send_date_time3(pte);
03358    if (unistimdebug)
03359       ast_verb(0, "Sending S7\n");
03360    memcpy(buffsend + SIZE_HEADER, packet_send_S7, sizeof(packet_send_S7));
03361    send_client(SIZE_HEADER + sizeof(packet_send_S7), buffsend, pte);
03362    if (unistimdebug)
03363       ast_verb(0, "Sending Contrast\n");
03364    memcpy(buffsend + SIZE_HEADER, packet_send_Contrast, sizeof(packet_send_Contrast));
03365    if (pte->device != NULL)
03366       buffsend[9] = pte->device->contrast;
03367    send_client(SIZE_HEADER + sizeof(packet_send_Contrast), buffsend, pte);
03368 
03369    if (unistimdebug)
03370       ast_verb(0, "Sending S9\n");
03371    memcpy(buffsend + SIZE_HEADER, packet_send_s9, sizeof(packet_send_s9));
03372    send_client(SIZE_HEADER + sizeof(packet_send_s9), buffsend, pte);
03373    send_no_ring(pte);
03374 
03375    if (unistimdebug)
03376       ast_verb(0, "Sending S7\n");
03377    memcpy(buffsend + SIZE_HEADER, packet_send_S7, sizeof(packet_send_S7));
03378    send_client(SIZE_HEADER + sizeof(packet_send_S7), buffsend, pte);
03379    send_led_update(pte, 0);
03380    send_ping(pte);
03381    if (pte->state < STATE_MAINPAGE) {
03382       if (autoprovisioning == AUTOPROVISIONING_TN) {
03383          ShowExtensionPage(pte);
03384          return;
03385       } else {
03386          int i;
03387          char tmp[30];
03388 
03389          for (i = 1; i < 6; i++)
03390             send_favorite(i, 0, pte, "");
03391          send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Sorry, this phone is not");
03392          send_text(TEXT_LINE1, TEXT_NORMAL, pte, "registered in unistim.cfg");
03393          strcpy(tmp, "MAC = ");
03394          strcat(tmp, pte->macaddr);
03395          send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
03396          send_text_status(pte, "");
03397          send_texttitle(pte, "UNISTIM for*");
03398          return;
03399       }
03400    }
03401    show_main_page(pte);
03402    refresh_all_favorite(pte);
03403    if (unistimdebug)
03404       ast_verb(0, "Sending arrow\n");
03405    memcpy(buffsend + SIZE_HEADER, packet_send_arrow, sizeof(packet_send_arrow));
03406    send_client(SIZE_HEADER + sizeof(packet_send_arrow), buffsend, pte);
03407    return;
03408 }
03409 
03410 static void process_request(int size, unsigned char *buf, struct unistimsession *pte)
03411 {
03412    char tmpbuf[255];
03413    if (memcmp
03414       (buf + SIZE_HEADER, packet_recv_resume_connection_with_server,
03415        sizeof(packet_recv_resume_connection_with_server)) == 0) {
03416       rcv_resume_connection_with_server(pte);
03417       return;
03418    }
03419    if (memcmp(buf + SIZE_HEADER, packet_recv_firm_version, sizeof(packet_recv_firm_version)) ==
03420       0) {
03421       buf[size] = 0;
03422       if (unistimdebug)
03423          ast_verb(0, "Got the firmware version : '%s'\n", buf + 13);
03424       init_phone_step2(pte);
03425       return;
03426    }
03427    if (memcmp(buf + SIZE_HEADER, packet_recv_mac_addr, sizeof(packet_recv_mac_addr)) == 0) {
03428       rcv_mac_addr(pte, buf);
03429       return;
03430    }
03431    if (memcmp(buf + SIZE_HEADER, packet_recv_r2, sizeof(packet_recv_r2)) == 0) {
03432       if (unistimdebug)
03433          ast_verb(0, "R2 received\n");
03434       return;
03435    }
03436 
03437    if (pte->state < STATE_MAINPAGE) {
03438       if (unistimdebug)
03439          ast_verb(0, "Request not authorized in this state\n");
03440       return;
03441    }
03442    if (!memcmp(buf + SIZE_HEADER, packet_recv_pressed_key, sizeof(packet_recv_pressed_key))) {
03443       char keycode = buf[13];
03444 
03445       if (unistimdebug)
03446          ast_verb(0, "Key pressed : keycode = 0x%.2x - current state : %d\n", keycode,
03447                   pte->state);
03448 
03449       switch (pte->state) {
03450       case STATE_INIT:
03451          if (unistimdebug)
03452             ast_verb(0, "No keys allowed in the init state\n");
03453          break;
03454       case STATE_AUTHDENY:
03455          if (unistimdebug)
03456             ast_verb(0, "No keys allowed in authdeny state\n");
03457          break;
03458       case STATE_MAINPAGE:
03459          key_main_page(pte, keycode);
03460          break;
03461       case STATE_DIALPAGE:
03462          key_dial_page(pte, keycode);
03463          break;
03464       case STATE_RINGING:
03465          key_ringing(pte, keycode);
03466          break;
03467       case STATE_CALL:
03468          key_call(pte, keycode);
03469          break;
03470       case STATE_EXTENSION:
03471          key_select_extension(pte, keycode);
03472          break;
03473       case STATE_SELECTCODEC:
03474          key_select_codec(pte, keycode);
03475          break;
03476       case STATE_HISTORY:
03477          key_history(pte, keycode);
03478          break;
03479       default:
03480          ast_log(LOG_WARNING, "Key : Unknown state\n");
03481       }
03482       return;
03483    }
03484    if (memcmp(buf + SIZE_HEADER, packet_recv_pick_up, sizeof(packet_recv_pick_up)) == 0) {
03485       if (unistimdebug)
03486          ast_verb(0, "Handset off hook\n");
03487       if (!pte->device)        /* We are not yet registered (asking for a TN in AUTOPROVISIONING_TN) */
03488          return;
03489       pte->device->receiver_state = STATE_OFFHOOK;
03490       if (pte->device->output == OUTPUT_HEADPHONE)
03491          send_select_output(pte, OUTPUT_HEADPHONE, pte->device->volume, MUTE_OFF);
03492       else
03493          send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
03494       if (pte->state == STATE_RINGING)
03495          HandleCallIncoming(pte);
03496       else if ((pte->state == STATE_DIALPAGE) || (pte->state == STATE_CALL))
03497          send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
03498       else if (pte->state == STATE_EXTENSION) /* We must have a TN before calling */
03499          return;
03500       else {
03501          send_select_output(pte, OUTPUT_HANDSET, pte->device->volume, MUTE_OFF);
03502          handle_dial_page(pte);
03503       }
03504       return;
03505    }
03506    if (memcmp(buf + SIZE_HEADER, packet_recv_hangup, sizeof(packet_recv_hangup)) == 0) {
03507       if (unistimdebug)
03508          ast_verb(0, "Handset on hook\n");
03509       if (!pte->device)
03510          return;
03511       pte->device->receiver_state = STATE_ONHOOK;
03512       if (pte->state == STATE_CALL)
03513          close_call(pte);
03514       else if (pte->device->lines->subs[SUB_REAL]->owner)
03515          close_call(pte);
03516       else if (pte->state == STATE_EXTENSION)
03517          return;
03518       else
03519          show_main_page(pte);
03520       return;
03521    }
03522    strcpy(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr));
03523    strcat(tmpbuf, " Unknown request packet\n");
03524    if (unistimdebug)
03525       ast_debug(1, "%s", tmpbuf);
03526    return;
03527 }
03528 
03529 static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
03530    struct sockaddr_in *addr_from)
03531 {
03532    unsigned short *sbuf = (unsigned short *) buf;
03533    unsigned short seq;
03534    char tmpbuf[255];
03535 
03536    strcpy(tmpbuf, ast_inet_ntoa(addr_from->sin_addr));
03537 
03538    if (size < 10) {
03539       if (size == 0) {
03540          ast_log(LOG_WARNING, "%s Read error\n", tmpbuf);
03541       } else {
03542          ast_log(LOG_NOTICE, "%s Packet too short - ignoring\n", tmpbuf);
03543       }
03544       return;
03545    }
03546    if (sbuf[0] == 0xffff) {   /* Starting with 0xffff ? *//* Yes, discovery packet ? */
03547       if (size != sizeof(packet_rcv_discovery)) {
03548          ast_log(LOG_NOTICE, "%s Invalid size of a discovery packet\n", tmpbuf);
03549       } else {
03550          if (memcmp(buf, packet_rcv_discovery, sizeof(packet_rcv_discovery)) == 0) {
03551             if (unistimdebug)
03552                ast_verb(0, "Discovery packet received - Sending Discovery ACK\n");
03553             if (pte) {        /* A session was already active for this IP ? */
03554                if (pte->state == STATE_INIT) { /* Yes, but it's a dupe */
03555                   if (unistimdebug)
03556                      ast_verb(1, "Duplicated Discovery packet\n");
03557                   send_raw_client(sizeof(packet_send_discovery_ack),
03558                              packet_send_discovery_ack, addr_from, &pte->sout);
03559                   pte->seq_phone = (short) 0x0000; /* reset sequence number */
03560                } else { /* No, probably a reboot, phone side */
03561                   close_client(pte);       /* Cleanup the previous session */
03562                   if (create_client(addr_from))
03563                      send_raw_client(sizeof(packet_send_discovery_ack),
03564                                 packet_send_discovery_ack, addr_from, &pte->sout);
03565                }
03566             } else {
03567                /* Creating new entry in our phone list */
03568                if ((pte = create_client(addr_from)))
03569                   send_raw_client(sizeof(packet_send_discovery_ack),
03570                              packet_send_discovery_ack, addr_from, &pte->sout);
03571             }
03572             return;
03573          }
03574          ast_log(LOG_NOTICE, "%s Invalid discovery packet\n", tmpbuf);
03575       }
03576       return;
03577    }
03578    if (!pte) {
03579       if (unistimdebug)
03580          ast_verb(0, "%s Not a discovery packet from an unknown source : ignoring\n",
03581                   tmpbuf);
03582       return;
03583    }
03584 
03585    if (sbuf[0] != 0) {          /* Starting with something else than 0x0000 ? */
03586       ast_log(LOG_NOTICE, "Unknown packet received - ignoring\n");
03587       return;
03588    }
03589    if (buf[5] != 2) {
03590       ast_log(LOG_NOTICE, "%s Wrong direction : got 0x%.2x expected 0x02\n", tmpbuf,
03591             buf[5]);
03592       return;
03593    }
03594    seq = ntohs(sbuf[1]);
03595    if (buf[4] == 1) {
03596       ast_mutex_lock(&pte->lock);
03597       if (unistimdebug)
03598          ast_verb(6, "ACK received for packet #0x%.4x\n", seq);
03599       pte->nb_retransmit = 0;
03600 
03601       if ((pte->last_seq_ack) + 1 == seq) {
03602          pte->last_seq_ack++;
03603          check_send_queue(pte);
03604          ast_mutex_unlock(&pte->lock);
03605          return;
03606       }
03607       if (pte->last_seq_ack > seq) {
03608          if (pte->last_seq_ack == 0xffff) {
03609             ast_verb(0, "ACK at 0xffff, restarting counter.\n");
03610             pte->last_seq_ack = 0;
03611          } else
03612             ast_log(LOG_NOTICE,
03613                   "%s Warning : ACK received for an already ACKed packet : #0x%.4x we are at #0x%.4x\n",
03614                   tmpbuf, seq, pte->last_seq_ack);
03615          ast_mutex_unlock(&pte->lock);
03616          return;
03617       }
03618       if (pte->seq_server < seq) {
03619          ast_log(LOG_NOTICE,
03620                "%s Error : ACK received for a non-existent packet : #0x%.4x\n",
03621                tmpbuf, pte->seq_server);
03622          ast_mutex_unlock(&pte->lock);
03623          return;
03624       }
03625       if (unistimdebug)
03626          ast_verb(0, "%s ACK gap : Received ACK #0x%.4x, previous was #0x%.4x\n",
03627                   tmpbuf, seq, pte->last_seq_ack);
03628       pte->last_seq_ack = seq;
03629       check_send_queue(pte);
03630       ast_mutex_unlock(&pte->lock);
03631       return;
03632    }
03633    if (buf[4] == 2) {
03634       if (unistimdebug)
03635          ast_verb(0, "Request received\n");
03636       if (pte->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          pte->seq_phone++;
03642 
03643          process_request(size, buf, pte);
03644          return;
03645       }
03646       if (pte->seq_phone > seq) {
03647          ast_log(LOG_NOTICE,
03648                "%s Warning : received a retransmitted packet : #0x%.4x (we are at #0x%.4x)\n",
03649                tmpbuf, seq, pte->seq_phone);
03650          /* BUG ? pte->device->seq_phone = seq; */
03651          /* Send ACK */
03652          buf[4] = 1;
03653          buf[5] = 1;
03654          send_raw_client(SIZE_HEADER, buf, addr_from, &pte->sout);
03655          return;
03656       }
03657       ast_log(LOG_NOTICE,
03658             "%s Warning : we lost a packet : received #0x%.4x (we are at #0x%.4x)\n",
03659             tmpbuf, seq, pte->seq_phone);
03660       return;
03661    }
03662    if (buf[4] == 0) {
03663       ast_log(LOG_NOTICE, "%s Retransmit request for packet #0x%.4x\n", tmpbuf, seq);
03664       if (pte->last_seq_ack > seq) {
03665          ast_log(LOG_NOTICE,
03666                "%s Error : received a request for an already ACKed packet : #0x%.4x\n",
03667                tmpbuf, pte->last_seq_ack);
03668          return;
03669       }
03670       if (pte->seq_server < seq) {
03671          ast_log(LOG_NOTICE,
03672                "%s Error : received a request for a non-existent packet : #0x%.4x\n",
03673                tmpbuf, pte->seq_server);
03674          return;
03675       }
03676       send_retransmit(pte);
03677       return;
03678    }
03679    ast_log(LOG_NOTICE, "%s Unknown request : got 0x%.2x expected 0x00,0x01 or 0x02\n",
03680          tmpbuf, buf[4]);
03681    return;
03682 }
03683 
03684 static struct unistimsession *channel_to_session(struct ast_channel *ast)
03685 {
03686    struct unistim_subchannel *sub;
03687    if (!ast) {
03688       ast_log(LOG_WARNING, "Unistim callback function called with a null channel\n");
03689       return NULL;
03690    }
03691    if (!ast->tech_pvt) {
03692       ast_log(LOG_WARNING, "Unistim callback function called without a tech_pvt\n");
03693       return NULL;
03694    }
03695    sub = ast->tech_pvt;
03696 
03697    if (!sub->parent) {
03698       ast_log(LOG_WARNING, "Unistim callback function called without a line\n");
03699       return NULL;
03700    }
03701    if (!sub->parent->parent) {
03702       ast_log(LOG_WARNING, "Unistim callback function called without a device\n");
03703       return NULL;
03704    }
03705    if (!sub->parent->parent->session) {
03706       ast_log(LOG_WARNING, "Unistim callback function called without a session\n");
03707       return NULL;
03708    }
03709    return sub->parent->parent->session;
03710 }
03711 
03712 /*--- unistim_call: Initiate UNISTIM call from PBX ---*/
03713 /*      used from the dial() application      */
03714 static int unistim_call(struct ast_channel *ast, char *dest, int timeout)
03715 {
03716    int res = 0;
03717    struct unistim_subchannel *sub;
03718    struct unistimsession *session;
03719 
03720    session = channel_to_session(ast);
03721    if (!session) {
03722       ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
03723       return -1;
03724    }
03725 
03726    sub = ast->tech_pvt;
03727    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
03728       ast_log(LOG_WARNING, "unistim_call called on %s, neither down nor reserved\n",
03729             ast->name);
03730       return -1;
03731    }
03732 
03733    if (unistimdebug)
03734       ast_verb(3, "unistim_call(%s)\n", ast->name);
03735 
03736    session->state = STATE_RINGING;
03737    Sendicon(TEXT_LINE0, FAV_ICON_NONE, session);
03738 
03739    if (sub->owner) {
03740       if (sub->owner->connected.id.number.valid
03741          && sub->owner->connected.id.number.str) {
03742          if (session->device->height == 1) {
03743             send_text(TEXT_LINE0, TEXT_NORMAL, session, sub->owner->connected.id.number.str);
03744          } else {
03745             send_text(TEXT_LINE1, TEXT_NORMAL, session, sub->owner->connected.id.number.str);
03746          }
03747          change_callerid(session, 0, sub->owner->connected.id.number.str);
03748       } else {
03749          if (session->device->height == 1) {
03750             send_text(TEXT_LINE0, TEXT_NORMAL, session, DEFAULTCALLERID);
03751          } else {
03752             send_text(TEXT_LINE1, TEXT_NORMAL, session, DEFAULTCALLERID);
03753          }
03754          change_callerid(session, 0, DEFAULTCALLERID);
03755       }
03756       if (sub->owner->connected.id.name.valid
03757          && sub->owner->connected.id.name.str) {
03758          send_text(TEXT_LINE0, TEXT_NORMAL, session, sub->owner->connected.id.name.str);
03759          change_callerid(session, 1, sub->owner->connected.id.name.str);
03760       } else {
03761          send_text(TEXT_LINE0, TEXT_NORMAL, session, DEFAULTCALLERNAME);
03762          change_callerid(session, 1, DEFAULTCALLERNAME);
03763       }
03764    }
03765    send_text(TEXT_LINE2, TEXT_NORMAL, session, "is calling you.");
03766    send_text_status(session, "Accept              Ignore");
03767 
03768    if (sub->ringstyle == -1)
03769       send_ring(session, session->device->ringvolume, session->device->ringstyle);
03770    else {
03771       if (sub->ringvolume == -1)
03772          send_ring(session, session->device->ringvolume, sub->ringstyle);
03773       else
03774          send_ring(session, sub->ringvolume, sub->ringstyle);
03775    }
03776    change_favorite_icon(session, FAV_ICON_SPEAKER_ONHOOK_BLACK + FAV_BLINK_FAST);
03777 
03778    ast_setstate(ast, AST_STATE_RINGING);
03779    ast_queue_control(ast, AST_CONTROL_RINGING);
03780    return res;
03781 }
03782 
03783 /*--- unistim_hangup: Hangup UNISTIM call */
03784 static int unistim_hangup(struct ast_channel *ast)
03785 {
03786    struct unistim_subchannel *sub;
03787    struct unistim_line *l;
03788    struct unistimsession *s;
03789 
03790    s = channel_to_session(ast);
03791    sub = ast->tech_pvt;
03792    if (!s) {
03793       ast_debug(1, "Asked to hangup channel not connected\n");
03794       ast_mutex_lock(&sub->lock);
03795       sub->owner = NULL;
03796       ast->tech_pvt = NULL;
03797       sub->alreadygone = 0;
03798       ast_mutex_unlock(&sub->lock);
03799       if (sub->rtp) {
03800          if (unistimdebug)
03801             ast_verb(0, "Destroying RTP session\n");
03802          ast_rtp_instance_destroy(sub->rtp);
03803          sub->rtp = NULL;
03804       }
03805       return 0;
03806    }
03807    l = sub->parent;
03808    if (unistimdebug)
03809       ast_verb(0, "unistim_hangup(%s) on %s@%s\n", ast->name, l->name, l->parent->name);
03810 
03811    if ((l->subs[SUB_THREEWAY]) && (sub->subtype == SUB_REAL)) {
03812       if (unistimdebug)
03813          ast_verb(0, "Real call disconnected while talking to threeway\n");
03814       sub->owner = NULL;
03815       ast->tech_pvt = NULL;
03816       return 0;
03817    }
03818    if ((l->subs[SUB_REAL]->owner) && (sub->subtype == SUB_THREEWAY) &&
03819       (sub->alreadygone == 0)) {
03820       if (unistimdebug)
03821          ast_verb(0, "threeway call disconnected, switching to real call\n");
03822       send_text(TEXT_LINE0, TEXT_NORMAL, s, "Three way call canceled,");
03823       send_text(TEXT_LINE1, TEXT_NORMAL, s, "switching back to");
03824       send_text(TEXT_LINE2, TEXT_NORMAL, s, "previous call.");
03825       send_text_status(s, "Hangup Transf");
03826       ast_moh_stop(ast_bridged_channel(l->subs[SUB_REAL]->owner));
03827       swap_subs(l, SUB_THREEWAY, SUB_REAL);
03828       l->parent->moh = 0;
03829       ast_mutex_lock(&sub->lock);
03830       sub->owner = NULL;
03831       ast->tech_pvt = NULL;
03832       ast_mutex_unlock(&sub->lock);
03833       unalloc_sub(l, SUB_THREEWAY);
03834       return 0;
03835    }
03836    ast_mutex_lock(&sub->lock);
03837    sub->owner = NULL;
03838    ast->tech_pvt = NULL;
03839    sub->alreadygone = 0;
03840    ast_mutex_unlock(&sub->lock);
03841    if (!s) {
03842       if (unistimdebug)
03843          ast_verb(0, "Asked to hangup channel not connected (no session)\n");
03844       if (sub->rtp) {
03845          if (unistimdebug)
03846             ast_verb(0, "Destroying RTP session\n");
03847          ast_rtp_instance_destroy(sub->rtp);
03848          sub->rtp = NULL;
03849       }
03850       return 0;
03851    }
03852    if (sub->subtype == SUB_REAL) {
03853       /* Stop the silence generator */
03854       if (s->device->silence_generator) {
03855          if (unistimdebug)
03856             ast_verb(0, "Stopping silence generator\n");
03857          if (sub->owner)
03858             ast_channel_stop_silence_generator(sub->owner,
03859                                        s->device->silence_generator);
03860          else
03861             ast_log(LOG_WARNING,
03862                   "Trying to stop silence generator on a null channel !\n");
03863          s->device->silence_generator = NULL;
03864       }
03865    }
03866    l->parent->moh = 0;
03867    send_no_ring(s);
03868    send_end_call(s);
03869    if (sub->rtp) {
03870       if (unistimdebug)
03871          ast_verb(0, "Destroying RTP session\n");
03872       ast_rtp_instance_destroy(sub->rtp);
03873       sub->rtp = NULL;
03874    } else if (unistimdebug)
03875       ast_verb(0, "No RTP session to destroy\n");
03876    if (l->subs[SUB_THREEWAY]) {
03877       if (unistimdebug)
03878          ast_verb(0, "Cleaning other subchannels\n");
03879       unalloc_sub(l, SUB_THREEWAY);
03880    }
03881    if (s->state == STATE_RINGING)
03882       cancel_dial(s);
03883    else if (s->state == STATE_CALL)
03884       close_call(s);
03885 
03886    return 0;
03887 }
03888 
03889 /*--- unistim_answer: Answer UNISTIM call */
03890 static int unistim_answer(struct ast_channel *ast)
03891 {
03892    int res = 0;
03893    struct unistim_subchannel *sub;
03894    struct unistim_line *l;
03895    struct unistimsession *s;
03896 
03897    s = channel_to_session(ast);
03898    if (!s) {
03899       ast_log(LOG_WARNING, "unistim_answer on a disconnected device ?\n");
03900       return -1;
03901    }
03902    sub = ast->tech_pvt;
03903    l = sub->parent;
03904 
03905    if ((!sub->rtp) && (!l->subs[SUB_THREEWAY]))
03906       start_rtp(sub);
03907    if (unistimdebug)
03908       ast_verb(0, "unistim_answer(%s) on %s@%s-%d\n", ast->name, l->name,
03909                l->parent->name, sub->subtype);
03910    send_text(TEXT_LINE2, TEXT_NORMAL, l->parent->session, "is now on-line");
03911    if (l->subs[SUB_THREEWAY])
03912       send_text_status(l->parent->session, "Transf Cancel");
03913    else
03914       send_text_status(l->parent->session, "Hangup Transf");
03915    send_start_timer(l->parent->session);
03916    if (ast->_state != AST_STATE_UP)
03917       ast_setstate(ast, AST_STATE_UP);
03918    return res;
03919 }
03920 
03921 /*--- unistimsock_read: Read data from UNISTIM socket ---*/
03922 /*    Successful messages is connected to UNISTIM call and forwarded to parsing() */
03923 static int unistimsock_read(int *id, int fd, short events, void *ignore)
03924 {
03925    struct sockaddr_in addr_from = { 0, };
03926    struct unistimsession *cur = NULL;
03927    int found = 0;
03928    int tmp = 0;
03929    int dw_num_bytes_rcvd;
03930 #ifdef DUMP_PACKET
03931    int dw_num_bytes_rcvdd;
03932    char iabuf[INET_ADDRSTRLEN];
03933 #endif
03934 
03935    dw_num_bytes_rcvd =
03936       recvfrom(unistimsock, buff, SIZE_PAGE, 0, (struct sockaddr *) &addr_from,
03937              &size_addr_from);
03938    if (dw_num_bytes_rcvd == -1) {
03939       if (errno == EAGAIN)
03940          ast_log(LOG_NOTICE, "UNISTIM: Received packet with bad UDP checksum\n");
03941       else if (errno != ECONNREFUSED)
03942          ast_log(LOG_WARNING, "Recv error %d (%s)\n", errno, strerror(errno));
03943       return 1;
03944    }
03945 
03946    /* Looking in the phone list if we already have a registration for him */
03947    ast_mutex_lock(&sessionlock);
03948    cur = sessions;
03949    while (cur) {
03950       if (cur->sin.sin_addr.s_addr == addr_from.sin_addr.s_addr) {
03951          found = 1;
03952          break;
03953       }
03954       tmp++;
03955       cur = cur->next;
03956    }
03957    ast_mutex_unlock(&sessionlock);
03958 
03959 #ifdef DUMP_PACKET
03960    if (unistimdebug)
03961       ast_verb(0, "\n*** Dump %d bytes from %s - phone_table[%d] ***\n",
03962                dw_num_bytes_rcvd, ast_inet_ntoa(addr_from.sin_addr), tmp);
03963    for (dw_num_bytes_rcvdd = 0; dw_num_bytes_rcvdd < dw_num_bytes_rcvd;
03964        dw_num_bytes_rcvdd++)
03965       ast_verb(0, "%.2x ", (unsigned char) buff[dw_num_bytes_rcvdd]);
03966    ast_verb(0, "\n******************************************\n");
03967 #endif
03968 
03969    if (!found) {
03970       if (unistimdebug)
03971          ast_verb(0, "Received a packet from an unknown source\n");
03972       parsing(dw_num_bytes_rcvd, buff, NULL, (struct sockaddr_in *) &addr_from);
03973 
03974    } else
03975       parsing(dw_num_bytes_rcvd, buff, cur, (struct sockaddr_in *) &addr_from);
03976 
03977    return 1;
03978 }
03979 
03980 static struct ast_frame *unistim_rtp_read(const struct ast_channel *ast,
03981    const struct unistim_subchannel *sub)
03982 {
03983    /* Retrieve audio/etc from channel.  Assumes sub->lock is already held. */
03984    struct ast_frame *f;
03985 
03986    if (!ast) {
03987       ast_log(LOG_WARNING, "Channel NULL while reading\n");
03988       return &ast_null_frame;
03989    }
03990 
03991    if (!sub->rtp) {
03992       ast_log(LOG_WARNING, "RTP handle NULL while reading on subchannel %d\n",
03993             sub->subtype);
03994       return &ast_null_frame;
03995    }
03996 
03997    switch (ast->fdno) {
03998    case 0:
03999       f = ast_rtp_instance_read(sub->rtp, 0);     /* RTP Audio */
04000       break;
04001    case 1:
04002       f = ast_rtp_instance_read(sub->rtp, 1);    /* RTCP Control Channel */
04003       break;
04004    default:
04005       f = &ast_null_frame;
04006    }
04007 
04008    if (sub->owner) {
04009       /* We already hold the channel lock */
04010       if (f->frametype == AST_FRAME_VOICE) {
04011          if (f->subclass.codec != sub->owner->nativeformats) {
04012             ast_debug(1,
04013                   "Oooh, format changed from %s to %s\n",
04014                   ast_getformatname(sub->owner->nativeformats),
04015                   ast_getformatname(f->subclass.codec));
04016 
04017             sub->owner->nativeformats = f->subclass.codec;
04018             ast_set_read_format(sub->owner, sub->owner->readformat);
04019             ast_set_write_format(sub->owner, sub->owner->writeformat);
04020          }
04021       }
04022    }
04023 
04024    return f;
04025 }
04026 
04027 static struct ast_frame *unistim_read(struct ast_channel *ast)
04028 {
04029    struct ast_frame *fr;
04030    struct unistim_subchannel *sub = ast->tech_pvt;
04031 
04032    ast_mutex_lock(&sub->lock);
04033    fr = unistim_rtp_read(ast, sub);
04034    ast_mutex_unlock(&sub->lock);
04035 
04036    return fr;
04037 }
04038 
04039 static int unistim_write(struct ast_channel *ast, struct ast_frame *frame)
04040 {
04041    struct unistim_subchannel *sub = ast->tech_pvt;
04042    int res = 0;
04043 
04044    if (frame->frametype != AST_FRAME_VOICE) {
04045       if (frame->frametype == AST_FRAME_IMAGE)
04046          return 0;
04047       else {
04048          ast_log(LOG_WARNING, "Can't send %d type frames with unistim_write\n",
04049                frame->frametype);
04050          return 0;
04051       }
04052    } else {
04053       if (!(frame->subclass.codec & ast->nativeformats)) {
04054          char tmp[256];
04055          ast_log(LOG_WARNING,
04056                "Asked to transmit frame type %s, while native formats is %s (read/write = (%s/%s)\n",
04057                ast_getformatname(frame->subclass.codec),
04058                ast_getformatname_multiple(tmp, sizeof(tmp), ast->nativeformats),
04059                ast_getformatname(ast->readformat),
04060                ast_getformatname(ast->writeformat));
04061          return -1;
04062       }
04063    }
04064 
04065    if (sub) {
04066       ast_mutex_lock(&sub->lock);
04067       if (sub->rtp) {
04068          res = ast_rtp_instance_write(sub->rtp, frame);
04069       }
04070       ast_mutex_unlock(&sub->lock);
04071    }
04072 
04073    return res;
04074 }
04075 
04076 static int unistim_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
04077 {
04078    struct unistim_subchannel *p = newchan->tech_pvt;
04079    struct unistim_line *l = p->parent;
04080 
04081    ast_mutex_lock(&p->lock);
04082 
04083    ast_debug(1, "New owner for channel USTM/%s@%s-%d is %s\n", l->name,
04084          l->parent->name, p->subtype, newchan->name);
04085 
04086    if (p->owner != oldchan) {
04087       ast_log(LOG_WARNING, "old channel wasn't %s (%p) but was %s (%p)\n",
04088             oldchan->name, oldchan, p->owner->name, p->owner);
04089       return -1;
04090    }
04091 
04092    p->owner = newchan;
04093 
04094    ast_mutex_unlock(&p->lock);
04095 
04096    return 0;
04097 
04098 }
04099 
04100 static char *control2str(int ind)
04101 {
04102    switch (ind) {
04103    case AST_CONTROL_HANGUP:
04104       return "Other end has hungup";
04105    case AST_CONTROL_RING:
04106       return "Local ring";
04107    case AST_CONTROL_RINGING:
04108       return "Remote end is ringing";
04109    case AST_CONTROL_ANSWER:
04110       return "Remote end has answered";
04111    case AST_CONTROL_BUSY:
04112       return "Remote end is busy";
04113    case AST_CONTROL_TAKEOFFHOOK:
04114       return "Make it go off hook";
04115    case AST_CONTROL_OFFHOOK:
04116       return "Line is off hook";
04117    case AST_CONTROL_CONGESTION:
04118       return "Congestion (circuits busy)";
04119    case AST_CONTROL_FLASH:
04120       return "Flash hook";
04121    case AST_CONTROL_WINK:
04122       return "Wink";
04123    case AST_CONTROL_OPTION:
04124       return "Set a low-level option";
04125    case AST_CONTROL_RADIO_KEY:
04126       return "Key Radio";
04127    case AST_CONTROL_RADIO_UNKEY:
04128       return "Un-Key Radio";
04129    case -1:
04130       return "Stop tone";
04131    }
04132    return "UNKNOWN";
04133 }
04134 
04135 static void in_band_indication(struct ast_channel *ast, const struct ast_tone_zone *tz,
04136    const char *indication)
04137 {
04138    struct ast_tone_zone_sound *ts = NULL;
04139 
04140    if ((ts = ast_get_indication_tone(tz, indication))) {
04141       ast_playtones_start(ast, 0, ts->data, 1);
04142       ts = ast_tone_zone_sound_unref(ts);
04143    } else {
04144       ast_log(LOG_WARNING, "Unable to get indication tone for %s\n", indication);
04145    }
04146 }
04147 
04148 static int unistim_indicate(struct ast_channel *ast, int ind, const void *data, 
04149    size_t datalen)
04150 {
04151    struct unistim_subchannel *sub;
04152    struct unistim_line *l;
04153    struct unistimsession *s;
04154 
04155    if (unistimdebug) {
04156       ast_verb(3, "Asked to indicate '%s' condition on channel %s\n",
04157                control2str(ind), ast->name);
04158    }
04159 
04160    s = channel_to_session(ast);
04161    if (!s)
04162       return -1;
04163 
04164    sub = ast->tech_pvt;
04165    l = sub->parent;
04166 
04167    switch (ind) {
04168    case AST_CONTROL_RINGING:
04169       if (ast->_state != AST_STATE_UP) {
04170          send_text(TEXT_LINE2, TEXT_NORMAL, s, "Ringing...");
04171          in_band_indication(ast, l->parent->tz, "ring");
04172          s->device->missed_call = -1;
04173          break;
04174       }
04175       return -1;
04176    case AST_CONTROL_BUSY:
04177       if (ast->_state != AST_STATE_UP) {
04178          sub->alreadygone = 1;
04179          send_text(TEXT_LINE2, TEXT_NORMAL, s, "Busy");
04180          in_band_indication(ast, l->parent->tz, "busy");
04181          s->device->missed_call = -1;
04182          break;
04183       }
04184       return -1;
04185    case AST_CONTROL_CONGESTION:
04186       if (ast->_state != AST_STATE_UP) {
04187          sub->alreadygone = 1;
04188          send_text(TEXT_LINE2, TEXT_NORMAL, s, "Congestion");
04189          in_band_indication(ast, l->parent->tz, "congestion");
04190          s->device->missed_call = -1;
04191          break;
04192       }
04193       return -1;
04194    case AST_CONTROL_HOLD:
04195       ast_moh_start(ast, data, NULL);
04196       break;
04197    case AST_CONTROL_UNHOLD:
04198       ast_moh_stop(ast);
04199       break;
04200    case AST_CONTROL_PROGRESS:
04201    case AST_CONTROL_SRCUPDATE:
04202       break;
04203    case -1:
04204       ast_playtones_stop(ast);
04205       s->device->missed_call = 0;
04206       break;
04207    case AST_CONTROL_PROCEEDING:
04208       break;
04209    default:
04210       ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
04211       return -1;
04212    }
04213 
04214    return 0;
04215 }
04216 
04217 static struct unistim_subchannel *find_subchannel_by_name(const char *dest)
04218 {
04219    struct unistim_line *l;
04220    struct unistim_device *d;
04221    char line[256];
04222    char *at;
04223    char *device;
04224 
04225    ast_copy_string(line, dest, sizeof(line));
04226    at = strchr(line, '@');
04227    if (!at) {
04228       ast_log(LOG_NOTICE, "Device '%s' has no @ (at) sign!\n", dest);
04229       return NULL;
04230    }
04231    *at = '\0';
04232    at++;
04233    device = at;
04234    ast_mutex_lock(&devicelock);
04235    d = devices;
04236    at = strchr(device, '/');       /* Extra options ? */
04237    if (at)
04238       *at = '\0';
04239    while (d) {
04240       if (!strcasecmp(d->name, device)) {
04241          if (unistimdebug)
04242             ast_verb(0, "Found device: %s\n", d->name);
04243          /* Found the device */
04244          l = d->lines;
04245          while (l) {
04246             /* Search for the right line */
04247             if (!strcasecmp(l->name, line)) {
04248                l->subs[SUB_REAL]->ringvolume = -1;
04249                l->subs[SUB_REAL]->ringstyle = -1;
04250                if (at) {       /* Other options ? */
04251                   at++;   /* Skip slash */
04252                   if (*at == 'r') {       /* distinctive ring */
04253                      at++;
04254                      if ((*at < '0') || (*at > '7')) /* ring style */
04255                         ast_log(LOG_WARNING, "Invalid ring selection (%s)", at);
04256                      else {
04257                         char ring_volume = -1;
04258                         char ring_style = *at - '0';
04259                         at++;
04260                         if ((*at >= '0') && (*at <= '3'))       /* ring volume */
04261                            ring_volume = *at - '0';
04262                         if (unistimdebug)
04263                            ast_verb(0, "Distinctive ring : style #%d volume %d\n",
04264                                ring_style, ring_volume);
04265                         l->subs[SUB_REAL]->ringvolume = ring_volume;
04266                         l->subs[SUB_REAL]->ringstyle = ring_style;
04267                      }
04268                   }
04269                }
04270                ast_mutex_unlock(&devicelock);
04271                return l->subs[SUB_REAL];
04272             }
04273             l = l->next;
04274          }
04275       }
04276       d = d->next;
04277    }
04278    /* Device not found */
04279    ast_mutex_unlock(&devicelock);
04280 
04281    return NULL;
04282 }
04283 
04284 static int unistim_senddigit_begin(struct ast_channel *ast, char digit)
04285 {
04286    struct unistimsession *pte = channel_to_session(ast);
04287 
04288    if (!pte)
04289       return -1;
04290 
04291    return unistim_do_senddigit(pte, digit);
04292 }
04293 
04294 static int unistim_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
04295 {
04296    struct unistimsession *pte = channel_to_session(ast);
04297    struct ast_frame f = { 0, };
04298    struct unistim_subchannel *sub;
04299 
04300    sub = pte->device->lines->subs[SUB_REAL];
04301 
04302    if (!sub->owner || sub->alreadygone) {
04303       ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit_end\n");
04304       return -1;
04305    }
04306 
04307    if (unistimdebug)
04308       ast_verb(0, "Send Digit off %c\n", digit);
04309 
04310    if (!pte)
04311       return -1;
04312 
04313    send_tone(pte, 0, 0);
04314    f.frametype = AST_FRAME_DTMF;
04315    f.subclass.integer = digit;
04316    f.src = "unistim";
04317    ast_queue_frame(sub->owner, &f);
04318 
04319    return 0;
04320 }
04321 
04322 /*--- unistim_sendtext: Display a text on the phone screen ---*/
04323 /*      Called from PBX core text message functions */
04324 static int unistim_sendtext(struct ast_channel *ast, const char *text)
04325 {
04326    struct unistimsession *pte = channel_to_session(ast);
04327    int size;
04328    char tmp[TEXT_LENGTH_MAX + 1];
04329 
04330    if (unistimdebug)
04331       ast_verb(0, "unistim_sendtext called\n");
04332 
04333    if (!text) {
04334       ast_log(LOG_WARNING, "unistim_sendtext called with a null text\n");
04335       return 1;
04336    }
04337 
04338    size = strlen(text);
04339    if (text[0] == '@') {
04340       int pos = 0, i = 1, tok = 0, sz = 0;
04341       char label[11];
04342       char number[16];
04343       char icon = '\0';
04344       char cur = '\0';
04345 
04346       memset(label, 0, 11);
04347       memset(number, 0, 16);
04348       while (text[i]) {
04349          cur = text[i++];
04350          switch (tok) {
04351          case 0:
04352             if ((cur < '0') && (cur > '5')) {
04353                ast_log(LOG_WARNING,
04354                      "sendtext failed : position must be a number beetween 0 and 5\n");
04355                return 1;
04356             }
04357             pos = cur - '0';
04358             tok = 1;
04359             continue;
04360          case 1:
04361             if (cur != '@') {
04362                ast_log(LOG_WARNING, "sendtext failed : invalid position\n");
04363                return 1;
04364             }
04365             tok = 2;
04366             continue;
04367          case 2:
04368             if ((cur < '3') && (cur > '6')) {
04369                ast_log(LOG_WARNING,
04370                      "sendtext failed : icon must be a number beetween 32 and 63 (first digit invalid)\n");
04371                return 1;
04372             }
04373             icon = (cur - '0') * 10;
04374             tok = 3;
04375             continue;
04376          case 3:
04377             if ((cur < '0') && (cur > '9')) {
04378                ast_log(LOG_WARNING,
04379                      "sendtext failed : icon must be a number beetween 32 and 63 (second digit invalid)\n");
04380                return 1;
04381             }
04382             icon += (cur - '0');
04383             tok = 4;
04384             continue;
04385          case 4:
04386             if (cur != '@') {
04387                ast_log(LOG_WARNING,
04388                      "sendtext failed : icon must be a number beetween 32 and 63 (too many digits)\n");
04389                return 1;
04390             }
04391             tok = 5;
04392             continue;
04393          case 5:
04394             if (cur == '@') {
04395                tok = 6;
04396                sz = 0;
04397                continue;
04398             }
04399             if (sz > 10)
04400                continue;
04401             label[sz] = cur;
04402             sz++;
04403             continue;
04404          case 6:
04405             if (sz > 15) {
04406                ast_log(LOG_WARNING,
04407                      "sendtext failed : extension too long = %d (15 car max)\n",
04408                      sz);
04409                return 1;
04410             }
04411             number[sz] = cur;
04412             sz++;
04413             continue;
04414          }
04415       }
04416       if (tok != 6) {
04417          ast_log(LOG_WARNING, "sendtext failed : incomplet command\n");
04418          return 1;
04419       }
04420       if (!pte->device) {
04421          ast_log(LOG_WARNING, "sendtext failed : no device ?\n");
04422          return 1;
04423       }
04424       strcpy(pte->device->softkeylabel[pos], label);
04425       strcpy(pte->device->softkeynumber[pos], number);
04426       pte->device->softkeyicon[pos] = icon;
04427       send_favorite(pos, icon, pte, label);
04428       return 0;
04429    }
04430 
04431    if (size <= TEXT_LENGTH_MAX * 2) {
04432       if (pte->device->height == 1) {
04433          send_text(TEXT_LINE0, TEXT_NORMAL, pte, text);
04434       } else {
04435          send_text(TEXT_LINE0, TEXT_NORMAL, pte, "Message :");
04436          send_text(TEXT_LINE1, TEXT_NORMAL, pte, text);
04437       }
04438       if (size <= TEXT_LENGTH_MAX) {
04439          send_text(TEXT_LINE2, TEXT_NORMAL, pte, "");
04440          return 0;
04441       }
04442       memcpy(tmp, text + TEXT_LENGTH_MAX, TEXT_LENGTH_MAX);
04443       tmp[sizeof(tmp) - 1] = '\0';
04444       send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
04445       return 0;
04446    }
04447    send_text(TEXT_LINE0, TEXT_NORMAL, pte, text);
04448    memcpy(tmp, text + TEXT_LENGTH_MAX, TEXT_LENGTH_MAX);
04449    tmp[sizeof(tmp) - 1] = '\0';
04450    send_text(TEXT_LINE1, TEXT_NORMAL, pte, tmp);
04451    memcpy(tmp, text + TEXT_LENGTH_MAX * 2, TEXT_LENGTH_MAX);
04452    tmp[sizeof(tmp) - 1] = '\0';
04453    send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
04454    return 0;
04455 }
04456 
04457 /*--- unistim_send_mwi_to_peer: Send message waiting indication ---*/
04458 static int unistim_send_mwi_to_peer(struct unistimsession *s, unsigned int tick)
04459 {
04460    struct ast_event *event;
04461    int new;
04462    char *mailbox, *context;
04463    struct unistim_line *peer = s->device->lines;
04464 
04465    context = mailbox = ast_strdupa(peer->mailbox);
04466    strsep(&context, "@");
04467    if (ast_strlen_zero(context))
04468       context = "default";
04469 
04470    event = ast_event_get_cached(AST_EVENT_MWI,
04471       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
04472       AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
04473       AST_EVENT_IE_END);
04474 
04475    if (event) {
04476       new = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
04477       ast_event_destroy(event);
04478    } else { /* Fall back on checking the mailbox directly */
04479       new = ast_app_has_voicemail(peer->mailbox, "INBOX");
04480    }
04481 
04482    peer->nextmsgcheck = tick + TIMER_MWI;
04483 
04484    /* Return now if it's the same thing we told them last time */
04485    if (new == peer->lastmsgssent) {
04486       return 0;
04487    }
04488 
04489    peer->lastmsgssent = new;
04490    if (new == 0) {
04491       send_led_update(s, 0);
04492    } else {
04493       send_led_update(s, 1);
04494    }
04495 
04496    return 0;
04497 }
04498 
04499 /*--- unistim_new: Initiate a call in the UNISTIM channel */
04500 /*      called from unistim_request (calls from the pbx ) */
04501 static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state, const char *linkedid)
04502 {
04503    struct ast_channel *tmp;
04504    struct unistim_line *l;
04505    int fmt;
04506 
04507    if (!sub) {
04508       ast_log(LOG_WARNING, "subchannel null in unistim_new\n");
04509       return NULL;
04510    }
04511    if (!sub->parent) {
04512       ast_log(LOG_WARNING, "no line for subchannel %p\n", sub);
04513       return NULL;
04514    }
04515    l = sub->parent;
04516    tmp = ast_channel_alloc(1, state, l->cid_num, NULL, l->accountcode, l->exten,
04517       l->context, linkedid, l->amaflags, "%s@%s-%d", l->name, l->parent->name, sub->subtype);
04518    if (unistimdebug)
04519       ast_verb(0, "unistim_new sub=%d (%p) chan=%p\n", sub->subtype, sub, tmp);
04520    if (!tmp) {
04521       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
04522       return NULL;
04523    }
04524 
04525    tmp->nativeformats = l->capability;
04526    if (!tmp->nativeformats)
04527       tmp->nativeformats = CAPABILITY;
04528    fmt = ast_best_codec(tmp->nativeformats);
04529    if (unistimdebug) {
04530       char tmp1[256], tmp2[256], tmp3[256];
04531       ast_verb(0, "Best codec = %s from nativeformats %s (line cap=%s global=%s)\n",
04532          ast_getformatname(fmt),
04533          ast_getformatname_multiple(tmp1, sizeof(tmp1), tmp->nativeformats),
04534          ast_getformatname_multiple(tmp2, sizeof(tmp2), l->capability),
04535          ast_getformatname_multiple(tmp3, sizeof(tmp3), CAPABILITY));
04536    }
04537    if ((sub->rtp) && (sub->subtype == 0)) {
04538       if (unistimdebug)
04539          ast_verb(0, "New unistim channel with a previous rtp handle ?\n");
04540       tmp->fds[0] = ast_rtp_instance_fd(sub->rtp, 0);
04541       tmp->fds[1] = ast_rtp_instance_fd(sub->rtp, 1);
04542    }
04543    if (sub->rtp)
04544       ast_jb_configure(tmp, &global_jbconf);
04545       
04546 /*      tmp->type = type; */
04547    ast_setstate(tmp, state);
04548    if (state == AST_STATE_RING)
04549       tmp->rings = 1;
04550    tmp->adsicpe = AST_ADSI_UNAVAILABLE;
04551    tmp->writeformat = fmt;
04552    tmp->rawwriteformat = fmt;
04553    tmp->readformat = fmt;
04554    tmp->rawreadformat = fmt;
04555    tmp->tech_pvt = sub;
04556    tmp->tech = &unistim_tech;
04557    if (!ast_strlen_zero(l->language))
04558       ast_string_field_set(tmp, language, l->language);
04559    sub->owner = tmp;
04560    ast_mutex_lock(&usecnt_lock);
04561    usecnt++;
04562    ast_mutex_unlock(&usecnt_lock);
04563    ast_update_use_count();
04564    tmp->callgroup = l->callgroup;
04565    tmp->pickupgroup = l->pickupgroup;
04566    ast_string_field_set(tmp, call_forward, l->parent->call_forward);
04567    if (!ast_strlen_zero(l->cid_num)) {
04568       char *name, *loc, *instr;
04569       instr = ast_strdup(l->cid_num);
04570       if (instr) {
04571          ast_callerid_parse(instr, &name, &loc);
04572          tmp->caller.id.number.valid = 1;
04573          ast_free(tmp->caller.id.number.str);
04574          tmp->caller.id.number.str = ast_strdup(loc);
04575          tmp->caller.id.name.valid = 1;
04576          ast_free(tmp->caller.id.name.str);
04577          tmp->caller.id.name.str = ast_strdup(name);
04578          ast_free(instr);
04579       }
04580    }
04581    tmp->priority = 1;
04582    if (state != AST_STATE_DOWN) {
04583       if (unistimdebug)
04584          ast_verb(0, "Starting pbx in unistim_new\n");
04585       if (ast_pbx_start(tmp)) {
04586          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
04587          ast_hangup(tmp);
04588          tmp = NULL;
04589       }
04590    }
04591 
04592    return tmp;
04593 }
04594 
04595 static void *do_monitor(void *data)
04596 {
04597    struct unistimsession *cur = NULL;
04598    unsigned int dw_timeout = 0;
04599    unsigned int tick;
04600    int res;
04601    int reloading;
04602 
04603    /* Add an I/O event to our UDP socket */
04604    if (unistimsock > -1)
04605       ast_io_add(io, unistimsock, unistimsock_read, AST_IO_IN, NULL);
04606 
04607    /* This thread monitors our UDP socket and timers */
04608    for (;;) {
04609       /* This loop is executed at least every IDLE_WAITus (1s) or every time a packet is received */
04610       /* Looking for the smallest time-out value */
04611       tick = get_tick_count();
04612       dw_timeout = UINT_MAX;
04613       ast_mutex_lock(&sessionlock);
04614       cur = sessions;
04615       DEBUG_TIMER("checking timeout for session %p with tick = %u\n", cur, tick);
04616       while (cur) {
04617          DEBUG_TIMER("checking timeout for session %p timeout = %u\n", cur,
04618                   cur->timeout);
04619          /* Check if we have miss something */
04620          if (cur->timeout <= tick) {
04621             DEBUG_TIMER("Event for session %p\n", cur);
04622             /* If the queue is empty, send a ping */
04623             if (cur->last_buf_available == 0)
04624                send_ping(cur);
04625             else {
04626                if (send_retransmit(cur)) {
04627                   DEBUG_TIMER("The chained link was modified, restarting...\n");
04628                   cur = sessions;
04629                   dw_timeout = UINT_MAX;
04630                   continue;
04631                }
04632             }
04633          }
04634          if (dw_timeout > cur->timeout - tick)
04635             dw_timeout = cur->timeout - tick;
04636          /* Checking if the phone is logged on for a new MWI */
04637          if (cur->device) {
04638             if ((!ast_strlen_zero(cur->device->lines->mailbox)) &&
04639                ((tick >= cur->device->lines->nextmsgcheck))) {
04640                DEBUG_TIMER("Checking mailbox for MWI\n");
04641                unistim_send_mwi_to_peer(cur, tick);
04642                break;
04643             }
04644          }
04645          cur = cur->next;
04646       }
04647       ast_mutex_unlock(&sessionlock);
04648       DEBUG_TIMER("Waiting for %dus\n", dw_timeout);
04649       res = dw_timeout;
04650       /* We should not wait more than IDLE_WAIT */
04651       if ((res < 0) || (res > IDLE_WAIT))
04652          res = IDLE_WAIT;
04653       /* Wait for UDP messages for a maximum of res us */
04654       res = ast_io_wait(io, res);     /* This function will call unistimsock_read if a packet is received */
04655       /* Check for a reload request */
04656       ast_mutex_lock(&unistim_reload_lock);
04657       reloading = unistim_reloading;
04658       unistim_reloading = 0;
04659       ast_mutex_unlock(&unistim_reload_lock);
04660       if (reloading) {
04661          ast_verb(1, "Reloading unistim.conf...\n");
04662          reload_config();
04663       }
04664       pthread_testcancel();
04665    }
04666    /* Never reached */
04667    return NULL;
04668 }
04669 
04670 /*--- restart_monitor: Start the channel monitor thread ---*/
04671 static int restart_monitor(void)
04672 {
04673    pthread_attr_t attr;
04674    /* If we're supposed to be stopped -- stay stopped */
04675    if (monitor_thread == AST_PTHREADT_STOP)
04676       return 0;
04677    if (ast_mutex_lock(&monlock)) {
04678       ast_log(LOG_WARNING, "Unable to lock monitor\n");
04679       return -1;
04680    }
04681    if (monitor_thread == pthread_self()) {
04682       ast_mutex_unlock(&monlock);
04683       ast_log(LOG_WARNING, "Cannot kill myself\n");
04684       return -1;
04685    }
04686    if (monitor_thread != AST_PTHREADT_NULL) {
04687       /* Wake up the thread */
04688       pthread_kill(monitor_thread, SIGURG);
04689    } else {
04690       pthread_attr_init(&attr);
04691       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
04692       /* Start a new monitor */
04693       if (ast_pthread_create(&monitor_thread, &attr, do_monitor, NULL) < 0) {
04694          ast_mutex_unlock(&monlock);
04695          ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
04696          return -1;
04697       }
04698    }
04699    ast_mutex_unlock(&monlock);
04700    return 0;
04701 }
04702 
04703 /*--- unistim_request: PBX interface function ---*/
04704 /* UNISTIM calls initiated by the PBX arrive here */
04705 static struct ast_channel *unistim_request(const char *type, format_t format, const struct ast_channel *requestor, void *data,
04706                                  int *cause)
04707 {
04708    format_t oldformat;
04709    struct unistim_subchannel *sub;
04710    struct ast_channel *tmpc = NULL;
04711    char tmp[256];
04712    char *dest = data;
04713 
04714    oldformat = format;
04715    format &= CAPABILITY;
04716    ast_log(LOG_NOTICE,
04717          "Asked to get a channel of format %s while capability is %s result : %s\n",
04718          ast_getformatname(oldformat),
04719          ast_getformatname_multiple(tmp, sizeof(tmp), CAPABILITY),
04720          ast_getformatname(format));
04721    if (!format) {
04722       ast_log(LOG_NOTICE,
04723             "Asked to get a channel of unsupported format %s while capability is %s\n",
04724             ast_getformatname(oldformat), ast_getformatname_multiple(tmp, sizeof(tmp), CAPABILITY));
04725       return NULL;
04726    }
04727 
04728    ast_copy_string(tmp, dest, sizeof(tmp));
04729    if (ast_strlen_zero(tmp)) {
04730       ast_log(LOG_NOTICE, "Unistim channels require a device\n");
04731       return NULL;
04732    }
04733 
04734    sub = find_subchannel_by_name(tmp);
04735    if (!sub) {
04736       ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
04737       *cause = AST_CAUSE_CONGESTION;
04738       return NULL;
04739    }
04740 
04741    ast_verb(3, "unistim_request(%s)\n", tmp);
04742    /* Busy ? */
04743    if (sub->owner) {
04744       if (unistimdebug)
04745          ast_verb(0, "Can't create channel : Busy !\n");
04746       *cause = AST_CAUSE_BUSY;
04747       return NULL;
04748    }
04749    sub->parent->capability = format;
04750    tmpc = unistim_new(sub, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
04751    if (!tmpc)
04752       ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
04753    if (unistimdebug)
04754       ast_verb(0, "unistim_request owner = %p\n", sub->owner);
04755    restart_monitor();
04756 
04757    /* and finish */
04758    return tmpc;
04759 }
04760 
04761 static char *unistim_info(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04762 {
04763    struct unistim_device *device = devices;
04764    struct unistim_line *line;
04765    struct unistim_subchannel *sub;
04766    struct unistimsession *s;
04767    int i;
04768    struct ast_channel *tmp;
04769 
04770    switch (cmd) {
04771    case CLI_INIT:
04772       e->command = "unistim show info";
04773       e->usage =
04774          "Usage: unistim show info\n" 
04775          "       Dump internal structures.\n";
04776       return NULL;
04777 
04778    case CLI_GENERATE:
04779       return NULL;   /* no completion */
04780    }
04781 
04782    if (a->argc != e->args)
04783       return CLI_SHOWUSAGE;
04784 
04785    ast_cli(a->fd, "Dumping internal structures :\ndevice\n->line\n-->sub\n");
04786    while (device) {
04787       ast_cli(a->fd, "\nname=%s id=%s line=%p ha=%p sess=%p device=%p\n",
04788             device->name, device->id, device->lines, device->ha, device->session,
04789             device);
04790       line = device->lines;
04791       while (line) {
04792          ast_cli(a->fd,
04793                "->name=%s fullname=%s exten=%s callid=%s cap=%" PRId64 " device=%p line=%p\n",
04794                line->name, line->fullname, line->exten, line->cid_num,
04795                line->capability, line->parent, line);
04796          for (i = 0; i < MAX_SUBS; i++) {
04797             sub = line->subs[i];
04798             if (!sub)
04799                continue;
04800             if (!sub->owner)
04801                tmp = (void *) -42;
04802             else
04803                tmp = sub->owner->_bridge;
04804             if (sub->subtype != i)
04805                ast_cli(a->fd, "Warning ! subchannel->subs[%d] have a subtype=%d\n", i,
04806                      sub->subtype);
04807             ast_cli(a->fd,
04808                   "-->subtype=%d chan=%p rtp=%p bridge=%p line=%p alreadygone=%d\n",
04809                   sub->subtype, sub->owner, sub->rtp, tmp, sub->parent,
04810                   sub->alreadygone);
04811          }
04812          line = line->next;
04813       }
04814       device = device->next;
04815    }
04816    ast_cli(a->fd, "\nSessions:\n");
04817    ast_mutex_lock(&sessionlock);
04818    s = sessions;
04819    while (s) {
04820       ast_cli(a->fd,
04821             "sin=%s timeout=%u state=%d macaddr=%s device=%p session=%p\n",
04822             ast_inet_ntoa(s->sin.sin_addr), s->timeout, s->state, s->macaddr,
04823             s->device, s);
04824       s = s->next;
04825    }
04826    ast_mutex_unlock(&sessionlock);
04827 
04828    return CLI_SUCCESS;
04829 }
04830 
04831 static char *unistim_sp(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04832 {
04833    BUFFSEND;
04834    struct unistim_subchannel *sub;
04835    int i, j = 0, len;
04836    unsigned char c, cc;
04837    char tmp[256];
04838 
04839    switch (cmd) {
04840    case CLI_INIT:
04841       e->command = "unistim send packet";
04842       e->usage =
04843          "Usage: unistim send packet USTM/line@name hexa\n"
04844          "       unistim send packet USTM/1000@hans 19040004\n";
04845       return NULL;
04846 
04847    case CLI_GENERATE:
04848       return NULL;   /* no completion */
04849    }
04850    
04851    if (a->argc < 5)
04852       return CLI_SHOWUSAGE;
04853 
04854    if (strlen(a->argv[3]) < 9)
04855       return CLI_SHOWUSAGE;
04856 
04857    len = strlen(a->argv[4]);
04858    if (len % 2)
04859       return CLI_SHOWUSAGE;
04860 
04861    ast_copy_string(tmp, a->argv[3] + 5, sizeof(tmp));
04862    sub = find_subchannel_by_name(tmp);
04863    if (!sub) {
04864       ast_cli(a->fd, "Can't find '%s'\n", tmp);
04865       return CLI_SUCCESS;
04866    }
04867    if (!sub->parent->parent->session) {
04868       ast_cli(a->fd, "'%s' is not connected\n", tmp);
04869       return CLI_SUCCESS;
04870    }
04871    ast_cli(a->fd, "Sending '%s' to %s (%p)\n", a->argv[4], tmp, sub->parent->parent->session);
04872    for (i = 0; i < len; i++) {
04873       c = a->argv[4][i];
04874       if (c >= 'a')
04875          c -= 'a' - 10;
04876       else
04877          c -= '0';
04878       i++;
04879       cc = a->argv[4][i];
04880       if (cc >= 'a')
04881          cc -= 'a' - 10;
04882       else
04883          cc -= '0';
04884       tmp[j++] = (c << 4) | cc;
04885    }
04886    memcpy(buffsend + SIZE_HEADER, tmp, j);
04887    send_client(SIZE_HEADER + j, buffsend, sub->parent->parent->session);
04888    return CLI_SUCCESS;
04889 }
04890 
04891 static char *unistim_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04892 {
04893    switch (cmd) {
04894    case CLI_INIT:
04895       e->command = "unistim set debug {on|off}";
04896       e->usage =
04897          "Usage: unistim set debug\n" 
04898          "       Display debug messages.\n";
04899       return NULL;
04900 
04901    case CLI_GENERATE:
04902       return NULL;   /* no completion */
04903    }
04904 
04905    if (a->argc != e->args)
04906       return CLI_SHOWUSAGE;
04907 
04908    if (!strcasecmp(a->argv[3], "on")) {
04909       unistimdebug = 1;
04910       ast_cli(a->fd, "UNISTIM Debugging Enabled\n");
04911    } else if (!strcasecmp(a->argv[3], "off")) {
04912       unistimdebug = 0;
04913       ast_cli(a->fd, "UNISTIM Debugging Disabled\n");
04914    } else
04915       return CLI_SHOWUSAGE;
04916 
04917    return CLI_SUCCESS;
04918 }
04919 
04920 /*! \brief --- unistim_reload: Force reload of module from cli ---
04921  * Runs in the asterisk main thread, so don't do anything useful
04922  * but setting a flag and waiting for do_monitor to do the job
04923  * in our thread */
04924 static char *unistim_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04925 {
04926    switch (cmd) {
04927    case CLI_INIT:
04928       e->command = "unistim reload";
04929       e->usage =
04930          "Usage: unistim reload\n" 
04931          "       Reloads UNISTIM configuration from unistim.conf\n";
04932       return NULL;
04933 
04934    case CLI_GENERATE:
04935       return NULL;   /* no completion */
04936    }
04937 
04938    if (e && a && a->argc != e->args)
04939       return CLI_SHOWUSAGE;
04940 
04941    if (unistimdebug)
04942       ast_verb(0, "reload unistim\n");
04943 
04944    ast_mutex_lock(&unistim_reload_lock);
04945    if (!unistim_reloading)
04946       unistim_reloading = 1;
04947    ast_mutex_unlock(&unistim_reload_lock);
04948 
04949    restart_monitor();
04950 
04951    return CLI_SUCCESS;
04952 }
04953 
04954 static struct ast_cli_entry unistim_cli[] = {
04955    AST_CLI_DEFINE(unistim_reload, "Reload UNISTIM configuration"),
04956    AST_CLI_DEFINE(unistim_info, "Show UNISTIM info"),
04957    AST_CLI_DEFINE(unistim_sp, "Send packet (for reverse engineering)"),
04958    AST_CLI_DEFINE(unistim_do_debug, "Toggle UNITSTIM debugging"),
04959 };
04960 
04961 static void unquote(char *out, const char *src, int maxlen)
04962 {
04963    int len = strlen(src);
04964    if (!len)
04965       return;
04966    if ((len > 1) && src[0] == '\"') {
04967       /* This is a quoted string */
04968       src++;
04969       /* Don't take more than what's there */
04970       len--;
04971       if (maxlen > len - 1)
04972          maxlen = len - 1;
04973       memcpy(out, src, maxlen);
04974       ((char *) out)[maxlen] = '\0';
04975    } else
04976       memcpy(out, src, maxlen);
04977    return;
04978 }
04979 
04980 static int ParseBookmark(const char *text, struct unistim_device *d)
04981 {
04982    char line[256];
04983    char *at;
04984    char *number;
04985    char *icon;
04986    int p;
04987    int len = strlen(text);
04988 
04989    ast_copy_string(line, text, sizeof(line));
04990    /* Position specified ? */
04991    if ((len > 2) && (line[1] == '@')) {
04992       p = line[0];
04993       if ((p >= '0') && (p <= '5'))
04994          p -= '0';
04995       else {
04996          ast_log(LOG_WARNING,
04997                "Invalid position for bookmark : must be between 0 and 5\n");
04998          return 0;
04999       }
05000       if (d->softkeyicon[p] != 0) {
05001          ast_log(LOG_WARNING, "Invalid position %d for bookmark : already used\n:", p);
05002          return 0;
05003       }
05004       memmove(line, line + 2, sizeof(line));
05005    } else {
05006       /* No position specified, looking for a free slot */
05007       for (p = 0; p <= 5; p++) {
05008          if (!d->softkeyicon[p])
05009             break;
05010       }
05011       if (p > 5) {
05012          ast_log(LOG_WARNING, "No more free bookmark position\n");
05013          return 0;
05014       }
05015    }
05016    at = strchr(line, '@');
05017    if (!at) {
05018       ast_log(LOG_NOTICE, "Bookmark entry '%s' has no @ (at) sign!\n", text);
05019       return 0;
05020    }
05021    *at = '\0';
05022    at++;
05023    number = at;
05024    at = strchr(at, '@');
05025    if (ast_strlen_zero(number)) {
05026       ast_log(LOG_NOTICE, "Bookmark entry '%s' has no number\n", text);
05027       return 0;
05028    }
05029    if (ast_strlen_zero(line)) {
05030       ast_log(LOG_NOTICE, "Bookmark entry '%s' has no description\n", text);
05031       return 0;
05032    }
05033 
05034    at = strchr(number, '@');
05035    if (!at)
05036       d->softkeyicon[p] = FAV_ICON_SHARP;     /* default icon */
05037    else {
05038       *at = '\0';
05039       at++;
05040       icon = at;
05041       if (ast_strlen_zero(icon)) {
05042          ast_log(LOG_NOTICE, "Bookmark entry '%s' has no icon value\n", text);
05043          return 0;
05044       }
05045       if (strncmp(icon, "USTM/", 5))
05046          d->softkeyicon[p] = atoi(icon);
05047       else {
05048          d->softkeyicon[p] = 1;
05049          ast_copy_string(d->softkeydevice[p], icon + 5, sizeof(d->softkeydevice[p]));
05050       }
05051    }
05052    ast_copy_string(d->softkeylabel[p], line, sizeof(d->softkeylabel[p]));
05053    ast_copy_string(d->softkeynumber[p], number, sizeof(d->softkeynumber[p]));
05054    if (unistimdebug)
05055       ast_verb(0, "New bookmark at pos %d label='%s' number='%s' icon=%x\n",
05056                p, d->softkeylabel[p], d->softkeynumber[p], d->softkeyicon[p]);
05057    return 1;
05058 }
05059 
05060 /* Looking for dynamic icons entries in bookmarks */
05061 static void finish_bookmark(void)
05062 {
05063    struct unistim_device *d = devices;
05064    int i;
05065    while (d) {
05066       for (i = 0; i < 6; i++) {
05067          if (d->softkeyicon[i] == 1) {   /* Something for us */
05068             struct unistim_device *d2 = devices;
05069             while (d2) {
05070                if (!strcmp(d->softkeydevice[i], d2->name)) {
05071                   d->sp[i] = d2;
05072                   d->softkeyicon[i] = 0;
05073                   break;
05074                }
05075                d2 = d2->next;
05076             }
05077             if (d->sp[i] == NULL)
05078                ast_log(LOG_NOTICE, "Bookmark entry with device %s not found\n",
05079                      d->softkeydevice[i]);
05080          }
05081       }
05082       d = d->next;
05083    }
05084 }
05085 
05086 static struct unistim_device *build_device(const char *cat, const struct ast_variable *v)
05087 {
05088    struct unistim_device *d;
05089    struct unistim_line *l = NULL;
05090    int create = 1;
05091    int nbsoftkey, dateformat, timeformat, callhistory;
05092    char linelabel[AST_MAX_EXTENSION];
05093    char context[AST_MAX_EXTENSION];
05094    char ringvolume, ringstyle;
05095 
05096    /* First, we need to know if we already have this name in our list */
05097    /* Get a lock for the device chained list */
05098    ast_mutex_lock(&devicelock);
05099    d = devices;
05100    while (d) {
05101       if (!strcmp(d->name, cat)) {
05102          /* Yep, we alreay have this one */
05103          if (unistimsock < 0) {
05104             /* It's a dupe */
05105             ast_log(LOG_WARNING, "Duplicate entry found (%s), ignoring.\n", cat);
05106             ast_mutex_unlock(&devicelock);
05107             return NULL;
05108          }
05109          /* we're reloading right now */
05110          create = 0;
05111          l = d->lines;
05112          break;
05113       }
05114       d = d->next;
05115    }
05116    ast_mutex_unlock(&devicelock);
05117    if (create) {
05118       if (!(d = ast_calloc(1, sizeof(*d))))
05119          return NULL;
05120 
05121       if (!(l = ast_calloc(1, sizeof(*l)))) {
05122          ast_free(d);
05123          return NULL;
05124       }
05125       ast_copy_string(d->name, cat, sizeof(d->name));
05126    }
05127    ast_copy_string(context, DEFAULTCONTEXT, sizeof(context));
05128    d->contrast = -1;
05129    d->output = OUTPUT_HANDSET;
05130    d->previous_output = OUTPUT_HANDSET;
05131    d->volume = VOLUME_LOW;
05132    d->mute = MUTE_OFF;
05133    d->height = DEFAULTHEIGHT;
05134    linelabel[0] = '\0';
05135    dateformat = 1;
05136    timeformat = 1;
05137    ringvolume = 2;
05138    callhistory = 1;
05139    ringstyle = 3;
05140    nbsoftkey = 0;
05141    while (v) {
05142       if (!strcasecmp(v->name, "rtp_port"))
05143          d->rtp_port = atoi(v->value);
05144       else if (!strcasecmp(v->name, "rtp_method"))
05145          d->rtp_method = atoi(v->value);
05146       else if (!strcasecmp(v->name, "status_method"))
05147          d->status_method = atoi(v->value);
05148       else if (!strcasecmp(v->name, "device"))
05149          ast_copy_string(d->id, v->value, sizeof(d->id));
05150       else if (!strcasecmp(v->name, "tn"))
05151          ast_copy_string(d->extension_number, v->value, sizeof(d->extension_number));
05152       else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny"))
05153          d->ha = ast_append_ha(v->name, v->value, d->ha, NULL);
05154       else if (!strcasecmp(v->name, "context"))
05155          ast_copy_string(context, v->value, sizeof(context));
05156       else if (!strcasecmp(v->name, "maintext0"))
05157          unquote(d->maintext0, v->value, sizeof(d->maintext0) - 1);
05158       else if (!strcasecmp(v->name, "maintext1"))
05159          unquote(d->maintext1, v->value, sizeof(d->maintext1) - 1);
05160       else if (!strcasecmp(v->name, "maintext2"))
05161          unquote(d->maintext2, v->value, sizeof(d->maintext2) - 1);
05162       else if (!strcasecmp(v->name, "titledefault"))
05163          unquote(d->titledefault, v->value, sizeof(d->titledefault) - 1);
05164       else if (!strcasecmp(v->name, "dateformat"))
05165          dateformat = atoi(v->value);
05166       else if (!strcasecmp(v->name, "timeformat"))
05167          timeformat = atoi(v->value);
05168       else if (!strcasecmp(v->name, "contrast")) {
05169          d->contrast = atoi(v->value);
05170          if ((d->contrast < 0) || (d->contrast > 15)) {
05171             ast_log(LOG_WARNING, "constrast must be beetween 0 and 15");
05172             d->contrast = 8;
05173          }
05174       } else if (!strcasecmp(v->name, "nat"))
05175          d->nat = ast_true(v->value);
05176       else if (!strcasecmp(v->name, "ringvolume"))
05177          ringvolume = atoi(v->value);
05178       else if (!strcasecmp(v->name, "ringstyle"))
05179          ringstyle = atoi(v->value);
05180       else if (!strcasecmp(v->name, "callhistory"))
05181          callhistory = atoi(v->value);
05182       else if (!strcasecmp(v->name, "callerid")) {
05183          if (!strcasecmp(v->value, "asreceived"))
05184             l->cid_num[0] = '\0';
05185          else
05186             ast_copy_string(l->cid_num, v->value, sizeof(l->cid_num));
05187       } else if (!strcasecmp(v->name, "language"))
05188          ast_copy_string(l->language, v->value, sizeof(l->language));
05189       else if (!strcasecmp(v->name, "country"))
05190          ast_copy_string(d->country, v->value, sizeof(d->country));
05191       else if (!strcasecmp(v->name, "accountcode"))
05192          ast_copy_string(l->accountcode, v->value, sizeof(l->accountcode));
05193       else if (!strcasecmp(v->name, "amaflags")) {
05194          int y;
05195          y = ast_cdr_amaflags2int(v->value);
05196          if (y < 0)
05197             ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value,
05198                   v->lineno);
05199          else
05200             l->amaflags = y;
05201       } else if (!strcasecmp(v->name, "musiconhold"))
05202          ast_copy_string(l->musicclass, v->value, sizeof(l->musicclass));
05203       else if (!strcasecmp(v->name, "callgroup"))
05204          l->callgroup = ast_get_group(v->value);
05205       else if (!strcasecmp(v->name, "pickupgroup"))
05206          l->pickupgroup = ast_get_group(v->value);
05207       else if (!strcasecmp(v->name, "mailbox"))
05208          ast_copy_string(l->mailbox, v->value, sizeof(l->mailbox));
05209       else if (!strcasecmp(v->name, "parkinglot"))
05210          ast_copy_string(l->parkinglot, v->value, sizeof(l->parkinglot));
05211       else if (!strcasecmp(v->name, "linelabel"))
05212          unquote(linelabel, v->value, sizeof(linelabel) - 1);
05213       else if (!strcasecmp(v->name, "extension")) {
05214          if (!strcasecmp(v->value, "none"))
05215             d->extension = EXTENSION_NONE;
05216          else if (!strcasecmp(v->value, "ask"))
05217             d->extension = EXTENSION_ASK;
05218          else if (!strcasecmp(v->value, "line"))
05219             d->extension = EXTENSION_LINE;
05220          else
05221             ast_log(LOG_WARNING, "Unknown extension option.\n");
05222       } else if (!strcasecmp(v->name, "bookmark")) {
05223          if (nbsoftkey > 5)
05224             ast_log(LOG_WARNING,
05225                   "More than 6 softkeys defined. Ignoring new entries.\n");
05226          else {
05227             if (ParseBookmark(v->value, d))
05228                nbsoftkey++;
05229          }
05230       } else if (!strcasecmp(v->name, "line")) {
05231          int len = strlen(linelabel);
05232 
05233          if (nbsoftkey) {
05234             ast_log(LOG_WARNING,
05235                   "You must use bookmark AFTER line=>. Only one line is supported in this version\n");
05236             if (create) {
05237                ast_free(d);
05238                ast_free(l);
05239             }
05240             return NULL;
05241          }
05242          if (create) {
05243             ast_mutex_init(&l->lock);
05244          } else {
05245             d->to_delete = 0;
05246             /* reset bookmarks */
05247             memset(d->softkeylabel, 0, sizeof(d->softkeylabel));
05248             memset(d->softkeynumber, 0, sizeof(d->softkeynumber));
05249             memset(d->softkeyicon, 0, sizeof(d->softkeyicon));
05250             memset(d->softkeydevice, 0, sizeof(d->softkeydevice));
05251             memset(d->sp, 0, sizeof(d->sp));
05252          }
05253          ast_copy_string(l->name, v->value, sizeof(l->name));
05254          snprintf(l->fullname, sizeof(l->fullname), "USTM/%s@%s", l->name, d->name);
05255          d->softkeyicon[0] = FAV_ICON_ONHOOK_BLACK;
05256          if (!len)             /* label is undefined ? */
05257             ast_copy_string(d->softkeylabel[0], v->value, sizeof(d->softkeylabel[0]));
05258          else {
05259             if ((len > 2) && (linelabel[1] == '@')) {
05260                d->softkeylinepos = linelabel[0];
05261                if ((d->softkeylinepos >= '0') && (d->softkeylinepos <= '5')) {
05262                   d->softkeylinepos -= '0';
05263                   d->softkeyicon[0] = 0;
05264                } else {
05265                   ast_log(LOG_WARNING,
05266                         "Invalid position for linelabel : must be between 0 and 5\n");
05267                   d->softkeylinepos = 0;
05268                }
05269                ast_copy_string(d->softkeylabel[d->softkeylinepos], linelabel + 2,
05270                            sizeof(d->softkeylabel[d->softkeylinepos]));
05271                d->softkeyicon[d->softkeylinepos] = FAV_ICON_ONHOOK_BLACK;
05272             } else
05273                ast_copy_string(d->softkeylabel[0], linelabel,
05274                            sizeof(d->softkeylabel[0]));
05275          }
05276          nbsoftkey++;
05277          ast_copy_string(l->context, context, sizeof(l->context));
05278          if (!ast_strlen_zero(l->mailbox)) {
05279             if (unistimdebug)
05280                ast_verb(3, "Setting mailbox '%s' on %s@%s\n", l->mailbox, d->name, l->name);
05281          }
05282 
05283          l->capability = CAPABILITY;
05284          l->parent = d;
05285 
05286          if (create) {
05287             if (!alloc_sub(l, SUB_REAL)) {
05288                ast_mutex_destroy(&l->lock);
05289                ast_free(l);
05290                ast_free(d);
05291                return NULL;
05292             }
05293             l->next = d->lines;
05294             d->lines = l;
05295          }
05296       } else if (!strcasecmp(v->name, "height")) {
05297          /* Allow the user to lower the expected display lines on the phone
05298           * For example the Nortal I2001 and I2002 only have one ! */
05299          d->height = atoi(v->value);
05300       } else
05301          ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name,
05302                v->lineno);
05303       v = v->next;
05304    }
05305    d->ringvolume = ringvolume;
05306    d->ringstyle = ringstyle;
05307    d->callhistory = callhistory;
05308    d->tz = ast_get_indication_zone(d->country);
05309    if ((d->tz == NULL) && !ast_strlen_zero(d->country))
05310       ast_log(LOG_WARNING, "Country '%s' was not found in indications.conf\n",
05311             d->country);
05312    d->datetimeformat = 56 + (dateformat * 4);
05313    d->datetimeformat += timeformat;
05314    if (!d->lines) {
05315       ast_log(LOG_ERROR, "An Unistim device must have at least one line!\n");
05316       ast_mutex_destroy(&l->lock);
05317       ast_free(l);
05318       if (d->tz) {
05319          d->tz = ast_tone_zone_unref(d->tz);
05320       }
05321       ast_free(d);
05322       return NULL;
05323    }
05324    if ((autoprovisioning == AUTOPROVISIONING_TN) &&
05325       (!ast_strlen_zero(d->extension_number))) {
05326       d->extension = EXTENSION_TN;
05327       if (!ast_strlen_zero(d->id))
05328          ast_log(LOG_WARNING,
05329                "tn= and device= can't be used together. Ignoring device= entry\n");
05330       d->id[0] = 'T';       /* magic : this is a tn entry */
05331       ast_copy_string((d->id) + 1, d->extension_number, sizeof(d->id) - 1);
05332       d->extension_number[0] = '\0';
05333    } else if (ast_strlen_zero(d->id)) {
05334       if (strcmp(d->name, "template")) {
05335          ast_log(LOG_ERROR, "You must specify the mac address with device=\n");
05336          ast_mutex_destroy(&l->lock);
05337          ast_free(l);
05338          if (d->tz) {
05339             d->tz = ast_tone_zone_unref(d->tz);
05340          }
05341          ast_free(d);
05342          return NULL;
05343       } else
05344          strcpy(d->id, "000000000000");
05345    }
05346    if (!d->rtp_port)
05347       d->rtp_port = 10000;
05348    if (d->contrast == -1)
05349       d->contrast = 8;
05350    if (ast_strlen_zero(d->maintext0))
05351       strcpy(d->maintext0, "Welcome");
05352    if (ast_strlen_zero(d->maintext1))
05353       strcpy(d->maintext1, d->name);
05354    if (ast_strlen_zero(d->titledefault)) {
05355       struct ast_tm tm = { 0, };
05356       struct timeval cur_time = ast_tvnow();
05357 
05358       if ((ast_localtime(&cur_time, &tm, 0)) == 0 || ast_strlen_zero(tm.tm_zone)) {
05359          display_last_error("Error in ast_localtime()");
05360          ast_copy_string(d->titledefault, "UNISTIM for*", 12);
05361       } else {
05362          if (strlen(tm.tm_zone) < 4) {
05363             strcpy(d->titledefault, "TimeZone ");
05364             strcat(d->titledefault, tm.tm_zone);
05365          } else if (strlen(tm.tm_zone) < 9) {
05366             strcpy(d->titledefault, "TZ ");
05367             strcat(d->titledefault, tm.tm_zone);
05368          } else
05369             ast_copy_string(d->titledefault, tm.tm_zone, 12);
05370       }
05371    }
05372    /* Update the chained link if it's a new device */
05373    if (create) {
05374       ast_mutex_lock(&devicelock);
05375       d->next = devices;
05376       devices = d;
05377       ast_mutex_unlock(&devicelock);
05378       ast_verb(3, "Added device '%s'\n", d->name);
05379    } else {
05380       ast_verb(3, "Device '%s' reloaded\n", d->name);
05381    }
05382    return d;
05383 }
05384 
05385 /*--- reload_config: Re-read unistim.conf config file ---*/
05386 static int reload_config(void)
05387 {
05388    struct ast_config *cfg;
05389    struct ast_variable *v;
05390    struct ast_hostent ahp;
05391    struct hostent *hp;
05392    struct sockaddr_in bindaddr = { 0, };
05393    char *config = "unistim.conf";
05394    char *cat;
05395    struct unistim_device *d;
05396    const int reuseFlag = 1;
05397    struct unistimsession *s;
05398    struct ast_flags config_flags = { 0, };
05399 
05400    cfg = ast_config_load(config, config_flags);
05401    /* We *must* have a config file otherwise stop immediately */
05402    if (!cfg) {
05403       ast_log(LOG_ERROR, "Unable to load config %s\n", config);
05404       return -1;
05405    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
05406       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
05407       return -1;
05408    }
05409    
05410    /* Copy the default jb config over global_jbconf */
05411    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
05412 
05413    unistim_keepalive = 120;
05414    unistim_port = 0;
05415    v = ast_variable_browse(cfg, "general");
05416    while (v) {
05417       /* handle jb conf */
05418       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
05419          continue;   
05420    
05421       if (!strcasecmp(v->name, "keepalive"))
05422          unistim_keepalive = atoi(v->value);
05423       else if (!strcasecmp(v->name, "port"))
05424          unistim_port = atoi(v->value);
05425                 else if (!strcasecmp(v->name, "tos")) {
05426                         if (ast_str2tos(v->value, &qos.tos))
05427                             ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
05428                 } else if (!strcasecmp(v->name, "tos_audio")) {
05429                         if (ast_str2tos(v->value, &qos.tos_audio))
05430                             ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
05431                 } else if (!strcasecmp(v->name, "cos")) {
05432                         if (ast_str2cos(v->value, &qos.cos))
05433                             ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
05434                 } else if (!strcasecmp(v->name, "cos_audio")) {
05435                         if (ast_str2cos(v->value, &qos.cos_audio))
05436                             ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
05437       } else if (!strcasecmp(v->name, "autoprovisioning")) {
05438          if (!strcasecmp(v->value, "no"))
05439             autoprovisioning = AUTOPROVISIONING_NO;
05440          else if (!strcasecmp(v->value, "yes"))
05441             autoprovisioning = AUTOPROVISIONING_YES;
05442          else if (!strcasecmp(v->value, "db"))
05443             autoprovisioning = AUTOPROVISIONING_DB;
05444          else if (!strcasecmp(v->value, "tn"))
05445             autoprovisioning = AUTOPROVISIONING_TN;
05446          else
05447             ast_log(LOG_WARNING, "Unknown autoprovisioning option.\n");
05448       } else if (!strcasecmp(v->name, "public_ip")) {
05449          if (!ast_strlen_zero(v->value)) {
05450             if (!(hp = ast_gethostbyname(v->value, &ahp)))
05451                ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
05452             else {
05453                memcpy(&public_ip.sin_addr, hp->h_addr, sizeof(public_ip.sin_addr));
05454                public_ip.sin_family = AF_INET;
05455             }
05456          }
05457       }
05458       v = v->next;
05459    }
05460    if ((unistim_keepalive < 10) ||
05461       (unistim_keepalive >
05462        255 - (((NB_MAX_RETRANSMIT + 1) * RETRANSMIT_TIMER) / 1000))) {
05463       ast_log(LOG_ERROR, "keepalive is invalid in %s\n", config);
05464       ast_config_destroy(cfg);
05465       return -1;
05466    }
05467    packet_send_ping[4] =
05468       unistim_keepalive + (((NB_MAX_RETRANSMIT + 1) * RETRANSMIT_TIMER) / 1000);
05469    if ((unistim_port < 1) || (unistim_port > 65535)) {
05470       ast_log(LOG_ERROR, "port is not set or invalid in %s\n", config);
05471       ast_config_destroy(cfg);
05472       return -1;
05473    }
05474    unistim_keepalive *= 1000;
05475 
05476    ast_mutex_lock(&devicelock);
05477    d = devices;
05478    while (d) {
05479       if (d->to_delete >= 0)
05480          d->to_delete = 1;
05481       d = d->next;
05482    }
05483    ast_mutex_unlock(&devicelock);
05484    /* load the device sections */
05485    cat = ast_category_browse(cfg, NULL);
05486    while (cat) {
05487       if (strcasecmp(cat, "general")) {
05488          d = build_device(cat, ast_variable_browse(cfg, cat));
05489       }
05490       cat = ast_category_browse(cfg, cat);
05491    }
05492    ast_mutex_lock(&devicelock);
05493    d = devices;
05494    while (d) {
05495       if (d->to_delete) {
05496          int i;
05497 
05498          if (unistimdebug)
05499             ast_verb(0, "Removing device '%s'\n", d->name);
05500          if (!d->lines) {
05501             ast_log(LOG_ERROR, "Device '%s' without a line !, aborting\n", d->name);
05502             ast_config_destroy(cfg);
05503             return 0;
05504          }
05505          if (!d->lines->subs[0]) {
05506             ast_log(LOG_ERROR, "Device '%s' without a subchannel !, aborting\n",
05507                   d->name);
05508             ast_config_destroy(cfg);
05509             return 0;
05510          }
05511          if (d->lines->subs[0]->owner) {
05512             ast_log(LOG_WARNING,
05513                   "Device '%s' was not deleted : a call is in progress. Try again later.\n",
05514                   d->name);
05515             d = d->next;
05516             continue;
05517          }
05518          ast_mutex_destroy(&d->lines->subs[0]->lock);
05519          ast_free(d->lines->subs[0]);
05520          for (i = 1; i < MAX_SUBS; i++) {
05521             if (d->lines->subs[i]) {
05522                ast_log(LOG_WARNING,
05523                      "Device '%s' with threeway call subchannels allocated, aborting.\n",
05524                      d->name);
05525                break;
05526             }
05527          }
05528          if (i < MAX_SUBS) {
05529             d = d->next;
05530             continue;
05531          }
05532          ast_mutex_destroy(&d->lines->lock);
05533          ast_free(d->lines);
05534          if (d->session) {
05535             if (sessions == d->session)
05536                sessions = d->session->next;
05537             else {
05538                s = sessions;
05539                while (s) {
05540                   if (s->next == d->session) {
05541                      s->next = d->session->next;
05542                      break;
05543                   }
05544                   s = s->next;
05545                }
05546             }
05547             ast_mutex_destroy(&d->session->lock);
05548             ast_free(d->session);
05549          }
05550          if (devices == d)
05551             devices = d->next;
05552          else {
05553             struct unistim_device *d2 = devices;
05554             while (d2) {
05555                if (d2->next == d) {
05556                   d2->next = d->next;
05557                   break;
05558                }
05559                d2 = d2->next;
05560             }
05561          }
05562          if (d->tz) {
05563             d->tz = ast_tone_zone_unref(d->tz);
05564          }
05565          ast_free(d);
05566          d = devices;
05567          continue;
05568       }
05569       d = d->next;
05570    }
05571    finish_bookmark();
05572    ast_mutex_unlock(&devicelock);
05573    ast_config_destroy(cfg);
05574    ast_mutex_lock(&sessionlock);
05575    s = sessions;
05576    while (s) {
05577       if (s->device)
05578          refresh_all_favorite(s);
05579       s = s->next;
05580    }
05581    ast_mutex_unlock(&sessionlock);
05582    /* We don't recreate a socket when reloading (locks would be necessary). */
05583    if (unistimsock > -1)
05584       return 0;
05585    bindaddr.sin_addr.s_addr = INADDR_ANY;
05586    bindaddr.sin_port = htons(unistim_port);
05587    bindaddr.sin_family = AF_INET;
05588    unistimsock = socket(AF_INET, SOCK_DGRAM, 0);
05589    if (unistimsock < 0) {
05590       ast_log(LOG_WARNING, "Unable to create UNISTIM socket: %s\n", strerror(errno));
05591       return -1;
05592    }
05593 #ifdef HAVE_PKTINFO
05594    {
05595       const int pktinfoFlag = 1;
05596       setsockopt(unistimsock, IPPROTO_IP, IP_PKTINFO, &pktinfoFlag,
05597                sizeof(pktinfoFlag));
05598    }
05599 #else
05600    if (public_ip.sin_family == 0) {
05601       ast_log(LOG_WARNING,
05602             "Your OS does not support IP_PKTINFO, you must set public_ip.\n");
05603       unistimsock = -1;
05604       return -1;
05605    }
05606 #endif
05607    setsockopt(unistimsock, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuseFlag,
05608             sizeof(reuseFlag));
05609    if (bind(unistimsock, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) < 0) {
05610       ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
05611             ast_inet_ntoa(bindaddr.sin_addr), htons(bindaddr.sin_port),
05612             strerror(errno));
05613       close(unistimsock);
05614       unistimsock = -1;
05615    } else {
05616       ast_verb(2, "UNISTIM Listening on %s:%d\n", ast_inet_ntoa(bindaddr.sin_addr), htons(bindaddr.sin_port));
05617       ast_netsock_set_qos(unistimsock, qos.tos, qos.cos, "UNISTIM");
05618    }
05619    return 0;
05620 }
05621 
05622 static enum ast_rtp_glue_result unistim_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
05623 {
05624    struct unistim_subchannel *sub = chan->tech_pvt;
05625 
05626    ao2_ref(sub->rtp, +1);
05627    *instance = sub->rtp;
05628 
05629    return AST_RTP_GLUE_RESULT_LOCAL;
05630 }
05631 
05632 static struct ast_rtp_glue unistim_rtp_glue = {
05633    .type = channel_type,
05634    .get_rtp_info = unistim_get_rtp_peer,
05635 };
05636 
05637 /*--- load_module: PBX load module - initialization ---*/
05638 int load_module(void)
05639 {
05640    int res;
05641 
05642    if (!(buff = ast_malloc(SIZE_PAGE)))
05643       goto buff_failed;
05644 
05645    io = io_context_create();
05646    if (!io) {
05647       ast_log(LOG_ERROR, "Failed to allocate IO context\n");
05648       goto io_failed;
05649    }
05650 
05651    sched = sched_context_create();
05652    if (!sched) {
05653       ast_log(LOG_ERROR, "Failed to allocate scheduler context\n");
05654       goto sched_failed;
05655    }
05656 
05657    res = reload_config();
05658    if (res)
05659       return AST_MODULE_LOAD_DECLINE;
05660 
05661    /* Make sure we can register our unistim channel type */
05662    if (ast_channel_register(&unistim_tech)) {
05663       ast_log(LOG_ERROR, "Unable to register channel type '%s'\n", channel_type);
05664       goto chanreg_failed;
05665    } 
05666 
05667    ast_rtp_glue_register(&unistim_rtp_glue);
05668 
05669    ast_cli_register_multiple(unistim_cli, ARRAY_LEN(unistim_cli));
05670 
05671    restart_monitor();
05672 
05673    return AST_MODULE_LOAD_SUCCESS;
05674 
05675 chanreg_failed:
05676    /*! XXX \todo Leaking anything allocated by reload_config() ... */
05677    sched_context_destroy(sched);
05678    sched = NULL;
05679 sched_failed:
05680    io_context_destroy(io);
05681    io = NULL;
05682 io_failed:
05683    ast_free(buff);
05684    buff = NULL;
05685 buff_failed:
05686    return AST_MODULE_LOAD_FAILURE;
05687 }
05688 
05689 static int unload_module(void)
05690 {
05691    /* First, take us out of the channel loop */
05692    if (sched)
05693       sched_context_destroy(sched);
05694 
05695    ast_cli_unregister_multiple(unistim_cli, ARRAY_LEN(unistim_cli));
05696 
05697    ast_channel_unregister(&unistim_tech);
05698    ast_rtp_glue_unregister(&unistim_rtp_glue);
05699 
05700    ast_mutex_lock(&monlock);
05701    if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
05702       pthread_cancel(monitor_thread);
05703       pthread_kill(monitor_thread, SIGURG);
05704       pthread_join(monitor_thread, NULL);
05705    }
05706    monitor_thread = AST_PTHREADT_STOP;
05707    ast_mutex_unlock(&monlock);
05708 
05709    if (buff)
05710       ast_free(buff);
05711    if (unistimsock > -1)
05712       close(unistimsock);
05713 
05714    return 0;
05715 }
05716 
05717 /*! reload: Part of Asterisk module interface ---*/
05718 int reload(void)
05719 {
05720    unistim_reload(NULL, 0, NULL);
05721    return 0;
05722 }
05723 
05724 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "UNISTIM Protocol (USTM)",
05725     .load = load_module,
05726     .unload = unload_module,
05727     .reload = reload,
05728 );