Mon Mar 31 07:38:47 2008

Asterisk developer's documentation


app_sms.c File Reference

SMS application - ETSI ES 201 912 protocol 1 implimentation. More...

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/alaw.h"
#include "asterisk/callerid.h"

Include dependency graph for app_sms.c:

Go to the source code of this file.

Data Structures

struct  sms_s

Defines

#define is16bit(dcs)   (((dcs)&0xC0)?0:(((dcs)&12)==8))
#define is7bit(dcs)   (((dcs)&0xC0)?(!((dcs)&4)):(!((dcs)&12)))
#define is8bit(dcs)   (((dcs)&0xC0)?(((dcs)&4)):(((dcs)&12)==4))
#define MAXSAMPLES   (800)
#define SAMPLE2LEN   sizeof(*buf)
#define SMSLEN   160

Typedefs

typedef sms_s sms_t

Functions

 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"SMS/PSTN handler")
static char * isodate (time_t t)
 static, return a date/time in ISO format
static int load_module (void)
static void numcpy (char *d, char *s)
 copy number, skipping non digits apart from leading +
static unsigned char packaddress (unsigned char *o, char *i)
 store an address at o, and return number of bytes used
static void packdate (unsigned char *o, time_t w)
 pack a date and return
static int packsms (unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
 general pack, with length and data, returns number of bytes of target used
static int packsms16 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
 takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 16 bit UCS-2 character codes The return value is the number of bytes packed in to o, which is internally limited to 140 o can be null, in which case this is used to validate or count only if the input contains invalid characters then the return value is -1
static int packsms7 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
 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
static int packsms8 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
 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
static struct dirent * readdirqueue (DIR *d, char *queue)
 read dir skipping dot files...
static void * sms_alloc (struct ast_channel *chan, void *params)
static void sms_debug (char *dir, unsigned char *msg)
static int sms_exec (struct ast_channel *chan, void *data)
static int sms_generate (struct ast_channel *chan, void *data, int len, int samples)
static unsigned char sms_handleincoming (sms_t *h)
 handle the incoming message
static void sms_log (sms_t *h, char status)
 Log the output, and remove file.
static void sms_messagerx (sms_t *h)
static void sms_messagetx (sms_t *h)
static void sms_nextoutgoing (sms_t *h)
 find and fill in next message, or send a REL if none waiting
static void sms_process (sms_t *h, int samples, signed short *data)
static void sms_readfile (sms_t *h, char *fn)
 parse and delete a file
static void sms_release (struct ast_channel *chan, void *data)
static void sms_writefile (sms_t *h)
 white a received text message to a file
static int unload_module (void)
static unsigned char unpackaddress (char *o, unsigned char *i)
 unpack an address from i, return byte length, unpack to o
static time_t unpackdate (unsigned char *i)
 unpack a date and return
static int unpacksms (unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
 general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length
static void unpacksms16 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
 unpacks bytes (16 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set
static void unpacksms7 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
 unpacks bytes (7 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set
static void unpacksms8 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
 unpacks bytes (8 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set
static long utf8decode (unsigned char **pp)
 reads next UCS character from null terminated UTF-8 string and advanced pointer

Variables

static char * app = "SMS"
static const unsigned short defaultalphabet []
static char * descrip
static const unsigned short escapes []
static char log_file [255]
static volatile unsigned char message_ref
static volatile unsigned int seq
static struct ast_generator smsgen
static char spool_dir [255]
static char * synopsis = "Communicates with SMS service centres and SMS capable analogue phones"
static signed short wave []


Detailed Description

SMS application - ETSI ES 201 912 protocol 1 implimentation.

Author:
Adrian Kennard

Definition in file app_sms.c.


Define Documentation

#define is16bit ( dcs   )     (((dcs)&0xC0)?0:(((dcs)&12)==8))

Definition at line 182 of file app_sms.c.

Referenced by sms_readfile().

#define is7bit ( dcs   )     (((dcs)&0xC0)?(!((dcs)&4)):(!((dcs)&12)))

Definition at line 180 of file app_sms.c.

Referenced by packsms(), sms_readfile(), and unpacksms().

#define is8bit ( dcs   )     (((dcs)&0xC0)?(((dcs)&4)):(((dcs)&12)==4))

Definition at line 181 of file app_sms.c.

Referenced by packsms(), sms_readfile(), and unpacksms().

#define MAXSAMPLES   (800)

Referenced by sms_generate().

#define SAMPLE2LEN   sizeof(*buf)

Referenced by sms_generate().

#define SMSLEN   160

Definition at line 122 of file app_sms.c.

Referenced by packsms7(), and sms_readfile().


Typedef Documentation

typedef struct sms_s sms_t


Function Documentation

AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"SMS/PSTN handler"   
)

static char* isodate ( time_t  t  )  [static]

static, return a date/time in ISO format

Definition at line 210 of file app_sms.c.

Referenced by sms_log(), and sms_writefile().

00211 {
00212    static char date[20];
00213    strftime (date, sizeof (date), "%Y-%m-%dT%H:%M:%S", localtime (&t));
00214    return date;
00215 }

static int load_module ( void   )  [static]

Definition at line 1522 of file app_sms.c.

References ast_config_AST_LOG_DIR, ast_config_AST_SPOOL_DIR, AST_LIN2A, ast_register_application(), and sms_exec().

01523 {
01524 #ifdef OUTALAW
01525    {
01526       int p;
01527       for (p = 0; p < 80; p++)
01528          wavea[p] = AST_LIN2A (wave[p]);
01529    }
01530 #endif
01531    snprintf (log_file, sizeof (log_file), "%s/sms", ast_config_AST_LOG_DIR);
01532    snprintf (spool_dir, sizeof (spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
01533    return ast_register_application (app, sms_exec, synopsis, descrip);
01534 }

static void numcpy ( char *  d,
char *  s 
) [static]

copy number, skipping non digits apart from leading +

Definition at line 197 of file app_sms.c.

Referenced by sms_readfile().

00198 {
00199    if (*s == '+')
00200       *d++ = *s++;
00201    while (*s) {
00202       if (isdigit (*s))
00203             *d++ = *s;
00204       s++;
00205    }
00206    *d = 0;
00207 }

static unsigned char packaddress ( unsigned char *  o,
char *  i 
) [static]

store an address at o, and return number of bytes used

Definition at line 610 of file app_sms.c.

Referenced by sms_nextoutgoing().

00611 {
00612    unsigned char p = 2;
00613    o[0] = 0;
00614    if (*i == '+') {
00615       i++;
00616       o[1] = 0x91;
00617    } else
00618       o[1] = 0x81;
00619    while (*i)
00620       if (isdigit (*i)) {
00621          if (o[0] & 1)
00622             o[p++] |= ((*i & 0xF) << 4);
00623          else
00624             o[p] = (*i & 0xF);
00625          o[0]++;
00626          i++;
00627       } else
00628          i++;
00629    if (o[0] & 1)
00630       o[p++] |= 0xF0;           /* pad */
00631    return p;
00632 }

static void packdate ( unsigned char *  o,
time_t  w 
) [static]

pack a date and return

Definition at line 435 of file app_sms.c.

References t.

Referenced by sms_nextoutgoing().

00436 {
00437    struct tm *t = localtime (&w);
00438 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
00439    int z = -t->tm_gmtoff / 60 / 15;
00440 #else
00441    int z = timezone / 60 / 15;
00442 #endif
00443    *o++ = ((t->tm_year % 10) << 4) + (t->tm_year % 100) / 10;
00444    *o++ = (((t->tm_mon + 1) % 10) << 4) + (t->tm_mon + 1) / 10;
00445    *o++ = ((t->tm_mday % 10) << 4) + t->tm_mday / 10;
00446    *o++ = ((t->tm_hour % 10) << 4) + t->tm_hour / 10;
00447    *o++ = ((t->tm_min % 10) << 4) + t->tm_min / 10;
00448    *o++ = ((t->tm_sec % 10) << 4) + t->tm_sec / 10;
00449    if (z < 0)
00450       *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
00451    else
00452       *o++ = ((z % 10) << 4) + z / 10;
00453 }

static int packsms ( unsigned char  dcs,
unsigned char *  base,
unsigned int  udhl,
unsigned char *  udh,
int  udl,
unsigned short *  ud 
) [static]

general pack, with length and data, returns number of bytes of target used

Definition at line 404 of file app_sms.c.

References is7bit, is8bit, packsms16(), packsms7(), and packsms8().

Referenced by sms_nextoutgoing().

00405 {
00406    unsigned char *p = base;
00407    if (udl) {
00408       int l = 0;
00409       if (is7bit (dcs)) {      /* 7 bit */
00410          l = packsms7 (p + 1, udhl, udh, udl, ud);
00411          if (l < 0)
00412             l = 0;
00413          *p++ = l;
00414          p += (l * 7 + 7) / 8;
00415       } else if (is8bit (dcs)) {                       /* 8 bit */
00416          l = packsms8 (p + 1, udhl, udh, udl, ud);
00417          if (l < 0)
00418             l = 0;
00419          *p++ = l;
00420          p += l;
00421       } else {        /* UCS-2 */
00422          l = packsms16 (p + 1, udhl, udh, udl, ud);
00423          if (l < 0)
00424             l = 0;
00425          *p++ = l;
00426          p += l;
00427       }
00428    } else
00429       *p++ = 0;           /* no user data */
00430    return p - base;
00431 }

static int packsms16 ( unsigned char *  o,
int  udhl,
unsigned char *  udh,
int  udl,
unsigned short *  ud 
) [static]

takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 16 bit UCS-2 character codes The return value is the number of bytes packed in to o, which is internally limited to 140 o can be null, in which case this is used to validate or count only if the input contains invalid characters then the return value is -1

Definition at line 373 of file app_sms.c.

Referenced by packsms(), and sms_readfile().

00374 {
00375    unsigned char p = 0;
00376    /* header - no encoding */
00377    if (udhl) {
00378       if (o)
00379          o[p++] = udhl;
00380       while (udhl--) {
00381          if (o)
00382             o[p++] = *udh++;
00383          if (p >= 140)
00384             return p;
00385       }
00386    }
00387    while (udl--) {
00388       long u;
00389       u = *ud++;
00390       if (o)
00391          o[p++] = (u >> 8);
00392       if (p >= 140)
00393          return p - 1;          /* could not fit last character */
00394       if (o)
00395          o[p++] = u;
00396       if (p >= 140)
00397          return p;
00398    }
00399    return p;
00400 }

static int packsms7 ( unsigned char *  o,
int  udhl,
unsigned char *  udh,
int  udl,
unsigned short *  ud 
) [static]

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

Definition at line 267 of file app_sms.c.

References SMSLEN.

Referenced by packsms(), and sms_readfile().

00268 {
00269     unsigned char p = 0, b = 0, n = 0;
00270 
00271    if (udhl) {                            /* header */
00272       if (o)
00273          o[p++] = udhl;
00274       b = 1;
00275       n = 1;
00276       while (udhl--) {
00277          if (o)
00278             o[p++] = *udh++;
00279          b += 8;
00280          while (b >= 7) {
00281             b -= 7;
00282             n++;
00283          }
00284          if (n >= SMSLEN)
00285             return n;
00286       }
00287       if (b) {
00288          b = 7 - b;
00289          if (++n >= SMSLEN)
00290             return n;
00291          }; /* filling to septet boundary */
00292       }
00293       if (o)
00294          o[p] = 0;
00295       /* message */
00296       while (udl--) {
00297          long u;
00298          unsigned char v;
00299          u = *ud++;
00300          for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
00301          if (v == 128 && u && n + 1 < SMSLEN) {
00302             for (v = 0; v < 128 && escapes[v] != u; v++);
00303             if (v < 128) { /* escaped sequence */
00304             if (o)
00305                o[p] |= (27 << b);
00306             b += 7;
00307             if (b >= 8) {
00308                b -= 8;
00309                p++;
00310                if (o)
00311                   o[p] = (27 >> (7 - b));
00312             }
00313             n++;
00314          }
00315       }
00316       if (v == 128)
00317          return -1;             /* invalid character */
00318       if (o)
00319          o[p] |= (v << b);
00320       b += 7;
00321       if (b >= 8) {
00322          b -= 8;
00323          p++;
00324          if (o)
00325             o[p] = (v >> (7 - b));
00326       }
00327       if (++n >= SMSLEN)
00328          return n;
00329    }
00330    return n;
00331 }

static int packsms8 ( unsigned char *  o,
int  udhl,
unsigned char *  udh,
int  udl,
unsigned short *  ud 
) [static]

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

Definition at line 337 of file app_sms.c.

Referenced by packsms(), and sms_readfile().

00338 {
00339    unsigned char p = 0;
00340 
00341    /* header - no encoding */
00342    if (udhl) {
00343       if (o)
00344          o[p++] = udhl;
00345       while (udhl--) {
00346          if (o)
00347             o[p++] = *udh++;
00348          if (p >= 140)
00349             return p;
00350       }
00351    }
00352    while (udl--) {
00353       long u;
00354       u = *ud++;
00355       if (u < 0 || u > 0xFF)
00356          return -1;             /* not valid */
00357       if (o)
00358          o[p++] = u;
00359       if (p >= 140)
00360          return p;
00361    }
00362    return p;
00363 }

static struct dirent* readdirqueue ( DIR *  d,
char *  queue 
) [static]

read dir skipping dot files...

Definition at line 943 of file app_sms.c.

References f.

Referenced by sms_nextoutgoing().

00944 {
00945    struct dirent *f;
00946    do {
00947       f = readdir (d);
00948    } while (f && (*f->d_name == '.' || strncmp (f->d_name, queue, strlen (queue)) || f->d_name[strlen (queue)] != '.'));
00949    return f;
00950 }

static void* sms_alloc ( struct ast_channel chan,
void *  params 
) [static]

Definition at line 184 of file app_sms.c.

00185 {
00186    return params;
00187 }

static void sms_debug ( char *  dir,
unsigned char *  msg 
) [static]

Definition at line 1088 of file app_sms.c.

References ast_verbose(), option_verbose, and VERBOSE_PREFIX_3.

Referenced by sms_messagerx(), and sms_messagetx().

01089 {
01090    char txt[259 * 3 + 1],
01091     *p = txt;                  /* always long enough */
01092    int n = msg[1] + 3,
01093       q = 0;
01094    while (q < n && q < 30) {
01095       sprintf (p, " %02X", msg[q++]);
01096       p += 3;
01097    }
01098    if (q < n)
01099       sprintf (p, "...");
01100    if (option_verbose > 2)
01101       ast_verbose (VERBOSE_PREFIX_3 "SMS %s%s\n", dir, txt);
01102 }

static int sms_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 1357 of file app_sms.c.

References answer, ast_log(), ast_module_user_add, ast_module_user_remove, ast_channel::cid, ast_callerid::cid_num, sms_s::cli, sms_s::dcs, f, sms_s::ipc0, sms_s::ipc1, LOG_ERROR, sms_s::oa, sms_s::pid, sms_s::queue, sms_s::scts, sms_s::smsc, and sms_s::srr.

Referenced by load_module().

01358 {
01359    int res = -1;
01360    struct ast_module_user *u;
01361    struct ast_frame *f;
01362    sms_t h = { 0 };
01363    
01364    u = ast_module_user_add(chan);
01365 
01366    h.ipc0 = h.ipc1 = 20;        /* phase for cosine */
01367    h.dcs = 0xF1;               /* default */
01368    if (!data) {
01369       ast_log (LOG_ERROR, "Requires queue name at least\n");
01370       ast_module_user_remove(u);
01371       return -1;
01372    }
01373 
01374    if (chan->cid.cid_num)
01375       ast_copy_string (h.cli, chan->cid.cid_num, sizeof (h.cli));
01376 
01377    {
01378       unsigned char *p;
01379       unsigned char *d = data,
01380          answer = 0;
01381       if (!*d || *d == '|') {
01382          ast_log (LOG_ERROR, "Requires queue name\n");
01383          ast_module_user_remove(u);
01384          return -1;
01385       }
01386       for (p = d; *p && *p != '|'; p++);
01387       if (p - d >= sizeof (h.queue)) {
01388          ast_log (LOG_ERROR, "Queue name too long\n");
01389          ast_module_user_remove(u);
01390          return -1;
01391       }
01392       strncpy(h.queue, (char *)d, p - d);
01393       if (*p == '|')
01394          p++;
01395       d = p;
01396       for (p = (unsigned char *)h.queue; *p; p++)
01397          if (!isalnum (*p))
01398             *p = '-';           /* make very safe for filenames */
01399       while (*d && *d != '|') {
01400          switch (*d) {
01401          case 'a':             /* we have to send the initial FSK sequence */
01402             answer = 1;
01403             break;
01404          case 's':             /* we are acting as a service centre talking to a phone */
01405             h.smsc = 1;
01406             break;
01407             /* the following apply if there is an arg3/4 and apply to the created message file */
01408          case 'r':
01409             h.srr = 1;
01410             break;
01411          case 'o':
01412             h.dcs |= 4;       /* octets */
01413             break;
01414          case '1':
01415          case '2':
01416          case '3':
01417          case '4':
01418          case '5':
01419          case '6':
01420          case '7':             /* set the pid for saved local message */
01421             h.pid = 0x40 + (*d & 0xF);
01422             break;
01423          }
01424          d++;
01425       }
01426       if (*d == '|') {
01427          /* submitting a message, not taking call. */
01428          /* deprecated, use smsq instead */
01429          d++;
01430          h.scts = time (0);
01431          for (p = d; *p && *p != '|'; p++);
01432          if (*p)
01433             *p++ = 0;
01434          if (strlen ((char *)d) >= sizeof (h.oa)) {
01435             ast_log (LOG_ERROR, "Address too long %s\n", d);
01436             return 0;
01437          }
01438          if (h.smsc) {
01439             ast_copy_string (h.oa, (char *)d, sizeof (h.oa));
01440          } else {
01441             ast_copy_string (h.da, (char *)d, sizeof (h.da));
01442          }
01443          if (!h.smsc)
01444             ast_copy_string (h.oa, h.cli, sizeof (h.oa));
01445          d = p;
01446          h.udl = 0;
01447          while (*p && h.udl < SMSLEN)
01448             h.ud[h.udl++] = utf8decode(&p);
01449          if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
01450             ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n");
01451          if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
01452             ast_log (LOG_WARNING, "Invalid 8 bit data\n");
01453          if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
01454             ast_log (LOG_WARNING, "Invalid 16 bit data\n");
01455          h.rx = 0;              /* sent message */
01456          h.mr = -1;
01457          sms_writefile (&h);
01458          ast_module_user_remove(u);
01459          return 0;
01460       }
01461 
01462       if (answer) {
01463          /* set up SMS_EST initial message */
01464          h.omsg[0] = 0x93;
01465          h.omsg[1] = 0;
01466          sms_messagetx (&h);
01467       }
01468    }
01469 
01470    if (chan->_state != AST_STATE_UP)
01471       ast_answer (chan);
01472 
01473 #ifdef OUTALAW
01474    res = ast_set_write_format (chan, AST_FORMAT_ALAW);
01475 #else
01476    res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
01477 #endif
01478    if (res >= 0)
01479       res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
01480    if (res < 0) {
01481       ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
01482       ast_module_user_remove(u);
01483       return -1;
01484    }
01485 
01486    if (ast_activate_generator (chan, &smsgen, &h) < 0) {
01487       ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
01488       ast_module_user_remove(u);
01489       return -1;
01490    }
01491 
01492    /* Do our thing here */
01493    while (ast_waitfor (chan, -1) > -1 && !h.hangup)
01494    {
01495       f = ast_read (chan);
01496       if (!f)
01497          break;
01498       if (f->frametype == AST_FRAME_VOICE) {
01499          sms_process (&h, f->samples, f->data);
01500       }
01501 
01502       ast_frfree (f);
01503    }
01504 
01505    sms_log (&h, '?');           /* log incomplete message */
01506 
01507    ast_module_user_remove(u);
01508    return (h.err);
01509 }

static int sms_generate ( struct ast_channel chan,
void *  data,
int  len,
int  samples 
) [static]

Definition at line 1174 of file app_sms.c.

References AST_FORMAT_ALAW, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), f, LOG_WARNING, MAXSAMPLES, sms_s::obitp, sms_s::obyte, sms_s::obyten, sms_s::obytep, sms_s::omsg, sms_s::opause, sms_s::ophase, sms_s::ophasep, sms_s::osync, and SAMPLE2LEN.

01175 {
01176    struct ast_frame f = { 0 };
01177 #define MAXSAMPLES (800)
01178 #ifdef OUTALAW
01179    unsigned char *buf;
01180 #else
01181    short *buf;
01182 #endif
01183 #define SAMPLE2LEN sizeof(*buf)
01184    sms_t *h = data;
01185    int i;
01186 
01187    if (samples > MAXSAMPLES) {
01188       ast_log (LOG_WARNING, "Only doing %d samples (%d requested)\n",
01189           MAXSAMPLES, samples);
01190       samples = MAXSAMPLES;
01191    }
01192    len = samples * SAMPLE2LEN + AST_FRIENDLY_OFFSET;
01193    buf = alloca(len);
01194 
01195    f.frametype = AST_FRAME_VOICE;
01196 #ifdef OUTALAW
01197    f.subclass = AST_FORMAT_ALAW;
01198 #else
01199    f.subclass = AST_FORMAT_SLINEAR;
01200 #endif
01201    f.datalen = samples * SAMPLE2LEN;
01202    f.offset = AST_FRIENDLY_OFFSET;
01203    f.mallocd = 0;
01204    f.data = buf;
01205    f.samples = samples;
01206    f.src = "app_sms";
01207    /* create a buffer containing the digital sms pattern */
01208    for (i = 0; i < samples; i++) {
01209 #ifdef OUTALAW
01210       buf[i] = wavea[0];
01211 #else
01212       buf[i] = wave[0];
01213 #endif
01214       if (h->opause)
01215          h->opause--;
01216       else if (h->obyten || h->osync) {                         /* sending data */
01217 #ifdef OUTALAW
01218          buf[i] = wavea[h->ophase];
01219 #else
01220          buf[i] = wave[h->ophase];
01221 #endif
01222          if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
01223             h->ophase -= 80;
01224          if ((h->ophasep += 12) >= 80) {                     /* next bit */
01225             h->ophasep -= 80;
01226             if (h->osync)
01227                h->osync--;    /* sending sync bits */
01228             else {
01229                h->obyte >>= 1;
01230                h->obitp++;
01231                if (h->obitp == 1)
01232                   h->obyte = 0; /* start bit; */
01233                else if (h->obitp == 2)
01234                   h->obyte = h->omsg[h->obytep];
01235                else if (h->obitp == 10) {
01236                   h->obyte = 1; /* stop bit */
01237                   h->obitp = 0;
01238                   h->obytep++;
01239                   if (h->obytep == h->obyten) {
01240                      h->obytep = h->obyten = 0; /* sent */
01241                      h->osync = 10;   /* trailing marks */
01242                   }
01243                }
01244             }
01245          }
01246       }
01247    }
01248    if (ast_write (chan, &f) < 0) {
01249       ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
01250       return -1;
01251    }
01252    return 0;
01253 #undef SAMPLE2LEN
01254 #undef MAXSAMPLES
01255 }

static unsigned char sms_handleincoming ( sms_t h  )  [static]

handle the incoming message

Definition at line 953 of file app_sms.c.

References ast_log(), sms_s::cli, sms_s::da, sms_s::dcs, sms_s::imsg, LOG_WARNING, sms_s::mr, sms_s::oa, sms_s::pid, sms_s::rp, sms_s::rx, sms_s::scts, sms_writefile(), sms_s::smsc, sms_s::srr, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, sms_s::udl, unpackaddress(), unpackdate(), unpacksms(), and sms_s::vp.

Referenced by sms_messagerx().

00954 {
00955    unsigned char p = 3;
00956    if (h->smsc) {                          /* SMSC */
00957       if ((h->imsg[2] & 3) == 1) {           /* SMS-SUBMIT */
00958          h->udhl = h->udl = 0;
00959          h->vp = 0;
00960          h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
00961          h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
00962          h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
00963          ast_copy_string (h->oa, h->cli, sizeof (h->oa));
00964          h->scts = time (0);
00965          h->mr = h->imsg[p++];
00966          p += unpackaddress (h->da, h->imsg + p);
00967          h->pid = h->imsg[p++];
00968          h->dcs = h->imsg[p++];
00969          if ((h->imsg[2] & 0x18) == 0x10) {                     /* relative VP */
00970             if (h->imsg[p] < 144)
00971                h->vp = (h->imsg[p] + 1) * 5;
00972             else if (h->imsg[p] < 168)
00973                h->vp = 720 + (h->imsg[p] - 143) * 30;
00974             else if (h->imsg[p] < 197)
00975                h->vp = (h->imsg[p] - 166) * 1440;
00976             else
00977                h->vp = (h->imsg[p] - 192) * 10080;
00978             p++;
00979          } else if (h->imsg[2] & 0x18)
00980             p += 7;            /* ignore enhanced / absolute VP */
00981          p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
00982          h->rx = 1;            /* received message */
00983          sms_writefile (h);     /* write the file */
00984          if (p != h->imsg[1] + 2) {
00985             ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
00986             return 0xFF;        /* duh! */
00987          }
00988       } else {
00989          ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
00990          return 0xFF;
00991       }
00992    } else {                          /* client */
00993       if (!(h->imsg[2] & 3)) {                         /* SMS-DELIVER */
00994          *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
00995          h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
00996          h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
00997          h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
00998          h->mr = -1;
00999          p += unpackaddress (h->oa, h->imsg + p);
01000          h->pid = h->imsg[p++];
01001          h->dcs = h->imsg[p++];
01002          h->scts = unpackdate (h->imsg + p);
01003          p += 7;
01004          p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
01005          h->rx = 1;            /* received message */
01006          sms_writefile (h);     /* write the file */
01007          if (p != h->imsg[1] + 2) {
01008             ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
01009             return 0xFF;        /* duh! */
01010          }
01011       } else {
01012          ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
01013          return 0xFF;
01014       }
01015    }
01016    return 0;                    /* no error */
01017 }

static void sms_log ( sms_t h,
char  status 
) [static]

Log the output, and remove file.

Definition at line 635 of file app_sms.c.

References sms_s::da, isodate(), sms_s::mr, sms_s::oa, sms_s::queue, sms_s::rx, sms_s::smsc, sms_s::ud, and sms_s::udl.

Referenced by sms_messagerx().

00636 {
00637    if (*h->oa || *h->da) {
00638       int o = open (log_file, O_CREAT | O_APPEND | O_WRONLY, 0666);
00639       if (o >= 0) {
00640          char line[1000], mrs[3] = "", *p;
00641          unsigned char n;
00642 
00643          if (h->mr >= 0)
00644             snprintf (mrs, sizeof (mrs), "%02X", h->mr);
00645          snprintf (line, sizeof (line), "%s %c%c%c%s %s %s %s ",
00646              isodate (time (0)), status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue, *h->oa ? h->oa : "-",
00647              *h->da ? h->da : "-");
00648          p = line + strlen (line);
00649          for (n = 0; n < h->udl; n++)
00650             if (h->ud[n] == '\\') {
00651                *p++ = '\\';
00652                *p++ = '\\';
00653             } else if (h->ud[n] == '\n') {
00654                *p++ = '\\';
00655                *p++ = 'n';
00656             } else if (h->ud[n] == '\r') {
00657                *p++ = '\\';
00658                *p++ = 'r';
00659             } else if (h->ud[n] < 32 || h->ud[n] == 127)
00660                *p++ = 191;
00661             else
00662                *p++ = h->ud[n];
00663          *p++ = '\n';
00664          *p = 0;
00665          write (o, line, strlen (line));
00666          close (o);
00667       }
00668       *h->oa = *h->da = h->udl = 0;
00669    }
00670 }

static void sms_messagerx ( sms_t h  )  [static]

Definition at line 1104 of file app_sms.c.

References sms_s::err, sms_s::hangup, sms_s::imsg, sms_s::omsg, sms_debug(), sms_handleincoming(), sms_log(), sms_messagetx(), and sms_nextoutgoing().

Referenced by sms_process().

01105 {
01106    sms_debug ("RX", h->imsg);
01107    /* testing */
01108    switch (h->imsg[0]) {
01109    case 0x91:                 /* SMS_DATA */
01110       {
01111          unsigned char cause = sms_handleincoming (h);
01112          if (!cause) {
01113             sms_log (h, 'Y');
01114             h->omsg[0] = 0x95;  /* SMS_ACK */
01115             h->omsg[1] = 0x02;
01116             h->omsg[2] = 0x00;  /* deliver report */
01117             h->omsg[3] = 0x00;  /* no parameters */
01118          } else {                    /* NACK */
01119             sms_log (h, 'N');
01120             h->omsg[0] = 0x96;  /* SMS_NACK */
01121             h->omsg[1] = 3;
01122             h->omsg[2] = 0;     /* delivery report */
01123             h->omsg[3] = cause; /* cause */
01124             h->omsg[4] = 0;     /* no parameters */
01125          }
01126          sms_messagetx (h);
01127       }
01128       break;
01129    case 0x92:                 /* SMS_ERROR */
01130       h->err = 1;
01131       sms_messagetx (h);        /* send whatever we sent again */
01132       break;
01133    case 0x93:                 /* SMS_EST */
01134       sms_nextoutgoing (h);
01135       break;
01136    case 0x94:                 /* SMS_REL */
01137       h->hangup = 1;          /* hangup */
01138       break;
01139    case 0x95:                 /* SMS_ACK */
01140       sms_log (h, 'Y');
01141       sms_nextoutgoing (h);
01142       break;
01143    case 0x96:                 /* SMS_NACK */
01144       h->err = 1;
01145       sms_log (h, 'N');
01146       sms_nextoutgoing (h);
01147       break;
01148    default:                  /* Unknown */
01149       h->omsg[0] = 0x92;        /* SMS_ERROR */
01150       h->omsg[1] = 1;
01151       h->omsg[2] = 3;           /* unknown message type; */
01152       sms_messagetx (h);
01153       break;
01154    }
01155 }

static void sms_messagetx ( sms_t h  )  [static]

Definition at line 1157 of file app_sms.c.

References sms_s::obitp, sms_s::obyte, sms_s::obyten, sms_s::obytep, sms_s::omsg, sms_s::opause, sms_s::osync, and sms_debug().

Referenced by sms_messagerx(), sms_nextoutgoing(), and sms_process().

01158 {
01159    unsigned char c = 0, p;
01160    for (p = 0; p < h->omsg[1] + 2; p++)
01161       c += h->omsg[p];
01162    h->omsg[h->omsg[1] + 2] = 0 - c;
01163    sms_debug ("TX", h->omsg);
01164    h->obyte = 1;
01165    h->opause = 200;
01166    if (h->omsg[0] == 0x93)
01167       h->opause = 2400;       /* initial message delay 300ms (for BT) */
01168    h->obytep = 0;
01169    h->obitp = 0;
01170    h->osync = 80;
01171    h->obyten = h->omsg[1] + 3;
01172 }

static void sms_nextoutgoing ( sms_t h  )  [static]

find and fill in next message, or send a REL if none waiting

Definition at line 1024 of file app_sms.c.

References sms_s::da, sms_s::dcs, f, sms_s::mr, sms_s::oa, sms_s::omsg, packaddress(), packdate(), packsms(), sms_s::pid, sms_s::queue, readdirqueue(), sms_s::rp, sms_s::rx, sms_s::scts, sms_messagetx(), sms_readfile(), sms_s::smsc, sms_s::srr, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, sms_s::udl, and sms_s::vp.

Referenced by sms_messagerx().

01025 {          
01026    char fn[100 + NAME_MAX] = "";
01027    DIR *d;
01028    char more = 0;
01029    ast_copy_string (fn, spool_dir, sizeof (fn));
01030    mkdir (fn, 0777);          /* ensure it exists */
01031    h->rx = 0;                  /* outgoing message */
01032    snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? "mttx" : "motx");
01033    mkdir (fn, 0777);          /* ensure it exists */
01034    d = opendir (fn);
01035    if (d) {
01036       struct dirent *f = readdirqueue (d, h->queue);
01037       if (f) {
01038          snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", f->d_name);
01039          sms_readfile (h, fn);
01040          if (readdirqueue (d, h->queue))
01041             more = 1;           /* more to send */
01042       }
01043       closedir (d);
01044    }
01045    if (*h->da || *h->oa) {                          /* message to send */
01046       unsigned char p = 2;
01047       h->omsg[0] = 0x91;        /* SMS_DATA */
01048       if (h->smsc) {        /* deliver */
01049          h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
01050          p += packaddress (h->omsg + p, h->oa);
01051          h->omsg[p++] = h->pid;
01052          h->omsg[p++] = h->dcs;
01053          packdate (h->omsg + p, h->scts);
01054          p += 7;
01055          p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01056       } else {        /* submit */
01057          h->omsg[p++] =
01058             0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
01059          if (h->mr < 0)
01060             h->mr = message_ref++;
01061          h->omsg[p++] = h->mr;
01062          p += packaddress (h->omsg + p, h->da);
01063          h->omsg[p++] = h->pid;
01064          h->omsg[p++] = h->dcs;
01065          if (h->vp) {       /* relative VP */
01066             if (h->vp < 720)
01067                h->omsg[p++] = (h->vp + 4) / 5 - 1;
01068             else if (h->vp < 1440)
01069                h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
01070             else if (h->vp < 43200)
01071                h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
01072             else if (h->vp < 635040)
01073                h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
01074             else
01075                h->omsg[p++] = 255;     /* max */
01076          }
01077          p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01078       }
01079       h->omsg[1] = p - 2;
01080       sms_messagetx (h);
01081    } else {           /* no message */
01082       h->omsg[0] = 0x94;        /* SMS_REL */
01083       h->omsg[1] = 0;
01084       sms_messagetx (h);
01085    }
01086 }

static void sms_process ( sms_t h,
int  samples,
signed short *  data 
) [static]

Definition at line 1257 of file app_sms.c.

References ast_log(), sms_s::err, sms_s::hangup, sms_s::ibitc, sms_s::ibith, sms_s::ibitl, sms_s::ibitn, sms_s::ibitt, sms_s::ibytec, sms_s::ibytep, sms_s::ibytev, sms_s::idle, sms_s::ierr, sms_s::imag, sms_s::imc0, sms_s::imc1, sms_s::ims0, sms_s::ims1, sms_s::imsg, sms_s::ipc0, sms_s::ipc1, sms_s::iphasep, sms_s::ips0, sms_s::ips1, LOG_EVENT, m1, sms_s::obyten, sms_s::omsg, sms_s::osync, sms_messagerx(), and sms_messagetx().

01258 {
01259    if (h->obyten || h->osync)
01260       return;                  /* sending */
01261    while (samples--) {
01262       unsigned long long m0, m1;
01263       if (abs (*data) > h->imag)
01264          h->imag = abs (*data);
01265       else
01266          h->imag = h->imag * 7 / 8;
01267       if (h->imag > 500) {
01268          h->idle = 0;
01269          h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
01270          h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
01271          h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
01272          h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
01273          m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
01274          m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
01275          if ((h->ips0 += 21) >= 80)
01276             h->ips0 -= 80;
01277          if ((h->ipc0 += 21) >= 80)
01278             h->ipc0 -= 80;
01279          if ((h->ips1 += 13) >= 80)
01280             h->ips1 -= 80;
01281          if ((h->ipc1 += 13) >= 80)
01282             h->ipc1 -= 80;
01283          {
01284             char bit;
01285             h->ibith <<= 1;
01286             if (m1 > m0)
01287                h->ibith |= 1;
01288             if (h->ibith & 8)
01289                h->ibitt--;
01290             if (h->ibith & 1)
01291                h->ibitt++;
01292             bit = ((h->ibitt > 1) ? 1 : 0);
01293             if (bit != h->ibitl)
01294                h->ibitc = 1;
01295             else
01296                h->ibitc++;
01297             h->ibitl = bit;
01298             if (!h->ibitn && h->ibitc == 4 && !bit) {
01299                h->ibitn = 1;
01300                h->iphasep = 0;
01301             }
01302             if (bit && h->ibitc == 200) {                 /* sync, restart message */
01303                h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01304             }
01305             if (h->ibitn) {
01306                h->iphasep += 12;
01307                if (h->iphasep >= 80) {              /* next bit */
01308                   h->iphasep -= 80;
01309                   if (h->ibitn++ == 9) {            /* end of byte */
01310                      if (!bit)  /* bad stop bit */
01311                         h->ierr = 0xFF; /* unknown error */
01312                      else {
01313                         if (h->ibytep < sizeof (h->imsg)) {
01314                            h->imsg[h->ibytep] = h->ibytev;
01315                            h->ibytec += h->ibytev;
01316                            h->ibytep++;
01317                         } else if (h->ibytep == sizeof (h->imsg))
01318                            h->ierr = 2; /* bad message length */
01319                         if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
01320                            if (!h->ibytec)
01321                               sms_messagerx (h);
01322                            else
01323                               h->ierr = 1;      /* bad checksum */
01324                         }
01325                      }
01326                      h->ibitn = 0;
01327                   }
01328                   h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
01329                }
01330             }
01331          }
01332       } else {        /* lost carrier */
01333          if (h->idle++ == 80000) {      /* nothing happening */
01334             ast_log (LOG_EVENT, "No data, hanging up\n");
01335             h->hangup = 1;
01336             h->err = 1;
01337          }
01338          if (h->ierr) {                    /* error */
01339             h->err = 1;
01340             h->omsg[0] = 0x92;  /* error */
01341             h->omsg[1] = 1;
01342             h->omsg[2] = h->ierr;
01343             sms_messagetx (h);  /* send error */
01344          }
01345          h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01346       }
01347       data++;
01348    }
01349 }

static void sms_readfile ( sms_t h,
char *  fn 
) [static]

parse and delete a file

Definition at line 673 of file app_sms.c.

References ast_log(), ast_mktime(), sms_s::da, sms_s::dcs, is16bit, is7bit, is8bit, LOG_EVENT, LOG_WARNING, sms_s::mr, numcpy(), sms_s::oa, packsms16(), packsms7(), packsms8(), sms_s::pid, sms_s::rp, sms_s::rx, S, s, sms_s::scts, SMSLEN, sms_s::srr, t, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, sms_s::udl, utf8decode(), and sms_s::vp.

Referenced by sms_nextoutgoing().

00674 {
00675    char line[1000];
00676    FILE *s;
00677    char dcsset = 0;            /* if DSC set */
00678    ast_log (LOG_EVENT, "Sending %s\n", fn);
00679    h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
00680    h->mr = -1;
00681    h->dcs = 0xF1;             /* normal messages class 1 */
00682    h->scts = time (0);
00683    s = fopen (fn, "r");
00684    if (s)
00685    {
00686       if (unlink (fn))
00687       {                        /* concurrent access, we lost */
00688          fclose (s);
00689          return;
00690       }
00691       while (fgets (line, sizeof (line), s))
00692       {                        /* process line in file */
00693          char *p;
00694          void *pp = &p;
00695          for (p = line; *p && *p != '\n' && *p != '\r'; p++);
00696          *p = 0;               /* strip eoln */
00697          p = line;
00698          if (!*p || *p == ';')
00699             continue;           /* blank line or comment, ignore */
00700          while (isalnum (*p))
00701          {
00702             *p = tolower (*p);
00703             p++;
00704          }
00705          while (isspace (*p))
00706             *p++ = 0;
00707          if (*p == '=')
00708          {
00709             *p++ = 0;
00710             if (!strcmp (line, "ud"))
00711             {                  /* parse message (UTF-8) */
00712                unsigned char o = 0;
00713                while (*p && o < SMSLEN)
00714                   h->ud[o++] = utf8decode(pp);
00715                h->udl = o;
00716                if (*p)
00717                   ast_log (LOG_WARNING, "UD too long in %s\n", fn);
00718             } else
00719             {
00720                while (isspace (*p))
00721                   p++;
00722                if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
00723                   numcpy (h->oa, p);
00724                else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
00725                   numcpy (h->da, p);
00726                else if (!strcmp (line, "pid"))
00727                   h->pid = atoi (p);
00728                else if (!strcmp (line, "dcs"))
00729                {
00730                   h->dcs = atoi (p);
00731                   dcsset = 1;
00732                } else if (!strcmp (line, "mr"))
00733                   h->mr = atoi (p);
00734                else if (!strcmp (line, "srr"))
00735                   h->srr = (atoi (p) ? 1 : 0);
00736                else if (!strcmp (line, "vp"))
00737                   h->vp = atoi (p);
00738                else if (!strcmp (line, "rp"))
00739                   h->rp = (atoi (p) ? 1 : 0);
00740                else if (!strcmp (line, "scts"))
00741                {               /* get date/time */
00742                   int Y,
00743                     m,
00744                     d,
00745                     H,
00746                     M,
00747                     S;
00748                   if (sscanf (p, "%d-%d-%dT%d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6)
00749                   {
00750                      struct tm t;
00751                      t.tm_year = Y - 1900;
00752                      t.tm_mon = m - 1;
00753                      t.tm_mday = d;
00754                      t.tm_hour = H;
00755                      t.tm_min = M;
00756                      t.tm_sec = S;
00757                      t.tm_isdst = -1;
00758                      h->scts = ast_mktime(&t, NULL);
00759                      if (h->scts == (time_t) - 1)
00760                         ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
00761                   }
00762                } else
00763                   ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
00764             }
00765          } else if (*p == '#')
00766          {                     /* raw hex format */
00767             *p++ = 0;
00768             if (*p == '#')
00769             {
00770                p++;
00771                if (!strcmp (line, "ud"))
00772                {               /* user data */
00773                   int o = 0;
00774                   while (*p && o < SMSLEN)
00775                   {
00776                      if (isxdigit (*p) && isxdigit (p[1]) && isxdigit (p[2]) && isxdigit (p[3]))
00777                      {
00778                         h->ud[o++] =
00779                            (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 12) +
00780                            (((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
00781                            (((isalpha (p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha (p[3]) ? 9 : 0) + (p[3] & 0xF));
00782                         p += 4;
00783                      } else
00784                         break;
00785                   }
00786                   h->udl = o;
00787                   if (*p)
00788                      ast_log (LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
00789                } else
00790                   ast_log (LOG_WARNING, "Only ud can use ## format, %s\n", fn);
00791             } else if (!strcmp (line, "ud"))
00792             {                  /* user data */
00793                int o = 0;
00794                while (*p && o < SMSLEN)
00795                {
00796                   if (isxdigit (*p) && isxdigit (p[1]))
00797                   {
00798                      h->ud[o++] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
00799                      p += 2;
00800                   } else
00801                      break;
00802                }
00803                h->udl = o;
00804                if (*p)
00805                   ast_log (LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
00806             } else if (!strcmp (line, "udh"))
00807             {                  /* user data header */
00808                unsigned char o = 0;
00809                h->udhi = 1;
00810                while (*p && o < SMSLEN)
00811                {
00812                   if (isxdigit (*p) && isxdigit (p[1]))
00813                   {
00814                      h->udh[o] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
00815                      o++;
00816                      p += 2;
00817                   } else
00818                      break;
00819                }
00820                h->udhl = o;
00821                if (*p)
00822                   ast_log (LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
00823             } else
00824                ast_log (LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
00825          } else
00826             ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
00827       }
00828       fclose (s);
00829       if (!dcsset && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00830       {
00831          if (packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00832          {
00833             if (packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00834                ast_log (LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
00835             else
00836             {
00837                h->dcs = 0x08; /* default to 16 bit */
00838                ast_log (LOG_WARNING, "Sending in 16 bit format (%s)\n", fn);
00839             }
00840          } else
00841          {
00842             h->dcs = 0xF5;    /* default to 8 bit */
00843             ast_log (LOG_WARNING, "Sending in 8 bit format (%s)\n", fn);
00844          }
00845       }
00846       if (is7bit (h->dcs) && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00847          ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
00848       if (is8bit (h->dcs) && packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00849          ast_log (LOG_WARNING, "Invalid 8 bit data %s\n", fn);
00850       if (is16bit (h->dcs) && packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
00851          ast_log (LOG_WARNING, "Invalid 16 bit data %s\n", fn);
00852    }
00853 }

static void sms_release ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 189 of file app_sms.c.

00190 {
00191    return;
00192 }

static void sms_writefile ( sms_t h  )  [static]

white a received text message to a file

Definition at line 856 of file app_sms.c.

References sms_s::da, isodate(), sms_s::oa, sms_s::queue, sms_s::rx, sms_s::scts, sms_s::smsc, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, and sms_s::udl.

Referenced by sms_handleincoming().

00857 {
00858    char fn[200] = "", fn2[200] = "";
00859    FILE *o;
00860    ast_copy_string (fn, spool_dir, sizeof (fn));
00861    mkdir (fn, 0777);       /* ensure it exists */
00862    snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
00863    mkdir (fn, 0777);       /* ensure it exists */
00864    ast_copy_string (fn2, fn, sizeof (fn2));
00865    snprintf (fn2 + strlen (fn2), sizeof (fn2) - strlen (fn2), "/%s.%s-%d", h->queue, isodate (h->scts), seq++);
00866    snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/.%s", fn2 + strlen (fn) + 1);
00867    o = fopen (fn, "w");
00868    if (o) {
00869       if (*h->oa)
00870          fprintf (o, "oa=%s\n", h->oa);
00871       if (*h->da)
00872          fprintf (o, "da=%s\n", h->da);
00873       if (h->udhi) {
00874          unsigned int p;
00875          fprintf (o, "udh#");
00876          for (p = 0; p < h->udhl; p++)
00877             fprintf (o, "%02X", h->udh[p]);
00878          fprintf (o, "\n");
00879       }
00880       if (h->udl) {
00881          unsigned int p;
00882          for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
00883          if (p < h->udl)
00884             fputc (';', o);     /* cannot use ud=, but include as a comment for human readable */
00885          fprintf (o, "ud=");
00886          for (p = 0; p < h->udl; p++) {
00887             unsigned short v = h->ud[p];
00888             if (v < 32)
00889                fputc (191, o);
00890             else if (v < 0x80)
00891                fputc (v, o);
00892             else if (v < 0x800)
00893             {
00894                fputc (0xC0 + (v >> 6), o);
00895                fputc (0x80 + (v & 0x3F), o);
00896             } else
00897             {
00898                fputc (0xE0 + (v >> 12), o);
00899                fputc (0x80 + ((v >> 6) & 0x3F), o);
00900                fputc (0x80 + (v & 0x3F), o);
00901             }
00902          }
00903          fprintf (o, "\n");
00904          for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
00905          if (p < h->udl) {
00906             for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
00907             if (p == h->udl) {                   /* can write in ucs-1 hex */
00908                fprintf (o, "ud#");
00909                for (p = 0; p < h->udl; p++)
00910                   fprintf (o, "%02X", h->ud[p]);
00911                fprintf (o, "\n");
00912             } else {                 /* write in UCS-2 */
00913                fprintf (o, "ud##");
00914                for (p = 0; p < h->udl; p++)
00915                   fprintf (o, "%04X", h->ud[p]);
00916                fprintf (o, "\n");
00917             }
00918          }
00919       }
00920       if (h->scts)
00921          fprintf (o, "scts=%s\n", isodate (h->scts));
00922       if (h->pid)
00923          fprintf (o, "pid=%d\n", h->pid);
00924       if (h->dcs != 0xF1)
00925          fprintf (o, "dcs=%d\n", h->dcs);
00926       if (h->vp)
00927          fprintf (o, "vp=%d\n", h->vp);
00928       if (h->srr)
00929          fprintf (o, "srr=1\n");
00930       if (h->mr >= 0)
00931          fprintf (o, "mr=%d\n", h->mr);
00932       if (h->rp)
00933          fprintf (o, "rp=1\n");
00934       fclose (o);
00935       if (rename (fn, fn2))
00936          unlink (fn);
00937       else
00938          ast_log (LOG_EVENT, "Received to %s\n", fn2);
00939    }
00940 }

static int unload_module ( void   )  [static]

Definition at line 1511 of file app_sms.c.

References ast_module_user_hangup_all, and ast_unregister_application().

01512 {
01513    int res;
01514 
01515    res = ast_unregister_application (app);
01516    
01517    ast_module_user_hangup_all();
01518 
01519    return res; 
01520 }

static unsigned char unpackaddress ( char *  o,
unsigned char *  i 
) [static]

unpack an address from i, return byte length, unpack to o

Definition at line 593 of file app_sms.c.

Referenced by sms_handleincoming().

00594 {
00595    unsigned char l = i[0],
00596       p;
00597    if (i[1] == 0x91)
00598       *o++ = '+';
00599    for (p = 0; p < l; p++) {
00600       if (p & 1)
00601          *o++ = (i[2 + p / 2] >> 4) + '0';
00602       else
00603          *o++ = (i[2 + p / 2] & 0xF) + '0';
00604    }
00605    *o = 0;
00606    return (l + 5) / 2;
00607 }

static time_t unpackdate ( unsigned char *  i  )  [static]

unpack a date and return

Definition at line 456 of file app_sms.c.

References ast_mktime().

Referenced by sms_handleincoming().

00457 {
00458    struct tm t;
00459    t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
00460    t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
00461    t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
00462    t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
00463    t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
00464    t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
00465    t.tm_isdst = 0;
00466    if (i[6] & 0x08)
00467       t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
00468    else
00469       t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
00470    return ast_mktime(&t, NULL);
00471 }

static int unpacksms ( unsigned char  dcs,
unsigned char *  i,
unsigned char *  udh,
int *  udhl,
unsigned short *  ud,
int *  udl,
char  udhi 
) [static]

general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length

Definition at line 579 of file app_sms.c.

References is7bit, is8bit, unpacksms16(), unpacksms7(), and unpacksms8().

Referenced by sms_handleincoming().

00580 {
00581    int l = *i++;
00582    if (is7bit (dcs)) {
00583       unpacksms7 (i, l, udh, udhl, ud, udl, udhi);
00584       l = (l * 7 + 7) / 8;    /* adjust length to return */
00585    } else if (is8bit (dcs))
00586       unpacksms8 (i, l, udh, udhl, ud, udl, udhi);
00587    else
00588       unpacksms16 (i, l, udh, udhl, ud, udl, udhi);
00589    return l + 1;
00590 }

static void unpacksms16 ( unsigned char *  i,
unsigned char  l,
unsigned char *  udh,
int *  udhl,
unsigned short *  ud,
int *  udl,
char  udhi 
) [static]

unpacks bytes (16 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set

Definition at line 552 of file app_sms.c.

Referenced by unpacksms().

00553 {
00554    unsigned short *o = ud;
00555    *udhl = 0;
00556    if (udhi) {
00557       int n = *i;
00558       *udhl = n;
00559       if (n) {
00560          i++;
00561          l--;
00562          while (l && n) {
00563             l--;
00564             n--;
00565             *udh++ = *i++;
00566          }
00567       }
00568    }
00569    while (l--) {
00570       int v = *i++;
00571       if (l--)
00572          v = (v << 8) + *i++;
00573       *o++ = v;
00574    }
00575    *udl = (o - ud);
00576 }

static void unpacksms7 ( unsigned char *  i,
unsigned char  l,
unsigned char *  udh,
int *  udhl,
unsigned short *  ud,
int *  udl,
char  udhi 
) [static]

unpacks bytes (7 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set

Definition at line 476 of file app_sms.c.

Referenced by unpacksms().

00477 {
00478    unsigned char b = 0, p = 0;
00479    unsigned short *o = ud;
00480    *udhl = 0;
00481    if (udhi && l) {      /* header */
00482       int h = i[p];
00483       *udhl = h;
00484       if (h) {
00485          b = 1;
00486          p++;
00487          l--;
00488          while (h-- && l) {
00489             *udh++ = i[p++];
00490             b += 8;
00491             while (b >= 7) {
00492                b -= 7;
00493                l--;
00494                if (!l)
00495                   break;
00496             }
00497          }
00498          /* adjust for fill, septets */
00499          if (b) {
00500             b = 7 - b;
00501             l--;
00502          }
00503       }
00504    }
00505    while (l--) {
00506       unsigned char v;
00507       if (b < 2)
00508          v = ((i[p] >> b) & 0x7F);
00509       else
00510          v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
00511       b += 7;
00512       if (b >= 8) {
00513          b -= 8;
00514          p++;
00515       }
00516       if (o > ud && o[-1] == 0x00A0 && escapes[v])
00517          o[-1] = escapes[v];
00518       else
00519          *o++ = defaultalphabet[v];
00520    }
00521    *udl = (o - ud);
00522 }

static void unpacksms8 ( unsigned char *  i,
unsigned char  l,
unsigned char *  udh,
int *  udhl,
unsigned short *  ud,
int *  udl,
char  udhi 
) [static]

unpacks bytes (8 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set

Definition at line 527 of file app_sms.c.

Referenced by unpacksms().

00528 {
00529    unsigned short *o = ud;
00530    *udhl = 0;
00531    if (udhi) {
00532       int n = *i;
00533       *udhl = n;
00534       if (n) {
00535          i++;
00536          l--;
00537          while (l && n) {
00538             l--;
00539             n--;
00540             *udh++ = *i++;
00541          }
00542       }
00543    }
00544    while (l--)
00545       *o++ = *i++;     /* not to UTF-8 as explicitly 8 bit coding in DCS */
00546    *udl = (o - ud);
00547 }

static long utf8decode ( unsigned char **  pp  )  [static]

reads next UCS character from null terminated UTF-8 string and advanced pointer

Definition at line 220 of file app_sms.c.

Referenced by sms_readfile().

00221 {
00222    unsigned char *p = *pp;
00223    if (!*p)
00224       return 0;                 /* null termination of string */
00225    (*pp)++;
00226    if (*p < 0xC0)
00227       return *p;                /* ascii or continuation character */
00228    if (*p < 0xE0) {
00229       if (*p < 0xC2 || (p[1] & 0xC0) != 0x80)
00230          return *p;             /* not valid UTF-8 */
00231       (*pp)++;
00232       return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
00233       }
00234    if (*p < 0xF0) {
00235       if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80)
00236           return *p;             /* not valid UTF-8 */
00237       (*pp) += 2;
00238       return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
00239    }
00240    if (*p < 0xF8) {
00241       if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80)
00242          return *p;             /* not valid UTF-8 */
00243       (*pp) += 3;
00244       return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
00245    }
00246    if (*p < 0xFC) {
00247       if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
00248          || (p[4] & 0xC0) != 0x80)
00249          return *p;             /* not valid UTF-8 */
00250       (*pp) += 4;
00251       return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
00252    }
00253    if (*p < 0xFE) {
00254       if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
00255          || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80)
00256          return *p;             /* not valid UTF-8 */
00257       (*pp) += 5;
00258       return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F);
00259    }
00260    return *p;                   /* not sensible */
00261 }


Variable Documentation

char* app = "SMS" [static]

Definition at line 64 of file app_sms.c.

const unsigned short defaultalphabet[] [static]

Definition at line 98 of file app_sms.c.

char* descrip [static]

Definition at line 68 of file app_sms.c.

const unsigned short escapes[] [static]

Definition at line 111 of file app_sms.c.

char log_file[255] [static]

Definition at line 61 of file app_sms.c.

volatile unsigned char message_ref [static]

Definition at line 58 of file app_sms.c.

volatile unsigned int seq [static]

Definition at line 59 of file app_sms.c.

Referenced by ast_udptl_write(), handle_link_data(), handle_remote_data(), and udptl_build_packet().

struct ast_generator smsgen [static]

Initial value:

 {
   alloc:sms_alloc,
   release:sms_release,
   generate:sms_generate,
}

Definition at line 1351 of file app_sms.c.

char spool_dir[255] [static]

Definition at line 62 of file app_sms.c.

char* synopsis = "Communicates with SMS service centres and SMS capable analogue phones" [static]

Definition at line 66 of file app_sms.c.

signed short wave[] [static]

Definition at line 83 of file app_sms.c.

Referenced by festival_exec().


Generated on Mon Mar 31 07:38:48 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1