Tue Mar 2 17:31:48 2010

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

Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1