Fri Jun 19 12:09:40 2009

Asterisk developer's documentation


chan_unistim.c

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

Generated on Fri Jun 19 12:09:41 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7