Mon Mar 20 08:20:07 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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: 7634 $")
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    unsigned char waste[AST_FRIENDLY_OFFSET];
01182 #ifdef OUTALAW
01183    unsigned char buf[800];
01184 #else
01185    signed short buf[800];
01186 #endif
01187    sms_t *h = data;
01188    int i;
01189 
01190    if (len > sizeof (buf)) {
01191       ast_log (LOG_WARNING, "Only doing %d bytes (%d bytes requested)\n", (int)(sizeof (buf) / sizeof (signed short)), len);
01192       len = sizeof (buf);
01193 #ifdef OUTALAW
01194       samples = len;
01195 #else
01196       samples = len / 2;
01197 #endif
01198    }
01199    waste[0] = 0;               /* make compiler happy */
01200    f.frametype = AST_FRAME_VOICE;
01201 #ifdef OUTALAW
01202    f.subclass = AST_FORMAT_ALAW;
01203    f.datalen = samples;
01204 #else
01205    f.subclass = AST_FORMAT_SLINEAR;
01206    f.datalen = samples * 2;
01207 #endif
01208    f.offset = AST_FRIENDLY_OFFSET;
01209    f.mallocd = 0;
01210    f.data = buf;
01211    f.samples = samples;
01212    f.src = "app_sms";
01213    /* create a buffer containing the digital sms pattern */
01214    for (i = 0; i < samples; i++) {
01215 #ifdef OUTALAW
01216       buf[i] = wavea[0];
01217 #else
01218       buf[i] = wave[0];
01219 #endif
01220       if (h->opause)
01221          h->opause--;
01222       else if (h->obyten || h->osync) {                         /* sending data */
01223 #ifdef OUTALAW
01224          buf[i] = wavea[h->ophase];
01225 #else
01226          buf[i] = wave[h->ophase];
01227 #endif
01228          if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
01229             h->ophase -= 80;
01230          if ((h->ophasep += 12) >= 80) {                     /* next bit */
01231             h->ophasep -= 80;
01232             if (h->osync)
01233                h->osync--;    /* sending sync bits */
01234             else {
01235                h->obyte >>= 1;
01236                h->obitp++;
01237                if (h->obitp == 1)
01238                   h->obyte = 0; /* start bit; */
01239                else if (h->obitp == 2)
01240                   h->obyte = h->omsg[h->obytep];
01241                else if (h->obitp == 10) {
01242                   h->obyte = 1; /* stop bit */
01243                   h->obitp = 0;
01244                   h->obytep++;
01245                   if (h->obytep == h->obyten) {
01246                      h->obytep = h->obyten = 0; /* sent */
01247                      h->osync = 10;   /* trailing marks */
01248                   }
01249                }
01250             }
01251          }
01252       }
01253    }
01254    if (ast_write (chan, &f) < 0) {
01255       ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
01256       return -1;
01257    }
01258    return 0;
01259 }
01260 
01261 static void sms_process (sms_t * h, int samples, signed short *data)
01262 {
01263    if (h->obyten || h->osync)
01264       return;                  /* sending */
01265    while (samples--) {
01266       unsigned long long m0, m1;
01267       if (abs (*data) > h->imag)
01268          h->imag = abs (*data);
01269       else
01270          h->imag = h->imag * 7 / 8;
01271       if (h->imag > 500) {
01272          h->idle = 0;
01273          h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
01274          h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
01275          h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
01276          h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
01277          m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
01278          m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
01279          if ((h->ips0 += 21) >= 80)
01280             h->ips0 -= 80;
01281          if ((h->ipc0 += 21) >= 80)
01282             h->ipc0 -= 80;
01283          if ((h->ips1 += 13) >= 80)
01284             h->ips1 -= 80;
01285          if ((h->ipc1 += 13) >= 80)
01286             h->ipc1 -= 80;
01287          {
01288             char bit;
01289             h->ibith <<= 1;
01290             if (m1 > m0)
01291                h->ibith |= 1;
01292             if (h->ibith & 8)
01293                h->ibitt--;
01294             if (h->ibith & 1)
01295                h->ibitt++;
01296             bit = ((h->ibitt > 1) ? 1 : 0);
01297             if (bit != h->ibitl)
01298                h->ibitc = 1;
01299             else
01300                h->ibitc++;
01301             h->ibitl = bit;
01302             if (!h->ibitn && h->ibitc == 4 && !bit) {
01303                h->ibitn = 1;
01304                h->iphasep = 0;
01305             }
01306             if (bit && h->ibitc == 200) {                 /* sync, restart message */
01307                h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01308             }
01309             if (h->ibitn) {
01310                h->iphasep += 12;
01311                if (h->iphasep >= 80) {              /* next bit */
01312                   h->iphasep -= 80;
01313                   if (h->ibitn++ == 9) {            /* end of byte */
01314                      if (!bit)  /* bad stop bit */
01315                         h->ierr = 0xFF; /* unknown error */
01316                      else {
01317                         if (h->ibytep < sizeof (h->imsg)) {
01318                            h->imsg[h->ibytep] = h->ibytev;
01319                            h->ibytec += h->ibytev;
01320                            h->ibytep++;
01321                         } else if (h->ibytep == sizeof (h->imsg))
01322                            h->ierr = 2; /* bad message length */
01323                         if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
01324                            if (!h->ibytec)
01325                               sms_messagerx (h);
01326                            else
01327                               h->ierr = 1;      /* bad checksum */
01328                         }
01329                      }
01330                      h->ibitn = 0;
01331                   }
01332                   h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
01333                }
01334             }
01335          }
01336       } else {        /* lost carrier */
01337          if (h->idle++ == 80000) {      /* nothing happening */
01338             ast_log (LOG_EVENT, "No data, hanging up\n");
01339             h->hangup = 1;
01340             h->err = 1;
01341          }
01342          if (h->ierr) {                    /* error */
01343             h->err = 1;
01344             h->omsg[0] = 0x92;  /* error */
01345             h->omsg[1] = 1;
01346             h->omsg[2] = h->ierr;
01347             sms_messagetx (h);  /* send error */
01348          }
01349          h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01350       }
01351       data++;
01352    }
01353 }
01354 
01355 static struct ast_generator smsgen = {
01356    alloc:sms_alloc,
01357    release:sms_release,
01358    generate:sms_generate,
01359 };
01360 
01361 static int sms_exec (struct ast_channel *chan, void *data)
01362 {
01363    int res = -1;
01364    struct localuser *u;
01365    struct ast_frame *f;
01366    sms_t h = { 0 };
01367    
01368    LOCAL_USER_ADD(u);
01369 
01370    h.ipc0 = h.ipc1 = 20;        /* phase for cosine */
01371    h.dcs = 0xF1;               /* default */
01372    if (!data) {
01373       ast_log (LOG_ERROR, "Requires queue name at least\n");
01374       LOCAL_USER_REMOVE(u);
01375       return -1;
01376    }
01377 
01378    if (chan->cid.cid_num)
01379       ast_copy_string (h.cli, chan->cid.cid_num, sizeof (h.cli));
01380 
01381    {
01382       unsigned char *p;
01383       unsigned char *d = data,
01384          answer = 0;
01385       if (!*d || *d == '|') {
01386          ast_log (LOG_ERROR, "Requires queue name\n");
01387          LOCAL_USER_REMOVE(u);
01388          return -1;
01389       }
01390       for (p = d; *p && *p != '|'; p++);
01391       if (p - d >= sizeof (h.queue)) {
01392          ast_log (LOG_ERROR, "Queue name too long\n");
01393          LOCAL_USER_REMOVE(u);
01394          return -1;
01395       }
01396       strncpy (h.queue, d, p - d);
01397       if (*p == '|')
01398          p++;
01399       d = p;
01400       for (p = h.queue; *p; p++)
01401          if (!isalnum (*p))
01402             *p = '-';           /* make very safe for filenames */
01403       while (*d && *d != '|') {
01404          switch (*d) {
01405          case 'a':             /* we have to send the initial FSK sequence */
01406             answer = 1;
01407             break;
01408          case 's':             /* we are acting as a service centre talking to a phone */
01409             h.smsc = 1;
01410             break;
01411             /* the following apply if there is an arg3/4 and apply to the created message file */
01412          case 'r':
01413             h.srr = 1;
01414             break;
01415          case 'o':
01416             h.dcs |= 4;       /* octets */
01417             break;
01418          case '1':
01419          case '2':
01420          case '3':
01421          case '4':
01422          case '5':
01423          case '6':
01424          case '7':             /* set the pid for saved local message */
01425             h.pid = 0x40 + (*d & 0xF);
01426             break;
01427          }
01428          d++;
01429       }
01430       if (*d == '|') {
01431          /* submitting a message, not taking call. */
01432          /* depricated, use smsq instead */
01433          d++;
01434          h.scts = time (0);
01435          for (p = d; *p && *p != '|'; p++);
01436          if (*p)
01437             *p++ = 0;
01438          if (strlen (d) >= sizeof (h.oa)) {
01439             ast_log (LOG_ERROR, "Address too long %s\n", d);
01440             return 0;
01441          }
01442          if (h.smsc) {
01443             ast_copy_string (h.oa, d, sizeof (h.oa));
01444          } else {
01445             ast_copy_string (h.da, d, sizeof (h.da));
01446          }
01447          if (!h.smsc)
01448             ast_copy_string (h.oa, h.cli, sizeof (h.oa));
01449          d = p;
01450          h.udl = 0;
01451          while (*p && h.udl < SMSLEN)
01452             h.ud[h.udl++] = utf8decode(&p);
01453          if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
01454             ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n");
01455          if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
01456             ast_log (LOG_WARNING, "Invalid 8 bit data\n");
01457          if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
01458             ast_log (LOG_WARNING, "Invalid 16 bit data\n");
01459          h.rx = 0;              /* sent message */
01460          h.mr = -1;
01461          sms_writefile (&h);
01462          LOCAL_USER_REMOVE(u);
01463          return 0;
01464       }
01465 
01466       if (answer) {
01467          /* set up SMS_EST initial message */
01468          h.omsg[0] = 0x93;
01469          h.omsg[1] = 0;
01470          sms_messagetx (&h);
01471       }
01472    }
01473 
01474    if (chan->_state != AST_STATE_UP)
01475       ast_answer (chan);
01476 
01477 #ifdef OUTALAW
01478    res = ast_set_write_format (chan, AST_FORMAT_ALAW);
01479 #else
01480    res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
01481 #endif
01482    if (res >= 0)
01483       res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
01484    if (res < 0) {
01485       ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
01486       LOCAL_USER_REMOVE (u);
01487       return -1;
01488    }
01489 
01490    if (ast_activate_generator (chan, &smsgen, &h) < 0) {
01491       ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
01492       LOCAL_USER_REMOVE (u);
01493       return -1;
01494    }
01495 
01496    /* Do our thing here */
01497    while (ast_waitfor (chan, -1) > -1 && !h.hangup)
01498    {
01499       f = ast_read (chan);
01500       if (!f)
01501          break;
01502       if (f->frametype == AST_FRAME_VOICE) {
01503          sms_process (&h, f->samples, f->data);
01504       }
01505 
01506       ast_frfree (f);
01507    }
01508 
01509    sms_log (&h, '?');           /* log incomplete message */
01510 
01511    LOCAL_USER_REMOVE (u);
01512    return (h.err);
01513 }
01514 
01515 int unload_module (void)
01516 {
01517    int res;
01518 
01519    res = ast_unregister_application (app);
01520    
01521    STANDARD_HANGUP_LOCALUSERS;
01522 
01523    return res; 
01524 }
01525 
01526 int load_module (void)
01527 {
01528 #ifdef OUTALAW
01529    {
01530       int p;
01531       for (p = 0; p < 80; p++)
01532          wavea[p] = AST_LIN2A (wave[p]);
01533    }
01534 #endif
01535    snprintf (log_file, sizeof (log_file), "%s/sms", ast_config_AST_LOG_DIR);
01536    snprintf (spool_dir, sizeof (spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
01537    return ast_register_application (app, sms_exec, synopsis, descrip);
01538 }
01539 
01540 char *description (void)
01541 {
01542    return tdesc;
01543 }
01544 
01545 int usecount (void)
01546 {
01547    int res;
01548    STANDARD_USECOUNT (res);
01549    return res;
01550 }
01551 
01552 char *key ()
01553 {
01554    return ASTERISK_GPL_KEY;
01555 }

Generated on Mon Mar 20 08:20:07 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1