Sat Aug 6 00:39:21 2011

Asterisk developer's documentation


app_sms.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2004 - 2005, Adrian Kennard, rights assigned to Digium
00005  *
00006  * See http://www.asterisk.org for more information about
00007  * the Asterisk project. Please do not directly contact
00008  * any of the maintainers of this project for assistance;
00009  * the project provides a web site, mailing lists and IRC
00010  * channels for your use.
00011  *
00012  * This program is free software, distributed under the terms of
00013  * the GNU General Public License Version 2. See the LICENSE file
00014  * at the top of the source tree.
00015  */
00016 
00017 /*! \file
00018  *
00019  * \brief SMS application - ETSI ES 201 912 protocol 1 implimentation
00020  * \ingroup applications
00021  *
00022  * \author Adrian Kennard
00023  */
00024 
00025 #include "asterisk.h"
00026 
00027 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 289424 $")
00028 
00029 #include <stdlib.h>
00030 #include <stdio.h>
00031 #include <string.h>
00032 #include <unistd.h>
00033 #include <errno.h>
00034 #include <dirent.h>
00035 #include <ctype.h>
00036 #include <sys/types.h>
00037 #include <sys/stat.h>
00038 
00039 #include "asterisk/lock.h"
00040 #include "asterisk/file.h"
00041 #include "asterisk/logger.h"
00042 #include "asterisk/options.h"
00043 #include "asterisk/channel.h"
00044 #include "asterisk/pbx.h"
00045 #include "asterisk/module.h"
00046 #include "asterisk/alaw.h"
00047 #include "asterisk/callerid.h"
00048 
00049 /* output using Alaw rather than linear */
00050 /* #define OUTALAW */
00051 
00052 /* ToDo */
00053 /* Add full VP support */
00054 /* Handle status report messages (generation and reception) */
00055 /* Time zones on time stamps */
00056 /* user ref field */
00057 
00058 static volatile unsigned char message_ref;      /* arbitary message ref */
00059 static volatile unsigned int seq;       /* arbitrary message sequence number for unqiue files */
00060 
00061 static char log_file[255];
00062 static char spool_dir[255];
00063 
00064 static char *app = "SMS";
00065 
00066 static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
00067 
00068 static char *descrip =
00069    "  SMS(name|[a][s]):  SMS handles exchange of SMS data with a call to/from SMS capabale\n"
00070    "phone or SMS PSTN service center. Can send and/or receive SMS messages.\n"
00071    "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
00072    "Typical usage is to use to handle called from the SMS service centre CLI,\n"
00073    "or to set up a call using 'outgoing' or manager interface to connect\n"
00074    "service centre to SMS()\n"
00075    "name is the name of the queue used in /var/spool/asterisk/sms\n"
00076    "Arguments:\n"
00077    " a: answer, i.e. send initial FSK packet.\n"
00078    " s: act as service centre talking to a phone.\n"
00079    "Messages are processed as per text file message queues.\n" 
00080    "smsq (a separate software) is a command to generate message\n"
00081    "queues and send messages.\n";
00082 
00083 static signed short wave[] = {
00084    0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
00085    5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
00086    0, -392, -782, -1167,
00087     -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
00088    -4985, -4938, -4862,
00089    -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
00090 };
00091 
00092 #ifdef OUTALAW
00093 static unsigned char wavea[80];
00094 #endif
00095 
00096 
00097 /* SMS 7 bit character mapping to UCS-2 */
00098 static const unsigned short defaultalphabet[] = {
00099    0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
00100    0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
00101    0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
00102    0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
00103    ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
00104    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
00105    161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
00106    'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
00107    191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
00108    'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
00109 };
00110 
00111 static const unsigned short escapes[] = {
00112    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
00113    0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00114    0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
00115    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
00116    0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00117    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00118    0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00119    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00120 };
00121 
00122 #define SMSLEN 160              /* max SMS length */
00123 
00124 typedef struct sms_s
00125 {
00126    unsigned char hangup;        /* we are done... */
00127    unsigned char err;           /* set for any errors */
00128    unsigned char smsc:1;        /* we are SMSC */
00129    unsigned char rx:1;          /* this is a received message */
00130    char queue[30];              /* queue name */
00131    char oa[20];                 /* originating address */
00132    char da[20];                 /* destination address */
00133    time_t scts;                 /* time stamp, UTC */
00134    unsigned char pid;           /* protocol ID */
00135    unsigned char dcs;           /* data coding scheme */
00136    short mr;                    /* message reference - actually a byte, but usde -1 for not set */
00137    int udl;                     /* user data length */
00138    int udhl;                    /* user data header length */
00139    unsigned char srr:1;         /* Status Report request */
00140    unsigned char udhi:1;        /* User Data Header required, even if length 0 */
00141    unsigned char rp:1;          /* Reply Path */
00142    unsigned int vp;             /* validity period in minutes, 0 for not set */
00143    unsigned short ud[SMSLEN];   /* user data (message), UCS-2 coded */
00144    unsigned char udh[SMSLEN];   /* user data header */
00145    char cli[20];                /* caller ID */
00146    unsigned char ophase;        /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
00147    unsigned char ophasep;       /* phase (0-79) for 1200 bps */
00148    unsigned char obyte;         /* byte being sent */
00149    unsigned int opause;         /* silent pause before sending (in sample periods) */
00150    unsigned char obitp;         /* bit in byte */
00151    unsigned char osync;         /* sync bits to send */
00152    unsigned char obytep;        /* byte in data */
00153    unsigned char obyten;        /* bytes in data */
00154    unsigned char omsg[256];     /* data buffer (out) */
00155    unsigned char imsg[200];     /* data buffer (in) */
00156    signed long long ims0,
00157       imc0,
00158       ims1,
00159       imc1;                      /* magnitude averages sin/cos 0/1 */
00160    unsigned int idle;
00161    unsigned short imag;         /* signal level */
00162    unsigned char ips0,
00163       ips1,
00164       ipc0,
00165       ipc1;                      /* phase sin/cos 0/1 */
00166    unsigned char ibitl;         /* last bit */
00167    unsigned char ibitc;         /* bit run length count */
00168    unsigned char iphasep;       /* bit phase (0-79) for 1200 bps */
00169    unsigned char ibitn;         /* bit number in byte being received */
00170    unsigned char ibytev;        /* byte value being received */
00171    unsigned char ibytep;        /* byte pointer in messafe */
00172    unsigned char ibytec;        /* byte checksum for message */
00173    unsigned char ierr;          /* error flag */
00174    unsigned char ibith;         /* history of last bits */
00175    unsigned char ibitt;         /* total of 1's in last 3 bites */
00176    /* more to go here */
00177 } sms_t;
00178 
00179 /* different types of encoding */
00180 #define is7bit(dcs) (((dcs)&0xC0)?(!((dcs)&4)):(!((dcs)&12)))
00181 #define is8bit(dcs) (((dcs)&0xC0)?(((dcs)&4)):(((dcs)&12)==4))
00182 #define is16bit(dcs) (((dcs)&0xC0)?0:(((dcs)&12)==8))
00183 
00184 static void *sms_alloc (struct ast_channel *chan, void *params)
00185 {
00186    return params;
00187 }
00188 
00189 static void sms_release (struct ast_channel *chan, void *data)
00190 {
00191    return;
00192 }
00193 
00194 static void sms_messagetx (sms_t * h);
00195 
00196 /*! \brief copy number, skipping non digits apart from leading + */
00197 static void numcpy (char *d, char *s)
00198 {
00199    if (*s == '+')
00200       *d++ = *s++;
00201    while (*s) {
00202       if (isdigit (*s))
00203             *d++ = *s;
00204       s++;
00205    }
00206    *d = 0;
00207 }
00208 
00209 /*! \brief static, return a date/time in ISO format */
00210 static char * isodate (time_t t)
00211 {
00212    static char date[20];
00213    strftime (date, sizeof (date), "%Y-%m-%dT%H:%M:%S", localtime (&t));
00214    return date;
00215 }
00216 
00217 /*! \brief reads next UCS character from null terminated UTF-8 string and advanced pointer */
00218 /* for non valid UTF-8 sequences, returns character as is */
00219 /* Does not advance pointer for null termination */
00220 static long utf8decode (unsigned char **pp)
00221 {
00222    unsigned char *p = *pp;
00223    if (!*p)
00224       return 0;                 /* null termination of string */
00225    (*pp)++;
00226    if (*p < 0xC0)
00227       return *p;                /* ascii or continuation character */
00228    if (*p < 0xE0) {
00229       if (*p < 0xC2 || (p[1] & 0xC0) != 0x80)
00230          return *p;             /* not valid UTF-8 */
00231       (*pp)++;
00232       return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
00233       }
00234    if (*p < 0xF0) {
00235       if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80)
00236           return *p;             /* not valid UTF-8 */
00237       (*pp) += 2;
00238       return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
00239    }
00240    if (*p < 0xF8) {
00241       if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80)
00242          return *p;             /* not valid UTF-8 */
00243       (*pp) += 3;
00244       return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
00245    }
00246    if (*p < 0xFC) {
00247       if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
00248          || (p[4] & 0xC0) != 0x80)
00249          return *p;             /* not valid UTF-8 */
00250       (*pp) += 4;
00251       return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
00252    }
00253    if (*p < 0xFE) {
00254       if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
00255          || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80)
00256          return *p;             /* not valid UTF-8 */
00257       (*pp) += 5;
00258       return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F);
00259    }
00260    return *p;                   /* not sensible */
00261 }
00262 
00263 /*! \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 */
00264 /* The return value is the number of septets packed in to o, which is internally limited to SMSLEN */
00265 /* o can be null, in which case this is used to validate or count only */
00266 /* if the input contains invalid characters then the return value is -1 */
00267 static int packsms7 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
00268 {
00269     unsigned char p = 0, b = 0, n = 0;
00270 
00271    if (udhl) {                            /* header */
00272       if (o)
00273          o[p++] = udhl;
00274       b = 1;
00275       n = 1;
00276       while (udhl--) {
00277          if (o)
00278             o[p++] = *udh++;
00279          b += 8;
00280          while (b >= 7) {
00281             b -= 7;
00282             n++;
00283          }
00284          if (n >= SMSLEN)
00285             return n;
00286       }
00287       if (b) {
00288          b = 7 - b;
00289          if (++n >= SMSLEN)
00290             return n;
00291          }; /* filling to septet boundary */
00292       }
00293       if (o)
00294          o[p] = 0;
00295       /* message */
00296       while (udl--) {
00297          long u;
00298          unsigned char v;
00299          u = *ud++;
00300          for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
00301          if (v == 128 && u && n + 1 < SMSLEN) {
00302             for (v = 0; v < 128 && escapes[v] != u; v++);
00303             if (v < 128) { /* escaped sequence */
00304             if (o)
00305                o[p] |= (27 << b);
00306             b += 7;
00307             if (b >= 8) {
00308                b -= 8;
00309                p++;
00310                if (o)
00311                   o[p] = (27 >> (7 - b));
00312             }
00313             n++;
00314          }
00315       }
00316       if (v == 128)
00317          return -1;             /* invalid character */
00318       if (o)
00319          o[p] |= (v << b);
00320       b += 7;
00321       if (b >= 8) {
00322          b -= 8;
00323          p++;
00324          if (o)
00325             o[p] = (v >> (7 - b));
00326       }
00327       if (++n >= SMSLEN)
00328          return n;
00329    }
00330    return n;
00331 }
00332 
00333 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 8 bit character codes */
00334 /* The return value is the number of bytes packed in to o, which is internally limited to 140 */
00335 /* o can be null, in which case this is used to validate or count only */
00336 /* if the input contains invalid characters then the return value is -1 */
00337 static int packsms8 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
00338 {
00339    unsigned char p = 0;
00340 
00341    /* header - no encoding */
00342    if (udhl) {
00343       if (o)
00344          o[p++] = udhl;
00345       while (udhl--) {
00346          if (o)
00347             o[p++] = *udh++;
00348          if (p >= 140)
00349             return p;
00350       }
00351    }
00352    while (udl--) {
00353       long u;
00354       u = *ud++;
00355       if (u < 0 || u > 0xFF)
00356          return -1;             /* not valid */
00357       if (o)
00358          o[p++] = u;
00359       if (p >= 140)
00360          return p;
00361    }
00362    return p;
00363 }
00364 
00365 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 
00366    message (udl characters at ud) and packs in to o using 16 bit 
00367    UCS-2 character codes 
00368    The return value is the number of bytes packed in to o, which is 
00369    internally limited to 140 
00370    o can be null, in which case this is used to validate or count 
00371    only if the input contains invalid characters then 
00372    the return value is -1 */
00373 static int packsms16 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
00374 {
00375    unsigned char p = 0;
00376    /* header - no encoding */
00377    if (udhl) {
00378       if (o)
00379          o[p++] = udhl;
00380       while (udhl--) {
00381          if (o)
00382             o[p++] = *udh++;
00383          if (p >= 140)
00384             return p;
00385       }
00386    }
00387    while (udl--) {
00388       long u;
00389       u = *ud++;
00390       if (o)
00391          o[p++] = (u >> 8);
00392       if (p >= 140)
00393          return p - 1;          /* could not fit last character */
00394       if (o)
00395          o[p++] = u;
00396       if (p >= 140)
00397          return p;
00398    }
00399    return p;
00400 }
00401 
00402 /*! \brief general pack, with length and data, 
00403    returns number of bytes of target used */
00404 static int packsms (unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
00405 {
00406    unsigned char *p = base;
00407    if (udl) {
00408       int l = 0;
00409       if (is7bit (dcs)) {      /* 7 bit */
00410          l = packsms7 (p + 1, udhl, udh, udl, ud);
00411          if (l < 0)
00412             l = 0;
00413          *p++ = l;
00414          p += (l * 7 + 7) / 8;
00415       } else if (is8bit (dcs)) {                       /* 8 bit */
00416          l = packsms8 (p + 1, udhl, udh, udl, ud);
00417          if (l < 0)
00418             l = 0;
00419          *p++ = l;
00420          p += l;
00421       } else {        /* UCS-2 */
00422          l = packsms16 (p + 1, udhl, udh, udl, ud);
00423          if (l < 0)
00424             l = 0;
00425          *p++ = l;
00426          p += l;
00427       }
00428    } else
00429       *p++ = 0;           /* no user data */
00430    return p - base;
00431 }
00432 
00433 
00434 /*! \brief pack a date and return */
00435 static void packdate (unsigned char *o, time_t w)
00436 {
00437    struct tm *t = localtime (&w);
00438 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
00439    int z = -t->tm_gmtoff / 60 / 15;
00440 #else
00441    int z = timezone / 60 / 15;
00442 #endif
00443    *o++ = ((t->tm_year % 10) << 4) + (t->tm_year % 100) / 10;
00444    *o++ = (((t->tm_mon + 1) % 10) << 4) + (t->tm_mon + 1) / 10;
00445    *o++ = ((t->tm_mday % 10) << 4) + t->tm_mday / 10;
00446    *o++ = ((t->tm_hour % 10) << 4) + t->tm_hour / 10;
00447    *o++ = ((t->tm_min % 10) << 4) + t->tm_min / 10;
00448    *o++ = ((t->tm_sec % 10) << 4) + t->tm_sec / 10;
00449    if (z < 0)
00450       *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
00451    else
00452       *o++ = ((z % 10) << 4) + z / 10;
00453 }
00454 
00455 /*! \brief unpack a date and return */
00456 static time_t unpackdate (unsigned char *i)
00457 {
00458    struct tm t;
00459    t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
00460    t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
00461    t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
00462    t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
00463    t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
00464    t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
00465    t.tm_isdst = 0;
00466    if (i[6] & 0x08)
00467       t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
00468    else
00469       t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
00470    return ast_mktime(&t, NULL);
00471 }
00472 
00473 /*! \brief unpacks bytes (7 bit encoding) at i, len l septets, 
00474    and places in udh and ud setting udhl and udl. udh not used 
00475    if udhi not set */
00476 static void unpacksms7 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
00477 {
00478    unsigned char b = 0, p = 0;
00479    unsigned short *o = ud;
00480    *udhl = 0;
00481    if (udhi && l) {      /* header */
00482       int h = i[p];
00483       *udhl = h;
00484       if (h) {
00485          b = 1;
00486          p++;
00487          l--;
00488          while (h-- && l) {
00489             *udh++ = i[p++];
00490             b += 8;
00491             while (b >= 7) {
00492                b -= 7;
00493                l--;
00494                if (!l)
00495                   break;
00496             }
00497          }
00498          /* adjust for fill, septets */
00499          if (b) {
00500             b = 7 - b;
00501             l--;
00502          }
00503       }
00504    }
00505    while (l--) {
00506       unsigned char v;
00507       if (b < 2)
00508          v = ((i[p] >> b) & 0x7F);
00509       else
00510          v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
00511       b += 7;
00512       if (b >= 8) {
00513          b -= 8;
00514          p++;
00515       }
00516       if (o > ud && o[-1] == 0x00A0 && escapes[v])
00517          o[-1] = escapes[v];
00518       else
00519          *o++ = defaultalphabet[v];
00520    }
00521    *udl = (o - ud);
00522 }
00523 
00524 /*! \brief unpacks bytes (8 bit encoding) at i, len l septets, 
00525       and places in udh and ud setting udhl and udl. udh not used 
00526       if udhi not set */
00527 static void unpacksms8 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
00528 {
00529    unsigned short *o = ud;
00530    *udhl = 0;
00531    if (udhi) {
00532       int n = *i;
00533       *udhl = n;
00534       if (n) {
00535          i++;
00536          l--;
00537          while (l && n) {
00538             l--;
00539             n--;
00540             *udh++ = *i++;
00541          }
00542       }
00543    }
00544    while (l--)
00545       *o++ = *i++;     /* not to UTF-8 as explicitely 8 bit coding in DCS */
00546    *udl = (o - ud);
00547 }
00548 
00549 /*! \brief unpacks bytes (16 bit encoding) at i, len l septets,
00550     and places in udh and ud setting udhl and udl. 
00551    udh not used if udhi not set */
00552 static void unpacksms16 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
00553 {
00554    unsigned short *o = ud;
00555    *udhl = 0;
00556    if (udhi) {
00557       int n = *i;
00558       *udhl = n;
00559       if (n) {
00560          i++;
00561          l--;
00562          while (l && n) {
00563             l--;
00564             n--;
00565             *udh++ = *i++;
00566          }
00567       }
00568    }
00569    while (l--) {
00570       int v = *i++;
00571       if (l--)
00572          v = (v << 8) + *i++;
00573       *o++ = v;
00574    }
00575    *udl = (o - ud);
00576 }
00577 
00578 /*! \brief general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
00579 static int unpacksms (unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
00580 {
00581    int l = *i++;
00582    if (is7bit (dcs)) {
00583       unpacksms7 (i, l, udh, udhl, ud, udl, udhi);
00584       l = (l * 7 + 7) / 8;    /* adjust length to return */
00585    } else if (is8bit (dcs))
00586       unpacksms8 (i, l, udh, udhl, ud, udl, udhi);
00587    else
00588       unpacksms16 (i, l, udh, udhl, ud, udl, udhi);
00589    return l + 1;
00590 }
00591 
00592 /*! \brief unpack an address from i, return byte length, unpack to o */
00593 static unsigned char unpackaddress (char *o, unsigned char *i)
00594 {
00595    unsigned char l = i[0],
00596       p;
00597    if (i[1] == 0x91)
00598       *o++ = '+';
00599    for (p = 0; p < l; p++) {
00600       if (p & 1)
00601          *o++ = (i[2 + p / 2] >> 4) + '0';
00602       else
00603          *o++ = (i[2 + p / 2] & 0xF) + '0';
00604    }
00605    *o = 0;
00606    return (l + 5) / 2;
00607 }
00608 
00609 /*! \brief store an address at o, and return number of bytes used */
00610 static unsigned char packaddress (unsigned char *o, char *i)
00611 {
00612    unsigned char p = 2;
00613    o[0] = 0;
00614    if (*i == '+') {
00615       i++;
00616       o[1] = 0x91;
00617    } else
00618       o[1] = 0x81;
00619    while (*i)
00620       if (isdigit (*i)) {
00621          if (o[0] & 1)
00622             o[p++] |= ((*i & 0xF) << 4);
00623          else
00624             o[p] = (*i & 0xF);
00625          o[0]++;
00626          i++;
00627       } else
00628          i++;
00629    if (o[0] & 1)
00630       o[p++] |= 0xF0;           /* pad */
00631    return p;
00632 }
00633 
00634 /*! \brief Log the output, and remove file */
00635 static void sms_log (sms_t * h, char status)
00636 {
00637    if (*h->oa || *h->da) {
00638       int o = open (log_file, O_CREAT | O_APPEND | O_WRONLY, 0666);
00639       if (o >= 0) {
00640          char line[1000], mrs[3] = "", *p;
00641          unsigned char n;
00642 
00643          if (h->mr >= 0)
00644             snprintf (mrs, sizeof (mrs), "%02X", h->mr);
00645          snprintf (line, sizeof (line), "%s %c%c%c%s %s %s %s ",
00646              isodate (time (0)), status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue, *h->oa ? h->oa : "-",
00647              *h->da ? h->da : "-");
00648          p = line + strlen (line);
00649          for (n = 0; n < h->udl; n++)
00650             if (h->ud[n] == '\\') {
00651                *p++ = '\\';
00652                *p++ = '\\';
00653             } else if (h->ud[n] == '\n') {
00654                *p++ = '\\';
00655                *p++ = 'n';
00656             } else if (h->ud[n] == '\r') {
00657                *p++ = '\\';
00658                *p++ = 'r';
00659             } else if (h->ud[n] < 32 || h->ud[n] == 127)
00660                *p++ = 191;
00661             else
00662                *p++ = h->ud[n];
00663          *p++ = '\n';
00664          *p = 0;
00665          if (write (o, line, strlen (line)) < 0) {
00666             ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00667          }
00668          close (o);
00669       }
00670       *h->oa = *h->da = h->udl = 0;
00671    }
00672 }
00673 
00674 /*! \brief parse and delete a file */
00675 static void sms_readfile (sms_t * h, char *fn)
00676 {
00677    char line[1000];
00678    FILE *s;
00679    char dcsset = 0;            /* if DSC set */
00680    ast_log (LOG_EVENT, "Sending %s\n", fn);
00681    h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
00682    h->mr = -1;
00683    h->dcs = 0xF1;             /* normal messages class 1 */
00684    h->scts = time (0);
00685    s = fopen (fn, "r");
00686    if (s)
00687    {
00688       if (unlink (fn))
00689       {                        /* concurrent access, we lost */
00690          fclose (s);
00691          return;
00692       }
00693       while (fgets (line, sizeof (line), s))
00694       {                        /* process line in file */
00695          char *p;
00696          void *pp = &p;
00697          for (p = line; *p && *p != '\n' && *p != '\r'; p++);
00698          *p = 0;               /* strip eoln */
00699          p = line;
00700          if (!*p || *p == ';')
00701             continue;           /* blank line or comment, ignore */
00702          while (isalnum (*p))
00703          {
00704             *p = tolower (*p);
00705             p++;
00706          }
00707          while (isspace (*p))
00708             *p++ = 0;
00709          if (*p == '=')
00710          {
00711             *p++ = 0;
00712             if (!strcmp (line, "ud"))
00713             {                  /* parse message (UTF-8) */
00714                unsigned char o = 0;
00715                while (*p && o < SMSLEN)
00716                   h->ud[o++] = utf8decode(pp);
00717                h->udl = o;
00718                if (*p)
00719                   ast_log (LOG_WARNING, "UD too long in %s\n", fn);
00720             } else
00721             {
00722                while (isspace (*p))
00723                   p++;
00724                if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
00725                   numcpy (h->oa, p);
00726                else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
00727                   numcpy (h->da, p);
00728                else if (!strcmp (line, "pid"))
00729                   h->pid = atoi (p);
00730                else if (!strcmp (line, "dcs"))
00731                {
00732                   h->dcs = atoi (p);
00733                   dcsset = 1;
00734                } else if (!strcmp (line, "mr"))
00735                   h->mr = atoi (p);
00736                else if (!strcmp (line, "srr"))
00737                   h->srr = (atoi (p) ? 1 : 0);
00738                else if (!strcmp (line, "vp"))
00739                   h->vp = atoi (p);
00740                else if (!strcmp (line, "rp"))
00741                   h->rp = (atoi (p) ? 1 : 0);
00742                else if (!strcmp (line, "scts"))
00743                {               /* get date/time */
00744                   int Y,
00745                     m,
00746                     d,
00747                     H,
00748                     M,
00749                     S;
00750                   if (sscanf (p, "%30d-%30d-%30dT%30d:%30d:%30d", &Y, &m, &d, &H, &M, &S) == 6)
00751                   {
00752                      struct tm t;
00753                      t.tm_year = Y - 1900;
00754                      t.tm_mon = m - 1;
00755                      t.tm_mday = d;
00756                      t.tm_hour = H;
00757                      t.tm_min = M;
00758                      t.tm_sec = S;
00759                      t.tm_isdst = -1;
00760                      h->scts = ast_mktime(&t, NULL);
00761                      if (h->scts == (time_t) - 1)
00762                         ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
00763                   }
00764                } else
00765                   ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
00766             }
00767          } else if (*p == '#')
00768          {                     /* raw hex format */
00769             *p++ = 0;
00770             if (*p == '#')
00771             {
00772                p++;
00773                if (!strcmp (line, "ud"))
00774                {               /* user data */
00775                   int o = 0;
00776                   while (*p && o < SMSLEN)
00777                   {
00778                      if (isxdigit (*p) && isxdigit (p[1]) && isxdigit (p[2]) && isxdigit (p[3]))
00779                      {
00780                         h->ud[o++] =
00781                            (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 12) +
00782                            (((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
00783                            (((isalpha (p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha (p[3]) ? 9 : 0) + (p[3] & 0xF));
00784                         p += 4;
00785                      } else
00786                         break;
00787                   }
00788                   h->udl = o;
00789                   if (*p)
00790                      ast_log (LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
00791                } else
00792                   ast_log (LOG_WARNING, "Only ud can use ## format, %s\n", fn);
00793             } else if (!strcmp (line, "ud"))
00794             {                  /* user data */
00795                int o = 0;
00796                while (*p && o < SMSLEN)
00797                {
00798                   if (isxdigit (*p) && isxdigit (p[1]))
00799                   {
00800                      h->ud[o++] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
00801                      p += 2;
00802                   } else
00803                      break;
00804                }
00805                h->udl = o;
00806                if (*p)
00807                   ast_log (LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
00808             } else if (!strcmp (line, "udh"))
00809             {                  /* user data header */
00810                unsigned char o = 0;
00811                h->udhi = 1;
00812                while (*p && o < SMSLEN)
00813                {
00814                   if (isxdigit (*p) && isxdigit (p[1]))
00815                   {
00816                      h->udh[o] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
00817                      o++;
00818                      p += 2;
00819                   } else
00820                      break;
00821                }
00822                h->udhl = o;
00823                if (*p)
00824                   ast_log (LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
00825             } else
00826                ast_log (LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
00827          } else
00828             ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
00829       }
00830       fclose (s);
00831       if (!dcsset && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00832       {
00833          if (packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00834          {
00835             if (packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00836                ast_log (LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
00837             else
00838             {
00839                h->dcs = 0x08; /* default to 16 bit */
00840                ast_log (LOG_WARNING, "Sending in 16 bit format (%s)\n", fn);
00841             }
00842          } else
00843          {
00844             h->dcs = 0xF5;    /* default to 8 bit */
00845             ast_log (LOG_WARNING, "Sending in 8 bit format (%s)\n", fn);
00846          }
00847       }
00848       if (is7bit (h->dcs) && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00849          ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
00850       if (is8bit (h->dcs) && packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00851          ast_log (LOG_WARNING, "Invalid 8 bit data %s\n", fn);
00852       if (is16bit (h->dcs) && packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00853          ast_log (LOG_WARNING, "Invalid 16 bit data %s\n", fn);
00854    }
00855 }
00856 
00857 /*! \brief white a received text message to a file */
00858 static void sms_writefile (sms_t * h)
00859 {
00860    char fn[200] = "", fn2[200] = "";
00861    FILE *o;
00862    ast_copy_string (fn, spool_dir, sizeof (fn));
00863    mkdir (fn, 0777);       /* ensure it exists */
00864    snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
00865    mkdir (fn, 0777);       /* ensure it exists */
00866    ast_copy_string (fn2, fn, sizeof (fn2));
00867    snprintf (fn2 + strlen (fn2), sizeof (fn2) - strlen (fn2), "/%s.%s-%d", h->queue, isodate (h->scts), seq++);
00868    snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/.%s", fn2 + strlen (fn) + 1);
00869    o = fopen (fn, "w");
00870    if (o) {
00871       if (*h->oa)
00872          fprintf (o, "oa=%s\n", h->oa);
00873       if (*h->da)
00874          fprintf (o, "da=%s\n", h->da);
00875       if (h->udhi) {
00876          unsigned int p;
00877          fprintf (o, "udh#");
00878          for (p = 0; p < h->udhl; p++)
00879             fprintf (o, "%02X", h->udh[p]);
00880          fprintf (o, "\n");
00881       }
00882       if (h->udl) {
00883          unsigned int p;
00884          for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
00885          if (p < h->udl)
00886             fputc (';', o);     /* cannot use ud=, but include as a comment for human readable */
00887          fprintf (o, "ud=");
00888          for (p = 0; p < h->udl; p++) {
00889             unsigned short v = h->ud[p];
00890             if (v < 32)
00891                fputc (191, o);
00892             else if (v < 0x80)
00893                fputc (v, o);
00894             else if (v < 0x800)
00895             {
00896                fputc (0xC0 + (v >> 6), o);
00897                fputc (0x80 + (v & 0x3F), o);
00898             } else
00899             {
00900                fputc (0xE0 + (v >> 12), o);
00901                fputc (0x80 + ((v >> 6) & 0x3F), o);
00902                fputc (0x80 + (v & 0x3F), o);
00903             }
00904          }
00905          fprintf (o, "\n");
00906          for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
00907          if (p < h->udl) {
00908             for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
00909             if (p == h->udl) {                   /* can write in ucs-1 hex */
00910                fprintf (o, "ud#");
00911                for (p = 0; p < h->udl; p++)
00912                   fprintf (o, "%02X", h->ud[p]);
00913                fprintf (o, "\n");
00914             } else {                 /* write in UCS-2 */
00915                fprintf (o, "ud##");
00916                for (p = 0; p < h->udl; p++)
00917                   fprintf (o, "%04X", h->ud[p]);
00918                fprintf (o, "\n");
00919             }
00920          }
00921       }
00922       if (h->scts)
00923          fprintf (o, "scts=%s\n", isodate (h->scts));
00924       if (h->pid)
00925          fprintf (o, "pid=%d\n", h->pid);
00926       if (h->dcs != 0xF1)
00927          fprintf (o, "dcs=%d\n", h->dcs);
00928       if (h->vp)
00929          fprintf (o, "vp=%d\n", h->vp);
00930       if (h->srr)
00931          fprintf (o, "srr=1\n");
00932       if (h->mr >= 0)
00933          fprintf (o, "mr=%d\n", h->mr);
00934       if (h->rp)
00935          fprintf (o, "rp=1\n");
00936       fclose (o);
00937       if (rename (fn, fn2))
00938          unlink (fn);
00939       else
00940          ast_log (LOG_EVENT, "Received to %s\n", fn2);
00941    }
00942 }
00943 
00944 /*! \brief read dir skipping dot files... */
00945 static struct dirent *readdirqueue (DIR * d, char *queue)
00946 {
00947    struct dirent *f;
00948    do {
00949       f = readdir (d);
00950    } while (f && (*f->d_name == '.' || strncmp (f->d_name, queue, strlen (queue)) || f->d_name[strlen (queue)] != '.'));
00951    return f;
00952 }
00953 
00954 /*! \brief handle the incoming message */
00955 static unsigned char sms_handleincoming (sms_t * h)
00956 {
00957    unsigned char p = 3;
00958    if (h->smsc) {                          /* SMSC */
00959       if ((h->imsg[2] & 3) == 1) {           /* SMS-SUBMIT */
00960          h->udhl = h->udl = 0;
00961          h->vp = 0;
00962          h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
00963          h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
00964          h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
00965          ast_copy_string (h->oa, h->cli, sizeof (h->oa));
00966          h->scts = time (0);
00967          h->mr = h->imsg[p++];
00968          p += unpackaddress (h->da, h->imsg + p);
00969          h->pid = h->imsg[p++];
00970          h->dcs = h->imsg[p++];
00971          if ((h->imsg[2] & 0x18) == 0x10) {                     /* relative VP */
00972             if (h->imsg[p] < 144)
00973                h->vp = (h->imsg[p] + 1) * 5;
00974             else if (h->imsg[p] < 168)
00975                h->vp = 720 + (h->imsg[p] - 143) * 30;
00976             else if (h->imsg[p] < 197)
00977                h->vp = (h->imsg[p] - 166) * 1440;
00978             else
00979                h->vp = (h->imsg[p] - 192) * 10080;
00980             p++;
00981          } else if (h->imsg[2] & 0x18)
00982             p += 7;            /* ignore enhanced / absolute VP */
00983          p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
00984          h->rx = 1;            /* received message */
00985          sms_writefile (h);     /* write the file */
00986          if (p != h->imsg[1] + 2) {
00987             ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
00988             return 0xFF;        /* duh! */
00989          }
00990       } else {
00991          ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
00992          return 0xFF;
00993       }
00994    } else {                          /* client */
00995       if (!(h->imsg[2] & 3)) {                         /* SMS-DELIVER */
00996          *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
00997          h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
00998          h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
00999          h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
01000          h->mr = -1;
01001          p += unpackaddress (h->oa, h->imsg + p);
01002          h->pid = h->imsg[p++];
01003          h->dcs = h->imsg[p++];
01004          h->scts = unpackdate (h->imsg + p);
01005          p += 7;
01006          p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
01007          h->rx = 1;            /* received message */
01008          sms_writefile (h);     /* write the file */
01009          if (p != h->imsg[1] + 2) {
01010             ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
01011             return 0xFF;        /* duh! */
01012          }
01013       } else {
01014          ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
01015          return 0xFF;
01016       }
01017    }
01018    return 0;                    /* no error */
01019 }
01020 
01021 #ifdef SOLARIS
01022 #define NAME_MAX 1024
01023 #endif
01024 
01025 /*! \brief find and fill in next message, or send a REL if none waiting */
01026 static void sms_nextoutgoing (sms_t * h)
01027 {          
01028    char fn[100 + NAME_MAX] = "";
01029    DIR *d;
01030    char more = 0;
01031    ast_copy_string (fn, spool_dir, sizeof (fn));
01032    mkdir (fn, 0777);          /* ensure it exists */
01033    h->rx = 0;                  /* outgoing message */
01034    snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? "mttx" : "motx");
01035    mkdir (fn, 0777);          /* ensure it exists */
01036    d = opendir (fn);
01037    if (d) {
01038       struct dirent *f = readdirqueue (d, h->queue);
01039       if (f) {
01040          snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", f->d_name);
01041          sms_readfile (h, fn);
01042          if (readdirqueue (d, h->queue))
01043             more = 1;           /* more to send */
01044       }
01045       closedir (d);
01046    }
01047    if (*h->da || *h->oa) {                          /* message to send */
01048       unsigned char p = 2;
01049       h->omsg[0] = 0x91;        /* SMS_DATA */
01050       if (h->smsc) {        /* deliver */
01051          h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
01052          p += packaddress (h->omsg + p, h->oa);
01053          h->omsg[p++] = h->pid;
01054          h->omsg[p++] = h->dcs;
01055          packdate (h->omsg + p, h->scts);
01056          p += 7;
01057          p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01058       } else {        /* submit */
01059          h->omsg[p++] =
01060             0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
01061          if (h->mr < 0)
01062             h->mr = message_ref++;
01063          h->omsg[p++] = h->mr;
01064          p += packaddress (h->omsg + p, h->da);
01065          h->omsg[p++] = h->pid;
01066          h->omsg[p++] = h->dcs;
01067          if (h->vp) {       /* relative VP */
01068             if (h->vp < 720)
01069                h->omsg[p++] = (h->vp + 4) / 5 - 1;
01070             else if (h->vp < 1440)
01071                h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
01072             else if (h->vp < 43200)
01073                h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
01074             else if (h->vp < 635040)
01075                h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
01076             else
01077                h->omsg[p++] = 255;     /* max */
01078          }
01079          p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01080       }
01081       h->omsg[1] = p - 2;
01082       sms_messagetx (h);
01083    } else {           /* no message */
01084       h->omsg[0] = 0x94;        /* SMS_REL */
01085       h->omsg[1] = 0;
01086       sms_messagetx (h);
01087    }
01088 }
01089 
01090 static void sms_debug (char *dir, unsigned char *msg)
01091 {
01092    char txt[259 * 3 + 1],
01093     *p = txt;                  /* always long enough */
01094    int n = msg[1] + 3,
01095       q = 0;
01096    while (q < n && q < 30) {
01097       sprintf (p, " %02X", msg[q++]);
01098       p += 3;
01099    }
01100    if (q < n)
01101       sprintf (p, "...");
01102    if (option_verbose > 2)
01103       ast_verbose (VERBOSE_PREFIX_3 "SMS %s%s\n", dir, txt);
01104 }
01105 
01106 static void sms_messagerx(sms_t * h)
01107 {
01108    sms_debug ("RX", h->imsg);
01109    /* testing */
01110    switch (h->imsg[0]) {
01111    case 0x91:                 /* SMS_DATA */
01112       {
01113          unsigned char cause = sms_handleincoming (h);
01114          if (!cause) {
01115             sms_log (h, 'Y');
01116             h->omsg[0] = 0x95;  /* SMS_ACK */
01117             h->omsg[1] = 0x02;
01118             h->omsg[2] = 0x00;  /* deliver report */
01119             h->omsg[3] = 0x00;  /* no parameters */
01120          } else {                    /* NACK */
01121             sms_log (h, 'N');
01122             h->omsg[0] = 0x96;  /* SMS_NACK */
01123             h->omsg[1] = 3;
01124             h->omsg[2] = 0;     /* delivery report */
01125             h->omsg[3] = cause; /* cause */
01126             h->omsg[4] = 0;     /* no parameters */
01127          }
01128          sms_messagetx (h);
01129       }
01130       break;
01131    case 0x92:                 /* SMS_ERROR */
01132       h->err = 1;
01133       sms_messagetx (h);        /* send whatever we sent again */
01134       break;
01135    case 0x93:                 /* SMS_EST */
01136       sms_nextoutgoing (h);
01137       break;
01138    case 0x94:                 /* SMS_REL */
01139       h->hangup = 1;          /* hangup */
01140       break;
01141    case 0x95:                 /* SMS_ACK */
01142       sms_log (h, 'Y');
01143       sms_nextoutgoing (h);
01144       break;
01145    case 0x96:                 /* SMS_NACK */
01146       h->err = 1;
01147       sms_log (h, 'N');
01148       sms_nextoutgoing (h);
01149       break;
01150    default:                  /* Unknown */
01151       h->omsg[0] = 0x92;        /* SMS_ERROR */
01152       h->omsg[1] = 1;
01153       h->omsg[2] = 3;           /* unknown message type; */
01154       sms_messagetx (h);
01155       break;
01156    }
01157 }
01158 
01159 static void sms_messagetx(sms_t * h)
01160 {
01161    unsigned char c = 0, p;
01162    for (p = 0; p < h->omsg[1] + 2; p++)
01163       c += h->omsg[p];
01164    h->omsg[h->omsg[1] + 2] = 0 - c;
01165    sms_debug ("TX", h->omsg);
01166    h->obyte = 1;
01167    h->opause = 200;
01168    if (h->omsg[0] == 0x93)
01169       h->opause = 2400;       /* initial message delay 300ms (for BT) */
01170    h->obytep = 0;
01171    h->obitp = 0;
01172    h->osync = 80;
01173    h->obyten = h->omsg[1] + 3;
01174 }
01175 
01176 static int sms_generate (struct ast_channel *chan, void *data, int len, int samples)
01177 {
01178    struct ast_frame f = { 0 };
01179 #define MAXSAMPLES (800)
01180 #ifdef OUTALAW
01181    unsigned char *buf;
01182 #else
01183    short *buf;
01184 #endif
01185 #define SAMPLE2LEN sizeof(*buf)
01186    sms_t *h = data;
01187    int i;
01188 
01189    if (samples > MAXSAMPLES) {
01190       ast_log (LOG_WARNING, "Only doing %d samples (%d requested)\n",
01191           MAXSAMPLES, samples);
01192       samples = MAXSAMPLES;
01193    }
01194    len = samples * SAMPLE2LEN + AST_FRIENDLY_OFFSET;
01195    buf = alloca(len);
01196 
01197    f.frametype = AST_FRAME_VOICE;
01198 #ifdef OUTALAW
01199    f.subclass = AST_FORMAT_ALAW;
01200 #else
01201    f.subclass = AST_FORMAT_SLINEAR;
01202 #endif
01203    f.datalen = samples * SAMPLE2LEN;
01204    f.offset = AST_FRIENDLY_OFFSET;
01205    f.mallocd = 0;
01206    f.data = buf;
01207    f.samples = samples;
01208    f.src = "app_sms";
01209    /* create a buffer containing the digital sms pattern */
01210    for (i = 0; i < samples; i++) {
01211 #ifdef OUTALAW
01212       buf[i] = wavea[0];
01213 #else
01214       buf[i] = wave[0];
01215 #endif
01216       if (h->opause)
01217          h->opause--;
01218       else if (h->obyten || h->osync) {                         /* sending data */
01219 #ifdef OUTALAW
01220          buf[i] = wavea[h->ophase];
01221 #else
01222          buf[i] = wave[h->ophase];
01223 #endif
01224          if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
01225             h->ophase -= 80;
01226          if ((h->ophasep += 12) >= 80) {                     /* next bit */
01227             h->ophasep -= 80;
01228             if (h->osync)
01229                h->osync--;    /* sending sync bits */
01230             else {
01231                h->obyte >>= 1;
01232                h->obitp++;
01233                if (h->obitp == 1)
01234                   h->obyte = 0; /* start bit; */
01235                else if (h->obitp == 2)
01236                   h->obyte = h->omsg[h->obytep];
01237                else if (h->obitp == 10) {
01238                   h->obyte = 1; /* stop bit */
01239                   h->obitp = 0;
01240                   h->obytep++;
01241                   if (h->obytep == h->obyten) {
01242                      h->obytep = h->obyten = 0; /* sent */
01243                      h->osync = 10;   /* trailing marks */
01244                   }
01245                }
01246             }
01247          }
01248       }
01249    }
01250    if (ast_write (chan, &f) < 0) {
01251       ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
01252       return -1;
01253    }
01254    return 0;
01255 #undef SAMPLE2LEN
01256 #undef MAXSAMPLES
01257 }
01258 
01259 static void sms_process (sms_t * h, int samples, signed short *data)
01260 {
01261    if (h->obyten || h->osync)
01262       return;                  /* sending */
01263    while (samples--) {
01264       unsigned long long m0, m1;
01265       if (abs (*data) > h->imag)
01266          h->imag = abs (*data);
01267       else
01268          h->imag = h->imag * 7 / 8;
01269       if (h->imag > 500) {
01270          h->idle = 0;
01271          h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
01272          h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
01273          h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
01274          h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
01275          m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
01276          m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
01277          if ((h->ips0 += 21) >= 80)
01278             h->ips0 -= 80;
01279          if ((h->ipc0 += 21) >= 80)
01280             h->ipc0 -= 80;
01281          if ((h->ips1 += 13) >= 80)
01282             h->ips1 -= 80;
01283          if ((h->ipc1 += 13) >= 80)
01284             h->ipc1 -= 80;
01285          {
01286             char bit;
01287             h->ibith <<= 1;
01288             if (m1 > m0)
01289                h->ibith |= 1;
01290             if (h->ibith & 8)
01291                h->ibitt--;
01292             if (h->ibith & 1)
01293                h->ibitt++;
01294             bit = ((h->ibitt > 1) ? 1 : 0);
01295             if (bit != h->ibitl)
01296                h->ibitc = 1;
01297             else
01298                h->ibitc++;
01299             h->ibitl = bit;
01300             if (!h->ibitn && h->ibitc == 4 && !bit) {
01301                h->ibitn = 1;
01302                h->iphasep = 0;
01303             }
01304             if (bit && h->ibitc == 200) {                 /* sync, restart message */
01305                h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01306             }
01307             if (h->ibitn) {
01308                h->iphasep += 12;
01309                if (h->iphasep >= 80) {              /* next bit */
01310                   h->iphasep -= 80;
01311                   if (h->ibitn++ == 9) {            /* end of byte */
01312                      if (!bit)  /* bad stop bit */
01313                         h->ierr = 0xFF; /* unknown error */
01314                      else {
01315                         if (h->ibytep < sizeof (h->imsg)) {
01316                            h->imsg[h->ibytep] = h->ibytev;
01317                            h->ibytec += h->ibytev;
01318                            h->ibytep++;
01319                         } else if (h->ibytep == sizeof (h->imsg))
01320                            h->ierr = 2; /* bad message length */
01321                         if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
01322                            if (!h->ibytec)
01323                               sms_messagerx (h);
01324                            else
01325                               h->ierr = 1;      /* bad checksum */
01326                         }
01327                      }
01328                      h->ibitn = 0;
01329                   }
01330                   h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
01331                }
01332             }
01333          }
01334       } else {        /* lost carrier */
01335          if (h->idle++ == 80000) {      /* nothing happening */
01336             ast_log (LOG_EVENT, "No data, hanging up\n");
01337             h->hangup = 1;
01338             h->err = 1;
01339          }
01340          if (h->ierr) {                    /* error */
01341             h->err = 1;
01342             h->omsg[0] = 0x92;  /* error */
01343             h->omsg[1] = 1;
01344             h->omsg[2] = h->ierr;
01345             sms_messagetx (h);  /* send error */
01346          }
01347          h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01348       }
01349       data++;
01350    }
01351 }
01352 
01353 static struct ast_generator smsgen = {
01354    alloc:sms_alloc,
01355    release:sms_release,
01356    generate:sms_generate,
01357 };
01358 
01359 static int sms_exec (struct ast_channel *chan, void *data)
01360 {
01361    int res = -1;
01362    struct ast_module_user *u;
01363    struct ast_frame *f;
01364    sms_t h = { 0 };
01365    
01366    u = ast_module_user_add(chan);
01367 
01368    h.ipc0 = h.ipc1 = 20;        /* phase for cosine */
01369    h.dcs = 0xF1;               /* default */
01370    if (!data) {
01371       ast_log (LOG_ERROR, "Requires queue name at least\n");
01372       ast_module_user_remove(u);
01373       return -1;
01374    }
01375 
01376    if (chan->cid.cid_num)
01377       ast_copy_string (h.cli, chan->cid.cid_num, sizeof (h.cli));
01378 
01379    {
01380       unsigned char *p;
01381       unsigned char *d = data,
01382          answer = 0;
01383       if (!*d || *d == '|') {
01384          ast_log (LOG_ERROR, "Requires queue name\n");
01385          ast_module_user_remove(u);
01386          return -1;
01387       }
01388       for (p = d; *p && *p != '|'; p++);
01389       if (p - d >= sizeof (h.queue)) {
01390          ast_log (LOG_ERROR, "Queue name too long\n");
01391          ast_module_user_remove(u);
01392          return -1;
01393       }
01394       strncpy(h.queue, (char *)d, p - d);
01395       if (*p == '|')
01396          p++;
01397       d = p;
01398       for (p = (unsigned char *)h.queue; *p; p++)
01399          if (!isalnum (*p))
01400             *p = '-';           /* make very safe for filenames */
01401       while (*d && *d != '|') {
01402          switch (*d) {
01403          case 'a':             /* we have to send the initial FSK sequence */
01404             answer = 1;
01405             break;
01406          case 's':             /* we are acting as a service centre talking to a phone */
01407             h.smsc = 1;
01408             break;
01409             /* the following apply if there is an arg3/4 and apply to the created message file */
01410          case 'r':
01411             h.srr = 1;
01412             break;
01413          case 'o':
01414             h.dcs |= 4;       /* octets */
01415             break;
01416          case '1':
01417          case '2':
01418          case '3':
01419          case '4':
01420          case '5':
01421          case '6':
01422          case '7':             /* set the pid for saved local message */
01423             h.pid = 0x40 + (*d & 0xF);
01424             break;
01425          }
01426          d++;
01427       }
01428       if (*d == '|') {
01429          /* submitting a message, not taking call. */
01430          /* deprecated, use smsq instead */
01431          d++;
01432          h.scts = time (0);
01433          for (p = d; *p && *p != '|'; p++);
01434          if (*p)
01435             *p++ = 0;
01436          if (strlen ((char *)d) >= sizeof (h.oa)) {
01437             ast_log (LOG_ERROR, "Address too long %s\n", d);
01438             return 0;
01439          }
01440          if (h.smsc) {
01441             ast_copy_string (h.oa, (char *)d, sizeof (h.oa));
01442          } else {
01443             ast_copy_string (h.da, (char *)d, sizeof (h.da));
01444          }
01445          if (!h.smsc)
01446             ast_copy_string (h.oa, h.cli, sizeof (h.oa));
01447          d = p;
01448          h.udl = 0;
01449          while (*p && h.udl < SMSLEN)
01450             h.ud[h.udl++] = utf8decode(&p);
01451          if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
01452             ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n");
01453          if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
01454             ast_log (LOG_WARNING, "Invalid 8 bit data\n");
01455          if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
01456             ast_log (LOG_WARNING, "Invalid 16 bit data\n");
01457          h.rx = 0;              /* sent message */
01458          h.mr = -1;
01459          sms_writefile (&h);
01460          ast_module_user_remove(u);
01461          return 0;
01462       }
01463 
01464       if (answer) {
01465          /* set up SMS_EST initial message */
01466          h.omsg[0] = 0x93;
01467          h.omsg[1] = 0;
01468          sms_messagetx (&h);
01469       }
01470    }
01471 
01472    if (chan->_state != AST_STATE_UP)
01473       ast_answer (chan);
01474 
01475 #ifdef OUTALAW
01476    res = ast_set_write_format (chan, AST_FORMAT_ALAW);
01477 #else
01478    res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
01479 #endif
01480    if (res >= 0)
01481       res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
01482    if (res < 0) {
01483       ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
01484       ast_module_user_remove(u);
01485       return -1;
01486    }
01487 
01488    if (ast_activate_generator (chan, &smsgen, &h) < 0) {
01489       ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
01490       ast_module_user_remove(u);
01491       return -1;
01492    }
01493 
01494    /* Do our thing here */
01495    while (ast_waitfor (chan, -1) > -1 && !h.hangup)
01496    {
01497       f = ast_read (chan);
01498       if (!f)
01499          break;
01500       if (f->frametype == AST_FRAME_VOICE) {
01501          sms_process (&h, f->samples, f->data);
01502       }
01503 
01504       ast_frfree (f);
01505    }
01506 
01507    sms_log (&h, '?');           /* log incomplete message */
01508 
01509    /* 
01510     * The SMS generator data is on the stack.  We _MUST_ make sure the generator
01511     * is stopped before returning from this function.
01512     */
01513    ast_deactivate_generator(chan);
01514 
01515    ast_module_user_remove(u);
01516    return (h.err);
01517 }
01518 
01519 static int unload_module(void)
01520 {
01521    int res;
01522 
01523    res = ast_unregister_application (app);
01524    
01525    ast_module_user_hangup_all();
01526 
01527    return res; 
01528 }
01529 
01530 static int load_module(void)
01531 {
01532 #ifdef OUTALAW
01533    {
01534       int p;
01535       for (p = 0; p < 80; p++)
01536          wavea[p] = AST_LIN2A (wave[p]);
01537    }
01538 #endif
01539    snprintf (log_file, sizeof (log_file), "%s/sms", ast_config_AST_LOG_DIR);
01540    snprintf (spool_dir, sizeof (spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
01541    return ast_register_application (app, sms_exec, synopsis, descrip);
01542 }
01543 
01544 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SMS/PSTN handler");

Generated on Sat Aug 6 00:39:21 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7