Optionally display the value of several variables within the Status command.
[asterisk-bristuff.git] / apps / app_sms.c
blob0272468d60e9ca61ea4264103bfd6f222c30eed9
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2004 - 2005, Adrian Kennard, rights assigned to Digium
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
17 /*! \file
19 * \brief SMS application - ETSI ES 201 912 protocol 1 implementation
21 * \par Development notes
22 * \note The ETSI standards are available free of charge from ETSI at
23 * http://pda.etsi.org/pda/queryform.asp
24 * Among the relevant documents here we have:
26 * ES 201 912 SMS for PSTN/ISDN
27 * TS 123 040 Technical realization of SMS
30 * \ingroup applications
32 * \author Adrian Kennard (for the original protocol 1 code)
33 * \author Filippo Grassilli (Hyppo) - protocol 2 support
34 * Not fully tested, under development
37 #include "asterisk.h"
39 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
41 #include <dirent.h>
42 #include <ctype.h>
43 #include <sys/stat.h>
45 #include "asterisk/paths.h" /* use ast_config_AST_SPOOL_DIR and LOG_DIR */
46 #include "asterisk/lock.h"
47 #include "asterisk/file.h"
48 #include "asterisk/channel.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/module.h"
51 #include "asterisk/alaw.h"
52 #include "asterisk/callerid.h"
53 #include "asterisk/utils.h"
54 #include "asterisk/app.h"
56 /* #define OUTALAW */ /* enable this to output Alaw rather than linear */
58 /* ToDo */
59 /* Add full VP support */
60 /* Handle status report messages (generation and reception) */
61 /* Time zones on time stamps */
62 /* user ref field */
64 static volatile unsigned char message_ref; /* arbitary message ref */
65 static volatile unsigned int seq; /* arbitrary message sequence number for unqiue files */
67 static char log_file[255];
69 static char *app = "SMS";
71 static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
73 static char *descrip =
74 " SMS(name,[a][s][t][p(d)][r][o],addr,body):\n"
75 "SMS handles exchange of SMS data with a call to/from SMS capable\n"
76 "phone or SMS PSTN service center. Can send and/or receive SMS messages.\n"
77 "Works to ETSI ES 201 912; compatible with BT SMS PSTN service in UK\n"
78 "and Telecom Italia in Italy.\n"
79 "Typical usage is to use to handle calls from the SMS service centre CLI,\n"
80 "or to set up a call using 'outgoing' or manager interface to connect\n"
81 "service centre to SMS()\n"
82 "name is the name of the queue used in /var/spool/asterisk/sms\n"
83 "Arguments:\n"
84 " a - answer, i.e. send initial FSK packet.\n"
85 " s - act as service centre talking to a phone.\n"
86 " t - use protocol 2 (default used is protocol 1).\n"
87 " p(N) - set the initial delay to N ms (default is 300).\n"
88 " addr and body are a deprecated format to send messages out.\n"
89 " s - set the Status Report Request (SRR) bit.\n"
90 " o - the body should be coded as octets not 7-bit symbols.\n"
91 "Messages are processed as per text file message queues.\n"
92 "smsq (a separate software) is a command to generate message\n"
93 "queues and send messages.\n"
94 "NOTE: the protocol has tight delay bounds. Please use short frames\n"
95 "and disable/keep short the jitter buffer on the ATA to make sure that\n"
96 "respones (ACK etc.) are received in time.\n";
99 * 80 samples of a single period of the wave. At 8000 Hz, it means these
100 * are the samples of a 100 Hz signal.
101 * To pick the two carriers (1300Hz for '1' and 2100 Hz for '0') used by
102 * the modulation, we should take one every 13 and 21 samples respectively.
104 static signed short wave[] = {
105 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
106 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
107 0, -392, -782, -1167,
108 -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
109 -4985, -4938, -4862,
110 -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
113 #ifdef OUTALAW
114 static unsigned char wavea[80];
115 typedef unsigned char output_t;
116 static const output_t *wave_out = wavea; /* outgoing samples */
117 #define __OUT_FMT AST_FORMAT_ALAW;
118 #else
119 typedef signed short output_t;
120 static const output_t *wave_out = wave; /* outgoing samples */
121 #define __OUT_FMT AST_FORMAT_SLINEAR
122 #endif
124 #define OSYNC_BITS 80 /* initial sync bits */
127 * The SMS spec ETSI ES 201 912 defines two protocols with different message types.
128 * Also note that the high bit is used to indicate whether the message
129 * is complete or not, but in two opposite ways:
130 * for Protocol 1, 0x80 means that the message is complete;
131 * for Protocol 2, 0x00 means that the message is complete;
133 enum message_types {
134 DLL_SMS_MASK = 0x7f, /* mask for the valid bits */
136 /* Protocol 1 values */
137 DLL1_SMS_DATA = 0x11, /* data packet */
138 DLL1_SMS_ERROR = 0x12,
139 DLL1_SMS_EST = 0x13, /* start the connection */
140 DLL1_SMS_REL = 0x14, /* end the connection */
141 DLL1_SMS_ACK = 0x15,
142 DLL1_SMS_NACK = 0x16,
144 DLL1_SMS_COMPLETE = 0x80, /* packet is complete */
145 DLL1_SMS_MORE = 0x00, /* more data to follow */
147 /* Protocol 2 values */
148 DLL2_SMS_EST = 0x7f, /* magic number. No message body */
149 DLL2_SMS_INFO_MO = 0x10,
150 DLL2_SMS_INFO_MT = 0x11,
151 DLL2_SMS_INFO_STA = 0x12,
152 DLL2_SMS_NACK = 0x13,
153 DLL2_SMS_ACK0 = 0x14, /* ack even-numbered frame */
154 DLL2_SMS_ACK1 = 0x15, /* ack odd-numbered frame */
155 DLL2_SMS_ENQ = 0x16,
156 DLL2_SMS_REL = 0x17, /* end the connection */
158 DLL2_SMS_COMPLETE = 0x00, /* packet is complete */
159 DLL2_SMS_MORE = 0x80, /* more data to follow */
162 /* SMS 7 bit character mapping to UCS-2 */
163 static const unsigned short defaultalphabet[] = {
164 0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
165 0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
166 0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
167 0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
168 ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
169 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
170 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
171 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
172 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
173 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
176 static const unsigned short escapes[] = {
177 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
178 0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
179 0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
180 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
181 0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
182 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
183 0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
184 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
187 #define SMSLEN 160 /*!< max SMS length */
188 #define SMSLEN_8 140 /*!< max SMS length for 8-bit char */
190 typedef struct sms_s {
191 unsigned char hangup; /*!< we are done... */
192 unsigned char err; /*!< set for any errors */
193 unsigned char smsc:1; /*!< we are SMSC */
194 unsigned char rx:1; /*!< this is a received message */
195 char queue[30]; /*!< queue name */
196 char oa[20]; /*!< originating address */
197 char da[20]; /*!< destination address */
198 struct timeval scts; /*!< time stamp, UTC */
199 unsigned char pid; /*!< protocol ID */
200 unsigned char dcs; /*!< data coding scheme */
201 short mr; /*!< message reference - actually a byte, but use -1 for not set */
202 int udl; /*!< user data length */
203 int udhl; /*!< user data header length */
204 unsigned char srr:1; /*!< Status Report request */
205 unsigned char udhi:1; /*!< User Data Header required, even if length 0 */
206 unsigned char rp:1; /*!< Reply Path */
207 unsigned int vp; /*!< validity period in minutes, 0 for not set */
208 unsigned short ud[SMSLEN]; /*!< user data (message), UCS-2 coded */
209 unsigned char udh[SMSLEN]; /*!< user data header */
210 char cli[20]; /*!< caller ID */
211 unsigned char ophase; /*!< phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
212 unsigned char ophasep; /*!< phase (0-79) for 1200 bps */
213 unsigned char obyte; /*!< byte being sent */
214 unsigned int opause; /*!< silent pause before sending (in sample periods) */
215 unsigned char obitp; /*!< bit in byte */
216 unsigned char osync; /*!< sync bits to send */
217 unsigned char obytep; /*!< byte in data */
218 unsigned char obyten; /*!< bytes in data */
219 unsigned char omsg[256]; /*!< data buffer (out) */
220 unsigned char imsg[250]; /*!< data buffer (in) */
221 signed long long ims0,
222 imc0,
223 ims1,
224 imc1; /*!< magnitude averages sin/cos 0/1 */
225 unsigned int idle;
226 unsigned short imag; /*!< signal level */
227 unsigned char ips0; /*!< phase sin for bit 0, start at 0 inc by 21 mod 80 */
228 unsigned char ips1; /*!< phase cos for bit 0, start at 20 inc by 21 mod 80 */
229 unsigned char ipc0; /*!< phase sin for bit 1, start at 0 inc by 13 mod 80 */
230 unsigned char ipc1; /*!< phase cos for bit 1, start at 20 inc by 13 mod 80 */
231 unsigned char ibitl; /*!< last bit */
232 unsigned char ibitc; /*!< bit run length count */
233 unsigned char iphasep; /*!< bit phase (0-79) for 1200 bps */
234 unsigned char ibitn; /*!< bit number in byte being received */
235 unsigned char ibytev; /*!< byte value being received */
236 unsigned char ibytep; /*!< byte pointer in message */
237 unsigned char ibytec; /*!< byte checksum for message */
238 unsigned char ierr; /*!< error flag */
239 unsigned char ibith; /*!< history of last bits */
240 unsigned char ibitt; /*!< total of 1's in last 3 bytes */
241 /* more to go here */
243 int opause_0; /*!< initial delay in ms, p() option */
244 int protocol; /*!< ETSI SMS protocol to use (passed at app call) */
245 int oseizure; /*!< protocol 2: channel seizure bits to send */
246 int framenumber; /*!< protocol 2: frame number (for sending ACK0 or ACK1) */
247 char udtxt[SMSLEN]; /*!< user data (message), PLAIN text */
248 } sms_t;
250 /* different types of encoding */
251 #define is7bit(dcs) ( ((dcs) & 0xC0) ? (!((dcs)&4) ) : (((dcs) & 0xc) == 0) )
252 #define is8bit(dcs) ( ((dcs) & 0xC0) ? ( ((dcs)&4) ) : (((dcs) & 0xc) == 4) )
253 #define is16bit(dcs) ( ((dcs) & 0xC0) ? 0 : (((dcs) & 0xc) == 8) )
255 static void sms_messagetx(sms_t *h);
257 /*! \brief copy number, skipping non digits apart from leading + */
258 static void numcpy(char *d, char *s)
260 if (*s == '+')
261 *d++ = *s++;
262 while (*s) {
263 if (isdigit(*s)) {
264 *d++ = *s;
266 s++;
268 *d = 0;
271 /*! \brief static, return a date/time in ISO format */
272 static char *isodate(time_t t, char *buf, int len)
274 struct ast_tm tm;
275 struct timeval tv = { t, 0 };
276 ast_localtime(&tv, &tm, NULL);
277 ast_strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm);
278 return buf;
281 /*! \brief Reads next UCS character from NUL terminated UTF-8 string and advance pointer */
282 /* for non valid UTF-8 sequences, returns character as is */
283 /* Does not advance pointer for null termination */
284 static long utf8decode(unsigned char **pp)
286 unsigned char *p = *pp;
287 if (!*p)
288 return 0; /* null termination of string */
289 (*pp)++;
290 if (*p < 0xC0)
291 return *p; /* ascii or continuation character */
292 if (*p < 0xE0) {
293 if (*p < 0xC2 || (p[1] & 0xC0) != 0x80)
294 return *p; /* not valid UTF-8 */
295 (*pp)++;
296 return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
298 if (*p < 0xF0) {
299 if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80)
300 return *p; /* not valid UTF-8 */
301 (*pp) += 2;
302 return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
304 if (*p < 0xF8) {
305 if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80)
306 return *p; /* not valid UTF-8 */
307 (*pp) += 3;
308 return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
310 if (*p < 0xFC) {
311 if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
312 || (p[4] & 0xC0) != 0x80)
313 return *p; /* not valid UTF-8 */
314 (*pp) += 4;
315 return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
317 if (*p < 0xFE) {
318 if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
319 || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80)
320 return *p; /* not valid UTF-8 */
321 (*pp) += 5;
322 return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F);
324 return *p; /* not sensible */
327 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using SMS 7 bit character codes */
328 /* The return value is the number of septets packed in to o, which is internally limited to SMSLEN */
329 /* o can be null, in which case this is used to validate or count only */
330 /* if the input contains invalid characters then the return value is -1 */
331 static int packsms7(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
333 unsigned char p = 0; /* output pointer (bytes) */
334 unsigned char b = 0; /* bit position */
335 unsigned char n = 0; /* output character count */
336 unsigned char dummy[SMSLEN];
338 if (o == NULL) /* output to a dummy buffer if o not set */
339 o = dummy;
341 if (udhl) { /* header */
342 o[p++] = udhl;
343 b = 1;
344 n = 1;
345 while (udhl--) {
346 o[p++] = *udh++;
347 b += 8;
348 while (b >= 7) {
349 b -= 7;
350 n++;
352 if (n >= SMSLEN)
353 return n;
355 if (b) {
356 b = 7 - b;
357 if (++n >= SMSLEN)
358 return n;
359 }; /* filling to septet boundary */
361 o[p] = 0;
362 /* message */
363 while (udl--) {
364 long u;
365 unsigned char v;
366 u = *ud++;
367 /* XXX 0 is invalid ? */
368 /* look up in defaultalphabet[]. If found, v is the 7-bit code */
369 for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
370 if (v == 128 /* not found */ && u && n + 1 < SMSLEN) {
371 /* if not found, look in the escapes table (we need 2 bytes) */
372 for (v = 0; v < 128 && escapes[v] != u; v++);
373 if (v < 128) { /* escaped sequence, esc + v */
374 /* store the low (8-b) bits in o[p], the remaining bits in o[p+1] */
375 o[p] |= (27 << b); /* the low bits go into o[p] */
376 b += 7;
377 if (b >= 8) {
378 b -= 8;
379 p++;
380 o[p] = (27 >> (7 - b));
382 n++;
385 if (v == 128)
386 return -1; /* invalid character */
387 /* store, same as above */
388 o[p] |= (v << b);
389 b += 7;
390 if (b >= 8) {
391 b -= 8;
392 p++;
393 o[p] = (v >> (7 - b));
395 if (++n >= SMSLEN)
396 return n;
398 return n;
401 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud)
402 * and packs in to o using 8 bit character codes.
403 * The return value is the number of bytes packed in to o, which is internally limited to 140.
404 * o can be null, in which case this is used to validate or count only.
405 * if the input contains invalid characters then the return value is -1
407 static int packsms8(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
409 unsigned char p = 0;
410 unsigned char dummy[SMSLEN_8];
412 if (o == NULL)
413 o = dummy;
414 /* header - no encoding */
415 if (udhl) {
416 o[p++] = udhl;
417 while (udhl--) {
418 o[p++] = *udh++;
419 if (p >= SMSLEN_8)
420 return p;
423 while (udl--) {
424 long u;
425 u = *ud++;
426 if (u < 0 || u > 0xFF)
427 return -1; /* not valid */
428 o[p++] = u;
429 if (p >= SMSLEN_8)
430 return p;
432 return p;
435 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2
436 message (udl characters at ud) and packs in to o using 16 bit
437 UCS-2 character codes
438 The return value is the number of bytes packed in to o, which is
439 internally limited to 140
440 o can be null, in which case this is used to validate or count
441 only if the input contains invalid characters then
442 the return value is -1 */
443 static int packsms16(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
445 unsigned char p = 0;
446 unsigned char dummy[SMSLEN_8];
448 if (o == NULL)
449 o = dummy;
450 /* header - no encoding */
451 if (udhl) {
452 o[p++] = udhl;
453 while (udhl--) {
454 o[p++] = *udh++;
455 if (p >= SMSLEN_8)
456 return p;
459 while (udl--) {
460 long u;
461 u = *ud++;
462 o[p++] = (u >> 8);
463 if (p >= SMSLEN_8)
464 return p - 1; /* could not fit last character */
465 o[p++] = u;
466 if (p >= SMSLEN_8)
467 return p;
469 return p;
472 /*! \brief general pack, with length and data,
473 returns number of bytes of target used */
474 static int packsms(unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
476 unsigned char *p = base;
477 if (udl == 0)
478 *p++ = 0; /* no user data */
479 else {
481 int l = 0;
482 if (is7bit(dcs)) { /* 7 bit */
483 l = packsms7(p + 1, udhl, udh, udl, ud);
484 if (l < 0)
485 l = 0;
486 *p++ = l;
487 p += (l * 7 + 7) / 8;
488 } else if (is8bit(dcs)) { /* 8 bit */
489 l = packsms8(p + 1, udhl, udh, udl, ud);
490 if (l < 0)
491 l = 0;
492 *p++ = l;
493 p += l;
494 } else { /* UCS-2 */
495 l = packsms16(p + 1, udhl, udh, udl, ud);
496 if (l < 0)
497 l = 0;
498 *p++ = l;
499 p += l;
502 return p - base;
506 /*! \brief pack a date and return */
507 static void packdate(unsigned char *o, time_t w)
509 struct ast_tm t;
510 struct timeval tv = { w, 0 };
511 int z;
513 ast_localtime(&tv, &t, NULL);
514 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) || defined(__CYGWIN__)
515 z = -t.tm_gmtoff / 60 / 15;
516 #else
517 z = timezone / 60 / 15;
518 #endif
519 *o++ = ((t.tm_year % 10) << 4) + (t.tm_year % 100) / 10;
520 *o++ = (((t.tm_mon + 1) % 10) << 4) + (t.tm_mon + 1) / 10;
521 *o++ = ((t.tm_mday % 10) << 4) + t.tm_mday / 10;
522 *o++ = ((t.tm_hour % 10) << 4) + t.tm_hour / 10;
523 *o++ = ((t.tm_min % 10) << 4) + t.tm_min / 10;
524 *o++ = ((t.tm_sec % 10) << 4) + t.tm_sec / 10;
525 if (z < 0)
526 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
527 else
528 *o++ = ((z % 10) << 4) + z / 10;
531 /*! \brief unpack a date and return */
532 static struct timeval unpackdate(unsigned char *i)
534 struct ast_tm t;
536 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
537 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
538 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
539 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
540 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
541 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
542 t.tm_isdst = 0;
543 if (i[6] & 0x08)
544 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
545 else
546 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
548 return ast_mktime(&t, NULL);
551 /*! \brief unpacks bytes (7 bit encoding) at i, len l septets,
552 and places in udh and ud setting udhl and udl. udh not used
553 if udhi not set */
554 static void unpacksms7(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
556 unsigned char b = 0, p = 0;
557 unsigned short *o = ud;
558 *udhl = 0;
559 if (udhi && l) { /* header */
560 int h = i[p];
561 *udhl = h;
562 if (h) {
563 b = 1;
564 p++;
565 l--;
566 while (h-- && l) {
567 *udh++ = i[p++];
568 b += 8;
569 while (b >= 7) {
570 b -= 7;
571 l--;
572 if (!l)
573 break;
576 /* adjust for fill, septets */
577 if (b) {
578 b = 7 - b;
579 l--;
583 while (l--) {
584 unsigned char v;
585 if (b < 2)
586 v = ((i[p] >> b) & 0x7F); /* everything in one byte */
587 else
588 v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
589 b += 7;
590 if (b >= 8) {
591 b -= 8;
592 p++;
594 /* 0x00A0 is the encoding of ESC (27) in defaultalphabet */
595 if (o > ud && o[-1] == 0x00A0 && escapes[v])
596 o[-1] = escapes[v];
597 else
598 *o++ = defaultalphabet[v];
600 *udl = (o - ud);
603 /*! \brief unpacks bytes (8 bit encoding) at i, len l septets,
604 * and places in udh and ud setting udhl and udl. udh not used
605 * if udhi not set.
607 static void unpacksms8(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
609 unsigned short *o = ud;
610 *udhl = 0;
611 if (udhi) {
612 int n = *i;
613 *udhl = n;
614 if (n) {
615 i++;
616 l--;
617 while (l && n) {
618 l--;
619 n--;
620 *udh++ = *i++;
624 while (l--)
625 *o++ = *i++; /* not to UTF-8 as explicitly 8 bit coding in DCS */
626 *udl = (o - ud);
629 /*! \brief unpacks bytes (16 bit encoding) at i, len l septets,
630 and places in udh and ud setting udhl and udl.
631 udh not used if udhi not set */
632 static void unpacksms16(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
634 unsigned short *o = ud;
635 *udhl = 0;
636 if (udhi) {
637 int n = *i;
638 *udhl = n;
639 if (n) {
640 i++;
641 l--;
642 while (l && n) {
643 l--;
644 n--;
645 *udh++ = *i++;
649 while (l--) {
650 int v = *i++;
651 if (l--)
652 v = (v << 8) + *i++;
653 *o++ = v;
655 *udl = (o - ud);
658 /*! \brief general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
659 static int unpacksms(unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
661 int l = *i++;
662 if (is7bit(dcs)) {
663 unpacksms7(i, l, udh, udhl, ud, udl, udhi);
664 l = (l * 7 + 7) / 8; /* adjust length to return */
665 } else if (is8bit(dcs))
666 unpacksms8(i, l, udh, udhl, ud, udl, udhi);
667 else
668 unpacksms16(i, l, udh, udhl, ud, udl, udhi);
669 return l + 1;
672 /*! \brief unpack an address from i, return byte length, unpack to o */
673 static unsigned char unpackaddress(char *o, unsigned char *i)
675 unsigned char l = i[0],
677 if (i[1] == 0x91)
678 *o++ = '+';
679 for (p = 0; p < l; p++) {
680 if (p & 1)
681 *o++ = (i[2 + p / 2] >> 4) + '0';
682 else
683 *o++ = (i[2 + p / 2] & 0xF) + '0';
685 *o = 0;
686 return (l + 5) / 2;
689 /*! \brief store an address at o, and return number of bytes used */
690 static unsigned char packaddress(unsigned char *o, char *i)
692 unsigned char p = 2;
693 o[0] = 0; /* number of bytes */
694 if (*i == '+') { /* record as bit 0 in byte 1 */
695 i++;
696 o[1] = 0x91;
697 } else
698 o[1] = 0x81;
699 for ( ; *i ; i++) {
700 if (!isdigit(*i)) /* ignore non-digits */
701 continue;
702 if (o[0] & 1)
703 o[p++] |= ((*i & 0xF) << 4);
704 else
705 o[p] = (*i & 0xF);
706 o[0]++;
708 if (o[0] & 1)
709 o[p++] |= 0xF0; /* pad */
710 return p;
713 /*! \brief Log the output, and remove file */
714 static void sms_log(sms_t * h, char status)
716 int o;
718 if (*h->oa == '\0' && *h->da == '\0')
719 return;
720 o = open(log_file, O_CREAT | O_APPEND | O_WRONLY, AST_FILE_MODE);
721 if (o >= 0) {
722 char line[1000], mrs[3] = "", *p;
723 char buf[30];
724 unsigned char n;
726 if (h->mr >= 0)
727 snprintf(mrs, sizeof(mrs), "%02X", h->mr);
728 snprintf(line, sizeof(line), "%s %c%c%c%s %s %s %s ",
729 isodate(time(NULL), buf, sizeof(buf)),
730 status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue,
731 S_OR(h->oa, "-"), S_OR(h->da, "-") );
732 p = line + strlen(line);
733 for (n = 0; n < h->udl; n++) {
734 if (h->ud[n] == '\\') {
735 *p++ = '\\';
736 *p++ = '\\';
737 } else if (h->ud[n] == '\n') {
738 *p++ = '\\';
739 *p++ = 'n';
740 } else if (h->ud[n] == '\r') {
741 *p++ = '\\';
742 *p++ = 'r';
743 } else if (h->ud[n] < 32 || h->ud[n] == 127)
744 *p++ = 191;
745 else
746 *p++ = h->ud[n];
748 *p++ = '\n';
749 *p = 0;
750 write(o, line, strlen(line));
751 close(o);
753 *h->oa = *h->da = h->udl = 0;
756 /*! \brief parse and delete a file */
757 static void sms_readfile(sms_t * h, char *fn)
759 char line[1000];
760 FILE *s;
761 char dcsset = 0; /* if DSC set */
762 ast_log(LOG_EVENT, "Sending %s\n", fn);
763 h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
764 h->mr = -1;
765 h->dcs = 0xF1; /* normal messages class 1 */
766 h->scts = ast_tvnow();
767 s = fopen(fn, "r");
768 if (s) {
769 if (unlink(fn)) { /* concurrent access, we lost */
770 fclose(s);
771 return;
773 while (fgets (line, sizeof(line), s)) { /* process line in file */
774 char *p;
775 void *pp = &p;
776 for (p = line; *p && *p != '\n' && *p != '\r'; p++);
777 *p = 0; /* strip eoln */
778 p = line;
779 if (!*p || *p == ';')
780 continue; /* blank line or comment, ignore */
781 while (isalnum(*p)) {
782 *p = tolower (*p);
783 p++;
785 while (isspace (*p))
786 *p++ = 0;
787 if (*p == '=') {
788 *p++ = 0;
789 if (!strcmp(line, "ud")) { /* parse message (UTF-8) */
790 unsigned char o = 0;
791 memcpy(h->udtxt, p, SMSLEN); /* for protocol 2 */
792 while (*p && o < SMSLEN)
793 h->ud[o++] = utf8decode(pp);
794 h->udl = o;
795 if (*p)
796 ast_log(LOG_WARNING, "UD too long in %s\n", fn);
797 } else {
798 while (isspace (*p))
799 p++;
800 if (!strcmp(line, "oa") && strlen(p) < sizeof(h->oa))
801 numcpy (h->oa, p);
802 else if (!strcmp(line, "da") && strlen(p) < sizeof(h->oa))
803 numcpy (h->da, p);
804 else if (!strcmp(line, "pid"))
805 h->pid = atoi(p);
806 else if (!strcmp(line, "dcs")) {
807 h->dcs = atoi(p);
808 dcsset = 1;
809 } else if (!strcmp(line, "mr"))
810 h->mr = atoi(p);
811 else if (!strcmp(line, "srr"))
812 h->srr = (atoi(p) ? 1 : 0);
813 else if (!strcmp(line, "vp"))
814 h->vp = atoi(p);
815 else if (!strcmp(line, "rp"))
816 h->rp = (atoi(p) ? 1 : 0);
817 else if (!strcmp(line, "scts")) { /* get date/time */
818 int Y,
824 if (sscanf (p, "%d-%d-%dT%d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6) {
825 struct ast_tm t = { 0, };
826 t.tm_year = Y - 1900;
827 t.tm_mon = m - 1;
828 t.tm_mday = d;
829 t.tm_hour = H;
830 t.tm_min = M;
831 t.tm_sec = S;
832 t.tm_isdst = -1;
833 h->scts = ast_mktime(&t, NULL);
834 if (h->scts.tv_sec == 0)
835 ast_log(LOG_WARNING, "Bad date/timein %s: %s", fn, p);
837 } else
838 ast_log(LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
840 } else if (*p == '#') { /* raw hex format */
841 *p++ = 0;
842 if (*p == '#') {
843 p++;
844 if (!strcmp(line, "ud")) { /* user data */
845 int o = 0;
846 while (*p && o < SMSLEN) {
847 if (isxdigit(*p) && isxdigit(p[1]) && isxdigit(p[2]) && isxdigit(p[3])) {
848 h->ud[o++] =
849 (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 12) +
850 (((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
851 (((isalpha(p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha(p[3]) ? 9 : 0) + (p[3] & 0xF));
852 p += 4;
853 } else
854 break;
856 h->udl = o;
857 if (*p)
858 ast_log(LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
859 } else
860 ast_log(LOG_WARNING, "Only ud can use ## format, %s\n", fn);
861 } else if (!strcmp(line, "ud")) { /* user data */
862 int o = 0;
863 while (*p && o < SMSLEN) {
864 if (isxdigit(*p) && isxdigit(p[1])) {
865 h->ud[o++] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
866 p += 2;
867 } else
868 break;
870 h->udl = o;
871 if (*p)
872 ast_log(LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
873 } else if (!strcmp(line, "udh")) { /* user data header */
874 unsigned char o = 0;
875 h->udhi = 1;
876 while (*p && o < SMSLEN) {
877 if (isxdigit(*p) && isxdigit(p[1])) {
878 h->udh[o] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
879 o++;
880 p += 2;
881 } else
882 break;
884 h->udhl = o;
885 if (*p)
886 ast_log(LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
887 } else
888 ast_log(LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
889 } else
890 ast_log(LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
892 fclose(s);
893 if (!dcsset && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
894 if (packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
895 if (packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0)
896 ast_log(LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
897 else {
898 h->dcs = 0x08; /* default to 16 bit */
899 ast_log(LOG_WARNING, "Sending in 16 bit format(%s)\n", fn);
901 } else {
902 h->dcs = 0xF5; /* default to 8 bit */
903 ast_log(LOG_WARNING, "Sending in 8 bit format(%s)\n", fn);
906 if (is7bit(h->dcs) && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0)
907 ast_log(LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
908 if (is8bit(h->dcs) && packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0)
909 ast_log(LOG_WARNING, "Invalid 8 bit data %s\n", fn);
910 if (is16bit(h->dcs) && packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0)
911 ast_log(LOG_WARNING, "Invalid 16 bit data %s\n", fn);
915 /*! \brief white a received text message to a file */
916 static void sms_writefile(sms_t * h)
918 char fn[200] = "", fn2[200] = "";
919 char buf[30];
920 FILE *o;
922 snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
923 ast_mkdir(fn, 0777); /* ensure it exists */
924 ast_copy_string(fn2, fn, sizeof(fn2));
925 snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%s.%s-%d", h->queue, isodate(h->scts.tv_sec, buf, sizeof(buf)), seq++);
926 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1);
927 o = fopen(fn, "w");
928 if (o == NULL)
929 return;
931 if (*h->oa)
932 fprintf(o, "oa=%s\n", h->oa);
933 if (*h->da)
934 fprintf(o, "da=%s\n", h->da);
935 if (h->udhi) {
936 unsigned int p;
937 fprintf(o, "udh#");
938 for (p = 0; p < h->udhl; p++)
939 fprintf(o, "%02X", h->udh[p]);
940 fprintf(o, "\n");
942 if (h->udl) {
943 unsigned int p;
944 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
945 if (p < h->udl)
946 fputc(';', o); /* cannot use ud=, but include as a comment for human readable */
947 fprintf(o, "ud=");
948 for (p = 0; p < h->udl; p++) {
949 unsigned short v = h->ud[p];
950 if (v < 32)
951 fputc(191, o);
952 else if (v < 0x80)
953 fputc(v, o);
954 else if (v < 0x800)
956 fputc(0xC0 + (v >> 6), o);
957 fputc(0x80 + (v & 0x3F), o);
958 } else
960 fputc(0xE0 + (v >> 12), o);
961 fputc(0x80 + ((v >> 6) & 0x3F), o);
962 fputc(0x80 + (v & 0x3F), o);
965 fprintf(o, "\n");
966 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
967 if (p < h->udl) {
968 for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
969 if (p == h->udl) { /* can write in ucs-1 hex */
970 fprintf(o, "ud#");
971 for (p = 0; p < h->udl; p++)
972 fprintf(o, "%02X", h->ud[p]);
973 fprintf(o, "\n");
974 } else { /* write in UCS-2 */
975 fprintf(o, "ud##");
976 for (p = 0; p < h->udl; p++)
977 fprintf(o, "%04X", h->ud[p]);
978 fprintf(o, "\n");
982 if (h->scts.tv_sec) {
983 char buf[30];
984 fprintf(o, "scts=%s\n", isodate(h->scts.tv_sec, buf, sizeof(buf)));
986 if (h->pid)
987 fprintf(o, "pid=%d\n", h->pid);
988 if (h->dcs != 0xF1)
989 fprintf(o, "dcs=%d\n", h->dcs);
990 if (h->vp)
991 fprintf(o, "vp=%d\n", h->vp);
992 if (h->srr)
993 fprintf(o, "srr=1\n");
994 if (h->mr >= 0)
995 fprintf(o, "mr=%d\n", h->mr);
996 if (h->rp)
997 fprintf(o, "rp=1\n");
998 fclose(o);
999 if (rename(fn, fn2))
1000 unlink(fn);
1001 else
1002 ast_log(LOG_EVENT, "Received to %s\n", fn2);
1005 /*! \brief read dir skipping dot files... */
1006 static struct dirent *readdirqueue(DIR *d, char *queue)
1008 struct dirent *f;
1009 do {
1010 f = readdir(d);
1011 } while (f && (*f->d_name == '.' || strncmp(f->d_name, queue, strlen(queue)) || f->d_name[strlen(queue)] != '.'));
1012 return f;
1015 /*! \brief handle the incoming message */
1016 static unsigned char sms_handleincoming (sms_t * h)
1018 unsigned char p = 3;
1019 if (h->smsc) { /* SMSC */
1020 if ((h->imsg[2] & 3) == 1) { /* SMS-SUBMIT */
1021 h->udhl = h->udl = 0;
1022 h->vp = 0;
1023 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
1024 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1025 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1026 ast_copy_string(h->oa, h->cli, sizeof(h->oa));
1027 h->scts = ast_tvnow();
1028 h->mr = h->imsg[p++];
1029 p += unpackaddress(h->da, h->imsg + p);
1030 h->pid = h->imsg[p++];
1031 h->dcs = h->imsg[p++];
1032 if ((h->imsg[2] & 0x18) == 0x10) { /* relative VP */
1033 if (h->imsg[p] < 144)
1034 h->vp = (h->imsg[p] + 1) * 5;
1035 else if (h->imsg[p] < 168)
1036 h->vp = 720 + (h->imsg[p] - 143) * 30;
1037 else if (h->imsg[p] < 197)
1038 h->vp = (h->imsg[p] - 166) * 1440;
1039 else
1040 h->vp = (h->imsg[p] - 192) * 10080;
1041 p++;
1042 } else if (h->imsg[2] & 0x18)
1043 p += 7; /* ignore enhanced / absolute VP */
1044 p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1045 h->rx = 1; /* received message */
1046 sms_writefile(h); /* write the file */
1047 if (p != h->imsg[1] + 2) {
1048 ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1049 return 0xFF; /* duh! */
1051 } else {
1052 ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
1053 return 0xFF;
1055 } else { /* client */
1056 if (!(h->imsg[2] & 3)) { /* SMS-DELIVER */
1057 *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
1058 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
1059 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1060 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1061 h->mr = -1;
1062 p += unpackaddress(h->oa, h->imsg + p);
1063 h->pid = h->imsg[p++];
1064 h->dcs = h->imsg[p++];
1065 h->scts = unpackdate(h->imsg + p);
1066 p += 7;
1067 p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1068 h->rx = 1; /* received message */
1069 sms_writefile(h); /* write the file */
1070 if (p != h->imsg[1] + 2) {
1071 ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1072 return 0xFF; /* duh! */
1074 } else {
1075 ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
1076 return 0xFF;
1079 return 0; /* no error */
1082 #ifdef SOLARIS
1083 #define NAME_MAX 1024
1084 #endif
1087 * Add data to a protocol 2 message.
1088 * Use the length field (h->omsg[1]) as a pointer to the next free position.
1090 static void adddata_proto2(sms_t *h, unsigned char msg, char *data, int size)
1092 int x = h->omsg[1]+2; /* Get current position */
1093 if (x == 2)
1094 x += 2; /* First: skip Payload length (set later) */
1095 h->omsg[x++] = msg; /* Message code */
1096 h->omsg[x++] = (unsigned char)size; /* Data size Low */
1097 h->omsg[x++] = 0; /* Data size Hi */
1098 for (; size > 0 ; size--)
1099 h->omsg[x++] = *data++;
1100 h->omsg[1] = x - 2; /* Frame size */
1101 h->omsg[2] = x - 4; /* Payload length (Lo) */
1102 h->omsg[3] = 0; /* Payload length (Hi) */
1105 static void putdummydata_proto2(sms_t *h)
1107 adddata_proto2(h, 0x10, "\0", 1); /* Media Identifier > SMS */
1108 adddata_proto2(h, 0x11, "\0\0\0\0\0\0", 6); /* Firmware version */
1109 adddata_proto2(h, 0x12, "\2\0\4", 3); /* SMS provider ID */
1110 adddata_proto2(h, 0x13, h->udtxt, h->udl); /* Body */
1113 static void sms_compose2(sms_t *h, int more)
1115 struct ast_tm tm;
1116 struct timeval tv = h->scts;
1117 char stm[9];
1119 h->omsg[0] = 0x00; /* set later... */
1120 h->omsg[1] = 0;
1121 putdummydata_proto2(h);
1122 if (h->smsc) { /* deliver */
1123 h->omsg[0] = 0x11; /* SMS_DELIVERY */
1124 /* Required: 10 11 12 13 14 15 17 (seems they must be ordered!) */
1125 ast_localtime(&tv, &tm, NULL);
1126 sprintf(stm, "%02d%02d%02d%02d", tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min); /* Date mmddHHMM */
1127 adddata_proto2(h, 0x14, stm, 8); /* Date */
1128 if (*h->oa == 0)
1129 strcpy(h->oa, "00000000");
1130 adddata_proto2(h, 0x15, h->oa, strlen(h->oa)); /* Originator */
1131 adddata_proto2(h, 0x17, "\1", 1); /* Calling Terminal ID */
1132 } else { /* submit */
1133 h->omsg[0] = 0x10; /* SMS_SUBMIT */
1134 /* Required: 10 11 12 13 17 18 1B 1C (seems they must be ordered!) */
1135 adddata_proto2(h, 0x17, "\1", 1); /* Calling Terminal ID */
1136 if (*h->da == 0)
1137 strcpy(h->da, "00000000");
1138 adddata_proto2(h, 0x18, h->da, strlen(h->da)); /* Originator */
1139 adddata_proto2(h, 0x1B, "\1", 1); /* Called Terminal ID */
1140 adddata_proto2(h, 0x1C, "\0\0\0", 3); /* Notification */
1144 static void putdummydata_proto2(sms_t *h);
1146 #define MAX_DEBUG_LEN 300
1147 static char *sms_hexdump(unsigned char buf[], int size, char *s /* destination */)
1149 char *p;
1150 int f;
1152 for (p = s, f = 0; f < size && f < MAX_DEBUG_LEN; f++, p += 3)
1153 sprintf(p, "%02X ", (unsigned char)buf[f]);
1154 return(s);
1158 /*! \brief sms_handleincoming_proto2: handle the incoming message */
1159 static int sms_handleincoming_proto2(sms_t *h)
1161 int f, i, sz = 0;
1162 int msg, msgsz;
1163 struct ast_tm tm;
1164 struct timeval tv = { 0, 0 };
1165 char debug_buf[MAX_DEBUG_LEN * 3 + 1];
1167 sz = h->imsg[1] + 2;
1168 /* ast_verb(3, "SMS-P2 Frame: %s\n", sms_hexdump(h->imsg, sz, debug_buf)); */
1170 /* Parse message body (called payload) */
1171 tv = h->scts = ast_tvnow();
1172 for (f = 4; f < sz; ) {
1173 msg = h->imsg[f++];
1174 msgsz = h->imsg[f++];
1175 msgsz += (h->imsg[f++] * 256);
1176 switch (msg) {
1177 case 0x13: /* Body */
1178 ast_verb(3, "SMS-P2 Body#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
1179 if (msgsz >= sizeof(h->imsg))
1180 msgsz = sizeof(h->imsg) - 1;
1181 for (i = 0; i < msgsz; i++)
1182 h->ud[i] = h->imsg[f + i];
1183 h->udl = msgsz;
1184 break;
1185 case 0x14: /* Date SCTS */
1186 tv = h->scts = ast_tvnow();
1187 ast_localtime(&tv, &tm, NULL);
1188 tm.tm_mon = ( (h->imsg[f] * 10) + h->imsg[f + 1] ) - 1;
1189 tm.tm_mday = ( (h->imsg[f + 2] * 10) + h->imsg[f + 3] );
1190 tm.tm_hour = ( (h->imsg[f + 4] * 10) + h->imsg[f + 5] );
1191 tm.tm_min = ( (h->imsg[f + 6] * 10) + h->imsg[f + 7] );
1192 tm.tm_sec = 0;
1193 h->scts = ast_mktime(&tm, NULL);
1194 ast_verb(3, "SMS-P2 Date#%02X=%02d/%02d %02d:%02d\n", msg, tm.tm_mday, tm.tm_mon + 1, tm.tm_hour, tm.tm_min);
1195 break;
1196 case 0x15: /* Calling line (from SMSC) */
1197 if (msgsz >= 20)
1198 msgsz = 20 - 1;
1199 ast_verb(3, "SMS-P2 Origin#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
1200 ast_copy_string(h->oa, (char *)(&h->imsg[f]), msgsz + 1);
1201 break;
1202 case 0x18: /* Destination(from TE/phone) */
1203 if (msgsz >= 20)
1204 msgsz = 20 - 1;
1205 ast_verb(3, "SMS-P2 Destination#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
1206 ast_copy_string(h->da, (char *)(&h->imsg[f]), msgsz + 1);
1207 break;
1208 case 0x1C: /* Notify */
1209 ast_verb(3, "SMS-P2 Notify#%02X=%s\n", msg, sms_hexdump(&h->imsg[f], 3, debug_buf));
1210 break;
1211 default:
1212 ast_verb(3, "SMS-P2 Par#%02X [%d]: %s\n", msg, msgsz, sms_hexdump(&h->imsg[f], msgsz, debug_buf));
1213 break;
1215 f+=msgsz; /* Skip to next */
1217 h->rx = 1; /* received message */
1218 sms_writefile(h); /* write the file */
1219 return 0; /* no error */
1222 #if 0
1223 static void smssend(sms_t *h, char *c)
1225 int f, x;
1226 for (f = 0; f < strlen(c); f++) {
1227 sscanf(&c[f*3], "%x", &x);
1228 h->omsg[f] = x;
1230 sms_messagetx(h);
1232 #endif
1234 static void sms_nextoutgoing (sms_t *h);
1236 static void sms_messagerx2(sms_t * h)
1238 int p = h->imsg[0] & DLL_SMS_MASK ; /* mask the high bit */
1239 int cause;
1241 #define DLL2_ACK(h) ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1)
1242 switch (p) {
1243 case DLL2_SMS_EST: /* Protocol 2: Connection ready (fake): send message */
1244 sms_nextoutgoing (h);
1245 /* smssend(h,"11 29 27 00 10 01 00 00 11 06 00 00 00 00 00 00 00 12 03 00 02 00 04 13 01 00 41 14 08 00 30 39 31 35 30 02 30 02 15 02 00 39 30 "); */
1246 break;
1248 case DLL2_SMS_INFO_MO: /* transport SMS_SUBMIT */
1249 case DLL2_SMS_INFO_MT: /* transport SMS_DELIVERY */
1250 cause = sms_handleincoming_proto2(h);
1251 if (!cause) /* ACK */
1252 sms_log(h, 'Y');
1253 h->omsg[0] = DLL2_ACK(h);
1254 h->omsg[1] = 0x06; /* msg len */
1255 h->omsg[2] = 0x04; /* payload len */
1256 h->omsg[3] = 0x00; /* payload len */
1257 h->omsg[4] = 0x1f; /* Response type */
1258 h->omsg[5] = 0x01; /* parameter len */
1259 h->omsg[6] = 0x00; /* parameter len */
1260 h->omsg[7] = cause; /* CONFIRM or error */
1261 sms_messagetx(h);
1262 break;
1264 case DLL2_SMS_NACK: /* Protocol 2: SMS_NAK */
1265 h->omsg[0] = DLL2_SMS_REL; /* SMS_REL */
1266 h->omsg[1] = 0x00; /* msg len */
1267 sms_messagetx(h);
1268 break;
1270 case DLL2_SMS_ACK0:
1271 case DLL2_SMS_ACK1:
1272 /* SMS_ACK also transport SMS_SUBMIT or SMS_DELIVERY */
1273 if ( (h->omsg[0] & DLL_SMS_MASK) == DLL2_SMS_REL) {
1274 /* a response to our Release, just hangup */
1275 h->hangup = 1; /* hangup */
1276 } else {
1277 /* XXX depending on what we are.. */
1278 ast_log(LOG_NOTICE, "SMS_SUBMIT or SMS_DELIVERY");
1279 sms_nextoutgoing (h);
1281 break;
1283 case DLL2_SMS_REL: /* Protocol 2: SMS_REL (hangup req) */
1284 h->omsg[0] = DLL2_ACK(h);
1285 h->omsg[1] = 0;
1286 sms_messagetx(h);
1287 break;
1291 /*! \brief compose a message for protocol 1 */
1292 static void sms_compose1(sms_t *h, int more)
1294 unsigned int p = 2; /* next byte to write. Skip type and len */
1296 h->omsg[0] = 0x91; /* SMS_DATA */
1297 if (h->smsc) { /* deliver */
1298 h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
1299 p += packaddress(h->omsg + p, h->oa);
1300 h->omsg[p++] = h->pid;
1301 h->omsg[p++] = h->dcs;
1302 packdate(h->omsg + p, h->scts.tv_sec);
1303 p += 7;
1304 p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1305 } else { /* submit */
1306 h->omsg[p++] =
1307 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
1308 if (h->mr < 0)
1309 h->mr = message_ref++;
1310 h->omsg[p++] = h->mr;
1311 p += packaddress(h->omsg + p, h->da);
1312 h->omsg[p++] = h->pid;
1313 h->omsg[p++] = h->dcs;
1314 if (h->vp) { /* relative VP */
1315 if (h->vp < 720)
1316 h->omsg[p++] = (h->vp + 4) / 5 - 1;
1317 else if (h->vp < 1440)
1318 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
1319 else if (h->vp < 43200)
1320 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
1321 else if (h->vp < 635040)
1322 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
1323 else
1324 h->omsg[p++] = 255; /* max */
1326 p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1328 h->omsg[1] = p - 2;
1331 /*! \brief find and fill in next message, or send a REL if none waiting */
1332 static void sms_nextoutgoing (sms_t * h)
1334 char fn[100 + NAME_MAX] = "";
1335 DIR *d;
1336 char more = 0;
1338 *h->da = *h->oa = '\0'; /* clear destinations */
1339 h->rx = 0; /* outgoing message */
1340 snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? "mttx" : "motx");
1341 ast_mkdir(fn, 0777); /* ensure it exists */
1342 d = opendir(fn);
1343 if (d) {
1344 struct dirent *f = readdirqueue(d, h->queue);
1345 if (f) {
1346 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", f->d_name);
1347 sms_readfile(h, fn);
1348 if (readdirqueue(d, h->queue))
1349 more = 1; /* more to send */
1351 closedir(d);
1353 if (*h->da || *h->oa) { /* message to send */
1354 if (h->protocol == 2)
1355 sms_compose2(h, more);
1356 else
1357 sms_compose1(h, more);
1358 } else { /* no message */
1359 if (h->protocol == 2) {
1360 h->omsg[0] = 0x17; /* SMS_REL */
1361 h->omsg[1] = 0;
1362 } else {
1363 h->omsg[0] = 0x94; /* SMS_REL */
1364 h->omsg[1] = 0;
1367 sms_messagetx(h);
1370 #define DIR_RX 1
1371 #define DIR_TX 2
1372 static void sms_debug (int dir, sms_t *h)
1374 char txt[259 * 3 + 1];
1375 char *p = txt; /* always long enough */
1376 unsigned char *msg = (dir == DIR_RX) ? h->imsg : h->omsg;
1377 int n = (dir == DIR_RX) ? h->ibytep : msg[1] + 2;
1378 int q = 0;
1379 while (q < n && q < 30) {
1380 sprintf(p, " %02X", msg[q++]);
1381 p += 3;
1383 if (q < n)
1384 sprintf(p, "...");
1385 ast_verb(3, "SMS %s%s\n", dir == DIR_RX ? "RX" : "TX", txt);
1389 static void sms_messagerx(sms_t * h)
1391 int cause;
1393 sms_debug (DIR_RX, h);
1394 if (h->protocol == 2) {
1395 sms_messagerx2(h);
1396 return;
1398 /* parse incoming message for Protocol 1 */
1399 switch (h->imsg[0]) {
1400 case 0x91: /* SMS_DATA */
1401 cause = sms_handleincoming (h);
1402 if (!cause) {
1403 sms_log(h, 'Y');
1404 h->omsg[0] = 0x95; /* SMS_ACK */
1405 h->omsg[1] = 0x02;
1406 h->omsg[2] = 0x00; /* deliver report */
1407 h->omsg[3] = 0x00; /* no parameters */
1408 } else { /* NACK */
1409 sms_log(h, 'N');
1410 h->omsg[0] = 0x96; /* SMS_NACK */
1411 h->omsg[1] = 3;
1412 h->omsg[2] = 0; /* delivery report */
1413 h->omsg[3] = cause; /* cause */
1414 h->omsg[4] = 0; /* no parameters */
1416 sms_messagetx(h);
1417 break;
1419 case 0x92: /* SMS_ERROR */
1420 h->err = 1;
1421 sms_messagetx(h); /* send whatever we sent again */
1422 break;
1423 case 0x93: /* SMS_EST */
1424 sms_nextoutgoing (h);
1425 break;
1426 case 0x94: /* SMS_REL */
1427 h->hangup = 1; /* hangup */
1428 break;
1429 case 0x95: /* SMS_ACK */
1430 sms_log(h, 'Y');
1431 sms_nextoutgoing (h);
1432 break;
1433 case 0x96: /* SMS_NACK */
1434 h->err = 1;
1435 sms_log(h, 'N');
1436 sms_nextoutgoing (h);
1437 break;
1438 default: /* Unknown */
1439 h->omsg[0] = 0x92; /* SMS_ERROR */
1440 h->omsg[1] = 1;
1441 h->omsg[2] = 3; /* unknown message type; */
1442 sms_messagetx(h);
1443 break;
1447 static void sms_messagetx(sms_t * h)
1449 unsigned char c = 0, p;
1450 int len = h->omsg[1] + 2; /* total message length excluding checksum */
1452 for (p = 0; p < len; p++) /* compute checksum */
1453 c += h->omsg[p];
1454 h->omsg[len] = 0 - c; /* actually, (256 - (c & 0fxx)) & 0xff) */
1455 sms_debug(DIR_TX, h);
1456 h->framenumber++; /* Proto 2 */
1457 h->obyte = 1; /* send mark ('1') at the beginning */
1458 h->opause = 200;
1459 /* Change the initial message delay. BT requires 300ms,
1460 * but for others this might be way too much and the phone
1461 * could time out. XXX make it configurable.
1463 if (h->omsg[0] == 0x93)
1464 h->opause = 8 * h->opause_0; /* initial message delay */
1465 h->obytep = 0;
1466 h->obitp = 0;
1467 if (h->protocol == 2) {
1468 h->oseizure = 300; /* Proto 2: 300bits (or more ?) */
1469 h->obyte = 0; /* Seizure starts with space (0) */
1470 h->opause = 400;
1471 } else {
1472 h->oseizure = 0; /* Proto 1: No seizure */
1474 /* Note - setting osync triggers the generator */
1475 h->osync = OSYNC_BITS; /* 80 sync bits */
1476 h->obyten = len + 1; /* bytes to send (including checksum) */
1480 * outgoing data are produced by this generator function, that reads from
1481 * the descriptor whether it has data to send and which ones.
1483 static int sms_generate(struct ast_channel *chan, void *data, int len, int samples)
1485 struct ast_frame f = { 0 };
1486 #define MAXSAMPLES (800)
1487 output_t *buf;
1488 sms_t *h = data;
1489 int i;
1491 if (samples > MAXSAMPLES) {
1492 ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n",
1493 MAXSAMPLES, samples);
1494 samples = MAXSAMPLES;
1496 len = samples * sizeof(*buf) + AST_FRIENDLY_OFFSET;
1497 buf = alloca(len);
1499 f.frametype = AST_FRAME_VOICE;
1500 f.subclass = __OUT_FMT;
1501 f.datalen = samples * sizeof(*buf);
1502 f.offset = AST_FRIENDLY_OFFSET;
1503 f.mallocd = 0;
1504 f.data = buf;
1505 f.samples = samples;
1506 f.src = "app_sms";
1507 /* create a buffer containing the digital sms pattern */
1508 for (i = 0; i < samples; i++) {
1509 buf[i] = wave_out[0]; /* default is silence */
1511 if (h->opause)
1512 h->opause--;
1513 else if (h->obyten || h->osync) { /* sending data */
1514 buf[i] = wave_out[h->ophase];
1515 h->ophase += (h->obyte & 1) ? 13 : 21; /* compute next phase */
1516 if (h->ophase >= 80)
1517 h->ophase -= 80;
1518 if ((h->ophasep += 12) >= 80) { /* time to send the next bit */
1519 h->ophasep -= 80;
1520 if (h->oseizure > 0) { /* sending channel seizure (proto 2) */
1521 h->oseizure--;
1522 h->obyte ^= 1; /* toggle low bit */
1523 } else if (h->osync) {
1524 h->obyte = 1; /* send mark as sync bit */
1525 h->osync--; /* sending sync bits */
1526 if (h->osync == 0 && h->protocol == 2 && h->omsg[0] == DLL2_SMS_EST) {
1527 h->obytep = h->obyten = 0; /* we are done */
1529 } else {
1530 h->obitp++;
1531 if (h->obitp == 1)
1532 h->obyte = 0; /* start bit; */
1533 else if (h->obitp == 2)
1534 h->obyte = h->omsg[h->obytep];
1535 else if (h->obitp == 10) {
1536 h->obyte = 1; /* stop bit */
1537 h->obitp = 0;
1538 h->obytep++;
1539 if (h->obytep == h->obyten) {
1540 h->obytep = h->obyten = 0; /* sent */
1541 h->osync = 10; /* trailing marks */
1543 } else
1544 h->obyte >>= 1;
1549 if (ast_write(chan, &f) < 0) {
1550 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
1551 return -1;
1553 return 0;
1554 #undef MAXSAMPLES
1558 * Just return the pointer to the descriptor that we received.
1560 static void *sms_alloc(struct ast_channel *chan, void *sms_t_ptr)
1562 return sms_t_ptr;
1565 static void sms_release(struct ast_channel *chan, void *data)
1567 return; /* nothing to do here. */
1570 static struct ast_generator smsgen = {
1571 .alloc = sms_alloc,
1572 .release = sms_release,
1573 .generate = sms_generate,
1577 * Process an incoming frame, trying to detect the carrier and
1578 * decode the message. The two frequencies are 1300 and 2100 Hz.
1579 * The decoder detects the amplitude of the signal over the last
1580 * few samples, filtering the absolute values with a lowpass filter.
1581 * If the magnitude (h->imag) is large enough, multiply the signal
1582 * by the two carriers, and compute the amplitudes m0 and m1.
1583 * Record the current sample as '0' or '1' depending on which one is greater.
1584 * The last 3 bits are stored in h->ibith, with the count of '1'
1585 * bits in h->ibitt.
1586 * XXX the rest is to be determined.
1588 static void sms_process(sms_t * h, int samples, signed short *data)
1590 int bit;
1593 * Ignore incoming audio while a packet is being transmitted,
1594 * the protocol is half-duplex.
1595 * Unfortunately this means that if the outbound and incoming
1596 * transmission overlap (which is an error condition anyways),
1597 * we may miss some data and this makes debugging harder.
1599 if (h->obyten || h->osync)
1600 return;
1601 for ( ; samples-- ; data++) {
1602 unsigned long long m0, m1;
1603 if (abs(*data) > h->imag)
1604 h->imag = abs(*data);
1605 else
1606 h->imag = h->imag * 7 / 8;
1607 if (h->imag <= 500) { /* below [arbitrary] threahold: lost carrier */
1608 if (h->idle++ == 80000) { /* nothing happening */
1609 ast_log(LOG_NOTICE, "No data, hanging up\n");
1610 h->hangup = 1;
1611 h->err = 1;
1613 if (h->ierr) { /* error */
1614 ast_log(LOG_NOTICE, "Error %d, hanging up\n", h->ierr);
1615 /* Protocol 1 */
1616 h->err = 1;
1617 h->omsg[0] = 0x92; /* error */
1618 h->omsg[1] = 1;
1619 h->omsg[2] = h->ierr;
1620 sms_messagetx(h); /* send error */
1622 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1623 continue;
1625 h->idle = 0;
1627 /* multiply signal by the two carriers. */
1628 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
1629 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
1630 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
1631 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
1632 /* compute the amplitudes */
1633 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
1634 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
1636 /* advance the sin/cos pointers */
1637 if ((h->ips0 += 21) >= 80)
1638 h->ips0 -= 80;
1639 if ((h->ipc0 += 21) >= 80)
1640 h->ipc0 -= 80;
1641 if ((h->ips1 += 13) >= 80)
1642 h->ips1 -= 80;
1643 if ((h->ipc1 += 13) >= 80)
1644 h->ipc1 -= 80;
1646 /* set new bit to 1 or 0 depending on which value is stronger */
1647 h->ibith <<= 1;
1648 if (m1 > m0)
1649 h->ibith |= 1;
1650 if (h->ibith & 8)
1651 h->ibitt--;
1652 if (h->ibith & 1)
1653 h->ibitt++;
1654 bit = ((h->ibitt > 1) ? 1 : 0);
1655 if (bit != h->ibitl)
1656 h->ibitc = 1;
1657 else
1658 h->ibitc++;
1659 h->ibitl = bit;
1660 if (!h->ibitn && h->ibitc == 4 && !bit) {
1661 h->ibitn = 1;
1662 h->iphasep = 0;
1664 if (bit && h->ibitc == 200) { /* sync, restart message */
1665 /* Protocol 2: empty connnection ready (I am master) */
1666 if (h->framenumber < 0 && h->ibytec >= 160 && !memcmp(h->imsg, "UUUUUUUUUUUUUUUUUUUU", 20)) {
1667 h->framenumber = 1;
1668 ast_verb(3, "SMS protocol 2 detected\n");
1669 h->protocol = 2;
1670 h->imsg[0] = 0xff; /* special message (fake) */
1671 h->imsg[1] = h->imsg[2] = 0x00;
1672 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1673 sms_messagerx(h);
1675 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1677 if (h->ibitn) {
1678 h->iphasep += 12;
1679 if (h->iphasep >= 80) { /* next bit */
1680 h->iphasep -= 80;
1681 if (h->ibitn++ == 9) { /* end of byte */
1682 if (!bit) { /* bad stop bit */
1683 ast_log(LOG_NOTICE, "bad stop bit");
1684 h->ierr = 0xFF; /* unknown error */
1685 } else {
1686 if (h->ibytep < sizeof(h->imsg)) {
1687 h->imsg[h->ibytep] = h->ibytev;
1688 h->ibytec += h->ibytev;
1689 h->ibytep++;
1690 } else if (h->ibytep == sizeof(h->imsg)) {
1691 ast_log(LOG_NOTICE, "msg too large");
1692 h->ierr = 2; /* bad message length */
1694 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
1695 if (!h->ibytec)
1696 sms_messagerx(h);
1697 else {
1698 ast_log(LOG_NOTICE, "bad checksum");
1699 h->ierr = 1; /* bad checksum */
1703 h->ibitn = 0;
1705 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1712 * Standard argument parsing:
1713 * - one enum for the flags we recognise,
1714 * - one enum for argument indexes
1715 * - AST_APP_OPTIONS() to drive the parsing routine
1716 * - in the function, AST_DECLARE_APP_ARGS(...) for the arguments.
1718 enum {
1719 OPTION_BE_SMSC = (1 << 0), /* act as sms center */
1720 OPTION_ANSWER = (1 << 1), /* answer on incoming calls */
1721 OPTION_TWO = (1 << 2), /* Use Protocol Two */
1722 OPTION_PAUSE = (1 << 3), /* pause before sending data, in ms */
1723 OPTION_SRR = (1 << 4), /* set srr */
1724 OPTION_DCS = (1 << 5), /* set dcs */
1725 } sms_flags;
1727 enum {
1728 OPTION_ARG_PAUSE = 0,
1729 OPTION_ARG_ARRAY_SIZE
1730 } sms_opt_args;
1732 AST_APP_OPTIONS(sms_options, {
1733 AST_APP_OPTION('s', OPTION_BE_SMSC),
1734 AST_APP_OPTION('a', OPTION_ANSWER),
1735 AST_APP_OPTION('t', OPTION_TWO),
1736 AST_APP_OPTION('r', OPTION_SRR),
1737 AST_APP_OPTION('o', OPTION_DCS),
1738 AST_APP_OPTION_ARG('p', OPTION_PAUSE, OPTION_ARG_PAUSE),
1739 } );
1741 static int sms_exec(struct ast_channel *chan, void *data)
1743 int res = -1;
1744 sms_t h = { 0 };
1745 /* argument parsing support */
1746 struct ast_flags sms_flags;
1747 char *parse, *sms_opts[OPTION_ARG_ARRAY_SIZE];
1748 char *p;
1749 AST_DECLARE_APP_ARGS(sms_args,
1750 AST_APP_ARG(queue);
1751 AST_APP_ARG(options);
1752 AST_APP_ARG(addr);
1753 AST_APP_ARG(body);
1756 if (!data) {
1757 ast_log(LOG_ERROR, "Requires queue name at least\n");
1758 return -1;
1761 parse = ast_strdupa(data); /* create a local copy */
1762 AST_STANDARD_APP_ARGS(sms_args, parse);
1763 if (sms_args.argc > 1)
1764 ast_app_parse_options(sms_options, &sms_flags, sms_opts, sms_args.options);
1766 ast_verb(1, "sms argc %d queue <%s> opts <%s> addr <%s> body <%s>\n",
1767 sms_args.argc, S_OR(sms_args.queue, ""),
1768 S_OR(sms_args.options, ""),
1769 S_OR(sms_args.addr, ""),
1770 S_OR(sms_args.body, "") );
1772 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1773 h.dcs = 0xF1; /* default */
1775 if (chan->cid.cid_num)
1776 ast_copy_string(h.cli, chan->cid.cid_num, sizeof(h.cli));
1778 if (ast_strlen_zero(sms_args.queue)) {
1779 ast_log(LOG_ERROR, "Requires queue name\n");
1780 goto done;
1782 if (strlen(sms_args.queue) >= sizeof(h.queue)) {
1783 ast_log(LOG_ERROR, "Queue name too long\n");
1784 goto done;
1786 ast_copy_string(h.queue, sms_args.queue, sizeof(h.queue));
1788 for (p = h.queue; *p; p++)
1789 if (!isalnum(*p))
1790 *p = '-'; /* make very safe for filenames */
1792 h.smsc = ast_test_flag(&sms_flags, OPTION_BE_SMSC);
1793 h.protocol = ast_test_flag(&sms_flags, OPTION_TWO) ? 2 : 1;
1794 if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE]))
1795 h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]);
1796 if (h.opause_0 < 25 || h.opause_0 > 2000)
1797 h.opause_0 = 300; /* default 300ms */
1798 ast_verb(1, "initial delay %dms\n", h.opause_0);
1801 /* the following apply if there is an arg3/4 and apply to the created message file */
1802 if (ast_test_flag(&sms_flags, OPTION_SRR))
1803 h.srr = 1;
1804 if (ast_test_flag(&sms_flags, OPTION_DCS))
1805 h.dcs = 1;
1806 #if 0
1807 case '1':
1808 case '2':
1809 case '3':
1810 case '4':
1811 case '5':
1812 case '6':
1813 case '7': /* set the pid for saved local message */
1814 h.pid = 0x40 + (*d & 0xF);
1815 break;
1817 #endif
1818 if (sms_args.argc > 2) {
1819 unsigned char *up;
1821 /* submitting a message, not taking call. */
1822 /* deprecated, use smsq instead */
1823 h.scts = ast_tvnow();
1824 if (ast_strlen_zero(sms_args.addr) || strlen(sms_args.addr) >= sizeof(h.oa)) {
1825 ast_log(LOG_ERROR, "Address too long %s\n", sms_args.addr);
1826 goto done;
1828 if (h.smsc)
1829 ast_copy_string(h.oa, sms_args.addr, sizeof(h.oa));
1830 else {
1831 ast_copy_string(h.da, sms_args.addr, sizeof(h.da));
1832 ast_copy_string(h.oa, h.cli, sizeof(h.oa));
1834 h.udl = 0;
1835 if (ast_strlen_zero(sms_args.body)) {
1836 ast_log(LOG_ERROR, "Missing body for %s\n", sms_args.addr);
1837 goto done;
1839 up = (unsigned char *)sms_args.body;
1840 while (*up && h.udl < SMSLEN)
1841 h.ud[h.udl++] = utf8decode(&up);
1842 if (is7bit(h.dcs) && packsms7(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
1843 ast_log(LOG_WARNING, "Invalid 7 bit GSM data\n");
1844 goto done;
1846 if (is8bit(h.dcs) && packsms8(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
1847 ast_log(LOG_WARNING, "Invalid 8 bit data\n");
1848 goto done;
1850 if (is16bit(h.dcs) && packsms16(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
1851 ast_log(LOG_WARNING, "Invalid 16 bit data\n");
1852 goto done;
1854 h.rx = 0; /* sent message */
1855 h.mr = -1;
1856 sms_writefile(&h);
1857 res = h.err;
1858 goto done;
1861 if (ast_test_flag(&sms_flags, OPTION_ANSWER)) {
1862 h.framenumber = 1; /* Proto 2 */
1863 /* set up SMS_EST initial message */
1864 if (h.protocol == 2) {
1865 h.omsg[0] = DLL2_SMS_EST;
1866 h.omsg[1] = 0;
1867 } else {
1868 h.omsg[0] = DLL1_SMS_EST | DLL1_SMS_COMPLETE;
1869 h.omsg[1] = 0;
1871 sms_messagetx(&h);
1874 if (chan->_state != AST_STATE_UP)
1875 ast_answer(chan);
1877 res = ast_set_write_format(chan, __OUT_FMT);
1878 if (res >= 0)
1879 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
1880 if (res < 0) {
1881 ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n");
1882 goto done;
1885 if ( (res = ast_activate_generator(chan, &smsgen, &h)) < 0) {
1886 ast_log(LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
1887 goto done;
1890 /* Do our thing here */
1891 for (;;) {
1892 struct ast_frame *f;
1893 int i = ast_waitfor(chan, -1);
1894 if (i < 0) {
1895 ast_log(LOG_NOTICE, "waitfor failed\n");
1896 break;
1898 if (h.hangup) {
1899 ast_log(LOG_NOTICE, "channel hangup\n");
1900 break;
1902 f = ast_read(chan);
1903 if (!f) {
1904 ast_log(LOG_NOTICE, "ast_read failed\n");
1905 break;
1907 if (f->frametype == AST_FRAME_VOICE) {
1908 sms_process(&h, f->samples, f->data);
1911 ast_frfree(f);
1913 res = h.err; /* XXX */
1915 sms_log(&h, '?'); /* log incomplete message */
1916 done:
1917 return (res);
1920 static int unload_module(void)
1922 return ast_unregister_application(app);
1925 static int load_module(void)
1927 #ifdef OUTALAW
1928 int p;
1929 for (p = 0; p < 80; p++)
1930 wavea[p] = AST_LIN2A (wave[p]);
1931 #endif
1932 snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR);
1933 return ast_register_application(app, sms_exec, synopsis, descrip);
1936 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SMS/PSTN handler");