move extern declaration for this option to a header file where it belongs
[asterisk-bristuff.git] / main / callerid.c
blobf7745bd49ae9890f53d08370ef05cc60c3b79ea4
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 /*! \file
21 * \brief CallerID Generation support
23 * \author Mark Spencer <markster@digium.com>
26 #include "asterisk.h"
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include <time.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <math.h>
36 #include <ctype.h>
38 #include "asterisk/ulaw.h"
39 #include "asterisk/alaw.h"
40 #include "asterisk/frame.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/callerid.h"
43 #include "asterisk/logger.h"
44 #include "asterisk/fskmodem.h"
45 #include "asterisk/options.h"
46 #include "asterisk/utils.h"
48 struct callerid_state {
49 fsk_data fskd;
50 char rawdata[256];
51 short oldstuff[160];
52 int oldlen;
53 int pos;
54 int type;
55 int cksum;
56 char name[64];
57 char number[64];
58 int flags;
59 int sawflag;
60 int len;
62 int skipflag;
63 unsigned short crc;
67 float cid_dr[4], cid_di[4];
68 float clidsb = 8000.0 / 1200.0;
69 float sasdr, sasdi;
70 float casdr1, casdi1, casdr2, casdi2;
72 #define CALLERID_SPACE 2200.0 /*!< 2200 hz for "0" */
73 #define CALLERID_MARK 1200.0 /*!< 1200 hz for "1" */
74 #define SAS_FREQ 440.0
75 #define CAS_FREQ1 2130.0
76 #define CAS_FREQ2 2750.0
78 #define AST_CALLERID_UNKNOWN "<unknown>"
80 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)
82 int x;
83 float t;
84 for (x=0;x<len;x++) {
85 t = *cr1 * ddr1 - *ci1 * ddi1;
86 *ci1 = *cr1 * ddi1 + *ci1 * ddr1;
87 *cr1 = t;
88 t = 2.0 - (*cr1 * *cr1 + *ci1 * *ci1);
89 *cr1 *= t;
90 *ci1 *= t;
92 t = *cr2 * ddr2 - *ci2 * ddi2;
93 *ci2 = *cr2 * ddi2 + *ci2 * ddr2;
94 *cr2 = t;
95 t = 2.0 - (*cr2 * *cr2 + *ci2 * *ci2);
96 *cr2 *= t;
97 *ci2 *= t;
98 buf[x] = AST_LIN2X((*cr1 + *cr2) * 2048.0);
102 static inline void gen_tone(unsigned char *buf, int len, int codec, float ddr1, float ddi1, float *cr1, float *ci1)
104 int x;
105 float t;
106 for (x=0;x<len;x++) {
107 t = *cr1 * ddr1 - *ci1 * ddi1;
108 *ci1 = *cr1 * ddi1 + *ci1 * ddr1;
109 *cr1 = t;
110 t = 2.0 - (*cr1 * *cr1 + *ci1 * *ci1);
111 *cr1 *= t;
112 *ci1 *= t;
113 buf[x] = AST_LIN2X(*cr1 * 8192.0);
117 /*! \brief Initialize stuff for inverse FFT */
118 void callerid_init(void)
120 cid_dr[0] = cos(CALLERID_SPACE * 2.0 * M_PI / 8000.0);
121 cid_di[0] = sin(CALLERID_SPACE * 2.0 * M_PI / 8000.0);
122 cid_dr[1] = cos(CALLERID_MARK * 2.0 * M_PI / 8000.0);
123 cid_di[1] = sin(CALLERID_MARK * 2.0 * M_PI / 8000.0);
124 sasdr = cos(SAS_FREQ * 2.0 * M_PI / 8000.0);
125 sasdi = sin(SAS_FREQ * 2.0 * M_PI / 8000.0);
126 casdr1 = cos(CAS_FREQ1 * 2.0 * M_PI / 8000.0);
127 casdi1 = sin(CAS_FREQ1 * 2.0 * M_PI / 8000.0);
128 casdr2 = cos(CAS_FREQ2 * 2.0 * M_PI / 8000.0);
129 casdi2 = sin(CAS_FREQ2 * 2.0 * M_PI / 8000.0);
132 struct callerid_state *callerid_new(int cid_signalling)
134 struct callerid_state *cid;
136 if ((cid = ast_calloc(1, sizeof(*cid)))) {
137 cid->fskd.spb = 7.0; /* 1200 baud */
138 /* cid->fskd.hdlc = 0; */ /* Async */
139 cid->fskd.nbit = 8; /* 8 bits */
140 cid->fskd.nstop = 1.0; /* 1 stop bit */
141 /* cid->fskd.paridad = 0; */ /* No parity */
142 cid->fskd.bw = 1; /* Filter 800 Hz */
143 if (cid_signalling == 2) { /* v23 signalling */
144 cid->fskd.f_mark_idx = 4; /* 1300 Hz */
145 cid->fskd.f_space_idx = 5; /* 2100 Hz */
146 } else { /* Bell 202 signalling as default */
147 cid->fskd.f_mark_idx = 2; /* 1200 Hz */
148 cid->fskd.f_space_idx = 3; /* 2200 Hz */
150 /* cid->fskd.pcola = 0; */ /* No clue */
151 /* cid->fskd.cont = 0.0; */ /* Digital PLL reset */
152 /* cid->fskd.x0 = 0.0; */
153 /* cid->fskd.state = 0; */
154 cid->flags = CID_UNKNOWN_NAME | CID_UNKNOWN_NUMBER;
155 /* cid->pos = 0; */
158 return cid;
161 void callerid_get(struct callerid_state *cid, char **name, char **number, int *flags)
163 *flags = cid->flags;
164 if (cid->flags & (CID_UNKNOWN_NAME | CID_PRIVATE_NUMBER))
165 *name = NULL;
166 else
167 *name = cid->name;
168 if (cid->flags & (CID_UNKNOWN_NUMBER | CID_PRIVATE_NUMBER))
169 *number = NULL;
170 else
171 *number = cid->number;
174 void callerid_get_dtmf(char *cidstring, char *number, int *flags)
176 int i;
177 int code;
179 /* "Clear" the number-buffer. */
180 number[0] = 0;
182 if (strlen(cidstring) < 2) {
183 ast_log(LOG_DEBUG, "No cid detected\n");
184 *flags = CID_UNKNOWN_NUMBER;
185 return;
188 /* Detect protocol and special types */
189 if (cidstring[0] == 'B') {
190 /* Handle special codes */
191 code = atoi(&cidstring[1]);
192 if (code == 0)
193 *flags = CID_UNKNOWN_NUMBER;
194 else if (code == 10)
195 *flags = CID_PRIVATE_NUMBER;
196 else
197 ast_log(LOG_DEBUG, "Unknown DTMF code %d\n", code);
198 } else if (cidstring[0] == 'D' && cidstring[2] == '#') {
199 /* .DK special code */
200 if (cidstring[1] == '1')
201 *flags = CID_PRIVATE_NUMBER;
202 if (cidstring[1] == '2' || cidstring[1] == '3')
203 *flags = CID_UNKNOWN_NUMBER;
204 } else if (cidstring[0] == 'D' || cidstring[0] == 'A') {
205 /* "Standard" callerid */
206 for (i = 1; i < strlen(cidstring); i++ ) {
207 if (cidstring[i] == 'C' || cidstring[i] == '#')
208 break;
209 if (isdigit(cidstring[i]))
210 number[i-1] = cidstring[i];
211 else
212 ast_log(LOG_DEBUG, "Unknown CID digit '%c'\n",
213 cidstring[i]);
215 number[i-1] = 0;
216 } else if (isdigit(cidstring[0])) {
217 /* It begins with a digit, so we parse it as a number and hope
218 * for the best */
219 ast_log(LOG_WARNING, "Couldn't detect start-character. CID "
220 "parsing might be unreliable\n");
221 for (i = 0; i < strlen(cidstring); i++) {
222 if (isdigit(cidstring[i]))
223 number[i] = cidstring[i];
224 else
225 break;
227 number[i] = 0;
228 } else {
229 ast_log(LOG_DEBUG, "Unknown CID protocol, start digit '%c'\n",
230 cidstring[0]);
231 *flags = CID_UNKNOWN_NUMBER;
235 int ast_gen_cas(unsigned char *outbuf, int sendsas, int len, int codec)
237 int pos = 0;
238 int saslen=2400;
239 float cr1 = 1.0;
240 float ci1 = 0.0;
241 float cr2 = 1.0;
242 float ci2 = 0.0;
243 if (sendsas) {
244 if (len < saslen)
245 return -1;
246 gen_tone(outbuf, saslen, codec, sasdr, sasdi, &cr1, &ci1);
247 len -= saslen;
248 pos += saslen;
249 cr2 = cr1;
250 ci2 = ci1;
252 gen_tones(outbuf + pos, len, codec, casdr1, casdi1, casdr2, casdi2, &cr1, &ci1, &cr2, &ci2);
253 return 0;
256 static unsigned short calc_crc(unsigned short crc, unsigned char data)
258 unsigned int i, j, org, dst;
259 org = data;
260 dst = 0;
262 for (i=0; i < CHAR_BIT; i++) {
263 org <<= 1;
264 dst >>= 1;
265 if (org & 0x100) {
266 dst |= 0x80;
269 data = (unsigned char)dst;
270 crc ^= (unsigned int)data << (16 - CHAR_BIT);
271 for ( j=0; j<CHAR_BIT; j++ ) {
272 if ( crc & 0x8000U )
273 crc = (crc << 1) ^ 0x1021U ;
274 else
275 crc <<= 1 ;
277 return crc;
280 int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, int codec)
282 int mylen = len;
283 int olen;
284 int b = 'X';
285 int b2 ;
286 int res;
287 int x;
288 short *buf;
289 short *obuf;
291 if (!(buf = ast_calloc(1, 2 * len + cid->oldlen))) {
292 return -1;
295 obuf = buf;
296 memcpy(buf, cid->oldstuff, cid->oldlen);
297 mylen += cid->oldlen/2;
299 for (x=0;x<len;x++)
300 buf[x+cid->oldlen/2] = AST_XLAW(ubuf[x]);
302 while (mylen >= 160) {
303 b = b2 = 0;
304 olen = mylen;
305 res = fsk_serie(&cid->fskd, buf, &mylen, &b);
307 if (mylen < 0) {
308 ast_log(LOG_ERROR, "fsk_serie made mylen < 0 (%d)\n", mylen);
309 free(obuf);
310 return -1;
313 buf += (olen - mylen);
315 if (res < 0) {
316 ast_log(LOG_NOTICE, "fsk_serie failed\n");
317 free(obuf);
318 return -1;
321 if (res == 1) {
323 b2 = b ;
324 b = b & 0x7f ;
326 /* crc checksum calculation */
327 if ( cid->sawflag > 1 ) {
328 cid->crc = calc_crc(cid->crc, (unsigned char)b2);
331 /* Ignore invalid bytes */
332 if (b > 0xff) {
333 continue;
336 /* skip DLE if needed */
337 if ( cid->sawflag > 0 ) {
338 if ( cid->sawflag != 5 && cid->skipflag == 0 && b == 0x10 ) {
339 cid->skipflag = 1 ;
340 continue ;
343 if ( cid->skipflag == 1 ) {
344 cid->skipflag = 0 ;
347 /* caller id retrieval */
348 switch(cid->sawflag) {
349 case 0: /* DLE */
350 if (b == 0x10) {
351 cid->sawflag = 1;
352 cid->skipflag = 0;
353 cid->crc = 0;
355 break;
356 case 1: /* SOH */
357 if (b == 0x01) {
358 cid->sawflag = 2;
360 break ;
361 case 2: /* HEADER */
362 if (b == 0x07) {
363 cid->sawflag = 3;
365 break;
366 case 3: /* STX */
367 if (b == 0x02) {
368 cid->sawflag = 4;
370 break;
371 case 4: /* SERVICE TYPE */
372 if (b == 0x40) {
373 cid->sawflag = 5;
375 break;
376 case 5: /* Frame Length */
377 cid->sawflag = 6;
378 break;
379 case 6: /* NUMBER TYPE */
380 cid->sawflag = 7;
381 cid->pos = 0;
382 cid->rawdata[cid->pos++] = b;
383 break;
384 case 7: /* NUMBER LENGTH */
385 cid->sawflag = 8;
386 cid->len = b;
387 if ( (cid->len+2) >= sizeof( cid->rawdata ) ) {
388 ast_log(LOG_WARNING, "too long caller id string\n" ) ;
389 free(obuf);
390 return -1;
392 cid->rawdata[cid->pos++] = b;
393 break;
394 case 8: /* Retrieve message */
395 cid->rawdata[cid->pos++] = b;
396 cid->len--;
397 if (cid->len<=0) {
398 cid->rawdata[cid->pos] = '\0';
399 cid->sawflag = 9;
401 break;
402 case 9: /* ETX */
403 cid->sawflag = 10;
404 break;
405 case 10: /* CRC Checksum 1 */
406 cid->sawflag = 11;
407 break;
408 case 11: /* CRC Checksum 2 */
409 cid->sawflag = 12;
410 if ( cid->crc != 0 ) {
411 ast_log(LOG_WARNING, "crc checksum error\n" ) ;
412 free(obuf);
413 return -1;
415 /* extract caller id data */
416 for (x=0; x<cid->pos; ) {
417 switch (cid->rawdata[x++]) {
418 case 0x02: /* caller id number */
419 cid->number[0] = '\0';
420 cid->name[0] = '\0';
421 cid->flags = 0;
422 res = cid->rawdata[x++];
423 ast_copy_string(cid->number, &cid->rawdata[x], res+1 );
424 x += res;
425 break;
426 case 0x21: /* additional information */
427 /* length */
428 x++;
429 /* number type */
430 switch (cid->rawdata[x]) {
431 case 0x00: /* unknown */
432 case 0x01: /* international number */
433 case 0x02: /* domestic number */
434 case 0x03: /* network */
435 case 0x04: /* local call */
436 case 0x06: /* short dial number */
437 case 0x07: /* reserved */
438 default: /* reserved */
439 if (option_debug > 1)
440 ast_log(LOG_DEBUG, "cid info:#1=%X\n", cid->rawdata[x]);
441 break ;
443 x++;
444 /* numbering plan octed 4 */
445 x++;
446 /* numbering plan octed 5 */
447 switch (cid->rawdata[x]) {
448 case 0x00: /* unknown */
449 case 0x01: /* recommendation E.164 ISDN */
450 case 0x03: /* recommendation X.121 */
451 case 0x04: /* telex dial plan */
452 case 0x08: /* domestic dial plan */
453 case 0x09: /* private dial plan */
454 case 0x05: /* reserved */
455 default: /* reserved */
456 if (option_debug > 1)
457 ast_log(LOG_DEBUG, "cid info:#2=%X\n", cid->rawdata[x]);
458 break ;
460 x++;
461 break ;
462 case 0x04: /* no callerid reason */
463 /* length */
464 x++;
465 /* no callerid reason code */
466 switch (cid->rawdata[x]) {
467 case 'P': /* caller id denied by user */
468 case 'O': /* service not available */
469 case 'C': /* pay phone */
470 case 'S': /* service congested */
471 cid->flags |= CID_UNKNOWN_NUMBER;
472 if (option_debug > 1)
473 ast_log(LOG_DEBUG, "no cid reason:%c\n",cid->rawdata[x]);
474 break ;
476 x++;
477 break ;
478 case 0x09: /* dialed number */
479 /* length */
480 res = cid->rawdata[x++];
481 /* dialed number */
482 x += res;
483 break ;
484 case 0x22: /* dialed number additional information */
485 /* length */
486 x++;
487 /* number type */
488 switch (cid->rawdata[x]) {
489 case 0x00: /* unknown */
490 case 0x01: /* international number */
491 case 0x02: /* domestic number */
492 case 0x03: /* network */
493 case 0x04: /* local call */
494 case 0x06: /* short dial number */
495 case 0x07: /* reserved */
496 default: /* reserved */
497 if (option_debug > 1)
498 ast_log(LOG_NOTICE, "did info:#1=%X\n", cid->rawdata[x]);
499 break ;
501 x++;
502 /* numbering plan octed 4 */
503 x++;
504 /* numbering plan octed 5 */
505 switch (cid->rawdata[x]) {
506 case 0x00: /* unknown */
507 case 0x01: /* recommendation E.164 ISDN */
508 case 0x03: /* recommendation X.121 */
509 case 0x04: /* telex dial plan */
510 case 0x08: /* domestic dial plan */
511 case 0x09: /* private dial plan */
512 case 0x05: /* reserved */
513 default: /* reserved */
514 if (option_debug > 1)
515 ast_log(LOG_DEBUG, "did info:#2=%X\n", cid->rawdata[x]);
516 break ;
518 x++;
519 break ;
522 free(obuf);
523 return 1;
524 break;
525 default:
526 ast_log(LOG_ERROR, "invalid value in sawflag %d\n", cid->sawflag);
530 if (mylen) {
531 memcpy(cid->oldstuff, buf, mylen * 2);
532 cid->oldlen = mylen * 2;
533 } else
534 cid->oldlen = 0;
535 free(obuf);
536 return 0;
540 int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int codec)
542 int mylen = len;
543 int olen;
544 int b = 'X';
545 int res;
546 int x;
547 short *buf;
548 short *obuf;
550 if (!(buf = ast_calloc(1, 2 * len + cid->oldlen))) {
551 return -1;
554 obuf = buf;
555 memcpy(buf, cid->oldstuff, cid->oldlen);
556 mylen += cid->oldlen/2;
558 for (x=0;x<len;x++)
559 buf[x+cid->oldlen/2] = AST_XLAW(ubuf[x]);
560 while(mylen >= 160) {
561 olen = mylen;
562 res = fsk_serie(&cid->fskd, buf, &mylen, &b);
563 if (mylen < 0) {
564 ast_log(LOG_ERROR, "fsk_serie made mylen < 0 (%d)\n", mylen);
565 free(obuf);
566 return -1;
568 buf += (olen - mylen);
569 if (res < 0) {
570 ast_log(LOG_NOTICE, "fsk_serie failed\n");
571 free(obuf);
572 return -1;
574 if (res == 1) {
575 /* Ignore invalid bytes */
576 if (b > 0xff)
577 continue;
578 switch(cid->sawflag) {
579 case 0: /* Look for flag */
580 if (b == 'U')
581 cid->sawflag = 2;
582 break;
583 case 2: /* Get lead-in */
584 if ((b == 0x04) || (b == 0x80)) {
585 cid->type = b;
586 cid->sawflag = 3;
587 cid->cksum = b;
589 break;
590 case 3: /* Get length */
591 /* Not a lead in. We're ready */
592 cid->sawflag = 4;
593 cid->len = b;
594 cid->pos = 0;
595 cid->cksum += b;
596 break;
597 case 4: /* Retrieve message */
598 if (cid->pos >= 128) {
599 ast_log(LOG_WARNING, "Caller ID too long???\n");
600 free(obuf);
601 return -1;
603 cid->rawdata[cid->pos++] = b;
604 cid->len--;
605 cid->cksum += b;
606 if (!cid->len) {
607 cid->rawdata[cid->pos] = '\0';
608 cid->sawflag = 5;
610 break;
611 case 5: /* Check checksum */
612 if (b != (256 - (cid->cksum & 0xff))) {
613 ast_log(LOG_NOTICE, "Caller*ID failed checksum\n");
614 /* Try again */
615 cid->sawflag = 0;
616 break;
619 cid->number[0] = '\0';
620 cid->name[0] = '\0';
621 /* If we get this far we're fine. */
622 if (cid->type == 0x80) {
623 /* MDMF */
624 /* Go through each element and process */
625 for (x=0;x< cid->pos;) {
626 switch(cid->rawdata[x++]) {
627 case 1:
628 /* Date */
629 break;
630 case 2: /* Number */
631 case 3: /* Number (for Zebble) */
632 case 4: /* Number */
633 res = cid->rawdata[x];
634 if (res > 32) {
635 ast_log(LOG_NOTICE, "Truncating long caller ID number from %d bytes to 32\n", cid->rawdata[x]);
636 res = 32;
638 if (ast_strlen_zero(cid->number)) {
639 memcpy(cid->number, cid->rawdata + x + 1, res);
640 /* Null terminate */
641 cid->number[res] = '\0';
643 break;
644 case 6: /* Stentor Call Qualifier (ie. Long Distance call) */
645 break;
646 case 7: /* Name */
647 case 8: /* Name */
648 res = cid->rawdata[x];
649 if (res > 32) {
650 ast_log(LOG_NOTICE, "Truncating long caller ID name from %d bytes to 32\n", cid->rawdata[x]);
651 res = 32;
653 memcpy(cid->name, cid->rawdata + x + 1, res);
654 cid->name[res] = '\0';
655 break;
656 case 17: /* UK: Call type, 1=Voice Call, 2=Ringback when free, 129=Message waiting */
657 case 19: /* UK: Network message system status (Number of messages waiting) */
658 case 22: /* Something French */
659 break;
660 default:
661 ast_log(LOG_NOTICE, "Unknown IE %d\n", cid->rawdata[x-1]);
663 x += cid->rawdata[x];
664 x++;
666 } else {
667 /* SDMF */
668 ast_copy_string(cid->number, cid->rawdata + 8, sizeof(cid->number));
670 /* Update flags */
671 cid->flags = 0;
672 if (!strcmp(cid->number, "P")) {
673 strcpy(cid->number, "");
674 cid->flags |= CID_PRIVATE_NUMBER;
675 } else if (!strcmp(cid->number, "O") || ast_strlen_zero(cid->number)) {
676 strcpy(cid->number, "");
677 cid->flags |= CID_UNKNOWN_NUMBER;
679 if (!strcmp(cid->name, "P")) {
680 strcpy(cid->name, "");
681 cid->flags |= CID_PRIVATE_NAME;
682 } else if (!strcmp(cid->name, "O") || ast_strlen_zero(cid->name)) {
683 strcpy(cid->name, "");
684 cid->flags |= CID_UNKNOWN_NAME;
686 free(obuf);
687 return 1;
688 break;
689 default:
690 ast_log(LOG_ERROR, "Dunno what to do with a digit in sawflag %d\n", cid->sawflag);
694 if (mylen) {
695 memcpy(cid->oldstuff, buf, mylen * 2);
696 cid->oldlen = mylen * 2;
697 } else
698 cid->oldlen = 0;
699 free(obuf);
700 return 0;
703 void callerid_free(struct callerid_state *cid)
705 free(cid);
708 static int callerid_genmsg(char *msg, int size, const char *number, const char *name, int flags)
710 time_t t;
711 struct tm tm;
712 char *ptr;
713 int res;
714 int i,x;
715 /* Get the time */
716 time(&t);
717 localtime_r(&t,&tm);
719 ptr = msg;
721 /* Format time and message header */
722 res = snprintf(ptr, size, "\001\010%02d%02d%02d%02d", tm.tm_mon + 1,
723 tm.tm_mday, tm.tm_hour, tm.tm_min);
724 size -= res;
725 ptr += res;
726 if (ast_strlen_zero(number) || (flags & CID_UNKNOWN_NUMBER)) {
727 /* Indicate number not known */
728 res = snprintf(ptr, size, "\004\001O");
729 size -= res;
730 ptr += res;
731 } else if (flags & CID_PRIVATE_NUMBER) {
732 /* Indicate number is private */
733 res = snprintf(ptr, size, "\004\001P");
734 size -= res;
735 ptr += res;
736 } else {
737 /* Send up to 16 digits of number MAX */
738 i = strlen(number);
739 if (i > 16) i = 16;
740 res = snprintf(ptr, size, "\002%c", i);
741 size -= res;
742 ptr += res;
743 for (x = 0; x < i; x++)
744 ptr[x] = number[x];
745 ptr[i] = '\0';
746 ptr += i;
747 size -= i;
750 if (ast_strlen_zero(name) || (flags & CID_UNKNOWN_NAME)) {
751 /* Indicate name not known */
752 res = snprintf(ptr, size, "\010\001O");
753 size -= res;
754 ptr += res;
755 } else if (flags & CID_PRIVATE_NAME) {
756 /* Indicate name is private */
757 res = snprintf(ptr, size, "\010\001P");
758 size -= res;
759 ptr += res;
760 } else {
761 /* Send up to 16 digits of name MAX */
762 i = strlen(name);
763 if (i > 16) i = 16;
764 res = snprintf(ptr, size, "\007%c", i);
765 size -= res;
766 ptr += res;
767 for (x=0;x<i;x++)
768 ptr[x] = name[x];
769 ptr[i] = '\0';
770 ptr += i;
771 size -= i;
773 return (ptr - msg);
777 int vmwi_generate(unsigned char *buf, int active, int mdmf, int codec)
779 unsigned char msg[256];
780 int len=0;
781 int sum;
782 int x;
783 int bytes = 0;
784 float cr = 1.0;
785 float ci = 0.0;
786 float scont = 0.0;
787 if (mdmf) {
788 /* MDMF Message waiting */
789 msg[len++] = 0x82;
790 /* Length is 3 */
791 msg[len++] = 3;
792 /* IE is "Message Waiting Parameter" */
793 msg[len++] = 0xb;
794 /* Length of IE is one */
795 msg[len++] = 1;
796 /* Active or not */
797 if (active)
798 msg[len++] = 0xff;
799 else
800 msg[len++] = 0x00;
801 } else {
802 /* SDMF Message waiting */
803 msg[len++] = 0x6;
804 /* Length is 3 */
805 msg[len++] = 3;
806 if (active) {
807 msg[len++] = 0x42;
808 msg[len++] = 0x42;
809 msg[len++] = 0x42;
810 } else {
811 msg[len++] = 0x6f;
812 msg[len++] = 0x6f;
813 msg[len++] = 0x6f;
816 sum = 0;
817 for (x=0; x<len; x++)
818 sum += msg[x];
819 sum = (256 - (sum & 255));
820 msg[len++] = sum;
821 /* Wait a half a second */
822 for (x=0; x<4000; x++)
823 PUT_BYTE(0x7f);
824 /* Transmit 30 0x55's (looks like a square wave) for channel seizure */
825 for (x=0; x<30; x++)
826 PUT_CLID(0x55);
827 /* Send 170ms of callerid marks */
828 for (x=0; x<170; x++)
829 PUT_CLID_MARKMS;
830 for (x=0; x<len; x++) {
831 PUT_CLID(msg[x]);
833 /* Send 50 more ms of marks */
834 for (x=0; x<50; x++)
835 PUT_CLID_MARKMS;
836 return bytes;
839 int callerid_generate(unsigned char *buf, const char *number, const char *name, int flags, int callwaiting, int codec)
841 int bytes=0;
842 int x, sum;
843 int len;
845 /* Initial carriers (real/imaginary) */
846 float cr = 1.0;
847 float ci = 0.0;
848 float scont = 0.0;
849 char msg[256];
850 len = callerid_genmsg(msg, sizeof(msg), number, name, flags);
851 if (!callwaiting) {
852 /* Wait a half a second */
853 for (x=0; x<4000; x++)
854 PUT_BYTE(0x7f);
855 /* Transmit 30 0x55's (looks like a square wave) for channel seizure */
856 for (x=0; x<30; x++)
857 PUT_CLID(0x55);
859 /* Send 150ms of callerid marks */
860 for (x=0; x<150; x++)
861 PUT_CLID_MARKMS;
862 /* Send 0x80 indicating MDMF format */
863 PUT_CLID(0x80);
864 /* Put length of whole message */
865 PUT_CLID(len);
866 sum = 0x80 + strlen(msg);
867 /* Put each character of message and update checksum */
868 for (x=0; x<len; x++) {
869 PUT_CLID(msg[x]);
870 sum += msg[x];
872 /* Send 2's compliment of sum */
873 PUT_CLID(256 - (sum & 255));
875 /* Send 50 more ms of marks */
876 for (x=0; x<50; x++)
877 PUT_CLID_MARKMS;
879 return bytes;
882 /*! \brief Clean up phone string
883 * remove '(', ' ', ')', non-trailing '.', and '-' not in square brackets.
884 * Basically, remove anything that could be invalid in a pattern.
886 void ast_shrink_phone_number(char *n)
888 int x, y=0;
889 int bracketed = 0;
891 for (x=0; n[x]; x++) {
892 switch(n[x]) {
893 case '[':
894 bracketed++;
895 n[y++] = n[x];
896 break;
897 case ']':
898 bracketed--;
899 n[y++] = n[x];
900 break;
901 case '-':
902 if (bracketed)
903 n[y++] = n[x];
904 break;
905 case '.':
906 if (!n[x+1])
907 n[y++] = n[x];
908 break;
909 default:
910 if (!strchr("( )", n[x]))
911 n[y++] = n[x];
914 n[y] = '\0';
917 /*! \brief Checks if phone number consists of valid characters
918 \param exten String that needs to be checked
919 \param valid Valid characters in string
920 \return 1 if valid string, 0 if string contains invalid characters
922 static int ast_is_valid_string(const char *exten, const char *valid)
924 int x;
926 if (ast_strlen_zero(exten))
927 return 0;
928 for (x=0; exten[x]; x++)
929 if (!strchr(valid, exten[x]))
930 return 0;
931 return 1;
934 /*! \brief checks if string consists only of digits and * \# and +
935 \return 1 if string is valid AST phone number
936 \return 0 if not
938 int ast_isphonenumber(const char *n)
940 return ast_is_valid_string(n, "0123456789*#+");
943 /*! \brief checks if string consists only of digits and ( ) - * \# and +
944 Pre-qualifies the string for ast_shrink_phone_number()
945 \return 1 if string is valid AST shrinkable phone number
946 \return 0 if not
948 int ast_is_shrinkable_phonenumber(const char *exten)
950 return ast_is_valid_string(exten, "0123456789*#+()-.");
953 /*! \brief parse string for caller id information
954 \return always returns 0, as the code always returns something.
955 XXX note that 'name' is not parsed consistently e.g. we have
957 input location name
958 " foo bar " <123> 123 ' foo bar ' (with spaces around)
959 " foo bar " NULL 'foo bar' (without spaces around)
960 " foo bar <123>" 123 '" foo bar'
961 The parsing of leading and trailing space/quotes should be more consistent.
963 int ast_callerid_parse(char *instr, char **name, char **location)
965 char *ns, *ne, *ls, *le;
967 /* Try "name" <location> format or name <location> format */
968 if ((ls = strchr(instr, '<')) && (le = strchr(ls, '>'))) {
969 *ls = *le = '\0'; /* location found, trim off the brackets */
970 *location = ls + 1; /* and this is the result */
971 if ((ns = strchr(instr, '"')) && (ne = strchr(ns + 1, '"'))) {
972 *ns = *ne = '\0'; /* trim off the quotes */
973 *name = ns + 1; /* and this is the name */
974 } else { /* no quotes, trim off leading and trailing spaces */
975 *name = ast_skip_blanks(instr);
976 ast_trim_blanks(*name);
978 } else { /* no valid brackets */
979 char tmp[256];
981 ast_copy_string(tmp, instr, sizeof(tmp));
982 ast_shrink_phone_number(tmp);
983 if (ast_isphonenumber(tmp)) { /* Assume it's just a location */
984 *name = NULL;
985 strcpy(instr, tmp); /* safe, because tmp will always be the same size or smaller than instr */
986 *location = instr;
987 } else { /* Assume it's just a name. */
988 *location = NULL;
989 if ((ns = strchr(instr, '"')) && (ne = strchr(ns + 1, '"'))) {
990 *ns = *ne = '\0'; /* trim off the quotes */
991 *name = ns + 1; /* and this is the name */
992 } else { /* no quotes, trim off leading and trailing spaces */
993 *name = ast_skip_blanks(instr);
994 ast_trim_blanks(*name);
998 return 0;
1001 static int __ast_callerid_generate(unsigned char *buf, const char *name, const char *number, int callwaiting, int codec)
1003 if (ast_strlen_zero(name))
1004 name = NULL;
1005 if (ast_strlen_zero(number))
1006 number = NULL;
1007 return callerid_generate(buf, number, name, 0, callwaiting, codec);
1010 int ast_callerid_generate(unsigned char *buf, const char *name, const char *number, int codec)
1012 return __ast_callerid_generate(buf, name, number, 0, codec);
1015 int ast_callerid_callwaiting_generate(unsigned char *buf, const char *name, const char *number, int codec)
1017 return __ast_callerid_generate(buf, name, number, 1, codec);
1020 char *ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
1022 if (!unknown)
1023 unknown = "<unknown>";
1024 if (name && num)
1025 snprintf(buf, bufsiz, "\"%s\" <%s>", name, num);
1026 else if (name)
1027 ast_copy_string(buf, name, bufsiz);
1028 else if (num)
1029 ast_copy_string(buf, num, bufsiz);
1030 else
1031 ast_copy_string(buf, unknown, bufsiz);
1032 return buf;
1035 int ast_callerid_split(const char *buf, char *name, int namelen, char *num, int numlen)
1037 char *tmp;
1038 char *l = NULL, *n = NULL;
1040 tmp = ast_strdupa(buf);
1041 ast_callerid_parse(tmp, &n, &l);
1042 if (n)
1043 ast_copy_string(name, n, namelen);
1044 else
1045 name[0] = '\0';
1046 if (l) {
1047 ast_shrink_phone_number(l);
1048 ast_copy_string(num, l, numlen);
1049 } else
1050 num[0] = '\0';
1051 return 0;
1054 /*! \brief Translation table for Caller ID Presentation settings */
1055 static struct {
1056 int val;
1057 char *name;
1058 char *description;
1059 } pres_types[] = {
1060 { AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened", "Presentation Allowed, Not Screened"},
1061 { AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen", "Presentation Allowed, Passed Screen"},
1062 { AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen", "Presentation Allowed, Failed Screen"},
1063 { AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed", "Presentation Allowed, Network Number"},
1064 { AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED, "prohib_not_screened", "Presentation Prohibited, Not Screened"},
1065 { AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen", "Presentation Prohibited, Passed Screen"},
1066 { AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen", "Presentation Prohibited, Failed Screen"},
1067 { AST_PRES_PROHIB_NETWORK_NUMBER, "prohib", "Presentation Prohibited, Network Number"},
1068 { AST_PRES_NUMBER_NOT_AVAILABLE, "unavailable", "Number Unavailable"},
1071 /*! \brief Convert caller ID text code to value
1072 used in config file parsing
1073 \param data text string
1074 \return value AST_PRES_ from callerid.h
1076 int ast_parse_caller_presentation(const char *data)
1078 int i;
1080 for (i = 0; i < ((sizeof(pres_types) / sizeof(pres_types[0]))); i++) {
1081 if (!strcasecmp(pres_types[i].name, data))
1082 return pres_types[i].val;
1085 return -1;
1088 /*! \brief Convert caller ID pres value to explanatory string
1089 \param data value (see callerid.h AST_PRES_ )
1090 \return string for human presentation
1092 const char *ast_describe_caller_presentation(int data)
1094 int i;
1096 for (i = 0; i < ((sizeof(pres_types) / sizeof(pres_types[0]))); i++) {
1097 if (pres_types[i].val == data)
1098 return pres_types[i].description;
1101 return "unknown";