Mon Jun 27 16:50:52 2011

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

Generated on Mon Jun 27 16:50:52 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7