(closes issue #12846)
[asterisk-bristuff.git] / apps / app_sms.c
blob53e8590df69734d9b763d907b6762f67b8c08d93
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2004 - 2005, Adrian Kennard, rights assigned to Digium
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
17 /*! \file
19 * \brief SMS application - ETSI ES 201 912 protocol 1 implimentation
20 * \ingroup applications
22 * \author Adrian Kennard
25 #include "asterisk.h"
27 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <dirent.h>
35 #include <ctype.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
39 #include "asterisk/lock.h"
40 #include "asterisk/file.h"
41 #include "asterisk/logger.h"
42 #include "asterisk/options.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/module.h"
46 #include "asterisk/alaw.h"
47 #include "asterisk/callerid.h"
49 /* output using Alaw rather than linear */
50 /* #define OUTALAW */
52 /* ToDo */
53 /* Add full VP support */
54 /* Handle status report messages (generation and reception) */
55 /* Time zones on time stamps */
56 /* user ref field */
58 static volatile unsigned char message_ref; /* arbitary message ref */
59 static volatile unsigned int seq; /* arbitrary message sequence number for unqiue files */
61 static char log_file[255];
62 static char spool_dir[255];
64 static char *app = "SMS";
66 static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
68 static char *descrip =
69 " SMS(name|[a][s]): SMS handles exchange of SMS data with a call to/from SMS capabale\n"
70 "phone or SMS PSTN service center. Can send and/or receive SMS messages.\n"
71 "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
72 "Typical usage is to use to handle called from the SMS service centre CLI,\n"
73 "or to set up a call using 'outgoing' or manager interface to connect\n"
74 "service centre to SMS()\n"
75 "name is the name of the queue used in /var/spool/asterisk/sms\n"
76 "Arguments:\n"
77 " a: answer, i.e. send initial FSK packet.\n"
78 " s: act as service centre talking to a phone.\n"
79 "Messages are processed as per text file message queues.\n"
80 "smsq (a separate software) is a command to generate message\n"
81 "queues and send messages.\n";
83 static signed short wave[] = {
84 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
85 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
86 0, -392, -782, -1167,
87 -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
88 -4985, -4938, -4862,
89 -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
92 #ifdef OUTALAW
93 static unsigned char wavea[80];
94 #endif
97 /* SMS 7 bit character mapping to UCS-2 */
98 static const unsigned short defaultalphabet[] = {
99 0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
100 0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
101 0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
102 0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
103 ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
104 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
105 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
106 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
107 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
108 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
111 static const unsigned short escapes[] = {
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
113 0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114 0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
116 0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118 0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122 #define SMSLEN 160 /* max SMS length */
124 typedef struct sms_s
126 unsigned char hangup; /* we are done... */
127 unsigned char err; /* set for any errors */
128 unsigned char smsc:1; /* we are SMSC */
129 unsigned char rx:1; /* this is a received message */
130 char queue[30]; /* queue name */
131 char oa[20]; /* originating address */
132 char da[20]; /* destination address */
133 time_t scts; /* time stamp, UTC */
134 unsigned char pid; /* protocol ID */
135 unsigned char dcs; /* data coding scheme */
136 short mr; /* message reference - actually a byte, but usde -1 for not set */
137 int udl; /* user data length */
138 int udhl; /* user data header length */
139 unsigned char srr:1; /* Status Report request */
140 unsigned char udhi:1; /* User Data Header required, even if length 0 */
141 unsigned char rp:1; /* Reply Path */
142 unsigned int vp; /* validity period in minutes, 0 for not set */
143 unsigned short ud[SMSLEN]; /* user data (message), UCS-2 coded */
144 unsigned char udh[SMSLEN]; /* user data header */
145 char cli[20]; /* caller ID */
146 unsigned char ophase; /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
147 unsigned char ophasep; /* phase (0-79) for 1200 bps */
148 unsigned char obyte; /* byte being sent */
149 unsigned int opause; /* silent pause before sending (in sample periods) */
150 unsigned char obitp; /* bit in byte */
151 unsigned char osync; /* sync bits to send */
152 unsigned char obytep; /* byte in data */
153 unsigned char obyten; /* bytes in data */
154 unsigned char omsg[256]; /* data buffer (out) */
155 unsigned char imsg[200]; /* data buffer (in) */
156 signed long long ims0,
157 imc0,
158 ims1,
159 imc1; /* magnitude averages sin/cos 0/1 */
160 unsigned int idle;
161 unsigned short imag; /* signal level */
162 unsigned char ips0,
163 ips1,
164 ipc0,
165 ipc1; /* phase sin/cos 0/1 */
166 unsigned char ibitl; /* last bit */
167 unsigned char ibitc; /* bit run length count */
168 unsigned char iphasep; /* bit phase (0-79) for 1200 bps */
169 unsigned char ibitn; /* bit number in byte being received */
170 unsigned char ibytev; /* byte value being received */
171 unsigned char ibytep; /* byte pointer in messafe */
172 unsigned char ibytec; /* byte checksum for message */
173 unsigned char ierr; /* error flag */
174 unsigned char ibith; /* history of last bits */
175 unsigned char ibitt; /* total of 1's in last 3 bites */
176 /* more to go here */
177 } sms_t;
179 /* different types of encoding */
180 #define is7bit(dcs) (((dcs)&0xC0)?(!((dcs)&4)):(!((dcs)&12)))
181 #define is8bit(dcs) (((dcs)&0xC0)?(((dcs)&4)):(((dcs)&12)==4))
182 #define is16bit(dcs) (((dcs)&0xC0)?0:(((dcs)&12)==8))
184 static void *sms_alloc (struct ast_channel *chan, void *params)
186 return params;
189 static void sms_release (struct ast_channel *chan, void *data)
191 return;
194 static void sms_messagetx (sms_t * h);
196 /*! \brief copy number, skipping non digits apart from leading + */
197 static void numcpy (char *d, char *s)
199 if (*s == '+')
200 *d++ = *s++;
201 while (*s) {
202 if (isdigit (*s))
203 *d++ = *s;
204 s++;
206 *d = 0;
209 /*! \brief static, return a date/time in ISO format */
210 static char * isodate (time_t t)
212 static char date[20];
213 strftime (date, sizeof (date), "%Y-%m-%dT%H:%M:%S", localtime (&t));
214 return date;
217 /*! \brief reads next UCS character from null terminated UTF-8 string and advanced pointer */
218 /* for non valid UTF-8 sequences, returns character as is */
219 /* Does not advance pointer for null termination */
220 static long utf8decode (unsigned char **pp)
222 unsigned char *p = *pp;
223 if (!*p)
224 return 0; /* null termination of string */
225 (*pp)++;
226 if (*p < 0xC0)
227 return *p; /* ascii or continuation character */
228 if (*p < 0xE0) {
229 if (*p < 0xC2 || (p[1] & 0xC0) != 0x80)
230 return *p; /* not valid UTF-8 */
231 (*pp)++;
232 return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
234 if (*p < 0xF0) {
235 if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80)
236 return *p; /* not valid UTF-8 */
237 (*pp) += 2;
238 return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
240 if (*p < 0xF8) {
241 if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80)
242 return *p; /* not valid UTF-8 */
243 (*pp) += 3;
244 return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
246 if (*p < 0xFC) {
247 if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
248 || (p[4] & 0xC0) != 0x80)
249 return *p; /* not valid UTF-8 */
250 (*pp) += 4;
251 return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
253 if (*p < 0xFE) {
254 if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
255 || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80)
256 return *p; /* not valid UTF-8 */
257 (*pp) += 5;
258 return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F);
260 return *p; /* not sensible */
263 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using SMS 7 bit character codes */
264 /* The return value is the number of septets packed in to o, which is internally limited to SMSLEN */
265 /* o can be null, in which case this is used to validate or count only */
266 /* if the input contains invalid characters then the return value is -1 */
267 static int packsms7 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
269 unsigned char p = 0, b = 0, n = 0;
271 if (udhl) { /* header */
272 if (o)
273 o[p++] = udhl;
274 b = 1;
275 n = 1;
276 while (udhl--) {
277 if (o)
278 o[p++] = *udh++;
279 b += 8;
280 while (b >= 7) {
281 b -= 7;
282 n++;
284 if (n >= SMSLEN)
285 return n;
287 if (b) {
288 b = 7 - b;
289 if (++n >= SMSLEN)
290 return n;
291 }; /* filling to septet boundary */
293 if (o)
294 o[p] = 0;
295 /* message */
296 while (udl--) {
297 long u;
298 unsigned char v;
299 u = *ud++;
300 for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
301 if (v == 128 && u && n + 1 < SMSLEN) {
302 for (v = 0; v < 128 && escapes[v] != u; v++);
303 if (v < 128) { /* escaped sequence */
304 if (o)
305 o[p] |= (27 << b);
306 b += 7;
307 if (b >= 8) {
308 b -= 8;
309 p++;
310 if (o)
311 o[p] = (27 >> (7 - b));
313 n++;
316 if (v == 128)
317 return -1; /* invalid character */
318 if (o)
319 o[p] |= (v << b);
320 b += 7;
321 if (b >= 8) {
322 b -= 8;
323 p++;
324 if (o)
325 o[p] = (v >> (7 - b));
327 if (++n >= SMSLEN)
328 return n;
330 return n;
333 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 8 bit character codes */
334 /* The return value is the number of bytes packed in to o, which is internally limited to 140 */
335 /* o can be null, in which case this is used to validate or count only */
336 /* if the input contains invalid characters then the return value is -1 */
337 static int packsms8 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
339 unsigned char p = 0;
341 /* header - no encoding */
342 if (udhl) {
343 if (o)
344 o[p++] = udhl;
345 while (udhl--) {
346 if (o)
347 o[p++] = *udh++;
348 if (p >= 140)
349 return p;
352 while (udl--) {
353 long u;
354 u = *ud++;
355 if (u < 0 || u > 0xFF)
356 return -1; /* not valid */
357 if (o)
358 o[p++] = u;
359 if (p >= 140)
360 return p;
362 return p;
365 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2
366 message (udl characters at ud) and packs in to o using 16 bit
367 UCS-2 character codes
368 The return value is the number of bytes packed in to o, which is
369 internally limited to 140
370 o can be null, in which case this is used to validate or count
371 only if the input contains invalid characters then
372 the return value is -1 */
373 static int packsms16 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
375 unsigned char p = 0;
376 /* header - no encoding */
377 if (udhl) {
378 if (o)
379 o[p++] = udhl;
380 while (udhl--) {
381 if (o)
382 o[p++] = *udh++;
383 if (p >= 140)
384 return p;
387 while (udl--) {
388 long u;
389 u = *ud++;
390 if (o)
391 o[p++] = (u >> 8);
392 if (p >= 140)
393 return p - 1; /* could not fit last character */
394 if (o)
395 o[p++] = u;
396 if (p >= 140)
397 return p;
399 return p;
402 /*! \brief general pack, with length and data,
403 returns number of bytes of target used */
404 static int packsms (unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
406 unsigned char *p = base;
407 if (udl) {
408 int l = 0;
409 if (is7bit (dcs)) { /* 7 bit */
410 l = packsms7 (p + 1, udhl, udh, udl, ud);
411 if (l < 0)
412 l = 0;
413 *p++ = l;
414 p += (l * 7 + 7) / 8;
415 } else if (is8bit (dcs)) { /* 8 bit */
416 l = packsms8 (p + 1, udhl, udh, udl, ud);
417 if (l < 0)
418 l = 0;
419 *p++ = l;
420 p += l;
421 } else { /* UCS-2 */
422 l = packsms16 (p + 1, udhl, udh, udl, ud);
423 if (l < 0)
424 l = 0;
425 *p++ = l;
426 p += l;
428 } else
429 *p++ = 0; /* no user data */
430 return p - base;
434 /*! \brief pack a date and return */
435 static void packdate (unsigned char *o, time_t w)
437 struct tm *t = localtime (&w);
438 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
439 int z = -t->tm_gmtoff / 60 / 15;
440 #else
441 int z = timezone / 60 / 15;
442 #endif
443 *o++ = ((t->tm_year % 10) << 4) + (t->tm_year % 100) / 10;
444 *o++ = (((t->tm_mon + 1) % 10) << 4) + (t->tm_mon + 1) / 10;
445 *o++ = ((t->tm_mday % 10) << 4) + t->tm_mday / 10;
446 *o++ = ((t->tm_hour % 10) << 4) + t->tm_hour / 10;
447 *o++ = ((t->tm_min % 10) << 4) + t->tm_min / 10;
448 *o++ = ((t->tm_sec % 10) << 4) + t->tm_sec / 10;
449 if (z < 0)
450 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
451 else
452 *o++ = ((z % 10) << 4) + z / 10;
455 /*! \brief unpack a date and return */
456 static time_t unpackdate (unsigned char *i)
458 struct tm t;
459 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
460 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
461 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
462 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
463 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
464 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
465 t.tm_isdst = 0;
466 if (i[6] & 0x08)
467 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
468 else
469 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
470 return ast_mktime(&t, NULL);
473 /*! \brief unpacks bytes (7 bit encoding) at i, len l septets,
474 and places in udh and ud setting udhl and udl. udh not used
475 if udhi not set */
476 static void unpacksms7 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
478 unsigned char b = 0, p = 0;
479 unsigned short *o = ud;
480 *udhl = 0;
481 if (udhi && l) { /* header */
482 int h = i[p];
483 *udhl = h;
484 if (h) {
485 b = 1;
486 p++;
487 l--;
488 while (h-- && l) {
489 *udh++ = i[p++];
490 b += 8;
491 while (b >= 7) {
492 b -= 7;
493 l--;
494 if (!l)
495 break;
498 /* adjust for fill, septets */
499 if (b) {
500 b = 7 - b;
501 l--;
505 while (l--) {
506 unsigned char v;
507 if (b < 2)
508 v = ((i[p] >> b) & 0x7F);
509 else
510 v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
511 b += 7;
512 if (b >= 8) {
513 b -= 8;
514 p++;
516 if (o > ud && o[-1] == 0x00A0 && escapes[v])
517 o[-1] = escapes[v];
518 else
519 *o++ = defaultalphabet[v];
521 *udl = (o - ud);
524 /*! \brief unpacks bytes (8 bit encoding) at i, len l septets,
525 and places in udh and ud setting udhl and udl. udh not used
526 if udhi not set */
527 static void unpacksms8 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
529 unsigned short *o = ud;
530 *udhl = 0;
531 if (udhi) {
532 int n = *i;
533 *udhl = n;
534 if (n) {
535 i++;
536 l--;
537 while (l && n) {
538 l--;
539 n--;
540 *udh++ = *i++;
544 while (l--)
545 *o++ = *i++; /* not to UTF-8 as explicitely 8 bit coding in DCS */
546 *udl = (o - ud);
549 /*! \brief unpacks bytes (16 bit encoding) at i, len l septets,
550 and places in udh and ud setting udhl and udl.
551 udh not used if udhi not set */
552 static void unpacksms16 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
554 unsigned short *o = ud;
555 *udhl = 0;
556 if (udhi) {
557 int n = *i;
558 *udhl = n;
559 if (n) {
560 i++;
561 l--;
562 while (l && n) {
563 l--;
564 n--;
565 *udh++ = *i++;
569 while (l--) {
570 int v = *i++;
571 if (l--)
572 v = (v << 8) + *i++;
573 *o++ = v;
575 *udl = (o - ud);
578 /*! \brief general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
579 static int unpacksms (unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
581 int l = *i++;
582 if (is7bit (dcs)) {
583 unpacksms7 (i, l, udh, udhl, ud, udl, udhi);
584 l = (l * 7 + 7) / 8; /* adjust length to return */
585 } else if (is8bit (dcs))
586 unpacksms8 (i, l, udh, udhl, ud, udl, udhi);
587 else
588 unpacksms16 (i, l, udh, udhl, ud, udl, udhi);
589 return l + 1;
592 /*! \brief unpack an address from i, return byte length, unpack to o */
593 static unsigned char unpackaddress (char *o, unsigned char *i)
595 unsigned char l = i[0],
597 if (i[1] == 0x91)
598 *o++ = '+';
599 for (p = 0; p < l; p++) {
600 if (p & 1)
601 *o++ = (i[2 + p / 2] >> 4) + '0';
602 else
603 *o++ = (i[2 + p / 2] & 0xF) + '0';
605 *o = 0;
606 return (l + 5) / 2;
609 /*! \brief store an address at o, and return number of bytes used */
610 static unsigned char packaddress (unsigned char *o, char *i)
612 unsigned char p = 2;
613 o[0] = 0;
614 if (*i == '+') {
615 i++;
616 o[1] = 0x91;
617 } else
618 o[1] = 0x81;
619 while (*i)
620 if (isdigit (*i)) {
621 if (o[0] & 1)
622 o[p++] |= ((*i & 0xF) << 4);
623 else
624 o[p] = (*i & 0xF);
625 o[0]++;
626 i++;
627 } else
628 i++;
629 if (o[0] & 1)
630 o[p++] |= 0xF0; /* pad */
631 return p;
634 /*! \brief Log the output, and remove file */
635 static void sms_log (sms_t * h, char status)
637 if (*h->oa || *h->da) {
638 int o = open (log_file, O_CREAT | O_APPEND | O_WRONLY, 0666);
639 if (o >= 0) {
640 char line[1000], mrs[3] = "", *p;
641 unsigned char n;
643 if (h->mr >= 0)
644 snprintf (mrs, sizeof (mrs), "%02X", h->mr);
645 snprintf (line, sizeof (line), "%s %c%c%c%s %s %s %s ",
646 isodate (time (0)), status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue, *h->oa ? h->oa : "-",
647 *h->da ? h->da : "-");
648 p = line + strlen (line);
649 for (n = 0; n < h->udl; n++)
650 if (h->ud[n] == '\\') {
651 *p++ = '\\';
652 *p++ = '\\';
653 } else if (h->ud[n] == '\n') {
654 *p++ = '\\';
655 *p++ = 'n';
656 } else if (h->ud[n] == '\r') {
657 *p++ = '\\';
658 *p++ = 'r';
659 } else if (h->ud[n] < 32 || h->ud[n] == 127)
660 *p++ = 191;
661 else
662 *p++ = h->ud[n];
663 *p++ = '\n';
664 *p = 0;
665 write (o, line, strlen (line));
666 close (o);
668 *h->oa = *h->da = h->udl = 0;
672 /*! \brief parse and delete a file */
673 static void sms_readfile (sms_t * h, char *fn)
675 char line[1000];
676 FILE *s;
677 char dcsset = 0; /* if DSC set */
678 ast_log (LOG_EVENT, "Sending %s\n", fn);
679 h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
680 h->mr = -1;
681 h->dcs = 0xF1; /* normal messages class 1 */
682 h->scts = time (0);
683 s = fopen (fn, "r");
684 if (s)
686 if (unlink (fn))
687 { /* concurrent access, we lost */
688 fclose (s);
689 return;
691 while (fgets (line, sizeof (line), s))
692 { /* process line in file */
693 char *p;
694 void *pp = &p;
695 for (p = line; *p && *p != '\n' && *p != '\r'; p++);
696 *p = 0; /* strip eoln */
697 p = line;
698 if (!*p || *p == ';')
699 continue; /* blank line or comment, ignore */
700 while (isalnum (*p))
702 *p = tolower (*p);
703 p++;
705 while (isspace (*p))
706 *p++ = 0;
707 if (*p == '=')
709 *p++ = 0;
710 if (!strcmp (line, "ud"))
711 { /* parse message (UTF-8) */
712 unsigned char o = 0;
713 while (*p && o < SMSLEN)
714 h->ud[o++] = utf8decode(pp);
715 h->udl = o;
716 if (*p)
717 ast_log (LOG_WARNING, "UD too long in %s\n", fn);
718 } else
720 while (isspace (*p))
721 p++;
722 if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
723 numcpy (h->oa, p);
724 else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
725 numcpy (h->da, p);
726 else if (!strcmp (line, "pid"))
727 h->pid = atoi (p);
728 else if (!strcmp (line, "dcs"))
730 h->dcs = atoi (p);
731 dcsset = 1;
732 } else if (!strcmp (line, "mr"))
733 h->mr = atoi (p);
734 else if (!strcmp (line, "srr"))
735 h->srr = (atoi (p) ? 1 : 0);
736 else if (!strcmp (line, "vp"))
737 h->vp = atoi (p);
738 else if (!strcmp (line, "rp"))
739 h->rp = (atoi (p) ? 1 : 0);
740 else if (!strcmp (line, "scts"))
741 { /* get date/time */
742 int Y,
748 if (sscanf (p, "%d-%d-%dT%d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6)
750 struct tm t;
751 t.tm_year = Y - 1900;
752 t.tm_mon = m - 1;
753 t.tm_mday = d;
754 t.tm_hour = H;
755 t.tm_min = M;
756 t.tm_sec = S;
757 t.tm_isdst = -1;
758 h->scts = ast_mktime(&t, NULL);
759 if (h->scts == (time_t) - 1)
760 ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
762 } else
763 ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
765 } else if (*p == '#')
766 { /* raw hex format */
767 *p++ = 0;
768 if (*p == '#')
770 p++;
771 if (!strcmp (line, "ud"))
772 { /* user data */
773 int o = 0;
774 while (*p && o < SMSLEN)
776 if (isxdigit (*p) && isxdigit (p[1]) && isxdigit (p[2]) && isxdigit (p[3]))
778 h->ud[o++] =
779 (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 12) +
780 (((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
781 (((isalpha (p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha (p[3]) ? 9 : 0) + (p[3] & 0xF));
782 p += 4;
783 } else
784 break;
786 h->udl = o;
787 if (*p)
788 ast_log (LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
789 } else
790 ast_log (LOG_WARNING, "Only ud can use ## format, %s\n", fn);
791 } else if (!strcmp (line, "ud"))
792 { /* user data */
793 int o = 0;
794 while (*p && o < SMSLEN)
796 if (isxdigit (*p) && isxdigit (p[1]))
798 h->ud[o++] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
799 p += 2;
800 } else
801 break;
803 h->udl = o;
804 if (*p)
805 ast_log (LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
806 } else if (!strcmp (line, "udh"))
807 { /* user data header */
808 unsigned char o = 0;
809 h->udhi = 1;
810 while (*p && o < SMSLEN)
812 if (isxdigit (*p) && isxdigit (p[1]))
814 h->udh[o] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
815 o++;
816 p += 2;
817 } else
818 break;
820 h->udhl = o;
821 if (*p)
822 ast_log (LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
823 } else
824 ast_log (LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
825 } else
826 ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
828 fclose (s);
829 if (!dcsset && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
831 if (packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
833 if (packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
834 ast_log (LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
835 else
837 h->dcs = 0x08; /* default to 16 bit */
838 ast_log (LOG_WARNING, "Sending in 16 bit format (%s)\n", fn);
840 } else
842 h->dcs = 0xF5; /* default to 8 bit */
843 ast_log (LOG_WARNING, "Sending in 8 bit format (%s)\n", fn);
846 if (is7bit (h->dcs) && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
847 ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
848 if (is8bit (h->dcs) && packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
849 ast_log (LOG_WARNING, "Invalid 8 bit data %s\n", fn);
850 if (is16bit (h->dcs) && packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
851 ast_log (LOG_WARNING, "Invalid 16 bit data %s\n", fn);
855 /*! \brief white a received text message to a file */
856 static void sms_writefile (sms_t * h)
858 char fn[200] = "", fn2[200] = "";
859 FILE *o;
860 ast_copy_string (fn, spool_dir, sizeof (fn));
861 mkdir (fn, 0777); /* ensure it exists */
862 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
863 mkdir (fn, 0777); /* ensure it exists */
864 ast_copy_string (fn2, fn, sizeof (fn2));
865 snprintf (fn2 + strlen (fn2), sizeof (fn2) - strlen (fn2), "/%s.%s-%d", h->queue, isodate (h->scts), seq++);
866 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/.%s", fn2 + strlen (fn) + 1);
867 o = fopen (fn, "w");
868 if (o) {
869 if (*h->oa)
870 fprintf (o, "oa=%s\n", h->oa);
871 if (*h->da)
872 fprintf (o, "da=%s\n", h->da);
873 if (h->udhi) {
874 unsigned int p;
875 fprintf (o, "udh#");
876 for (p = 0; p < h->udhl; p++)
877 fprintf (o, "%02X", h->udh[p]);
878 fprintf (o, "\n");
880 if (h->udl) {
881 unsigned int p;
882 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
883 if (p < h->udl)
884 fputc (';', o); /* cannot use ud=, but include as a comment for human readable */
885 fprintf (o, "ud=");
886 for (p = 0; p < h->udl; p++) {
887 unsigned short v = h->ud[p];
888 if (v < 32)
889 fputc (191, o);
890 else if (v < 0x80)
891 fputc (v, o);
892 else if (v < 0x800)
894 fputc (0xC0 + (v >> 6), o);
895 fputc (0x80 + (v & 0x3F), o);
896 } else
898 fputc (0xE0 + (v >> 12), o);
899 fputc (0x80 + ((v >> 6) & 0x3F), o);
900 fputc (0x80 + (v & 0x3F), o);
903 fprintf (o, "\n");
904 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
905 if (p < h->udl) {
906 for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
907 if (p == h->udl) { /* can write in ucs-1 hex */
908 fprintf (o, "ud#");
909 for (p = 0; p < h->udl; p++)
910 fprintf (o, "%02X", h->ud[p]);
911 fprintf (o, "\n");
912 } else { /* write in UCS-2 */
913 fprintf (o, "ud##");
914 for (p = 0; p < h->udl; p++)
915 fprintf (o, "%04X", h->ud[p]);
916 fprintf (o, "\n");
920 if (h->scts)
921 fprintf (o, "scts=%s\n", isodate (h->scts));
922 if (h->pid)
923 fprintf (o, "pid=%d\n", h->pid);
924 if (h->dcs != 0xF1)
925 fprintf (o, "dcs=%d\n", h->dcs);
926 if (h->vp)
927 fprintf (o, "vp=%d\n", h->vp);
928 if (h->srr)
929 fprintf (o, "srr=1\n");
930 if (h->mr >= 0)
931 fprintf (o, "mr=%d\n", h->mr);
932 if (h->rp)
933 fprintf (o, "rp=1\n");
934 fclose (o);
935 if (rename (fn, fn2))
936 unlink (fn);
937 else
938 ast_log (LOG_EVENT, "Received to %s\n", fn2);
942 /*! \brief read dir skipping dot files... */
943 static struct dirent *readdirqueue (DIR * d, char *queue)
945 struct dirent *f;
946 do {
947 f = readdir (d);
948 } while (f && (*f->d_name == '.' || strncmp (f->d_name, queue, strlen (queue)) || f->d_name[strlen (queue)] != '.'));
949 return f;
952 /*! \brief handle the incoming message */
953 static unsigned char sms_handleincoming (sms_t * h)
955 unsigned char p = 3;
956 if (h->smsc) { /* SMSC */
957 if ((h->imsg[2] & 3) == 1) { /* SMS-SUBMIT */
958 h->udhl = h->udl = 0;
959 h->vp = 0;
960 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
961 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
962 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
963 ast_copy_string (h->oa, h->cli, sizeof (h->oa));
964 h->scts = time (0);
965 h->mr = h->imsg[p++];
966 p += unpackaddress (h->da, h->imsg + p);
967 h->pid = h->imsg[p++];
968 h->dcs = h->imsg[p++];
969 if ((h->imsg[2] & 0x18) == 0x10) { /* relative VP */
970 if (h->imsg[p] < 144)
971 h->vp = (h->imsg[p] + 1) * 5;
972 else if (h->imsg[p] < 168)
973 h->vp = 720 + (h->imsg[p] - 143) * 30;
974 else if (h->imsg[p] < 197)
975 h->vp = (h->imsg[p] - 166) * 1440;
976 else
977 h->vp = (h->imsg[p] - 192) * 10080;
978 p++;
979 } else if (h->imsg[2] & 0x18)
980 p += 7; /* ignore enhanced / absolute VP */
981 p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
982 h->rx = 1; /* received message */
983 sms_writefile (h); /* write the file */
984 if (p != h->imsg[1] + 2) {
985 ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
986 return 0xFF; /* duh! */
988 } else {
989 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
990 return 0xFF;
992 } else { /* client */
993 if (!(h->imsg[2] & 3)) { /* SMS-DELIVER */
994 *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
995 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
996 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
997 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
998 h->mr = -1;
999 p += unpackaddress (h->oa, h->imsg + p);
1000 h->pid = h->imsg[p++];
1001 h->dcs = h->imsg[p++];
1002 h->scts = unpackdate (h->imsg + p);
1003 p += 7;
1004 p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1005 h->rx = 1; /* received message */
1006 sms_writefile (h); /* write the file */
1007 if (p != h->imsg[1] + 2) {
1008 ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1009 return 0xFF; /* duh! */
1011 } else {
1012 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
1013 return 0xFF;
1016 return 0; /* no error */
1019 #ifdef SOLARIS
1020 #define NAME_MAX 1024
1021 #endif
1023 /*! \brief find and fill in next message, or send a REL if none waiting */
1024 static void sms_nextoutgoing (sms_t * h)
1026 char fn[100 + NAME_MAX] = "";
1027 DIR *d;
1028 char more = 0;
1029 ast_copy_string (fn, spool_dir, sizeof (fn));
1030 mkdir (fn, 0777); /* ensure it exists */
1031 h->rx = 0; /* outgoing message */
1032 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? "mttx" : "motx");
1033 mkdir (fn, 0777); /* ensure it exists */
1034 d = opendir (fn);
1035 if (d) {
1036 struct dirent *f = readdirqueue (d, h->queue);
1037 if (f) {
1038 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", f->d_name);
1039 sms_readfile (h, fn);
1040 if (readdirqueue (d, h->queue))
1041 more = 1; /* more to send */
1043 closedir (d);
1045 if (*h->da || *h->oa) { /* message to send */
1046 unsigned char p = 2;
1047 h->omsg[0] = 0x91; /* SMS_DATA */
1048 if (h->smsc) { /* deliver */
1049 h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
1050 p += packaddress (h->omsg + p, h->oa);
1051 h->omsg[p++] = h->pid;
1052 h->omsg[p++] = h->dcs;
1053 packdate (h->omsg + p, h->scts);
1054 p += 7;
1055 p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1056 } else { /* submit */
1057 h->omsg[p++] =
1058 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
1059 if (h->mr < 0)
1060 h->mr = message_ref++;
1061 h->omsg[p++] = h->mr;
1062 p += packaddress (h->omsg + p, h->da);
1063 h->omsg[p++] = h->pid;
1064 h->omsg[p++] = h->dcs;
1065 if (h->vp) { /* relative VP */
1066 if (h->vp < 720)
1067 h->omsg[p++] = (h->vp + 4) / 5 - 1;
1068 else if (h->vp < 1440)
1069 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
1070 else if (h->vp < 43200)
1071 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
1072 else if (h->vp < 635040)
1073 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
1074 else
1075 h->omsg[p++] = 255; /* max */
1077 p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1079 h->omsg[1] = p - 2;
1080 sms_messagetx (h);
1081 } else { /* no message */
1082 h->omsg[0] = 0x94; /* SMS_REL */
1083 h->omsg[1] = 0;
1084 sms_messagetx (h);
1088 static void sms_debug (char *dir, unsigned char *msg)
1090 char txt[259 * 3 + 1],
1091 *p = txt; /* always long enough */
1092 int n = msg[1] + 3,
1093 q = 0;
1094 while (q < n && q < 30) {
1095 sprintf (p, " %02X", msg[q++]);
1096 p += 3;
1098 if (q < n)
1099 sprintf (p, "...");
1100 if (option_verbose > 2)
1101 ast_verbose (VERBOSE_PREFIX_3 "SMS %s%s\n", dir, txt);
1104 static void sms_messagerx(sms_t * h)
1106 sms_debug ("RX", h->imsg);
1107 /* testing */
1108 switch (h->imsg[0]) {
1109 case 0x91: /* SMS_DATA */
1111 unsigned char cause = sms_handleincoming (h);
1112 if (!cause) {
1113 sms_log (h, 'Y');
1114 h->omsg[0] = 0x95; /* SMS_ACK */
1115 h->omsg[1] = 0x02;
1116 h->omsg[2] = 0x00; /* deliver report */
1117 h->omsg[3] = 0x00; /* no parameters */
1118 } else { /* NACK */
1119 sms_log (h, 'N');
1120 h->omsg[0] = 0x96; /* SMS_NACK */
1121 h->omsg[1] = 3;
1122 h->omsg[2] = 0; /* delivery report */
1123 h->omsg[3] = cause; /* cause */
1124 h->omsg[4] = 0; /* no parameters */
1126 sms_messagetx (h);
1128 break;
1129 case 0x92: /* SMS_ERROR */
1130 h->err = 1;
1131 sms_messagetx (h); /* send whatever we sent again */
1132 break;
1133 case 0x93: /* SMS_EST */
1134 sms_nextoutgoing (h);
1135 break;
1136 case 0x94: /* SMS_REL */
1137 h->hangup = 1; /* hangup */
1138 break;
1139 case 0x95: /* SMS_ACK */
1140 sms_log (h, 'Y');
1141 sms_nextoutgoing (h);
1142 break;
1143 case 0x96: /* SMS_NACK */
1144 h->err = 1;
1145 sms_log (h, 'N');
1146 sms_nextoutgoing (h);
1147 break;
1148 default: /* Unknown */
1149 h->omsg[0] = 0x92; /* SMS_ERROR */
1150 h->omsg[1] = 1;
1151 h->omsg[2] = 3; /* unknown message type; */
1152 sms_messagetx (h);
1153 break;
1157 static void sms_messagetx(sms_t * h)
1159 unsigned char c = 0, p;
1160 for (p = 0; p < h->omsg[1] + 2; p++)
1161 c += h->omsg[p];
1162 h->omsg[h->omsg[1] + 2] = 0 - c;
1163 sms_debug ("TX", h->omsg);
1164 h->obyte = 1;
1165 h->opause = 200;
1166 if (h->omsg[0] == 0x93)
1167 h->opause = 2400; /* initial message delay 300ms (for BT) */
1168 h->obytep = 0;
1169 h->obitp = 0;
1170 h->osync = 80;
1171 h->obyten = h->omsg[1] + 3;
1174 static int sms_generate (struct ast_channel *chan, void *data, int len, int samples)
1176 struct ast_frame f = { 0 };
1177 #define MAXSAMPLES (800)
1178 #ifdef OUTALAW
1179 unsigned char *buf;
1180 #else
1181 short *buf;
1182 #endif
1183 #define SAMPLE2LEN sizeof(*buf)
1184 sms_t *h = data;
1185 int i;
1187 if (samples > MAXSAMPLES) {
1188 ast_log (LOG_WARNING, "Only doing %d samples (%d requested)\n",
1189 MAXSAMPLES, samples);
1190 samples = MAXSAMPLES;
1192 len = samples * SAMPLE2LEN + AST_FRIENDLY_OFFSET;
1193 buf = alloca(len);
1195 f.frametype = AST_FRAME_VOICE;
1196 #ifdef OUTALAW
1197 f.subclass = AST_FORMAT_ALAW;
1198 #else
1199 f.subclass = AST_FORMAT_SLINEAR;
1200 #endif
1201 f.datalen = samples * SAMPLE2LEN;
1202 f.offset = AST_FRIENDLY_OFFSET;
1203 f.mallocd = 0;
1204 f.data = buf;
1205 f.samples = samples;
1206 f.src = "app_sms";
1207 /* create a buffer containing the digital sms pattern */
1208 for (i = 0; i < samples; i++) {
1209 #ifdef OUTALAW
1210 buf[i] = wavea[0];
1211 #else
1212 buf[i] = wave[0];
1213 #endif
1214 if (h->opause)
1215 h->opause--;
1216 else if (h->obyten || h->osync) { /* sending data */
1217 #ifdef OUTALAW
1218 buf[i] = wavea[h->ophase];
1219 #else
1220 buf[i] = wave[h->ophase];
1221 #endif
1222 if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
1223 h->ophase -= 80;
1224 if ((h->ophasep += 12) >= 80) { /* next bit */
1225 h->ophasep -= 80;
1226 if (h->osync)
1227 h->osync--; /* sending sync bits */
1228 else {
1229 h->obyte >>= 1;
1230 h->obitp++;
1231 if (h->obitp == 1)
1232 h->obyte = 0; /* start bit; */
1233 else if (h->obitp == 2)
1234 h->obyte = h->omsg[h->obytep];
1235 else if (h->obitp == 10) {
1236 h->obyte = 1; /* stop bit */
1237 h->obitp = 0;
1238 h->obytep++;
1239 if (h->obytep == h->obyten) {
1240 h->obytep = h->obyten = 0; /* sent */
1241 h->osync = 10; /* trailing marks */
1248 if (ast_write (chan, &f) < 0) {
1249 ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
1250 return -1;
1252 return 0;
1253 #undef SAMPLE2LEN
1254 #undef MAXSAMPLES
1257 static void sms_process (sms_t * h, int samples, signed short *data)
1259 if (h->obyten || h->osync)
1260 return; /* sending */
1261 while (samples--) {
1262 unsigned long long m0, m1;
1263 if (abs (*data) > h->imag)
1264 h->imag = abs (*data);
1265 else
1266 h->imag = h->imag * 7 / 8;
1267 if (h->imag > 500) {
1268 h->idle = 0;
1269 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
1270 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
1271 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
1272 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
1273 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
1274 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
1275 if ((h->ips0 += 21) >= 80)
1276 h->ips0 -= 80;
1277 if ((h->ipc0 += 21) >= 80)
1278 h->ipc0 -= 80;
1279 if ((h->ips1 += 13) >= 80)
1280 h->ips1 -= 80;
1281 if ((h->ipc1 += 13) >= 80)
1282 h->ipc1 -= 80;
1284 char bit;
1285 h->ibith <<= 1;
1286 if (m1 > m0)
1287 h->ibith |= 1;
1288 if (h->ibith & 8)
1289 h->ibitt--;
1290 if (h->ibith & 1)
1291 h->ibitt++;
1292 bit = ((h->ibitt > 1) ? 1 : 0);
1293 if (bit != h->ibitl)
1294 h->ibitc = 1;
1295 else
1296 h->ibitc++;
1297 h->ibitl = bit;
1298 if (!h->ibitn && h->ibitc == 4 && !bit) {
1299 h->ibitn = 1;
1300 h->iphasep = 0;
1302 if (bit && h->ibitc == 200) { /* sync, restart message */
1303 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1305 if (h->ibitn) {
1306 h->iphasep += 12;
1307 if (h->iphasep >= 80) { /* next bit */
1308 h->iphasep -= 80;
1309 if (h->ibitn++ == 9) { /* end of byte */
1310 if (!bit) /* bad stop bit */
1311 h->ierr = 0xFF; /* unknown error */
1312 else {
1313 if (h->ibytep < sizeof (h->imsg)) {
1314 h->imsg[h->ibytep] = h->ibytev;
1315 h->ibytec += h->ibytev;
1316 h->ibytep++;
1317 } else if (h->ibytep == sizeof (h->imsg))
1318 h->ierr = 2; /* bad message length */
1319 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
1320 if (!h->ibytec)
1321 sms_messagerx (h);
1322 else
1323 h->ierr = 1; /* bad checksum */
1326 h->ibitn = 0;
1328 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1332 } else { /* lost carrier */
1333 if (h->idle++ == 80000) { /* nothing happening */
1334 ast_log (LOG_EVENT, "No data, hanging up\n");
1335 h->hangup = 1;
1336 h->err = 1;
1338 if (h->ierr) { /* error */
1339 h->err = 1;
1340 h->omsg[0] = 0x92; /* error */
1341 h->omsg[1] = 1;
1342 h->omsg[2] = h->ierr;
1343 sms_messagetx (h); /* send error */
1345 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1347 data++;
1351 static struct ast_generator smsgen = {
1352 alloc:sms_alloc,
1353 release:sms_release,
1354 generate:sms_generate,
1357 static int sms_exec (struct ast_channel *chan, void *data)
1359 int res = -1;
1360 struct ast_module_user *u;
1361 struct ast_frame *f;
1362 sms_t h = { 0 };
1364 u = ast_module_user_add(chan);
1366 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1367 h.dcs = 0xF1; /* default */
1368 if (!data) {
1369 ast_log (LOG_ERROR, "Requires queue name at least\n");
1370 ast_module_user_remove(u);
1371 return -1;
1374 if (chan->cid.cid_num)
1375 ast_copy_string (h.cli, chan->cid.cid_num, sizeof (h.cli));
1378 unsigned char *p;
1379 unsigned char *d = data,
1380 answer = 0;
1381 if (!*d || *d == '|') {
1382 ast_log (LOG_ERROR, "Requires queue name\n");
1383 ast_module_user_remove(u);
1384 return -1;
1386 for (p = d; *p && *p != '|'; p++);
1387 if (p - d >= sizeof (h.queue)) {
1388 ast_log (LOG_ERROR, "Queue name too long\n");
1389 ast_module_user_remove(u);
1390 return -1;
1392 strncpy(h.queue, (char *)d, p - d);
1393 if (*p == '|')
1394 p++;
1395 d = p;
1396 for (p = (unsigned char *)h.queue; *p; p++)
1397 if (!isalnum (*p))
1398 *p = '-'; /* make very safe for filenames */
1399 while (*d && *d != '|') {
1400 switch (*d) {
1401 case 'a': /* we have to send the initial FSK sequence */
1402 answer = 1;
1403 break;
1404 case 's': /* we are acting as a service centre talking to a phone */
1405 h.smsc = 1;
1406 break;
1407 /* the following apply if there is an arg3/4 and apply to the created message file */
1408 case 'r':
1409 h.srr = 1;
1410 break;
1411 case 'o':
1412 h.dcs |= 4; /* octets */
1413 break;
1414 case '1':
1415 case '2':
1416 case '3':
1417 case '4':
1418 case '5':
1419 case '6':
1420 case '7': /* set the pid for saved local message */
1421 h.pid = 0x40 + (*d & 0xF);
1422 break;
1424 d++;
1426 if (*d == '|') {
1427 /* submitting a message, not taking call. */
1428 /* deprecated, use smsq instead */
1429 d++;
1430 h.scts = time (0);
1431 for (p = d; *p && *p != '|'; p++);
1432 if (*p)
1433 *p++ = 0;
1434 if (strlen ((char *)d) >= sizeof (h.oa)) {
1435 ast_log (LOG_ERROR, "Address too long %s\n", d);
1436 return 0;
1438 if (h.smsc) {
1439 ast_copy_string (h.oa, (char *)d, sizeof (h.oa));
1440 } else {
1441 ast_copy_string (h.da, (char *)d, sizeof (h.da));
1443 if (!h.smsc)
1444 ast_copy_string (h.oa, h.cli, sizeof (h.oa));
1445 d = p;
1446 h.udl = 0;
1447 while (*p && h.udl < SMSLEN)
1448 h.ud[h.udl++] = utf8decode(&p);
1449 if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1450 ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n");
1451 if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1452 ast_log (LOG_WARNING, "Invalid 8 bit data\n");
1453 if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1454 ast_log (LOG_WARNING, "Invalid 16 bit data\n");
1455 h.rx = 0; /* sent message */
1456 h.mr = -1;
1457 sms_writefile (&h);
1458 ast_module_user_remove(u);
1459 return 0;
1462 if (answer) {
1463 /* set up SMS_EST initial message */
1464 h.omsg[0] = 0x93;
1465 h.omsg[1] = 0;
1466 sms_messagetx (&h);
1470 if (chan->_state != AST_STATE_UP)
1471 ast_answer (chan);
1473 #ifdef OUTALAW
1474 res = ast_set_write_format (chan, AST_FORMAT_ALAW);
1475 #else
1476 res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
1477 #endif
1478 if (res >= 0)
1479 res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
1480 if (res < 0) {
1481 ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
1482 ast_module_user_remove(u);
1483 return -1;
1486 if (ast_activate_generator (chan, &smsgen, &h) < 0) {
1487 ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
1488 ast_module_user_remove(u);
1489 return -1;
1492 /* Do our thing here */
1493 while (ast_waitfor (chan, -1) > -1 && !h.hangup)
1495 f = ast_read (chan);
1496 if (!f)
1497 break;
1498 if (f->frametype == AST_FRAME_VOICE) {
1499 sms_process (&h, f->samples, f->data);
1502 ast_frfree (f);
1505 sms_log (&h, '?'); /* log incomplete message */
1507 ast_module_user_remove(u);
1508 return (h.err);
1511 static int unload_module(void)
1513 int res;
1515 res = ast_unregister_application (app);
1517 ast_module_user_hangup_all();
1519 return res;
1522 static int load_module(void)
1524 #ifdef OUTALAW
1526 int p;
1527 for (p = 0; p < 80; p++)
1528 wavea[p] = AST_LIN2A (wave[p]);
1530 #endif
1531 snprintf (log_file, sizeof (log_file), "%s/sms", ast_config_AST_LOG_DIR);
1532 snprintf (spool_dir, sizeof (spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
1533 return ast_register_application (app, sms_exec, synopsis, descrip);
1536 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SMS/PSTN handler");