Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

callerid.c

Go to the documentation of this file.
00001 /* 00002 * Asterisk -- A telephony toolkit for Linux. 00003 * 00004 * CallerID Generation support 00005 * 00006 * Copyright (C) 2001, Linux Support Services, Inc. 00007 * 00008 * Mark Spencer <markster@linux-support.net> 00009 * 00010 * This program is free software, distributed under the terms of 00011 * the GNU General Public License. 00012 * 00013 * Includes code and algorithms from the Zapata library. 00014 * 00015 */ 00016 00017 #include <time.h> 00018 #include <string.h> 00019 #include <stdio.h> 00020 #include <stdlib.h> 00021 #include <unistd.h> 00022 #include <math.h> 00023 #include <asterisk/ulaw.h> 00024 #include <asterisk/alaw.h> 00025 #include <asterisk/frame.h> 00026 #include <asterisk/callerid.h> 00027 #include <asterisk/logger.h> 00028 #include <asterisk/fskmodem.h> 00029 #include <asterisk/utils.h> 00030 00031 struct callerid_state { 00032 fsk_data fskd; 00033 char rawdata[256]; 00034 short oldstuff[160]; 00035 int oldlen; 00036 int pos; 00037 int type; 00038 int cksum; 00039 char name[64]; 00040 char number[64]; 00041 int flags; 00042 int sawflag; 00043 int len; 00044 }; 00045 00046 00047 float cid_dr[4], cid_di[4]; 00048 float clidsb = 8000.0 / 1200.0; 00049 float sasdr, sasdi; 00050 float casdr1, casdi1, casdr2, casdi2; 00051 00052 #define CALLERID_SPACE 2200.0 /* 2200 hz for "0" */ 00053 #define CALLERID_MARK 1200.0 /* 1200 hz for "1" */ 00054 #define SAS_FREQ 440.0 00055 #define CAS_FREQ1 2130.0 00056 #define CAS_FREQ2 2750.0 00057 00058 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) 00059 { 00060 int x; 00061 float t; 00062 for (x=0;x<len;x++) { 00063 t = *cr1 * ddr1 - *ci1 * ddi1; 00064 *ci1 = *cr1 * ddi1 + *ci1 * ddr1; 00065 *cr1 = t; 00066 t = 2.0 - (*cr1 * *cr1 + *ci1 * *ci1); 00067 *cr1 *= t; 00068 *ci1 *= t; 00069 00070 t = *cr2 * ddr2 - *ci2 * ddi2; 00071 *ci2 = *cr2 * ddi2 + *ci2 * ddr2; 00072 *cr2 = t; 00073 t = 2.0 - (*cr2 * *cr2 + *ci2 * *ci2); 00074 *cr2 *= t; 00075 *ci2 *= t; 00076 buf[x] = AST_LIN2X((*cr1 + *cr2) * 8192.0); 00077 } 00078 } 00079 00080 static inline void gen_tone(unsigned char *buf, int len, int codec, float ddr1, float ddi1, float *cr1, float *ci1) 00081 { 00082 int x; 00083 float t; 00084 for (x=0;x<len;x++) { 00085 t = *cr1 * ddr1 - *ci1 * ddi1; 00086 *ci1 = *cr1 * ddi1 + *ci1 * ddr1; 00087 *cr1 = t; 00088 t = 2.0 - (*cr1 * *cr1 + *ci1 * *ci1); 00089 *cr1 *= t; 00090 *ci1 *= t; 00091 buf[x] = AST_LIN2X(*cr1 * 8192.0); 00092 } 00093 } 00094 00095 void callerid_init(void) 00096 { 00097 /* Initialize stuff for inverse FFT */ 00098 cid_dr[0] = cos(CALLERID_SPACE * 2.0 * M_PI / 8000.0); 00099 cid_di[0] = sin(CALLERID_SPACE * 2.0 * M_PI / 8000.0); 00100 cid_dr[1] = cos(CALLERID_MARK * 2.0 * M_PI / 8000.0); 00101 cid_di[1] = sin(CALLERID_MARK * 2.0 * M_PI / 8000.0); 00102 sasdr = cos(SAS_FREQ * 2.0 * M_PI / 8000.0); 00103 sasdi = sin(SAS_FREQ * 2.0 * M_PI / 8000.0); 00104 casdr1 = cos(CAS_FREQ1 * 2.0 * M_PI / 8000.0); 00105 casdi1 = sin(CAS_FREQ1 * 2.0 * M_PI / 8000.0); 00106 casdr2 = cos(CAS_FREQ2 * 2.0 * M_PI / 8000.0); 00107 casdi2 = sin(CAS_FREQ2 * 2.0 * M_PI / 8000.0); 00108 } 00109 00110 struct callerid_state *callerid_new(void) 00111 { 00112 struct callerid_state *cid; 00113 cid = malloc(sizeof(struct callerid_state)); 00114 if (cid) { 00115 memset(cid, 0, sizeof(struct callerid_state)); 00116 cid->fskd.spb = 7; /* 1200 baud */ 00117 cid->fskd.hdlc = 0; /* Async */ 00118 cid->fskd.nbit = 8; /* 8 bits */ 00119 cid->fskd.nstop = 1; /* 1 stop bit */ 00120 cid->fskd.paridad = 0; /* No parity */ 00121 cid->fskd.bw=1; /* Filter 800 Hz */ 00122 cid->fskd.f_mark_idx = 2; /* 1200 Hz */ 00123 cid->fskd.f_space_idx = 3; /* 2200 Hz */ 00124 cid->fskd.pcola = 0; /* No clue */ 00125 cid->fskd.cont = 0; /* Digital PLL reset */ 00126 cid->fskd.x0 = 0.0; 00127 cid->fskd.state = 0; 00128 memset(cid->name, 0, sizeof(cid->name)); 00129 memset(cid->number, 0, sizeof(cid->number)); 00130 cid->flags = CID_UNKNOWN_NAME | CID_UNKNOWN_NUMBER; 00131 cid->pos = 0; 00132 } else 00133 ast_log(LOG_WARNING, "Out of memory\n"); 00134 return cid; 00135 } 00136 00137 void callerid_get(struct callerid_state *cid, char **name, char **number, int *flags) 00138 { 00139 *flags = cid->flags; 00140 if (cid->flags & (CID_UNKNOWN_NAME | CID_PRIVATE_NUMBER)) 00141 *name = NULL; 00142 else 00143 *name = cid->name; 00144 if (cid->flags & (CID_UNKNOWN_NUMBER | CID_PRIVATE_NUMBER)) 00145 *number = NULL; 00146 else 00147 *number = cid->number; 00148 } 00149 00150 int ast_gen_cas(unsigned char *outbuf, int sendsas, int len, int codec) 00151 { 00152 int pos = 0; 00153 int saslen=2400; 00154 float cr1 = 1.0; 00155 float ci1 = 0.0; 00156 float cr2 = 1.0; 00157 float ci2 = 0.0; 00158 if (sendsas) { 00159 if (len < saslen) 00160 return -1; 00161 gen_tone(outbuf, saslen, codec, sasdr, sasdi, &cr1, &ci1); 00162 len -= saslen; 00163 pos += saslen; 00164 cr2 = cr1; 00165 ci2 = ci1; 00166 } 00167 gen_tones(outbuf + pos, len, codec, casdr1, casdi1, casdr2, casdi2, &cr1, &ci1, &cr2, &ci2); 00168 return 0; 00169 } 00170 00171 int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int codec) 00172 { 00173 int mylen = len; 00174 int olen; 00175 int b = 'X'; 00176 int res; 00177 int x; 00178 short *buf = malloc(2 * len + cid->oldlen); 00179 short *obuf = buf; 00180 if (!buf) { 00181 ast_log(LOG_WARNING, "Out of memory\n"); 00182 return -1; 00183 } 00184 memset(buf, 0, 2 * len + cid->oldlen); 00185 memcpy(buf, cid->oldstuff, cid->oldlen); 00186 mylen += cid->oldlen/2; 00187 for (x=0;x<len;x++) 00188 buf[x+cid->oldlen/2] = AST_XLAW(ubuf[x]); 00189 while(mylen >= 80) { 00190 olen = mylen; 00191 res = fsk_serie(&cid->fskd, buf, &mylen, &b); 00192 if (mylen < 0) { 00193 ast_log(LOG_ERROR, "fsk_serie made mylen < 0 (%d)\n", mylen); 00194 return -1; 00195 } 00196 buf += (olen - mylen); 00197 if (res < 0) { 00198 ast_log(LOG_NOTICE, "fsk_serie failed\n"); 00199 return -1; 00200 } 00201 if (res == 1) { 00202 /* Ignore invalid bytes */ 00203 if (b > 0xff) 00204 continue; 00205 switch(cid->sawflag) { 00206 case 0: /* Look for flag */ 00207 if (b == 'U') 00208 cid->sawflag = 2; 00209 break; 00210 case 2: /* Get lead-in */ 00211 if ((b == 0x04) || (b == 0x80)) { 00212 cid->type = b; 00213 cid->sawflag = 3; 00214 cid->cksum = b; 00215 } 00216 break; 00217 case 3: /* Get length */ 00218 /* Not a lead in. We're ready */ 00219 cid->sawflag = 4; 00220 cid->len = b; 00221 cid->pos = 0; 00222 cid->cksum += b; 00223 break; 00224 case 4: /* Retrieve message */ 00225 if (cid->pos >= 128) { 00226 ast_log(LOG_WARNING, "Caller ID too long???\n"); 00227 return -1; 00228 } 00229 cid->rawdata[cid->pos++] = b; 00230 cid->len--; 00231 cid->cksum += b; 00232 if (!cid->len) { 00233 cid->rawdata[cid->pos] = '\0'; 00234 cid->sawflag = 5; 00235 } 00236 break; 00237 case 5: /* Check checksum */ 00238 if (b != (256 - (cid->cksum & 0xff))) { 00239 ast_log(LOG_NOTICE, "Caller*ID failed checksum\n"); 00240 /* Try again */ 00241 cid->sawflag = 0; 00242 break; 00243 } 00244 00245 strcpy(cid->number, ""); 00246 strcpy(cid->name, ""); 00247 /* If we get this far we're fine. */ 00248 if (cid->type == 0x80) { 00249 /* MDMF */ 00250 /* Go through each element and process */ 00251 for (x=0;x< cid->pos;) { 00252 switch(cid->rawdata[x++]) { 00253 case 1: 00254 /* Date */ 00255 break; 00256 case 2: /* Number */ 00257 case 3: /* Number (for Zebble) */ 00258 case 4: /* Number */ 00259 res = cid->rawdata[x]; 00260 if (res > 32) { 00261 ast_log(LOG_NOTICE, "Truncating long caller ID number from %d bytes to 32\n", cid->rawdata[x]); 00262 res = 32; 00263 } 00264 memcpy(cid->number, cid->rawdata + x + 1, res); 00265 /* Null terminate */ 00266 cid->number[res] = '\0'; 00267 break; 00268 case 7: /* Name */ 00269 case 8: /* Name */ 00270 res = cid->rawdata[x]; 00271 if (res > 32) { 00272 ast_log(LOG_NOTICE, "Truncating long caller ID name from %d bytes to 32\n", cid->rawdata[x]); 00273 res = 32; 00274 } 00275 memcpy(cid->name, cid->rawdata + x + 1, res); 00276 cid->name[res] = '\0'; 00277 break; 00278 case 22: /* Something French */ 00279 break; 00280 default: 00281 ast_log(LOG_NOTICE, "Unknown IE %d\n", cid->rawdata[x-1]); 00282 } 00283 x += cid->rawdata[x]; 00284 x++; 00285 } 00286 } else { 00287 /* SDMF */ 00288 strncpy(cid->number, cid->rawdata + 8, sizeof(cid->number)-1); 00289 } 00290 /* Update flags */ 00291 cid->flags = 0; 00292 if (!strcmp(cid->number, "P")) { 00293 strcpy(cid->number, ""); 00294 cid->flags |= CID_PRIVATE_NUMBER; 00295 } else if (!strcmp(cid->number, "O") || ast_strlen_zero(cid->number)) { 00296 strcpy(cid->number, ""); 00297 cid->flags |= CID_UNKNOWN_NUMBER; 00298 } 00299 if (!strcmp(cid->name, "P")) { 00300 strcpy(cid->name, ""); 00301 cid->flags |= CID_PRIVATE_NAME; 00302 } else if (!strcmp(cid->name, "O") || ast_strlen_zero(cid->name)) { 00303 strcpy(cid->name, ""); 00304 cid->flags |= CID_UNKNOWN_NAME; 00305 } 00306 return 1; 00307 break; 00308 default: 00309 ast_log(LOG_ERROR, "Dunno what to do with a digit in sawflag %d\n", cid->sawflag); 00310 } 00311 } 00312 } 00313 if (mylen) { 00314 memcpy(cid->oldstuff, buf, mylen * 2); 00315 cid->oldlen = mylen * 2; 00316 } else 00317 cid->oldlen = 0; 00318 free(obuf); 00319 return 0; 00320 } 00321 00322 void callerid_free(struct callerid_state *cid) 00323 { 00324 free(cid); 00325 } 00326 00327 static int callerid_genmsg(char *msg, int size, char *number, char *name, int flags) 00328 { 00329 time_t t; 00330 struct tm tm; 00331 char *ptr; 00332 int res; 00333 int i,x; 00334 /* Get the time */ 00335 time(&t); 00336 localtime_r(&t,&tm); 00337 00338 ptr = msg; 00339 00340 /* Format time and message header */ 00341 res = snprintf(ptr, size, "\001\010%02d%02d%02d%02d", tm.tm_mon + 1, 00342 tm.tm_mday, tm.tm_hour, tm.tm_min); 00343 size -= res; 00344 ptr += res; 00345 if (!number || ast_strlen_zero(number) || (flags & CID_UNKNOWN_NUMBER)) { 00346 /* Indicate number not known */ 00347 res = snprintf(ptr, size, "\004\001O"); 00348 size -= res; 00349 ptr += res; 00350 } else if (flags & CID_PRIVATE_NUMBER) { 00351 /* Indicate number is private */ 00352 res = snprintf(ptr, size, "\004\001P"); 00353 size -= res; 00354 ptr += res; 00355 } else { 00356 /* Send up to 16 digits of number MAX */ 00357 i = strlen(number); 00358 if (i > 16) i = 16; 00359 res = snprintf(ptr, size, "\002%c", i); 00360 size -= res; 00361 ptr += res; 00362 for (x=0;x<i;x++) 00363 ptr[x] = number[x]; 00364 ptr[i] = '\0'; 00365 ptr += i; 00366 size -= i; 00367 } 00368 00369 if (!name || ast_strlen_zero(name) || (flags & CID_UNKNOWN_NAME)) { 00370 /* Indicate name not known */ 00371 res = snprintf(ptr, size, "\010\001O"); 00372 size -= res; 00373 ptr += res; 00374 } else if (flags & CID_PRIVATE_NAME) { 00375 /* Indicate name is private */ 00376 res = snprintf(ptr, size, "\010\001P"); 00377 size -= res; 00378 ptr += res; 00379 } else { 00380 /* Send up to 16 digits of name MAX */ 00381 i = strlen(name); 00382 if (i > 16) i = 16; 00383 res = snprintf(ptr, size, "\007%c", i); 00384 size -= res; 00385 ptr += res; 00386 for (x=0;x<i;x++) 00387 ptr[x] = name[x]; 00388 ptr[i] = '\0'; 00389 ptr += i; 00390 size -= i; 00391 } 00392 return (ptr - msg); 00393 00394 } 00395 00396 int vmwi_generate(unsigned char *buf, int active, int mdmf, int codec) 00397 { 00398 unsigned char msg[256]; 00399 int len=0; 00400 int sum; 00401 int x; 00402 int bytes = 0; 00403 float cr = 1.0; 00404 float ci = 0.0; 00405 float scont = 0.0; 00406 if (mdmf) { 00407 /* MDMF Message waiting */ 00408 msg[len++] = 0x82; 00409 /* Length is 3 */ 00410 msg[len++] = 3; 00411 /* IE is "Message Waiting Parameter" */ 00412 msg[len++] = 0xb; 00413 /* Length of IE is one */ 00414 msg[len++] = 1; 00415 /* Active or not */ 00416 if (active) 00417 msg[len++] = 0xff; 00418 else 00419 msg[len++] = 0x00; 00420 } else { 00421 /* SDMF Message waiting */ 00422 msg[len++] = 0x6; 00423 /* Length is 3 */ 00424 msg[len++] = 3; 00425 if (active) { 00426 msg[len++] = 0x42; 00427 msg[len++] = 0x42; 00428 msg[len++] = 0x42; 00429 } else { 00430 msg[len++] = 0x6f; 00431 msg[len++] = 0x6f; 00432 msg[len++] = 0x6f; 00433 } 00434 } 00435 sum = 0; 00436 for (x=0;x<len;x++) 00437 sum += msg[x]; 00438 sum = (256 - (sum & 255)); 00439 msg[len++] = sum; 00440 /* Wait a half a second */ 00441 for (x=0;x<4000;x++) 00442 PUT_BYTE(0x7f); 00443 /* Transmit 30 0x55's (looks like a square wave) for channel seizure */ 00444 for (x=0;x<30;x++) 00445 PUT_CLID(0x55); 00446 /* Send 170ms of callerid marks */ 00447 for (x=0;x<170;x++) 00448 PUT_CLID_MARKMS; 00449 for (x=0;x<len;x++) { 00450 PUT_CLID(msg[x]); 00451 } 00452 /* Send 50 more ms of marks */ 00453 for (x=0;x<50;x++) 00454 PUT_CLID_MARKMS; 00455 return bytes; 00456 } 00457 00458 int callerid_generate(unsigned char *buf, char *number, char *name, int flags, int callwaiting, int codec) 00459 { 00460 int bytes=0; 00461 int x, sum; 00462 int len; 00463 /* Initial carriers (real/imaginary) */ 00464 float cr = 1.0; 00465 float ci = 0.0; 00466 float scont = 0.0; 00467 unsigned char msg[256]; 00468 len = callerid_genmsg(msg, sizeof(msg), number, name, flags); 00469 if (!callwaiting) { 00470 /* Wait a half a second */ 00471 for (x=0;x<4000;x++) 00472 PUT_BYTE(0x7f); 00473 /* Transmit 30 0x55's (looks like a square wave) for channel seizure */ 00474 for (x=0;x<30;x++) 00475 PUT_CLID(0x55); 00476 } 00477 /* Send 150ms of callerid marks */ 00478 for (x=0;x<150;x++) 00479 PUT_CLID_MARKMS; 00480 /* Send 0x80 indicating MDMF format */ 00481 PUT_CLID(0x80); 00482 /* Put length of whole message */ 00483 PUT_CLID(len); 00484 sum = 0x80 + strlen(msg); 00485 /* Put each character of message and update checksum */ 00486 for (x=0;x<len; x++) { 00487 PUT_CLID(msg[x]); 00488 sum += msg[x]; 00489 } 00490 /* Send 2's compliment of sum */ 00491 PUT_CLID(256 - (sum & 255)); 00492 00493 /* Send 50 more ms of marks */ 00494 for (x=0;x<50;x++) 00495 PUT_CLID_MARKMS; 00496 00497 return bytes; 00498 } 00499 00500 void ast_shrink_phone_number(char *n) 00501 { 00502 int x,y=0; 00503 for (x=0;n[x];x++) 00504 if (!strchr("( )-.", n[x])) 00505 n[y++] = n[x]; 00506 n[y] = '\0'; 00507 } 00508 00509 int ast_isphonenumber(char *n) 00510 { 00511 int x; 00512 if (!n || ast_strlen_zero(n)) 00513 return 0; 00514 for (x=0;n[x];x++) 00515 if (!strchr("0123456789*#+", n[x])) 00516 return 0; 00517 return 1; 00518 } 00519 00520 int ast_callerid_parse(char *instr, char **name, char **location) 00521 { 00522 char *ns, *ne; 00523 char *ls, *le; 00524 char tmp[256]; 00525 /* Try for "name" <location> format or 00526 name <location> format */ 00527 if ((ls = strchr(instr, '<')) && (le = strchr(ls, '>'))) { 00528 /* Found the location */ 00529 *le = '\0'; 00530 *ls = '\0'; 00531 *location = ls + 1; 00532 if ((ns = strchr(instr, '\"')) && (ne = strchr(ns + 1, '\"'))) { 00533 /* Get name out of quotes */ 00534 *ns = '\0'; 00535 *ne = '\0'; 00536 *name = ns + 1; 00537 return 0; 00538 } else { 00539 /* Just trim off any trailing spaces */ 00540 *name = instr; 00541 while(!ast_strlen_zero(instr) && (instr[strlen(instr) - 1] < 33)) 00542 instr[strlen(instr) - 1] = '\0'; 00543 /* And leading spaces */ 00544 while(**name && (**name < 33)) 00545 (*name)++; 00546 return 0; 00547 } 00548 } else { 00549 strncpy(tmp, instr, sizeof(tmp)-1); 00550 ast_shrink_phone_number(tmp); 00551 if (ast_isphonenumber(tmp)) { 00552 /* Assume it's just a location */ 00553 *name = NULL; 00554 *location = instr; 00555 } else { 00556 /* Assume it's just a name. Make sure it's not quoted though */ 00557 *name = instr; 00558 while(*(*name) && ((*(*name) < 33) || (*(*name) == '\"'))) (*name)++; 00559 ne = *name + strlen(*name) - 1; 00560 while((ne > *name) && ((*ne < 33) || (*ne == '\"'))) { *ne = '\0'; ne--; } 00561 *location = NULL; 00562 } 00563 return 0; 00564 } 00565 return -1; 00566 } 00567 00568 static int __ast_callerid_generate(unsigned char *buf, char *callerid, int callwaiting, int codec) 00569 { 00570 char tmp[256]; 00571 char *n, *l; 00572 if (!callerid) 00573 return callerid_generate(buf, NULL, NULL, 0, callwaiting, codec); 00574 strncpy(tmp, callerid, sizeof(tmp)-1); 00575 if (ast_callerid_parse(tmp, &n, &l)) { 00576 ast_log(LOG_WARNING, "Unable to parse '%s' into CallerID name & number\n", callerid); 00577 return callerid_generate(buf, NULL, NULL, 0, callwaiting, codec); 00578 } 00579 if (l) 00580 ast_shrink_phone_number(l); 00581 if (!ast_isphonenumber(l)) 00582 return callerid_generate(buf, NULL, n, 0, callwaiting, codec); 00583 return callerid_generate(buf, l, n, 0, callwaiting, codec); 00584 } 00585 00586 int ast_callerid_generate(unsigned char *buf, char *callerid, int codec) 00587 { 00588 return __ast_callerid_generate(buf, callerid, 0, codec); 00589 } 00590 00591 int ast_callerid_callwaiting_generate(unsigned char *buf, char *callerid, int codec) 00592 { 00593 return __ast_callerid_generate(buf, callerid, 1, codec); 00594 }

Generated on Sat Jun 12 16:40:57 2004 for Asterisk by doxygen 1.3.7