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