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

Generated on Thu Jul 9 13:40:20 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7