~ubuntu-branches/ubuntu/karmic/asterisk/karmic

« back to all changes in this revision

Viewing changes to callerid.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Purcell
  • Date: 2002-04-27 21:19:32 UTC
  • Revision ID: james.westby@ubuntu.com-20020427211932-kqaertc4bg7ss5mc
Tags: upstream-0.1.11
ImportĀ upstreamĀ versionĀ 0.1.11

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}