Mon Jul 14 17:24:49 2008

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: 107461 $")
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          write (o, line, strlen (line));
00666          close (o);
00667       }
00668       *h->oa = *h->da = h->udl = 0;
00669    }
00670 }
00671 
00672 /*! \brief parse and delete a file */
00673 static void sms_readfile (sms_t * h, char *fn)
00674 {
00675    char line[1000];
00676    FILE *s;
00677    char dcsset = 0;            /* if DSC set */
00678    ast_log (LOG_EVENT, "Sending %s\n", fn);
00679    h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
00680    h->mr = -1;
00681    h->dcs = 0xF1;             /* normal messages class 1 */
00682    h->scts = time (0);
00683    s = fopen (fn, "r");
00684    if (s)
00685    {
00686       if (unlink (fn))
00687       {                        /* concurrent access, we lost */
00688          fclose (s);
00689          return;
00690       }
00691       while (fgets (line, sizeof (line), s))
00692       {                        /* process line in file */
00693          char *p;
00694          void *pp = &p;
00695          for (p = line; *p && *p != '\n' && *p != '\r'; p++);
00696          *p = 0;               /* strip eoln */
00697          p = line;
00698          if (!*p || *p == ';')
00699             continue;           /* blank line or comment, ignore */
00700          while (isalnum (*p))
00701          {
00702             *p = tolower (*p);
00703             p++;
00704          }
00705          while (isspace (*p))
00706             *p++ = 0;
00707          if (*p == '=')
00708          {
00709             *p++ = 0;
00710             if (!strcmp (line, "ud"))
00711             {                  /* parse message (UTF-8) */
00712                unsigned char o = 0;
00713                while (*p && o < SMSLEN)
00714                   h->ud[o++] = utf8decode(pp);
00715                h->udl = o;
00716                if (*p)
00717                   ast_log (LOG_WARNING, "UD too long in %s\n", fn);
00718             } else
00719             {
00720                while (isspace (*p))
00721                   p++;
00722                if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
00723                   numcpy (h->oa, p);
00724                else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
00725                   numcpy (h->da, p);
00726                else if (!strcmp (line, "pid"))
00727                   h->pid = atoi (p);
00728                else if (!strcmp (line, "dcs"))
00729                {
00730                   h->dcs = atoi (p);
00731                   dcsset = 1;
00732                } else if (!strcmp (line, "mr"))
00733                   h->mr = atoi (p);
00734                else if (!strcmp (line, "srr"))
00735                   h->srr = (atoi (p) ? 1 : 0);
00736                else if (!strcmp (line, "vp"))
00737                   h->vp = atoi (p);
00738                else if (!strcmp (line, "rp"))
00739                   h->rp = (atoi (p) ? 1 : 0);
00740                else if (!strcmp (line, "scts"))
00741                {               /* get date/time */
00742                   int Y,
00743                     m,
00744                     d,
00745                     H,
00746                     M,
00747                     S;
00748                   if (sscanf (p, "%d-%d-%dT%d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6)
00749                   {
00750                      struct tm t;
00751                      t.tm_year = Y - 1900;
00752                      t.tm_mon = m - 1;
00753                      t.tm_mday = d;
00754                      t.tm_hour = H;
00755                      t.tm_min = M;
00756                      t.tm_sec = S;
00757                      t.tm_isdst = -1;
00758                      h->scts = ast_mktime(&t, NULL);
00759                      if (h->scts == (time_t) - 1)
00760                         ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
00761                   }
00762                } else
00763                   ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
00764             }
00765          } else if (*p == '#')
00766          {                     /* raw hex format */
00767             *p++ = 0;
00768             if (*p == '#')
00769             {
00770                p++;
00771                if (!strcmp (line, "ud"))
00772                {               /* user data */
00773                   int o = 0;
00774                   while (*p && o < SMSLEN)
00775                   {
00776                      if (isxdigit (*p) && isxdigit (p[1]) && isxdigit (p[2]) && isxdigit (p[3]))
00777                      {
00778                         h->ud[o++] =
00779                            (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 12) +
00780                            (((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
00781                            (((isalpha (p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha (p[3]) ? 9 : 0) + (p[3] & 0xF));
00782                         p += 4;
00783                      } else
00784                         break;
00785                   }
00786                   h->udl = o;
00787                   if (*p)
00788                      ast_log (LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
00789                } else
00790                   ast_log (LOG_WARNING, "Only ud can use ## format, %s\n", fn);
00791             } else if (!strcmp (line, "ud"))
00792             {                  /* user data */
00793                int o = 0;
00794                while (*p && o < SMSLEN)
00795                {
00796                   if (isxdigit (*p) && isxdigit (p[1]))
00797                   {
00798                      h->ud[o++] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
00799                      p += 2;
00800                   } else
00801                      break;
00802                }
00803                h->udl = o;
00804                if (*p)
00805                   ast_log (LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
00806             } else if (!strcmp (line, "udh"))
00807             {                  /* user data header */
00808                unsigned char o = 0;
00809                h->udhi = 1;
00810                while (*p && o < SMSLEN)
00811                {
00812                   if (isxdigit (*p) && isxdigit (p[1]))
00813                   {
00814                      h->udh[o] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
00815                      o++;
00816                      p += 2;
00817                   } else
00818                      break;
00819                }
00820                h->udhl = o;
00821                if (*p)
00822                   ast_log (LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
00823             } else
00824                ast_log (LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
00825          } else
00826             ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
00827       }
00828       fclose (s);
00829       if (!dcsset && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00830       {
00831          if (packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00832          {
00833             if (packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00834                ast_log (LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
00835             else
00836             {
00837                h->dcs = 0x08; /* default to 16 bit */
00838                ast_log (LOG_WARNING, "Sending in 16 bit format (%s)\n", fn);
00839             }
00840          } else
00841          {
00842             h->dcs = 0xF5;    /* default to 8 bit */
00843             ast_log (LOG_WARNING, "Sending in 8 bit format (%s)\n", fn);
00844          }
00845       }
00846       if (is7bit (h->dcs) && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00847          ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
00848       if (is8bit (h->dcs) && packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00849          ast_log (LOG_WARNING, "Invalid 8 bit data %s\n", fn);
00850       if (is16bit (h->dcs) && packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00851          ast_log (LOG_WARNING, "Invalid 16 bit data %s\n", fn);
00852    }
00853 }
00854 
00855 /*! \brief white a received text message to a file */
00856 static void sms_writefile (sms_t * h)
00857 {
00858    char fn[200] = "", fn2[200] = "";
00859    FILE *o;
00860    ast_copy_string (fn, spool_dir, sizeof (fn));
00861    mkdir (fn, 0777);       /* ensure it exists */
00862    snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
00863    mkdir (fn, 0777);       /* ensure it exists */
00864    ast_copy_string (fn2, fn, sizeof (fn2));
00865    snprintf (fn2 + strlen (fn2), sizeof (fn2) - strlen (fn2), "/%s.%s-%d", h->queue, isodate (h->scts), seq++);
00866    snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/.%s", fn2 + strlen (fn) + 1);
00867    o = fopen (fn, "w");
00868    if (o) {
00869       if (*h->oa)
00870          fprintf (o, "oa=%s\n", h->oa);
00871       if (*h->da)
00872          fprintf (o, "da=%s\n", h->da);
00873       if (h->udhi) {
00874          unsigned int p;
00875          fprintf (o, "udh#");
00876          for (p = 0; p < h->udhl; p++)
00877             fprintf (o, "%02X", h->udh[p]);
00878          fprintf (o, "\n");
00879       }
00880       if (h->udl) {
00881          unsigned int p;
00882          for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
00883          if (p < h->udl)
00884             fputc (';', o);     /* cannot use ud=, but include as a comment for human readable */
00885          fprintf (o, "ud=");
00886          for (p = 0; p < h->udl; p++) {
00887             unsigned short v = h->ud[p];
00888             if (v < 32)
00889                fputc (191, o);
00890             else if (v < 0x80)
00891                fputc (v, o);
00892             else if (v < 0x800)
00893             {
00894                fputc (0xC0 + (v >> 6), o);
00895                fputc (0x80 + (v & 0x3F), o);
00896             } else
00897             {
00898                fputc (0xE0 + (v >> 12), o);
00899                fputc (0x80 + ((v >> 6) & 0x3F), o);
00900                fputc (0x80 + (v & 0x3F), o);
00901             }
00902          }
00903          fprintf (o, "\n");
00904          for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
00905          if (p < h->udl) {
00906             for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
00907             if (p == h->udl) {                   /* can write in ucs-1 hex */
00908                fprintf (o, "ud#");
00909                for (p = 0; p < h->udl; p++)
00910                   fprintf (o, "%02X", h->ud[p]);
00911                fprintf (o, "\n");
00912             } else {                 /* write in UCS-2 */
00913                fprintf (o, "ud##");
00914                for (p = 0; p < h->udl; p++)
00915                   fprintf (o, "%04X", h->ud[p]);
00916                fprintf (o, "\n");
00917             }
00918          }
00919       }
00920       if (h->scts)
00921          fprintf (o, "scts=%s\n", isodate (h->scts));
00922       if (h->pid)
00923          fprintf (o, "pid=%d\n", h->pid);
00924       if (h->dcs != 0xF1)
00925          fprintf (o, "dcs=%d\n", h->dcs);
00926       if (h->vp)
00927          fprintf (o, "vp=%d\n", h->vp);
00928       if (h->srr)
00929          fprintf (o, "srr=1\n");
00930       if (h->mr >= 0)
00931          fprintf (o, "mr=%d\n", h->mr);
00932       if (h->rp)
00933          fprintf (o, "rp=1\n");
00934       fclose (o);
00935       if (rename (fn, fn2))
00936          unlink (fn);
00937       else
00938          ast_log (LOG_EVENT, "Received to %s\n", fn2);
00939    }
00940 }
00941 
00942 /*! \brief read dir skipping dot files... */
00943 static struct dirent *readdirqueue (DIR * d, char *queue)
00944 {
00945    struct dirent *f;
00946    do {
00947       f = readdir (d);
00948    } while (f && (*f->d_name == '.' || strncmp (f->d_name, queue, strlen (queue)) || f->d_name[strlen (queue)] != '.'));
00949    return f;
00950 }
00951 
00952 /*! \brief handle the incoming message */
00953 static unsigned char sms_handleincoming (sms_t * h)
00954 {
00955    unsigned char p = 3;
00956    if (h->smsc) {                          /* SMSC */
00957       if ((h->imsg[2] & 3) == 1) {           /* SMS-SUBMIT */
00958          h->udhl = h->udl = 0;
00959          h->vp = 0;
00960          h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
00961          h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
00962          h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
00963          ast_copy_string (h->oa, h->cli, sizeof (h->oa));
00964          h->scts = time (0);
00965          h->mr = h->imsg[p++];
00966          p += unpackaddress (h->da, h->imsg + p);
00967          h->pid = h->imsg[p++];
00968          h->dcs = h->imsg[p++];
00969          if ((h->imsg[2] & 0x18) == 0x10) {                     /* relative VP */
00970             if (h->imsg[p] < 144)
00971                h->vp = (h->imsg[p] + 1) * 5;
00972             else if (h->imsg[p] < 168)
00973                h->vp = 720 + (h->imsg[p] - 143) * 30;
00974             else if (h->imsg[p] < 197)
00975                h->vp = (h->imsg[p] - 166) * 1440;
00976             else
00977                h->vp = (h->imsg[p] - 192) * 10080;
00978             p++;
00979          } else if (h->imsg[2] & 0x18)
00980             p += 7;            /* ignore enhanced / absolute VP */
00981          p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
00982          h->rx = 1;            /* received message */
00983          sms_writefile (h);     /* write the file */
00984          if (p != h->imsg[1] + 2) {
00985             ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
00986             return 0xFF;        /* duh! */
00987          }
00988       } else {
00989          ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
00990          return 0xFF;
00991       }
00992    } else {                          /* client */
00993       if (!(h->imsg[2] & 3)) {                         /* SMS-DELIVER */
00994          *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
00995          h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
00996          h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
00997          h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
00998          h->mr = -1;
00999          p += unpackaddress (h->oa, h->imsg + p);
01000          h->pid = h->imsg[p++];
01001          h->dcs = h->imsg[p++];
01002          h->scts = unpackdate (h->imsg + p);
01003          p += 7;
01004          p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
01005          h->rx = 1;            /* received message */
01006          sms_writefile (h);     /* write the file */
01007          if (p != h->imsg[1] + 2) {
01008             ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
01009             return 0xFF;        /* duh! */
01010          }
01011       } else {
01012          ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
01013          return 0xFF;
01014       }
01015    }
01016    return 0;                    /* no error */
01017 }
01018 
01019 #ifdef SOLARIS
01020 #define NAME_MAX 1024
01021 #endif
01022 
01023 /*! \brief find and fill in next message, or send a REL if none waiting */
01024 static void sms_nextoutgoing (sms_t * h)
01025 {          
01026    char fn[100 + NAME_MAX] = "";
01027    DIR *d;
01028    char more = 0;
01029    ast_copy_string (fn, spool_dir, sizeof (fn));
01030    mkdir (fn, 0777);          /* ensure it exists */
01031    h->rx = 0;                  /* outgoing message */
01032    snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? "mttx" : "motx");
01033    mkdir (fn, 0777);          /* ensure it exists */
01034    d = opendir (fn);
01035    if (d) {
01036       struct dirent *f = readdirqueue (d, h->queue);
01037       if (f) {
01038          snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", f->d_name);
01039          sms_readfile (h, fn);
01040          if (readdirqueue (d, h->queue))
01041             more = 1;           /* more to send */
01042       }
01043       closedir (d);
01044    }
01045    if (*h->da || *h->oa) {                          /* message to send */
01046       unsigned char p = 2;
01047       h->omsg[0] = 0x91;        /* SMS_DATA */
01048       if (h->smsc) {        /* deliver */
01049          h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
01050          p += packaddress (h->omsg + p, h->oa);
01051          h->omsg[p++] = h->pid;
01052          h->omsg[p++] = h->dcs;
01053          packdate (h->omsg + p, h->scts);
01054          p += 7;
01055          p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01056       } else {        /* submit */
01057          h->omsg[p++] =
01058             0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
01059          if (h->mr < 0)
01060             h->mr = message_ref++;
01061          h->omsg[p++] = h->mr;
01062          p += packaddress (h->omsg + p, h->da);
01063          h->omsg[p++] = h->pid;
01064          h->omsg[p++] = h->dcs;
01065          if (h->vp) {       /* relative VP */
01066             if (h->vp < 720)
01067                h->omsg[p++] = (h->vp + 4) / 5 - 1;
01068             else if (h->vp < 1440)
01069                h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
01070             else if (h->vp < 43200)
01071                h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
01072             else if (h->vp < 635040)
01073                h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
01074             else
01075                h->omsg[p++] = 255;     /* max */
01076          }
01077          p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01078       }
01079       h->omsg[1] = p - 2;
01080       sms_messagetx (h);
01081    } else {           /* no message */
01082       h->omsg[0] = 0x94;        /* SMS_REL */
01083       h->omsg[1] = 0;
01084       sms_messagetx (h);
01085    }
01086 }
01087 
01088 static void sms_debug (char *dir, unsigned char *msg)
01089 {
01090    char txt[259 * 3 + 1],
01091     *p = txt;                  /* always long enough */
01092    int n = msg[1] + 3,
01093       q = 0;
01094    while (q < n && q < 30) {
01095       sprintf (p, " %02X", msg[q++]);
01096       p += 3;
01097    }
01098    if (q < n)
01099       sprintf (p, "...");
01100    if (option_verbose > 2)
01101       ast_verbose (VERBOSE_PREFIX_3 "SMS %s%s\n", dir, txt);
01102 }
01103 
01104 static void sms_messagerx(sms_t * h)
01105 {
01106    sms_debug ("RX", h->imsg);
01107    /* testing */
01108    switch (h->imsg[0]) {
01109    case 0x91:                 /* SMS_DATA */
01110       {
01111          unsigned char cause = sms_handleincoming (h);
01112          if (!cause) {
01113             sms_log (h, 'Y');
01114             h->omsg[0] = 0x95;  /* SMS_ACK */
01115             h->omsg[1] = 0x02;
01116             h->omsg[2] = 0x00;  /* deliver report */
01117             h->omsg[3] = 0x00;  /* no parameters */
01118          } else {                    /* NACK */
01119             sms_log (h, 'N');
01120             h->omsg[0] = 0x96;  /* SMS_NACK */
01121             h->omsg[1] = 3;
01122             h->omsg[2] = 0;     /* delivery report */
01123             h->omsg[3] = cause; /* cause */
01124             h->omsg[4] = 0;     /* no parameters */
01125          }
01126          sms_messagetx (h);
01127       }
01128       break;
01129    case 0x92:                 /* SMS_ERROR */
01130       h->err = 1;
01131       sms_messagetx (h);        /* send whatever we sent again */
01132       break;
01133    case 0x93:                 /* SMS_EST */
01134       sms_nextoutgoing (h);
01135       break;
01136    case 0x94:                 /* SMS_REL */
01137       h->hangup = 1;          /* hangup */
01138       break;
01139    case 0x95:                 /* SMS_ACK */
01140       sms_log (h, 'Y');
01141       sms_nextoutgoing (h);
01142       break;
01143    case 0x96:                 /* SMS_NACK */
01144       h->err = 1;
01145       sms_log (h, 'N');
01146       sms_nextoutgoing (h);
01147       break;
01148    default:                  /* Unknown */
01149       h->omsg[0] = 0x92;        /* SMS_ERROR */
01150       h->omsg[1] = 1;
01151       h->omsg[2] = 3;           /* unknown message type; */
01152       sms_messagetx (h);
01153       break;
01154    }
01155 }
01156 
01157 static void sms_messagetx(sms_t * h)
01158 {
01159    unsigned char c = 0, p;
01160    for (p = 0; p < h->omsg[1] + 2; p++)
01161       c += h->omsg[p];
01162    h->omsg[h->omsg[1] + 2] = 0 - c;
01163    sms_debug ("TX", h->omsg);
01164    h->obyte = 1;
01165    h->opause = 200;
01166    if (h->omsg[0] == 0x93)
01167       h->opause = 2400;       /* initial message delay 300ms (for BT) */
01168    h->obytep = 0;
01169    h->obitp = 0;
01170    h->osync = 80;
01171    h->obyten = h->omsg[1] + 3;
01172 }
01173 
01174 static int sms_generate (struct ast_channel *chan, void *data, int len, int samples)
01175 {
01176    struct ast_frame f = { 0 };
01177 #define MAXSAMPLES (800)
01178 #ifdef OUTALAW
01179    unsigned char *buf;
01180 #else
01181    short *buf;
01182 #endif
01183 #define SAMPLE2LEN sizeof(*buf)
01184    sms_t *h = data;
01185    int i;
01186 
01187    if (samples > MAXSAMPLES) {
01188       ast_log (LOG_WARNING, "Only doing %d samples (%d requested)\n",
01189           MAXSAMPLES, samples);
01190       samples = MAXSAMPLES;
01191    }
01192    len = samples * SAMPLE2LEN + AST_FRIENDLY_OFFSET;
01193    buf = alloca(len);
01194 
01195    f.frametype = AST_FRAME_VOICE;
01196 #ifdef OUTALAW
01197    f.subclass = AST_FORMAT_ALAW;
01198 #else
01199    f.subclass = AST_FORMAT_SLINEAR;
01200 #endif
01201    f.datalen = samples * SAMPLE2LEN;
01202    f.offset = AST_FRIENDLY_OFFSET;
01203    f.mallocd = 0;
01204    f.data = buf;
01205    f.samples = samples;
01206    f.src = "app_sms";
01207    /* create a buffer containing the digital sms pattern */
01208    for (i = 0; i < samples; i++) {
01209 #ifdef OUTALAW
01210       buf[i] = wavea[0];
01211 #else
01212       buf[i] = wave[0];
01213 #endif
01214       if (h->opause)
01215          h->opause--;
01216       else if (h->obyten || h->osync) {                         /* sending data */
01217 #ifdef OUTALAW
01218          buf[i] = wavea[h->ophase];
01219 #else
01220          buf[i] = wave[h->ophase];
01221 #endif
01222          if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
01223             h->ophase -= 80;
01224          if ((h->ophasep += 12) >= 80) {                     /* next bit */
01225             h->ophasep -= 80;
01226             if (h->osync)
01227                h->osync--;    /* sending sync bits */
01228             else {
01229                h->obyte >>= 1;
01230                h->obitp++;
01231                if (h->obitp == 1)
01232                   h->obyte = 0; /* start bit; */
01233                else if (h->obitp == 2)
01234                   h->obyte = h->omsg[h->obytep];
01235                else if (h->obitp == 10) {
01236                   h->obyte = 1; /* stop bit */
01237                   h->obitp = 0;
01238                   h->obytep++;
01239                   if (h->obytep == h->obyten) {
01240                      h->obytep = h->obyten = 0; /* sent */
01241                      h->osync = 10;   /* trailing marks */
01242                   }
01243                }
01244             }
01245          }
01246       }
01247    }
01248    if (ast_write (chan, &f) < 0) {
01249       ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
01250       return -1;
01251    }
01252    return 0;
01253 #undef SAMPLE2LEN
01254 #undef MAXSAMPLES
01255 }
01256 
01257 static void sms_process (sms_t * h, int samples, signed short *data)
01258 {
01259    if (h->obyten || h->osync)
01260       return;                  /* sending */
01261    while (samples--) {
01262       unsigned long long m0, m1;
01263       if (abs (*data) > h->imag)
01264          h->imag = abs (*data);
01265       else
01266          h->imag = h->imag * 7 / 8;
01267       if (h->imag > 500) {
01268          h->idle = 0;
01269          h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
01270          h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
01271          h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
01272          h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
01273          m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
01274          m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
01275          if ((h->ips0 += 21) >= 80)
01276             h->ips0 -= 80;
01277          if ((h->ipc0 += 21) >= 80)
01278             h->ipc0 -= 80;
01279          if ((h->ips1 += 13) >= 80)
01280             h->ips1 -= 80;
01281          if ((h->ipc1 += 13) >= 80)
01282             h->ipc1 -= 80;
01283          {
01284             char bit;
01285             h->ibith <<= 1;
01286             if (m1 > m0)
01287                h->ibith |= 1;
01288             if (h->ibith & 8)
01289                h->ibitt--;
01290             if (h->ibith & 1)
01291                h->ibitt++;
01292             bit = ((h->ibitt > 1) ? 1 : 0);
01293             if (bit != h->ibitl)
01294                h->ibitc = 1;
01295             else
01296                h->ibitc++;
01297             h->ibitl = bit;
01298             if (!h->ibitn && h->ibitc == 4 && !bit) {
01299                h->ibitn = 1;
01300                h->iphasep = 0;
01301             }
01302             if (bit && h->ibitc == 200) {                 /* sync, restart message */
01303                h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01304             }
01305             if (h->ibitn) {
01306                h->iphasep += 12;
01307                if (h->iphasep >= 80) {              /* next bit */
01308                   h->iphasep -= 80;
01309                   if (h->ibitn++ == 9) {            /* end of byte */
01310                      if (!bit)  /* bad stop bit */
01311                         h->ierr = 0xFF; /* unknown error */
01312                      else {
01313                         if (h->ibytep < sizeof (h->imsg)) {
01314                            h->imsg[h->ibytep] = h->ibytev;
01315                            h->ibytec += h->ibytev;
01316                            h->ibytep++;
01317                         } else if (h->ibytep == sizeof (h->imsg))
01318                            h->ierr = 2; /* bad message length */
01319                         if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
01320                            if (!h->ibytec)
01321                               sms_messagerx (h);
01322                            else
01323                               h->ierr = 1;      /* bad checksum */
01324                         }
01325                      }
01326                      h->ibitn = 0;
01327                   }
01328                   h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
01329                }
01330             }
01331          }
01332       } else {        /* lost carrier */
01333          if (h->idle++ == 80000) {      /* nothing happening */
01334             ast_log (LOG_EVENT, "No data, hanging up\n");
01335             h->hangup = 1;
01336             h->err = 1;
01337          }
01338          if (h->ierr) {                    /* error */
01339             h->err = 1;
01340             h->omsg[0] = 0x92;  /* error */
01341             h->omsg[1] = 1;
01342             h->omsg[2] = h->ierr;
01343             sms_messagetx (h);  /* send error */
01344          }
01345          h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01346       }
01347       data++;
01348    }
01349 }
01350 
01351 static struct ast_generator smsgen = {
01352    alloc:sms_alloc,
01353    release:sms_release,
01354    generate:sms_generate,
01355 };
01356 
01357 static int sms_exec (struct ast_channel *chan, void *data)
01358 {
01359    int res = -1;
01360    struct ast_module_user *u;
01361    struct ast_frame *f;
01362    sms_t h = { 0 };
01363    
01364    u = ast_module_user_add(chan);
01365 
01366    h.ipc0 = h.ipc1 = 20;        /* phase for cosine */
01367    h.dcs = 0xF1;               /* default */
01368    if (!data) {
01369       ast_log (LOG_ERROR, "Requires queue name at least\n");
01370       ast_module_user_remove(u);
01371       return -1;
01372    }
01373 
01374    if (chan->cid.cid_num)
01375       ast_copy_string (h.cli, chan->cid.cid_num, sizeof (h.cli));
01376 
01377    {
01378       unsigned char *p;
01379       unsigned char *d = data,
01380          answer = 0;
01381       if (!*d || *d == '|') {
01382          ast_log (LOG_ERROR, "Requires queue name\n");
01383          ast_module_user_remove(u);
01384          return -1;
01385       }
01386       for (p = d; *p && *p != '|'; p++);
01387       if (p - d >= sizeof (h.queue)) {
01388          ast_log (LOG_ERROR, "Queue name too long\n");
01389          ast_module_user_remove(u);
01390          return -1;
01391       }
01392       strncpy(h.queue, (char *)d, p - d);
01393       if (*p == '|')
01394          p++;
01395       d = p;
01396       for (p = (unsigned char *)h.queue; *p; p++)
01397          if (!isalnum (*p))
01398             *p = '-';           /* make very safe for filenames */
01399       while (*d && *d != '|') {
01400          switch (*d) {
01401          case 'a':             /* we have to send the initial FSK sequence */
01402             answer = 1;
01403             break;
01404          case 's':             /* we are acting as a service centre talking to a phone */
01405             h.smsc = 1;
01406             break;
01407             /* the following apply if there is an arg3/4 and apply to the created message file */
01408          case 'r':
01409             h.srr = 1;
01410             break;
01411          case 'o':
01412             h.dcs |= 4;       /* octets */
01413             break;
01414          case '1':
01415          case '2':
01416          case '3':
01417          case '4':
01418          case '5':
01419          case '6':
01420          case '7':             /* set the pid for saved local message */
01421             h.pid = 0x40 + (*d & 0xF);
01422             break;
01423          }
01424          d++;
01425       }
01426       if (*d == '|') {
01427          /* submitting a message, not taking call. */
01428          /* deprecated, use smsq instead */
01429          d++;
01430          h.scts = time (0);
01431          for (p = d; *p && *p != '|'; p++);
01432          if (*p)
01433             *p++ = 0;
01434          if (strlen ((char *)d) >= sizeof (h.oa)) {
01435             ast_log (LOG_ERROR, "Address too long %s\n", d);
01436             return 0;
01437          }
01438          if (h.smsc) {
01439             ast_copy_string (h.oa, (char *)d, sizeof (h.oa));
01440          } else {
01441             ast_copy_string (h.da, (char *)d, sizeof (h.da));
01442          }
01443          if (!h.smsc)
01444             ast_copy_string (h.oa, h.cli, sizeof (h.oa));
01445          d = p;
01446          h.udl = 0;
01447          while (*p && h.udl < SMSLEN)
01448             h.ud[h.udl++] = utf8decode(&p);
01449          if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
01450             ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n");
01451          if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
01452             ast_log (LOG_WARNING, "Invalid 8 bit data\n");
01453          if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
01454             ast_log (LOG_WARNING, "Invalid 16 bit data\n");
01455          h.rx = 0;              /* sent message */
01456          h.mr = -1;
01457          sms_writefile (&h);
01458          ast_module_user_remove(u);
01459          return 0;
01460       }
01461 
01462       if (answer) {
01463          /* set up SMS_EST initial message */
01464          h.omsg[0] = 0x93;
01465          h.omsg[1] = 0;
01466          sms_messagetx (&h);
01467       }
01468    }
01469 
01470    if (chan->_state != AST_STATE_UP)
01471       ast_answer (chan);
01472 
01473 #ifdef OUTALAW
01474    res = ast_set_write_format (chan, AST_FORMAT_ALAW);
01475 #else
01476    res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
01477 #endif
01478    if (res >= 0)
01479       res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
01480    if (res < 0) {
01481       ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
01482       ast_module_user_remove(u);
01483       return -1;
01484    }
01485 
01486    if (ast_activate_generator (chan, &smsgen, &h) < 0) {
01487       ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
01488       ast_module_user_remove(u);
01489       return -1;
01490    }
01491 
01492    /* Do our thing here */
01493    while (ast_waitfor (chan, -1) > -1 && !h.hangup)
01494    {
01495       f = ast_read (chan);
01496       if (!f)
01497          break;
01498       if (f->frametype == AST_FRAME_VOICE) {
01499          sms_process (&h, f->samples, f->data);
01500       }
01501 
01502       ast_frfree (f);
01503    }
01504 
01505    sms_log (&h, '?');           /* log incomplete message */
01506 
01507    ast_module_user_remove(u);
01508    return (h.err);
01509 }
01510 
01511 static int unload_module(void)
01512 {
01513    int res;
01514 
01515    res = ast_unregister_application (app);
01516    
01517    ast_module_user_hangup_all();
01518 
01519    return res; 
01520 }
01521 
01522 static int load_module(void)
01523 {
01524 #ifdef OUTALAW
01525    {
01526       int p;
01527       for (p = 0; p < 80; p++)
01528          wavea[p] = AST_LIN2A (wave[p]);
01529    }
01530 #endif
01531    snprintf (log_file, sizeof (log_file), "%s/sms", ast_config_AST_LOG_DIR);
01532    snprintf (spool_dir, sizeof (spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
01533    return ast_register_application (app, sms_exec, synopsis, descrip);
01534 }
01535 
01536 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SMS/PSTN handler");

Generated on Mon Jul 14 17:24:49 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1