Tue Aug 20 16:34:30 2013

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

Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1