Sat Mar 10 01:54:13 2012

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

Generated on Sat Mar 10 01:54:13 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7