Merge the rest of the FullyBooted patch
[asterisk/asterisk.git] / main / callerid.c
index 6ade694..17d265e 100644 (file)
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <time.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
 #include <math.h>
 #include <ctype.h>
 
@@ -40,9 +36,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/frame.h"
 #include "asterisk/channel.h"
 #include "asterisk/callerid.h"
-#include "asterisk/logger.h"
 #include "asterisk/fskmodem.h"
-#include "asterisk/options.h"
 #include "asterisk/utils.h"
 
 struct callerid_state {
@@ -77,7 +71,7 @@ float casdr1, casdi1, casdr2, casdi2;
 
 #define AST_CALLERID_UNKNOWN   "<unknown>"
 
-static inline void gen_tones(unsigned char *buf, int len, int codec, float ddr1, float ddi1, float ddr2, float ddi2, float *cr1, float *ci1, float *cr2, float *ci2)
+static inline void gen_tones(unsigned char *buf, int len, format_t codec, float ddr1, float ddi1, float ddr2, float ddi2, float *cr1, float *ci1, float *cr2, float *ci2)
 {
        int x;
        float t;
@@ -99,7 +93,7 @@ static inline void gen_tones(unsigned char *buf, int len, int codec, float ddr1,
        }
 }
 
-static inline void gen_tone(unsigned char *buf, int len, int codec, float ddr1, float ddi1, float *cr1, float *ci1)
+static inline void gen_tone(unsigned char *buf, int len, format_t codec, float ddr1, float ddi1, float *cr1, float *ci1)
 {
        int x;
        float t;
@@ -134,6 +128,35 @@ struct callerid_state *callerid_new(int cid_signalling)
        struct callerid_state *cid;
 
        if ((cid = ast_calloc(1, sizeof(*cid)))) {
+#ifdef INTEGER_CALLERID
+               cid->fskd.ispb = 7;             /* 1200 baud */ 
+               /* Set up for 1200 / 8000 freq *32 to allow ints */
+               cid->fskd.pllispb  = (int)(8000 * 32  / 1200);
+               cid->fskd.pllids   = cid->fskd.pllispb/32;
+               cid->fskd.pllispb2 = cid->fskd.pllispb/2;
+               
+               cid->fskd.icont = 0;           /* PLL REset */
+               /* cid->fskd.hdlc = 0; */       /* Async */
+               cid->fskd.nbit = 8;             /* 8 bits */
+               cid->fskd.instop = 1;           /* 1 stop bit */
+               /* cid->fskd.paridad = 0; */    /* No parity */
+               cid->fskd.bw = 1;               /* Filter 800 Hz */
+               if (cid_signalling == 2) {      /* v23 signalling */
+                       cid->fskd.f_mark_idx  = 4;      /* 1300 Hz */
+                       cid->fskd.f_space_idx = 5;      /* 2100 Hz */
+               } else {                        /* Bell 202 signalling as default */
+                       cid->fskd.f_mark_idx  = 2;      /* 1200 Hz */
+                       cid->fskd.f_space_idx = 3;      /* 2200 Hz */
+               }
+               /* cid->fskd.pcola = 0; */      /* No clue */
+               /* cid->fskd.cont = 0.0; */     /* Digital PLL reset */
+               /* cid->fskd.x0 = 0.0; */
+               /* cid->fskd.state = 0; */
+               cid->flags = CID_UNKNOWN_NAME | CID_UNKNOWN_NUMBER;
+               /* cid->pos = 0; */
+
+               fskmodem_init(&cid->fskd);
+#else
                cid->fskd.spb = 7.0;            /* 1200 baud */
                /* cid->fskd.hdlc = 0; */       /* Async */
                cid->fskd.nbit = 8;             /* 8 bits */
@@ -153,6 +176,7 @@ struct callerid_state *callerid_new(int cid_signalling)
                /* cid->fskd.state = 0; */
                cid->flags = CID_UNKNOWN_NAME | CID_UNKNOWN_NUMBER;
                /* cid->pos = 0; */
+#endif
        }
 
        return cid;
@@ -161,7 +185,7 @@ struct callerid_state *callerid_new(int cid_signalling)
 void callerid_get(struct callerid_state *cid, char **name, char **number, int *flags)
 {
        *flags = cid->flags;
-       if (cid->flags & (CID_UNKNOWN_NAME | CID_PRIVATE_NUMBER))
+       if (cid->flags & (CID_UNKNOWN_NAME | CID_PRIVATE_NAME))
                *name = NULL;
        else
                *name = cid->name;
@@ -180,7 +204,7 @@ void callerid_get_dtmf(char *cidstring, char *number, int *flags)
        number[0] = 0;
 
        if (strlen(cidstring) < 2) {
-               ast_log(LOG_DEBUG, "No cid detected\n");
+               ast_debug(1, "No cid detected\n");
                *flags = CID_UNKNOWN_NUMBER;
                return;
        }
@@ -194,7 +218,7 @@ void callerid_get_dtmf(char *cidstring, char *number, int *flags)
                else if (code == 10) 
                        *flags = CID_PRIVATE_NUMBER;
                else
-                       ast_log(LOG_DEBUG, "Unknown DTMF code %d\n", code);
+                       ast_debug(1, "Unknown DTMF code %d\n", code);
        } else if (cidstring[0] == 'D' && cidstring[2] == '#') {
                /* .DK special code */
                if (cidstring[1] == '1')
@@ -209,7 +233,7 @@ void callerid_get_dtmf(char *cidstring, char *number, int *flags)
                        if (isdigit(cidstring[i]))
                                number[i-1] = cidstring[i];
                        else
-                               ast_log(LOG_DEBUG, "Unknown CID digit '%c'\n",
+                               ast_debug(1, "Unknown CID digit '%c'\n",
                                        cidstring[i]);
                }
                number[i-1] = 0;
@@ -226,13 +250,12 @@ void callerid_get_dtmf(char *cidstring, char *number, int *flags)
                }
                number[i] = 0;
        } else {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Unknown CID protocol, start digit '%c'\n", cidstring[0]);
+               ast_debug(1, "Unknown CID protocol, start digit '%c'\n", cidstring[0]);
                *flags = CID_UNKNOWN_NUMBER;
        }
 }
 
-int ast_gen_cas(unsigned char *outbuf, int sendsas, int len, int codec)
+int ast_gen_cas(unsigned char *outbuf, int sendsas, int len, format_t codec)
 {
        int pos = 0;
        int saslen = 2400;
@@ -277,7 +300,7 @@ static unsigned short calc_crc(unsigned short crc, unsigned char data)
        return crc;
 }
 
-int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, int codec)
+int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, format_t codec)
 {
        int mylen = len;
        int olen;
@@ -298,17 +321,17 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, i
        while (mylen >= 160) {
                b = b2 = 0;
                olen = mylen;
-               res = fsk_serie(&cid->fskd, buf, &mylen, &b);
+               res = fsk_serial(&cid->fskd, buf, &mylen, &b);
 
                if (mylen < 0) {
-                       ast_log(LOG_ERROR, "fsk_serie made mylen < 0 (%d)\n", mylen);
+                       ast_log(LOG_ERROR, "No start bit found in fsk data.\n");
                        return -1;
                }
 
                buf += (olen - mylen);
 
                if (res < 0) {
-                       ast_log(LOG_NOTICE, "fsk_serie failed\n");
+                       ast_log(LOG_NOTICE, "fsk_serial failed\n");
                        return -1;
                }
 
@@ -335,7 +358,7 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, i
                                cid->skipflag = 0 ;
 
                        /* caller id retrieval */
-                       switch(cid->sawflag) {
+                       switch (cid->sawflag) {
                        case 0: /* DLE */
                                if (b == 0x10) {
                                        cid->sawflag = 1;
@@ -411,7 +434,7 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, i
                                                /* length */
                                                x++; 
                                                /* number type */
-                                                       switch (cid->rawdata[x]) { 
+                                               switch (cid->rawdata[x]) { 
                                                case 0x00: /* unknown */
                                                case 0x01: /* international number */
                                                case 0x02: /* domestic number */
@@ -420,8 +443,7 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, i
                                                case 0x06: /* short dial number */
                                                case 0x07: /* reserved */
                                                default:   /* reserved */
-                                                       if (option_debug > 1)
-                                                               ast_log(LOG_DEBUG, "cid info:#1=%X\n", cid->rawdata[x]);
+                                                       ast_debug(2, "cid info:#1=%X\n", cid->rawdata[x]);
                                                        break ;
                                                }
                                                x++; 
@@ -437,8 +459,7 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, i
                                                case 0x09: /* private dial plan */
                                                case 0x05: /* reserved */
                                                default:   /* reserved */
-                                                       if (option_debug > 1)
-                                                               ast_log(LOG_DEBUG, "cid info:#2=%X\n", cid->rawdata[x]);
+                                                       ast_debug(2, "cid info:#2=%X\n", cid->rawdata[x]);
                                                        break ;
                                                }
                                                x++; 
@@ -452,9 +473,8 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, i
                                                case 'O': /* service not available */
                                                case 'C': /* pay phone */
                                                case 'S': /* service congested */
-                                                               cid->flags |= CID_UNKNOWN_NUMBER;
-                                                       if (option_debug > 1)
-                                                               ast_log(LOG_DEBUG, "no cid reason:%c\n",cid->rawdata[x]);
+                                                       cid->flags |= CID_UNKNOWN_NUMBER;
+                                                       ast_debug(2, "no cid reason:%c\n", cid->rawdata[x]);
                                                        break ;
                                                }
                                                x++; 
@@ -485,7 +505,7 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, i
                                                x++;
                                                /* numbering plan octed 4 */
                                                x++;
-                                                       /* numbering plan octed 5 */
+                                               /* numbering plan octed 5 */
                                                switch (cid->rawdata[x]) {
                                                case 0x00: /* unknown */
                                                case 0x01: /* recommendation E.164 ISDN */
@@ -495,8 +515,7 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, i
                                                case 0x09: /* private dial plan */
                                                case 0x05: /* reserved */
                                                default:   /* reserved */
-                                                       if (option_debug > 1)
-                                                               ast_log(LOG_DEBUG, "did info:#2=%X\n", cid->rawdata[x]);
+                                                       ast_debug(2, "did info:#2=%X\n", cid->rawdata[x]);
                                                        break ;
                                                }
                                                x++;
@@ -520,7 +539,7 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, i
 }
 
 
-int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int codec)
+int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, format_t codec)
 {
        int mylen = len;
        int olen;
@@ -538,27 +557,27 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int
                buf[x+cid->oldlen/2] = AST_XLAW(ubuf[x]);
        while (mylen >= 160) {
                olen = mylen;
-               res = fsk_serie(&cid->fskd, buf, &mylen, &b);
+               res = fsk_serial(&cid->fskd, buf, &mylen, &b);
                if (mylen < 0) {
-                       ast_log(LOG_ERROR, "fsk_serie made mylen < 0 (%d)\n", mylen);
+                       ast_log(LOG_ERROR, "No start bit found in fsk data.\n");
                        return -1;
                }
                buf += (olen - mylen);
                if (res < 0) {
-                       ast_log(LOG_NOTICE, "fsk_serie failed\n");
+                       ast_log(LOG_NOTICE, "fsk_serial failed\n");
                        return -1;
                }
                if (res == 1) {
                        /* Ignore invalid bytes */
                        if (b > 0xff)
                                continue;
-                       switch(cid->sawflag) {
+                       switch (cid->sawflag) {
                        case 0: /* Look for flag */
                                if (b == 'U')
                                        cid->sawflag = 2;
                                break;
                        case 2: /* Get lead-in */
-                               if ((b == 0x04) || (b == 0x80)) {
+                               if ((b == 0x04) || (b == 0x80) || (b == 0x06) || (b == 0x82)) {
                                        cid->type = b;
                                        cid->sawflag = 3;
                                        cid->cksum = b;
@@ -594,12 +613,14 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int
                
                                cid->number[0] = '\0';
                                cid->name[0] = '\0';
+                               /* Update flags */
+                               cid->flags = 0;
                                /* If we get this far we're fine.  */
-                               if (cid->type == 0x80) {
+                               if ((cid->type == 0x80) || (cid->type == 0x82)) {
                                        /* MDMF */
                                        /* Go through each element and process */
                                        for (x = 0; x < cid->pos;) {
-                                               switch(cid->rawdata[x++]) {
+                                               switch (cid->rawdata[x++]) {
                                                case 1:
                                                        /* Date */
                                                        break;
@@ -629,6 +650,13 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int
                                                        memcpy(cid->name, cid->rawdata + x + 1, res);
                                                        cid->name[res] = '\0';
                                                        break;
+                                               case 11: /* Message Waiting */
+                                                       res = cid->rawdata[x + 1];
+                                                       if (res)
+                                                               cid->flags |= CID_MSGWAITING;
+                                                       else
+                                                               cid->flags |= CID_NOMSGWAITING;
+                                                       break;
                                                case 17: /* UK: Call type, 1=Voice Call, 2=Ringback when free, 129=Message waiting  */
                                                case 19: /* UK: Network message system status (Number of messages waiting) */
                                                case 22: /* Something French */
@@ -636,15 +664,27 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int
                                                default:
                                                        ast_log(LOG_NOTICE, "Unknown IE %d\n", cid->rawdata[x - 1]);
                                                }
+                                               res = cid->rawdata[x];
+                                               if (0 > res){   /* Negative offset in the CID Spill */
+                                                       ast_log(LOG_NOTICE, "IE %d has bad field length of %d at offset %d\n", cid->rawdata[x-1], cid->rawdata[x], x);
+                                                       /* Try again */
+                                                       cid->sawflag = 0;
+                                                       break;  /* Exit the loop */
+                                               }
                                                x += cid->rawdata[x];
                                                x++;
                                        }
+                               } else if (cid->type == 0x6) {
+                                       /* VMWI SDMF */
+                                       if (cid->rawdata[2] == 0x42) {
+                                               cid->flags |= CID_MSGWAITING;
+                                       } else if (cid->rawdata[2] == 0x6f) {
+                                               cid->flags |= CID_NOMSGWAITING;
+                                       }
                                } else {
                                        /* SDMF */
                                        ast_copy_string(cid->number, cid->rawdata + 8, sizeof(cid->number));
                                }
-                               /* Update flags */
-                               cid->flags = 0;
                                if (!strcmp(cid->number, "P")) {
                                        strcpy(cid->number, "");
                                        cid->flags |= CID_PRIVATE_NUMBER;
@@ -677,20 +717,19 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int
 
 void callerid_free(struct callerid_state *cid)
 {
-       free(cid);
+       ast_free(cid);
 }
 
 static int callerid_genmsg(char *msg, int size, const char *number, const char *name, int flags)
 {
-       time_t t;
-       struct tm tm;
+       struct timeval now = ast_tvnow();
+       struct ast_tm tm;
        char *ptr;
        int res;
        int i, x;
 
        /* Get the time */
-       time(&t);
-       localtime_r(&t,&tm);
+       ast_localtime(&now, &tm, NULL);
        
        ptr = msg;
        
@@ -752,24 +791,49 @@ static int callerid_genmsg(char *msg, int size, const char *number, const char *
        
 }
 
-int vmwi_generate(unsigned char *buf, int active, int mdmf, int codec)
+int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, format_t codec,
+                              const char* name, const char* number, int flags)
 {
-       unsigned char msg[256];
-       int len=0;
+       char msg[256];
+       int len = 0;
        int sum;
        int x;
        int bytes = 0;
        float cr = 1.0;
        float ci = 0.0;
        float scont = 0.0;
+       
+       if (type == CID_MWI_TYPE_MDMF_FULL) {
+               /* MDMF Message waiting with date, number, name and MWI parameter */
+               msg[0] = 0x82;
 
-       if (mdmf) {
-               /* MDMF Message waiting */
+               /* put date, number info at the right place */
+               len = callerid_genmsg(msg+2, sizeof(msg)-2, number, name, flags); 
+               
+               /* length of MDMF CLI plus Message Waiting Structure */
+               msg[1] = len+3;
+               
+               /* Go to the position to write to */
+               len = len+2;
+               
+               /* "Message Waiting Parameter" */
+               msg[len++] = 0x0b;
+               /* Length of IE is one */
+               msg[len++] = 1;
+               /* Active or not */
+               if (active)
+                       msg[len++] = 0xff;
+               else
+                       msg[len++] = 0x00;
+               
+       } else if (type == CID_MWI_TYPE_MDMF) {
+               /* MDMF Message waiting only */
+               /* same as above except that the we only put MWI parameter */
                msg[len++] = 0x82;
                /* Length is 3 */
                msg[len++] = 3;
                /* IE is "Message Waiting Parameter" */
-               msg[len++] = 0xb;
+               msg[len++] = 0x0b;
                /* Length of IE is one */
                msg[len++] = 1;
                /* Active or not */
@@ -793,31 +857,31 @@ int vmwi_generate(unsigned char *buf, int active, int mdmf, int codec)
                }
        }
        sum = 0;
-       for (x=0; x<len; x++)
+       for (x = 0; x < len; x++)
                sum += msg[x];
        sum = (256 - (sum & 255));
        msg[len++] = sum;
        /* Wait a half a second */
-       for (x=0; x<4000; x++)
+       for (x = 0; x < 4000; x++)
                PUT_BYTE(0x7f);
        /* Transmit 30 0x55's (looks like a square wave) for channel seizure */
-       for (x=0; x<30; x++)
+       for (x = 0; x < 30; x++)
                PUT_CLID(0x55);
        /* Send 170ms of callerid marks */
-       for (x=0; x<170; x++)
+       for (x = 0; x < 170; x++)
                PUT_CLID_MARKMS;
-       for (x=0; x<len; x++) {
+       for (x = 0; x < len; x++) {
                PUT_CLID(msg[x]);
        }
        /* Send 50 more ms of marks */
-       for (x=0; x<50; x++)
+       for (x = 0; x < 50; x++)
                PUT_CLID_MARKMS;
        return bytes;
 }
 
-int callerid_generate(unsigned char *buf, const char *number, const char *name, int flags, int callwaiting, int codec)
+int callerid_generate(unsigned char *buf, const char *number, const char *name, int flags, int callwaiting, format_t codec)
 {
-       int bytes=0;
+       int bytes = 0;
        int x, sum;
        int len;
 
@@ -829,14 +893,14 @@ int callerid_generate(unsigned char *buf, const char *number, const char *name,
        len = callerid_genmsg(msg, sizeof(msg), number, name, flags);
        if (!callwaiting) {
                /* Wait a half a second */
-               for (x=0; x<4000; x++)
+               for (x = 0; x < 4000; x++)
                        PUT_BYTE(0x7f);
                /* Transmit 30 0x55's (looks like a square wave) for channel seizure */
-               for (x=0; x<30; x++)
+               for (x = 0; x < 30; x++)
                        PUT_CLID(0x55);
        }
        /* Send 150ms of callerid marks */
-       for (x=0; x<150; x++)
+       for (x = 0; x < 150; x++)
                PUT_CLID_MARKMS;
        /* Send 0x80 indicating MDMF format */
        PUT_CLID(0x80);
@@ -844,7 +908,7 @@ int callerid_generate(unsigned char *buf, const char *number, const char *name,
        PUT_CLID(len);
        sum = 0x80 + strlen(msg);
        /* Put each character of message and update checksum */
-       for (x=0; x<len; x++) {
+       for (x = 0; x < len; x++) {
                PUT_CLID(msg[x]);
                sum += msg[x];
        }
@@ -852,23 +916,25 @@ int callerid_generate(unsigned char *buf, const char *number, const char *name,
        PUT_CLID(256 - (sum & 255));
 
        /* Send 50 more ms of marks */
-       for (x=0; x<50; x++)
+       for (x = 0; x < 50; x++)
                PUT_CLID_MARKMS;
        
        return bytes;
 }
 
-/*! \brief Clean up phone string
- * remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
+/*!
+ * \brief Clean up phone string
+ * \details
+ * Remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
  * Basically, remove anything that could be invalid in a pattern.
  */
 void ast_shrink_phone_number(char *n)
 {
-       int x, y=0;
+       int x, y = 0;
        int bracketed = 0;
 
-       for (x=0; n[x]; x++) {
-               switch(n[x]) {
+       for (x = 0; n[x]; x++) {
+               switch (n[x]) {
                case '[':
                        bracketed++;
                        n[y++] = n[x];
@@ -886,70 +952,65 @@ void ast_shrink_phone_number(char *n)
                                n[y++] = n[x];
                        break;
                default:
-                       if (!strchr("()", n[x]))
+                       /* ignore parenthesis and whitespace */
+                       if (!strchr("( )", n[x]))
                                n[y++] = n[x];
                }
        }
        n[y] = '\0';
 }
 
-/*! \brief Checks if phone number consists of valid characters 
-       \param exten    String that needs to be checked
-       \param valid    Valid characters in string
-       \return 1 if valid string, 0 if string contains invalid characters
-*/
+/*!
+ * \brief Checks if phone number consists of valid characters
+ * \param exten        String that needs to be checked
+ * \param valid        Valid characters in string
+ * \retval 1 if valid string
+ * \retval 0 if string contains invalid characters
+ */
 static int ast_is_valid_string(const char *exten, const char *valid)
 {
        int x;
 
        if (ast_strlen_zero(exten))
                return 0;
-       for (x=0; exten[x]; x++)
+       for (x = 0; exten[x]; x++)
                if (!strchr(valid, exten[x]))
                        return 0;
        return 1;
 }
 
-/*! \brief checks if string consists only of digits and * \# and + 
-       \return 1 if string is valid AST phone number
-       \return 0 if not
-*/
 int ast_isphonenumber(const char *n)
 {
        return ast_is_valid_string(n, "0123456789*#+");
 }
 
-/*! \brief checks if string consists only of digits and ( ) - * \# and + 
-       Pre-qualifies the string for ast_shrink_phone_number()
-       \return 1 if string is valid AST shrinkable phone number
-       \return 0 if not
-*/
 int ast_is_shrinkable_phonenumber(const char *exten)
 {
        return ast_is_valid_string(exten, "0123456789*#+()-.");
 }
 
-/*! \brief parse string for caller id information 
-       \return always returns 0, as the code always returns something.
-  XXX note that 'name' is not parsed consistently e.g. we have
-
-       input                   location        name
-       " foo bar " <123>       123             ' foo bar ' (with spaces around)
-       " foo bar "             NULL            'foo bar' (without spaces around)
-       " foo bar  <123>"       123             '" foo bar'
-  The parsing of leading and trailing space/quotes should be more consistent.
-*/
 int ast_callerid_parse(char *instr, char **name, char **location)
 {
        char *ns, *ne, *ls, *le;
 
        /* Try "name" <location> format or name <location> format */
-       if ((ls = strchr(instr, '<')) && (le = strchr(ls, '>'))) {
+       if ((ls = strrchr(instr, '<')) && (le = strrchr(ls, '>'))) {
                *ls = *le = '\0';       /* location found, trim off the brackets */
                *location = ls + 1;     /* and this is the result */
                if ((ns = strchr(instr, '"')) && (ne = strchr(ns + 1, '"'))) {
                        *ns = *ne = '\0';       /* trim off the quotes */
                        *name = ns + 1;         /* and this is the name */
+               } else if (ns) {
+                       /* An opening quote was found but no closing quote was. The closing
+                        * quote may actually be after the end of the bracketed number
+                        */
+                       if (strchr(le + 1, '\"')) {
+                               *ns = '\0';
+                               *name = ns + 1;
+                               ast_trim_blanks(*name);
+                       } else {
+                               *name = NULL;
+                       }
                } else { /* no quotes, trim off leading and trailing spaces */
                        *name = ast_skip_blanks(instr);
                        ast_trim_blanks(*name);
@@ -977,7 +1038,7 @@ int ast_callerid_parse(char *instr, char **name, char **location)
        return 0;
 }
 
-static int __ast_callerid_generate(unsigned char *buf, const char *name, const char *number, int callwaiting, int codec)
+static int __ast_callerid_generate(unsigned char *buf, const char *name, const char *number, int callwaiting, format_t codec)
 {
        if (ast_strlen_zero(name))
                name = NULL;
@@ -986,12 +1047,12 @@ static int __ast_callerid_generate(unsigned char *buf, const char *name, const c
        return callerid_generate(buf, number, name, 0, callwaiting, codec);
 }
 
-int ast_callerid_generate(unsigned char *buf, const char *name, const char *number, int codec)
+int ast_callerid_generate(unsigned char *buf, const char *name, const char *number, format_t codec)
 {
        return __ast_callerid_generate(buf, name, number, 0, codec);
 }
 
-int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, int codec)
+int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, format_t codec)
 {
        return __ast_callerid_generate(buf, name, number, 1, codec);
 }
@@ -1030,68 +1091,194 @@ int ast_callerid_split(const char *buf, char *name, int namelen, char *num, int
        return 0;
 }
 
-/*! \brief Translation table for Caller ID Presentation settings */
-static struct {
-       int val;
+struct ast_value_translation {
+       int value;
        const char *name;
        const char *description;
-} pres_types[] = {
-       {  AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened", "Presentation Allowed, Not Screened"},
-       {  AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", "Presentation Allowed, Passed Screen"},
-       {  AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", "Presentation Allowed, Failed Screen"},
-       {  AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed", "Presentation Allowed, Network Number"},
-       {  AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "prohib_not_screened", "Presentation Prohibited, Not Screened"},
-       {  AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", "Presentation Prohibited, Passed Screen"},
-       {  AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", "Presentation Prohibited, Failed Screen"},
-       {  AST_PRES_PROHIB_NETWORK_NUMBER, "prohib", "Presentation Prohibited, Network Number"},
-       {  AST_PRES_NUMBER_NOT_AVAILABLE, "unavailable", "Number Unavailable"},
 };
 
-/*! \brief Convert caller ID text code to value 
-       used in config file parsing
-       \param data text string
-       \return value AST_PRES_ from callerid.h 
-*/
+/*! \brief Translation table for Caller ID Presentation settings */
+static const struct ast_value_translation pres_types[] = {
+/* *INDENT-OFF* */
+       { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED,        "allowed_not_screened",  "Presentation Allowed, Not Screened" },
+       { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN,     "allowed_passed_screen", "Presentation Allowed, Passed Screen" },
+       { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN,     "allowed_failed_screen", "Presentation Allowed, Failed Screen" },
+       { AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER,                "allowed",               "Presentation Allowed, Network Number" },
+
+       { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED,     "prohib_not_screened",   "Presentation Prohibited, Not Screened" },
+       { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN,  "prohib_passed_screen",  "Presentation Prohibited, Passed Screen" },
+       { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN,  "prohib_failed_screen",  "Presentation Prohibited, Failed Screen" },
+       { AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER,             "prohib",                "Presentation Prohibited, Network Number" },
+
+       { AST_PRES_UNAVAILABLE | AST_PRES_NETWORK_NUMBER,            "unavailable",           "Number Unavailable" }, /* Default name to value conversion. */
+       { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_UNSCREENED,    "unavailable",           "Number Unavailable" },
+       { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_FAILED_SCREEN, "unavailable",           "Number Unavailable" },
+       { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_PASSED_SCREEN, "unavailable",           "Number Unavailable" },
+/* *INDENT-ON* */
+};
+
+/*!
+ * \brief Convert caller ID text code to value (used in config file parsing)
+ * \param data text string from config file
+ * \retval value AST_PRES_ from callerid.h
+ * \retval -1 if not in table
+ */
 int ast_parse_caller_presentation(const char *data)
 {
-       int i;
+       int index;
+       if (!data) {
+               return -1;
+       }
 
-       for (i = 0; i < ((sizeof(pres_types) / sizeof(pres_types[0]))); i++) {
-               if (!strcasecmp(pres_types[i].name, data))
-                       return pres_types[i].val;
+       for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
+               if (!strcasecmp(pres_types[index].name, data)) {
+                       return pres_types[index].value;
+               }
        }
 
        return -1;
 }
 
-/*! \brief Convert caller ID pres value to explanatory string 
-       \param data value (see callerid.h AST_PRES_ ) 
-       \return string for human presentation
-*/
+/*!
+ * \brief Convert caller ID pres value to explanatory string
+ * \param data AST_PRES_ value from callerid.h
+ * \return string for human presentation
+ */
 const char *ast_describe_caller_presentation(int data)
 {
-       int i;
+       int index;
 
-       for (i = 0; i < ((sizeof(pres_types) / sizeof(pres_types[0]))); i++) {
-               if (pres_types[i].val == data)
-                       return pres_types[i].description;
+       for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
+               if (pres_types[index].value == data) {
+                       return pres_types[index].description;
+               }
        }
 
        return "unknown";
 }
 
-/*! \brief Convert caller ID pres value to text code
-       \param data text string
-       \return string for config file
-*/
+/*!
+ * \brief Convert caller ID pres value to text code
+ * \param data AST_PRES_ value from callerid.h
+ * \return string for config file
+ */
 const char *ast_named_caller_presentation(int data)
 {
-       int i;
+       int index;
 
-       for (i = 0; i < ((sizeof(pres_types) / sizeof(pres_types[0]))); i++) {
-               if (pres_types[i].val == data)
-                       return pres_types[i].name;
+       for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
+               if (pres_types[index].value == data) {
+                       return pres_types[index].name;
+               }
        }
 
        return "unknown";
 }
+
+/*! \brief Translation table for redirecting reason settings */
+static const struct ast_value_translation redirecting_reason_types[] = {
+/* *INDENT-OFF* */
+       { AST_REDIRECTING_REASON_UNKNOWN,        "unknown",      "Unknown" },
+       { AST_REDIRECTING_REASON_USER_BUSY,      "cfb",          "Call Forwarding Busy" },
+       { AST_REDIRECTING_REASON_NO_ANSWER,      "cfnr",         "Call Forwarding No Reply" },
+       { AST_REDIRECTING_REASON_UNAVAILABLE,    "unavailable",  "Callee is Unavailable" },
+       { AST_REDIRECTING_REASON_UNCONDITIONAL,  "cfu",          "Call Forwarding Unconditional" },
+       { AST_REDIRECTING_REASON_TIME_OF_DAY,    "time_of_day",  "Time of Day" },
+       { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "dnd",          "Do Not Disturb" },
+       { AST_REDIRECTING_REASON_DEFLECTION,     "deflection",   "Call Deflection" },
+       { AST_REDIRECTING_REASON_FOLLOW_ME,      "follow_me",    "Follow Me" },
+       { AST_REDIRECTING_REASON_OUT_OF_ORDER,   "out_of_order", "Called DTE Out-Of-Order" },
+       { AST_REDIRECTING_REASON_AWAY,           "away",         "Callee is Away" },
+       { AST_REDIRECTING_REASON_CALL_FWD_DTE,   "cf_dte",       "Call Forwarding By The Called DTE" },
+/* *INDENT-ON* */
+};
+
+int ast_redirecting_reason_parse(const char *data)
+{
+       int index;
+
+       for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
+               if (!strcasecmp(redirecting_reason_types[index].name, data)) {
+                       return redirecting_reason_types[index].value;
+               }
+       }
+
+       return -1;
+}
+
+const char *ast_redirecting_reason_describe(int data)
+{
+       int index;
+
+       for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
+               if (redirecting_reason_types[index].value == data) {
+                       return redirecting_reason_types[index].description;
+               }
+       }
+
+       return "not-known";
+}
+
+const char *ast_redirecting_reason_name(int data)
+{
+       int index;
+
+       for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
+               if (redirecting_reason_types[index].value == data) {
+                       return redirecting_reason_types[index].name;
+               }
+       }
+
+       return "not-known";
+}
+
+/*! \brief Translation table for connected line update source settings */
+static const struct ast_value_translation connected_line_source_types[] = {
+/* *INDENT-OFF* */
+       { AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN,           "unknown",           "Unknown" },
+       { AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER,            "answer",            "Normal Call Answering" },
+       { AST_CONNECTED_LINE_UPDATE_SOURCE_DIVERSION,         "diversion",         "Call Diversion (Deprecated, use REDIRECTING)" },
+       { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER,          "transfer_active",   "Call Transfer(Active)" },
+       { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER,          "transfer",          "Call Transfer(Active)" },/* Old name must come after new name. */
+       { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING, "transfer_alerting", "Call Transfer(Alerting)" }
+/* *INDENT-ON* */
+};
+
+int ast_connected_line_source_parse(const char *data)
+{
+       int index;
+
+       for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
+               if (!strcasecmp(connected_line_source_types[index].name, data)) {
+                       return connected_line_source_types[index].value;
+               }
+       }
+
+       return -1;
+}
+
+const char *ast_connected_line_source_describe(int data)
+{
+       int index;
+
+       for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
+               if (connected_line_source_types[index].value == data) {
+                       return connected_line_source_types[index].description;
+               }
+       }
+
+       return "not-known";
+}
+
+const char *ast_connected_line_source_name(int data)
+{
+       int index;
+
+       for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
+               if (connected_line_source_types[index].value == data) {
+                       return connected_line_source_types[index].name;
+               }
+       }
+
+       return "not-known";
+}