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