Thu Jul 9 13:40:31 2009

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

Generated on Thu Jul 9 13:40:31 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7