Tue Aug 20 16:34:22 2013

Asterisk developer's documentation


app_sms.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2004 - 2005, Adrian Kennard, rights assigned to Digium
00005  *
00006  * See http://www.asterisk.org for more information about
00007  * the Asterisk project. Please do not directly contact
00008  * any of the maintainers of this project for assistance;
00009  * the project provides a web site, mailing lists and IRC
00010  * channels for your use.
00011  *
00012  * This program is free software, distributed under the terms of
00013  * the GNU General Public License Version 2. See the LICENSE file
00014  * at the top of the source tree.
00015  */
00016 
00017 /*! \file
00018  *
00019  * \brief SMS application - ETSI ES 201 912 protocol 1 implementation
00020  * 
00021  * \par Development notes
00022  * \note The ETSI standards are available free of charge from ETSI at
00023  * http://pda.etsi.org/pda/queryform.asp
00024  *    Among the relevant documents here we have:
00025  *
00026  * ES 201 912  SMS for PSTN/ISDN
00027  * TS 123 040  Technical realization of SMS
00028  *
00029  * 
00030  * \ingroup applications
00031  *
00032  * \author Adrian Kennard (for the original protocol 1 code)
00033  * \author Filippo Grassilli (Hyppo) - protocol 2 support
00034  *       Not fully tested, under development
00035  */
00036 
00037 /*** MODULEINFO
00038    <support_level>extended</support_level>
00039  ***/
00040 
00041 #include "asterisk.h"
00042 
00043 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370642 $")
00044 
00045 #include <dirent.h>
00046 #include <ctype.h>
00047 #include <sys/stat.h>
00048 
00049 #include "asterisk/paths.h"  /* use ast_config_AST_SPOOL_DIR and LOG_DIR */
00050 #include "asterisk/lock.h"
00051 #include "asterisk/file.h"
00052 #include "asterisk/channel.h"
00053 #include "asterisk/pbx.h"
00054 #include "asterisk/module.h"
00055 #include "asterisk/alaw.h"
00056 #include "asterisk/callerid.h"
00057 #include "asterisk/utils.h"
00058 #include "asterisk/app.h"
00059 
00060 /*** DOCUMENTATION
00061    <application name="SMS" language="en_US">
00062       <synopsis>
00063          Communicates with SMS service centres and SMS capable analogue phones.
00064       </synopsis>
00065       <syntax>
00066          <parameter name="name" required="true">
00067             <para>The name of the queue used in <filename>/var/spool/asterisk/sms</filename></para>
00068          </parameter>
00069          <parameter name="options">
00070             <optionlist>
00071                <option name="a">
00072                   <para>Answer, i.e. send initial FSK packet.</para>
00073                </option>
00074                <option name="s">
00075                   <para>Act as service centre talking to a phone.</para>
00076                </option>
00077                <option name="t">
00078                   <para>Use protocol 2 (default used is protocol 1).</para>
00079                </option>
00080                <option name="p">
00081                   <para>Set the initial delay to N ms (default is <literal>300</literal>).
00082                   addr and body are a deprecated format to send messages out.</para>
00083                </option>
00084                <option name="r">
00085                   <para>Set the Status Report Request (SRR) bit.</para>
00086                </option>
00087                <option name="o">
00088                   <para>The body should be coded as octets not 7-bit symbols.</para>
00089                </option>
00090             </optionlist>
00091          </parameter>
00092          <parameter name="addr" />
00093          <parameter name="body" />
00094       </syntax>
00095       <description>
00096          <para>SMS handles exchange of SMS data with a call to/from SMS capable phone or SMS PSTN service center.
00097          Can send and/or receive SMS messages. Works to ETSI ES 201 912; compatible with BT SMS PSTN service in
00098          UK and Telecom Italia in Italy.</para>
00099          <para>Typical usage is to use to handle calls from the SMS service centre CLI, or to set up a call using
00100          <literal>outgoing</literal> or manager interface to connect service centre to SMS().</para>
00101          <para>"Messages are processed as per text file message queues. smsq (a separate software) is a command to
00102          generate message queues and send messages.</para>
00103          <note><para>The protocol has tight delay bounds. Please use short frames and disable/keep short the
00104          jitter buffer on the ATA to make sure that respones (ACK etc.) are received in time.</para></note>
00105       </description>
00106    </application>
00107  ***/
00108 
00109 /* #define OUTALAW */        /* enable this to output Alaw rather than linear */
00110 
00111 /* ToDo */
00112 /* Add full VP support */
00113 /* Handle status report messages (generation and reception) */
00114 /* Time zones on time stamps */
00115 /* user ref field */
00116 
00117 static volatile unsigned char message_ref;  /* arbitary message ref */
00118 static volatile unsigned int seq;           /* arbitrary message sequence number for unqiue files */
00119 
00120 static char log_file[255];
00121 
00122 static char *app = "SMS";
00123 
00124 /*
00125  * 80 samples of a single period of the wave. At 8000 Hz, it means these
00126  * are the samples of a 100 Hz signal.
00127  * To pick the two carriers (1300Hz for '1' and 2100 Hz for '0') used by
00128  * the modulation, we should take one every 13 and 21 samples respectively.
00129  */
00130 static const signed short wave[] = {
00131    0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
00132    5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
00133    0, -392, -782, -1167,
00134     -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
00135    -4985, -4938, -4862,
00136    -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
00137 };
00138 
00139 #ifdef OUTALAW
00140 static unsigned char wavea[80];
00141 typedef unsigned char output_t;
00142 static const output_t *wave_out = wavea;    /* outgoing samples */
00143 #define __OUT_FMT AST_FORMAT_ALAW;
00144 #else
00145 typedef signed short output_t;
00146 static const output_t *wave_out = wave;     /* outgoing samples */
00147 #define __OUT_FMT AST_FORMAT_SLINEAR
00148 #endif
00149 
00150 #define OSYNC_BITS   80                      /* initial sync bits */
00151 
00152 /*!
00153  * The SMS spec ETSI ES 201 912 defines two protocols with different message types.
00154  * Also note that the high bit is used to indicate whether the message
00155  * is complete or not, but in two opposite ways:
00156  * for Protocol 1, 0x80 means that the message is complete;
00157  * for Protocol 2, 0x00 means that the message is complete;
00158  */
00159 enum message_types {
00160    DLL_SMS_MASK        = 0x7f,             /* mask for the valid bits */
00161 
00162    /* Protocol 1 values */
00163    DLL1_SMS_DATA       = 0x11,             /* data packet */
00164    DLL1_SMS_ERROR      = 0x12,
00165    DLL1_SMS_EST        = 0x13,             /* start the connection */
00166    DLL1_SMS_REL        = 0x14,             /* end the connection */
00167    DLL1_SMS_ACK        = 0x15,
00168    DLL1_SMS_NACK       = 0x16,
00169 
00170    DLL1_SMS_COMPLETE   = 0x80,             /* packet is complete */
00171    DLL1_SMS_MORE       = 0x00,             /* more data to follow */
00172 
00173    /* Protocol 2 values */
00174    DLL2_SMS_EST        = 0x7f,             /* magic number. No message body */
00175    DLL2_SMS_INFO_MO    = 0x10,
00176    DLL2_SMS_INFO_MT    = 0x11,
00177    DLL2_SMS_INFO_STA   = 0x12,
00178    DLL2_SMS_NACK       = 0x13,
00179    DLL2_SMS_ACK0       = 0x14,             /* ack even-numbered frame */
00180    DLL2_SMS_ACK1       = 0x15,             /* ack odd-numbered frame */
00181    DLL2_SMS_ENQ        = 0x16,
00182    DLL2_SMS_REL        = 0x17,             /* end the connection */
00183 
00184    DLL2_SMS_COMPLETE   = 0x00,             /* packet is complete */
00185    DLL2_SMS_MORE       = 0x80,             /* more data to follow */
00186 };
00187 
00188 /* SMS 7 bit character mapping to UCS-2 */
00189 static const unsigned short defaultalphabet[] = {
00190    0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
00191    0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
00192    0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
00193    0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
00194    ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
00195    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
00196    161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
00197    'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
00198    191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
00199    'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
00200 };
00201 
00202 static const unsigned short escapes[] = {
00203    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
00204    0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00205    0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
00206    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
00207    0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00208    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00209    0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00210    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00211 };
00212 
00213 #define SMSLEN      160          /*!< max SMS length */
00214 #define SMSLEN_8    140          /*!< max SMS length for 8-bit char */
00215 
00216 typedef struct sms_s {
00217    unsigned char hangup;        /*!< we are done... */
00218    unsigned char err;           /*!< set for any errors */
00219    unsigned char smsc:1;        /*!< we are SMSC */
00220    unsigned char rx:1;          /*!< this is a received message */
00221    char queue[30];              /*!< queue name */
00222    char oa[20];                 /*!< originating address */
00223    char da[20];                 /*!< destination address */
00224    struct timeval scts;         /*!< time stamp, UTC */
00225    unsigned char pid;           /*!< protocol ID */
00226    unsigned char dcs;           /*!< data coding scheme */
00227    short mr;                    /*!< message reference - actually a byte, but use -1 for not set */
00228    int udl;                     /*!< user data length */
00229    int udhl;                    /*!< user data header length */
00230    unsigned char srr:1;         /*!< Status Report request */
00231    unsigned char udhi:1;        /*!< User Data Header required, even if length 0 */
00232    unsigned char rp:1;          /*!< Reply Path */
00233    unsigned int vp;             /*!< validity period in minutes, 0 for not set */
00234    unsigned short ud[SMSLEN];   /*!< user data (message), UCS-2 coded */
00235    unsigned char udh[SMSLEN];   /*!< user data header */
00236    char cli[20];                /*!< caller ID */
00237    unsigned char ophase;        /*!< phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
00238    unsigned char ophasep;       /*!< phase (0-79) for 1200 bps */
00239    unsigned char obyte;         /*!< byte being sent */
00240    unsigned int opause;         /*!< silent pause before sending (in sample periods) */
00241    unsigned char obitp;         /*!< bit in byte */
00242    unsigned char osync;         /*!< sync bits to send */
00243    unsigned char obytep;        /*!< byte in data */
00244    unsigned char obyten;        /*!< bytes in data */
00245    unsigned char omsg[256];     /*!< data buffer (out) */
00246    unsigned char imsg[250];     /*!< data buffer (in) */
00247    signed long long ims0,
00248       imc0,
00249       ims1,
00250       imc1;                    /*!< magnitude averages sin/cos 0/1 */
00251    unsigned int idle;
00252    unsigned short imag;         /*!< signal level */
00253    unsigned char ips0;          /*!< phase sin for bit 0, start at  0 inc by 21 mod 80 */
00254    unsigned char ips1;          /*!< phase cos for bit 0, start at 20 inc by 21 mod 80 */
00255    unsigned char ipc0;          /*!< phase sin for bit 1, start at  0 inc by 13 mod 80 */
00256    unsigned char ipc1;          /*!< phase cos for bit 1, start at 20 inc by 13 mod 80 */
00257    unsigned char ibitl;         /*!< last bit */
00258    unsigned char ibitc;         /*!< bit run length count */
00259    unsigned char iphasep;       /*!< bit phase (0-79) for 1200 bps */
00260    unsigned char ibitn;         /*!< bit number in byte being received */
00261    unsigned char ibytev;        /*!< byte value being received */
00262    unsigned char ibytep;        /*!< byte pointer in message */
00263    unsigned char ibytec;        /*!< byte checksum for message */
00264    unsigned char ierr;          /*!< error flag */
00265    unsigned char ibith;         /*!< history of last bits */
00266    unsigned char ibitt;         /*!< total of 1's in last 3 bytes */
00267    /* more to go here */
00268 
00269    int opause_0;                /*!< initial delay in ms, p() option */
00270    int protocol;                /*!< ETSI SMS protocol to use (passed at app call) */
00271    int oseizure;                /*!< protocol 2: channel seizure bits to send */
00272    int framenumber;             /*!< protocol 2: frame number (for sending ACK0 or ACK1) */
00273    char udtxt[SMSLEN];          /*!< user data (message), PLAIN text */
00274 } sms_t;
00275 
00276 /* different types of encoding */
00277 #define is7bit(dcs)  ( ((dcs) & 0xC0) ? (!((dcs) & 4) ) : (((dcs) & 0xc) == 0) )
00278 #define is8bit(dcs)  ( ((dcs) & 0xC0) ? ( ((dcs) & 4) ) : (((dcs) & 0xc) == 4) )
00279 #define is16bit(dcs) ( ((dcs) & 0xC0) ? 0               : (((dcs) & 0xc) == 8) )
00280 
00281 static void sms_messagetx(sms_t *h);
00282 
00283 /*! \brief copy number, skipping non digits apart from leading + */
00284 static void numcpy(char *d, char *s)
00285 {
00286    if (*s == '+') {
00287       *d++ = *s++;
00288    }
00289    while (*s) {
00290       if (isdigit(*s)) {
00291          *d++ = *s;
00292       }
00293       s++;
00294    }
00295    *d = 0;
00296 }
00297 
00298 /*! \brief static, return a date/time in ISO format */
00299 static char *isodate(time_t t, char *buf, int len)
00300 {
00301    struct ast_tm tm;
00302    struct timeval local = { t, 0 };
00303    ast_localtime(&local, &tm, NULL);
00304    ast_strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm);
00305    return buf;
00306 }
00307 
00308 /*! \brief Reads next UCS character from NUL terminated UTF-8 string and advance pointer */
00309 /* for non valid UTF-8 sequences, returns character as is */
00310 /* Does not advance pointer for null termination */
00311 static long utf8decode(unsigned char **pp)
00312 {
00313    unsigned char *p = *pp;
00314    if (!*p) {
00315       return 0;                           /* null termination of string */
00316    }
00317    (*pp)++;
00318    if (*p < 0xC0) {
00319       return *p;                          /* ascii or continuation character */
00320    }
00321    if (*p < 0xE0) {
00322       if (*p < 0xC2 || (p[1] & 0xC0) != 0x80) {
00323          return *p;                      /* not valid UTF-8 */
00324       }
00325       (*pp)++;
00326       return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
00327       }
00328    if (*p < 0xF0) {
00329       if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80) {
00330          return *p;                      /* not valid UTF-8 */
00331       }
00332       (*pp) += 2;
00333       return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
00334    }
00335    if (*p < 0xF8) {
00336       if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80) {
00337          return *p;                      /* not valid UTF-8 */
00338       }
00339       (*pp) += 3;
00340       return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
00341    }
00342    if (*p < 0xFC) {
00343       if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
00344          || (p[4] & 0xC0) != 0x80) {
00345          return *p;                      /* not valid UTF-8 */
00346       }
00347       (*pp) += 4;
00348       return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
00349    }
00350    if (*p < 0xFE) {
00351       if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
00352          || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80) {
00353          return *p;                      /* not valid UTF-8 */
00354       }
00355       (*pp) += 5;
00356       return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F);
00357    }
00358    return *p;                              /* not sensible */
00359 }
00360 
00361 /*! \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 */
00362 /* The return value is the number of septets packed in to o, which is internally limited to SMSLEN */
00363 /* o can be null, in which case this is used to validate or count only */
00364 /* if the input contains invalid characters then the return value is -1 */
00365 static int packsms7(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
00366 {
00367    unsigned char p = 0;                    /* output pointer (bytes) */
00368    unsigned char b = 0;                    /* bit position */
00369    unsigned char n = 0;                    /* output character count */
00370    unsigned char dummy[SMSLEN];
00371 
00372    if (o == NULL) {                        /* output to a dummy buffer if o not set */
00373       o = dummy;
00374    }
00375 
00376    if (udhl) {                             /* header */
00377       o[p++] = udhl;
00378       b = 1;
00379       n = 1;
00380       while (udhl--) {
00381          o[p++] = *udh++;
00382          b += 8;
00383          while (b >= 7) {
00384             b -= 7;
00385             n++;
00386          }
00387          if (n >= SMSLEN)
00388             return n;
00389       }
00390       if (b) {
00391          b = 7 - b;
00392          if (++n >= SMSLEN)
00393             return n;
00394       }                                   /* filling to septet boundary */
00395    }
00396    o[p] = 0;
00397    /* message */
00398    while (udl--) {
00399       long u;
00400       unsigned char v;
00401       u = *ud++;
00402       /* XXX 0 is invalid ? */
00403       /* look up in defaultalphabet[]. If found, v is the 7-bit code */
00404       for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
00405       if (v == 128 /* not found */ && u && n + 1 < SMSLEN) {
00406          /* if not found, look in the escapes table (we need 2 bytes) */
00407          for (v = 0; v < 128 && escapes[v] != u; v++);
00408          if (v < 128) { /* escaped sequence, esc + v */
00409             /* store the low (8-b) bits in o[p], the remaining bits in o[p+1] */
00410             o[p] |= (27 << b);          /* the low bits go into o[p] */ 
00411             b += 7;
00412             if (b >= 8) {
00413                b -= 8;
00414                p++;
00415                o[p] = (27 >> (7 - b));
00416             }
00417             n++;
00418          }
00419       }
00420       if (v == 128)
00421          return -1;                      /* invalid character */
00422       /* store, same as above */
00423       o[p] |= (v << b);
00424       b += 7;
00425       if (b >= 8) {
00426          b -= 8;
00427          p++;
00428          o[p] = (v >> (7 - b));
00429       }
00430       if (++n >= SMSLEN)
00431          return n;
00432    }
00433    return n;
00434 }
00435 
00436 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud)
00437  * and packs in to o using 8 bit character codes.
00438  * The return value is the number of bytes packed in to o, which is internally limited to 140.
00439  * o can be null, in which case this is used to validate or count only.
00440  * if the input contains invalid characters then the return value is -1
00441  */
00442 static int packsms8(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
00443 {
00444    unsigned char p = 0;
00445    unsigned char dummy[SMSLEN_8];
00446 
00447    if (o == NULL)
00448       o = dummy;
00449    /* header - no encoding */
00450    if (udhl) {
00451       o[p++] = udhl;
00452       while (udhl--) {
00453          o[p++] = *udh++;
00454          if (p >= SMSLEN_8) {
00455             return p;
00456          }
00457       }
00458    }
00459    while (udl--) {
00460       long u;
00461       u = *ud++;
00462       if (u < 0 || u > 0xFF) {
00463          return -1;                      /* not valid */
00464       }
00465       o[p++] = u;
00466       if (p >= SMSLEN_8) {
00467          return p;
00468       }
00469    }
00470    return p;
00471 }
00472 
00473 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 
00474    message (udl characters at ud) and packs in to o using 16 bit 
00475    UCS-2 character codes 
00476    The return value is the number of bytes packed in to o, which is 
00477    internally limited to 140 
00478    o can be null, in which case this is used to validate or count 
00479    only if the input contains invalid characters then 
00480    the return value is -1 */
00481 static int packsms16(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
00482 {
00483    unsigned char p = 0;
00484    unsigned char dummy[SMSLEN_8];
00485 
00486    if (o == NULL) {
00487       o = dummy;
00488    }
00489    /* header - no encoding */
00490    if (udhl) {
00491       o[p++] = udhl;
00492       while (udhl--) {
00493          o[p++] = *udh++;
00494          if (p >= SMSLEN_8) {
00495             return p;
00496          }
00497       }
00498    }
00499    while (udl--) {
00500       long u;
00501       u = *ud++;
00502       o[p++] = (u >> 8);
00503       if (p >= SMSLEN_8) {
00504          return p - 1;                   /* could not fit last character */
00505       }
00506       o[p++] = u;
00507       if (p >= SMSLEN_8) {
00508          return p;
00509       }
00510    }
00511    return p;
00512 }
00513 
00514 /*! \brief general pack, with length and data, 
00515    returns number of bytes of target used */
00516 static int packsms(unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
00517 {
00518    unsigned char *p = base;
00519    if (udl == 0) {
00520       *p++ = 0;                           /* no user data */
00521    } else {
00522       
00523       int l = 0;
00524       if (is7bit(dcs)) {                  /* 7 bit */
00525          if ((l = packsms7(p + 1, udhl, udh, udl, ud)) < 0) {
00526             l = 0;
00527          }
00528          *p++ = l;
00529          p += (l * 7 + 7) / 8;
00530       } else if (is8bit(dcs)) {           /* 8 bit */
00531          if ((l = packsms8(p + 1, udhl, udh, udl, ud)) < 0) {
00532             l = 0;
00533          }
00534          *p++ = l;
00535          p += l;
00536       } else {                            /* UCS-2 */
00537          if ((l = packsms16(p + 1, udhl, udh, udl, ud)) < 0) {
00538             l = 0;
00539          }
00540          *p++ = l;
00541          p += l;
00542       }
00543    }
00544    return p - base;
00545 }
00546 
00547 
00548 /*! \brief pack a date and return */
00549 static void packdate(unsigned char *o, time_t w)
00550 {
00551    struct ast_tm t;
00552    struct timeval topack = { w, 0 };
00553    int z;
00554 
00555    ast_localtime(&topack, &t, NULL);
00556 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) || defined(__CYGWIN__)
00557    z = -t.tm_gmtoff / 60 / 15;
00558 #else
00559    z = timezone / 60 / 15;
00560 #endif
00561    *o++ = ((t.tm_year % 10) << 4) + (t.tm_year % 100) / 10;
00562    *o++ = (((t.tm_mon + 1) % 10) << 4) + (t.tm_mon + 1) / 10;
00563    *o++ = ((t.tm_mday % 10) << 4) + t.tm_mday / 10;
00564    *o++ = ((t.tm_hour % 10) << 4) + t.tm_hour / 10;
00565    *o++ = ((t.tm_min % 10) << 4) + t.tm_min / 10;
00566    *o++ = ((t.tm_sec % 10) << 4) + t.tm_sec / 10;
00567    if (z < 0) {
00568       *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
00569    } else {
00570       *o++ = ((z % 10) << 4) + z / 10;
00571    }
00572 }
00573 
00574 /*! \brief unpack a date and return */
00575 static struct timeval unpackdate(unsigned char *i)
00576 {
00577    struct ast_tm t;
00578 
00579    t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
00580    t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
00581    t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
00582    t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
00583    t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
00584    t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
00585    t.tm_isdst = 0;
00586    if (i[6] & 0x08) {
00587       t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
00588    } else {
00589       t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
00590    }
00591 
00592    return ast_mktime(&t, NULL);
00593 }
00594 
00595 /*! \brief unpacks bytes (7 bit encoding) at i, len l septets, 
00596    and places in udh and ud setting udhl and udl. udh not used 
00597    if udhi not set */
00598 static void unpacksms7(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
00599 {
00600    unsigned char b = 0, p = 0;
00601    unsigned short *o = ud;
00602    *udhl = 0;
00603    if (udhi && l) {                        /* header */
00604       int h = i[p];
00605       *udhl = h;
00606       if (h) {
00607          b = 1;
00608          p++;
00609          l--;
00610          while (h-- && l) {
00611             *udh++ = i[p++];
00612             b += 8;
00613             while (b >= 7) {
00614                b -= 7;
00615                l--;
00616                if (!l) {
00617                   break;
00618                }
00619             }
00620          }
00621          /* adjust for fill, septets */
00622          if (b) {
00623             b = 7 - b;
00624             l--;
00625          }
00626       }
00627    }
00628    while (l--) {
00629       unsigned char v;
00630       if (b < 2) {
00631          v = ((i[p] >> b) & 0x7F);       /* everything in one byte */
00632       } else {
00633          v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
00634       }
00635       b += 7;
00636       if (b >= 8) {
00637          b -= 8;
00638          p++;
00639       }
00640       /* 0x00A0 is the encoding of ESC (27) in defaultalphabet */
00641       if (o > ud && o[-1] == 0x00A0 && escapes[v]) {
00642          o[-1] = escapes[v];
00643       } else {
00644          *o++ = defaultalphabet[v];
00645       }
00646    }
00647    *udl = (o - ud);
00648 }
00649 
00650 /*! \brief unpacks bytes (8 bit encoding) at i, len l septets, 
00651  *  and places in udh and ud setting udhl and udl. udh not used 
00652  *  if udhi not set.
00653  */
00654 static void unpacksms8(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
00655 {
00656    unsigned short *o = ud;
00657    *udhl = 0;
00658    if (udhi) {
00659       int n = *i;
00660       *udhl = n;
00661       if (n) {
00662          i++;
00663          l--;
00664          while (l && n) {
00665             l--;
00666             n--;
00667             *udh++ = *i++;
00668          }
00669       }
00670    }
00671    while (l--) {
00672       *o++ = *i++;                        /* not to UTF-8 as explicitly 8 bit coding in DCS */
00673    }
00674    *udl = (o - ud);
00675 }
00676 
00677 /*! \brief unpacks bytes (16 bit encoding) at i, len l septets,
00678     and places in udh and ud setting udhl and udl. 
00679    udh not used if udhi not set */
00680 static void unpacksms16(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
00681 {
00682    unsigned short *o = ud;
00683    *udhl = 0;
00684    if (udhi) {
00685       int n = *i;
00686       *udhl = n;
00687       if (n) {
00688          i++;
00689          l--;
00690          while (l && n) {
00691             l--;
00692             n--;
00693             *udh++ = *i++;
00694          }
00695       }
00696    }
00697    while (l--) {
00698       int v = *i++;
00699       if (l--) {
00700          v = (v << 8) + *i++;
00701       }
00702       *o++ = v;
00703    }
00704    *udl = (o - ud);
00705 }
00706 
00707 /*! \brief general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
00708 static int unpacksms(unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
00709 {
00710    int l = *i++;
00711    if (is7bit(dcs)) {
00712       unpacksms7(i, l, udh, udhl, ud, udl, udhi);
00713       l = (l * 7 + 7) / 8;                /* adjust length to return */
00714    } else if (is8bit(dcs)) {
00715       unpacksms8(i, l, udh, udhl, ud, udl, udhi);
00716    } else {
00717       unpacksms16(i, l, udh, udhl, ud, udl, udhi);
00718    }
00719    return l + 1;
00720 }
00721 
00722 /*! \brief unpack an address from i, return byte length, unpack to o */
00723 static unsigned char unpackaddress(char *o, unsigned char *i)
00724 {
00725    unsigned char l = i[0], p;
00726    if (i[1] == 0x91) {
00727       *o++ = '+';
00728    }
00729    for (p = 0; p < l; p++) {
00730       if (p & 1) {
00731          *o++ = (i[2 + p / 2] >> 4) + '0';
00732       } else {
00733          *o++ = (i[2 + p / 2] & 0xF) + '0';
00734       }
00735    }
00736    *o = 0;
00737    return (l + 5) / 2;
00738 }
00739 
00740 /*! \brief store an address at o, and return number of bytes used */
00741 static unsigned char packaddress(unsigned char *o, char *i)
00742 {
00743    unsigned char p = 2;
00744    o[0] = 0;                               /* number of bytes */
00745    if (*i == '+') {                        /* record as bit 0 in byte 1 */
00746       i++;
00747       o[1] = 0x91;
00748    } else {
00749       o[1] = 0x81;
00750    }
00751    for ( ; *i ; i++) {
00752       if (!isdigit(*i)) {                 /* ignore non-digits */
00753          continue;
00754       }
00755       if (o[0] & 1) {
00756          o[p++] |= ((*i & 0xF) << 4);
00757       } else {
00758          o[p] = (*i & 0xF);
00759       }
00760       o[0]++;
00761    }
00762    if (o[0] & 1) {
00763       o[p++] |= 0xF0;                     /* pad */
00764    }
00765    return p;
00766 }
00767 
00768 /*! \brief Log the output, and remove file */
00769 static void sms_log(sms_t * h, char status)
00770 {
00771    int o;
00772 
00773    if (*h->oa == '\0' && *h->da == '\0') {
00774       return;
00775    }
00776    o = open(log_file, O_CREAT | O_APPEND | O_WRONLY, AST_FILE_MODE);
00777    if (o >= 0) {
00778       char line[1000], mrs[3] = "", *p;
00779       char buf[30];
00780       unsigned char n;
00781 
00782       if (h->mr >= 0) {
00783          snprintf(mrs, sizeof(mrs), "%02X", h->mr);
00784       }
00785       snprintf(line, sizeof(line), "%s %c%c%c%s %s %s %s ",
00786          isodate(time(NULL), buf, sizeof(buf)),
00787          status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue,
00788          S_OR(h->oa, "-"), S_OR(h->da, "-") );
00789       p = line + strlen(line);
00790       for (n = 0; n < h->udl; n++) {
00791          if (h->ud[n] == '\\') {
00792             *p++ = '\\';
00793             *p++ = '\\';
00794          } else if (h->ud[n] == '\n') {
00795             *p++ = '\\';
00796             *p++ = 'n';
00797          } else if (h->ud[n] == '\r') {
00798             *p++ = '\\';
00799             *p++ = 'r';
00800          } else if (h->ud[n] < 32 || h->ud[n] == 127) {
00801             *p++ = 191;
00802          } else {
00803             *p++ = h->ud[n];
00804          }
00805       }
00806       *p++ = '\n';
00807       *p = 0;
00808       if (write(o, line, strlen(line)) < 0) {
00809          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00810       }
00811       close(o);
00812    }
00813    *h->oa = *h->da = h->udl = 0;
00814 }
00815 
00816 /*! \brief parse and delete a file */
00817 static void sms_readfile(sms_t * h, char *fn)
00818 {
00819    char line[1000];
00820    FILE *s;
00821    char dcsset = 0;                        /* if DSC set */
00822    ast_log(LOG_NOTICE, "Sending %s\n", fn);
00823    h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
00824    h->mr = -1;
00825    h->dcs = 0xF1;                          /* normal messages class 1 */
00826    h->scts = ast_tvnow();
00827    s = fopen(fn, "r");
00828    if (s) {
00829       if (unlink(fn)) {                   /* concurrent access, we lost */
00830          fclose(s);
00831          return;
00832       }
00833       while (fgets (line, sizeof(line), s)) {   /* process line in file */
00834          char *p;
00835          void *pp = &p;
00836          for (p = line; *p && *p != '\n' && *p != '\r'; p++);
00837          *p = 0;                         /* strip eoln */
00838          p = line;
00839          if (!*p || *p == ';') {
00840             continue;                   /* blank line or comment, ignore */
00841          }
00842          while (isalnum(*p)) {
00843             *p = tolower (*p);
00844             p++;
00845          }
00846          while (isspace (*p)) {
00847             *p++ = 0;
00848          }
00849          if (*p == '=') {
00850             *p++ = 0;
00851             if (!strcmp(line, "ud")) {  /* parse message (UTF-8) */
00852                unsigned char o = 0;
00853                memcpy(h->udtxt, p, SMSLEN); /* for protocol 2 */
00854                while (*p && o < SMSLEN) {
00855                   h->ud[o++] = utf8decode(pp);
00856                }
00857                h->udl = o;
00858                if (*p) {
00859                   ast_log(LOG_WARNING, "UD too long in %s\n", fn);
00860                }
00861             } else {
00862                while (isspace (*p)) {
00863                   p++;
00864                }
00865                if (!strcmp(line, "oa") && strlen(p) < sizeof(h->oa)) {
00866                   numcpy (h->oa, p);
00867                } else if (!strcmp(line, "da") && strlen(p) < sizeof(h->oa)) {
00868                   numcpy (h->da, p);
00869                } else if (!strcmp(line, "pid")) {
00870                   h->pid = atoi(p);
00871                } else if (!strcmp(line, "dcs")) {
00872                   h->dcs = atoi(p);
00873                   dcsset = 1;
00874                } else if (!strcmp(line, "mr")) {
00875                   h->mr = atoi(p);
00876                } else if (!strcmp(line, "srr")) {
00877                   h->srr = (atoi(p) ? 1 : 0);
00878                } else if (!strcmp(line, "vp")) {
00879                   h->vp = atoi(p);
00880                } else if (!strcmp(line, "rp")) {
00881                   h->rp = (atoi(p) ? 1 : 0);
00882                } else if (!strcmp(line, "scts")) {    /* get date/time */
00883                   int Y, m, d, H, M, S;
00884                   /* XXX Why aren't we using ast_strptime here? */
00885                   if (sscanf(p, "%4d-%2d-%2dT%2d:%2d:%2d", &Y, &m, &d, &H, &M, &S) == 6) {
00886                      struct ast_tm t = { 0, };
00887                      t.tm_year = Y - 1900;
00888                      t.tm_mon = m - 1;
00889                      t.tm_mday = d;
00890                      t.tm_hour = H;
00891                      t.tm_min = M;
00892                      t.tm_sec = S;
00893                      t.tm_isdst = -1;
00894                      h->scts = ast_mktime(&t, NULL);
00895                      if (h->scts.tv_sec == 0) {
00896                         ast_log(LOG_WARNING, "Bad date/timein %s: %s", fn, p);
00897                      }
00898                   }
00899                } else {
00900                   ast_log(LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
00901                }
00902             }
00903          } else if (*p == '#') {                   /* raw hex format */
00904             *p++ = 0;
00905             if (*p == '#') {
00906                p++;
00907                if (!strcmp(line, "ud")) {        /* user data */
00908                   int o = 0;
00909                   while (*p && o < SMSLEN) {
00910                      if (isxdigit(*p) && isxdigit(p[1]) && isxdigit(p[2]) && isxdigit(p[3])) {
00911                         h->ud[o++] =
00912                            (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 12) +
00913                            (((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
00914                            (((isalpha(p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha(p[3]) ? 9 : 0) + (p[3] & 0xF));
00915                         p += 4;
00916                      } else
00917                         break;
00918                   }
00919                   h->udl = o;
00920                   if (*p)
00921                      ast_log(LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
00922                } else
00923                   ast_log(LOG_WARNING, "Only ud can use ## format, %s\n", fn);
00924             } else if (!strcmp(line, "ud")) {       /* user data */
00925                int o = 0;
00926                while (*p && o < SMSLEN) {
00927                   if (isxdigit(*p) && isxdigit(p[1])) {
00928                      h->ud[o++] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
00929                      p += 2;
00930                   } else {
00931                      break;
00932                   }
00933                }
00934                h->udl = o;
00935                if (*p) {
00936                   ast_log(LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
00937                }
00938             } else if (!strcmp(line, "udh")) {      /* user data header */
00939                unsigned char o = 0;
00940                h->udhi = 1;
00941                while (*p && o < SMSLEN) {
00942                   if (isxdigit(*p) && isxdigit(p[1])) {
00943                      h->udh[o] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
00944                      o++;
00945                      p += 2;
00946                   } else {
00947                      break;
00948                   }
00949                }
00950                h->udhl = o;
00951                if (*p) {
00952                   ast_log(LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
00953                }
00954             } else {
00955                ast_log(LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
00956             }
00957          } else {
00958             ast_log(LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
00959          }
00960       }
00961       fclose(s);
00962       if (!dcsset && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00963          if (packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00964             if (packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00965                ast_log(LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
00966             } else {
00967                h->dcs = 0x08;          /* default to 16 bit */
00968                ast_log(LOG_WARNING, "Sending in 16 bit format(%s)\n", fn);
00969             }
00970          } else {
00971             h->dcs = 0xF5;              /* default to 8 bit */
00972             ast_log(LOG_WARNING, "Sending in 8 bit format(%s)\n", fn);
00973          }
00974       }
00975       if (is7bit(h->dcs) && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00976          ast_log(LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
00977       }
00978       if (is8bit(h->dcs) && packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00979          ast_log(LOG_WARNING, "Invalid 8 bit data %s\n", fn);
00980       }
00981       if (is16bit(h->dcs) && packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00982          ast_log(LOG_WARNING, "Invalid 16 bit data %s\n", fn);
00983       }
00984    }
00985 }
00986 
00987 /*! \brief white a received text message to a file */
00988 static void sms_writefile(sms_t * h)
00989 {
00990    char fn[200] = "", fn2[200] = "";
00991    char buf[30];
00992    FILE *o;
00993 
00994    if (ast_tvzero(h->scts)) {
00995       h->scts = ast_tvnow();
00996    }
00997    snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
00998    ast_mkdir(fn, 0777);                    /* ensure it exists */
00999    ast_copy_string(fn2, fn, sizeof(fn2));
01000    snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%s.%s-%d", h->queue, isodate(h->scts.tv_sec, buf, sizeof(buf)), seq++);
01001    snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1);
01002    if ((o = fopen(fn, "w")) == NULL) {
01003       return;
01004    }
01005 
01006    if (*h->oa) {
01007       fprintf(o, "oa=%s\n", h->oa);
01008    }
01009    if (*h->da) {
01010       fprintf(o, "da=%s\n", h->da);
01011    }
01012    if (h->udhi) {
01013       unsigned int p;
01014       fprintf(o, "udh#");
01015       for (p = 0; p < h->udhl; p++) {
01016          fprintf(o, "%02X", h->udh[p]);
01017       }
01018       fprintf(o, "\n");
01019    }
01020    if (h->udl) {
01021       unsigned int p;
01022       for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
01023       if (p < h->udl) {
01024          fputc(';', o);                  /* cannot use ud=, but include as a comment for human readable */
01025       }
01026       fprintf(o, "ud=");
01027       for (p = 0; p < h->udl; p++) {
01028          unsigned short v = h->ud[p];
01029          if (v < 32) {
01030             fputc(191, o);
01031          } else if (v < 0x80) {
01032             fputc(v, o);
01033          } else if (v < 0x800) {
01034             fputc(0xC0 + (v >> 6), o);
01035             fputc(0x80 + (v & 0x3F), o);
01036          } else {
01037             fputc(0xE0 + (v >> 12), o);
01038             fputc(0x80 + ((v >> 6) & 0x3F), o);
01039             fputc(0x80 + (v & 0x3F), o);
01040          }
01041       }
01042       fprintf(o, "\n");
01043       for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
01044       if (p < h->udl) {
01045          for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
01046          if (p == h->udl) {              /* can write in ucs-1 hex */
01047             fprintf(o, "ud#");
01048             for (p = 0; p < h->udl; p++) {
01049                fprintf(o, "%02X", h->ud[p]);
01050             }
01051             fprintf(o, "\n");
01052          } else {                        /* write in UCS-2 */
01053             fprintf(o, "ud##");
01054             for (p = 0; p < h->udl; p++) {
01055                fprintf(o, "%04X", h->ud[p]);
01056             }
01057             fprintf(o, "\n");
01058          }
01059       }
01060    }
01061    if (h->scts.tv_sec) {
01062       char datebuf[30];
01063       fprintf(o, "scts=%s\n", isodate(h->scts.tv_sec, datebuf, sizeof(datebuf)));
01064    }
01065    if (h->pid) {
01066       fprintf(o, "pid=%d\n", h->pid);
01067    }
01068    if (h->dcs != 0xF1) {
01069       fprintf(o, "dcs=%d\n", h->dcs);
01070    }
01071    if (h->vp) {
01072       fprintf(o, "vp=%d\n", h->vp);
01073    }
01074    if (h->srr) {
01075       fprintf(o, "srr=1\n");
01076    }
01077    if (h->mr >= 0) {
01078       fprintf(o, "mr=%d\n", h->mr);
01079    }
01080    if (h->rp) {
01081       fprintf(o, "rp=1\n");
01082    }
01083    fclose(o);
01084    if (rename(fn, fn2)) {
01085       unlink(fn);
01086    } else {
01087       ast_log(LOG_NOTICE, "Received to %s\n", fn2);
01088    }
01089 }
01090 
01091 /*! \brief read dir skipping dot files... */
01092 static struct dirent *readdirqueue(DIR *d, char *queue)
01093 {
01094    struct dirent *f;
01095    do {
01096       f = readdir(d);
01097    } while (f && (*f->d_name == '.' || strncmp(f->d_name, queue, strlen(queue)) || f->d_name[strlen(queue)] != '.'));
01098    return f;
01099 }
01100 
01101 /*! \brief handle the incoming message */
01102 static unsigned char sms_handleincoming (sms_t * h)
01103 {
01104    unsigned char p = 3;
01105    if (h->smsc) {                          /* SMSC */
01106       if ((h->imsg[2] & 3) == 1) {        /* SMS-SUBMIT */
01107          h->udhl = h->udl = 0;
01108          h->vp = 0;
01109          h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
01110          h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
01111          h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
01112          ast_copy_string(h->oa, h->cli, sizeof(h->oa));
01113          h->scts = ast_tvnow();
01114          h->mr = h->imsg[p++];
01115          p += unpackaddress(h->da, h->imsg + p);
01116          h->pid = h->imsg[p++];
01117          h->dcs = h->imsg[p++];
01118          if ((h->imsg[2] & 0x18) == 0x10) {       /* relative VP */
01119             if (h->imsg[p] < 144) {
01120                h->vp = (h->imsg[p] + 1) * 5;
01121             } else if (h->imsg[p] < 168) {
01122                h->vp = 720 + (h->imsg[p] - 143) * 30;
01123             } else if (h->imsg[p] < 197) {
01124                h->vp = (h->imsg[p] - 166) * 1440;
01125             } else {
01126                h->vp = (h->imsg[p] - 192) * 10080;
01127             }
01128             p++;
01129          } else if (h->imsg[2] & 0x18) {
01130             p += 7;                     /* ignore enhanced / absolute VP */
01131          }
01132          p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
01133          h->rx = 1;                      /* received message */
01134          sms_writefile(h);               /* write the file */
01135          if (p != h->imsg[1] + 2) {
01136             ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
01137             return 0xFF;        /* duh! */
01138          }
01139       } else {
01140          ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
01141          return 0xFF;
01142       }
01143    } else {                                /* client */
01144       if (!(h->imsg[2] & 3)) {            /* SMS-DELIVER */
01145          *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
01146          h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
01147          h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
01148          h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
01149          h->mr = -1;
01150          p += unpackaddress(h->oa, h->imsg + p);
01151          h->pid = h->imsg[p++];
01152          h->dcs = h->imsg[p++];
01153          h->scts = unpackdate(h->imsg + p);
01154          p += 7;
01155          p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
01156          h->rx = 1;                      /* received message */
01157          sms_writefile(h);               /* write the file */
01158          if (p != h->imsg[1] + 2) {
01159             ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
01160             return 0xFF;                /* duh! */
01161          }
01162       } else {
01163          ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
01164          return 0xFF;
01165       }
01166    }
01167    return 0;                               /* no error */
01168 }
01169 
01170 #ifdef SOLARIS
01171 #define NAME_MAX 1024
01172 #endif
01173 
01174 /*!
01175  * Add data to a protocol 2 message.
01176  * Use the length field (h->omsg[1]) as a pointer to the next free position.
01177  */
01178 static void adddata_proto2(sms_t *h, unsigned char msg, char *data, int size)
01179 {
01180    int x = h->omsg[1] + 2;                 /* Get current position */
01181    if (x == 2) {
01182       x += 2;                             /* First: skip Payload length (set later) */
01183    }
01184    h->omsg[x++] = msg;                     /* Message code */
01185    h->omsg[x++] = (unsigned char)size;     /* Data size Low */
01186    h->omsg[x++] = 0;                       /* Data size Hi */
01187    for (; size > 0 ; size--) {
01188       h->omsg[x++] = *data++;
01189    }
01190    h->omsg[1] = x - 2;                     /* Frame size */
01191    h->omsg[2] = x - 4;                     /* Payload length (Lo) */
01192    h->omsg[3] = 0;                         /* Payload length (Hi) */
01193 }
01194 
01195 static void putdummydata_proto2(sms_t *h)
01196 {
01197    adddata_proto2(h, 0x10, "\0", 1);           /* Media Identifier > SMS */
01198    adddata_proto2(h, 0x11, "\0\0\0\0\0\0", 6); /* Firmware version */
01199    adddata_proto2(h, 0x12, "\2\0\4", 3);       /* SMS provider ID */
01200    adddata_proto2(h, 0x13, h->udtxt, h->udl);  /* Body */
01201 }
01202 
01203 static void sms_compose2(sms_t *h, int more)
01204 {
01205    struct ast_tm tm;
01206    struct timeval now = h->scts;
01207    char stm[9];
01208 
01209    h->omsg[0] = 0x00;                      /* set later... */
01210    h->omsg[1] = 0;
01211    putdummydata_proto2(h);
01212    if (h->smsc) {                          /* deliver */
01213       h->omsg[0] = 0x11;                  /* SMS_DELIVERY */
01214       /* Required: 10 11 12 13 14 15 17 (seems they must be ordered!) */
01215       ast_localtime(&now, &tm, NULL);
01216       sprintf(stm, "%02d%02d%02d%02d", tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min);  /* Date mmddHHMM */
01217       adddata_proto2(h, 0x14, stm, 8);    /* Date */
01218       if (*h->oa == 0) {
01219          strcpy(h->oa, "00000000");
01220       }
01221       adddata_proto2(h, 0x15, h->oa, strlen(h->oa)); /* Originator */
01222       adddata_proto2(h, 0x17, "\1", 1);   /* Calling Terminal ID */
01223    } else {                                /* submit */
01224       h->omsg[0] = 0x10;                  /* SMS_SUBMIT */
01225       /* Required: 10 11 12 13 17 18 1B 1C (seems they must be ordered!) */
01226       adddata_proto2(h, 0x17, "\1", 1);   /* Calling Terminal ID */
01227       if (*h->da == 0) {
01228          strcpy(h->da, "00000000");
01229       }
01230       adddata_proto2(h, 0x18, h->da, strlen(h->da)); /* Originator */
01231       adddata_proto2(h, 0x1B, "\1", 1);         /* Called Terminal ID */
01232       adddata_proto2(h, 0x1C, "\0\0\0", 3);    /* Notification */
01233    }
01234 }
01235 
01236 static void putdummydata_proto2(sms_t *h);
01237 
01238 #define MAX_DEBUG_LEN   300
01239 static char *sms_hexdump(unsigned char buf[], int size, char *s /* destination */)
01240 {
01241    char *p;
01242    int f;
01243 
01244    for (p = s, f = 0; f < size && f < MAX_DEBUG_LEN; f++, p += 3) {
01245       sprintf(p, "%02X ", (unsigned char)buf[f]);
01246    }
01247    return(s);
01248 }
01249 
01250 
01251 /*! \brief sms_handleincoming_proto2: handle the incoming message */
01252 static int sms_handleincoming_proto2(sms_t *h)
01253 {
01254    int f, i, sz = 0;
01255    int msg, msgsz;
01256    struct ast_tm tm;
01257    struct timeval now = { 0, 0 };
01258    char debug_buf[MAX_DEBUG_LEN * 3 + 1];
01259 
01260    sz = h->imsg[1] + 2;
01261    /* ast_verb(3, "SMS-P2 Frame: %s\n", sms_hexdump(h->imsg, sz, debug_buf)); */
01262 
01263    /* Parse message body (called payload) */
01264    now = h->scts = ast_tvnow();
01265    for (f = 4; f < sz; ) {
01266       msg = h->imsg[f++];
01267       msgsz = h->imsg[f++];
01268       msgsz += (h->imsg[f++] * 256);
01269       switch (msg) {
01270       case 0x13:                          /* Body */
01271          ast_verb(3, "SMS-P2 Body#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
01272          if (msgsz >= sizeof(h->ud)) {
01273             msgsz = sizeof(h->ud) - 1;
01274          }
01275          for (i = 0; i < msgsz; i++) {
01276             h->ud[i] = h->imsg[f + i];
01277          }
01278          h->udl = msgsz;
01279          break;
01280       case 0x14:                          /* Date SCTS */
01281          now = h->scts = ast_tvnow();
01282          ast_localtime(&now, &tm, NULL);
01283          tm.tm_mon = ( (h->imsg[f] * 10) + h->imsg[f + 1] ) - 1;
01284          tm.tm_mday = ( (h->imsg[f + 2] * 10) + h->imsg[f + 3] );
01285          tm.tm_hour = ( (h->imsg[f + 4] * 10) + h->imsg[f + 5] );
01286          tm.tm_min = ( (h->imsg[f + 6] * 10) + h->imsg[f + 7] );
01287          tm.tm_sec = 0;
01288          h->scts = ast_mktime(&tm, NULL);
01289          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);
01290          break;
01291       case 0x15:                          /* Calling line (from SMSC) */
01292          if (msgsz >= 20) {
01293             msgsz = 20 - 1;
01294          }
01295          ast_verb(3, "SMS-P2 Origin#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
01296          ast_copy_string(h->oa, (char *)(&h->imsg[f]), msgsz + 1);
01297          break;
01298       case 0x18:                          /* Destination(from TE/phone) */
01299          if (msgsz >= 20) {
01300             msgsz = 20 - 1;
01301          }
01302          ast_verb(3, "SMS-P2 Destination#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
01303          ast_copy_string(h->da, (char *)(&h->imsg[f]), msgsz + 1);
01304          break;
01305       case 0x1C:                          /* Notify */
01306          ast_verb(3, "SMS-P2 Notify#%02X=%s\n", msg, sms_hexdump(&h->imsg[f], 3, debug_buf));
01307          break;
01308       default:
01309          ast_verb(3, "SMS-P2 Par#%02X [%d]: %s\n", msg, msgsz, sms_hexdump(&h->imsg[f], msgsz, debug_buf));
01310          break;
01311       }
01312       f+=msgsz;                           /* Skip to next */
01313    }
01314    h->rx = 1;                              /* received message */
01315    sms_writefile(h);                       /* write the file */
01316    return 0;                               /* no error */
01317 }
01318 
01319 #if 0
01320 static void smssend(sms_t *h, char *c)
01321 {
01322    int f, x;
01323    for (f = 0; f < strlen(c); f++) {
01324       sscanf(&c[f*3], "%x", &x);
01325       h->omsg[f] = x;
01326    }
01327    sms_messagetx(h);
01328 }
01329 #endif
01330 
01331 static void sms_nextoutgoing (sms_t *h);
01332 
01333 static void sms_messagerx2(sms_t * h)
01334 {
01335    int p = h->imsg[0] & DLL_SMS_MASK ; /* mask the high bit */
01336    int cause;
01337 
01338 #define DLL2_ACK(h) ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1)
01339    switch (p) {
01340    case DLL2_SMS_EST:                      /* Protocol 2: Connection ready (fake): send message  */
01341       sms_nextoutgoing (h);
01342       /* 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 "); */
01343       break;
01344 
01345    case DLL2_SMS_INFO_MO:                  /* transport SMS_SUBMIT */
01346    case DLL2_SMS_INFO_MT:                  /* transport SMS_DELIVERY */
01347       cause = sms_handleincoming_proto2(h);
01348       if (!cause) {                       /* ACK */
01349          sms_log(h, 'Y');
01350       }
01351       h->omsg[0] = DLL2_ACK(h);
01352       h->omsg[1] = 0x06;                  /* msg len */
01353       h->omsg[2] = 0x04;                  /* payload len */
01354       h->omsg[3] = 0x00;                  /* payload len */
01355       h->omsg[4] = 0x1f;                  /* Response type */
01356       h->omsg[5] = 0x01;                  /* parameter len */
01357       h->omsg[6] = 0x00;                  /* parameter len */
01358       h->omsg[7] = cause;                 /* CONFIRM or error */
01359       sms_messagetx(h);
01360       break;
01361 
01362    case DLL2_SMS_NACK:                     /* Protocol 2: SMS_NAK */
01363       h->omsg[0] = DLL2_SMS_REL;          /* SMS_REL */
01364       h->omsg[1] = 0x00;                  /* msg len */
01365       sms_messagetx(h);
01366       break;
01367 
01368    case DLL2_SMS_ACK0:
01369    case DLL2_SMS_ACK1:
01370       /* SMS_ACK also transport SMS_SUBMIT or SMS_DELIVERY */
01371       if ( (h->omsg[0] & DLL_SMS_MASK) == DLL2_SMS_REL) {
01372          /* a response to our Release, just hangup */
01373          h->hangup = 1;                  /* hangup */
01374       } else {
01375          /* XXX depending on what we are.. */
01376          ast_log(LOG_NOTICE, "SMS_SUBMIT or SMS_DELIVERY\n");
01377          sms_nextoutgoing (h);
01378       }
01379       break;
01380 
01381    case DLL2_SMS_REL:                      /* Protocol 2: SMS_REL (hangup req) */
01382       h->omsg[0] = DLL2_ACK(h);
01383       h->omsg[1] = 0;
01384       sms_messagetx(h);
01385       break;
01386    }
01387 }
01388 
01389 /*! \brief compose a message for protocol 1 */
01390 static void sms_compose1(sms_t *h, int more)
01391 {
01392    unsigned int p = 2;                     /* next byte to write. Skip type and len */
01393 
01394    h->omsg[0] = 0x91;                      /* SMS_DATA */
01395    if (h->smsc) {                          /* deliver */
01396       h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
01397       p += packaddress(h->omsg + p, h->oa);
01398       h->omsg[p++] = h->pid;
01399       h->omsg[p++] = h->dcs;
01400       packdate(h->omsg + p, h->scts.tv_sec);
01401       p += 7;
01402       p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01403    } else {                                /* submit */
01404       h->omsg[p++] =
01405          0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
01406       if (h->mr < 0) {
01407          h->mr = message_ref++;
01408       }
01409       h->omsg[p++] = h->mr;
01410       p += packaddress(h->omsg + p, h->da);
01411       h->omsg[p++] = h->pid;
01412       h->omsg[p++] = h->dcs;
01413       if (h->vp) {                        /* relative VP */
01414          if (h->vp < 720) {
01415             h->omsg[p++] = (h->vp + 4) / 5 - 1;
01416          } else if (h->vp < 1440) {
01417             h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
01418          } else if (h->vp < 43200) {
01419             h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
01420          } else if (h->vp < 635040) {
01421             h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
01422          } else {
01423             h->omsg[p++] = 255;         /* max */
01424          }
01425       }
01426       p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01427    }
01428    h->omsg[1] = p - 2;
01429 }
01430 
01431 /*! \brief find and fill in next message, or send a REL if none waiting */
01432 static void sms_nextoutgoing (sms_t * h)
01433 {    
01434    char fn[100 + NAME_MAX] = "";
01435    DIR *d;
01436    char more = 0;
01437 
01438    *h->da = *h->oa = '\0';                 /* clear destinations */
01439    h->rx = 0;                              /* outgoing message */
01440    snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? "mttx" : "motx");
01441    ast_mkdir(fn, 0777);                    /* ensure it exists */
01442    d = opendir(fn);
01443    if (d) {
01444       struct dirent *f = readdirqueue(d, h->queue);
01445       if (f) {
01446          snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", f->d_name);
01447          sms_readfile(h, fn);
01448          if (readdirqueue(d, h->queue)) {
01449             more = 1;                   /* more to send */
01450          }
01451       }
01452       closedir(d);
01453    }
01454    if (*h->da || *h->oa) {                 /* message to send */
01455       if (h->protocol == 2) {
01456          sms_compose2(h, more);
01457       } else {
01458          sms_compose1(h, more);
01459       }
01460    } else {                                /* no message */
01461       if (h->protocol == 2) {
01462          h->omsg[0] = 0x17;              /* SMS_REL */
01463          h->omsg[1] = 0;
01464       } else {
01465          h->omsg[0] = 0x94;              /* SMS_REL */
01466          h->omsg[1] = 0;
01467       }
01468    }
01469    sms_messagetx(h);
01470 }
01471 
01472 #define DIR_RX 1
01473 #define DIR_TX 2
01474 static void sms_debug (int dir, sms_t *h)
01475 {
01476    char txt[259 * 3 + 1];
01477    char *p = txt;                          /* always long enough */
01478    unsigned char *msg = (dir == DIR_RX) ? h->imsg : h->omsg;
01479    int n = (dir == DIR_RX) ? h->ibytep : msg[1] + 2;
01480    int q = 0;
01481    while (q < n && q < 30) {
01482       sprintf(p, " %02X", msg[q++]);
01483       p += 3;
01484    }
01485    if (q < n) {
01486       sprintf(p, "...");
01487    }
01488    ast_verb(3, "SMS %s%s\n", dir == DIR_RX ? "RX" : "TX", txt);
01489 }
01490 
01491 
01492 static void sms_messagerx(sms_t * h)
01493 {
01494    int cause;
01495 
01496    sms_debug (DIR_RX, h);
01497    if (h->protocol == 2) {
01498       sms_messagerx2(h);
01499       return;
01500    }
01501    /* parse incoming message for Protocol 1 */
01502    switch (h->imsg[0]) {
01503    case 0x91:                              /* SMS_DATA */
01504       cause = sms_handleincoming (h);
01505       if (!cause) {
01506          sms_log(h, 'Y');
01507          h->omsg[0] = 0x95;              /* SMS_ACK */
01508          h->omsg[1] = 0x02;
01509          h->omsg[2] = 0x00;              /* deliver report */
01510          h->omsg[3] = 0x00;              /* no parameters */
01511       } else {                            /* NACK */
01512          sms_log(h, 'N');
01513          h->omsg[0] = 0x96;              /* SMS_NACK */
01514          h->omsg[1] = 3;
01515          h->omsg[2] = 0;                 /* delivery report */
01516          h->omsg[3] = cause;             /* cause */
01517          h->omsg[4] = 0;                 /* no parameters */
01518       }
01519       sms_messagetx(h);
01520       break;
01521 
01522    case 0x92:                              /* SMS_ERROR */
01523       h->err = 1;
01524       sms_messagetx(h);                   /* send whatever we sent again */
01525       break;
01526    case 0x93:                              /* SMS_EST */
01527       sms_nextoutgoing (h);
01528       break;
01529    case 0x94:                              /* SMS_REL */
01530       h->hangup = 1;                      /* hangup */
01531       break;
01532    case 0x95:                              /* SMS_ACK */
01533       sms_log(h, 'Y');
01534       sms_nextoutgoing (h);
01535       break;
01536    case 0x96:                              /* SMS_NACK */
01537       h->err = 1;
01538       sms_log(h, 'N');
01539       sms_nextoutgoing (h);
01540       break;
01541    default:                                /* Unknown */
01542       h->omsg[0] = 0x92;                  /* SMS_ERROR */
01543       h->omsg[1] = 1;
01544       h->omsg[2] = 3;                     /* unknown message type */
01545       sms_messagetx(h);
01546       break;
01547    }
01548 }
01549 
01550 static void sms_messagetx(sms_t * h)
01551 {
01552    unsigned char c = 0, p;
01553    int len = h->omsg[1] + 2;               /* total message length excluding checksum */
01554 
01555    for (p = 0; p < len; p++) {             /* compute checksum */
01556       c += h->omsg[p];
01557    }
01558    h->omsg[len] = 0 - c;                   /* actually, (256 - (c & 0fxx)) & 0xff) */
01559    sms_debug(DIR_TX, h);
01560    h->framenumber++;                       /* Proto 2 */
01561    h->obytep = 0;
01562    h->obitp = 0;
01563    if (h->protocol == 2) {                 /* Proto 2: */
01564       h->oseizure = 300;                  /* 300bits (or more ?) */
01565       h->obyte = 0;                       /* Seizure starts with  space (0) */
01566       if (h->omsg[0] == 0x7F) {
01567          h->opause = 8 * h->opause_0;    /* initial message delay */
01568       } else {
01569          h->opause = 400;
01570       }
01571    } else {                                /* Proto 1: */
01572       h->oseizure = 0;                    /* No seizure */
01573       h->obyte = 1;                       /* send mark ('1') at the beginning */
01574       /* Change the initial message delay. BT requires 300ms,
01575        * but for others this might be way too much and the phone
01576        * could time out. XXX make it configurable.
01577       */
01578       if (h->omsg[0] == 0x93) {
01579          h->opause = 8 * h->opause_0;    /* initial message delay */
01580       } else {
01581          h->opause = 200;
01582       }
01583    }
01584    /* Note - setting osync triggers the generator */
01585    h->osync = OSYNC_BITS;                  /* 80 sync bits */
01586    h->obyten = len + 1;                    /* bytes to send (including checksum) */
01587 }
01588 
01589 /*!
01590  * outgoing data are produced by this generator function, that reads from
01591  * the descriptor whether it has data to send and which ones.
01592  */
01593 static int sms_generate(struct ast_channel *chan, void *data, int len, int samples)
01594 {
01595    struct ast_frame f = { 0 };
01596 #define MAXSAMPLES (800)
01597    output_t *buf;
01598    sms_t *h = data;
01599    int i;
01600 
01601    if (samples > MAXSAMPLES) {
01602       ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n",
01603           MAXSAMPLES, samples);
01604       samples = MAXSAMPLES;
01605    }
01606    len = samples * sizeof(*buf) + AST_FRIENDLY_OFFSET;
01607    buf = ast_alloca(len);
01608 
01609    f.frametype = AST_FRAME_VOICE;
01610    f.subclass.codec = __OUT_FMT;
01611    f.datalen = samples * sizeof(*buf);
01612    f.offset = AST_FRIENDLY_OFFSET;
01613    f.mallocd = 0;
01614    f.data.ptr = buf;
01615    f.samples = samples;
01616    f.src = "app_sms";
01617    /* create a buffer containing the digital sms pattern */
01618    for (i = 0; i < samples; i++) {
01619       buf[i] = wave_out[0];               /* default is silence */
01620 
01621       if (h->opause) {
01622          h->opause--;
01623       } else if (h->obyten || h->osync) { /* sending data */
01624          buf[i] = wave_out[h->ophase];
01625          h->ophase += (h->obyte & 1) ? 13 : 21; /* compute next phase */
01626          if (h->ophase >= 80)
01627             h->ophase -= 80;
01628          if ((h->ophasep += 12) >= 80) { /* time to send the next bit */
01629             h->ophasep -= 80;
01630             if (h->oseizure > 0) {      /* sending channel seizure (proto 2) */
01631                h->oseizure--;
01632                h->obyte ^= 1;          /* toggle low bit */
01633             } else if (h->osync) {
01634                h->obyte = 1;           /* send mark as sync bit */
01635                h->osync--;             /* sending sync bits */
01636                if (h->osync == 0 && h->protocol == 2 && h->omsg[0] == DLL2_SMS_EST) {
01637                   h->obytep = h->obyten = 0; /* we are done */
01638                }
01639             } else {
01640                h->obitp++;
01641                if (h->obitp == 1) {
01642                   h->obyte = 0;       /* start bit; */
01643                } else if (h->obitp == 2) {
01644                   h->obyte = h->omsg[h->obytep];
01645                } else if (h->obitp == 10) {
01646                   h->obyte = 1; /* stop bit */
01647                   h->obitp = 0;
01648                   h->obytep++;
01649                   if (h->obytep == h->obyten) {
01650                      h->obytep = h->obyten = 0; /* sent */
01651                      h->osync = 10;   /* trailing marks */
01652                   }
01653                } else {
01654                   h->obyte >>= 1;
01655                }
01656             }
01657          }
01658       }
01659    }
01660    if (ast_write(chan, &f) < 0) {
01661       ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
01662       return -1;
01663    }
01664    return 0;
01665 #undef MAXSAMPLES
01666 }
01667 
01668 /*!
01669  * Just return the pointer to the descriptor that we received.
01670  */
01671 static void *sms_alloc(struct ast_channel *chan, void *sms_t_ptr)
01672 {
01673    return sms_t_ptr;
01674 }
01675 
01676 static void sms_release(struct ast_channel *chan, void *data)
01677 {
01678    return;  /* nothing to do here. */
01679 }
01680 
01681 static struct ast_generator smsgen = {
01682    .alloc = sms_alloc,
01683    .release = sms_release,
01684    .generate = sms_generate,
01685 };
01686 
01687 /*!
01688  * Process an incoming frame, trying to detect the carrier and
01689  * decode the message. The two frequencies are 1300 and 2100 Hz.
01690  * The decoder detects the amplitude of the signal over the last
01691  * few samples, filtering the absolute values with a lowpass filter.
01692  * If the magnitude (h->imag) is large enough, multiply the signal
01693  * by the two carriers, and compute the amplitudes m0 and m1.
01694  * Record the current sample as '0' or '1' depending on which one is greater.
01695  * The last 3 bits are stored in h->ibith, with the count of '1'
01696  * bits in h->ibitt.
01697  * XXX the rest is to be determined.
01698  */
01699 static void sms_process(sms_t * h, int samples, signed short *data)
01700 {
01701    int bit;
01702 
01703    /*
01704     * Ignore incoming audio while a packet is being transmitted,
01705     * the protocol is half-duplex.
01706     * Unfortunately this means that if the outbound and incoming
01707     * transmission overlap (which is an error condition anyways),
01708     * we may miss some data and this makes debugging harder.
01709     */
01710    if (h->obyten || h->osync) {
01711       return;
01712    }
01713    for ( ; samples-- ; data++) {
01714       unsigned long long m0, m1;
01715       if (abs(*data) > h->imag) {
01716          h->imag = abs(*data);
01717       } else {
01718          h->imag = h->imag * 7 / 8;
01719       }
01720       if (h->imag <= 500) {               /* below [arbitrary] threahold: lost carrier */
01721          if (h->idle++ == 80000) {       /* nothing happening */
01722             ast_log(LOG_NOTICE, "No data, hanging up\n");
01723             h->hangup = 1;
01724             h->err = 1;
01725          }
01726          if (h->ierr) {                  /* error */
01727             ast_log(LOG_NOTICE, "Error %d, hanging up\n", h->ierr);
01728             /* Protocol 1 */
01729             h->err = 1;
01730             h->omsg[0] = 0x92;          /* error */
01731             h->omsg[1] = 1;
01732             h->omsg[2] = h->ierr;
01733             sms_messagetx(h);           /* send error */
01734          }
01735          h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01736          continue;
01737       }
01738       h->idle = 0;
01739 
01740       /* multiply signal by the two carriers. */
01741       h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
01742       h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
01743       h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
01744       h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
01745       /* compute the amplitudes */
01746       m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
01747       m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
01748 
01749       /* advance the sin/cos pointers */
01750       if ((h->ips0 += 21) >= 80) {
01751          h->ips0 -= 80;
01752       }
01753       if ((h->ipc0 += 21) >= 80) {
01754          h->ipc0 -= 80;
01755       }
01756       if ((h->ips1 += 13) >= 80) {
01757          h->ips1 -= 80;
01758       }
01759       if ((h->ipc1 += 13) >= 80) {
01760          h->ipc1 -= 80;
01761       }
01762 
01763       /* set new bit to 1 or 0 depending on which value is stronger */
01764       h->ibith <<= 1;
01765       if (m1 > m0) {
01766          h->ibith |= 1;
01767       }
01768       if (h->ibith & 8) {
01769          h->ibitt--;
01770       }
01771       if (h->ibith & 1) {
01772          h->ibitt++;
01773       }
01774       bit = ((h->ibitt > 1) ? 1 : 0);
01775       if (bit != h->ibitl) {
01776          h->ibitc = 1;
01777       } else {
01778          h->ibitc++;
01779       }
01780       h->ibitl = bit;
01781       if (!h->ibitn && h->ibitc == 4 && !bit) {
01782          h->ibitn = 1;
01783          h->iphasep = 0;
01784       }
01785       if (bit && h->ibitc == 200) {       /* sync, restart message */
01786          /* Protocol 2: empty connection ready (I am master) */
01787          if (h->framenumber < 0 && h->ibytec >= 160 && !memcmp(h->imsg, "UUUUUUUUUUUUUUUUUUUU", 20)) {
01788             h->framenumber = 1;
01789             ast_verb(3, "SMS protocol 2 detected\n");
01790             h->protocol = 2;
01791             h->imsg[0] = 0xff;          /* special message (fake) */
01792             h->imsg[1] = h->imsg[2] = 0x00;
01793             h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01794             sms_messagerx(h);
01795          }
01796          h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01797       }
01798       if (h->ibitn) {
01799          h->iphasep += 12;
01800          if (h->iphasep >= 80) {         /* next bit */
01801             h->iphasep -= 80;
01802             if (h->ibitn++ == 9) {      /* end of byte */
01803                if (!bit) {             /* bad stop bit */
01804                   ast_log(LOG_NOTICE, "bad stop bit\n");
01805                   h->ierr = 0xFF;     /* unknown error */
01806                } else {
01807                   if (h->ibytep < sizeof(h->imsg)) {
01808                      h->imsg[h->ibytep] = h->ibytev;
01809                      h->ibytec += h->ibytev;
01810                      h->ibytep++;
01811                   } else if (h->ibytep == sizeof(h->imsg)) {
01812                      ast_log(LOG_NOTICE, "msg too large\n");
01813                      h->ierr = 2;    /* bad message length */
01814                   }
01815                   if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
01816                      if (!h->ibytec) {
01817                         sms_messagerx(h);
01818                      } else {
01819                         ast_log(LOG_NOTICE, "bad checksum\n");
01820                         h->ierr = 1; /* bad checksum */
01821                      }
01822                   }
01823                }
01824                h->ibitn = 0;
01825             }
01826             h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
01827          }
01828       }
01829    }
01830 }
01831 
01832 /*
01833  * Standard argument parsing:
01834  * - one enum for the flags we recognise,
01835  * - one enum for argument indexes
01836  * - AST_APP_OPTIONS() to drive the parsing routine
01837  * - in the function, AST_DECLARE_APP_ARGS(...) for the arguments.
01838  */
01839 enum sms_flags {
01840    OPTION_BE_SMSC = (1 << 0),             /* act as sms center */
01841    OPTION_ANSWER  = (1 << 1),             /* answer on incoming calls */
01842    OPTION_TWO  = (1 << 2),                 /* Use Protocol Two */
01843    OPTION_PAUSE   = (1 << 3),             /* pause before sending data, in ms */
01844    OPTION_SRR  = (1 << 4),                 /* set srr */
01845    OPTION_DCS  = (1 << 5),                 /* set dcs */
01846 };
01847 
01848 enum sms_opt_args {
01849    OPTION_ARG_PAUSE = 0,
01850    OPTION_ARG_ARRAY_SIZE
01851 };
01852 
01853 AST_APP_OPTIONS(sms_options, {
01854    AST_APP_OPTION('s', OPTION_BE_SMSC),
01855    AST_APP_OPTION('a', OPTION_ANSWER),
01856    AST_APP_OPTION('t', OPTION_TWO),
01857    AST_APP_OPTION('r', OPTION_SRR),
01858    AST_APP_OPTION('o', OPTION_DCS),
01859    AST_APP_OPTION_ARG('p', OPTION_PAUSE, OPTION_ARG_PAUSE),
01860    } );
01861 
01862 static int sms_exec(struct ast_channel *chan, const char *data)
01863 {
01864    int res = -1;
01865    sms_t h = { 0 };
01866    /* argument parsing support */
01867    struct ast_flags flags;
01868    char *parse, *sms_opts[OPTION_ARG_ARRAY_SIZE] = { 0, };
01869    char *p;
01870    AST_DECLARE_APP_ARGS(sms_args,
01871       AST_APP_ARG(queue);
01872       AST_APP_ARG(options);
01873       AST_APP_ARG(addr);
01874       AST_APP_ARG(body);
01875    );
01876 
01877    if (!data) {
01878       ast_log(LOG_ERROR, "Requires queue name at least\n");
01879       return -1;
01880    }
01881 
01882    parse = ast_strdupa(data);              /* create a local copy */
01883    AST_STANDARD_APP_ARGS(sms_args, parse);
01884    if (sms_args.argc > 1) {
01885       ast_app_parse_options(sms_options, &flags, sms_opts, sms_args.options);
01886    }
01887 
01888    ast_verb(1, "sms argc %d queue <%s> opts <%s> addr <%s> body <%s>\n",
01889       sms_args.argc, S_OR(sms_args.queue, ""),
01890       S_OR(sms_args.options, ""),
01891       S_OR(sms_args.addr, ""),
01892       S_OR(sms_args.body, "") );
01893 
01894    h.ipc0 = h.ipc1 = 20;                   /* phase for cosine */
01895    h.dcs = 0xF1;                           /* default */
01896 
01897    ast_copy_string(h.cli,
01898       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
01899       sizeof(h.cli));
01900 
01901    if (ast_strlen_zero(sms_args.queue)) {
01902       ast_log(LOG_ERROR, "Requires queue name\n");
01903       goto done;
01904    }
01905    if (strlen(sms_args.queue) >= sizeof(h.queue)) {
01906       ast_log(LOG_ERROR, "Queue name too long\n");
01907       goto done;
01908    }
01909    ast_copy_string(h.queue, sms_args.queue, sizeof(h.queue));
01910 
01911    for (p = h.queue; *p; p++) {
01912       if (!isalnum(*p)) {
01913          *p = '-';                       /* make very safe for filenames */
01914       }
01915    }
01916 
01917    h.smsc = ast_test_flag(&flags, OPTION_BE_SMSC);
01918    h.protocol = ast_test_flag(&flags, OPTION_TWO) ? 2 : 1;
01919    if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE])) {
01920       h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]);
01921    }
01922    if (h.opause_0 < 25 || h.opause_0 > 2000) {
01923       h.opause_0 = 300;                   /* default 300ms */
01924    }
01925    ast_verb(1, "initial delay %dms\n", h.opause_0);
01926 
01927 
01928    /* the following apply if there is an arg3/4 and apply to the created message file */
01929    if (ast_test_flag(&flags, OPTION_SRR)) {
01930       h.srr = 1;
01931    }
01932    if (ast_test_flag(&flags, OPTION_DCS)) {
01933       h.dcs = 1;
01934    }
01935 #if 0 
01936       case '1':
01937       case '2':
01938       case '3':
01939       case '4':
01940       case '5':
01941       case '6':
01942       case '7':                           /* set the pid for saved local message */
01943          h.pid = 0x40 + (*d & 0xF);
01944          break;
01945       }
01946 #endif
01947    if (sms_args.argc > 2) {
01948       unsigned char *up;
01949 
01950       /* submitting a message, not taking call. */
01951       /* deprecated, use smsq instead */
01952       h.scts = ast_tvnow();
01953       if (ast_strlen_zero(sms_args.addr) || strlen(sms_args.addr) >= sizeof(h.oa)) {
01954          ast_log(LOG_ERROR, "Address too long %s\n", sms_args.addr);
01955          goto done;
01956       }
01957       if (h.smsc) {
01958          ast_copy_string(h.oa, sms_args.addr, sizeof(h.oa));
01959       } else {
01960          ast_copy_string(h.da, sms_args.addr, sizeof(h.da));
01961          ast_copy_string(h.oa, h.cli, sizeof(h.oa));
01962       }
01963       h.udl = 0;
01964       if (ast_strlen_zero(sms_args.body)) {
01965          ast_log(LOG_ERROR, "Missing body for %s\n", sms_args.addr);
01966          goto done;
01967       }
01968       up = (unsigned char *)sms_args.body;
01969       while (*up && h.udl < SMSLEN) {
01970          h.ud[h.udl++] = utf8decode(&up);
01971       }
01972       if (is7bit(h.dcs) && packsms7(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
01973          ast_log(LOG_WARNING, "Invalid 7 bit GSM data\n");
01974          goto done;
01975       }
01976       if (is8bit(h.dcs) && packsms8(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
01977          ast_log(LOG_WARNING, "Invalid 8 bit data\n");
01978          goto done;
01979       }
01980       if (is16bit(h.dcs) && packsms16(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
01981          ast_log(LOG_WARNING, "Invalid 16 bit data\n");
01982          goto done;
01983       }
01984       h.rx = 0;                           /* sent message */
01985       h.mr = -1;
01986       sms_writefile(&h);
01987       res = h.err;
01988       goto done;
01989    }
01990    
01991    if (chan->_state != AST_STATE_UP) {    /* make sure channel is answered before any TX */
01992       ast_answer(chan);
01993    }
01994 
01995    if (ast_test_flag(&flags, OPTION_ANSWER)) {
01996       h.framenumber = 1;                  /* Proto 2 */
01997       /* set up SMS_EST initial message */
01998       if (h.protocol == 2) {
01999          h.omsg[0] = DLL2_SMS_EST;
02000          h.omsg[1] = 0;
02001       } else {
02002          h.omsg[0] = DLL1_SMS_EST | DLL1_SMS_COMPLETE;
02003          h.omsg[1] = 0;
02004       }
02005       sms_messagetx(&h);
02006    }
02007 
02008    res = ast_set_write_format(chan, __OUT_FMT);
02009    if (res >= 0) {
02010       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
02011    }
02012    if (res < 0) {
02013       ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n");
02014       goto done;
02015    }
02016 
02017    if ( (res = ast_activate_generator(chan, &smsgen, &h)) < 0) {
02018       ast_log(LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
02019       goto done;
02020    }
02021 
02022    /* Do our thing here */
02023    for (;;) {
02024       struct ast_frame *f;
02025       int i = ast_waitfor(chan, -1);
02026       if (i < 0) {
02027          ast_log(LOG_NOTICE, "waitfor failed\n");
02028          break;
02029       }
02030       if (h.hangup) {
02031          ast_log(LOG_NOTICE, "channel hangup\n");
02032          break;
02033       }
02034       f = ast_read(chan);
02035       if (!f) {
02036          ast_log(LOG_NOTICE, "ast_read failed\n");
02037          break;
02038       }
02039       if (f->frametype == AST_FRAME_VOICE) {
02040          sms_process(&h, f->samples, f->data.ptr);
02041       }
02042 
02043       ast_frfree(f);
02044    }
02045    res = h.err;                            /* XXX */
02046 
02047    /* 
02048     * The SMS generator data is on the stack.  We _MUST_ make sure the generator
02049     * is stopped before returning from this function.
02050     */
02051    ast_deactivate_generator(chan);
02052 
02053    sms_log(&h, '?');                       /* log incomplete message */
02054 done:
02055    return (res);
02056 }
02057 
02058 static int unload_module(void)
02059 {
02060    return ast_unregister_application(app);
02061 }
02062 
02063 static int load_module(void)
02064 {
02065 #ifdef OUTALAW
02066    int p;
02067    for (p = 0; p < 80; p++) {
02068       wavea[p] = AST_LIN2A(wave[p]);
02069    }
02070 #endif
02071    snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR);
02072    return ast_register_application_xml(app, sms_exec);
02073 }
02074 
02075 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SMS/PSTN handler");

Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1