Thu Apr 28 2011 17:13:32

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