Asterisk - The Open Source Telephony Project  18.5.0
app_sms.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2004 - 2005, Adrian Kennard, rights assigned to Digium
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16 
17 /*! \file
18  *
19  * \brief SMS application - ETSI ES 201 912 protocol 1 implementation
20  *
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:
25  *
26  * ES 201 912 SMS for PSTN/ISDN
27  * TS 123 040 Technical realization of SMS
28  *
29  *
30  * \ingroup applications
31  *
32  * \author Adrian Kennard (for the original protocol 1 code)
33  * \author Filippo Grassilli (Hyppo) - protocol 2 support
34  * Not fully tested, under development
35  */
36 
37 /*** MODULEINFO
38  <support_level>extended</support_level>
39  ***/
40 
41 #include "asterisk.h"
42 
43 #include <dirent.h>
44 #include <ctype.h>
45 #include <sys/stat.h>
46 
47 #include "asterisk/paths.h" /* use ast_config_AST_SPOOL_DIR and LOG_DIR */
48 #include "asterisk/lock.h"
49 #include "asterisk/file.h"
50 #include "asterisk/channel.h"
51 #include "asterisk/pbx.h"
52 #include "asterisk/module.h"
53 #include "asterisk/alaw.h"
54 #include "asterisk/callerid.h"
55 #include "asterisk/utils.h"
56 #include "asterisk/app.h"
57 #include "asterisk/format_cache.h"
58 
59 /*** DOCUMENTATION
60  <application name="SMS" language="en_US">
61  <synopsis>
62  Communicates with SMS service centres and SMS capable analogue phones.
63  </synopsis>
64  <syntax>
65  <parameter name="name" required="true">
66  <para>The name of the queue used in <filename>/var/spool/asterisk/sms</filename></para>
67  </parameter>
68  <parameter name="options">
69  <optionlist>
70  <option name="a">
71  <para>Answer, i.e. send initial FSK packet.</para>
72  </option>
73  <option name="s">
74  <para>Act as service centre talking to a phone.</para>
75  </option>
76  <option name="t">
77  <para>Use protocol 2 (default used is protocol 1).</para>
78  </option>
79  <option name="p">
80  <para>Set the initial delay to N ms (default is <literal>300</literal>).
81  addr and body are a deprecated format to send messages out.</para>
82  </option>
83  <option name="r">
84  <para>Set the Status Report Request (SRR) bit.</para>
85  </option>
86  <option name="o">
87  <para>The body should be coded as octets not 7-bit symbols.</para>
88  </option>
89  <option name="n">
90  <para>Do not log any SMS content to log file (privacy).</para>
91  </option>
92  </optionlist>
93  </parameter>
94  <parameter name="addr" />
95  <parameter name="body" />
96  </syntax>
97  <description>
98  <para>SMS handles exchange of SMS data with a call to/from SMS capable phone or SMS PSTN service center.
99  Can send and/or receive SMS messages. Works to ETSI ES 201 912; compatible with BT SMS PSTN service in
100  UK and Telecom Italia in Italy.</para>
101  <para>Typical usage is to use to handle calls from the SMS service centre CLI, or to set up a call using
102  <literal>outgoing</literal> or manager interface to connect service centre to SMS().</para>
103  <para>"Messages are processed as per text file message queues. smsq (a separate software) is a command to
104  generate message queues and send messages.</para>
105  <note><para>The protocol has tight delay bounds. Please use short frames and disable/keep short the
106  jitter buffer on the ATA to make sure that respones (ACK etc.) are received in time.</para></note>
107  </description>
108  </application>
109  ***/
110 
111 /* #define OUTALAW */ /* enable this to output Alaw rather than linear */
112 
113 /* ToDo */
114 /* Add full VP support */
115 /* Handle status report messages (generation and reception) */
116 /* Time zones on time stamps */
117 /* user ref field */
118 
119 static volatile unsigned char message_ref; /* arbitary message ref */
120 static volatile unsigned int seq; /* arbitrary message sequence number for unqiue files */
121 
122 static char log_file[255];
123 
124 static char *app = "SMS";
125 
126 /*
127  * 80 samples of a single period of the wave. At 8000 Hz, it means these
128  * are the samples of a 100 Hz signal.
129  * To pick the two carriers (1300Hz for '1' and 2100 Hz for '0') used by
130  * the modulation, we should take one every 13 and 21 samples respectively.
131  */
132 static const signed short wave[] = {
133  0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
134  5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
135  0, -392, -782, -1167,
136  -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
137  -4985, -4938, -4862,
138  -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
139 };
140 
141 #ifdef OUTALAW
142 static unsigned char wavea[80];
143 typedef unsigned char output_t;
144 static const output_t *wave_out = wavea; /* outgoing samples */
145 #define __OUT_FMT ast_format_alaw
146 #else
147 typedef signed short output_t;
148 static const output_t *wave_out = wave; /* outgoing samples */
149 #define __OUT_FMT ast_format_slin
150 #endif
151 
152 #define OSYNC_BITS 80 /* initial sync bits */
153 
154 /*!
155  * The SMS spec ETSI ES 201 912 defines two protocols with different message types.
156  * Also note that the high bit is used to indicate whether the message
157  * is complete or not, but in two opposite ways:
158  * for Protocol 1, 0x80 means that the message is complete;
159  * for Protocol 2, 0x00 means that the message is complete;
160  */
162  DLL_SMS_MASK = 0x7f, /* mask for the valid bits */
163 
164  /* Protocol 1 values */
165  DLL1_SMS_DATA = 0x11, /* data packet */
167  DLL1_SMS_EST = 0x13, /* start the connection */
168  DLL1_SMS_REL = 0x14, /* end the connection */
169  DLL1_SMS_ACK = 0x15,
171 
172  DLL1_SMS_COMPLETE = 0x80, /* packet is complete */
173  DLL1_SMS_MORE = 0x00, /* more data to follow */
174 
175  /* Protocol 2 values */
176  DLL2_SMS_EST = 0x7f, /* magic number. No message body */
181  DLL2_SMS_ACK0 = 0x14, /* ack even-numbered frame */
182  DLL2_SMS_ACK1 = 0x15, /* ack odd-numbered frame */
183  DLL2_SMS_ENQ = 0x16,
184  DLL2_SMS_REL = 0x17, /* end the connection */
185 
186  DLL2_SMS_COMPLETE = 0x00, /* packet is complete */
187  DLL2_SMS_MORE = 0x80, /* more data to follow */
188 };
189 
190 /* SMS 7 bit character mapping to UCS-2 */
191 static const unsigned short defaultalphabet[] = {
192  0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
193  0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
194  0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
195  0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
196  ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
197  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
198  161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
199  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
200  191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
201  'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
202 };
203 
204 static const unsigned short escapes[] = {
205  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
206  0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
207  0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
208  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
209  0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
210  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
211  0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
212  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
213 };
214 
215 #define SMSLEN 160 /*!< max SMS length */
216 #define SMSLEN_8 140 /*!< max SMS length for 8-bit char */
217 
218 typedef struct sms_s {
219  unsigned char hangup; /*!< we are done... */
220  unsigned char err; /*!< set for any errors */
221  unsigned char sent_rel:1; /*!< have sent REL message... */
222  unsigned char smsc:1; /*!< we are SMSC */
223  unsigned char rx:1; /*!< this is a received message */
224  unsigned char nolog:1; /*!< do not log plain text SMS content (privacy) */
225  char queue[30]; /*!< queue name */
226  char oa[20]; /*!< originating address */
227  char da[20]; /*!< destination address */
228  struct timeval scts; /*!< time stamp, UTC */
229  unsigned char pid; /*!< protocol ID */
230  unsigned char dcs; /*!< data coding scheme */
231  short mr; /*!< message reference - actually a byte, but use -1 for not set */
232  int udl; /*!< user data length */
233  int udhl; /*!< user data header length */
234  unsigned char srr:1; /*!< Status Report request */
235  unsigned char udhi:1; /*!< User Data Header required, even if length 0 */
236  unsigned char rp:1; /*!< Reply Path */
237  unsigned int vp; /*!< validity period in minutes, 0 for not set */
238  unsigned short ud[SMSLEN]; /*!< user data (message), UCS-2 coded */
239  unsigned char udh[SMSLEN]; /*!< user data header */
240  char cli[20]; /*!< caller ID */
241  unsigned char ophase; /*!< phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
242  unsigned char ophasep; /*!< phase (0-79) for 1200 bps */
243  unsigned char obyte; /*!< byte being sent */
244  unsigned int opause; /*!< silent pause before sending (in sample periods) */
245  unsigned char obitp; /*!< bit in byte */
246  unsigned char osync; /*!< sync bits to send */
247  unsigned char obytep; /*!< byte in data */
248  unsigned char obyten; /*!< bytes in data */
249  unsigned char omsg[256]; /*!< data buffer (out) */
250  unsigned char imsg[250]; /*!< data buffer (in) */
251  signed long long ims0,
252  imc0,
253  ims1,
254  imc1; /*!< magnitude averages sin/cos 0/1 */
255  unsigned int idle;
256  unsigned short imag; /*!< signal level */
257  unsigned char ips0; /*!< phase sin for bit 0, start at 0 inc by 21 mod 80 */
258  unsigned char ips1; /*!< phase cos for bit 0, start at 20 inc by 21 mod 80 */
259  unsigned char ipc0; /*!< phase sin for bit 1, start at 0 inc by 13 mod 80 */
260  unsigned char ipc1; /*!< phase cos for bit 1, start at 20 inc by 13 mod 80 */
261  unsigned char ibitl; /*!< last bit */
262  unsigned char ibitc; /*!< bit run length count */
263  unsigned char iphasep; /*!< bit phase (0-79) for 1200 bps */
264  unsigned char ibitn; /*!< bit number in byte being received */
265  unsigned char ibytev; /*!< byte value being received */
266  unsigned char ibytep; /*!< byte pointer in message */
267  unsigned char ibytec; /*!< byte checksum for message */
268  unsigned char ierr; /*!< error flag */
269  unsigned char ibith; /*!< history of last bits */
270  unsigned char ibitt; /*!< total of 1's in last 3 bytes */
271  /* more to go here */
272 
273  int opause_0; /*!< initial delay in ms, p() option */
274  int protocol; /*!< ETSI SMS protocol to use (passed at app call) */
275  int oseizure; /*!< protocol 2: channel seizure bits to send */
276  int framenumber; /*!< protocol 2: frame number (for sending ACK0 or ACK1) */
277  char udtxt[SMSLEN]; /*!< user data (message), PLAIN text */
278 } sms_t;
279 
280 /* different types of encoding */
281 #define is7bit(dcs) ( ((dcs) & 0xC0) ? (!((dcs) & 4) ) : (((dcs) & 0xc) == 0) )
282 #define is8bit(dcs) ( ((dcs) & 0xC0) ? ( ((dcs) & 4) ) : (((dcs) & 0xc) == 4) )
283 #define is16bit(dcs) ( ((dcs) & 0xC0) ? 0 : (((dcs) & 0xc) == 8) )
284 
285 static void sms_messagetx(sms_t *h);
286 
287 /*! \brief copy number, skipping non digits apart from leading + */
288 static void numcpy(char *d, char *s)
289 {
290  if (*s == '+') {
291  *d++ = *s++;
292  }
293  while (*s) {
294  if (isdigit(*s)) {
295  *d++ = *s;
296  }
297  s++;
298  }
299  *d = 0;
300 }
301 
302 /*! \brief static, return a date/time in ISO format */
303 static char *isodate(time_t t, char *buf, int len)
304 {
305  struct ast_tm tm;
306  struct timeval local = { t, 0 };
307  ast_localtime(&local, &tm, NULL);
308  ast_strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm);
309  return buf;
310 }
311 
312 /*! \brief Reads next UCS character from NUL terminated UTF-8 string and advance pointer */
313 /* for non valid UTF-8 sequences, returns character as is */
314 /* Does not advance pointer for null termination */
315 static long utf8decode(unsigned char **pp)
316 {
317  unsigned char *p = *pp;
318  if (!*p) {
319  return 0; /* null termination of string */
320  }
321  (*pp)++;
322  if (*p < 0xC0) {
323  return *p; /* ascii or continuation character */
324  }
325  if (*p < 0xE0) {
326  if (*p < 0xC2 || (p[1] & 0xC0) != 0x80) {
327  return *p; /* not valid UTF-8 */
328  }
329  (*pp)++;
330  return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
331  }
332  if (*p < 0xF0) {
333  if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80) {
334  return *p; /* not valid UTF-8 */
335  }
336  (*pp) += 2;
337  return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
338  }
339  if (*p < 0xF8) {
340  if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80) {
341  return *p; /* not valid UTF-8 */
342  }
343  (*pp) += 3;
344  return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
345  }
346  if (*p < 0xFC) {
347  if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
348  || (p[4] & 0xC0) != 0x80) {
349  return *p; /* not valid UTF-8 */
350  }
351  (*pp) += 4;
352  return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
353  }
354  if (*p < 0xFE) {
355  if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
356  || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80) {
357  return *p; /* not valid UTF-8 */
358  }
359  (*pp) += 5;
360  return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F);
361  }
362  return *p; /* not sensible */
363 }
364 
365 /*! \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 */
366 /* The return value is the number of septets packed in to o, which is internally limited to SMSLEN */
367 /* o can be null, in which case this is used to validate or count only */
368 /* if the input contains invalid characters then the return value is -1 */
369 static int packsms7(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
370 {
371  unsigned char p = 0; /* output pointer (bytes) */
372  unsigned char b = 0; /* bit position */
373  unsigned char n = 0; /* output character count */
374  unsigned char dummy[SMSLEN];
375 
376  if (o == NULL) { /* output to a dummy buffer if o not set */
377  o = dummy;
378  }
379 
380  if (udhl) { /* header */
381  o[p++] = udhl;
382  b = 1;
383  n = 1;
384  while (udhl--) {
385  o[p++] = *udh++;
386  b += 8;
387  while (b >= 7) {
388  b -= 7;
389  n++;
390  }
391  if (n >= SMSLEN)
392  return n;
393  }
394  if (b) {
395  b = 7 - b;
396  if (++n >= SMSLEN)
397  return n;
398  } /* filling to septet boundary */
399  }
400  o[p] = 0;
401  /* message */
402  while (udl--) {
403  long u;
404  unsigned char v;
405  u = *ud++;
406  /* XXX 0 is invalid ? */
407  /* look up in defaultalphabet[]. If found, v is the 7-bit code */
408  for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
409  if (v == 128 /* not found */ && u && n + 1 < SMSLEN) {
410  /* if not found, look in the escapes table (we need 2 bytes) */
411  for (v = 0; v < 128 && escapes[v] != u; v++);
412  if (v < 128) { /* escaped sequence, esc + v */
413  /* store the low (8-b) bits in o[p], the remaining bits in o[p+1] */
414  o[p] |= (27 << b); /* the low bits go into o[p] */
415  b += 7;
416  if (b >= 8) {
417  b -= 8;
418  p++;
419  o[p] = (27 >> (7 - b));
420  }
421  n++;
422  }
423  }
424  if (v == 128)
425  return -1; /* invalid character */
426  /* store, same as above */
427  o[p] |= (v << b);
428  b += 7;
429  if (b >= 8) {
430  b -= 8;
431  p++;
432  o[p] = (v >> (7 - b));
433  }
434  if (++n >= SMSLEN)
435  return n;
436  }
437  return n;
438 }
439 
440 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud)
441  * and packs in to o using 8 bit character codes.
442  * The return value is the number of bytes packed in to o, which is internally limited to 140.
443  * o can be null, in which case this is used to validate or count only.
444  * if the input contains invalid characters then the return value is -1
445  */
446 static int packsms8(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
447 {
448  unsigned char p = 0;
449  unsigned char dummy[SMSLEN_8];
450 
451  if (o == NULL)
452  o = dummy;
453  /* header - no encoding */
454  if (udhl) {
455  o[p++] = udhl;
456  while (udhl--) {
457  o[p++] = *udh++;
458  if (p >= SMSLEN_8) {
459  return p;
460  }
461  }
462  }
463  while (udl--) {
464  long u;
465  u = *ud++;
466  if (u < 0 || u > 0xFF) {
467  return -1; /* not valid */
468  }
469  o[p++] = u;
470  if (p >= SMSLEN_8) {
471  return p;
472  }
473  }
474  return p;
475 }
476 
477 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2
478  message (udl characters at ud) and packs in to o using 16 bit
479  UCS-2 character codes
480  The return value is the number of bytes packed in to o, which is
481  internally limited to 140
482  o can be null, in which case this is used to validate or count
483  only if the input contains invalid characters then
484  the return value is -1 */
485 static int packsms16(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
486 {
487  unsigned char p = 0;
488  unsigned char dummy[SMSLEN_8];
489 
490  if (o == NULL) {
491  o = dummy;
492  }
493  /* header - no encoding */
494  if (udhl) {
495  o[p++] = udhl;
496  while (udhl--) {
497  o[p++] = *udh++;
498  if (p >= SMSLEN_8) {
499  return p;
500  }
501  }
502  }
503  while (udl--) {
504  long u;
505  u = *ud++;
506  o[p++] = (u >> 8);
507  if (p >= SMSLEN_8) {
508  return p - 1; /* could not fit last character */
509  }
510  o[p++] = u;
511  if (p >= SMSLEN_8) {
512  return p;
513  }
514  }
515  return p;
516 }
517 
518 /*! \brief general pack, with length and data,
519  returns number of bytes of target used */
520 static int packsms(unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
521 {
522  unsigned char *p = base;
523  if (udl == 0) {
524  *p++ = 0; /* no user data */
525  } else {
526 
527  int l = 0;
528  if (is7bit(dcs)) { /* 7 bit */
529  if ((l = packsms7(p + 1, udhl, udh, udl, ud)) < 0) {
530  l = 0;
531  }
532  *p++ = l;
533  p += (l * 7 + 7) / 8;
534  } else if (is8bit(dcs)) { /* 8 bit */
535  if ((l = packsms8(p + 1, udhl, udh, udl, ud)) < 0) {
536  l = 0;
537  }
538  *p++ = l;
539  p += l;
540  } else { /* UCS-2 */
541  if ((l = packsms16(p + 1, udhl, udh, udl, ud)) < 0) {
542  l = 0;
543  }
544  *p++ = l;
545  p += l;
546  }
547  }
548  return p - base;
549 }
550 
551 
552 /*! \brief pack a date and return */
553 static void packdate(unsigned char *o, time_t w)
554 {
555  struct ast_tm t;
556  struct timeval topack = { w, 0 };
557  int z;
558 
559  ast_localtime(&topack, &t, NULL);
560 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) || defined(__CYGWIN__)
561  z = -t.tm_gmtoff / 60 / 15;
562 #else
563  z = timezone / 60 / 15;
564 #endif
565  *o++ = ((t.tm_year % 10) << 4) + (t.tm_year % 100) / 10;
566  *o++ = (((t.tm_mon + 1) % 10) << 4) + (t.tm_mon + 1) / 10;
567  *o++ = ((t.tm_mday % 10) << 4) + t.tm_mday / 10;
568  *o++ = ((t.tm_hour % 10) << 4) + t.tm_hour / 10;
569  *o++ = ((t.tm_min % 10) << 4) + t.tm_min / 10;
570  *o++ = ((t.tm_sec % 10) << 4) + t.tm_sec / 10;
571  if (z < 0) {
572  *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
573  } else {
574  *o++ = ((z % 10) << 4) + z / 10;
575  }
576 }
577 
578 /*! \brief unpack a date and return */
579 static struct timeval unpackdate(unsigned char *i)
580 {
581  struct ast_tm t;
582 
583  t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
584  t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
585  t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
586  t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
587  t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
588  t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
589  t.tm_isdst = 0;
590  if (i[6] & 0x08) {
591  t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
592  } else {
593  t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
594  }
595 
596  return ast_mktime(&t, NULL);
597 }
598 
599 /*! \brief unpacks bytes (7 bit encoding) at i, len l septets,
600  and places in udh and ud setting udhl and udl. udh not used
601  if udhi not set */
602 static void unpacksms7(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
603 {
604  unsigned char b = 0, p = 0;
605  unsigned short *o = ud;
606  *udhl = 0;
607  if (udhi && l) { /* header */
608  int h = i[p];
609  *udhl = h;
610  if (h) {
611  b = 1;
612  p++;
613  l--;
614  while (h-- && l) {
615  *udh++ = i[p++];
616  b += 8;
617  while (b >= 7) {
618  b -= 7;
619  l--;
620  if (!l) {
621  break;
622  }
623  }
624  }
625  /* adjust for fill, septets */
626  if (b) {
627  b = 7 - b;
628  l--;
629  }
630  }
631  }
632  while (l--) {
633  unsigned char v;
634  if (b < 2) {
635  v = ((i[p] >> b) & 0x7F); /* everything in one byte */
636  } else {
637  v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
638  }
639  b += 7;
640  if (b >= 8) {
641  b -= 8;
642  p++;
643  }
644  /* 0x00A0 is the encoding of ESC (27) in defaultalphabet */
645  if (o > ud && o[-1] == 0x00A0 && escapes[v]) {
646  o[-1] = escapes[v];
647  } else {
648  *o++ = defaultalphabet[v];
649  }
650  }
651  *udl = (o - ud);
652 }
653 
654 /*! \brief unpacks bytes (8 bit encoding) at i, len l septets,
655  * and places in udh and ud setting udhl and udl. udh not used
656  * if udhi not set.
657  */
658 static void unpacksms8(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
659 {
660  unsigned short *o = ud;
661  *udhl = 0;
662  if (udhi) {
663  int n = *i;
664  *udhl = n;
665  if (n) {
666  i++;
667  l--;
668  while (l && n) {
669  l--;
670  n--;
671  *udh++ = *i++;
672  }
673  }
674  }
675  while (l--) {
676  *o++ = *i++; /* not to UTF-8 as explicitly 8 bit coding in DCS */
677  }
678  *udl = (o - ud);
679 }
680 
681 /*! \brief unpacks bytes (16 bit encoding) at i, len l septets,
682  and places in udh and ud setting udhl and udl.
683  udh not used if udhi not set */
684 static void unpacksms16(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
685 {
686  unsigned short *o = ud;
687  *udhl = 0;
688  if (udhi) {
689  int n = *i;
690  *udhl = n;
691  if (n) {
692  i++;
693  l--;
694  while (l && n) {
695  l--;
696  n--;
697  *udh++ = *i++;
698  }
699  }
700  }
701  while (l--) {
702  int v = *i++;
703  if (l && l--) {
704  v = (v << 8) + *i++;
705  }
706  *o++ = v;
707  }
708  *udl = (o - ud);
709 }
710 
711 /*! \brief general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
712 static int unpacksms(unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
713 {
714  int l = *i++;
715  if (is7bit(dcs)) {
716  unpacksms7(i, l, udh, udhl, ud, udl, udhi);
717  l = (l * 7 + 7) / 8; /* adjust length to return */
718  } else if (is8bit(dcs)) {
719  unpacksms8(i, l, udh, udhl, ud, udl, udhi);
720  } else {
721  l += l % 2;
722  unpacksms16(i, l, udh, udhl, ud, udl, udhi);
723  }
724  return l + 1;
725 }
726 
727 /*! \brief unpack an address from i, return byte length, unpack to o */
728 static unsigned char unpackaddress(char *o, unsigned char *i)
729 {
730  unsigned char l = i[0], p;
731  if (i[1] == 0x91) {
732  *o++ = '+';
733  }
734  for (p = 0; p < l; p++) {
735  if (p & 1) {
736  *o++ = (i[2 + p / 2] >> 4) + '0';
737  } else {
738  *o++ = (i[2 + p / 2] & 0xF) + '0';
739  }
740  }
741  *o = 0;
742  return (l + 5) / 2;
743 }
744 
745 /*! \brief store an address at o, and return number of bytes used */
746 static unsigned char packaddress(unsigned char *o, char *i)
747 {
748  unsigned char p = 2;
749  o[0] = 0; /* number of bytes */
750  if (*i == '+') { /* record as bit 0 in byte 1 */
751  i++;
752  o[1] = 0x91;
753  } else {
754  o[1] = 0x81;
755  }
756  for ( ; *i ; i++) {
757  if (!isdigit(*i)) { /* ignore non-digits */
758  continue;
759  }
760  if (o[0] & 1) {
761  o[p++] |= ((*i & 0xF) << 4);
762  } else {
763  o[p] = (*i & 0xF);
764  }
765  o[0]++;
766  }
767  if (o[0] & 1) {
768  o[p++] |= 0xF0; /* pad */
769  }
770  return p;
771 }
772 
773 /*! \brief Log the output, and remove file */
774 static void sms_log(sms_t * h, char status)
775 {
776  int o;
777 
778  if (*h->oa == '\0' && *h->da == '\0') {
779  return;
780  }
781  o = open(log_file, O_CREAT | O_APPEND | O_WRONLY, AST_FILE_MODE);
782  if (o >= 0) {
783  char line[1000], mrs[3] = "", *p;
784  char buf[30];
785  unsigned char n;
786 
787  if (h->mr >= 0) {
788  snprintf(mrs, sizeof(mrs), "%02hhX", (unsigned char)h->mr);
789  }
790  snprintf(line, sizeof(line), "%s %c%c%c%s %s %s %s ",
791  isodate(time(NULL), buf, sizeof(buf)),
792  status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue,
793  S_OR(h->oa, "-"), S_OR(h->da, "-") );
794  p = line + strlen(line);
795 
796  if (h->nolog) {
797  p += snprintf(p, 1000 - strlen(line), "udl=%d", h->udl);
798  } else {
799  for (n = 0; n < h->udl; n++) {
800  if (h->ud[n] == '\\') {
801  *p++ = '\\';
802  *p++ = '\\';
803  } else if (h->ud[n] == '\n') {
804  *p++ = '\\';
805  *p++ = 'n';
806  } else if (h->ud[n] == '\r') {
807  *p++ = '\\';
808  *p++ = 'r';
809  } else if (h->ud[n] < 32 || h->ud[n] == 127) {
810  *p++ = 0xbf;
811  } else {
812  *p++ = h->ud[n];
813  }
814  }
815  }
816  *p++ = '\n';
817  *p = 0;
818  if (write(o, line, strlen(line)) < 0) {
819  ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
820  }
821  close(o);
822  }
823  *h->oa = *h->da = h->udl = 0;
824 }
825 
826 /*! \brief parse and delete a file */
827 static void sms_readfile(sms_t * h, char *fn)
828 {
829  char line[1000];
830  FILE *s;
831  char dcsset = 0; /* if DSC set */
832  ast_log(LOG_NOTICE, "Sending %s\n", fn);
833  h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
834  h->mr = -1;
835  h->dcs = 0xF1; /* normal messages class 1 */
836  h->scts = ast_tvnow();
837  s = fopen(fn, "r");
838  if (s) {
839  if (unlink(fn)) { /* concurrent access, we lost */
840  fclose(s);
841  return;
842  }
843  while (fgets (line, sizeof(line), s)) { /* process line in file */
844  char *p;
845  void *pp = &p;
846  for (p = line; *p && *p != '\n' && *p != '\r'; p++);
847  *p = 0; /* strip eoln */
848  p = line;
849  if (!*p || *p == ';') {
850  continue; /* blank line or comment, ignore */
851  }
852  while (isalnum(*p)) {
853  *p = tolower (*p);
854  p++;
855  }
856  while (isspace (*p)) {
857  *p++ = 0;
858  }
859  if (*p == '=') {
860  *p++ = 0;
861  if (!strcmp(line, "ud")) { /* parse message (UTF-8) */
862  unsigned char o = 0;
863  memcpy(h->udtxt, p, SMSLEN); /* for protocol 2 */
864  while (*p && o < SMSLEN) {
865  h->ud[o++] = utf8decode(pp);
866  }
867  h->udl = o;
868  if (*p) {
869  ast_log(LOG_WARNING, "UD too long in %s\n", fn);
870  }
871  } else {
872  while (isspace (*p)) {
873  p++;
874  }
875  if (!strcmp(line, "oa") && strlen(p) < sizeof(h->oa)) {
876  numcpy (h->oa, p);
877  } else if (!strcmp(line, "da") && strlen(p) < sizeof(h->oa)) {
878  numcpy (h->da, p);
879  } else if (!strcmp(line, "pid")) {
880  h->pid = atoi(p);
881  } else if (!strcmp(line, "dcs")) {
882  h->dcs = atoi(p);
883  dcsset = 1;
884  } else if (!strcmp(line, "mr")) {
885  h->mr = atoi(p);
886  } else if (!strcmp(line, "srr")) {
887  h->srr = (atoi(p) ? 1 : 0);
888  } else if (!strcmp(line, "vp")) {
889  h->vp = atoi(p);
890  } else if (!strcmp(line, "rp")) {
891  h->rp = (atoi(p) ? 1 : 0);
892  } else if (!strcmp(line, "scts")) { /* get date/time */
893  int Y, m, d, H, M, S;
894  /* XXX Why aren't we using ast_strptime here? */
895  if (sscanf(p, "%4d-%2d-%2dT%2d:%2d:%2d", &Y, &m, &d, &H, &M, &S) == 6) {
896  struct ast_tm t = { 0, };
897  t.tm_year = Y - 1900;
898  t.tm_mon = m - 1;
899  t.tm_mday = d;
900  t.tm_hour = H;
901  t.tm_min = M;
902  t.tm_sec = S;
903  t.tm_isdst = -1;
904  h->scts = ast_mktime(&t, NULL);
905  if (h->scts.tv_sec == 0) {
906  ast_log(LOG_WARNING, "Bad date/timein %s: %s", fn, p);
907  }
908  }
909  } else {
910  ast_log(LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
911  }
912  }
913  } else if (*p == '#') { /* raw hex format */
914  *p++ = 0;
915  if (*p == '#') {
916  p++;
917  if (!strcmp(line, "ud")) { /* user data */
918  int o = 0;
919  while (*p && o < SMSLEN) {
920  if (isxdigit(*p) && isxdigit(p[1]) && isxdigit(p[2]) && isxdigit(p[3])) {
921  h->ud[o++] =
922  (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 12) +
923  (((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
924  (((isalpha(p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha(p[3]) ? 9 : 0) + (p[3] & 0xF));
925  p += 4;
926  } else
927  break;
928  }
929  h->udl = o;
930  if (*p)
931  ast_log(LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
932  } else
933  ast_log(LOG_WARNING, "Only ud can use ## format, %s\n", fn);
934  } else if (!strcmp(line, "ud")) { /* user data */
935  int o = 0;
936  while (*p && o < SMSLEN) {
937  if (isxdigit(*p) && isxdigit(p[1])) {
938  h->ud[o++] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
939  p += 2;
940  } else {
941  break;
942  }
943  }
944  h->udl = o;
945  if (*p) {
946  ast_log(LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
947  }
948  } else if (!strcmp(line, "udh")) { /* user data header */
949  unsigned char o = 0;
950  h->udhi = 1;
951  while (*p && o < SMSLEN) {
952  if (isxdigit(*p) && isxdigit(p[1])) {
953  h->udh[o] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
954  o++;
955  p += 2;
956  } else {
957  break;
958  }
959  }
960  h->udhl = o;
961  if (*p) {
962  ast_log(LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
963  }
964  } else {
965  ast_log(LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
966  }
967  } else {
968  ast_log(LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
969  }
970  }
971  fclose(s);
972  if (!dcsset && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
973  if (packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
974  if (packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
975  ast_log(LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
976  } else {
977  h->dcs = 0x08; /* default to 16 bit */
978  ast_log(LOG_WARNING, "Sending in 16 bit format(%s)\n", fn);
979  }
980  } else {
981  h->dcs = 0xF5; /* default to 8 bit */
982  ast_log(LOG_WARNING, "Sending in 8 bit format(%s)\n", fn);
983  }
984  }
985  if (is7bit(h->dcs) && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
986  ast_log(LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
987  }
988  if (is8bit(h->dcs) && packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
989  ast_log(LOG_WARNING, "Invalid 8 bit data %s\n", fn);
990  }
991  if (is16bit(h->dcs) && packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
992  ast_log(LOG_WARNING, "Invalid 16 bit data %s\n", fn);
993  }
994  }
995 }
996 
997 /*! \brief white a received text message to a file */
998 static void sms_writefile(sms_t * h)
999 {
1000  char fn[200] = "", fn2[200] = "";
1001  char buf[30];
1002  FILE *o;
1003 
1004  if (ast_tvzero(h->scts)) {
1005  h->scts = ast_tvnow();
1006  }
1007  snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
1008  ast_mkdir(fn, 0777); /* ensure it exists */
1009  ast_copy_string(fn2, fn, sizeof(fn2));
1010  snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%s.%s-%u", h->queue, isodate(h->scts.tv_sec, buf, sizeof(buf)), seq++);
1011  snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1);
1012  if ((o = fopen(fn, "w")) == NULL) {
1013  return;
1014  }
1015 
1016  if (*h->oa) {
1017  fprintf(o, "oa=%s\n", h->oa);
1018  }
1019  if (*h->da) {
1020  fprintf(o, "da=%s\n", h->da);
1021  }
1022  if (h->udhi) {
1023  unsigned int p;
1024  fprintf(o, "udh#");
1025  for (p = 0; p < h->udhl; p++) {
1026  fprintf(o, "%02hhX", (unsigned char)h->udh[p]);
1027  }
1028  fprintf(o, "\n");
1029  }
1030  if (h->udl) {
1031  unsigned int p;
1032  for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
1033  if (p < h->udl) {
1034  fputc(';', o); /* cannot use ud=, but include as a comment for human readable */
1035  }
1036  fprintf(o, "ud=");
1037  for (p = 0; p < h->udl; p++) {
1038  unsigned short v = h->ud[p];
1039  if (v < 32) {
1040  fputc(191, o);
1041  } else if (v < 0x80) {
1042  fputc(v, o);
1043  } else if (v < 0x800) {
1044  fputc(0xC0 + (v >> 6), o);
1045  fputc(0x80 + (v & 0x3F), o);
1046  } else {
1047  fputc(0xE0 + (v >> 12), o);
1048  fputc(0x80 + ((v >> 6) & 0x3F), o);
1049  fputc(0x80 + (v & 0x3F), o);
1050  }
1051  }
1052  fprintf(o, "\n");
1053  for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
1054  if (p < h->udl) {
1055  for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
1056  if (p == h->udl) { /* can write in ucs-1 hex */
1057  fprintf(o, "ud#");
1058  for (p = 0; p < h->udl; p++) {
1059  fprintf(o, "%02hhX", (unsigned char)h->ud[p]);
1060  }
1061  fprintf(o, "\n");
1062  } else { /* write in UCS-2 */
1063  fprintf(o, "ud##");
1064  for (p = 0; p < h->udl; p++) {
1065  fprintf(o, "%04X", (unsigned)h->ud[p]);
1066  }
1067  fprintf(o, "\n");
1068  }
1069  }
1070  }
1071  if (h->scts.tv_sec) {
1072  char datebuf[30];
1073  fprintf(o, "scts=%s\n", isodate(h->scts.tv_sec, datebuf, sizeof(datebuf)));
1074  }
1075  if (h->pid) {
1076  fprintf(o, "pid=%d\n", h->pid);
1077  }
1078  if (h->dcs != 0xF1) {
1079  fprintf(o, "dcs=%d\n", h->dcs);
1080  }
1081  if (h->vp) {
1082  fprintf(o, "vp=%u\n", h->vp);
1083  }
1084  if (h->srr) {
1085  fprintf(o, "srr=1\n");
1086  }
1087  if (h->mr >= 0) {
1088  fprintf(o, "mr=%d\n", h->mr);
1089  }
1090  if (h->rp) {
1091  fprintf(o, "rp=1\n");
1092  }
1093  fclose(o);
1094  if (rename(fn, fn2)) {
1095  unlink(fn);
1096  } else {
1097  ast_log(LOG_NOTICE, "Received to %s\n", fn2);
1098  }
1099 }
1100 
1101 /*! \brief read dir skipping dot files... */
1102 static struct dirent *readdirqueue(DIR *d, char *queue)
1103 {
1104  struct dirent *f;
1105  do {
1106  f = readdir(d);
1107  } while (f && (*f->d_name == '.' || strncmp(f->d_name, queue, strlen(queue)) || f->d_name[strlen(queue)] != '.'));
1108  return f;
1109 }
1110 
1111 /*! \brief handle the incoming message */
1112 static unsigned char sms_handleincoming (sms_t * h)
1113 {
1114  unsigned char p = 3;
1115  if (h->smsc) { /* SMSC */
1116  if ((h->imsg[2] & 3) == 1) { /* SMS-SUBMIT */
1117  h->udhl = h->udl = 0;
1118  h->vp = 0;
1119  h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
1120  h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1121  h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1122  ast_copy_string(h->oa, h->cli, sizeof(h->oa));
1123  h->scts = ast_tvnow();
1124  h->mr = h->imsg[p++];
1125  p += unpackaddress(h->da, h->imsg + p);
1126  h->pid = h->imsg[p++];
1127  h->dcs = h->imsg[p++];
1128  if ((h->imsg[2] & 0x18) == 0x10) { /* relative VP */
1129  if (h->imsg[p] < 144) {
1130  h->vp = (h->imsg[p] + 1) * 5;
1131  } else if (h->imsg[p] < 168) {
1132  h->vp = 720 + (h->imsg[p] - 143) * 30;
1133  } else if (h->imsg[p] < 197) {
1134  h->vp = (h->imsg[p] - 166) * 1440;
1135  } else {
1136  h->vp = (h->imsg[p] - 192) * 10080;
1137  }
1138  p++;
1139  } else if (h->imsg[2] & 0x18) {
1140  p += 7; /* ignore enhanced / absolute VP */
1141  }
1142  p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1143  h->rx = 1; /* received message */
1144  sms_writefile(h); /* write the file */
1145  if (p != h->imsg[1] + 2) {
1146  ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1147  return 0xFF; /* duh! */
1148  }
1149  } else {
1150  ast_log(LOG_WARNING, "Unknown message type %02hhX\n", h->imsg[2]);
1151  return 0xFF;
1152  }
1153  } else { /* client */
1154  if (!(h->imsg[2] & 3)) { /* SMS-DELIVER */
1155  *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
1156  h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
1157  h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1158  h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1159  h->mr = -1;
1160  p += unpackaddress(h->oa, h->imsg + p);
1161  h->pid = h->imsg[p++];
1162  h->dcs = h->imsg[p++];
1163  h->scts = unpackdate(h->imsg + p);
1164  p += 7;
1165  p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1166  h->rx = 1; /* received message */
1167  sms_writefile(h); /* write the file */
1168  if (p != h->imsg[1] + 2) {
1169  ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1170  return 0xFF; /* duh! */
1171  }
1172  } else {
1173  ast_log(LOG_WARNING, "Unknown message type %02hhX\n", h->imsg[2]);
1174  return 0xFF;
1175  }
1176  }
1177  return 0; /* no error */
1178 }
1179 
1180 #ifdef SOLARIS
1181 #define NAME_MAX 1024
1182 #endif
1183 
1184 /*!
1185  * Add data to a protocol 2 message.
1186  * Use the length field (h->omsg[1]) as a pointer to the next free position.
1187  */
1188 static void adddata_proto2(sms_t *h, unsigned char msg, char *data, int size)
1189 {
1190  int x = h->omsg[1] + 2; /* Get current position */
1191  if (x == 2) {
1192  x += 2; /* First: skip Payload length (set later) */
1193  }
1194  h->omsg[x++] = msg; /* Message code */
1195  h->omsg[x++] = (unsigned char)size; /* Data size Low */
1196  h->omsg[x++] = 0; /* Data size Hi */
1197  for (; size > 0 ; size--) {
1198  h->omsg[x++] = *data++;
1199  }
1200  h->omsg[1] = x - 2; /* Frame size */
1201  h->omsg[2] = x - 4; /* Payload length (Lo) */
1202  h->omsg[3] = 0; /* Payload length (Hi) */
1203 }
1204 
1206 {
1207  adddata_proto2(h, 0x10, "\0", 1); /* Media Identifier > SMS */
1208  adddata_proto2(h, 0x11, "\0\0\0\0\0\0", 6); /* Firmware version */
1209  adddata_proto2(h, 0x12, "\2\0\4", 3); /* SMS provider ID */
1210  adddata_proto2(h, 0x13, h->udtxt, h->udl); /* Body */
1211 }
1212 
1213 static void sms_compose2(sms_t *h, int more)
1214 {
1215  struct ast_tm tm;
1216  struct timeval now = h->scts;
1217  char stm[45];
1218 
1219  h->omsg[0] = 0x00; /* set later... */
1220  h->omsg[1] = 0;
1222  if (h->smsc) { /* deliver */
1223  h->omsg[0] = 0x11; /* SMS_DELIVERY */
1224  /* Required: 10 11 12 13 14 15 17 (seems they must be ordered!) */
1225  ast_localtime(&now, &tm, NULL);
1226  sprintf(stm, "%02d%02d%02d%02d", tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min); /* Date mmddHHMM */
1227  adddata_proto2(h, 0x14, stm, 8); /* Date */
1228  if (*h->oa == 0) {
1229  strcpy(h->oa, "00000000");
1230  }
1231  adddata_proto2(h, 0x15, h->oa, strlen(h->oa)); /* Originator */
1232  adddata_proto2(h, 0x17, "\1", 1); /* Calling Terminal ID */
1233  } else { /* submit */
1234  h->omsg[0] = 0x10; /* SMS_SUBMIT */
1235  /* Required: 10 11 12 13 17 18 1B 1C (seems they must be ordered!) */
1236  adddata_proto2(h, 0x17, "\1", 1); /* Calling Terminal ID */
1237  if (*h->da == 0) {
1238  strcpy(h->da, "00000000");
1239  }
1240  adddata_proto2(h, 0x18, h->da, strlen(h->da)); /* Originator */
1241  adddata_proto2(h, 0x1B, "\1", 1); /* Called Terminal ID */
1242  adddata_proto2(h, 0x1C, "\0\0\0", 3); /* Notification */
1243  }
1244 }
1245 
1246 static void putdummydata_proto2(sms_t *h);
1247 
1248 #define MAX_DEBUG_LEN 300
1249 static char *sms_hexdump(unsigned char buf[], int size, char *s /* destination */)
1250 {
1251  char *p;
1252  int f;
1253 
1254  for (p = s, f = 0; f < size && f < MAX_DEBUG_LEN; f++, p += 3) {
1255  sprintf(p, "%02hhX ", (unsigned char)buf[f]);
1256  }
1257  return(s);
1258 }
1259 
1260 
1261 /*! \brief sms_handleincoming_proto2: handle the incoming message */
1263 {
1264  int f, i, sz = 0;
1265  int msg, msgsz;
1266  struct ast_tm tm;
1267  struct timeval now = { 0, 0 };
1268  char debug_buf[MAX_DEBUG_LEN * 3 + 1];
1269 
1270  sz = h->imsg[1] + 2;
1271  /* ast_verb(3, "SMS-P2 Frame: %s\n", sms_hexdump(h->imsg, sz, debug_buf)); */
1272 
1273  /* Parse message body (called payload) */
1274  now = h->scts = ast_tvnow();
1275  for (f = 4; f < sz; ) {
1276  msg = h->imsg[f++];
1277  msgsz = h->imsg[f++];
1278  msgsz += (h->imsg[f++] * 256);
1279  switch (msg) {
1280  case 0x13: /* Body */
1281  ast_verb(3, "SMS-P2 Body#%02X=[%.*s]\n", (unsigned)msg, msgsz, &h->imsg[f]);
1282  if (msgsz >= sizeof(h->ud)) {
1283  msgsz = sizeof(h->ud) - 1;
1284  }
1285  for (i = 0; i < msgsz; i++) {
1286  h->ud[i] = h->imsg[f + i];
1287  }
1288  h->udl = msgsz;
1289  break;
1290  case 0x14: /* Date SCTS */
1291  now = h->scts = ast_tvnow();
1292  ast_localtime(&now, &tm, NULL);
1293  tm.tm_mon = ( (h->imsg[f] * 10) + h->imsg[f + 1] ) - 1;
1294  tm.tm_mday = ( (h->imsg[f + 2] * 10) + h->imsg[f + 3] );
1295  tm.tm_hour = ( (h->imsg[f + 4] * 10) + h->imsg[f + 5] );
1296  tm.tm_min = ( (h->imsg[f + 6] * 10) + h->imsg[f + 7] );
1297  tm.tm_sec = 0;
1298  h->scts = ast_mktime(&tm, NULL);
1299  ast_verb(3, "SMS-P2 Date#%02X=%02d/%02d %02d:%02d\n", (unsigned)msg, tm.tm_mday, tm.tm_mon + 1, tm.tm_hour, tm.tm_min);
1300  break;
1301  case 0x15: /* Calling line (from SMSC) */
1302  if (msgsz >= 20) {
1303  msgsz = 20 - 1;
1304  }
1305  ast_verb(3, "SMS-P2 Origin#%02X=[%.*s]\n", (unsigned)msg, msgsz, &h->imsg[f]);
1306  ast_copy_string(h->oa, (char *)(&h->imsg[f]), msgsz + 1);
1307  break;
1308  case 0x18: /* Destination(from TE/phone) */
1309  if (msgsz >= 20) {
1310  msgsz = 20 - 1;
1311  }
1312  ast_verb(3, "SMS-P2 Destination#%02X=[%.*s]\n", (unsigned)msg, msgsz, &h->imsg[f]);
1313  ast_copy_string(h->da, (char *)(&h->imsg[f]), msgsz + 1);
1314  break;
1315  case 0x1C: /* Notify */
1316  ast_verb(3, "SMS-P2 Notify#%02X=%s\n", (unsigned)msg, sms_hexdump(&h->imsg[f], 3, debug_buf));
1317  break;
1318  default:
1319  ast_verb(3, "SMS-P2 Par#%02X [%d]: %s\n", (unsigned)msg, msgsz, sms_hexdump(&h->imsg[f], msgsz, debug_buf));
1320  break;
1321  }
1322  f+=msgsz; /* Skip to next */
1323  }
1324  h->rx = 1; /* received message */
1325  sms_writefile(h); /* write the file */
1326  return 0; /* no error */
1327 }
1328 
1329 #if 0
1330 static void smssend(sms_t *h, char *c)
1331 {
1332  int f, x;
1333  for (f = 0; f < strlen(c); f++) {
1334  sscanf(&c[f*3], "%x", &x);
1335  h->omsg[f] = x;
1336  }
1337  sms_messagetx(h);
1338 }
1339 #endif
1340 
1341 static void sms_nextoutgoing (sms_t *h);
1342 
1343 static void sms_messagerx2(sms_t * h)
1344 {
1345  int p = h->imsg[0] & DLL_SMS_MASK ; /* mask the high bit */
1346  int cause;
1347 
1348 #define DLL2_ACK(h) ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1)
1349  switch (p) {
1350  case DLL2_SMS_EST: /* Protocol 2: Connection ready (fake): send message */
1351  sms_nextoutgoing (h);
1352  /* 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 "); */
1353  break;
1354 
1355  case DLL2_SMS_INFO_MO: /* transport SMS_SUBMIT */
1356  case DLL2_SMS_INFO_MT: /* transport SMS_DELIVERY */
1357  cause = sms_handleincoming_proto2(h);
1358  if (!cause) { /* ACK */
1359  sms_log(h, 'Y');
1360  }
1361  h->omsg[0] = DLL2_ACK(h);
1362  h->omsg[1] = 0x06; /* msg len */
1363  h->omsg[2] = 0x04; /* payload len */
1364  h->omsg[3] = 0x00; /* payload len */
1365  h->omsg[4] = 0x1f; /* Response type */
1366  h->omsg[5] = 0x01; /* parameter len */
1367  h->omsg[6] = 0x00; /* parameter len */
1368  h->omsg[7] = cause; /* CONFIRM or error */
1369  sms_messagetx(h);
1370  break;
1371 
1372  case DLL2_SMS_NACK: /* Protocol 2: SMS_NAK */
1373  h->omsg[0] = DLL2_SMS_REL; /* SMS_REL */
1374  h->omsg[1] = 0x00; /* msg len */
1375  sms_messagetx(h);
1376  break;
1377 
1378  case DLL2_SMS_ACK0:
1379  case DLL2_SMS_ACK1:
1380  /* SMS_ACK also transport SMS_SUBMIT or SMS_DELIVERY */
1381  if ( (h->omsg[0] & DLL_SMS_MASK) == DLL2_SMS_REL) {
1382  /* a response to our Release, just hangup */
1383  h->hangup = 1; /* hangup */
1384  } else {
1385  /* XXX depending on what we are.. */
1386  ast_log(LOG_NOTICE, "SMS_SUBMIT or SMS_DELIVERY\n");
1387  sms_nextoutgoing (h);
1388  }
1389  break;
1390 
1391  case DLL2_SMS_REL: /* Protocol 2: SMS_REL (hangup req) */
1392  h->omsg[0] = DLL2_ACK(h);
1393  h->omsg[1] = 0;
1394  sms_messagetx(h);
1395  break;
1396  }
1397 }
1398 
1399 /*! \brief compose a message for protocol 1 */
1400 static void sms_compose1(sms_t *h, int more)
1401 {
1402  unsigned int p = 2; /* next byte to write. Skip type and len */
1403 
1404  h->omsg[0] = 0x91; /* SMS_DATA */
1405  if (h->smsc) { /* deliver */
1406  h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
1407  p += packaddress(h->omsg + p, h->oa);
1408  h->omsg[p++] = h->pid;
1409  h->omsg[p++] = h->dcs;
1410  packdate(h->omsg + p, h->scts.tv_sec);
1411  p += 7;
1412  p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1413  } else { /* submit */
1414  h->omsg[p++] =
1415  0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
1416  if (h->mr < 0) {
1417  h->mr = message_ref++;
1418  }
1419  h->omsg[p++] = h->mr;
1420  p += packaddress(h->omsg + p, h->da);
1421  h->omsg[p++] = h->pid;
1422  h->omsg[p++] = h->dcs;
1423  if (h->vp) { /* relative VP */
1424  if (h->vp < 720) {
1425  h->omsg[p++] = (h->vp + 4) / 5 - 1;
1426  } else if (h->vp < 1440) {
1427  h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
1428  } else if (h->vp < 43200) {
1429  h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
1430  } else if (h->vp < 635040) {
1431  h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
1432  } else {
1433  h->omsg[p++] = 255; /* max */
1434  }
1435  }
1436  p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1437  }
1438  h->omsg[1] = p - 2;
1439 }
1440 
1441 /*! \brief find and fill in next message, or send a REL if none waiting */
1442 static void sms_nextoutgoing (sms_t * h)
1443 {
1444  char fn[100 + NAME_MAX] = "";
1445  DIR *d;
1446  char more = 0;
1447 
1448  *h->da = *h->oa = '\0'; /* clear destinations */
1449  h->rx = 0; /* outgoing message */
1450  snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? "mttx" : "motx");
1451  ast_mkdir(fn, 0777); /* ensure it exists */
1452  d = opendir(fn);
1453  if (d) {
1454  struct dirent *f = readdirqueue(d, h->queue);
1455  if (f) {
1456  snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", f->d_name);
1457  sms_readfile(h, fn);
1458  if (readdirqueue(d, h->queue)) {
1459  more = 1; /* more to send */
1460  }
1461  }
1462  closedir(d);
1463  }
1464  if (*h->da || *h->oa) { /* message to send */
1465  if (h->protocol == 2) {
1466  sms_compose2(h, more);
1467  } else {
1468  sms_compose1(h, more);
1469  }
1470  } else { /* no message */
1471  if (h->protocol == 2) {
1472  h->omsg[0] = 0x17; /* SMS_REL */
1473  h->omsg[1] = 0;
1474  } else {
1475  h->omsg[0] = 0x94; /* SMS_REL */
1476  h->omsg[1] = 0;
1477  h->sent_rel = 1;
1478  }
1479  }
1480  sms_messagetx(h);
1481 }
1482 
1483 #define DIR_RX 1
1484 #define DIR_TX 2
1485 static void sms_debug (int dir, sms_t *h)
1486 {
1487  char txt[259 * 3 + 1];
1488  char *p = txt; /* always long enough */
1489  unsigned char *msg = (dir == DIR_RX) ? h->imsg : h->omsg;
1490  int n = (dir == DIR_RX) ? h->ibytep : msg[1] + 2;
1491  int q = 0;
1492  while (q < n && q < 30) {
1493  sprintf(p, " %02hhX", msg[q++]);
1494  p += 3;
1495  }
1496  if (q < n) {
1497  sprintf(p, "...");
1498  }
1499  ast_verb(3, "SMS %s%s\n", dir == DIR_RX ? "RX" : "TX", txt);
1500 }
1501 
1502 
1503 static void sms_messagerx(sms_t * h)
1504 {
1505  int cause;
1506 
1507  sms_debug (DIR_RX, h);
1508  if (h->protocol == 2) {
1509  sms_messagerx2(h);
1510  return;
1511  }
1512  /* parse incoming message for Protocol 1 */
1513  switch (h->imsg[0]) {
1514  case 0x91: /* SMS_DATA */
1515  cause = sms_handleincoming (h);
1516  if (!cause) {
1517  sms_log(h, 'Y');
1518  h->omsg[0] = 0x95; /* SMS_ACK */
1519  h->omsg[1] = 0x02;
1520  h->omsg[2] = 0x00; /* deliver report */
1521  h->omsg[3] = 0x00; /* no parameters */
1522  } else { /* NACK */
1523  sms_log(h, 'N');
1524  h->omsg[0] = 0x96; /* SMS_NACK */
1525  h->omsg[1] = 3;
1526  h->omsg[2] = 0; /* delivery report */
1527  h->omsg[3] = cause; /* cause */
1528  h->omsg[4] = 0; /* no parameters */
1529  }
1530  sms_messagetx(h);
1531  break;
1532 
1533  case 0x92: /* SMS_ERROR */
1534  h->err = 1;
1535  sms_messagetx(h); /* send whatever we sent again */
1536  break;
1537  case 0x93: /* SMS_EST */
1538  sms_nextoutgoing (h);
1539  break;
1540  case 0x94: /* SMS_REL */
1541  h->hangup = 1; /* hangup */
1542  break;
1543  case 0x95: /* SMS_ACK */
1544  sms_log(h, 'Y');
1545  sms_nextoutgoing (h);
1546  break;
1547  case 0x96: /* SMS_NACK */
1548  h->err = 1;
1549  sms_log(h, 'N');
1550  sms_nextoutgoing (h);
1551  break;
1552  default: /* Unknown */
1553  h->omsg[0] = 0x92; /* SMS_ERROR */
1554  h->omsg[1] = 1;
1555  h->omsg[2] = 3; /* unknown message type */
1556  sms_messagetx(h);
1557  break;
1558  }
1559 }
1560 
1561 static void sms_messagetx(sms_t * h)
1562 {
1563  unsigned char c = 0, p;
1564  int len = h->omsg[1] + 2; /* total message length excluding checksum */
1565 
1566  for (p = 0; p < len; p++) { /* compute checksum */
1567  c += h->omsg[p];
1568  }
1569  h->omsg[len] = 0 - c; /* actually, (256 - (c & 0fxx)) & 0xff) */
1570  sms_debug(DIR_TX, h);
1571  h->framenumber++; /* Proto 2 */
1572  h->obytep = 0;
1573  h->obitp = 0;
1574  if (h->protocol == 2) { /* Proto 2: */
1575  h->oseizure = 300; /* 300bits (or more ?) */
1576  h->obyte = 0; /* Seizure starts with space (0) */
1577  if (h->omsg[0] == 0x7F) {
1578  h->opause = 8 * h->opause_0; /* initial message delay */
1579  } else {
1580  h->opause = 400;
1581  }
1582  } else { /* Proto 1: */
1583  h->oseizure = 0; /* No seizure */
1584  h->obyte = 1; /* send mark ('1') at the beginning */
1585  /* Change the initial message delay. BT requires 300ms,
1586  * but for others this might be way too much and the phone
1587  * could time out. XXX make it configurable.
1588  */
1589  if (h->omsg[0] == 0x93) {
1590  h->opause = 8 * h->opause_0; /* initial message delay */
1591  } else {
1592  h->opause = 200;
1593  }
1594  }
1595  /* Note - setting osync triggers the generator */
1596  h->osync = OSYNC_BITS; /* 80 sync bits */
1597  h->obyten = len + 1; /* bytes to send (including checksum) */
1598 }
1599 
1600 /*!
1601  * outgoing data are produced by this generator function, that reads from
1602  * the descriptor whether it has data to send and which ones.
1603  */
1604 static int sms_generate(struct ast_channel *chan, void *data, int len, int samples)
1605 {
1606  struct ast_frame f = { 0 };
1607 #define MAXSAMPLES (800)
1608  output_t *buf;
1609  sms_t *h = data;
1610  int i, res;
1611 
1612  if (samples > MAXSAMPLES) {
1613  ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n",
1614  MAXSAMPLES, samples);
1615  samples = MAXSAMPLES;
1616  }
1617  len = samples * sizeof(*buf) + AST_FRIENDLY_OFFSET;
1618  buf = ast_alloca(len);
1619 
1622  f.datalen = samples * sizeof(*buf);
1624  f.mallocd = 0;
1625  f.data.ptr = buf;
1626  f.samples = samples;
1627  f.src = "app_sms";
1628  /* create a buffer containing the digital sms pattern */
1629  for (i = 0; i < samples; i++) {
1630  buf[i] = wave_out[0]; /* default is silence */
1631 
1632  if (h->opause) {
1633  h->opause--;
1634  } else if (h->obyten || h->osync) { /* sending data */
1635  buf[i] = wave_out[h->ophase];
1636  h->ophase += (h->obyte & 1) ? 13 : 21; /* compute next phase */
1637  if (h->ophase >= 80)
1638  h->ophase -= 80;
1639  if ((h->ophasep += 12) >= 80) { /* time to send the next bit */
1640  h->ophasep -= 80;
1641  if (h->oseizure > 0) { /* sending channel seizure (proto 2) */
1642  h->oseizure--;
1643  h->obyte ^= 1; /* toggle low bit */
1644  } else if (h->osync) {
1645  h->obyte = 1; /* send mark as sync bit */
1646  h->osync--; /* sending sync bits */
1647  if (h->osync == 0 && h->protocol == 2 && h->omsg[0] == DLL2_SMS_EST) {
1648  h->obytep = h->obyten = 0; /* we are done */
1649  }
1650  } else {
1651  h->obitp++;
1652  if (h->obitp == 1) {
1653  h->obyte = 0; /* start bit; */
1654  } else if (h->obitp == 2) {
1655  h->obyte = h->omsg[h->obytep];
1656  } else if (h->obitp == 10) {
1657  h->obyte = 1; /* stop bit */
1658  h->obitp = 0;
1659  h->obytep++;
1660  if (h->obytep == h->obyten) {
1661  h->obytep = h->obyten = 0; /* sent */
1662  h->osync = 10; /* trailing marks */
1663  }
1664  } else {
1665  h->obyte >>= 1;
1666  }
1667  }
1668  }
1669  }
1670  }
1671  res = ast_write(chan, &f);
1672  ast_frfree(&f);
1673  if (res < 0) {
1674  ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
1675  return -1;
1676  }
1677  return 0;
1678 #undef MAXSAMPLES
1679 }
1680 
1681 /*!
1682  * Just return the pointer to the descriptor that we received.
1683  */
1684 static void *sms_alloc(struct ast_channel *chan, void *sms_t_ptr)
1685 {
1686  return sms_t_ptr;
1687 }
1688 
1689 static void sms_release(struct ast_channel *chan, void *data)
1690 {
1691  return; /* nothing to do here. */
1692 }
1693 
1694 static struct ast_generator smsgen = {
1695  .alloc = sms_alloc,
1696  .release = sms_release,
1697  .generate = sms_generate,
1698 };
1699 
1700 /*!
1701  * Process an incoming frame, trying to detect the carrier and
1702  * decode the message. The two frequencies are 1300 and 2100 Hz.
1703  * The decoder detects the amplitude of the signal over the last
1704  * few samples, filtering the absolute values with a lowpass filter.
1705  * If the magnitude (h->imag) is large enough, multiply the signal
1706  * by the two carriers, and compute the amplitudes m0 and m1.
1707  * Record the current sample as '0' or '1' depending on which one is greater.
1708  * The last 3 bits are stored in h->ibith, with the count of '1'
1709  * bits in h->ibitt.
1710  * XXX the rest is to be determined.
1711  */
1712 static void sms_process(sms_t * h, int samples, signed short *data)
1713 {
1714  int bit;
1715 
1716  /*
1717  * Ignore incoming audio while a packet is being transmitted,
1718  * the protocol is half-duplex.
1719  * Unfortunately this means that if the outbound and incoming
1720  * transmission overlap (which is an error condition anyways),
1721  * we may miss some data and this makes debugging harder.
1722  */
1723  if (h->obyten || h->osync) {
1724  return;
1725  }
1726  for ( ; samples-- ; data++) {
1727  unsigned long long m0, m1;
1728  if (abs(*data) > h->imag) {
1729  h->imag = abs(*data);
1730  } else {
1731  h->imag = h->imag * 7 / 8;
1732  }
1733  if (h->imag <= 500) { /* below [arbitrary] threahold: lost carrier */
1734  if (h->idle++ == 80000) { /* nothing happening */
1735  ast_log(LOG_NOTICE, "No data, hanging up\n");
1736  h->hangup = 1;
1737  h->err = 1;
1738  }
1739  if (h->ierr) { /* error */
1740  ast_log(LOG_NOTICE, "Error %d, hanging up\n", h->ierr);
1741  /* Protocol 1 */
1742  h->err = 1;
1743  h->omsg[0] = 0x92; /* error */
1744  h->omsg[1] = 1;
1745  h->omsg[2] = h->ierr;
1746  sms_messagetx(h); /* send error */
1747  }
1748  h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1749  continue;
1750  }
1751  h->idle = 0;
1752 
1753  /* multiply signal by the two carriers. */
1754  h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
1755  h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
1756  h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
1757  h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
1758  /* compute the amplitudes */
1759  m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
1760  m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
1761 
1762  /* advance the sin/cos pointers */
1763  if ((h->ips0 += 21) >= 80) {
1764  h->ips0 -= 80;
1765  }
1766  if ((h->ipc0 += 21) >= 80) {
1767  h->ipc0 -= 80;
1768  }
1769  if ((h->ips1 += 13) >= 80) {
1770  h->ips1 -= 80;
1771  }
1772  if ((h->ipc1 += 13) >= 80) {
1773  h->ipc1 -= 80;
1774  }
1775 
1776  /* set new bit to 1 or 0 depending on which value is stronger */
1777  h->ibith <<= 1;
1778  if (m1 > m0) {
1779  h->ibith |= 1;
1780  }
1781  if (h->ibith & 8) {
1782  h->ibitt--;
1783  }
1784  if (h->ibith & 1) {
1785  h->ibitt++;
1786  }
1787  bit = ((h->ibitt > 1) ? 1 : 0);
1788  if (bit != h->ibitl) {
1789  h->ibitc = 1;
1790  } else {
1791  h->ibitc++;
1792  }
1793  h->ibitl = bit;
1794  if (!h->ibitn && h->ibitc == 4 && !bit) {
1795  h->ibitn = 1;
1796  h->iphasep = 0;
1797  }
1798  if (bit && h->ibitc == 200) { /* sync, restart message */
1799  /* Protocol 2: empty connection ready (I am master) */
1800  if (h->framenumber < 0 && h->ibytec >= 160 && !memcmp(h->imsg, "UUUUUUUUUUUUUUUUUUUU", 20)) {
1801  h->framenumber = 1;
1802  ast_verb(3, "SMS protocol 2 detected\n");
1803  h->protocol = 2;
1804  h->imsg[0] = 0xff; /* special message (fake) */
1805  h->imsg[1] = h->imsg[2] = 0x00;
1806  h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1807  sms_messagerx(h);
1808  }
1809  h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1810  }
1811  if (h->ibitn) {
1812  h->iphasep += 12;
1813  if (h->iphasep >= 80) { /* next bit */
1814  h->iphasep -= 80;
1815  if (h->ibitn++ == 9) { /* end of byte */
1816  if (!bit) { /* bad stop bit */
1817  if (h->sent_rel) {
1818  h->hangup = 1;
1819  } else {
1820  ast_log(LOG_NOTICE, "Bad stop bit\n");
1821  h->ierr = 0xFF; /* unknown error */
1822  }
1823  } else {
1824  if (h->ibytep < sizeof(h->imsg)) {
1825  h->imsg[h->ibytep] = h->ibytev;
1826  h->ibytec += h->ibytev;
1827  h->ibytep++;
1828  } else if (h->ibytep == sizeof(h->imsg)) {
1829  ast_log(LOG_NOTICE, "msg too large\n");
1830  h->ierr = 2; /* bad message length */
1831  }
1832  if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
1833  if (!h->ibytec) {
1834  sms_messagerx(h);
1835  } else {
1836  ast_log(LOG_NOTICE, "bad checksum\n");
1837  h->ierr = 1; /* bad checksum */
1838  }
1839  }
1840  }
1841  h->ibitn = 0;
1842  }
1843  h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1844  }
1845  }
1846  }
1847 }
1848 
1849 /*
1850  * Standard argument parsing:
1851  * - one enum for the flags we recognise,
1852  * - one enum for argument indexes
1853  * - AST_APP_OPTIONS() to drive the parsing routine
1854  * - in the function, AST_DECLARE_APP_ARGS(...) for the arguments.
1855  */
1857  OPTION_BE_SMSC = (1 << 0), /* act as sms center */
1858  OPTION_ANSWER = (1 << 1), /* answer on incoming calls */
1859  OPTION_TWO = (1 << 2), /* Use Protocol Two */
1860  OPTION_PAUSE = (1 << 3), /* pause before sending data, in ms */
1861  OPTION_SRR = (1 << 4), /* set srr */
1862  OPTION_DCS = (1 << 5), /* set dcs */
1863  OPTIONS_NO_LOG = (1 << 6), /* Don't log SMS content */
1864 };
1865 
1869 };
1870 
1874  AST_APP_OPTION('t', OPTION_TWO),
1875  AST_APP_OPTION('r', OPTION_SRR),
1876  AST_APP_OPTION('o', OPTION_DCS),
1879  } );
1880 
1881 static int sms_exec(struct ast_channel *chan, const char *data)
1882 {
1883  int res = -1;
1884  sms_t h = { 0 };
1885  /* argument parsing support */
1886  struct ast_flags flags = { 0 };
1887  char *parse, *sms_opts[OPTION_ARG_ARRAY_SIZE] = { 0, };
1888  char *p;
1889  AST_DECLARE_APP_ARGS(sms_args,
1890  AST_APP_ARG(queue);
1892  AST_APP_ARG(addr);
1893  AST_APP_ARG(body);
1894  );
1895 
1896  if (!data) {
1897  ast_log(LOG_ERROR, "Requires queue name at least\n");
1898  return -1;
1899  }
1900 
1901  parse = ast_strdupa(data); /* create a local copy */
1902  AST_STANDARD_APP_ARGS(sms_args, parse);
1903  if (sms_args.argc > 1) {
1904  ast_app_parse_options(sms_options, &flags, sms_opts, sms_args.options);
1905  }
1906 
1907  ast_verb(1, "sms argc %u queue <%s> opts <%s> addr <%s> body <%s>\n",
1908  sms_args.argc, S_OR(sms_args.queue, ""),
1909  S_OR(sms_args.options, ""),
1910  S_OR(sms_args.addr, ""),
1911  S_OR(sms_args.body, "") );
1912 
1913  h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1914  h.dcs = 0xF1; /* default */
1915 
1916  ast_copy_string(h.cli,
1917  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
1918  sizeof(h.cli));
1919 
1920  if (ast_strlen_zero(sms_args.queue)) {
1921  ast_log(LOG_ERROR, "Requires queue name\n");
1922  goto done;
1923  }
1924  if (strlen(sms_args.queue) >= sizeof(h.queue)) {
1925  ast_log(LOG_ERROR, "Queue name too long\n");
1926  goto done;
1927  }
1928  ast_copy_string(h.queue, sms_args.queue, sizeof(h.queue));
1929 
1930  for (p = h.queue; *p; p++) {
1931  if (!isalnum(*p)) {
1932  *p = '-'; /* make very safe for filenames */
1933  }
1934  }
1935 
1936  h.smsc = ast_test_flag(&flags, OPTION_BE_SMSC);
1937  h.protocol = ast_test_flag(&flags, OPTION_TWO) ? 2 : 1;
1938  h.nolog = ast_test_flag(&flags, OPTIONS_NO_LOG) ? 1 : 0;
1939  if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE])) {
1940  h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]);
1941  }
1942  if (h.opause_0 < 25 || h.opause_0 > 2000) {
1943  h.opause_0 = 300; /* default 300ms */
1944  }
1945  ast_verb(1, "initial delay %dms\n", h.opause_0);
1946 
1947 
1948  /* the following apply if there is an arg3/4 and apply to the created message file */
1949  if (ast_test_flag(&flags, OPTION_SRR)) {
1950  h.srr = 1;
1951  }
1952  if (ast_test_flag(&flags, OPTION_DCS)) {
1953  h.dcs = 1;
1954  }
1955 #if 0
1956  case '1':
1957  case '2':
1958  case '3':
1959  case '4':
1960  case '5':
1961  case '6':
1962  case '7': /* set the pid for saved local message */
1963  h.pid = 0x40 + (*d & 0xF);
1964  break;
1965  }
1966 #endif
1967  if (sms_args.argc > 2) {
1968  unsigned char *up;
1969 
1970  /* submitting a message, not taking call. */
1971  /* deprecated, use smsq instead */
1972  h.scts = ast_tvnow();
1973  if (ast_strlen_zero(sms_args.addr) || strlen(sms_args.addr) >= sizeof(h.oa)) {
1974  ast_log(LOG_ERROR, "Address too long %s\n", sms_args.addr);
1975  goto done;
1976  }
1977  if (h.smsc) {
1978  ast_copy_string(h.oa, sms_args.addr, sizeof(h.oa));
1979  } else {
1980  ast_copy_string(h.da, sms_args.addr, sizeof(h.da));
1981  ast_copy_string(h.oa, h.cli, sizeof(h.oa));
1982  }
1983  h.udl = 0;
1984  if (ast_strlen_zero(sms_args.body)) {
1985  ast_log(LOG_ERROR, "Missing body for %s\n", sms_args.addr);
1986  goto done;
1987  }
1988  up = (unsigned char *)sms_args.body;
1989  while (*up && h.udl < SMSLEN) {
1990  h.ud[h.udl++] = utf8decode(&up);
1991  }
1992  if (is7bit(h.dcs) && packsms7(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
1993  ast_log(LOG_WARNING, "Invalid 7 bit GSM data\n");
1994  goto done;
1995  }
1996  if (is8bit(h.dcs) && packsms8(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
1997  ast_log(LOG_WARNING, "Invalid 8 bit data\n");
1998  goto done;
1999  }
2000  if (is16bit(h.dcs) && packsms16(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
2001  ast_log(LOG_WARNING, "Invalid 16 bit data\n");
2002  goto done;
2003  }
2004  h.rx = 0; /* sent message */
2005  h.mr = -1;
2006  sms_writefile(&h);
2007  res = h.err;
2008  goto done;
2009  }
2010 
2011  if (ast_channel_state(chan) != AST_STATE_UP) { /* make sure channel is answered before any TX */
2012  ast_answer(chan);
2013  }
2014 
2016  h.framenumber = 1; /* Proto 2 */
2017  /* set up SMS_EST initial message */
2018  if (h.protocol == 2) {
2019  h.omsg[0] = DLL2_SMS_EST;
2020  h.omsg[1] = 0;
2021  } else {
2023  h.omsg[1] = 0;
2024  }
2025  sms_messagetx(&h);
2026  }
2027 
2028  res = ast_set_write_format(chan, __OUT_FMT);
2029  if (res >= 0) {
2030  res = ast_set_read_format(chan, ast_format_slin);
2031  }
2032  if (res < 0) {
2033  ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n");
2034  goto done;
2035  }
2036 
2037  if ( (res = ast_activate_generator(chan, &smsgen, &h)) < 0) {
2038  ast_log(LOG_ERROR, "Failed to activate generator on '%s'\n", ast_channel_name(chan));
2039  goto done;
2040  }
2041 
2042  /* Do our thing here */
2043  for (;;) {
2044  struct ast_frame *f;
2045  int i = ast_waitfor(chan, -1);
2046  if (i < 0) {
2047  ast_log(LOG_NOTICE, "waitfor failed\n");
2048  break;
2049  }
2050  if (h.hangup) {
2051  ast_log(LOG_NOTICE, "channel hangup\n");
2052  break;
2053  }
2054  f = ast_read(chan);
2055  if (!f) {
2056  ast_log(LOG_NOTICE, "ast_read failed\n");
2057  break;
2058  }
2059  if (f->frametype == AST_FRAME_VOICE) {
2060  sms_process(&h, f->samples, f->data.ptr);
2061  }
2062 
2063  ast_frfree(f);
2064  }
2065  res = h.err; /* XXX */
2066 
2067  /*
2068  * The SMS generator data is on the stack. We _MUST_ make sure the generator
2069  * is stopped before returning from this function.
2070  */
2072 
2073  sms_log(&h, '?'); /* log incomplete message */
2074 done:
2075  return (res);
2076 }
2077 
2078 static int unload_module(void)
2079 {
2081 }
2082 
2083 static int load_module(void)
2084 {
2085 #ifdef OUTALAW
2086  int p;
2087  for (p = 0; p < 80; p++) {
2088  wavea[p] = AST_LIN2A(wave[p]);
2089  }
2090 #endif
2091  snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR);
2093 }
2094 
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
#define is7bit(dcs)
Definition: app_sms.c:281
A-Law to Signed linear conversion.
static void sms_messagerx(sms_t *h)
Definition: app_sms.c:1503
static void sms_messagetx(sms_t *h)
Definition: app_sms.c:1561
Main Channel structure associated with a channel.
static char * app
Definition: app_sms.c:124
static int load_module(void)
Definition: app_sms.c:2083
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
unsigned char hangup
Definition: app_sms.c:219
unsigned char ipc1
Definition: app_sms.c:260
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
int opause_0
Definition: app_sms.c:273
void *(* alloc)(struct ast_channel *chan, void *params)
Definition: channel.h:227
unsigned int vp
Definition: app_sms.c:237
#define ast_test_flag(p, flag)
Definition: utils.h:63
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:2960
static long utf8decode(unsigned char **pp)
Reads next UCS character from NUL terminated UTF-8 string and advance pointer.
Definition: app_sms.c:315
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
unsigned char obyten
Definition: app_sms.c:248
#define SMSLEN
Definition: app_sms.c:215
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
unsigned char ophase
Definition: app_sms.c:241
int udhl
Definition: app_sms.c:233
unsigned char ipc0
Definition: app_sms.c:259
#define LOG_WARNING
Definition: logger.h:274
unsigned char rx
Definition: app_sms.c:223
unsigned char obitp
Definition: app_sms.c:245
static struct test_val d
static void dummy(char *unused,...)
Definition: chan_unistim.c:220
static void packdate(unsigned char *o, time_t w)
pack a date and return
Definition: app_sms.c:553
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
unsigned int flags
Definition: utils.h:200
static unsigned char packaddress(unsigned char *o, char *i)
store an address at o, and return number of bytes used
Definition: app_sms.c:746
static int sms_handleincoming_proto2(sms_t *h)
sms_handleincoming_proto2: handle the incoming message
Definition: app_sms.c:1262
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
static void sms_compose1(sms_t *h, int more)
compose a message for protocol 1
Definition: app_sms.c:1400
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
unsigned char ibitl
Definition: app_sms.c:261
ast_channel_state
ast_channel states
Definition: channelstate.h:35
static void sms_debug(int dir, sms_t *h)
Definition: app_sms.c:1485
unsigned char ibytep
Definition: app_sms.c:266
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "SMS/PSTN handler")
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
static int sms_exec(struct ast_channel *chan, const char *data)
Definition: app_sms.c:1881
static struct test_val c
unsigned char osync
Definition: app_sms.c:246
static unsigned char unpackaddress(char *o, unsigned char *i)
unpack an address from i, return byte length, unpack to o
Definition: app_sms.c:728
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
#define S(e)
#define NULL
Definition: resample.c:96
unsigned char imsg[250]
Definition: app_sms.c:250
Definition: app_sms.c:218
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define AST_FILE_MODE
Definition: asterisk.h:32
int tm_year
Definition: localtime.h:41
unsigned char udhi
Definition: app_sms.c:235
#define ast_verb(level,...)
Definition: logger.h:463
unsigned int idle
Definition: app_sms.c:255
signed long long imc0
Definition: app_sms.c:251
struct timeval scts
Definition: app_sms.c:228
struct ast_frame_subclass subclass
unsigned char omsg[256]
Definition: app_sms.c:249
static void sms_readfile(sms_t *h, char *fn)
parse and delete a file
Definition: app_sms.c:827
Utility functions.
static void sms_process(sms_t *h, int samples, signed short *data)
Definition: app_sms.c:1712
#define ast_strlen_zero(foo)
Definition: strings.h:52
message_types
Definition: app_sms.c:161
#define OSYNC_BITS
Definition: app_sms.c:152
static int sms_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_sms.c:1604
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
int done
Definition: test_amihooks.c:48
Number structure.
Definition: app_followme.c:154
static void unpacksms8(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
unpacks bytes (8 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl...
Definition: app_sms.c:658
unsigned char ibytev
Definition: app_sms.c:265
unsigned char ibitt
Definition: app_sms.c:270
#define DIR_RX
Definition: app_sms.c:1483
#define ast_log
Definition: astobj2.c:42
static struct dirent * readdirqueue(DIR *d, char *queue)
read dir skipping dot files...
Definition: app_sms.c:1102
static volatile unsigned char message_ref
Definition: app_sms.c:119
static void sms_compose2(sms_t *h, int more)
Definition: app_sms.c:1213
General Asterisk PBX channel definitions.
char queue[30]
Definition: app_sms.c:225
Asterisk file paths, configured in asterisk.conf.
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
const char * src
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5849
#define SMSLEN_8
Definition: app_sms.c:216
while(1)
Definition: ast_expr2f.c:894
static int packsms16(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o ...
Definition: app_sms.c:485
static char * isodate(time_t t, char *buf, int len)
static, return a date/time in ISO format
Definition: app_sms.c:303
int tm_mon
Definition: localtime.h:40
unsigned char ips0
Definition: app_sms.c:257
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
static const struct ast_app_option sms_options[128]
Definition: app_sms.c:1879
static void unpacksms16(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
unpacks bytes (16 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl...
Definition: app_sms.c:684
unsigned char srr
Definition: app_sms.c:234
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
struct sms_s sms_t
unsigned char obyte
Definition: app_sms.c:243
static void sms_release(struct ast_channel *chan, void *data)
Definition: app_sms.c:1689
static const signed short wave[]
Definition: app_sms.c:132
static void * sms_alloc(struct ast_channel *chan, void *sms_t_ptr)
Definition: app_sms.c:1684
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5890
static const output_t * wave_out
Definition: app_sms.c:148
signed long long imc1
Definition: app_sms.c:251
int tm_mday
Definition: localtime.h:39
static void sms_writefile(sms_t *h)
white a received text message to a file
Definition: app_sms.c:998
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:2906
unsigned char smsc
Definition: app_sms.c:222
unsigned short imag
Definition: app_sms.c:256
Core PBX routines and definitions.
static char log_file[255]
Definition: app_sms.c:122
signed short output_t
Definition: app_sms.c:147
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
static const unsigned short defaultalphabet[]
Definition: app_sms.c:191
unsigned char nolog
Definition: app_sms.c:224
#define LOG_ERROR
Definition: logger.h:285
int framenumber
Definition: app_sms.c:276
unsigned char ierr
Definition: app_sms.c:268
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
unsigned char rp
Definition: app_sms.c:236
unsigned char ophasep
Definition: app_sms.c:242
#define is16bit(dcs)
Definition: app_sms.c:283
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int errno
#define DIR_TX
Definition: app_sms.c:1484
unsigned char ibitc
Definition: app_sms.c:262
#define DLL2_ACK(h)
char cli[20]
Definition: app_sms.c:240
static struct ast_generator smsgen
Definition: app_sms.c:1694
unsigned char obytep
Definition: app_sms.c:247
unsigned short ud[SMSLEN]
Definition: app_sms.c:238
#define __OUT_FMT
Definition: app_sms.c:149
short mr
Definition: app_sms.c:231
#define LOG_NOTICE
Definition: logger.h:263
int oseizure
Definition: app_sms.c:275
const char * ast_config_AST_LOG_DIR
Definition: options.c:159
static char * sms_hexdump(unsigned char buf[], int size, char *s)
Definition: app_sms.c:1249
static int unpacksms(unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
general unpack - starts with length byte (octet or septet) and returns number of bytes used...
Definition: app_sms.c:712
long int tm_gmtoff
Definition: localtime.h:45
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
static int packsms(unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
general pack, with length and data, returns number of bytes of target used
Definition: app_sms.c:520
static void sms_log(sms_t *h, char status)
Log the output, and remove file.
Definition: app_sms.c:774
sms_opt_args
Definition: app_sms.c:1866
sms_flags
Definition: app_sms.c:1856
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:5189
char udtxt[SMSLEN]
Definition: app_sms.c:277
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:154
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
int tm_hour
Definition: localtime.h:38
static void adddata_proto2(sms_t *h, unsigned char msg, char *data, int size)
Definition: app_sms.c:1188
Structure used to handle boolean flags.
Definition: utils.h:199
static void sms_messagerx2(sms_t *h)
Definition: app_sms.c:1343
#define MAX_DEBUG_LEN
Definition: app_sms.c:1248
int tm_sec
Definition: localtime.h:36
int udl
Definition: app_sms.c:232
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2902
unsigned char err
Definition: app_sms.c:220
static volatile unsigned int seq
Definition: app_sms.c:120
unsigned char ibytec
Definition: app_sms.c:267
static struct timeval unpackdate(unsigned char *i)
unpack a date and return
Definition: app_sms.c:579
static int packsms7(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o ...
Definition: app_sms.c:369
static int unload_module(void)
Definition: app_sms.c:2078
char da[20]
Definition: app_sms.c:227
unsigned char dcs
Definition: app_sms.c:230
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3171
#define abs(x)
Definition: f2c.h:195
struct timeval ast_mktime(struct ast_tm *const tmp, const char *zone)
Timezone-independent version of mktime(3).
Definition: localtime.c:2357
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
unsigned char ibith
Definition: app_sms.c:269
int tm_isdst
Definition: localtime.h:44
#define ast_frfree(fr)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2814
unsigned int opause
Definition: app_sms.c:244
static int packsms8(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o ...
Definition: app_sms.c:446
Data structure associated with a single frame of data.
unsigned char ips1
Definition: app_sms.c:258
static struct test_val b
char oa[20]
Definition: app_sms.c:226
union ast_frame::@263 data
enum ast_frame_type frametype
static struct test_options options
static void unpacksms7(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
unpacks bytes (7 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl...
Definition: app_sms.c:602
static void putdummydata_proto2(sms_t *h)
Definition: app_sms.c:1205
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
unsigned char sent_rel
Definition: app_sms.c:221
struct ast_format * format
unsigned char iphasep
Definition: app_sms.c:263
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
Asterisk module definitions.
#define MAXSAMPLES
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
signed long long ims0
Definition: app_sms.c:251
static void numcpy(char *d, char *s)
copy number, skipping non digits apart from leading +
Definition: app_sms.c:288
#define is8bit(dcs)
Definition: app_sms.c:282
unsigned char pid
Definition: app_sms.c:229
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
int protocol
Definition: app_sms.c:274
int tm_min
Definition: localtime.h:37
unsigned char ibitn
Definition: app_sms.c:264
jack_status_t status
Definition: app_jack.c:146
static void sms_nextoutgoing(sms_t *h)
find and fill in next message, or send a REL if none waiting
Definition: app_sms.c:1442
Media Format Cache API.
#define AST_LIN2A(a)
Definition: alaw.h:50
static const unsigned short escapes[]
Definition: app_sms.c:204
#define AST_APP_ARG(name)
Define an application argument.
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: main/utils.c:2231
static unsigned char sms_handleincoming(sms_t *h)
handle the incoming message
Definition: app_sms.c:1112
unsigned char udh[SMSLEN]
Definition: app_sms.c:239
signed long long ims1
Definition: app_sms.c:251