Fri Jul 24 00:40:42 2009

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

Generated on Fri Jul 24 00:40:42 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7