Sat Mar 10 01:54:05 2012

Asterisk developer's documentation


callerid.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief CallerID Generation support 
00022  *
00023  * \author Mark Spencer <markster@digium.com> 
00024  */
00025 
00026 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 310636 $")
00029 
00030 #include <time.h>
00031 #include <math.h>
00032 #include <ctype.h>
00033 
00034 #include "asterisk/ulaw.h"
00035 #include "asterisk/alaw.h"
00036 #include "asterisk/frame.h"
00037 #include "asterisk/channel.h"
00038 #include "asterisk/callerid.h"
00039 #include "asterisk/fskmodem.h"
00040 #include "asterisk/utils.h"
00041 
00042 struct callerid_state {
00043    fsk_data fskd;
00044    char rawdata[256];
00045    short oldstuff[160];
00046    int oldlen;
00047    int pos;
00048    int type;
00049    int cksum;
00050    char name[64];
00051    char number[64];
00052    int flags;
00053    int sawflag;
00054    int len;
00055 
00056    int skipflag; 
00057    unsigned short crc;
00058 };
00059 
00060 
00061 float cid_dr[4], cid_di[4];
00062 float clidsb = 8000.0 / 1200.0;
00063 float sasdr, sasdi;
00064 float casdr1, casdi1, casdr2, casdi2;
00065 
00066 #define CALLERID_SPACE  2200.0      /*!< 2200 hz for "0" */
00067 #define CALLERID_MARK   1200.0      /*!< 1200 hz for "1" */
00068 #define SAS_FREQ      440.0
00069 #define CAS_FREQ1    2130.0
00070 #define CAS_FREQ2    2750.0
00071 
00072 #define AST_CALLERID_UNKNOWN  "<unknown>"
00073 
00074 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)
00075 {
00076    int x;
00077    float t;
00078    for (x = 0; x < len; x++) {
00079       t = *cr1 * ddr1 - *ci1 * ddi1;
00080       *ci1 = *cr1 * ddi1 + *ci1 * ddr1;
00081       *cr1 = t;
00082       t = 2.0 - (*cr1 * *cr1 + *ci1 * *ci1);
00083       *cr1 *= t;
00084       *ci1 *= t;  
00085 
00086       t = *cr2 * ddr2 - *ci2 * ddi2;
00087       *ci2 = *cr2 * ddi2 + *ci2 * ddr2;
00088       *cr2 = t;
00089       t = 2.0 - (*cr2 * *cr2 + *ci2 * *ci2);
00090       *cr2 *= t;
00091       *ci2 *= t;  
00092       buf[x] = AST_LIN2X((*cr1 + *cr2) * 2048.0);
00093    }
00094 }
00095 
00096 static inline void gen_tone(unsigned char *buf, int len, format_t codec, float ddr1, float ddi1, float *cr1, float *ci1)
00097 {
00098    int x;
00099    float t;
00100    for (x = 0; x < len; x++) {
00101       t = *cr1 * ddr1 - *ci1 * ddi1;
00102       *ci1 = *cr1 * ddi1 + *ci1 * ddr1;
00103       *cr1 = t;
00104       t = 2.0 - (*cr1 * *cr1 + *ci1 * *ci1);
00105       *cr1 *= t;
00106       *ci1 *= t;  
00107       buf[x] = AST_LIN2X(*cr1 * 8192.0);
00108    }
00109 }
00110 
00111 /*! \brief Initialize stuff for inverse FFT */
00112 void callerid_init(void)
00113 {
00114    cid_dr[0] = cos(CALLERID_SPACE * 2.0 * M_PI / 8000.0);
00115    cid_di[0] = sin(CALLERID_SPACE * 2.0 * M_PI / 8000.0);
00116    cid_dr[1] = cos(CALLERID_MARK * 2.0 * M_PI / 8000.0);
00117    cid_di[1] = sin(CALLERID_MARK * 2.0 * M_PI / 8000.0);
00118    sasdr = cos(SAS_FREQ * 2.0 * M_PI / 8000.0);
00119    sasdi = sin(SAS_FREQ * 2.0 * M_PI / 8000.0);
00120    casdr1 = cos(CAS_FREQ1 * 2.0 * M_PI / 8000.0);
00121    casdi1 = sin(CAS_FREQ1 * 2.0 * M_PI / 8000.0);
00122    casdr2 = cos(CAS_FREQ2 * 2.0 * M_PI / 8000.0);
00123    casdi2 = sin(CAS_FREQ2 * 2.0 * M_PI / 8000.0);
00124 }
00125 
00126 struct callerid_state *callerid_new(int cid_signalling)
00127 {
00128    struct callerid_state *cid;
00129 
00130    if ((cid = ast_calloc(1, sizeof(*cid)))) {
00131 #ifdef INTEGER_CALLERID
00132       cid->fskd.ispb = 7;           /* 1200 baud */   
00133       /* Set up for 1200 / 8000 freq *32 to allow ints */
00134       cid->fskd.pllispb  = (int)(8000 * 32  / 1200);
00135       cid->fskd.pllids   = cid->fskd.pllispb/32;
00136       cid->fskd.pllispb2 = cid->fskd.pllispb/2;
00137       
00138       cid->fskd.icont = 0;           /* PLL REset */
00139       /* cid->fskd.hdlc = 0; */        /* Async */
00140       cid->fskd.nbit = 8;              /* 8 bits */
00141       cid->fskd.instop = 1;         /* 1 stop bit */
00142       /* cid->fskd.paridad = 0; */     /* No parity */
00143       cid->fskd.bw = 1;                /* Filter 800 Hz */
00144       if (cid_signalling == 2) {       /* v23 signalling */
00145          cid->fskd.f_mark_idx  = 4; /* 1300 Hz */
00146          cid->fskd.f_space_idx = 5; /* 2100 Hz */
00147       } else {                         /* Bell 202 signalling as default */
00148          cid->fskd.f_mark_idx  = 2; /* 1200 Hz */
00149          cid->fskd.f_space_idx = 3; /* 2200 Hz */
00150       }
00151       /* cid->fskd.pcola = 0; */       /* No clue */
00152       /* cid->fskd.cont = 0.0; */      /* Digital PLL reset */
00153       /* cid->fskd.x0 = 0.0; */
00154       /* cid->fskd.state = 0; */
00155       cid->flags = CID_UNKNOWN_NAME | CID_UNKNOWN_NUMBER;
00156       /* cid->pos = 0; */
00157 
00158       fskmodem_init(&cid->fskd);
00159 #else
00160       cid->fskd.spb = 7.0;             /* 1200 baud */
00161       /* cid->fskd.hdlc = 0; */        /* Async */
00162       cid->fskd.nbit = 8;              /* 8 bits */
00163       cid->fskd.nstop = 1.0;           /* 1 stop bit */
00164       /* cid->fskd.paridad = 0; */     /* No parity */
00165       cid->fskd.bw = 1;                /* Filter 800 Hz */
00166       if (cid_signalling == 2) {       /* v23 signalling */
00167          cid->fskd.f_mark_idx =  4; /* 1300 Hz */
00168          cid->fskd.f_space_idx = 5; /* 2100 Hz */
00169       } else {                         /* Bell 202 signalling as default */
00170          cid->fskd.f_mark_idx =  2; /* 1200 Hz */
00171          cid->fskd.f_space_idx = 3; /* 2200 Hz */
00172       }
00173       /* cid->fskd.pcola = 0; */       /* No clue */
00174       /* cid->fskd.cont = 0.0; */      /* Digital PLL reset */
00175       /* cid->fskd.x0 = 0.0; */
00176       /* cid->fskd.state = 0; */
00177       cid->flags = CID_UNKNOWN_NAME | CID_UNKNOWN_NUMBER;
00178       /* cid->pos = 0; */
00179 #endif
00180    }
00181 
00182    return cid;
00183 }
00184 
00185 void callerid_get(struct callerid_state *cid, char **name, char **number, int *flags)
00186 {
00187    *flags = cid->flags;
00188    if (cid->flags & (CID_UNKNOWN_NAME | CID_PRIVATE_NAME))
00189       *name = NULL;
00190    else
00191       *name = cid->name;
00192    if (cid->flags & (CID_UNKNOWN_NUMBER | CID_PRIVATE_NUMBER))
00193       *number = NULL;
00194    else
00195       *number = cid->number;
00196 }
00197 
00198 void callerid_get_dtmf(char *cidstring, char *number, int *flags)
00199 {
00200    int i;
00201    int code;
00202 
00203    /* "Clear" the number-buffer. */
00204    number[0] = 0;
00205 
00206    if (strlen(cidstring) < 2) {
00207       ast_debug(1, "No cid detected\n");
00208       *flags = CID_UNKNOWN_NUMBER;
00209       return;
00210    }
00211    
00212    /* Detect protocol and special types */
00213    if (cidstring[0] == 'B') {
00214       /* Handle special codes */
00215       code = atoi(&cidstring[1]);
00216       if (code == 0)
00217          *flags = CID_UNKNOWN_NUMBER;
00218       else if (code == 10) 
00219          *flags = CID_PRIVATE_NUMBER;
00220       else
00221          ast_debug(1, "Unknown DTMF code %d\n", code);
00222    } else if (cidstring[0] == 'D' && cidstring[2] == '#') {
00223       /* .DK special code */
00224       if (cidstring[1] == '1')
00225          *flags = CID_PRIVATE_NUMBER;
00226       if (cidstring[1] == '2' || cidstring[1] == '3')
00227          *flags = CID_UNKNOWN_NUMBER;
00228    } else if (cidstring[0] == 'D' || cidstring[0] == 'A') {
00229       /* "Standard" callerid */
00230       for (i = 1; i < strlen(cidstring); i++) {
00231          if (cidstring[i] == 'C' || cidstring[i] == '#')
00232             break;
00233          if (isdigit(cidstring[i]))
00234             number[i-1] = cidstring[i];
00235          else
00236             ast_debug(1, "Unknown CID digit '%c'\n",
00237                cidstring[i]);
00238       }
00239       number[i-1] = 0;
00240    } else if (isdigit(cidstring[0])) {
00241       /* It begins with a digit, so we parse it as a number and hope
00242        * for the best */
00243       ast_log(LOG_WARNING, "Couldn't detect start-character. CID "
00244          "parsing might be unreliable\n");
00245       for (i = 0; i < strlen(cidstring); i++) {
00246          if (isdigit(cidstring[i]))
00247             number[i] = cidstring[i];
00248          else
00249             break;
00250       }
00251       number[i] = 0;
00252    } else {
00253       ast_debug(1, "Unknown CID protocol, start digit '%c'\n", cidstring[0]);
00254       *flags = CID_UNKNOWN_NUMBER;
00255    }
00256 }
00257 
00258 int ast_gen_cas(unsigned char *outbuf, int sendsas, int len, format_t codec)
00259 {
00260    int pos = 0;
00261    int saslen = 2400;
00262    float cr1 = 1.0;
00263    float ci1 = 0.0;
00264    float cr2 = 1.0;
00265    float ci2 = 0.0;
00266 
00267    if (sendsas) {
00268       if (len < saslen)
00269          return -1;
00270       gen_tone(outbuf, saslen, codec, sasdr, sasdi, &cr1, &ci1);
00271       len -= saslen;
00272       pos += saslen;
00273       cr2 = cr1;
00274       ci2 = ci1;
00275    }
00276    gen_tones(outbuf + pos, len, codec, casdr1, casdi1, casdr2, casdi2, &cr1, &ci1, &cr2, &ci2);
00277    return 0;
00278 }
00279 
00280 static unsigned short calc_crc(unsigned short crc, unsigned char data)
00281 {
00282    unsigned int i, j, org, dst;
00283    org = data;
00284    dst = 0;
00285 
00286    for (i = 0; i < CHAR_BIT; i++) {
00287       org <<= 1;
00288       dst >>= 1;
00289       if (org & 0x100) 
00290          dst |= 0x80;
00291    }
00292    data = (unsigned char) dst;
00293    crc ^= (unsigned int) data << (16 - CHAR_BIT);
00294    for (j = 0; j < CHAR_BIT; j++) {
00295       if (crc & 0x8000U)
00296          crc = (crc << 1) ^ 0x1021U ;
00297       else
00298          crc <<= 1 ;
00299    }
00300       return crc;
00301 }
00302 
00303 int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, format_t codec)
00304 {
00305    int mylen = len;
00306    int olen;
00307    int b = 'X';
00308    int b2;
00309    int res;
00310    int x;
00311    short *buf;
00312 
00313    buf = alloca(2 * len + cid->oldlen);
00314 
00315    memcpy(buf, cid->oldstuff, cid->oldlen);
00316    mylen += cid->oldlen / 2;
00317 
00318    for (x = 0; x < len; x++) 
00319       buf[x+cid->oldlen/2] = AST_XLAW(ubuf[x]);
00320 
00321    while (mylen >= 160) {
00322       b = b2 = 0;
00323       olen = mylen;
00324       res = fsk_serial(&cid->fskd, buf, &mylen, &b);
00325 
00326       if (mylen < 0) {
00327          ast_log(LOG_ERROR, "No start bit found in fsk data.\n");
00328          return -1;
00329       }
00330 
00331       buf += (olen - mylen);
00332 
00333       if (res < 0) {
00334          ast_log(LOG_NOTICE, "fsk_serial failed\n");
00335          return -1;
00336       }
00337 
00338       if (res == 1) {
00339          b2 = b;
00340          b  &= 0x7f;
00341 
00342          /* crc checksum calculation */
00343          if (cid->sawflag > 1)
00344             cid->crc = calc_crc(cid->crc, (unsigned char) b2);
00345 
00346          /* Ignore invalid bytes */
00347          if (b > 0xff)
00348             continue;
00349 
00350          /* skip DLE if needed */
00351          if (cid->sawflag > 0) {
00352             if (cid->sawflag != 5 && cid->skipflag == 0 && b == 0x10) {
00353                cid->skipflag = 1 ;
00354                continue ;
00355             }
00356          }
00357          if (cid->skipflag == 1)
00358             cid->skipflag = 0 ;
00359 
00360          /* caller id retrieval */
00361          switch (cid->sawflag) {
00362          case 0: /* DLE */
00363             if (b == 0x10) {
00364                cid->sawflag = 1;
00365                cid->skipflag = 0;
00366                cid->crc = 0;
00367             }
00368             break;
00369          case 1: /* SOH */
00370             if (b == 0x01) 
00371                cid->sawflag = 2;
00372             break ;
00373          case 2: /* HEADER */
00374             if (b == 0x07) 
00375                cid->sawflag = 3;
00376             break;
00377          case 3: /* STX */
00378             if (b == 0x02) 
00379                cid->sawflag = 4;
00380             break;
00381          case 4: /* SERVICE TYPE */
00382             if (b == 0x40) 
00383                cid->sawflag = 5;
00384             break;
00385          case 5: /* Frame Length */
00386             cid->sawflag = 6;
00387             break;   
00388          case 6: /* NUMBER TYPE */
00389             cid->sawflag = 7;
00390             cid->pos = 0;
00391             cid->rawdata[cid->pos++] = b;
00392             break;
00393          case 7:  /* NUMBER LENGTH */
00394             cid->sawflag = 8;
00395             cid->len = b;
00396             if ((cid->len+2) >= sizeof(cid->rawdata)) {
00397                ast_log(LOG_WARNING, "too long caller id string\n") ;
00398                return -1;
00399             }
00400             cid->rawdata[cid->pos++] = b;
00401             break;
00402          case 8:  /* Retrieve message */
00403             cid->rawdata[cid->pos++] = b;
00404             cid->len--;
00405             if (cid->len<=0) {
00406                cid->rawdata[cid->pos] = '\0';
00407                cid->sawflag = 9;
00408             }
00409             break;
00410          case 9:  /* ETX */
00411             cid->sawflag = 10;
00412             break;
00413          case 10: /* CRC Checksum 1 */
00414             cid->sawflag = 11;
00415             break;
00416          case 11: /* CRC Checksum 2 */
00417             cid->sawflag = 12;
00418             if (cid->crc != 0) {
00419                ast_log(LOG_WARNING, "crc checksum error\n") ;
00420                return -1;
00421             } 
00422             /* extract caller id data */
00423             for (x = 0; x < cid->pos;) {
00424                switch (cid->rawdata[x++]) {
00425                case 0x02: /* caller id  number */
00426                   cid->number[0] = '\0';
00427                   cid->name[0] = '\0';
00428                   cid->flags = 0;
00429                   res = cid->rawdata[x++];
00430                   ast_copy_string(cid->number, &cid->rawdata[x], res+1);
00431                   x += res;
00432                   break;
00433                case 0x21: /* additional information */
00434                   /* length */
00435                   x++; 
00436                   /* number type */
00437                   switch (cid->rawdata[x]) { 
00438                   case 0x00: /* unknown */
00439                   case 0x01: /* international number */
00440                   case 0x02: /* domestic number */
00441                   case 0x03: /* network */
00442                   case 0x04: /* local call */
00443                   case 0x06: /* short dial number */
00444                   case 0x07: /* reserved */
00445                   default:   /* reserved */
00446                      ast_debug(2, "cid info:#1=%X\n", cid->rawdata[x]);
00447                      break ;
00448                   }
00449                   x++; 
00450                   /* numbering plan octed 4 */
00451                   x++; 
00452                   /* numbering plan octed 5 */
00453                   switch (cid->rawdata[x]) { 
00454                   case 0x00: /* unknown */
00455                   case 0x01: /* recommendation E.164 ISDN */
00456                   case 0x03: /* recommendation X.121 */
00457                   case 0x04: /* telex dial plan */
00458                   case 0x08: /* domestic dial plan */
00459                   case 0x09: /* private dial plan */
00460                   case 0x05: /* reserved */
00461                   default:   /* reserved */
00462                      ast_debug(2, "cid info:#2=%X\n", cid->rawdata[x]);
00463                      break ;
00464                   }
00465                   x++; 
00466                   break ;
00467                case 0x04: /* no callerid reason */
00468                   /* length */
00469                   x++; 
00470                   /* no callerid reason code */
00471                   switch (cid->rawdata[x]) {
00472                   case 'P': /* caller id denied by user */
00473                   case 'O': /* service not available */
00474                   case 'C': /* pay phone */
00475                   case 'S': /* service congested */
00476                      cid->flags |= CID_UNKNOWN_NUMBER;
00477                      ast_debug(2, "no cid reason:%c\n", cid->rawdata[x]);
00478                      break ;
00479                   }
00480                   x++; 
00481                   break ;
00482                case 0x09: /* dialed number */
00483                   /* length */
00484                   res = cid->rawdata[x++];
00485                   /* dialed number */
00486                   x += res;
00487                   break ;
00488                case 0x22: /* dialed number additional information */
00489                   /* length */
00490                   x++;
00491                   /* number type */
00492                   switch (cid->rawdata[x]) {
00493                   case 0x00: /* unknown */
00494                   case 0x01: /* international number */
00495                   case 0x02: /* domestic number */
00496                   case 0x03: /* network */
00497                   case 0x04: /* local call */
00498                   case 0x06: /* short dial number */
00499                   case 0x07: /* reserved */
00500                   default:   /* reserved */
00501                      if (option_debug > 1)
00502                         ast_log(LOG_NOTICE, "did info:#1=%X\n", cid->rawdata[x]);
00503                      break ;
00504                   }
00505                   x++;
00506                   /* numbering plan octed 4 */
00507                   x++;
00508                   /* numbering plan octed 5 */
00509                   switch (cid->rawdata[x]) {
00510                   case 0x00: /* unknown */
00511                   case 0x01: /* recommendation E.164 ISDN */
00512                   case 0x03: /* recommendation X.121 */
00513                   case 0x04: /* telex dial plan */
00514                   case 0x08: /* domestic dial plan */
00515                   case 0x09: /* private dial plan */
00516                   case 0x05: /* reserved */
00517                   default:   /* reserved */
00518                      ast_debug(2, "did info:#2=%X\n", cid->rawdata[x]);
00519                      break ;
00520                   }
00521                   x++;
00522                   break ;
00523                }
00524             }
00525             return 1;
00526             break;
00527          default:
00528             ast_log(LOG_ERROR, "invalid value in sawflag %d\n", cid->sawflag);
00529          }
00530       }
00531    }
00532    if (mylen) {
00533       memcpy(cid->oldstuff, buf, mylen * 2);
00534       cid->oldlen = mylen * 2;
00535    } else
00536       cid->oldlen = 0;
00537    
00538    return 0;
00539 }
00540 
00541 
00542 int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, format_t codec)
00543 {
00544    int mylen = len;
00545    int olen;
00546    int b = 'X';
00547    int res;
00548    int x;
00549    short *buf;
00550 
00551    buf = alloca(2 * len + cid->oldlen);
00552 
00553    memcpy(buf, cid->oldstuff, cid->oldlen);
00554    mylen += cid->oldlen/2;
00555 
00556    for (x = 0; x < len; x++) 
00557       buf[x+cid->oldlen/2] = AST_XLAW(ubuf[x]);
00558    while (mylen >= 160) {
00559       olen = mylen;
00560       res = fsk_serial(&cid->fskd, buf, &mylen, &b);
00561       if (mylen < 0) {
00562          ast_log(LOG_ERROR, "No start bit found in fsk data.\n");
00563          return -1;
00564       }
00565       buf += (olen - mylen);
00566       if (res < 0) {
00567          ast_log(LOG_NOTICE, "fsk_serial failed\n");
00568          return -1;
00569       }
00570       if (res == 1) {
00571          if (b > 0xff) {
00572             if (cid->sawflag != 5) {
00573                /* Ignore invalid bytes */
00574                continue;
00575             }
00576             /*
00577              * We can tollerate an error on the checksum character since the
00578              * checksum character is the last character in the message and
00579              * it validates the message.
00580              *
00581              * Remove character error flags.
00582              * Bit 8 : Parity error
00583              * Bit 9 : Framing error
00584              */
00585             b &= 0xff;
00586          }
00587          switch (cid->sawflag) {
00588          case 0: /* Look for flag */
00589             if (b == 'U')
00590                cid->sawflag = 2;
00591             break;
00592          case 2: /* Get lead-in */
00593             if ((b == 0x04) || (b == 0x80) || (b == 0x06) || (b == 0x82)) {
00594                cid->type = b;
00595                cid->sawflag = 3;
00596                cid->cksum = b;
00597             }
00598             break;
00599          case 3:  /* Get length */
00600             /* Not a lead in.  We're ready  */
00601             cid->sawflag = 4;
00602             cid->len = b;
00603             cid->pos = 0;
00604             cid->cksum += b;
00605             break;
00606          case 4: /* Retrieve message */
00607             if (cid->pos >= 128) {
00608                ast_log(LOG_WARNING, "Caller ID too long???\n");
00609                return -1;
00610             }
00611             cid->rawdata[cid->pos++] = b;
00612             cid->len--;
00613             cid->cksum += b;
00614             if (!cid->len) {
00615                cid->rawdata[cid->pos] = '\0';
00616                cid->sawflag = 5;
00617             }
00618             break;
00619          case 5: /* Check checksum */
00620             if (b != (256 - (cid->cksum & 0xff))) {
00621                ast_log(LOG_NOTICE, "Caller*ID failed checksum\n");
00622                /* Try again */
00623                cid->sawflag = 0;
00624                break;
00625             }
00626       
00627             cid->number[0] = '\0';
00628             cid->name[0] = '\0';
00629             /* Update flags */
00630             cid->flags = 0;
00631             /* If we get this far we're fine.  */
00632             if ((cid->type == 0x80) || (cid->type == 0x82)) {
00633                /* MDMF */
00634                /* Go through each element and process */
00635                for (x = 0; x < cid->pos;) {
00636                   switch (cid->rawdata[x++]) {
00637                   case 1:
00638                      /* Date */
00639                      break;
00640                   case 2: /* Number */
00641                   case 3: /* Number (for Zebble) */
00642                   case 4: /* Number */
00643                      res = cid->rawdata[x];
00644                      if (res > 32) {
00645                         ast_log(LOG_NOTICE, "Truncating long caller ID number from %d bytes to 32\n", cid->rawdata[x]);
00646                         res = 32; 
00647                      }
00648                      if (ast_strlen_zero(cid->number)) {
00649                         memcpy(cid->number, cid->rawdata + x + 1, res);
00650                         /* Null terminate */
00651                         cid->number[res] = '\0';
00652                      }
00653                      break;
00654                   case 6: /* Stentor Call Qualifier (ie. Long Distance call) */
00655                      break;
00656                   case 7: /* Name */
00657                   case 8: /* Name */
00658                      res = cid->rawdata[x];
00659                      if (res > 32) {
00660                         ast_log(LOG_NOTICE, "Truncating long caller ID name from %d bytes to 32\n", cid->rawdata[x]);
00661                         res = 32; 
00662                      }
00663                      memcpy(cid->name, cid->rawdata + x + 1, res);
00664                      cid->name[res] = '\0';
00665                      break;
00666                   case 11: /* Message Waiting */
00667                      res = cid->rawdata[x + 1];
00668                      if (res)
00669                         cid->flags |= CID_MSGWAITING;
00670                      else
00671                         cid->flags |= CID_NOMSGWAITING;
00672                      break;
00673                   case 17: /* UK: Call type, 1=Voice Call, 2=Ringback when free, 129=Message waiting  */
00674                   case 19: /* UK: Network message system status (Number of messages waiting) */
00675                   case 22: /* Something French */
00676                      break;
00677                   default:
00678                      ast_log(LOG_NOTICE, "Unknown IE %d\n", cid->rawdata[x - 1]);
00679                   }
00680                   res = cid->rawdata[x];
00681                   if (0 > res){  /* Negative offset in the CID Spill */
00682                      ast_log(LOG_NOTICE, "IE %d has bad field length of %d at offset %d\n", cid->rawdata[x-1], cid->rawdata[x], x);
00683                      /* Try again */
00684                      cid->sawflag = 0;
00685                      break;   /* Exit the loop */
00686                   }
00687                   x += cid->rawdata[x];
00688                   x++;
00689                }
00690             } else if (cid->type == 0x6) {
00691                /* VMWI SDMF */
00692                if (cid->rawdata[2] == 0x42) {
00693                   cid->flags |= CID_MSGWAITING;
00694                } else if (cid->rawdata[2] == 0x6f) {
00695                   cid->flags |= CID_NOMSGWAITING;
00696                }
00697             } else {
00698                /* SDMF */
00699                ast_copy_string(cid->number, cid->rawdata + 8, sizeof(cid->number));
00700             }
00701             if (!strcmp(cid->number, "P")) {
00702                strcpy(cid->number, "");
00703                cid->flags |= CID_PRIVATE_NUMBER;
00704             } else if (!strcmp(cid->number, "O") || ast_strlen_zero(cid->number)) {
00705                strcpy(cid->number, "");
00706                cid->flags |= CID_UNKNOWN_NUMBER;
00707             }
00708             if (!strcmp(cid->name, "P")) {
00709                strcpy(cid->name, "");
00710                cid->flags |= CID_PRIVATE_NAME;
00711             } else if (!strcmp(cid->name, "O") || ast_strlen_zero(cid->name)) {
00712                strcpy(cid->name, "");
00713                cid->flags |= CID_UNKNOWN_NAME;
00714             }
00715             return 1;
00716             break;
00717          default:
00718             ast_log(LOG_ERROR, "Dunno what to do with a digit in sawflag %d\n", cid->sawflag);
00719          }
00720       }
00721    }
00722    if (mylen) {
00723       memcpy(cid->oldstuff, buf, mylen * 2);
00724       cid->oldlen = mylen * 2;
00725    } else
00726       cid->oldlen = 0;
00727 
00728    return 0;
00729 }
00730 
00731 void callerid_free(struct callerid_state *cid)
00732 {
00733    ast_free(cid);
00734 }
00735 
00736 static int callerid_genmsg(char *msg, int size, const char *number, const char *name, int flags)
00737 {
00738    struct timeval now = ast_tvnow();
00739    struct ast_tm tm;
00740    char *ptr;
00741    int res;
00742    int i, x;
00743 
00744    /* Get the time */
00745    ast_localtime(&now, &tm, NULL);
00746    
00747    ptr = msg;
00748    
00749    /* Format time and message header */
00750    res = snprintf(ptr, size, "\001\010%02d%02d%02d%02d", tm.tm_mon + 1,
00751             tm.tm_mday, tm.tm_hour, tm.tm_min);
00752    size -= res;
00753    ptr += res;
00754    if (ast_strlen_zero(number) || (flags & CID_UNKNOWN_NUMBER)) {
00755       /* Indicate number not known */
00756       res = snprintf(ptr, size, "\004\001O");
00757       size -= res;
00758       ptr += res;
00759    } else if (flags & CID_PRIVATE_NUMBER) {
00760       /* Indicate number is private */
00761       res = snprintf(ptr, size, "\004\001P");
00762       size -= res;
00763       ptr += res;
00764    } else {
00765       /* Send up to 16 digits of number MAX */
00766       i = strlen(number);
00767       if (i > 16)
00768          i = 16;
00769       res = snprintf(ptr, size, "\002%c", i);
00770       size -= res;
00771       ptr += res;
00772       for (x = 0; x < i; x++)
00773          ptr[x] = number[x];
00774       ptr[i] = '\0';
00775       ptr += i;
00776       size -= i;
00777    }
00778 
00779    if (ast_strlen_zero(name) || (flags & CID_UNKNOWN_NAME)) {
00780       /* Indicate name not known */
00781       res = snprintf(ptr, size, "\010\001O");
00782       size -= res;
00783       ptr += res;
00784    } else if (flags & CID_PRIVATE_NAME) {
00785       /* Indicate name is private */
00786       res = snprintf(ptr, size, "\010\001P");
00787       size -= res;
00788       ptr += res;
00789    } else {
00790       /* Send up to 16 digits of name MAX */
00791       i = strlen(name);
00792       if (i > 16)
00793          i = 16;
00794       res = snprintf(ptr, size, "\007%c", i);
00795       size -= res;
00796       ptr += res;
00797       for (x = 0; x < i; x++)
00798          ptr[x] = name[x];
00799       ptr[i] = '\0';
00800       ptr += i;
00801       size -= i;
00802    }
00803    return (ptr - msg);
00804    
00805 }
00806 
00807 int ast_callerid_vmwi_generate(unsigned char *buf, int active, int type, format_t codec,
00808                 const char* name, const char* number, int flags)
00809 {
00810    char msg[256];
00811    int len = 0;
00812    int sum;
00813    int x;
00814    int bytes = 0;
00815    float cr = 1.0;
00816    float ci = 0.0;
00817    float scont = 0.0;
00818    
00819    if (type == CID_MWI_TYPE_MDMF_FULL) {
00820       /* MDMF Message waiting with date, number, name and MWI parameter */
00821       msg[0] = 0x82;
00822 
00823       /* put date, number info at the right place */
00824       len = callerid_genmsg(msg+2, sizeof(msg)-2, number, name, flags); 
00825       
00826       /* length of MDMF CLI plus Message Waiting Structure */
00827       msg[1] = len+3;
00828       
00829       /* Go to the position to write to */
00830       len = len+2;
00831       
00832       /* "Message Waiting Parameter" */
00833       msg[len++] = 0x0b;
00834       /* Length of IE is one */
00835       msg[len++] = 1;
00836       /* Active or not */
00837       if (active)
00838          msg[len++] = 0xff;
00839       else
00840          msg[len++] = 0x00;
00841       
00842    } else if (type == CID_MWI_TYPE_MDMF) {
00843       /* MDMF Message waiting only */
00844       /* same as above except that the we only put MWI parameter */
00845       msg[len++] = 0x82;
00846       /* Length is 3 */
00847       msg[len++] = 3;
00848       /* IE is "Message Waiting Parameter" */
00849       msg[len++] = 0x0b;
00850       /* Length of IE is one */
00851       msg[len++] = 1;
00852       /* Active or not */
00853       if (active)
00854          msg[len++] = 0xff;
00855       else
00856          msg[len++] = 0x00;
00857    } else {
00858       /* SDMF Message waiting */
00859       msg[len++] = 0x6;
00860       /* Length is 3 */
00861       msg[len++] = 3;
00862       if (active) {
00863          msg[len++] = 0x42;
00864          msg[len++] = 0x42;
00865          msg[len++] = 0x42;
00866       } else {
00867          msg[len++] = 0x6f;
00868          msg[len++] = 0x6f;
00869          msg[len++] = 0x6f;
00870       }
00871    }
00872    sum = 0;
00873    for (x = 0; x < len; x++)
00874       sum += msg[x];
00875    sum = (256 - (sum & 255));
00876    msg[len++] = sum;
00877    /* Wait a half a second */
00878    for (x = 0; x < 4000; x++)
00879       PUT_BYTE(0x7f);
00880    /* Transmit 30 0x55's (looks like a square wave) for channel seizure */
00881    for (x = 0; x < 30; x++)
00882       PUT_CLID(0x55);
00883    /* Send 170ms of callerid marks */
00884    for (x = 0; x < 170; x++)
00885       PUT_CLID_MARKMS;
00886    for (x = 0; x < len; x++) {
00887       PUT_CLID(msg[x]);
00888    }
00889    /* Send 50 more ms of marks */
00890    for (x = 0; x < 50; x++)
00891       PUT_CLID_MARKMS;
00892    return bytes;
00893 }
00894 
00895 int callerid_generate(unsigned char *buf, const char *number, const char *name, int flags, int callwaiting, format_t codec)
00896 {
00897    int bytes = 0;
00898    int x, sum;
00899    int len;
00900 
00901    /* Initial carriers (real/imaginary) */
00902    float cr = 1.0;
00903    float ci = 0.0;
00904    float scont = 0.0;
00905    char msg[256];
00906    len = callerid_genmsg(msg, sizeof(msg), number, name, flags);
00907    if (!callwaiting) {
00908       /* Wait a half a second */
00909       for (x = 0; x < 4000; x++)
00910          PUT_BYTE(0x7f);
00911       /* Transmit 30 0x55's (looks like a square wave) for channel seizure */
00912       for (x = 0; x < 30; x++)
00913          PUT_CLID(0x55);
00914    }
00915    /* Send 150ms of callerid marks */
00916    for (x = 0; x < 150; x++)
00917       PUT_CLID_MARKMS;
00918    /* Send 0x80 indicating MDMF format */
00919    PUT_CLID(0x80);
00920    /* Put length of whole message */
00921    PUT_CLID(len);
00922    sum = 0x80 + strlen(msg);
00923    /* Put each character of message and update checksum */
00924    for (x = 0; x < len; x++) {
00925       PUT_CLID(msg[x]);
00926       sum += msg[x];
00927    }
00928    /* Send 2's compliment of sum */
00929    PUT_CLID(256 - (sum & 255));
00930 
00931    /* Send 50 more ms of marks */
00932    for (x = 0; x < 50; x++)
00933       PUT_CLID_MARKMS;
00934    
00935    return bytes;
00936 }
00937 
00938 /*!
00939  * \brief Clean up phone string
00940  * \details
00941  * Remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
00942  * Basically, remove anything that could be invalid in a pattern.
00943  */
00944 void ast_shrink_phone_number(char *n)
00945 {
00946    int x, y = 0;
00947    int bracketed = 0;
00948 
00949    for (x = 0; n[x]; x++) {
00950       switch (n[x]) {
00951       case '[':
00952          bracketed++;
00953          n[y++] = n[x];
00954          break;
00955       case ']':
00956          bracketed--;
00957          n[y++] = n[x];
00958          break;
00959       case '-':
00960          if (bracketed)
00961             n[y++] = n[x];
00962          break;
00963       case '.':
00964          if (!n[x+1])
00965             n[y++] = n[x];
00966          break;
00967       default:
00968          /* ignore parenthesis and whitespace */
00969          if (!strchr("( )", n[x]))
00970             n[y++] = n[x];
00971       }
00972    }
00973    n[y] = '\0';
00974 }
00975 
00976 /*!
00977  * \brief Checks if phone number consists of valid characters
00978  * \param exten   String that needs to be checked
00979  * \param valid   Valid characters in string
00980  * \retval 1 if valid string
00981  * \retval 0 if string contains invalid characters
00982  */
00983 static int ast_is_valid_string(const char *exten, const char *valid)
00984 {
00985    int x;
00986 
00987    if (ast_strlen_zero(exten))
00988       return 0;
00989    for (x = 0; exten[x]; x++)
00990       if (!strchr(valid, exten[x]))
00991          return 0;
00992    return 1;
00993 }
00994 
00995 int ast_isphonenumber(const char *n)
00996 {
00997    return ast_is_valid_string(n, "0123456789*#+");
00998 }
00999 
01000 int ast_is_shrinkable_phonenumber(const char *exten)
01001 {
01002    return ast_is_valid_string(exten, "0123456789*#+()-.");
01003 }
01004 
01005 int ast_callerid_parse(char *instr, char **name, char **location)
01006 {
01007    char *ns, *ne, *ls, *le;
01008 
01009    /* Try "name" <location> format or name <location> format */
01010    if ((ls = strrchr(instr, '<')) && (le = strrchr(ls, '>'))) {
01011       *ls = *le = '\0'; /* location found, trim off the brackets */
01012       *location = ls + 1;  /* and this is the result */
01013       if ((ns = strchr(instr, '"')) && (ne = strchr(ns + 1, '"'))) {
01014          *ns = *ne = '\0'; /* trim off the quotes */
01015          *name = ns + 1;      /* and this is the name */
01016       } else if (ns) {
01017          /* An opening quote was found but no closing quote was. The closing
01018           * quote may actually be after the end of the bracketed number
01019           */
01020          if (strchr(le + 1, '\"')) {
01021             *ns = '\0';
01022             *name = ns + 1;
01023             ast_trim_blanks(*name);
01024          } else {
01025             *name = NULL;
01026          }
01027       } else { /* no quotes, trim off leading and trailing spaces */
01028          *name = ast_skip_blanks(instr);
01029          ast_trim_blanks(*name);
01030       }
01031    } else { /* no valid brackets */
01032       char tmp[256];
01033 
01034       ast_copy_string(tmp, instr, sizeof(tmp));
01035       ast_shrink_phone_number(tmp);
01036       if (ast_isphonenumber(tmp)) { /* Assume it's just a location */
01037          *name = NULL;
01038          strcpy(instr, tmp); /* safe, because tmp will always be the same size or smaller than instr */
01039          *location = instr;
01040       } else { /* Assume it's just a name. */
01041          *location = NULL;
01042          if ((ns = strchr(instr, '"')) && (ne = strchr(ns + 1, '"'))) {
01043             *ns = *ne = '\0'; /* trim off the quotes */
01044             *name = ns + 1;      /* and this is the name */
01045          } else { /* no quotes, trim off leading and trailing spaces */
01046             *name = ast_skip_blanks(instr);
01047             ast_trim_blanks(*name);
01048          }
01049       }
01050    }
01051    return 0;
01052 }
01053 
01054 static int __ast_callerid_generate(unsigned char *buf, const char *name, const char *number, int callwaiting, format_t codec)
01055 {
01056    if (ast_strlen_zero(name))
01057       name = NULL;
01058    if (ast_strlen_zero(number))
01059       number = NULL;
01060    return callerid_generate(buf, number, name, 0, callwaiting, codec);
01061 }
01062 
01063 int ast_callerid_generate(unsigned char *buf, const char *name, const char *number, format_t codec)
01064 {
01065    return __ast_callerid_generate(buf, name, number, 0, codec);
01066 }
01067 
01068 int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, format_t codec)
01069 {
01070    return __ast_callerid_generate(buf, name, number, 1, codec);
01071 }
01072 
01073 char *ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
01074 {
01075    if (!unknown)
01076       unknown = "<unknown>";
01077    if (name && num)
01078       snprintf(buf, bufsiz, "\"%s\" <%s>", name, num);
01079    else if (name) 
01080       ast_copy_string(buf, name, bufsiz);
01081    else if (num)
01082       ast_copy_string(buf, num, bufsiz);
01083    else
01084       ast_copy_string(buf, unknown, bufsiz);
01085    return buf;
01086 }
01087 
01088 int ast_callerid_split(const char *buf, char *name, int namelen, char *num, int numlen)
01089 {
01090    char *tmp;
01091    char *l = NULL, *n = NULL;
01092 
01093    tmp = ast_strdupa(buf);
01094    ast_callerid_parse(tmp, &n, &l);
01095    if (n)
01096       ast_copy_string(name, n, namelen);
01097    else
01098       name[0] = '\0';
01099    if (l) {
01100       ast_shrink_phone_number(l);
01101       ast_copy_string(num, l, numlen);
01102    } else
01103       num[0] = '\0';
01104    return 0;
01105 }
01106 
01107 struct ast_value_translation {
01108    int value;
01109    const char *name;
01110    const char *description;
01111 };
01112 
01113 /*! \brief Translation table for Caller ID Presentation settings */
01114 static const struct ast_value_translation pres_types[] = {
01115 /* *INDENT-OFF* */
01116    { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED,        "allowed_not_screened",  "Presentation Allowed, Not Screened" },
01117    { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_PASSED_SCREEN,     "allowed_passed_screen", "Presentation Allowed, Passed Screen" },
01118    { AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_FAILED_SCREEN,     "allowed_failed_screen", "Presentation Allowed, Failed Screen" },
01119    { AST_PRES_ALLOWED | AST_PRES_NETWORK_NUMBER,                "allowed",               "Presentation Allowed, Network Number" },
01120 
01121    { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED,     "prohib_not_screened",   "Presentation Prohibited, Not Screened" },
01122    { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_PASSED_SCREEN,  "prohib_passed_screen",  "Presentation Prohibited, Passed Screen" },
01123    { AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_FAILED_SCREEN,  "prohib_failed_screen",  "Presentation Prohibited, Failed Screen" },
01124    { AST_PRES_RESTRICTED | AST_PRES_NETWORK_NUMBER,             "prohib",                "Presentation Prohibited, Network Number" },
01125 
01126    { AST_PRES_UNAVAILABLE | AST_PRES_NETWORK_NUMBER,            "unavailable",           "Number Unavailable" }, /* Default name to value conversion. */
01127    { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_UNSCREENED,    "unavailable",           "Number Unavailable" },
01128    { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_FAILED_SCREEN, "unavailable",           "Number Unavailable" },
01129    { AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_PASSED_SCREEN, "unavailable",           "Number Unavailable" },
01130 /* *INDENT-ON* */
01131 };
01132 
01133 /*!
01134  * \brief Convert caller ID text code to value (used in config file parsing)
01135  * \param data text string from config file
01136  * \retval value AST_PRES_ from callerid.h
01137  * \retval -1 if not in table
01138  */
01139 int ast_parse_caller_presentation(const char *data)
01140 {
01141    int index;
01142    if (!data) {
01143       return -1;
01144    }
01145 
01146    for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
01147       if (!strcasecmp(pres_types[index].name, data)) {
01148          return pres_types[index].value;
01149       }
01150    }
01151 
01152    return -1;
01153 }
01154 
01155 /*!
01156  * \brief Convert caller ID pres value to explanatory string
01157  * \param data AST_PRES_ value from callerid.h
01158  * \return string for human presentation
01159  */
01160 const char *ast_describe_caller_presentation(int data)
01161 {
01162    int index;
01163 
01164    for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
01165       if (pres_types[index].value == data) {
01166          return pres_types[index].description;
01167       }
01168    }
01169 
01170    return "unknown";
01171 }
01172 
01173 /*!
01174  * \brief Convert caller ID pres value to text code
01175  * \param data AST_PRES_ value from callerid.h
01176  * \return string for config file
01177  */
01178 const char *ast_named_caller_presentation(int data)
01179 {
01180    int index;
01181 
01182    for (index = 0; index < ARRAY_LEN(pres_types); ++index) {
01183       if (pres_types[index].value == data) {
01184          return pres_types[index].name;
01185       }
01186    }
01187 
01188    return "unknown";
01189 }
01190 
01191 /*! \brief Translation table for redirecting reason settings */
01192 static const struct ast_value_translation redirecting_reason_types[] = {
01193 /* *INDENT-OFF* */
01194    { AST_REDIRECTING_REASON_UNKNOWN,        "unknown",      "Unknown" },
01195    { AST_REDIRECTING_REASON_USER_BUSY,      "cfb",          "Call Forwarding Busy" },
01196    { AST_REDIRECTING_REASON_NO_ANSWER,      "cfnr",         "Call Forwarding No Reply" },
01197    { AST_REDIRECTING_REASON_UNAVAILABLE,    "unavailable",  "Callee is Unavailable" },
01198    { AST_REDIRECTING_REASON_UNCONDITIONAL,  "cfu",          "Call Forwarding Unconditional" },
01199    { AST_REDIRECTING_REASON_TIME_OF_DAY,    "time_of_day",  "Time of Day" },
01200    { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "dnd",          "Do Not Disturb" },
01201    { AST_REDIRECTING_REASON_DEFLECTION,     "deflection",   "Call Deflection" },
01202    { AST_REDIRECTING_REASON_FOLLOW_ME,      "follow_me",    "Follow Me" },
01203    { AST_REDIRECTING_REASON_OUT_OF_ORDER,   "out_of_order", "Called DTE Out-Of-Order" },
01204    { AST_REDIRECTING_REASON_AWAY,           "away",         "Callee is Away" },
01205    { AST_REDIRECTING_REASON_CALL_FWD_DTE,   "cf_dte",       "Call Forwarding By The Called DTE" },
01206 /* *INDENT-ON* */
01207 };
01208 
01209 int ast_redirecting_reason_parse(const char *data)
01210 {
01211    int index;
01212 
01213    for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
01214       if (!strcasecmp(redirecting_reason_types[index].name, data)) {
01215          return redirecting_reason_types[index].value;
01216       }
01217    }
01218 
01219    return -1;
01220 }
01221 
01222 const char *ast_redirecting_reason_describe(int data)
01223 {
01224    int index;
01225 
01226    for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
01227       if (redirecting_reason_types[index].value == data) {
01228          return redirecting_reason_types[index].description;
01229       }
01230    }
01231 
01232    return "not-known";
01233 }
01234 
01235 const char *ast_redirecting_reason_name(int data)
01236 {
01237    int index;
01238 
01239    for (index = 0; index < ARRAY_LEN(redirecting_reason_types); ++index) {
01240       if (redirecting_reason_types[index].value == data) {
01241          return redirecting_reason_types[index].name;
01242       }
01243    }
01244 
01245    return "not-known";
01246 }
01247 
01248 /*! \brief Translation table for connected line update source settings */
01249 static const struct ast_value_translation connected_line_source_types[] = {
01250 /* *INDENT-OFF* */
01251    { AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN,           "unknown",           "Unknown" },
01252    { AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER,            "answer",            "Normal Call Answering" },
01253    { AST_CONNECTED_LINE_UPDATE_SOURCE_DIVERSION,         "diversion",         "Call Diversion (Deprecated, use REDIRECTING)" },
01254    { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER,          "transfer_active",   "Call Transfer(Active)" },
01255    { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER,          "transfer",          "Call Transfer(Active)" },/* Old name must come after new name. */
01256    { AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING, "transfer_alerting", "Call Transfer(Alerting)" }
01257 /* *INDENT-ON* */
01258 };
01259 
01260 int ast_connected_line_source_parse(const char *data)
01261 {
01262    int index;
01263 
01264    for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
01265       if (!strcasecmp(connected_line_source_types[index].name, data)) {
01266          return connected_line_source_types[index].value;
01267       }
01268    }
01269 
01270    return -1;
01271 }
01272 
01273 const char *ast_connected_line_source_describe(int data)
01274 {
01275    int index;
01276 
01277    for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
01278       if (connected_line_source_types[index].value == data) {
01279          return connected_line_source_types[index].description;
01280       }
01281    }
01282 
01283    return "not-known";
01284 }
01285 
01286 const char *ast_connected_line_source_name(int data)
01287 {
01288    int index;
01289 
01290    for (index = 0; index < ARRAY_LEN(connected_line_source_types); ++index) {
01291       if (connected_line_source_types[index].value == data) {
01292          return connected_line_source_types[index].name;
01293       }
01294    }
01295 
01296    return "not-known";
01297 }
01298 
01299 /*! \brief Translation table for ast_party_name char-set settings */
01300 static const struct ast_value_translation party_name_charset_tbl[] = {
01301 /* *INDENT-OFF* */
01302    { AST_PARTY_CHAR_SET_UNKNOWN,               "unknown",      "Unknown" },
01303    { AST_PARTY_CHAR_SET_ISO8859_1,             "iso8859-1",    "ISO8859-1" },
01304    { AST_PARTY_CHAR_SET_WITHDRAWN,             "withdrawn",    "Withdrawn" },
01305    { AST_PARTY_CHAR_SET_ISO8859_2,             "iso8859-2",    "ISO8859-2" },
01306    { AST_PARTY_CHAR_SET_ISO8859_3,             "iso8859-3",    "ISO8859-3" },
01307    { AST_PARTY_CHAR_SET_ISO8859_4,             "iso8859-4",    "ISO8859-4" },
01308    { AST_PARTY_CHAR_SET_ISO8859_5,             "iso8859-5",    "ISO8859-5" },
01309    { AST_PARTY_CHAR_SET_ISO8859_7,             "iso8859-7",    "ISO8859-7" },
01310    { AST_PARTY_CHAR_SET_ISO10646_BMPSTRING,    "bmp",          "ISO10646 Bmp String" },
01311    { AST_PARTY_CHAR_SET_ISO10646_UTF_8STRING,  "utf8",         "ISO10646 UTF-8 String" },
01312 /* *INDENT-ON* */
01313 };
01314 
01315 int ast_party_name_charset_parse(const char *data)
01316 {
01317    int index;
01318 
01319    for (index = 0; index < ARRAY_LEN(party_name_charset_tbl); ++index) {
01320       if (!strcasecmp(party_name_charset_tbl[index].name, data)) {
01321          return party_name_charset_tbl[index].value;
01322       }
01323    }
01324 
01325    return -1;
01326 }
01327 
01328 const char *ast_party_name_charset_describe(int data)
01329 {
01330    int index;
01331 
01332    for (index = 0; index < ARRAY_LEN(party_name_charset_tbl); ++index) {
01333       if (party_name_charset_tbl[index].value == data) {
01334          return party_name_charset_tbl[index].description;
01335       }
01336    }
01337 
01338    return "not-known";
01339 }
01340 
01341 const char *ast_party_name_charset_str(int data)
01342 {
01343    int index;
01344 
01345    for (index = 0; index < ARRAY_LEN(party_name_charset_tbl); ++index) {
01346       if (party_name_charset_tbl[index].value == data) {
01347          return party_name_charset_tbl[index].name;
01348       }
01349    }
01350 
01351    return "not-known";
01352 }

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