Version 0.1.11 from FTP
[asterisk/asterisk.git] / callerid.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * CallerID Generation support 
5  * 
6  * Copyright (C) 2001, Linux Support Services, Inc.
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License.
12  *
13  * Includes code and algorithms from the Zapata library.
14  *
15  */
16
17 #include <time.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <math.h>
23 #include <asterisk/ulaw.h>
24 #include <asterisk/callerid.h>
25 #include <asterisk/logger.h>
26 #include <asterisk/fskmodem.h>
27 #include "sas.h"
28 #include "cas.h"
29
30
31 struct callerid_state {
32         fsk_data fskd;
33         char rawdata[256];
34         short oldstuff[160];
35         int oldlen;
36         int pos;
37         int type;
38         int cksum;
39         char name[64];
40         char number[64];
41         int flags;
42         int sawflag;
43         int len;
44 };
45
46
47 float cid_dr[4], cid_di[4];
48 float clidsb = 8000.0 / 1200.0;
49
50 #define CALLERID_SPACE  2200.0          /* 2200 hz for "0" */
51 #define CALLERID_MARK   1200.0          /* 1200 hz for "1" */
52
53 void callerid_init(void)
54 {
55         /* Initialize stuff for inverse FFT */
56         cid_dr[0] = cos(CALLERID_SPACE * 2.0 * M_PI / 8000.0);
57         cid_di[0] = sin(CALLERID_SPACE * 2.0 * M_PI / 8000.0);
58         cid_dr[1] = cos(CALLERID_MARK * 2.0 * M_PI / 8000.0);
59         cid_di[1] = sin(CALLERID_MARK * 2.0 * M_PI / 8000.0);
60 }
61
62 struct callerid_state *callerid_new(void)
63 {
64         struct callerid_state *cid;
65         cid = malloc(sizeof(struct callerid_state));
66         memset(cid, 0, sizeof(struct callerid_state));
67         if (cid) {
68                 cid->fskd.spb = 7;              /* 1200 baud */
69                 cid->fskd.hdlc = 0;             /* Async */
70                 cid->fskd.nbit = 8;             /* 8 bits */
71                 cid->fskd.nstop = 1;    /* 1 stop bit */
72                 cid->fskd.paridad = 0;  /* No parity */
73                 cid->fskd.bw=1;                 /* Filter 800 Hz */
74                 cid->fskd.f_mark_idx =  2;      /* 1200 Hz */
75                 cid->fskd.f_space_idx = 3;      /* 2200 Hz */
76                 cid->fskd.pcola = 0;            /* No clue */
77                 cid->fskd.cont = 0;                     /* Digital PLL reset */
78                 cid->fskd.x0 = 0.0;
79                 cid->fskd.state = 0;
80                 memset(cid->name, 0, sizeof(cid->name));
81                 memset(cid->number, 0, sizeof(cid->number));
82                 cid->flags = CID_UNKNOWN_NAME | CID_UNKNOWN_NUMBER;
83                 cid->pos = 0;
84         } else
85                 ast_log(LOG_WARNING, "Out of memory\n");
86         return cid;
87 }
88
89 void callerid_get(struct callerid_state *cid, char **name, char **number, int *flags)
90 {
91         *flags = cid->flags;
92         if (cid->flags & (CID_UNKNOWN_NAME | CID_PRIVATE_NUMBER))
93                 *name = NULL;
94         else
95                 *name = cid->name;
96         if (cid->flags & (CID_UNKNOWN_NUMBER | CID_PRIVATE_NUMBER))
97                 *number = NULL;
98         else
99                 *number = cid->number;
100 }
101
102 int ast_gen_cas(unsigned char *outbuf, int sendsas, int len)
103 {
104         int pos = 0;
105         int cnt;
106         int saslen=2400;
107         if (sendsas) {
108                 if (len < saslen)
109                         return -1;
110                 while(saslen) {
111                         cnt = saslen;
112                         if (cnt > sizeof(sas))
113                                 cnt = sizeof(sas);
114                         memcpy(outbuf + pos, sas, cnt);
115                         pos += cnt;
116                         len -= cnt;
117                         saslen -= cnt;
118                 }
119         }
120         while(len) {
121                 cnt = len;
122                 if (cnt > sizeof(cas))
123                         cnt = sizeof(cas);
124                 memcpy(outbuf + pos, cas, cnt);
125                 pos += cnt;
126                 len -= cnt;
127         }
128         return 0;
129 }
130
131 int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len)
132 {
133         int mylen = len;
134         int olen;
135         int b = 'X';
136         int res;
137         int x;
138         short *buf = malloc(2 * len + cid->oldlen);
139         short *obuf = buf;
140         if (!buf) {
141                 ast_log(LOG_WARNING, "Out of memory\n");
142                 return -1;
143         }
144         memset(buf, 0, 2 * len + cid->oldlen);
145         memcpy(buf, cid->oldstuff, cid->oldlen);
146         mylen += cid->oldlen/2;
147         for (x=0;x<len;x++) 
148                 buf[x+cid->oldlen/2] = AST_MULAW(ubuf[x]);
149         while(mylen >= 80) {
150                 olen = mylen;
151                 res = fsk_serie(&cid->fskd, buf, &mylen, &b);
152                 if (mylen < 0) {
153                         ast_log(LOG_ERROR, "fsk_serie made mylen < 0 (%d)\n", mylen);
154                         return -1;
155                 }
156                 buf += (olen - mylen);
157                 if (res < 0) {
158                         ast_log(LOG_NOTICE, "fsk_serie failed\n");
159                         return -1;
160                 }
161                 if (res == 1) {
162                         /* Ignore invalid bytes */
163                         if (b > 0xff)
164                                 continue;
165                         switch(cid->sawflag) {
166                         case 0: /* Look for flag */
167                                 if (b == 'U')
168                                         cid->sawflag = 2;
169                                 break;
170                         case 2: /* Get lead-in */
171                                 if ((b == 0x04) || (b == 0x80)) {
172                                         cid->type = b;
173                                         cid->sawflag = 3;
174                                         cid->cksum = b;
175                                 }
176                                 break;
177                         case 3: /* Get length */
178                                 /* Not a lead in.  We're ready  */
179                                 cid->sawflag = 4;
180                                 cid->len = b;
181                                 cid->pos = 0;
182                                 cid->cksum += b;
183                                 break;
184                         case 4: /* Retrieve message */
185                                 if (cid->pos >= 128) {
186                                         ast_log(LOG_WARNING, "Caller ID too long???\n");
187                                         return -1;
188                                 }
189                                 cid->rawdata[cid->pos++] = b;
190                                 cid->len--;
191                                 cid->cksum += b;
192                                 if (!cid->len) {
193                                         cid->rawdata[cid->pos] = '\0';
194                                         cid->sawflag = 5;
195                                 }
196                                 break;
197                         case 5: /* Check checksum */
198                                 if (b != (256 - (cid->cksum & 0xff))) {
199                                         ast_log(LOG_NOTICE, "Caller*ID failed checksum\n");
200                                         /* Try again */
201                                         cid->sawflag = 0;
202                                         break;
203                                 }
204                 
205                                 strcpy(cid->number, "");
206                                 strcpy(cid->name, "");
207                                 /* If we get this far we're fine.  */
208                                 if (cid->type == 0x80) {
209                                         /* MDMF */
210                                         /* Go through each element and process */
211                                         for (x=0;x< cid->pos;) {
212                                                 switch(cid->rawdata[x++]) {
213                                                 case 1:
214                                                         /* Date */
215                                                         break;
216                                                 case 2: /* Number */
217                                                 case 4: /* Number */
218                                                         res = cid->rawdata[x];
219                                                         if (res > 32) {
220                                                                 ast_log(LOG_NOTICE, "Truncating long caller ID number from %d bytes to 32\n", cid->rawdata[x]);
221                                                                 res = 32; 
222                                                         }
223                                                         memcpy(cid->number, cid->rawdata + x + 1, res);
224                                                         /* Null terminate */
225                                                         cid->number[res] = '\0';
226                                                         break;
227                                                 case 7: /* Name */
228                                                 case 8: /* Name */
229                                                         res = cid->rawdata[x];
230                                                         if (res > 32) {
231                                                                 ast_log(LOG_NOTICE, "Truncating long caller ID name from %d bytes to 32\n", cid->rawdata[x]);
232                                                                 res = 32; 
233                                                         }
234                                                         memcpy(cid->name, cid->rawdata + x + 1, res);
235                                                         cid->name[res] = '\0';
236                                                         break;
237                                                 default:
238                                                         ast_log(LOG_NOTICE, "Unknown IE %d\n", cid->rawdata[x-1]);
239                                                 }
240                                                 x += cid->rawdata[x];
241                                                 x++;
242                                         }
243                                 } else {
244                                         /* SDMF */
245                                         strncpy(cid->number, cid->rawdata + 8, sizeof(cid->number)-1);
246                                 }
247                                 /* Update flags */
248                                 cid->flags = 0;
249                                 if (!strcmp(cid->number, "P")) {
250                                         strcpy(cid->number, "");
251                                         cid->flags |= CID_PRIVATE_NUMBER;
252                                 } else if (!strcmp(cid->number, "O") || !strlen(cid->number)) {
253                                         strcpy(cid->number, "");
254                                         cid->flags |= CID_UNKNOWN_NUMBER;
255                                 }
256                                 if (!strcmp(cid->name, "P")) {
257                                         strcpy(cid->name, "");
258                                         cid->flags |= CID_PRIVATE_NAME;
259                                 } else if (!strcmp(cid->name, "O") || !strlen(cid->name)) {
260                                         strcpy(cid->name, "");
261                                         cid->flags |= CID_UNKNOWN_NAME;
262                                 }
263                                 return 1;
264                                 break;
265                         default:
266                                 ast_log(LOG_ERROR, "Dunno what to do with a digit in sawflag %d\n", cid->sawflag);
267                         }
268                 }
269         }
270         if (mylen) {
271                 memcpy(cid->oldstuff, buf, mylen * 2);
272                 cid->oldlen = mylen * 2;
273         } else
274                 cid->oldlen = 0;
275         free(obuf);
276         return 0;
277 }
278
279 void callerid_free(struct callerid_state *cid)
280 {
281         free(cid);
282 }
283
284 static void callerid_genmsg(char *msg, int size, char *number, char *name, int flags)
285 {
286         time_t t;
287         struct tm *tm;
288         char *ptr;
289         int res;
290         int i,x;
291         /* Get the time */
292         time(&t);
293         tm = localtime(&t);
294         
295         ptr = msg;
296         
297         /* Format time and message header */
298         res = snprintf(ptr, size, "\001\010%02d%02d%02d%02d", tm->tm_mon + 1,
299                                 tm->tm_mday, tm->tm_hour, tm->tm_min);
300         size -= res;
301         ptr += res;
302         if (!number || !strlen(number) || (flags & CID_UNKNOWN_NUMBER)) {
303                 /* Indicate number not known */
304                 res = snprintf(ptr, size, "\004\001O");
305                 size -= res;
306                 ptr += res;
307         } else if (flags & CID_PRIVATE_NUMBER) {
308                 /* Indicate number is private */
309                 res = snprintf(ptr, size, "\004\001P");
310                 size -= res;
311                 ptr += res;
312         } else {
313                 /* Send up to 10 digits of number MAX */
314                 i = strlen(number);
315                 if (i > 10) i = 10;
316                 res = snprintf(ptr, size, "\002%c", i);
317                 size -= res;
318                 ptr += res;
319                 for (x=0;x<i;x++)
320                         ptr[x] = number[x];
321                 ptr[i] = '\0';
322                 ptr += i;
323                 size -= i;
324         }
325
326         if (!name || !strlen(name) || (flags & CID_UNKNOWN_NAME)) {
327                 /* Indicate name not known */
328                 res = snprintf(ptr, size, "\010\001O");
329                 size -= res;
330                 ptr += res;
331         } else if (flags & CID_PRIVATE_NAME) {
332                 /* Indicate name is private */
333                 res = snprintf(ptr, size, "\010\001P");
334                 size -= res;
335                 ptr += res;
336         } else {
337                 /* Send up to 10 digits of number MAX */
338                 i = strlen(name);
339                 if (i > 16) i = 16;
340                 res = snprintf(ptr, size, "\007%c", i);
341                 size -= res;
342                 ptr += res;
343                 for (x=0;x<i;x++)
344                         ptr[x] = name[x];
345                 ptr[i] = '\0';
346                 ptr += i;
347                 size -= i;
348         }
349         
350 }
351
352 int callerid_generate(unsigned char *buf, char *number, char *name, int flags, int callwaiting)
353 {
354         int bytes=0;
355         int x, sum;
356         /* Initial carriers (real/imaginary) */
357         float cr = 1.0;
358         float ci = 0.0;
359         float scont = 0.0;
360         char msg[256];
361         callerid_genmsg(msg, sizeof(msg), number, name, flags);
362         if (!callwaiting) {
363                 /* Wait a half a second */
364                 for (x=0;x<4000;x++)
365                         PUT_BYTE(0x7f);
366                 /* Transmit 30 0x55's (looks like a square wave) for channel seizure */
367                 for (x=0;x<30;x++)
368                         PUT_CLID(0x55);
369         }
370         /* Send 150ms of callerid marks */
371         for (x=0;x<150;x++)
372                 PUT_CLID_MARKMS;
373         /* Send 0x80 indicating MDMF format */
374         PUT_CLID(0x80);
375         /* Put length of whole message */
376         PUT_CLID(strlen(msg));
377         sum = 0x80 + strlen(msg);
378         /* Put each character of message and update checksum */
379         for (x=0;x<strlen(msg); x++) {
380                 PUT_CLID(msg[x]);
381                 sum += msg[x];
382         }
383         /* Send 2's compliment of sum */
384         PUT_CLID(256 - (sum & 255));
385         /* Send 50 more ms of marks */
386         for (x=0;x<50;x++)
387                 PUT_CLID_MARKMS;
388         
389         return bytes;
390 }
391
392 void ast_shrink_phone_number(char *n)
393 {
394         int x,y=0;
395         for (x=0;n[x];x++)
396                 if (!strchr("( )-.", n[x]))
397                         n[y++] = n[x];
398         n[y] = '\0';
399 }
400
401 int ast_isphonenumber(char *n)
402 {
403         int x;
404         if (!n || !strlen(n))
405                 return 0;
406         for (x=0;n[x];x++)
407                 if (!strchr("0123456789", n[x]))
408                         return 0;
409         return 1;
410 }
411
412 int ast_callerid_parse(char *instr, char **name, char **location)
413 {
414         char *ns, *ne;
415         char *ls, *le;
416         char tmp[256];
417         /* Try for "name" <location> format or 
418            name <location> format */
419         if ((ls = strchr(instr, '<')) && (le = strchr(ls, '>'))) {
420                 /* Found the location */
421                 *le = '\0';
422                 *ls = '\0';
423                 *location = ls + 1;
424                 if ((ns = strchr(instr, '\"')) && (ne = strchr(ns + 1, '\"'))) {
425                         /* Get name out of quotes */
426                         *ns = '\0';
427                         *ne = '\0';
428                         *name = ns + 1;
429                         return 0;
430                 } else {
431                         /* Just trim off any trailing spaces */
432                         *name = instr;
433                         while(strlen(instr) && (instr[strlen(instr) - 1] < 33))
434                                 instr[strlen(instr) - 1] = '\0';
435                         /* And leading spaces */
436                         while(**name && (**name < 33))
437                                 name++;
438                         return 0;
439                 }
440         } else {
441                 strncpy(tmp, instr, sizeof(tmp)-1);
442                 ast_shrink_phone_number(tmp);
443                 if (ast_isphonenumber(tmp)) {
444                         /* Assume it's just a location */
445                         *name = NULL;
446                         *location = instr;
447                 } else {
448                         /* Assume it's just a name */
449                         *name = instr;
450                         *location = NULL;
451                 }
452                 return 0;
453         }
454         return -1;
455 }
456
457 static int __ast_callerid_generate(unsigned char *buf, char *callerid, int callwaiting)
458 {
459         char tmp[256];
460         char *n, *l;
461         if (!callerid)
462                 return callerid_generate(buf, NULL, NULL, 0, callwaiting);
463         strncpy(tmp, callerid, sizeof(tmp)-1);
464         if (ast_callerid_parse(tmp, &n, &l)) {
465                 ast_log(LOG_WARNING, "Unable to parse '%s' into CallerID name & number\n", callerid);
466                 return callerid_generate(buf, NULL, NULL, 0, callwaiting);
467         }
468         if (l)
469                 ast_shrink_phone_number(l);
470         if (!ast_isphonenumber(l))
471                 return callerid_generate(buf, NULL, n, 0, callwaiting);
472         return callerid_generate(buf, l, n, 0, callwaiting);
473 }
474
475 int ast_callerid_generate(unsigned char *buf, char *callerid)
476 {
477         return __ast_callerid_generate(buf, callerid, 0);
478 }
479
480 int ast_callerid_callwaiting_generate(unsigned char *buf, char *callerid)
481 {
482         return __ast_callerid_generate(buf, callerid, 1);
483 }