Wed Apr 6 11:29:39 2011

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

Generated on Wed Apr 6 11:29:39 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7