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