jansson-bundled: Patch for off-nominal crash.
[asterisk/asterisk.git] / channels / chan_unistim.c
index 3f6fd01..28d84ee 100644 (file)
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include <sys/stat.h>
 #include <signal.h>
 
-#if defined(__CYGWIN__)
+#if defined(__CYGWIN__) || defined(__NetBSD__)
 /*
  * cygwin headers are partly inconsistent. struct iovec is defined in sys/uio.h
  * which is not included by default by sys/socket.h - in_pktinfo is defined in
@@ -55,7 +53,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #ifdef HAVE_PKTINFO
 #undef HAVE_PKTINFO
 #endif
-#endif /* __CYGWIN__ */
+#endif /* __CYGWIN__ || __NetBSD__ */
 
 #include "asterisk/paths.h"    /* ast_config_AST_LOG_DIR used in (too ?) many places */
 #include "asterisk/network.h"
@@ -116,7 +114,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #define SUB_REAL               0
 #define SUB_RING                1
 #define SUB_THREEWAY            2
-#define SUB_ONHOLD              3
 
 struct ast_format_cap *global_cap;
 
@@ -163,6 +160,7 @@ enum autoprov_extn {
 #define LED_HEADPHONE_ON               0x011
 #define LED_MUTE_OFF                   0x018
 #define LED_MUTE_ON                    0x019
+#define LED_MUTE_BLINK                 0x1A
 
 #define SIZE_HEADER         6
 #define SIZE_MAC_ADDR     17
@@ -352,15 +350,16 @@ struct wsabuf {
 
 struct unistim_subchannel {
        ast_mutex_t lock;
-       unsigned int subtype;           /*! SUB_REAL, SUB_RING, SUB_THREEWAY or SUB_ONHOLD */
+       unsigned int subtype;           /*! SUB_REAL, SUB_RING or SUB_THREEWAY */
        struct ast_channel *owner;      /*! Asterisk channel used by the subchannel */
        struct unistim_line *parent;    /*! Unistim line */
        struct ast_rtp_instance *rtp;   /*! RTP handle */
        int softkey;                    /*! Softkey assigned */
        pthread_t ss_thread;            /*! unistim_ss thread handle */
        int alreadygone;
-       char ringvolume;
-       char ringstyle;
+       int holding;                    /*! this subchannel holds someone */
+       signed char ringvolume;
+       signed char ringstyle;
        int moh;                                        /*!< Music on hold in progress */
        AST_LIST_ENTRY(unistim_subchannel) list;
 };
@@ -371,7 +370,7 @@ struct unistim_subchannel {
 struct unistim_line {
        ast_mutex_t lock;
        char name[80]; /*! Like 200 */
-       char fullname[80]; /*! Like USTM/200\@black */
+       char fullname[101]; /*! Like USTM/200\@black */
        char exten[AST_MAX_EXTENSION]; /*! Extension where to start */
        char cid_num[AST_MAX_EXTENSION]; /*! CallerID Number */
        char mailbox[AST_MAX_EXTENSION]; /*! Mailbox for MWI */
@@ -415,13 +414,13 @@ static struct unistim_device {
        char maintext2[25];                  /*!< when the phone is idle, display this string on line 2 */
        char titledefault[13];    /*!< title (text before date/time) */
        char datetimeformat;        /*!< format used for displaying time/date */
-       char contrast;                    /*!< contrast */
+       signed char contrast;                     /*!< contrast */
        char country[3];                        /*!< country used for dial tone frequency */
        struct ast_tone_zone *tz;              /*!< Tone zone for res_indications (ring, busy, congestion) */
-       char ringvolume;                        /*!< Ring volume */
-       char ringstyle;                  /*!< Ring melody */
-       char cwvolume;                  /*!< Ring volume on call waiting */
-       char cwstyle;                    /*!< Ring melody on call waiting */
+       signed char ringvolume;                 /*!< Ring volume */
+       signed char ringstyle;                   /*!< Ring melody */
+       signed char cwvolume;                   /*!< Ring volume on call waiting */
+       signed char cwstyle;                     /*!< Ring melody on call waiting */
        int interdigit_timer;           /*!< Interdigit timer for dialing number by timeout */
        int dtmfduration;               /*!< DTMF playback duration */
        time_t nextdial;                /*!< Timer used for dial by timeout */
@@ -445,7 +444,7 @@ static struct unistim_device {
        int nat;                                        /*!< Used by the obscure ast_rtp_setnat */
        enum autoprov_extn extension;   /*!< See ifdef EXTENSION for valid values */
        char extension_number[11];      /*!< Extension number entered by the user */
-       char to_delete;                  /*!< Used in reload */
+       signed char to_delete;                   /*!< Used in reload */
        struct ast_silence_generator *silence_generator;
        AST_LIST_HEAD(,unistim_subchannel) subs; /*!< pointer to our current connection, channel... */
        AST_LIST_HEAD(,unistim_line) lines;
@@ -468,7 +467,7 @@ static struct unistimsession {
        int state;                                    /*!< state of the phone (see phone_state) */
        int size_buff_entry;        /*!< size of the buffer used to enter datas */
        char buff_entry[16];        /*!< Buffer for temporary datas */
-       char macaddr[18];                      /*!< mac adress of the phone (not always available) */
+       char macaddr[18];                      /*!< mac address of the phone (not always available) */
        char firmware[8];                      /*!< firmware of the phone (not always available) */
        struct wsabuf wsabufsend[MAX_BUF_NUMBER];      /*!< Size of each paquet stored in the buffer array & pointer to this buffer */
        unsigned char buf[MAX_BUF_NUMBER][MAX_BUF_SIZE];        /*!< Buffer array used to keep the lastest non-acked paquets */
@@ -567,8 +566,10 @@ static const unsigned char packet_send_stream_based_tone_off[] =
        { 0x16, 0x05, 0x1c, 0x00, 0x00 };
 
 static const unsigned char packet_send_mute[] = { 0x16, 0x05, 0x04, 0x00, 0x00 };
+#ifdef NOT_USED
 static const unsigned char packet_send_CloseAudioStreamRX[] = { 0x16, 0x05, 0x31, 0x00, 0xff };
 static const unsigned char packet_send_CloseAudioStreamTX[] = { 0x16, 0x05, 0x31, 0xff, 0x00 };
+#endif
 static const unsigned char packet_send_stream_based_tone_on[] =
        { 0x16, 0x06, 0x1b, 0x00, 0x00, 0x05 };
 static const unsigned char packet_send_stream_based_tone_single_freq[] =
@@ -935,7 +936,7 @@ static void send_raw_client(int size, const unsigned char *data, struct sockaddr
                                        ast_inet_ntoa(addr_ourip->sin_addr), (int) size,
                                        ast_inet_ntoa(addr_to->sin_addr));
                for (tmp = 0; tmp < size; tmp++)
-                       ast_verb(0, "%.2x ", (unsigned char) data[tmp]);
+                       ast_verb(0, "%02hhx ", data[tmp]);
                ast_verb(0, "\n******************************************\n");
 
        }
@@ -974,7 +975,7 @@ static void send_client(int size, const unsigned char *data, struct unistimsessi
 
 /*#ifdef DUMP_PACKET */
        if (unistimdebug) {
-               ast_verb(0, "Sending datas with seq #0x%.4x Using slot #%d :\n", (unsigned)pte->seq_server, buf_pos);
+               ast_verb(0, "Sending datas with seq #0x%04x Using slot #%d :\n", (unsigned)pte->seq_server, buf_pos);
        }
 /*#endif */
        send_raw_client(pte->wsabufsend[buf_pos].len, pte->wsabufsend[buf_pos].buf, &(pte->sin),
@@ -1021,7 +1022,7 @@ static int get_to_address(int fd, struct sockaddr_in *toAddr)
        memcpy(&toAddr->sin_addr, &ip_msg.address, sizeof(struct in_addr));
        return err;
 #else
-       memcpy(&toAddr, &public_ip, sizeof(&toAddr));
+       memcpy(toAddr, &public_ip, sizeof(*toAddr));
        return 0;
 #endif
 }
@@ -1130,7 +1131,7 @@ static void send_icon(unsigned char pos, unsigned char status, struct unistimses
 {
        BUFFSEND;
        if (unistimdebug) {
-               ast_verb(0, "Sending icon pos %d with status 0x%.2x\n", pos, (unsigned)status);
+               ast_verb(0, "Sending icon pos %d with status 0x%02hhx\n", pos, status);
        }
        memcpy(buffsend + SIZE_HEADER, packet_send_icon, sizeof(packet_send_icon));
        buffsend[9] = pos;
@@ -1150,7 +1151,7 @@ static void send_expansion_icon(unsigned char pos, unsigned char status, struct
 {
        BUFFSEND;
        if (unistimdebug) {
-               ast_verb(0, "Sending expansion icon pos %d with status 0x%.2x\n", pos, (unsigned)status);
+               ast_verb(0, "Sending expansion icon pos %d with status 0x%02hhx\n", pos, status);
        }
        memcpy(buffsend + SIZE_HEADER, packet_send_expansion_icon, sizeof(packet_send_expansion_icon));
        buffsend[10] = pos;
@@ -1262,7 +1263,7 @@ send_favorite(unsigned char pos, unsigned char status, struct unistimsession *pt
        int i;
 
        if (unistimdebug) {
-               ast_verb(0, "Sending favorite pos %d with status 0x%.2x\n", pos, (unsigned)status);
+               ast_verb(0, "Sending favorite pos %d with status 0x%02hhx\n", pos, status);
        }
        memcpy(buffsend + SIZE_HEADER, packet_send_favorite, sizeof(packet_send_favorite));
        buffsend[10] = pos;
@@ -1539,7 +1540,7 @@ static int send_retransmit(struct unistimsession *pte)
                 i < pte->last_buf_available; i++) {
                if (i < 0) {
                        ast_log(LOG_WARNING,
-                                       "Asked to retransmit an ACKed slot ! last_buf_available=%d, seq_server = #0x%.4x last_seq_ack = #0x%.4x\n",
+                                       "Asked to retransmit an ACKed slot ! last_buf_available=%d, seq_server = #0x%04x last_seq_ack = #0x%04x\n",
                                        pte->last_buf_available, (unsigned)pte->seq_server, (unsigned)pte->last_seq_ack);
                        continue;
                }
@@ -1549,7 +1550,7 @@ static int send_retransmit(struct unistimsession *pte)
                        unsigned short seq;
 
                        seq = ntohs(sbuf[1]);
-                       ast_verb(0, "Retransmit slot #%d (seq=#0x%.4x), last ack was #0x%.4x\n", i,
+                       ast_verb(0, "Retransmit slot #%d (seq=#0x%04x), last ack was #0x%04x\n", i,
                                                (unsigned)seq, (unsigned)pte->last_seq_ack);
                }
                send_raw_client(pte->wsabufsend[i].len, pte->wsabufsend[i].buf, &pte->sin,
@@ -1701,7 +1702,7 @@ send_select_output(struct unistimsession *pte, unsigned char output, unsigned ch
        }
        pte->device->output = output;
 }
-static void send_ring(struct unistimsession *pte, char volume, char style)
+static void send_ring(struct unistimsession *pte, signed char volume, signed char style)
 {
        BUFFSEND;
        if (unistimdebug) {
@@ -2014,8 +2015,6 @@ static const char *subtype_tostr(const int type)
        switch (type) {
        case SUB_REAL:
                return "REAL";
-       case SUB_ONHOLD:
-               return "ONHOLD";
        case SUB_RING:
                return "RINGING";
        case SUB_THREEWAY:
@@ -2062,7 +2061,7 @@ static void rcv_mac_addr(struct unistimsession *pte, const unsigned char *buf)
        char addrmac[19];
        int res = 0;
        for (tmp = 15; tmp < 15 + SIZE_HEADER; tmp++) {
-               sprintf(&addrmac[i], "%.2x", (unsigned) buf[tmp]);
+               sprintf(&addrmac[i], "%02hhx", buf[tmp]);
                i += 2;
        }
        if (unistimdebug) {
@@ -2495,6 +2494,24 @@ static struct unistim_subchannel* get_sub(struct unistim_device *device, int typ
        return sub;
 }
 
+static struct unistim_subchannel* get_sub_holding(struct unistim_device *device, int type, int holding)
+{
+       struct unistim_subchannel *sub = NULL;
+
+       AST_LIST_LOCK(&device->subs);
+       AST_LIST_TRAVERSE(&device->subs, sub, list) {
+               if (!sub) {
+                       continue;
+               }
+               if (sub->subtype == type && sub->holding == holding) {
+                       break;
+               }
+       }
+       AST_LIST_UNLOCK(&device->subs);
+
+       return sub;
+}
+
 static void sub_start_silence(struct unistimsession *pte, struct unistim_subchannel *sub)
 {
        /* Silence our channel */
@@ -2532,13 +2549,12 @@ static void sub_hold(struct unistimsession *pte, struct unistim_subchannel *sub)
                return;
        }
        sub->moh = 1;
-       sub->subtype = SUB_ONHOLD;
+       sub->holding = 1;
        send_favorite_short(sub->softkey, FAV_ICON_ONHOLD_BLACK + FAV_BLINK_SLOW, pte);
        send_select_output(pte, pte->device->output, pte->device->volume, MUTE_ON);
        send_stop_timer(pte);
        if (sub->owner) {
                ast_queue_hold(sub->owner, NULL);
-               send_end_call(pte);
        }
        return;
 }
@@ -2553,7 +2569,7 @@ static void sub_unhold(struct unistimsession *pte, struct unistim_subchannel *su
        }
 
        sub->moh = 0;
-       sub->subtype = SUB_REAL;
+       sub->holding = 0;
        send_favorite_short(sub->softkey, FAV_ICON_OFFHOOK_BLACK, pte);
        send_select_output(pte, pte->device->output, pte->device->volume, MUTE_OFF);
        send_start_timer(pte);
@@ -2634,6 +2650,9 @@ static void *unistim_ss(void *data)
        struct unistimsession *s = l->parent->session;
        int res;
 
+       if (!s) {
+               return NULL;
+       }
        ast_verb(3, "Starting switch on '%s@%s-%d' to %s\n", l->name, l->parent->name, sub->softkey, s->device->phone_number);
        ast_channel_lock(chan);
        ast_channel_exten_set(chan, s->device->phone_number);
@@ -2706,7 +2725,8 @@ static void send_start_rtp(struct unistim_subchannel *sub)
        }
 
        pte = sub->parent->parent->session;
-       codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, ast_channel_readformat(sub->owner), 0);
+       codec = ast_rtp_codecs_payload_code_tx(ast_rtp_instance_get_codecs(sub->rtp),
+               1, ast_channel_readformat(sub->owner), 0);
        if ((ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) ||
                (ast_format_cmp(ast_channel_readformat(sub->owner), ast_format_alaw) == AST_FORMAT_CMP_EQUAL)) {
                if (unistimdebug) {
@@ -2886,7 +2906,7 @@ static void start_rtp(struct unistim_subchannel *sub)
        ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
        if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), ast_channel_readformat(sub->owner)) == AST_FORMAT_CMP_NOT_EQUAL) {
                struct ast_format *tmpfmt;
-               struct ast_str *cap_buf = ast_str_alloca(64);
+               struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
 
                tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(sub->owner), 0);
                ast_log(LOG_WARNING,
@@ -3350,12 +3370,12 @@ static int unistim_do_senddigit(struct unistimsession *pte, char digit)
 static void handle_key_fav(struct unistimsession *pte, char keycode)
 {
        int keynum = keycode - KEY_FAV0;
-       struct unistim_subchannel *sub;
-
-       sub = get_sub(pte->device, SUB_REAL);
+       struct unistim_subchannel *sub, *sub_key = NULL;
+       sub = get_sub_holding(pte->device, SUB_REAL, 0);
 
        /* Make an action on selected favorite key */
        if (!pte->device->ssub[keynum]) { /* Key have no assigned call */
+               sub = get_sub_holding(pte->device, SUB_REAL, 0);
                send_favorite_selected(FAV_LINE_ICON, pte);
                if (is_key_line(pte->device, keynum)) {
                        if (unistimdebug) {
@@ -3380,21 +3400,24 @@ static void handle_key_fav(struct unistimsession *pte, char keycode)
                        key_favorite(pte, keycode);
                }
        } else {
-               sub = pte->device->ssub[keynum];
+               sub_key = pte->device->ssub[keynum];
                /* Favicon have assigned sub, activate it and put current on hold */
-               if (sub->subtype == SUB_REAL) {
-                       sub_hold(pte, sub);
+               if (sub_key->subtype == SUB_REAL && !sub_key->holding) {
+                       sub_hold(pte, sub_key);
                        show_main_page(pte);
-               } else if (sub->subtype == SUB_RING) {
-                       sub->softkey = keynum;
-                       handle_call_incoming(pte);
-               } else if (sub->subtype == SUB_ONHOLD) {
+               } else if (sub_key->subtype == SUB_REAL && sub_key->holding) {
+                       /* We are going to unhold line (we should put active line on hold, of any) */
                        if (pte->state == STATE_DIALPAGE){
                                send_tone(pte, 0, 0);
                        }
-                       send_callerid_screen(pte, sub);
-                       sub_unhold(pte, sub);
+                       sub_hold(pte, sub);
+                       send_callerid_screen(pte, sub_key);
+                       sub_unhold(pte, sub_key);
                        pte->state = STATE_CALL;
+               } else if (sub_key->subtype == SUB_RING) {
+                       sub_hold(pte, sub);
+                       sub_key->softkey = keynum;
+                       handle_call_incoming(pte);
                }
        }
 }
@@ -3404,6 +3427,9 @@ static void key_call(struct unistimsession *pte, char keycode)
        struct unistim_subchannel *sub = get_sub(pte->device, SUB_REAL);
        struct unistim_subchannel *sub_3way = get_sub(pte->device, SUB_THREEWAY);
 
+       if (!sub) {
+               return;
+       }
        if ((keycode >= KEY_0) && (keycode <= KEY_SHARP)) {
                if (keycode == KEY_SHARP) {
                        keycode = '#';
@@ -3417,7 +3443,7 @@ static void key_call(struct unistimsession *pte, char keycode)
        }
        switch (keycode) {
        case KEY_FUNC1:
-               if (ast_channel_state(sub->owner) == AST_STATE_UP) {
+               if (sub->owner && ast_channel_state(sub->owner) == AST_STATE_UP) {
                        if (sub_3way) {
                                close_call(pte);
                        }
@@ -3461,8 +3487,13 @@ static void key_call(struct unistimsession *pte, char keycode)
        case KEY_ONHOLD:
                if (!sub) {
                        if(pte->device->ssub[pte->device->selected]) {
-                               sub_hold(pte, pte->device->ssub[pte->device->selected]);
+                               sub = pte->device->ssub[pte->device->selected];
+                       } else {
+                               break;
                        }
+               }
+               if (sub->holding) {
+                       sub_unhold(pte, sub);
                } else {
                        sub_hold(pte, sub);
                }
@@ -3690,7 +3721,7 @@ static void key_select_option(struct unistimsession *pte, char keycode)
 #define SELECTCODEC_MSG "Codec number : .."
 static void handle_select_codec(struct unistimsession *pte)
 {
-       char buf[30], buf2[5];
+       char buf[30], buf2[6];
 
        pte->state = STATE_SELECTCODEC;
        ast_copy_string(buf, ustmtext("Using codec", pte), sizeof(buf));
@@ -4120,7 +4151,7 @@ static void show_main_page(struct unistimsession *pte)
                        send_date_time2(pte);
                        send_idle_clock(pte);
                        if (strlen(pte->device->maintext0)) {
-                               send_text(TEXT_LINE0, TEXT_NORMAL, pte, pte->device->maintext0);
+                               send_text(TEXT_LINE0, TEXT_NORMAL, pte, ustmtext(pte->device->maintext0, pte));
                        }
                } else {
                        if (pte->device->missed_call == 1) {
@@ -4139,11 +4170,11 @@ static void show_main_page(struct unistimsession *pte)
                        strcat(tmpbuf, ast_inet_ntoa(pte->sin.sin_addr));
                        send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmpbuf);
                } else {
-                       send_text(TEXT_LINE2, TEXT_NORMAL, pte, pte->device->maintext2);
+                       send_text(TEXT_LINE2, TEXT_NORMAL, pte, ustmtext(pte->device->maintext2, pte));
                }
        }
 
-       send_texttitle(pte, pte->device->titledefault);
+       send_texttitle(pte, ustmtext(pte->device->titledefault, pte));
        change_favorite_icon(pte, FAV_LINE_ICON);
 }
 
@@ -4398,7 +4429,7 @@ static void init_phone_step2(struct unistimsession *pte)
                        strcat(tmp, pte->macaddr);
                        send_text(TEXT_LINE2, TEXT_NORMAL, pte, tmp);
                        send_text_status(pte, "");
-                       send_texttitle(pte, "UNISTIM for*");
+                       send_texttitle(pte, ustmtext("UNISTIM for*", pte));
                        return;
                }
        }
@@ -4476,9 +4507,9 @@ static void process_request(int size, unsigned char *buf, struct unistimsession
        }
        if (!memcmp(buf + SIZE_HEADER, packet_recv_expansion_pressed_key, sizeof(packet_recv_expansion_pressed_key))) {
                char keycode = buf[13];
-               
+
                if (unistimdebug) {
-                       ast_verb(0, "Expansion key pressed: keycode = 0x%.2x - current state: %s\n", (unsigned)keycode,
+                       ast_verb(0, "Expansion key pressed: keycode = 0x%02hhx - current state: %s\n", (unsigned char)keycode,
                                                ptestate_tostr(pte->state));
                }
        }
@@ -4486,7 +4517,7 @@ static void process_request(int size, unsigned char *buf, struct unistimsession
                char keycode = buf[13];
 
                if (unistimdebug) {
-                       ast_verb(0, "Key pressed: keycode = 0x%.2x - current state: %s\n", (unsigned)keycode,
+                       ast_verb(0, "Key pressed: keycode = 0x%02hhx - current state: %s\n", (unsigned char)keycode,
                                                ptestate_tostr(pte->state));
                }
                if (keycode == KEY_MUTE) {
@@ -4654,15 +4685,14 @@ static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
                return;
        }
        if (buf[5] != 2) {
-               ast_log(LOG_NOTICE, "%s Wrong direction : got 0x%.2x expected 0x02\n", tmpbuf,
-                               (unsigned)buf[5]);
+               ast_log(LOG_NOTICE, "%s Wrong direction : got 0x%02hhx expected 0x02\n", tmpbuf, buf[5]);
                return;
        }
        seq = ntohs(sbuf[1]);
        if (buf[4] == 1) {
                ast_mutex_lock(&pte->lock);
                if (unistimdebug) {
-                       ast_verb(0, "ACK received for packet #0x%.4x\n", (unsigned)seq);
+                       ast_verb(0, "ACK received for packet #0x%04x\n", (unsigned)seq);
                }
                pte->nb_retransmit = 0;
 
@@ -4678,7 +4708,7 @@ static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
                                pte->last_seq_ack = 0;
                        } else {
                                ast_log(LOG_NOTICE,
-                                               "%s Warning : ACK received for an already ACKed packet : #0x%.4x we are at #0x%.4x\n",
+                                               "%s Warning : ACK received for an already ACKed packet : #0x%04x we are at #0x%04x\n",
                                                tmpbuf, (unsigned)seq, (unsigned)pte->last_seq_ack);
                        }
                        ast_mutex_unlock(&pte->lock);
@@ -4686,13 +4716,13 @@ static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
                }
                if (pte->seq_server < seq) {
                        ast_log(LOG_NOTICE,
-                                       "%s Error : ACK received for a non-existent packet : #0x%.4x\n",
+                                       "%s Error : ACK received for a non-existent packet : #0x%04x\n",
                                        tmpbuf, (unsigned)pte->seq_server);
                        ast_mutex_unlock(&pte->lock);
                        return;
                }
                if (unistimdebug) {
-                       ast_verb(0, "%s ACK gap : Received ACK #0x%.4x, previous was #0x%.4x\n",
+                       ast_verb(0, "%s ACK gap : Received ACK #0x%04x, previous was #0x%04x\n",
                                                tmpbuf, (unsigned)seq, (unsigned)pte->last_seq_ack);
                }
                pte->last_seq_ack = seq;
@@ -4716,7 +4746,7 @@ static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
                }
                if (pte->seq_phone > seq) {
                        ast_log(LOG_NOTICE,
-                                       "%s Warning : received a retransmitted packet : #0x%.4x (we are at #0x%.4x)\n",
+                                       "%s Warning : received a retransmitted packet : #0x%04x (we are at #0x%04x)\n",
                                        tmpbuf, (unsigned)seq, (unsigned)pte->seq_phone);
                        /* BUG ? pte->device->seq_phone = seq; */
                        /* Send ACK */
@@ -4726,29 +4756,28 @@ static void parsing(int size, unsigned char *buf, struct unistimsession *pte,
                        return;
                }
                ast_log(LOG_NOTICE,
-                               "%s Warning : we lost a packet : received #0x%.4x (we are at #0x%.4x)\n",
+                               "%s Warning : we lost a packet : received #0x%04x (we are at #0x%04x)\n",
                                tmpbuf, (unsigned)seq, (unsigned)pte->seq_phone);
                return;
        }
        if (buf[4] == 0) {
-               ast_log(LOG_NOTICE, "%s Retransmit request for packet #0x%.4x\n", tmpbuf, (unsigned)seq);
+               ast_log(LOG_NOTICE, "%s Retransmit request for packet #0x%04x\n", tmpbuf, (unsigned)seq);
                if (pte->last_seq_ack > seq) {
                        ast_log(LOG_NOTICE,
-                                       "%s Error : received a request for an already ACKed packet : #0x%.4x\n",
+                                       "%s Error : received a request for an already ACKed packet : #0x%04x\n",
                                        tmpbuf, (unsigned)pte->last_seq_ack);
                        return;
                }
                if (pte->seq_server < seq) {
                        ast_log(LOG_NOTICE,
-                                       "%s Error : received a request for a non-existent packet : #0x%.4x\n",
+                                       "%s Error : received a request for a non-existent packet : #0x%04x\n",
                                        tmpbuf, (unsigned)pte->seq_server);
                        return;
                }
                send_retransmit(pte);
                return;
        }
-       ast_log(LOG_NOTICE, "%s Unknown request : got 0x%.2x expected 0x00,0x01 or 0x02\n",
-                       tmpbuf, (unsigned)buf[4]);
+       ast_log(LOG_NOTICE, "%s Unknown request : got 0x%02hhx expected 0x00,0x01 or 0x02\n", tmpbuf, buf[4]);
        return;
 }
 
@@ -4830,7 +4859,7 @@ static int unistim_call(struct ast_channel *ast, const char *dest, int timeout)
        int res = 0, i;
        struct unistim_subchannel *sub, *sub_real;
        struct unistimsession *session;
-       char ringstyle, ringvolume;
+       signed char ringstyle, ringvolume;
 
        session = channel_to_session(ast);
        if (!session) {
@@ -4890,14 +4919,15 @@ static int unistim_hangup_clean(struct ast_channel *ast, struct unistim_subchann
        ast_channel_tech_pvt_set(ast, NULL);
        unistim_set_owner(sub, NULL);
        sub->alreadygone = 0;
-       ast_mutex_unlock(&sub->lock);
        if (sub->rtp) {
                if (unistimdebug) {
                        ast_verb(0, "Destroying RTP session\n");
                }
+               ast_rtp_instance_stop(sub->rtp);
                ast_rtp_instance_destroy(sub->rtp);
                sub->rtp = NULL;
        }
+       ast_mutex_unlock(&sub->lock);
        return 0;
 }
 
@@ -4953,18 +4983,20 @@ static int unistim_hangup(struct ast_channel *ast)
        } else if (sub->subtype == SUB_RING) {
                send_no_ring(s);
                for (i = 0; i < FAVNUM; i++) {
-                       if (!soft_key_visible(s->device, i))
+                       if (!soft_key_visible(s->device, i)) {
                                continue;
-                       if (d->ssub[i] != sub)
+                       }
+                       if (d->ssub[i] != sub) {
+                               if (d->ssub[i] != NULL) { /* Found other subchannel active other than hangup'ed one */
+                                       end_call = 0;
+                               }
                                continue;
+                       }
                        if (is_key_line(d, i) && !strcmp(l->name, d->sline[i]->name)) {
                                send_favorite_short(i, FAV_LINE_ICON, s);
                                d->ssub[i] = NULL;
                                continue;
                        }
-                       if (d->ssub[i] != NULL) { /* Found other subchannel active other then hangup'ed one */
-                               end_call = 0;
-                       }
                }
        }
        if (end_call) {
@@ -5088,7 +5120,7 @@ static int unistimsock_read(int *id, int fd, short events, void *ignore)
                                        dw_num_bytes_rcvd, ast_inet_ntoa(addr_from.sin_addr), tmp);
        for (dw_num_bytes_rcvdd = 0; dw_num_bytes_rcvdd < dw_num_bytes_rcvd;
                 dw_num_bytes_rcvdd++)
-               ast_verb(0, "%.2x ", (unsigned char) buff[dw_num_bytes_rcvdd]);
+               ast_verb(0, "%02hhx ", buff[dw_num_bytes_rcvdd]);
        ast_verb(0, "\n******************************************\n");
 #endif
 
@@ -5136,7 +5168,7 @@ static struct ast_frame *unistim_rtp_read(const struct ast_channel *ast,
                /* We already hold the channel lock */
                if (f->frametype == AST_FRAME_VOICE) {
                        if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-                               struct ast_str *cap_buf = ast_str_alloca(64);
+                               struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
                                struct ast_format_cap *caps;
 
                                ast_debug(1,
@@ -5186,7 +5218,7 @@ static int unistim_write(struct ast_channel *ast, struct ast_frame *frame)
                }
        } else {
                if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
-                       struct ast_str *cap_buf = ast_str_alloca(64);
+                       struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
 
                        ast_log(LOG_WARNING,
                                        "Asked to transmit frame type %s, while native formats is %s (read/write = (%s/%s)\n",
@@ -5369,6 +5401,7 @@ static int unistim_indicate(struct ast_channel *ast, int ind, const void *data,
                ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
                /* fallthrough */
        case AST_CONTROL_PVT_CAUSE_CODE:
+       case AST_CONTROL_MASQUERADE_NOTIFY:
                return -1;
        }
 
@@ -5418,7 +5451,8 @@ static struct unistim_subchannel *find_subchannel_by_name(const char *dest)
                                        }
                                        if (sub->owner) {
                                                /* Allocate additional channel if asterisk channel already here */
-                                               sub = unistim_alloc_sub(d, SUB_ONHOLD);
+                                               sub = unistim_alloc_sub(d, SUB_REAL);
+                                               sub->holding = 1;
                                        }
                                        sub->ringvolume = -1;
                                        sub->ringstyle = -1;
@@ -5429,8 +5463,8 @@ static struct unistim_subchannel *find_subchannel_by_name(const char *dest)
                                                        if ((*at < '0') || (*at > '7')) { /* ring style */
                                                                ast_log(LOG_WARNING, "Invalid ring selection (%s)", at);
                                                        } else {
-                                                               char ring_volume = -1;
-                                                               char ring_style = *at - '0';
+                                                               signed char ring_volume = -1;
+                                                               signed char ring_style = *at - '0';
                                                                at++;
                                                                if ((*at >= '0') && (*at <= '3')) {      /* ring volume */
                                                                        ring_volume = *at - '0';
@@ -5716,9 +5750,9 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state
        tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(tmp), 0);
 
        if (unistimdebug) {
-               struct ast_str *native_buf = ast_str_alloca(64);
-               struct ast_str *cap_buf = ast_str_alloca(64);
-               struct ast_str *global_buf = ast_str_alloca(64);
+               struct ast_str *native_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
+               struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
+               struct ast_str *global_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
 
                ast_verb(0, "Best codec = %s from nativeformats %s (line cap=%s global=%s)\n",
                        ast_format_get_name(tmpfmt),
@@ -5931,8 +5965,8 @@ static struct ast_channel *unistim_request(const char *type, struct ast_format_c
        char tmp[256];
 
        if (!(ast_format_cap_iscompatible(cap, global_cap))) {
-               struct ast_str *cap_buf = ast_str_alloca(64);
-               struct ast_str *global_buf = ast_str_alloca(64);
+               struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
+               struct ast_str *global_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
                ast_log(LOG_NOTICE,
                                "Asked to get a channel of unsupported format %s while capability is %s\n",
                                ast_format_cap_get_names(cap, &cap_buf),
@@ -6007,7 +6041,7 @@ static char *unistim_show_info(struct ast_cli_entry *e, int cmd, struct ast_cli_
        struct unistim_line *line;
        struct unistim_subchannel *sub;
        struct unistimsession *s;
-       struct ast_str *cap_buf = ast_str_alloca(64);
+       struct ast_str *cap_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
 
        switch (cmd) {
        case CLI_INIT:
@@ -6388,6 +6422,85 @@ static struct unistim_line *find_line_by_number(struct unistim_device *d, const
        return ret;
 }
 
+static void delete_device(struct unistim_device *d)
+{
+       struct unistim_line *l;
+       struct unistim_subchannel *sub;
+       struct unistimsession *s;
+
+       if (unistimdebug) {
+               ast_verb(0, "Removing device '%s'\n", d->name);
+       }
+       AST_LIST_LOCK(&d->subs);
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, sub, list){
+               if (sub->subtype == SUB_REAL) {
+                       if (sub->owner) {
+                               ast_log(LOG_WARNING,
+                                               "Device '%s' was not deleted : a call is in progress. Try again later.\n",
+                                               d->name);
+                               AST_LIST_UNLOCK(&d->subs);
+                               return;
+                       }
+               }
+               if (sub->subtype == SUB_THREEWAY) {
+                       ast_log(LOG_WARNING,
+                                       "Device '%s' with threeway call subchannels allocated, aborting.\n",
+                                       d->name);
+                       AST_LIST_UNLOCK(&d->subs);
+                       return;
+               }
+               AST_LIST_REMOVE_CURRENT(list);
+               ast_mutex_destroy(&sub->lock);
+               ast_free(sub);
+       }
+       AST_LIST_TRAVERSE_SAFE_END
+       AST_LIST_UNLOCK(&d->subs);
+
+
+       AST_LIST_LOCK(&d->lines);
+       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->lines, l, list){
+               AST_LIST_REMOVE_CURRENT(list);
+               ast_mutex_destroy(&l->lock);
+               unistim_line_destroy(l);
+       }
+       AST_LIST_TRAVERSE_SAFE_END
+       AST_LIST_UNLOCK(&d->lines);
+
+       if (d->session) {
+               if (sessions == d->session) {
+                       sessions = d->session->next;
+               } else {
+                       s = sessions;
+                       while (s) {
+                               if (s->next == d->session) {
+                                       s->next = d->session->next;
+                                       break;
+                               }
+                               s = s->next;
+                       }
+               }
+               ast_mutex_destroy(&d->session->lock);
+               ast_free(d->session);
+       }
+       if (devices == d) {
+               devices = d->next;
+       } else {
+               struct unistim_device *d2 = devices;
+               while (d2) {
+                       if (d2->next == d) {
+                               d2->next = d->next;
+                               break;
+                       }
+                       d2 = d2->next;
+               }
+       }
+       if (d->tz) {
+               d->tz = ast_tone_zone_unref(d->tz);
+       }
+       ast_mutex_destroy(&d->lock);
+       ast_free(d);
+}
+
 static struct unistim_device *build_device(const char *cat, const struct ast_variable *v)
 {
        struct unistim_device *d;
@@ -6395,7 +6508,7 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
        int create = 1;
        int nbsoftkey, dateformat, timeformat, callhistory, sharpdial, linecnt;
        char linelabel[AST_MAX_EXTENSION];
-       char ringvolume, ringstyle, cwvolume, cwstyle;
+       signed char ringvolume, ringstyle, cwvolume, cwstyle;
 
        /* First, we need to know if we already have this name in our list */
        /* Get a lock for the device chained list */
@@ -6426,7 +6539,7 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
                }
                ast_mutex_init(&d->lock);
                ast_copy_string(d->name, cat, sizeof(d->name));
-               
+
                ast_copy_string(d->context, DEFAULTCONTEXT, sizeof(d->context));
                d->contrast = -1;
                d->output = OUTPUT_HANDSET;
@@ -6479,7 +6592,14 @@ static struct unistim_device *build_device(const char *cat, const struct ast_var
                } else if (!strcasecmp(v->name, "tn")) {
                        ast_copy_string(d->extension_number, v->value, sizeof(d->extension_number));
                } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
-                       d->ha = ast_append_ha(v->name, v->value, d->ha, NULL);
+                       int acl_error = 0;
+                       d->ha = ast_append_ha(v->name, v->value, d->ha, &acl_error);
+                       if (acl_error) {
+                               ast_log(LOG_ERROR, "Invalid ACL '%s' specified for device '%s' on line %d. Deleting device\n",
+                                               v->value, cat, v->lineno);
+                               delete_device(d);
+                               return NULL;
+                       }
                } else if (!strcasecmp(v->name, "context")) {
                        ast_copy_string(d->context, v->value, sizeof(d->context));
                } else if (!strcasecmp(v->name, "maintext0")) {
@@ -6846,85 +6966,7 @@ static int reload_config(void)
        d = devices;
        while (d) {
                if (d->to_delete) {
-                       struct unistim_line *l;
-                       struct unistim_subchannel *sub;
-
-                       if (unistimdebug) {
-                               ast_verb(0, "Removing device '%s'\n", d->name);
-                       }
-                       AST_LIST_LOCK(&d->subs);
-                       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->subs, sub, list){
-                               if (sub->subtype == SUB_REAL) {
-                                       if (!sub) {
-                                               ast_log(LOG_ERROR, "Device '%s' without a subchannel !, aborting\n",
-                                                               d->name);
-                                               ast_config_destroy(cfg);
-                                               return 0;
-                                       }
-                                       if (sub->owner) {
-                                               ast_log(LOG_WARNING,
-                                                               "Device '%s' was not deleted : a call is in progress. Try again later.\n",
-                                                               d->name);
-                                               d = d->next;
-                                               continue;
-                                       }
-                               }
-                               if (sub->subtype == SUB_THREEWAY) {
-                                       ast_log(LOG_WARNING,
-                                                       "Device '%s' with threeway call subchannels allocated, aborting.\n",
-                                                       d->name);
-                                       break;
-                               }
-                               AST_LIST_REMOVE_CURRENT(list);
-                               ast_mutex_destroy(&sub->lock);
-                               ast_free(sub);
-                       }
-                       AST_LIST_TRAVERSE_SAFE_END
-                       AST_LIST_UNLOCK(&d->subs);
-
-
-                       AST_LIST_LOCK(&d->lines);
-                       AST_LIST_TRAVERSE_SAFE_BEGIN(&d->lines, l, list){
-                               AST_LIST_REMOVE_CURRENT(list);
-                               ast_mutex_destroy(&l->lock);
-                               unistim_line_destroy(l);
-                       }
-                       AST_LIST_TRAVERSE_SAFE_END
-                       AST_LIST_UNLOCK(&d->lines);
-
-                       if (d->session) {
-                               if (sessions == d->session) {
-                                       sessions = d->session->next;
-                               } else {
-                                       s = sessions;
-                                       while (s) {
-                                               if (s->next == d->session) {
-                                                       s->next = d->session->next;
-                                                       break;
-                                               }
-                                               s = s->next;
-                                       }
-                               }
-                               ast_mutex_destroy(&d->session->lock);
-                               ast_free(d->session);
-                       }
-                       if (devices == d) {
-                               devices = d->next;
-                       } else {
-                               struct unistim_device *d2 = devices;
-                               while (d2) {
-                                       if (d2->next == d) {
-                                               d2->next = d->next;
-                                               break;
-                                       }
-                                       d2 = d2->next;
-                               }
-                       }
-                       if (d->tz) {
-                               d->tz = ast_tone_zone_unref(d->tz);
-                       }
-                       ast_mutex_destroy(&d->lock);
-                       ast_free(d);
+                       delete_device(d);
                        d = devices;
                        continue;
                }
@@ -7014,7 +7056,7 @@ static int unistim_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instanc
        if (!rtp) {
                return 0;
        }
-       
+
        sub = (struct unistim_subchannel *) ast_channel_tech_pvt(chan);
        if (!sub) {
                ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
@@ -7027,9 +7069,9 @@ static int unistim_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instanc
                ast_rtp_instance_get_local_address(rtp, &tmp);
                ast_sockaddr_to_sin(&tmp, &us);
        }
-       
+
        /* TODO: Set rtp on phone in case of direct rtp (not implemented) */
-       
+
        return 0;
 }
 
@@ -7108,7 +7150,7 @@ buff_failed:
        global_cap = NULL;
        ao2_cleanup(unistim_tech.capabilities);
        unistim_tech.capabilities = NULL;
-       return AST_MODULE_LOAD_FAILURE;
+       return AST_MODULE_LOAD_DECLINE;
 }
 
 static int unload_module(void)
@@ -7162,7 +7204,8 @@ int reload(void)
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "UNISTIM Protocol (USTM)",
-    .load = load_module,
-    .unload = unload_module,
-    .reload = reload,
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .reload = reload,
 );