Version 0.2.0 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 3: /* Number (for Zebble) */
218                                                 case 4: /* Number */
219                                                         res = cid->rawdata[x];
220                                                         if (res > 32) {
221                                                                 ast_log(LOG_NOTICE, "Truncating long caller ID number from %d bytes to 32\n", cid->rawdata[x]);
222                                                                 res = 32; 
223                                                         }
224                                                         memcpy(cid->number, cid->rawdata + x + 1, res);
225                                                         /* Null terminate */
226                                                         cid->number[res] = '\0';
227                                                         break;
228                                                 case 7: /* Name */
229                                                 case 8: /* Name */
230                                                         res = cid->rawdata[x];
231                                                         if (res > 32) {
232                                                                 ast_log(LOG_NOTICE, "Truncating long caller ID name from %d bytes to 32\n", cid->rawdata[x]);
233                                                                 res = 32; 
234                                                         }
235                                                         memcpy(cid->name, cid->rawdata + x + 1, res);
236                                                         cid->name[res] = '\0';
237                                                         break;
238                                                 default:
239                                                         ast_log(LOG_NOTICE, "Unknown IE %d\n", cid->rawdata[x-1]);
240                                                 }
241                                                 x += cid->rawdata[x];
242                                                 x++;
243                                         }
244                                 } else {
245                                         /* SDMF */
246                                         strncpy(cid->number, cid->rawdata + 8, sizeof(cid->number)-1);
247                                 }
248                                 /* Update flags */
249                                 cid->flags = 0;
250                                 if (!strcmp(cid->number, "P")) {
251                                         strcpy(cid->number, "");
252                                         cid->flags |= CID_PRIVATE_NUMBER;
253                                 } else if (!strcmp(cid->number, "O") || !strlen(cid->number)) {
254                                         strcpy(cid->number, "");
255                                         cid->flags |= CID_UNKNOWN_NUMBER;
256                                 }
257                                 if (!strcmp(cid->name, "P")) {
258                                         strcpy(cid->name, "");
259                                         cid->flags |= CID_PRIVATE_NAME;
260                                 } else if (!strcmp(cid->name, "O") || !strlen(cid->name)) {
261                                         strcpy(cid->name, "");
262                                         cid->flags |= CID_UNKNOWN_NAME;
263                                 }
264                                 return 1;
265                                 break;
266                         default:
267                                 ast_log(LOG_ERROR, "Dunno what to do with a digit in sawflag %d\n", cid->sawflag);
268                         }
269                 }
270         }
271         if (mylen) {
272                 memcpy(cid->oldstuff, buf, mylen * 2);
273                 cid->oldlen = mylen * 2;
274         } else
275                 cid->oldlen = 0;
276         free(obuf);
277         return 0;
278 }
279
280 void callerid_free(struct callerid_state *cid)
281 {
282         free(cid);
283 }
284
285 static void callerid_genmsg(char *msg, int size, char *number, char *name, int flags)
286 {
287         time_t t;
288         struct tm *tm;
289         char *ptr;
290         int res;
291         int i,x;
292         /* Get the time */
293         time(&t);
294         tm = localtime(&t);
295         
296         ptr = msg;
297         
298         /* Format time and message header */
299         res = snprintf(ptr, size, "\001\010%02d%02d%02d%02d", tm->tm_mon + 1,
300                                 tm->tm_mday, tm->tm_hour, tm->tm_min);
301         size -= res;
302         ptr += res;
303         if (!number || !strlen(number) || (flags & CID_UNKNOWN_NUMBER)) {
304                 /* Indicate number not known */
305                 res = snprintf(ptr, size, "\004\001O");
306                 size -= res;
307                 ptr += res;
308         } else if (flags & CID_PRIVATE_NUMBER) {
309                 /* Indicate number is private */
310                 res = snprintf(ptr, size, "\004\001P");
311                 size -= res;
312                 ptr += res;
313         } else {
314                 /* Send up to 10 digits of number MAX */
315                 i = strlen(number);
316                 if (i > 10) i = 10;
317                 res = snprintf(ptr, size, "\002%c", i);
318                 size -= res;
319                 ptr += res;
320                 for (x=0;x<i;x++)
321                         ptr[x] = number[x];
322                 ptr[i] = '\0';
323                 ptr += i;
324                 size -= i;
325         }
326
327         if (!name || !strlen(name) || (flags & CID_UNKNOWN_NAME)) {
328                 /* Indicate name not known */
329                 res = snprintf(ptr, size, "\010\001O");
330                 size -= res;
331                 ptr += res;
332         } else if (flags & CID_PRIVATE_NAME) {
333                 /* Indicate name is private */
334                 res = snprintf(ptr, size, "\010\001P");
335                 size -= res;
336                 ptr += res;
337         } else {
338                 /* Send up to 10 digits of number MAX */
339                 i = strlen(name);
340                 if (i > 16) i = 16;
341                 res = snprintf(ptr, size, "\007%c", i);
342                 size -= res;
343                 ptr += res;
344                 for (x=0;x<i;x++)
345                         ptr[x] = name[x];
346                 ptr[i] = '\0';
347                 ptr += i;
348                 size -= i;
349         }
350         
351 }
352
353 int callerid_generate(unsigned char *buf, char *number, char *name, int flags, int callwaiting)
354 {
355         int bytes=0;
356         int x, sum;
357         /* Initial carriers (real/imaginary) */
358         float cr = 1.0;
359         float ci = 0.0;
360         float scont = 0.0;
361         char msg[256];
362         callerid_genmsg(msg, sizeof(msg), number, name, flags);
363         if (!callwaiting) {
364                 /* Wait a half a second */
365                 for (x=0;x<4000;x++)
366                         PUT_BYTE(0x7f);
367                 /* Transmit 30 0x55's (looks like a square wave) for channel seizure */
368                 for (x=0;x<30;x++)
369                         PUT_CLID(0x55);
370         }
371         /* Send 150ms of callerid marks */
372         for (x=0;x<150;x++)
373                 PUT_CLID_MARKMS;
374         /* Send 0x80 indicating MDMF format */
375         PUT_CLID(0x80);
376         /* Put length of whole message */
377         PUT_CLID(strlen(msg));
378         sum = 0x80 + strlen(msg);
379         /* Put each character of message and update checksum */
380         for (x=0;x<strlen(msg); x++) {
381                 PUT_CLID(msg[x]);
382                 sum += msg[x];
383         }
384         /* Send 2's compliment of sum */
385         PUT_CLID(256 - (sum & 255));
386         /* Send 50 more ms of marks */
387         for (x=0;x<50;x++)
388                 PUT_CLID_MARKMS;
389         
390         return bytes;
391 }
392
393 void ast_shrink_phone_number(char *n)
394 {
395         int x,y=0;
396         for (x=0;n[x];x++)
397                 if (!strchr("( )-.", n[x]))
398                         n[y++] = n[x];
399         n[y] = '\0';
400 }
401
402 int ast_isphonenumber(char *n)
403 {
404         int x;
405         if (!n || !strlen(n))
406                 return 0;
407         for (x=0;n[x];x++)
408                 if (!strchr("0123456789", n[x]))
409                         return 0;
410         return 1;
411 }
412
413 int ast_callerid_parse(char *instr, char **name, char **location)
414 {
415         char *ns, *ne;
416         char *ls, *le;
417         char tmp[256];
418         /* Try for "name" <location> format or 
419            name <location> format */
420         if ((ls = strchr(instr, '<')) && (le = strchr(ls, '>'))) {
421                 /* Found the location */
422                 *le = '\0';
423                 *ls = '\0';
424                 *location = ls + 1;
425                 if ((ns = strchr(instr, '\"')) && (ne = strchr(ns + 1, '\"'))) {
426                         /* Get name out of quotes */
427                         *ns = '\0';
428                         *ne = '\0';
429                         *name = ns + 1;
430                         return 0;
431                 } else {
432                         /* Just trim off any trailing spaces */
433                         *name = instr;
434                         while(strlen(instr) && (instr[strlen(instr) - 1] < 33))
435                                 instr[strlen(instr) - 1] = '\0';
436                         /* And leading spaces */
437                         while(**name && (**name < 33))
438                                 name++;
439                         return 0;
440                 }
441         } else {
442                 strncpy(tmp, instr, sizeof(tmp)-1);
443                 ast_shrink_phone_number(tmp);
444                 if (ast_isphonenumber(tmp)) {
445                         /* Assume it's just a location */
446                         *name = NULL;
447                         *location = instr;
448                 } else {
449                         /* Assume it's just a name */
450                         *name = instr;
451                         *location = NULL;
452                 }
453                 return 0;
454         }
455         return -1;
456 }
457
458 static int __ast_callerid_generate(unsigned char *buf, char *callerid, int callwaiting)
459 {
460         char tmp[256];
461         char *n, *l;
462         if (!callerid)
463                 return callerid_generate(buf, NULL, NULL, 0, callwaiting);
464         strncpy(tmp, callerid, sizeof(tmp)-1);
465         if (ast_callerid_parse(tmp, &n, &l)) {
466                 ast_log(LOG_WARNING, "Unable to parse '%s' into CallerID name & number\n", callerid);
467                 return callerid_generate(buf, NULL, NULL, 0, callwaiting);
468         }
469         if (l)
470                 ast_shrink_phone_number(l);
471         if (!ast_isphonenumber(l))
472                 return callerid_generate(buf, NULL, n, 0, callwaiting);
473         return callerid_generate(buf, l, n, 0, callwaiting);
474 }
475
476 int ast_callerid_generate(unsigned char *buf, char *callerid)
477 {
478         return __ast_callerid_generate(buf, callerid, 0);
479 }
480
481 int ast_callerid_callwaiting_generate(unsigned char *buf, char *callerid)
482 {
483         return __ast_callerid_generate(buf, callerid, 1);
484 }