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