Mon Sep 18 09:12:45 2006

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

Generated on Mon Sep 18 09:12:46 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7