Sat Nov 1 06:28:46 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