Mon Oct 8 12:39:01 2012

Asterisk developer's documentation


chan_unistim.c

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

Generated on Mon Oct 8 12:39:01 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7