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