Thu Jul 9 13:40:49 2009

Asterisk developer's documentation


app_sms.c File Reference

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

#include "asterisk.h"
#include <dirent.h>
#include <ctype.h>
#include <sys/stat.h>
#include "asterisk/paths.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/alaw.h"
#include "asterisk/callerid.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"

Go to the source code of this file.

Data Structures

struct  sms_s

Defines

#define __OUT_FMT   AST_FORMAT_SLINEAR
#define DIR_RX   1
#define DIR_TX   2
#define DLL2_ACK(h)   ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1)
#define is16bit(dcs)   ( ((dcs) & 0xC0) ? 0 : (((dcs) & 0xc) == 8) )
#define is7bit(dcs)   ( ((dcs) & 0xC0) ? (!((dcs)&4) ) : (((dcs) & 0xc) == 0) )
#define is8bit(dcs)   ( ((dcs) & 0xC0) ? ( ((dcs)&4) ) : (((dcs) & 0xc) == 4) )
#define MAX_DEBUG_LEN   300
#define MAXSAMPLES   (800)
#define OSYNC_BITS   80
#define SMSLEN   160
#define SMSLEN_8   140

Typedefs

typedef signed short output_t
typedef sms_s sms_t

Enumerations

enum  {
  OPTION_BE_SMSC = (1 << 0), OPTION_ANSWER = (1 << 1), OPTION_TWO = (1 << 2), OPTION_PAUSE = (1 << 3),
  OPTION_SRR = (1 << 4), OPTION_DCS = (1 << 5)
}
enum  { OPTION_ARG_PAUSE = 0, OPTION_ARG_ARRAY_SIZE }
enum  message_types {
  DLL_SMS_MASK = 0x7f, DLL1_SMS_DATA = 0x11, DLL1_SMS_ERROR = 0x12, DLL1_SMS_EST = 0x13,
  DLL1_SMS_REL = 0x14, DLL1_SMS_ACK = 0x15, DLL1_SMS_NACK = 0x16, DLL1_SMS_COMPLETE = 0x80,
  DLL1_SMS_MORE = 0x00, DLL2_SMS_EST = 0x7f, DLL2_SMS_INFO_MO = 0x10, DLL2_SMS_INFO_MT = 0x11,
  DLL2_SMS_INFO_STA = 0x12, DLL2_SMS_NACK = 0x13, DLL2_SMS_ACK0 = 0x14, DLL2_SMS_ACK1 = 0x15,
  DLL2_SMS_ENQ = 0x16, DLL2_SMS_REL = 0x17, DLL2_SMS_COMPLETE = 0x00, DLL2_SMS_MORE = 0x80
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void adddata_proto2 (sms_t *h, unsigned char msg, char *data, int size)
static char * isodate (time_t t, char *buf, int len)
 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. 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 void putdummydata_proto2 (sms_t *h)
static struct dirent * readdirqueue (DIR *d, char *queue)
 read dir skipping dot files...
static void * sms_alloc (struct ast_channel *chan, void *sms_t_ptr)
static void sms_compose1 (sms_t *h, int more)
 compose a message for protocol 1
static void sms_compose2 (sms_t *h, int more)
static void sms_debug (int dir, sms_t *h)
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 int sms_handleincoming_proto2 (sms_t *h)
 sms_handleincoming_proto2: handle the incoming message
static char * sms_hexdump (unsigned char buf[], int size, char *s)
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_messagerx2 (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 struct timeval 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 NUL terminated UTF-8 string and advance pointer.

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "SMS/PSTN handler" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, }
static char * app = "SMS"
static const struct ast_module_infoast_module_info = &__mod_info
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
enum { ... }  sms_flags
enum { ... }  sms_opt_args
static struct ast_app_option sms_options [128] = { [ 's' ] = { .flag = OPTION_BE_SMSC }, [ 'a' ] = { .flag = OPTION_ANSWER }, [ 't' ] = { .flag = OPTION_TWO }, [ 'r' ] = { .flag = OPTION_SRR }, [ 'o' ] = { .flag = OPTION_DCS }, [ 'p' ] = { .flag = OPTION_PAUSE , .arg_index = OPTION_ARG_PAUSE + 1 }, }
static struct ast_generator smsgen
static char * synopsis = "Communicates with SMS service centres and SMS capable analogue phones"
static signed short wave []
static const output_twave_out = wave


Detailed Description

SMS application - ETSI ES 201 912 protocol 1 implementation.

Development notes
Note:
The ETSI standards are available free of charge from ETSI at http://pda.etsi.org/pda/queryform.asp Among the relevant documents here we have:
ES 201 912 SMS for PSTN/ISDN TS 123 040 Technical realization of SMS

Author:
Adrian Kennard (for the original protocol 1 code)

Filippo Grassilli (Hyppo) - protocol 2 support Not fully tested, under development

Definition in file app_sms.c.


Define Documentation

#define __OUT_FMT   AST_FORMAT_SLINEAR

Definition at line 121 of file app_sms.c.

Referenced by sms_generate().

#define DIR_RX   1

Definition at line 1370 of file app_sms.c.

Referenced by sms_debug(), and sms_messagerx().

#define DIR_TX   2

Definition at line 1371 of file app_sms.c.

Referenced by sms_messagetx().

#define DLL2_ACK (  )     ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1)

Referenced by sms_messagerx2().

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

Definition at line 253 of file app_sms.c.

Referenced by sms_readfile().

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

Definition at line 251 of file app_sms.c.

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

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

Definition at line 252 of file app_sms.c.

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

#define MAX_DEBUG_LEN   300

Definition at line 1146 of file app_sms.c.

Referenced by sms_handleincoming_proto2(), and sms_hexdump().

#define MAXSAMPLES   (800)

Referenced by sms_generate().

#define OSYNC_BITS   80

Definition at line 124 of file app_sms.c.

#define SMSLEN   160

max SMS length

Definition at line 187 of file app_sms.c.

Referenced by packsms7(), and sms_readfile().

#define SMSLEN_8   140

max SMS length for 8-bit char

Definition at line 188 of file app_sms.c.

Referenced by packsms16(), and packsms8().


Typedef Documentation

typedef signed short output_t

Definition at line 119 of file app_sms.c.

typedef struct sms_s sms_t


Enumeration Type Documentation

anonymous enum

Enumerator:
OPTION_BE_SMSC 
OPTION_ANSWER 
OPTION_TWO 
OPTION_PAUSE 
OPTION_SRR 
OPTION_DCS 

Definition at line 1718 of file app_sms.c.

01718      {
01719    OPTION_BE_SMSC = (1 << 0), /* act as sms center */
01720    OPTION_ANSWER  = (1 << 1), /* answer on incoming calls */
01721    OPTION_TWO  = (1 << 2), /* Use Protocol Two */
01722    OPTION_PAUSE   = (1 << 3), /* pause before sending data, in ms */
01723    OPTION_SRR  = (1 << 4), /* set srr */
01724    OPTION_DCS  = (1 << 5), /* set dcs */
01725 } sms_flags;

anonymous enum

Enumerator:
OPTION_ARG_PAUSE 
OPTION_ARG_ARRAY_SIZE 

Definition at line 1727 of file app_sms.c.

01727      {
01728    OPTION_ARG_PAUSE = 0,
01729    OPTION_ARG_ARRAY_SIZE
01730 } sms_opt_args;

enum message_types

The SMS spec ETSI ES 201 912 defines two protocols with different message types. Also note that the high bit is used to indicate whether the message is complete or not, but in two opposite ways: for Protocol 1, 0x80 means that the message is complete; for Protocol 2, 0x00 means that the message is complete;

Enumerator:
DLL_SMS_MASK 
DLL1_SMS_DATA 
DLL1_SMS_ERROR 
DLL1_SMS_EST 
DLL1_SMS_REL 
DLL1_SMS_ACK 
DLL1_SMS_NACK 
DLL1_SMS_COMPLETE 
DLL1_SMS_MORE 
DLL2_SMS_EST 
DLL2_SMS_INFO_MO 
DLL2_SMS_INFO_MT 
DLL2_SMS_INFO_STA 
DLL2_SMS_NACK 
DLL2_SMS_ACK0 
DLL2_SMS_ACK1 
DLL2_SMS_ENQ 
DLL2_SMS_REL 
DLL2_SMS_COMPLETE 
DLL2_SMS_MORE 

Definition at line 133 of file app_sms.c.

00133                    {
00134    DLL_SMS_MASK   = 0x7f,  /* mask for the valid bits */
00135 
00136    /* Protocol 1 values */
00137    DLL1_SMS_DATA     = 0x11,  /* data packet */
00138    DLL1_SMS_ERROR    = 0x12,
00139    DLL1_SMS_EST      = 0x13,  /* start the connection */
00140    DLL1_SMS_REL      = 0x14,  /* end the connection */
00141    DLL1_SMS_ACK      = 0x15,
00142    DLL1_SMS_NACK     = 0x16,
00143 
00144    DLL1_SMS_COMPLETE    = 0x80,  /* packet is complete */
00145    DLL1_SMS_MORE     = 0x00,  /* more data to follow */
00146 
00147    /* Protocol 2 values */
00148    DLL2_SMS_EST      = 0x7f,  /* magic number. No message body */
00149    DLL2_SMS_INFO_MO  = 0x10,
00150    DLL2_SMS_INFO_MT  = 0x11,
00151    DLL2_SMS_INFO_STA    = 0x12,
00152    DLL2_SMS_NACK     = 0x13,
00153    DLL2_SMS_ACK0     = 0x14,  /* ack even-numbered frame */
00154    DLL2_SMS_ACK1     = 0x15,  /* ack odd-numbered frame */
00155    DLL2_SMS_ENQ      = 0x16,
00156    DLL2_SMS_REL      = 0x17,  /* end the connection */
00157 
00158    DLL2_SMS_COMPLETE    = 0x00,  /* packet is complete */
00159    DLL2_SMS_MORE     = 0x80,  /* more data to follow */
00160 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1936 of file app_sms.c.

static void __unreg_module ( void   )  [static]

Definition at line 1936 of file app_sms.c.

static void adddata_proto2 ( sms_t h,
unsigned char  msg,
char *  data,
int  size 
) [static]

Add data to a protocol 2 message. Use the length field (h->omsg[1]) as a pointer to the next free position.

Definition at line 1090 of file app_sms.c.

References sms_s::omsg.

Referenced by putdummydata_proto2(), and sms_compose2().

01091 {
01092    int x = h->omsg[1]+2;   /* Get current position */
01093    if (x == 2)
01094       x += 2;     /* First: skip Payload length (set later) */
01095    h->omsg[x++] = msg;  /* Message code */
01096    h->omsg[x++] = (unsigned char)size;       /* Data size Low */
01097    h->omsg[x++] = 0;  /* Data size Hi */
01098    for (; size > 0 ; size--)
01099       h->omsg[x++] = *data++;
01100    h->omsg[1] = x - 2;  /* Frame size */
01101    h->omsg[2] = x - 4;  /* Payload length (Lo) */
01102    h->omsg[3] = 0;      /* Payload length (Hi) */
01103 }

static char* isodate ( time_t  t,
char *  buf,
int  len 
) [static]

static, return a date/time in ISO format

Definition at line 271 of file app_sms.c.

References ast_localtime(), and ast_strftime().

Referenced by sms_log(), and sms_writefile().

00272 {
00273    struct ast_tm tm;
00274    struct timeval tv = { t, 0 };
00275    ast_localtime(&tv, &tm, NULL);
00276    ast_strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm);
00277    return buf;
00278 }

static int load_module ( void   )  [static]

Definition at line 1925 of file app_sms.c.

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

01926 {
01927 #ifdef OUTALAW
01928    int p;
01929    for (p = 0; p < 80; p++)
01930       wavea[p] = AST_LIN2A (wave[p]);
01931 #endif
01932    snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR);
01933    return ast_register_application(app, sms_exec, synopsis, descrip);
01934 }

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

copy number, skipping non digits apart from leading +

Definition at line 258 of file app_sms.c.

Referenced by sms_readfile().

00259 {
00260    if (*s == '+')
00261       *d++ = *s++;
00262    while (*s) {
00263       if (isdigit(*s))
00264             *d++ = *s;
00265       s++;
00266    }
00267    *d = 0;
00268 }

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

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

Definition at line 688 of file app_sms.c.

Referenced by sms_compose1().

00689 {
00690    unsigned char p = 2;
00691    o[0] = 0;      /* number of bytes */
00692    if (*i == '+') {  /* record as bit 0 in byte 1 */
00693       i++;
00694       o[1] = 0x91;
00695    } else
00696       o[1] = 0x81;
00697    for ( ; *i ; i++) {
00698       if (!isdigit(*i)) /* ignore non-digits */
00699          continue;
00700       if (o[0] & 1)
00701          o[p++] |= ((*i & 0xF) << 4);
00702       else
00703          o[p] = (*i & 0xF);
00704       o[0]++;
00705    }
00706    if (o[0] & 1)
00707       o[p++] |= 0xF0;           /* pad */
00708    return p;
00709 }

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

pack a date and return

Definition at line 506 of file app_sms.c.

References ast_localtime(), ast_tm::tm_gmtoff, ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, and ast_tm::tm_year.

Referenced by sms_compose1().

00507 {
00508    struct ast_tm t;
00509    struct timeval tv = { w, 0 };
00510    int z;
00511 
00512    ast_localtime(&tv, &t, NULL);
00513 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) || defined(__CYGWIN__)
00514    z = -t.tm_gmtoff / 60 / 15;
00515 #else
00516    z = timezone / 60 / 15;
00517 #endif
00518    *o++ = ((t.tm_year % 10) << 4) + (t.tm_year % 100) / 10;
00519    *o++ = (((t.tm_mon + 1) % 10) << 4) + (t.tm_mon + 1) / 10;
00520    *o++ = ((t.tm_mday % 10) << 4) + t.tm_mday / 10;
00521    *o++ = ((t.tm_hour % 10) << 4) + t.tm_hour / 10;
00522    *o++ = ((t.tm_min % 10) << 4) + t.tm_min / 10;
00523    *o++ = ((t.tm_sec % 10) << 4) + t.tm_sec / 10;
00524    if (z < 0)
00525       *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
00526    else
00527       *o++ = ((z % 10) << 4) + z / 10;
00528 }

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 473 of file app_sms.c.

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

Referenced by sms_compose1().

00474 {
00475    unsigned char *p = base;
00476    if (udl == 0)
00477       *p++ = 0;         /* no user data */
00478    else {
00479       
00480       int l = 0;
00481       if (is7bit(dcs)) {      /* 7 bit */
00482          l = packsms7(p + 1, udhl, udh, udl, ud);
00483          if (l < 0)
00484             l = 0;
00485          *p++ = l;
00486          p += (l * 7 + 7) / 8;
00487       } else if (is8bit(dcs)) {  /* 8 bit */
00488          l = packsms8(p + 1, udhl, udh, udl, ud);
00489          if (l < 0)
00490             l = 0;
00491          *p++ = l;
00492          p += l;
00493       } else {       /* UCS-2 */
00494          l = packsms16(p + 1, udhl, udh, udl, ud);
00495          if (l < 0)
00496             l = 0;
00497          *p++ = l;
00498          p += l;
00499       }
00500    }
00501    return p - base;
00502 }

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 442 of file app_sms.c.

References dummy(), and SMSLEN_8.

Referenced by packsms(), and sms_readfile().

00443 {
00444    unsigned char p = 0;
00445    unsigned char dummy[SMSLEN_8];
00446 
00447    if (o == NULL)
00448       o = dummy;
00449    /* header - no encoding */
00450    if (udhl) {
00451       o[p++] = udhl;
00452       while (udhl--) {
00453          o[p++] = *udh++;
00454          if (p >= SMSLEN_8)
00455             return p;
00456       }
00457    }
00458    while (udl--) {
00459       long u;
00460       u = *ud++;
00461       o[p++] = (u >> 8);
00462       if (p >= SMSLEN_8)
00463          return p - 1;    /* could not fit last character */
00464       o[p++] = u;
00465       if (p >= SMSLEN_8)
00466          return p;
00467    }
00468    return p;
00469 }

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 330 of file app_sms.c.

References dummy(), and SMSLEN.

Referenced by packsms(), and sms_readfile().

00331 {
00332    unsigned char p = 0; /* output pointer (bytes) */
00333    unsigned char b = 0; /* bit position */
00334    unsigned char n = 0; /* output character count */
00335    unsigned char dummy[SMSLEN];
00336 
00337    if (o == NULL)    /* output to a dummy buffer if o not set */
00338       o = dummy;
00339 
00340    if (udhl) {           /* header */
00341       o[p++] = udhl;
00342       b = 1;
00343       n = 1;
00344       while (udhl--) {
00345          o[p++] = *udh++;
00346          b += 8;
00347          while (b >= 7) {
00348             b -= 7;
00349             n++;
00350          }
00351          if (n >= SMSLEN)
00352             return n;
00353       }
00354       if (b) {
00355          b = 7 - b;
00356          if (++n >= SMSLEN)
00357             return n;
00358       }; /* filling to septet boundary */
00359    }
00360    o[p] = 0;
00361    /* message */
00362    while (udl--) {
00363       long u;
00364       unsigned char v;
00365       u = *ud++;
00366       /* XXX 0 is invalid ? */
00367       /* look up in defaultalphabet[]. If found, v is the 7-bit code */
00368       for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
00369       if (v == 128 /* not found */ && u && n + 1 < SMSLEN) {
00370          /* if not found, look in the escapes table (we need 2 bytes) */
00371          for (v = 0; v < 128 && escapes[v] != u; v++);
00372          if (v < 128) { /* escaped sequence, esc + v */
00373             /* store the low (8-b) bits in o[p], the remaining bits in o[p+1] */
00374             o[p] |= (27 << b);   /* the low bits go into o[p] */ 
00375             b += 7;
00376             if (b >= 8) {
00377                b -= 8;
00378                p++;
00379                o[p] = (27 >> (7 - b));
00380             }
00381             n++;
00382          }
00383       }
00384       if (v == 128)
00385          return -1;       /* invalid character */
00386       /* store, same as above */
00387       o[p] |= (v << b);
00388       b += 7;
00389       if (b >= 8) {
00390          b -= 8;
00391          p++;
00392          o[p] = (v >> (7 - b));
00393       }
00394       if (++n >= SMSLEN)
00395          return n;
00396    }
00397    return n;
00398 }

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. 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 406 of file app_sms.c.

References dummy(), and SMSLEN_8.

Referenced by packsms(), and sms_readfile().

00407 {
00408    unsigned char p = 0;
00409    unsigned char dummy[SMSLEN_8];
00410 
00411    if (o == NULL)
00412       o = dummy;
00413    /* header - no encoding */
00414    if (udhl) {
00415       o[p++] = udhl;
00416       while (udhl--) {
00417          o[p++] = *udh++;
00418          if (p >= SMSLEN_8)
00419             return p;
00420       }
00421    }
00422    while (udl--) {
00423       long u;
00424       u = *ud++;
00425       if (u < 0 || u > 0xFF)
00426          return -1;       /* not valid */
00427       o[p++] = u;
00428       if (p >= SMSLEN_8)
00429          return p;
00430    }
00431    return p;
00432 }

static void putdummydata_proto2 ( sms_t h  )  [static]

Definition at line 1105 of file app_sms.c.

References adddata_proto2(), sms_s::udl, and sms_s::udtxt.

Referenced by sms_compose2().

01106 {
01107    adddata_proto2(h, 0x10, "\0", 1);         /* Media Identifier > SMS */
01108    adddata_proto2(h, 0x11, "\0\0\0\0\0\0", 6);    /* Firmware version */
01109    adddata_proto2(h, 0x12, "\2\0\4", 3);    /* SMS provider ID */
01110    adddata_proto2(h, 0x13, h->udtxt, h->udl);     /* Body */
01111 }

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

read dir skipping dot files...

Definition at line 1006 of file app_sms.c.

References f.

Referenced by sms_nextoutgoing().

01007 {
01008    struct dirent *f;
01009    do {
01010       f = readdir(d);
01011    } while (f && (*f->d_name == '.' || strncmp(f->d_name, queue, strlen(queue)) || f->d_name[strlen(queue)] != '.'));
01012    return f;
01013 }

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

Just return the pointer to the descriptor that we received.

Definition at line 1560 of file app_sms.c.

01561 {
01562    return sms_t_ptr;
01563 }

static void sms_compose1 ( sms_t h,
int  more 
) [static]

compose a message for protocol 1

Definition at line 1292 of file app_sms.c.

References sms_s::da, sms_s::dcs, sms_s::mr, sms_s::oa, sms_s::omsg, packaddress(), packdate(), packsms(), sms_s::pid, sms_s::rp, sms_s::scts, 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_nextoutgoing().

01293 {
01294    unsigned int p = 2;  /* next byte to write. Skip type and len */
01295 
01296    h->omsg[0] = 0x91;        /* SMS_DATA */
01297    if (h->smsc) {        /* deliver */
01298       h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
01299       p += packaddress(h->omsg + p, h->oa);
01300       h->omsg[p++] = h->pid;
01301       h->omsg[p++] = h->dcs;
01302       packdate(h->omsg + p, h->scts.tv_sec);
01303       p += 7;
01304       p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01305    } else {        /* submit */
01306       h->omsg[p++] =
01307          0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
01308       if (h->mr < 0)
01309          h->mr = message_ref++;
01310       h->omsg[p++] = h->mr;
01311       p += packaddress(h->omsg + p, h->da);
01312       h->omsg[p++] = h->pid;
01313       h->omsg[p++] = h->dcs;
01314       if (h->vp) {       /* relative VP */
01315          if (h->vp < 720)
01316             h->omsg[p++] = (h->vp + 4) / 5 - 1;
01317          else if (h->vp < 1440)
01318             h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
01319          else if (h->vp < 43200)
01320             h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
01321          else if (h->vp < 635040)
01322             h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
01323          else
01324             h->omsg[p++] = 255;     /* max */
01325       }
01326       p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01327    }
01328    h->omsg[1] = p - 2;
01329 }

static void sms_compose2 ( sms_t h,
int  more 
) [static]

Definition at line 1113 of file app_sms.c.

References adddata_proto2(), ast_localtime(), sms_s::da, sms_s::oa, sms_s::omsg, putdummydata_proto2(), sms_s::scts, sms_s::smsc, ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, and ast_tm::tm_mon.

Referenced by sms_nextoutgoing().

01114 {
01115    struct ast_tm tm;
01116    struct timeval tv = h->scts;
01117    char stm[9];
01118 
01119    h->omsg[0] = 0x00;       /* set later... */
01120    h->omsg[1] = 0;
01121    putdummydata_proto2(h);
01122    if (h->smsc) {      /* deliver */
01123       h->omsg[0] = 0x11;      /* SMS_DELIVERY */
01124       /* Required: 10 11 12 13 14 15 17 (seems they must be ordered!) */
01125       ast_localtime(&tv, &tm, NULL);
01126       sprintf(stm, "%02d%02d%02d%02d", tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min);     /* Date mmddHHMM */
01127       adddata_proto2(h, 0x14, stm, 8);        /* Date */
01128       if (*h->oa == 0)
01129          strcpy(h->oa, "00000000");
01130       adddata_proto2(h, 0x15, h->oa, strlen(h->oa)); /* Originator */
01131       adddata_proto2(h, 0x17, "\1", 1);         /* Calling Terminal ID */
01132    } else {       /* submit */
01133       h->omsg[0] = 0x10;      /* SMS_SUBMIT */
01134       /* Required: 10 11 12 13 17 18 1B 1C (seems they must be ordered!) */
01135       adddata_proto2(h, 0x17, "\1", 1);         /* Calling Terminal ID */
01136       if (*h->da == 0)
01137          strcpy(h->da, "00000000");
01138       adddata_proto2(h, 0x18, h->da, strlen(h->da)); /* Originator */
01139       adddata_proto2(h, 0x1B, "\1", 1);         /* Called Terminal ID */
01140       adddata_proto2(h, 0x1C, "\0\0\0", 3);    /* Notification */
01141    }
01142 }

static void sms_debug ( int  dir,
sms_t h 
) [static]

Definition at line 1372 of file app_sms.c.

References ast_verb, DIR_RX, sms_s::ibytep, sms_s::imsg, msg, and sms_s::omsg.

Referenced by sms_messagerx(), and sms_messagetx().

01373 {
01374    char txt[259 * 3 + 1];
01375    char *p = txt;                 /* always long enough */
01376    unsigned char *msg = (dir == DIR_RX) ? h->imsg : h->omsg;
01377    int n = (dir == DIR_RX) ? h->ibytep : msg[1] + 2;
01378    int q = 0;
01379    while (q < n && q < 30) {
01380       sprintf(p, " %02X", msg[q++]);
01381       p += 3;
01382    }
01383    if (q < n)
01384       sprintf(p, "...");
01385    ast_verb(3, "SMS %s%s\n", dir == DIR_RX ? "RX" : "TX", txt);
01386 }

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

Definition at line 1741 of file app_sms.c.

References AST_APP_ARG, ast_app_parse_options(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, chan, ast_channel::cid, ast_callerid::cid_num, sms_s::cli, sms_s::dcs, sms_s::ipc0, sms_s::ipc1, LOG_ERROR, sms_s::opause_0, OPTION_ARG_ARRAY_SIZE, OPTION_ARG_PAUSE, OPTION_BE_SMSC, OPTION_DCS, OPTION_SRR, OPTION_TWO, parse(), sms_s::pid, sms_s::protocol, sms_s::queue, S_OR, sms_flags, sms_options, sms_s::smsc, and sms_s::srr.

Referenced by load_module().

01742 {
01743    int res = -1;
01744    sms_t h = { 0 };
01745    /* argument parsing support */
01746    struct ast_flags sms_flags;
01747    char *parse, *sms_opts[OPTION_ARG_ARRAY_SIZE] = { 0, };
01748    char *p;
01749    AST_DECLARE_APP_ARGS(sms_args,
01750       AST_APP_ARG(queue);
01751       AST_APP_ARG(options);
01752       AST_APP_ARG(addr);
01753       AST_APP_ARG(body);
01754    );
01755 
01756    if (!data) {
01757       ast_log(LOG_ERROR, "Requires queue name at least\n");
01758       return -1;
01759    }
01760 
01761    parse = ast_strdupa(data); /* create a local copy */
01762    AST_STANDARD_APP_ARGS(sms_args, parse);
01763    if (sms_args.argc > 1)
01764       ast_app_parse_options(sms_options, &sms_flags, sms_opts, sms_args.options);
01765 
01766    ast_verb(1, "sms argc %d queue <%s> opts <%s> addr <%s> body <%s>\n",
01767       sms_args.argc, S_OR(sms_args.queue, ""),
01768       S_OR(sms_args.options, ""),
01769       S_OR(sms_args.addr, ""),
01770       S_OR(sms_args.body, "") );
01771 
01772    h.ipc0 = h.ipc1 = 20;      /* phase for cosine */
01773    h.dcs = 0xF1;        /* default */
01774 
01775    if (chan->cid.cid_num)
01776       ast_copy_string(h.cli, chan->cid.cid_num, sizeof(h.cli));
01777 
01778    if (ast_strlen_zero(sms_args.queue)) {
01779       ast_log(LOG_ERROR, "Requires queue name\n");
01780       goto done;
01781    }
01782    if (strlen(sms_args.queue) >= sizeof(h.queue)) {
01783       ast_log(LOG_ERROR, "Queue name too long\n");
01784       goto done;
01785    }
01786    ast_copy_string(h.queue, sms_args.queue, sizeof(h.queue));
01787 
01788    for (p = h.queue; *p; p++)
01789       if (!isalnum(*p))
01790          *p = '-';           /* make very safe for filenames */
01791 
01792    h.smsc = ast_test_flag(&sms_flags, OPTION_BE_SMSC);
01793    h.protocol = ast_test_flag(&sms_flags, OPTION_TWO) ? 2 : 1;
01794    if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE]))
01795       h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]);
01796    if (h.opause_0 < 25 || h.opause_0 > 2000)
01797       h.opause_0 = 300; /* default 300ms */
01798    ast_verb(1, "initial delay %dms\n", h.opause_0);
01799 
01800 
01801    /* the following apply if there is an arg3/4 and apply to the created message file */
01802    if (ast_test_flag(&sms_flags, OPTION_SRR))
01803       h.srr = 1;
01804    if (ast_test_flag(&sms_flags, OPTION_DCS))
01805       h.dcs = 1;
01806 #if 0 
01807       case '1':
01808       case '2':
01809       case '3':
01810       case '4':
01811       case '5':
01812       case '6':
01813       case '7':             /* set the pid for saved local message */
01814          h.pid = 0x40 + (*d & 0xF);
01815          break;
01816       }
01817 #endif
01818    if (sms_args.argc > 2) {
01819       unsigned char *up;
01820 
01821       /* submitting a message, not taking call. */
01822       /* deprecated, use smsq instead */
01823       h.scts = ast_tvnow();
01824       if (ast_strlen_zero(sms_args.addr) || strlen(sms_args.addr) >= sizeof(h.oa)) {
01825          ast_log(LOG_ERROR, "Address too long %s\n", sms_args.addr);
01826          goto done;
01827       }
01828       if (h.smsc)
01829          ast_copy_string(h.oa, sms_args.addr, sizeof(h.oa));
01830       else {
01831          ast_copy_string(h.da, sms_args.addr, sizeof(h.da));
01832          ast_copy_string(h.oa, h.cli, sizeof(h.oa));
01833       }
01834       h.udl = 0;
01835       if (ast_strlen_zero(sms_args.body)) {
01836          ast_log(LOG_ERROR, "Missing body for %s\n", sms_args.addr);
01837          goto done;
01838       }
01839       up = (unsigned char *)sms_args.body;
01840       while (*up && h.udl < SMSLEN)
01841          h.ud[h.udl++] = utf8decode(&up);
01842       if (is7bit(h.dcs) && packsms7(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
01843          ast_log(LOG_WARNING, "Invalid 7 bit GSM data\n");
01844          goto done;
01845       }
01846       if (is8bit(h.dcs) && packsms8(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
01847          ast_log(LOG_WARNING, "Invalid 8 bit data\n");
01848          goto done;
01849       }
01850       if (is16bit(h.dcs) && packsms16(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
01851          ast_log(LOG_WARNING, "Invalid 16 bit data\n");
01852          goto done;
01853       }
01854       h.rx = 0;              /* sent message */
01855       h.mr = -1;
01856       sms_writefile(&h);
01857       res = h.err;
01858       goto done;
01859    }
01860 
01861    if (ast_test_flag(&sms_flags, OPTION_ANSWER)) {
01862       h.framenumber = 1;        /* Proto 2 */
01863       /* set up SMS_EST initial message */
01864       if (h.protocol == 2) {
01865          h.omsg[0] = DLL2_SMS_EST;
01866          h.omsg[1] = 0;
01867       } else {
01868          h.omsg[0] = DLL1_SMS_EST | DLL1_SMS_COMPLETE;
01869          h.omsg[1] = 0;
01870       }
01871       sms_messagetx(&h);
01872    }
01873 
01874    if (chan->_state != AST_STATE_UP)
01875       ast_answer(chan);
01876 
01877    res = ast_set_write_format(chan, __OUT_FMT);
01878    if (res >= 0)
01879       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
01880    if (res < 0) {
01881       ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n");
01882       goto done;
01883    }
01884 
01885    if ( (res = ast_activate_generator(chan, &smsgen, &h)) < 0) {
01886       ast_log(LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
01887       goto done;
01888    }
01889 
01890    /* Do our thing here */
01891    for (;;) {
01892       struct ast_frame *f;
01893       int i = ast_waitfor(chan, -1);
01894       if (i < 0) {
01895          ast_log(LOG_NOTICE, "waitfor failed\n");
01896          break;
01897       }
01898       if (h.hangup) {
01899          ast_log(LOG_NOTICE, "channel hangup\n");
01900          break;
01901       }
01902       f = ast_read(chan);
01903       if (!f) {
01904          ast_log(LOG_NOTICE, "ast_read failed\n");
01905          break;
01906       }
01907       if (f->frametype == AST_FRAME_VOICE) {
01908          sms_process(&h, f->samples, f->data);
01909       }
01910 
01911       ast_frfree(f);
01912    }
01913    res = h.err;   /* XXX */
01914 
01915    sms_log(&h, '?');         /* log incomplete message */
01916 done:
01917    return (res);
01918 }

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

outgoing data are produced by this generator function, that reads from the descriptor whether it has data to send and which ones.

Definition at line 1483 of file app_sms.c.

References __OUT_FMT, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), DLL2_SMS_EST, f, LOG_WARNING, MAXSAMPLES, sms_s::obyte, sms_s::obyten, sms_s::obytep, sms_s::omsg, sms_s::opause, sms_s::ophase, sms_s::ophasep, sms_s::oseizure, sms_s::osync, and sms_s::protocol.

01484 {
01485    struct ast_frame f = { 0 };
01486 #define MAXSAMPLES (800)
01487    output_t *buf;
01488    sms_t *h = data;
01489    int i;
01490 
01491    if (samples > MAXSAMPLES) {
01492       ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n",
01493           MAXSAMPLES, samples);
01494       samples = MAXSAMPLES;
01495    }
01496    len = samples * sizeof(*buf) + AST_FRIENDLY_OFFSET;
01497    buf = alloca(len);
01498 
01499    f.frametype = AST_FRAME_VOICE;
01500    f.subclass = __OUT_FMT;
01501    f.datalen = samples * sizeof(*buf);
01502    f.offset = AST_FRIENDLY_OFFSET;
01503    f.mallocd = 0;
01504    f.data = buf;
01505    f.samples = samples;
01506    f.src = "app_sms";
01507    /* create a buffer containing the digital sms pattern */
01508    for (i = 0; i < samples; i++) {
01509       buf[i] = wave_out[0];   /* default is silence */
01510 
01511       if (h->opause)
01512          h->opause--;
01513       else if (h->obyten || h->osync) {   /* sending data */
01514          buf[i] = wave_out[h->ophase];
01515          h->ophase += (h->obyte & 1) ? 13 : 21; /* compute next phase */
01516          if (h->ophase >= 80)
01517             h->ophase -= 80;
01518          if ((h->ophasep += 12) >= 80) {     /* time to send the next bit */
01519             h->ophasep -= 80;
01520             if (h->oseizure > 0) {     /* sending channel seizure (proto 2) */
01521                h->oseizure--;
01522                h->obyte ^= 1; /* toggle low bit */
01523             } else if (h->osync) {
01524                h->obyte = 1;  /* send mark as sync bit */
01525                h->osync--;    /* sending sync bits */
01526                if (h->osync == 0 && h->protocol == 2 && h->omsg[0] == DLL2_SMS_EST) {
01527                   h->obytep = h->obyten = 0; /* we are done */
01528                }
01529             } else {
01530                h->obitp++;
01531                if (h->obitp == 1)
01532                   h->obyte = 0; /* start bit; */
01533                else if (h->obitp == 2)
01534                   h->obyte = h->omsg[h->obytep];
01535                else if (h->obitp == 10) {
01536                   h->obyte = 1; /* stop bit */
01537                   h->obitp = 0;
01538                   h->obytep++;
01539                   if (h->obytep == h->obyten) {
01540                      h->obytep = h->obyten = 0; /* sent */
01541                      h->osync = 10;   /* trailing marks */
01542                   }
01543                } else
01544                   h->obyte >>= 1;
01545             }
01546          }
01547       }
01548    }
01549    if (ast_write(chan, &f) < 0) {
01550       ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
01551       return -1;
01552    }
01553    return 0;
01554 #undef MAXSAMPLES
01555 }

static unsigned char sms_handleincoming ( sms_t h  )  [static]

handle the incoming message

Definition at line 1016 of file app_sms.c.

References ast_copy_string(), ast_log(), ast_tvnow(), 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().

01017 {
01018    unsigned char p = 3;
01019    if (h->smsc) {                          /* SMSC */
01020       if ((h->imsg[2] & 3) == 1) {           /* SMS-SUBMIT */
01021          h->udhl = h->udl = 0;
01022          h->vp = 0;
01023          h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
01024          h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
01025          h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
01026          ast_copy_string(h->oa, h->cli, sizeof(h->oa));
01027          h->scts = ast_tvnow();
01028          h->mr = h->imsg[p++];
01029          p += unpackaddress(h->da, h->imsg + p);
01030          h->pid = h->imsg[p++];
01031          h->dcs = h->imsg[p++];
01032          if ((h->imsg[2] & 0x18) == 0x10) {                     /* relative VP */
01033             if (h->imsg[p] < 144)
01034                h->vp = (h->imsg[p] + 1) * 5;
01035             else if (h->imsg[p] < 168)
01036                h->vp = 720 + (h->imsg[p] - 143) * 30;
01037             else if (h->imsg[p] < 197)
01038                h->vp = (h->imsg[p] - 166) * 1440;
01039             else
01040                h->vp = (h->imsg[p] - 192) * 10080;
01041             p++;
01042          } else if (h->imsg[2] & 0x18)
01043             p += 7;            /* ignore enhanced / absolute VP */
01044          p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
01045          h->rx = 1;            /* received message */
01046          sms_writefile(h);   /* write the file */
01047          if (p != h->imsg[1] + 2) {
01048             ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
01049             return 0xFF;        /* duh! */
01050          }
01051       } else {
01052          ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
01053          return 0xFF;
01054       }
01055    } else {                          /* client */
01056       if (!(h->imsg[2] & 3)) {                         /* SMS-DELIVER */
01057          *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
01058          h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
01059          h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
01060          h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
01061          h->mr = -1;
01062          p += unpackaddress(h->oa, h->imsg + p);
01063          h->pid = h->imsg[p++];
01064          h->dcs = h->imsg[p++];
01065          h->scts = unpackdate(h->imsg + p);
01066          p += 7;
01067          p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
01068          h->rx = 1;            /* received message */
01069          sms_writefile(h);   /* write the file */
01070          if (p != h->imsg[1] + 2) {
01071             ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
01072             return 0xFF;        /* duh! */
01073          }
01074       } else {
01075          ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
01076          return 0xFF;
01077       }
01078    }
01079    return 0;                    /* no error */
01080 }

static int sms_handleincoming_proto2 ( sms_t h  )  [static]

sms_handleincoming_proto2: handle the incoming message

Definition at line 1159 of file app_sms.c.

References ast_copy_string(), ast_localtime(), ast_mktime(), ast_tvnow(), ast_verb, sms_s::da, f, sms_s::imsg, MAX_DEBUG_LEN, msg, sms_s::oa, sms_s::rx, sms_s::scts, sms_hexdump(), sms_writefile(), ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, sms_s::ud, and sms_s::udl.

Referenced by sms_messagerx2().

01160 {
01161    int f, i, sz = 0;
01162    int msg, msgsz;
01163    struct ast_tm tm;
01164    struct timeval tv = { 0, 0 };
01165    char debug_buf[MAX_DEBUG_LEN * 3 + 1];
01166 
01167    sz = h->imsg[1] + 2;
01168    /* ast_verb(3, "SMS-P2 Frame: %s\n", sms_hexdump(h->imsg, sz, debug_buf)); */
01169 
01170    /* Parse message body (called payload) */
01171    tv = h->scts = ast_tvnow();
01172    for (f = 4; f < sz; ) {
01173       msg = h->imsg[f++];
01174       msgsz = h->imsg[f++];
01175       msgsz += (h->imsg[f++] * 256);
01176       switch (msg) {
01177       case 0x13:      /* Body */
01178          ast_verb(3, "SMS-P2 Body#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
01179          if (msgsz >= sizeof(h->imsg))
01180             msgsz = sizeof(h->imsg) - 1;
01181          for (i = 0; i < msgsz; i++)
01182             h->ud[i] = h->imsg[f + i];
01183          h->udl = msgsz;
01184          break;
01185       case 0x14:      /* Date SCTS */
01186          tv = h->scts = ast_tvnow();
01187          ast_localtime(&tv, &tm, NULL);
01188          tm.tm_mon = ( (h->imsg[f] * 10) + h->imsg[f + 1] ) - 1;
01189          tm.tm_mday = ( (h->imsg[f + 2] * 10) + h->imsg[f + 3] );
01190          tm.tm_hour = ( (h->imsg[f + 4] * 10) + h->imsg[f + 5] );
01191          tm.tm_min = ( (h->imsg[f + 6] * 10) + h->imsg[f + 7] );
01192          tm.tm_sec = 0;
01193          h->scts = ast_mktime(&tm, NULL);
01194          ast_verb(3, "SMS-P2 Date#%02X=%02d/%02d %02d:%02d\n", msg, tm.tm_mday, tm.tm_mon + 1, tm.tm_hour, tm.tm_min);
01195          break;
01196       case 0x15:      /* Calling line (from SMSC) */
01197          if (msgsz >= 20)
01198             msgsz = 20 - 1;
01199          ast_verb(3, "SMS-P2 Origin#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
01200          ast_copy_string(h->oa, (char *)(&h->imsg[f]), msgsz + 1);
01201          break;
01202       case 0x18:      /* Destination(from TE/phone) */
01203          if (msgsz >= 20)
01204             msgsz = 20 - 1;
01205          ast_verb(3, "SMS-P2 Destination#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
01206          ast_copy_string(h->da, (char *)(&h->imsg[f]), msgsz + 1);
01207          break;
01208       case 0x1C:      /* Notify */
01209          ast_verb(3, "SMS-P2 Notify#%02X=%s\n", msg, sms_hexdump(&h->imsg[f], 3, debug_buf));
01210          break;
01211       default:
01212          ast_verb(3, "SMS-P2 Par#%02X [%d]: %s\n", msg, msgsz, sms_hexdump(&h->imsg[f], msgsz, debug_buf));
01213          break;
01214       }
01215       f+=msgsz;       /* Skip to next */
01216    }
01217    h->rx = 1;        /* received message */
01218    sms_writefile(h);      /* write the file */
01219    return 0;          /* no error */
01220 }

static char* sms_hexdump ( unsigned char  buf[],
int  size,
char *  s 
) [static]

Definition at line 1147 of file app_sms.c.

References f, and MAX_DEBUG_LEN.

Referenced by sms_handleincoming_proto2().

01148 {
01149    char *p;
01150    int f;
01151 
01152    for (p = s, f = 0; f < size && f < MAX_DEBUG_LEN; f++, p += 3) 
01153       sprintf(p, "%02X ", (unsigned char)buf[f]);
01154    return(s);
01155 }

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

Log the output, and remove file.

Definition at line 712 of file app_sms.c.

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

Referenced by sms_messagerx(), and sms_messagerx2().

00713 {
00714    int o;
00715 
00716    if (*h->oa == '\0' && *h->da == '\0')
00717       return;
00718    o = open(log_file, O_CREAT | O_APPEND | O_WRONLY, AST_FILE_MODE);
00719    if (o >= 0) {
00720       char line[1000], mrs[3] = "", *p;
00721       char buf[30];
00722       unsigned char n;
00723 
00724       if (h->mr >= 0)
00725          snprintf(mrs, sizeof(mrs), "%02X", h->mr);
00726       snprintf(line, sizeof(line), "%s %c%c%c%s %s %s %s ",
00727          isodate(time(NULL), buf, sizeof(buf)),
00728          status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue,
00729          S_OR(h->oa, "-"), S_OR(h->da, "-") );
00730       p = line + strlen(line);
00731       for (n = 0; n < h->udl; n++) {
00732          if (h->ud[n] == '\\') {
00733             *p++ = '\\';
00734             *p++ = '\\';
00735          } else if (h->ud[n] == '\n') {
00736             *p++ = '\\';
00737             *p++ = 'n';
00738          } else if (h->ud[n] == '\r') {
00739             *p++ = '\\';
00740             *p++ = 'r';
00741          } else if (h->ud[n] < 32 || h->ud[n] == 127)
00742             *p++ = 191;
00743          else
00744             *p++ = h->ud[n];
00745       }
00746       *p++ = '\n';
00747       *p = 0;
00748       if (write(o, line, strlen(line)) < 0) {
00749          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00750       }
00751       close(o);
00752    }
00753    *h->oa = *h->da = h->udl = 0;
00754 }

static void sms_messagerx ( sms_t h  )  [static]

Definition at line 1389 of file app_sms.c.

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

01390 {
01391    int cause;
01392 
01393    sms_debug (DIR_RX, h);
01394    if (h->protocol == 2) {
01395       sms_messagerx2(h);
01396       return;
01397    }
01398    /* parse incoming message for Protocol 1 */
01399    switch (h->imsg[0]) {
01400    case 0x91:                 /* SMS_DATA */
01401       cause = sms_handleincoming (h);
01402       if (!cause) {
01403          sms_log(h, 'Y');
01404          h->omsg[0] = 0x95;  /* SMS_ACK */
01405          h->omsg[1] = 0x02;
01406          h->omsg[2] = 0x00;  /* deliver report */
01407          h->omsg[3] = 0x00;  /* no parameters */
01408       } else {                    /* NACK */
01409          sms_log(h, 'N');
01410          h->omsg[0] = 0x96;  /* SMS_NACK */
01411          h->omsg[1] = 3;
01412          h->omsg[2] = 0;     /* delivery report */
01413          h->omsg[3] = cause; /* cause */
01414          h->omsg[4] = 0;     /* no parameters */
01415       }
01416       sms_messagetx(h);
01417       break;
01418 
01419    case 0x92:                 /* SMS_ERROR */
01420       h->err = 1;
01421       sms_messagetx(h);      /* send whatever we sent again */
01422       break;
01423    case 0x93:                 /* SMS_EST */
01424       sms_nextoutgoing (h);
01425       break;
01426    case 0x94:                 /* SMS_REL */
01427       h->hangup = 1;          /* hangup */
01428       break;
01429    case 0x95:                 /* SMS_ACK */
01430       sms_log(h, 'Y');
01431       sms_nextoutgoing (h);
01432       break;
01433    case 0x96:                 /* SMS_NACK */
01434       h->err = 1;
01435       sms_log(h, 'N');
01436       sms_nextoutgoing (h);
01437       break;
01438    default:                  /* Unknown */
01439       h->omsg[0] = 0x92;        /* SMS_ERROR */
01440       h->omsg[1] = 1;
01441       h->omsg[2] = 3;           /* unknown message type; */
01442       sms_messagetx(h);
01443       break;
01444    }
01445 }

static void sms_messagerx2 ( sms_t h  )  [static]

Definition at line 1236 of file app_sms.c.

References ast_log(), DLL2_ACK, DLL2_SMS_ACK0, DLL2_SMS_ACK1, DLL2_SMS_EST, DLL2_SMS_INFO_MO, DLL2_SMS_INFO_MT, DLL2_SMS_NACK, DLL2_SMS_REL, DLL_SMS_MASK, sms_s::imsg, LOG_NOTICE, sms_handleincoming_proto2(), sms_log(), sms_messagetx(), and sms_nextoutgoing().

Referenced by sms_messagerx().

01237 {
01238    int p = h->imsg[0] & DLL_SMS_MASK ; /* mask the high bit */
01239    int cause;
01240 
01241 #define DLL2_ACK(h) ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1)
01242    switch (p) {
01243    case DLL2_SMS_EST:   /* Protocol 2: Connection ready (fake): send message  */
01244       sms_nextoutgoing (h);
01245       /* smssend(h,"11 29 27 00 10 01 00 00 11 06 00 00 00 00 00 00 00 12 03 00 02 00 04 13 01 00 41 14 08 00 30 39 31 35 30 02 30 02 15 02 00 39 30 "); */
01246       break;
01247 
01248    case DLL2_SMS_INFO_MO:  /* transport SMS_SUBMIT */
01249    case DLL2_SMS_INFO_MT:  /* transport SMS_DELIVERY */
01250       cause = sms_handleincoming_proto2(h);
01251       if (!cause) /* ACK */
01252          sms_log(h, 'Y');
01253       h->omsg[0] = DLL2_ACK(h);
01254       h->omsg[1] = 0x06;  /* msg len */
01255       h->omsg[2] = 0x04;  /* payload len */
01256       h->omsg[3] = 0x00;  /* payload len */
01257       h->omsg[4] = 0x1f;  /* Response type */
01258       h->omsg[5] = 0x01;  /* parameter len */
01259       h->omsg[6] = 0x00;  /* parameter len */
01260       h->omsg[7] = cause;  /* CONFIRM or error */
01261       sms_messagetx(h);
01262       break;
01263 
01264    case DLL2_SMS_NACK:  /* Protocol 2: SMS_NAK */
01265       h->omsg[0] = DLL2_SMS_REL;  /* SMS_REL */
01266       h->omsg[1] = 0x00;  /* msg len */
01267       sms_messagetx(h);
01268       break;
01269 
01270    case DLL2_SMS_ACK0:
01271    case DLL2_SMS_ACK1:
01272       /* SMS_ACK also transport SMS_SUBMIT or SMS_DELIVERY */
01273       if ( (h->omsg[0] & DLL_SMS_MASK) == DLL2_SMS_REL) {
01274          /* a response to our Release, just hangup */
01275          h->hangup = 1;   /* hangup */
01276       } else {
01277          /* XXX depending on what we are.. */
01278          ast_log(LOG_NOTICE, "SMS_SUBMIT or SMS_DELIVERY");
01279          sms_nextoutgoing (h);
01280       }
01281       break;
01282 
01283    case DLL2_SMS_REL:   /* Protocol 2: SMS_REL (hangup req) */
01284       h->omsg[0] = DLL2_ACK(h);
01285       h->omsg[1] = 0;
01286       sms_messagetx(h);
01287       break;
01288    }
01289 }

static void sms_messagetx ( sms_t h  )  [static]

Definition at line 1447 of file app_sms.c.

References DIR_TX, sms_s::framenumber, len(), sms_s::obitp, sms_s::obyte, sms_s::obytep, sms_s::omsg, sms_s::opause, sms_s::opause_0, sms_s::oseizure, sms_s::protocol, and sms_debug().

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

01448 {
01449    unsigned char c = 0, p;
01450    int len = h->omsg[1] + 2;  /* total message length excluding checksum */
01451 
01452    for (p = 0; p < len; p++)  /* compute checksum */
01453       c += h->omsg[p];
01454    h->omsg[len] = 0 - c;      /* actually, (256 - (c & 0fxx)) & 0xff) */
01455    sms_debug(DIR_TX, h);
01456    h->framenumber++; /* Proto 2 */
01457    h->obyte = 1;     /* send mark ('1') at the beginning */
01458    h->opause = 200;
01459    /* Change the initial message delay. BT requires 300ms,
01460     * but for others this might be way too much and the phone
01461     * could time out. XXX make it configurable.
01462     */
01463    if (h->omsg[0] == 0x93)
01464       h->opause = 8 * h->opause_0;  /* initial message delay */
01465    h->obytep = 0;
01466    h->obitp = 0;
01467    if (h->protocol == 2) {
01468       h->oseizure = 300;      /* Proto 2: 300bits (or more ?) */
01469       h->obyte = 0;     /* Seizure starts with  space (0) */
01470       h->opause = 400;
01471    } else {
01472       h->oseizure = 0;  /* Proto 1: No seizure */
01473    }
01474    /* Note - setting osync triggers the generator */
01475    h->osync = OSYNC_BITS;        /* 80 sync bits */
01476    h->obyten = len + 1;    /* bytes to send (including checksum) */
01477 }

static void sms_nextoutgoing ( sms_t h  )  [static]

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

Definition at line 1332 of file app_sms.c.

References ast_config_AST_SPOOL_DIR, ast_mkdir(), sms_s::da, sms_s::oa, sms_s::omsg, sms_s::protocol, sms_s::queue, readdirqueue(), sms_s::rx, sms_compose1(), sms_compose2(), sms_messagetx(), sms_readfile(), and sms_s::smsc.

Referenced by sms_messagerx(), and sms_messagerx2().

01333 {    
01334    char fn[100 + NAME_MAX] = "";
01335    DIR *d;
01336    char more = 0;
01337 
01338    *h->da = *h->oa = '\0';       /* clear destinations */
01339    h->rx = 0;           /* outgoing message */
01340    snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? "mttx" : "motx");
01341    ast_mkdir(fn, 0777);       /* ensure it exists */
01342    d = opendir(fn);
01343    if (d) {
01344       struct dirent *f = readdirqueue(d, h->queue);
01345       if (f) {
01346          snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", f->d_name);
01347          sms_readfile(h, fn);
01348          if (readdirqueue(d, h->queue))
01349             more = 1;           /* more to send */
01350       }
01351       closedir(d);
01352    }
01353    if (*h->da || *h->oa) {                          /* message to send */
01354       if (h->protocol == 2)
01355          sms_compose2(h, more);
01356       else
01357          sms_compose1(h, more);
01358    } else {          /* no message */
01359       if (h->protocol == 2) {
01360          h->omsg[0] = 0x17;      /* SMS_REL */
01361          h->omsg[1] = 0;
01362       } else {
01363          h->omsg[0] = 0x94;      /* SMS_REL */
01364          h->omsg[1] = 0;
01365       }
01366    }
01367    sms_messagetx(h);
01368 }

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

Process an incoming frame, trying to detect the carrier and decode the message. The two frequencies are 1300 and 2100 Hz. The decoder detects the amplitude of the signal over the last few samples, filtering the absolute values with a lowpass filter. If the magnitude (h->imag) is large enough, multiply the signal by the two carriers, and compute the amplitudes m0 and m1. Record the current sample as '0' or '1' depending on which one is greater. The last 3 bits are stored in h->ibith, with the count of '1' bits in h->ibitt. XXX the rest is to be determined.

Definition at line 1588 of file app_sms.c.

References ast_log(), sms_s::err, sms_s::hangup, sms_s::idle, sms_s::ierr, sms_s::imag, LOG_NOTICE, m1, sms_s::obyten, sms_s::omsg, sms_s::osync, and sms_messagetx().

01589 {
01590    int bit;
01591 
01592    /*
01593     * Ignore incoming audio while a packet is being transmitted,
01594     * the protocol is half-duplex.
01595     * Unfortunately this means that if the outbound and incoming
01596     * transmission overlap (which is an error condition anyways),
01597     * we may miss some data and this makes debugging harder.
01598     */
01599    if (h->obyten || h->osync)
01600       return;
01601    for ( ; samples-- ; data++) {
01602       unsigned long long m0, m1;
01603       if (abs(*data) > h->imag)
01604          h->imag = abs(*data);
01605       else
01606          h->imag = h->imag * 7 / 8;
01607       if (h->imag <= 500) {      /* below [arbitrary] threahold: lost carrier */
01608          if (h->idle++ == 80000) {      /* nothing happening */
01609             ast_log(LOG_NOTICE, "No data, hanging up\n");
01610             h->hangup = 1;
01611             h->err = 1;
01612          }
01613          if (h->ierr) {    /* error */
01614             ast_log(LOG_NOTICE, "Error %d, hanging up\n", h->ierr);
01615             /* Protocol 1 */
01616             h->err = 1;
01617             h->omsg[0] = 0x92;  /* error */
01618             h->omsg[1] = 1;
01619             h->omsg[2] = h->ierr;
01620             sms_messagetx(h);  /* send error */
01621          }
01622          h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01623          continue;
01624       }
01625       h->idle = 0;
01626 
01627       /* multiply signal by the two carriers. */
01628       h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
01629       h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
01630       h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
01631       h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
01632       /* compute the amplitudes */
01633       m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
01634       m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
01635 
01636       /* advance the sin/cos pointers */
01637       if ((h->ips0 += 21) >= 80)
01638          h->ips0 -= 80;
01639       if ((h->ipc0 += 21) >= 80)
01640          h->ipc0 -= 80;
01641       if ((h->ips1 += 13) >= 80)
01642          h->ips1 -= 80;
01643       if ((h->ipc1 += 13) >= 80)
01644          h->ipc1 -= 80;
01645 
01646       /* set new bit to 1 or 0 depending on which value is stronger */
01647       h->ibith <<= 1;
01648       if (m1 > m0)
01649          h->ibith |= 1;
01650       if (h->ibith & 8)
01651          h->ibitt--;
01652       if (h->ibith & 1)
01653          h->ibitt++;
01654       bit = ((h->ibitt > 1) ? 1 : 0);
01655       if (bit != h->ibitl)
01656          h->ibitc = 1;
01657       else
01658          h->ibitc++;
01659       h->ibitl = bit;
01660       if (!h->ibitn && h->ibitc == 4 && !bit) {
01661          h->ibitn = 1;
01662          h->iphasep = 0;
01663       }
01664       if (bit && h->ibitc == 200) {                 /* sync, restart message */
01665          /* Protocol 2: empty connnection ready (I am master) */
01666          if (h->framenumber < 0 && h->ibytec >= 160 && !memcmp(h->imsg, "UUUUUUUUUUUUUUUUUUUU", 20)) {
01667             h->framenumber = 1;
01668             ast_verb(3, "SMS protocol 2 detected\n");
01669             h->protocol = 2;
01670             h->imsg[0] = 0xff;      /* special message (fake) */
01671             h->imsg[1] = h->imsg[2] = 0x00;
01672             h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01673             sms_messagerx(h);
01674          }
01675          h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01676       }
01677       if (h->ibitn) {
01678          h->iphasep += 12;
01679          if (h->iphasep >= 80) {             /* next bit */
01680             h->iphasep -= 80;
01681             if (h->ibitn++ == 9) {           /* end of byte */
01682                if (!bit) { /* bad stop bit */
01683                   ast_log(LOG_NOTICE, "bad stop bit");
01684                   h->ierr = 0xFF; /* unknown error */
01685                } else {
01686                   if (h->ibytep < sizeof(h->imsg)) {
01687                      h->imsg[h->ibytep] = h->ibytev;
01688                      h->ibytec += h->ibytev;
01689                      h->ibytep++;
01690                   } else if (h->ibytep == sizeof(h->imsg)) {
01691                      ast_log(LOG_NOTICE, "msg too large");
01692                      h->ierr = 2; /* bad message length */
01693                   }
01694                   if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
01695                      if (!h->ibytec)
01696                         sms_messagerx(h);
01697                      else {
01698                         ast_log(LOG_NOTICE, "bad checksum");
01699                         h->ierr = 1;      /* bad checksum */
01700                      }
01701                   }
01702                }
01703                h->ibitn = 0;
01704             }
01705             h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
01706          }
01707       }
01708    }
01709 }

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

parse and delete a file

Definition at line 757 of file app_sms.c.

References ast_log(), ast_mktime(), ast_tvnow(), 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, pp, sms_s::rp, sms_s::rx, S, s, sms_s::scts, SMSLEN, sms_s::srr, ast_tm::tm_hour, ast_tm::tm_isdst, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, ast_tm::tm_year, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, sms_s::udl, sms_s::udtxt, utf8decode(), and sms_s::vp.

Referenced by sms_nextoutgoing().

00758 {
00759    char line[1000];
00760    FILE *s;
00761    char dcsset = 0;     /* if DSC set */
00762    ast_log(LOG_EVENT, "Sending %s\n", fn);
00763    h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
00764    h->mr = -1;
00765    h->dcs = 0xF1;       /* normal messages class 1 */
00766    h->scts = ast_tvnow();
00767    s = fopen(fn, "r");
00768    if (s) {
00769       if (unlink(fn)) { /* concurrent access, we lost */
00770          fclose(s);
00771          return;
00772       }
00773       while (fgets (line, sizeof(line), s)) {   /* process line in file */
00774          char *p;
00775          void *pp = &p;
00776          for (p = line; *p && *p != '\n' && *p != '\r'; p++);
00777          *p = 0;               /* strip eoln */
00778          p = line;
00779          if (!*p || *p == ';')
00780             continue;           /* blank line or comment, ignore */
00781          while (isalnum(*p)) {
00782             *p = tolower (*p);
00783             p++;
00784          }
00785          while (isspace (*p))
00786             *p++ = 0;
00787          if (*p == '=') {
00788             *p++ = 0;
00789             if (!strcmp(line, "ud")) {  /* parse message (UTF-8) */
00790                unsigned char o = 0;
00791                memcpy(h->udtxt, p, SMSLEN);  /* for protocol 2 */
00792                while (*p && o < SMSLEN)
00793                   h->ud[o++] = utf8decode(pp);
00794                h->udl = o;
00795                if (*p)
00796                   ast_log(LOG_WARNING, "UD too long in %s\n", fn);
00797             } else {
00798                while (isspace (*p))
00799                   p++;
00800                if (!strcmp(line, "oa") && strlen(p) < sizeof(h->oa))
00801                   numcpy (h->oa, p);
00802                else if (!strcmp(line, "da") && strlen(p) < sizeof(h->oa))
00803                   numcpy (h->da, p);
00804                else if (!strcmp(line, "pid"))
00805                   h->pid = atoi(p);
00806                else if (!strcmp(line, "dcs")) {
00807                   h->dcs = atoi(p);
00808                   dcsset = 1;
00809                } else if (!strcmp(line, "mr"))
00810                   h->mr = atoi(p);
00811                else if (!strcmp(line, "srr"))
00812                   h->srr = (atoi(p) ? 1 : 0);
00813                else if (!strcmp(line, "vp"))
00814                   h->vp = atoi(p);
00815                else if (!strcmp(line, "rp"))
00816                   h->rp = (atoi(p) ? 1 : 0);
00817                else if (!strcmp(line, "scts")) {   /* get date/time */
00818                   int Y,
00819                     m,
00820                     d,
00821                     H,
00822                     M,
00823                     S;
00824                   if (sscanf (p, "%d-%d-%dT%d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6) {
00825                      struct ast_tm t = { 0, };
00826                      t.tm_year = Y - 1900;
00827                      t.tm_mon = m - 1;
00828                      t.tm_mday = d;
00829                      t.tm_hour = H;
00830                      t.tm_min = M;
00831                      t.tm_sec = S;
00832                      t.tm_isdst = -1;
00833                      h->scts = ast_mktime(&t, NULL);
00834                      if (h->scts.tv_sec == 0)
00835                         ast_log(LOG_WARNING, "Bad date/timein %s: %s", fn, p);
00836                   }
00837                } else
00838                   ast_log(LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
00839             }
00840          } else if (*p == '#') {    /* raw hex format */
00841             *p++ = 0;
00842             if (*p == '#') {
00843                p++;
00844                if (!strcmp(line, "ud")) { /* user data */
00845                   int o = 0;
00846                   while (*p && o < SMSLEN) {
00847                      if (isxdigit(*p) && isxdigit(p[1]) && isxdigit(p[2]) && isxdigit(p[3])) {
00848                         h->ud[o++] =
00849                            (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 12) +
00850                            (((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
00851                            (((isalpha(p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha(p[3]) ? 9 : 0) + (p[3] & 0xF));
00852                         p += 4;
00853                      } else
00854                         break;
00855                   }
00856                   h->udl = o;
00857                   if (*p)
00858                      ast_log(LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
00859                } else
00860                   ast_log(LOG_WARNING, "Only ud can use ## format, %s\n", fn);
00861             } else if (!strcmp(line, "ud")) {   /* user data */
00862                int o = 0;
00863                while (*p && o < SMSLEN) {
00864                   if (isxdigit(*p) && isxdigit(p[1])) {
00865                      h->ud[o++] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
00866                      p += 2;
00867                   } else
00868                      break;
00869                }
00870                h->udl = o;
00871                if (*p)
00872                   ast_log(LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
00873             } else if (!strcmp(line, "udh")) {  /* user data header */
00874                unsigned char o = 0;
00875                h->udhi = 1;
00876                while (*p && o < SMSLEN) {
00877                   if (isxdigit(*p) && isxdigit(p[1])) {
00878                      h->udh[o] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
00879                      o++;
00880                      p += 2;
00881                   } else
00882                      break;
00883                }
00884                h->udhl = o;
00885                if (*p)
00886                   ast_log(LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
00887             } else
00888                ast_log(LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
00889          } else
00890             ast_log(LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
00891       }
00892       fclose(s);
00893       if (!dcsset && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00894          if (packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00895             if (packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0)
00896                ast_log(LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
00897             else {
00898                h->dcs = 0x08; /* default to 16 bit */
00899                ast_log(LOG_WARNING, "Sending in 16 bit format(%s)\n", fn);
00900             }
00901          } else {
00902             h->dcs = 0xF5;    /* default to 8 bit */
00903             ast_log(LOG_WARNING, "Sending in 8 bit format(%s)\n", fn);
00904          }
00905       }
00906       if (is7bit(h->dcs) && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0)
00907          ast_log(LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
00908       if (is8bit(h->dcs) && packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0)
00909          ast_log(LOG_WARNING, "Invalid 8 bit data %s\n", fn);
00910       if (is16bit(h->dcs) && packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0)
00911          ast_log(LOG_WARNING, "Invalid 16 bit data %s\n", fn);
00912    }
00913 }

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

Definition at line 1565 of file app_sms.c.

01566 {
01567    return;  /* nothing to do here. */
01568 }

static void sms_writefile ( sms_t h  )  [static]

white a received text message to a file

Definition at line 916 of file app_sms.c.

References ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_mkdir(), buf, 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(), and sms_handleincoming_proto2().

00917 {
00918    char fn[200] = "", fn2[200] = "";
00919    char buf[30];
00920    FILE *o;
00921 
00922    snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
00923    ast_mkdir(fn, 0777);       /* ensure it exists */
00924    ast_copy_string(fn2, fn, sizeof(fn2));
00925    snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%s.%s-%d", h->queue, isodate(h->scts.tv_sec, buf, sizeof(buf)), seq++);
00926    snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1);
00927    o = fopen(fn, "w");
00928    if (o == NULL)
00929       return;
00930 
00931    if (*h->oa)
00932       fprintf(o, "oa=%s\n", h->oa);
00933    if (*h->da)
00934       fprintf(o, "da=%s\n", h->da);
00935    if (h->udhi) {
00936       unsigned int p;
00937       fprintf(o, "udh#");
00938       for (p = 0; p < h->udhl; p++)
00939          fprintf(o, "%02X", h->udh[p]);
00940       fprintf(o, "\n");
00941    }
00942    if (h->udl) {
00943       unsigned int p;
00944       for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
00945       if (p < h->udl)
00946          fputc(';', o);   /* cannot use ud=, but include as a comment for human readable */
00947       fprintf(o, "ud=");
00948       for (p = 0; p < h->udl; p++) {
00949          unsigned short v = h->ud[p];
00950          if (v < 32)
00951             fputc(191, o);
00952          else if (v < 0x80)
00953             fputc(v, o);
00954          else if (v < 0x800)
00955          {
00956             fputc(0xC0 + (v >> 6), o);
00957             fputc(0x80 + (v & 0x3F), o);
00958          } else
00959          {
00960             fputc(0xE0 + (v >> 12), o);
00961             fputc(0x80 + ((v >> 6) & 0x3F), o);
00962             fputc(0x80 + (v & 0x3F), o);
00963          }
00964       }
00965       fprintf(o, "\n");
00966       for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
00967       if (p < h->udl) {
00968          for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
00969          if (p == h->udl) {                   /* can write in ucs-1 hex */
00970             fprintf(o, "ud#");
00971             for (p = 0; p < h->udl; p++)
00972                fprintf(o, "%02X", h->ud[p]);
00973             fprintf(o, "\n");
00974          } else {                 /* write in UCS-2 */
00975             fprintf(o, "ud##");
00976             for (p = 0; p < h->udl; p++)
00977                fprintf(o, "%04X", h->ud[p]);
00978             fprintf(o, "\n");
00979          }
00980       }
00981    }
00982    if (h->scts.tv_sec) {
00983       char buf[30];
00984       fprintf(o, "scts=%s\n", isodate(h->scts.tv_sec, buf, sizeof(buf)));
00985    }
00986    if (h->pid)
00987       fprintf(o, "pid=%d\n", h->pid);
00988    if (h->dcs != 0xF1)
00989       fprintf(o, "dcs=%d\n", h->dcs);
00990    if (h->vp)
00991       fprintf(o, "vp=%d\n", h->vp);
00992    if (h->srr)
00993       fprintf(o, "srr=1\n");
00994    if (h->mr >= 0)
00995       fprintf(o, "mr=%d\n", h->mr);
00996    if (h->rp)
00997       fprintf(o, "rp=1\n");
00998    fclose(o);
00999    if (rename(fn, fn2))
01000       unlink(fn);
01001    else
01002       ast_log(LOG_EVENT, "Received to %s\n", fn2);
01003 }

static int unload_module ( void   )  [static]

Definition at line 1920 of file app_sms.c.

References ast_unregister_application().

01921 {
01922    return ast_unregister_application(app);
01923 }

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

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

Definition at line 671 of file app_sms.c.

Referenced by sms_handleincoming().

00672 {
00673    unsigned char l = i[0],
00674       p;
00675    if (i[1] == 0x91)
00676       *o++ = '+';
00677    for (p = 0; p < l; p++) {
00678       if (p & 1)
00679          *o++ = (i[2 + p / 2] >> 4) + '0';
00680       else
00681          *o++ = (i[2 + p / 2] & 0xF) + '0';
00682    }
00683    *o = 0;
00684    return (l + 5) / 2;
00685 }

static struct timeval unpackdate ( unsigned char *  i  )  [static]

unpack a date and return

Definition at line 531 of file app_sms.c.

References ast_mktime().

Referenced by sms_handleincoming().

00532 {
00533    struct ast_tm t;
00534 
00535    t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
00536    t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
00537    t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
00538    t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
00539    t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
00540    t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
00541    t.tm_isdst = 0;
00542    if (i[6] & 0x08)
00543       t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
00544    else
00545       t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
00546 
00547    return ast_mktime(&t, NULL);
00548 }

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 657 of file app_sms.c.

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

Referenced by sms_handleincoming().

00658 {
00659    int l = *i++;
00660    if (is7bit(dcs)) {
00661       unpacksms7(i, l, udh, udhl, ud, udl, udhi);
00662       l = (l * 7 + 7) / 8;    /* adjust length to return */
00663    } else if (is8bit(dcs))
00664       unpacksms8(i, l, udh, udhl, ud, udl, udhi);
00665    else
00666       unpacksms16(i, l, udh, udhl, ud, udl, udhi);
00667    return l + 1;
00668 }

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 630 of file app_sms.c.

Referenced by unpacksms().

00631 {
00632    unsigned short *o = ud;
00633    *udhl = 0;
00634    if (udhi) {
00635       int n = *i;
00636       *udhl = n;
00637       if (n) {
00638          i++;
00639          l--;
00640          while (l && n) {
00641             l--;
00642             n--;
00643             *udh++ = *i++;
00644          }
00645       }
00646    }
00647    while (l--) {
00648       int v = *i++;
00649       if (l--)
00650          v = (v << 8) + *i++;
00651       *o++ = v;
00652    }
00653    *udl = (o - ud);
00654 }

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 553 of file app_sms.c.

Referenced by unpacksms().

00554 {
00555    unsigned char b = 0, p = 0;
00556    unsigned short *o = ud;
00557    *udhl = 0;
00558    if (udhi && l) {      /* header */
00559       int h = i[p];
00560       *udhl = h;
00561       if (h) {
00562          b = 1;
00563          p++;
00564          l--;
00565          while (h-- && l) {
00566             *udh++ = i[p++];
00567             b += 8;
00568             while (b >= 7) {
00569                b -= 7;
00570                l--;
00571                if (!l)
00572                   break;
00573             }
00574          }
00575          /* adjust for fill, septets */
00576          if (b) {
00577             b = 7 - b;
00578             l--;
00579          }
00580       }
00581    }
00582    while (l--) {
00583       unsigned char v;
00584       if (b < 2)
00585          v = ((i[p] >> b) & 0x7F);  /* everything in one byte */
00586       else
00587          v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
00588       b += 7;
00589       if (b >= 8) {
00590          b -= 8;
00591          p++;
00592       }
00593       /* 0x00A0 is the encoding of ESC (27) in defaultalphabet */
00594       if (o > ud && o[-1] == 0x00A0 && escapes[v])
00595          o[-1] = escapes[v];
00596       else
00597          *o++ = defaultalphabet[v];
00598    }
00599    *udl = (o - ud);
00600 }

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 605 of file app_sms.c.

Referenced by unpacksms().

00606 {
00607    unsigned short *o = ud;
00608    *udhl = 0;
00609    if (udhi) {
00610       int n = *i;
00611       *udhl = n;
00612       if (n) {
00613          i++;
00614          l--;
00615          while (l && n) {
00616             l--;
00617             n--;
00618             *udh++ = *i++;
00619          }
00620       }
00621    }
00622    while (l--)
00623       *o++ = *i++;     /* not to UTF-8 as explicitly 8 bit coding in DCS */
00624    *udl = (o - ud);
00625 }

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

Reads next UCS character from NUL terminated UTF-8 string and advance pointer.

Definition at line 283 of file app_sms.c.

Referenced by sms_readfile().

00284 {
00285    unsigned char *p = *pp;
00286    if (!*p)
00287       return 0;       /* null termination of string */
00288    (*pp)++;
00289    if (*p < 0xC0)
00290       return *p;     /* ascii or continuation character */
00291    if (*p < 0xE0) {
00292       if (*p < 0xC2 || (p[1] & 0xC0) != 0x80)
00293          return *p;       /* not valid UTF-8 */
00294       (*pp)++;
00295       return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
00296       }
00297    if (*p < 0xF0) {
00298       if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80)
00299           return *p;      /* not valid UTF-8 */
00300       (*pp) += 2;
00301       return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
00302    }
00303    if (*p < 0xF8) {
00304       if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80)
00305          return *p;       /* not valid UTF-8 */
00306       (*pp) += 3;
00307       return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
00308    }
00309    if (*p < 0xFC) {
00310       if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
00311          || (p[4] & 0xC0) != 0x80)
00312          return *p;       /* not valid UTF-8 */
00313       (*pp) += 4;
00314       return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
00315    }
00316    if (*p < 0xFE) {
00317       if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
00318          || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80)
00319          return *p;       /* not valid UTF-8 */
00320       (*pp) += 5;
00321       return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F);
00322    }
00323    return *p;        /* not sensible */
00324 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "SMS/PSTN handler" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } [static]

Definition at line 1936 of file app_sms.c.

char* app = "SMS" [static]

Definition at line 69 of file app_sms.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1936 of file app_sms.c.

const unsigned short defaultalphabet[] [static]

Definition at line 163 of file app_sms.c.

char* descrip [static]

Definition at line 73 of file app_sms.c.

const unsigned short escapes[] [static]

Definition at line 176 of file app_sms.c.

char log_file[255] [static]

Definition at line 67 of file app_sms.c.

volatile unsigned char message_ref [static]

Definition at line 64 of file app_sms.c.

volatile unsigned int seq [static]

Definition at line 65 of file app_sms.c.

Referenced by __manager_event(), append_event(), ast_udptl_write(), handle_link_data(), handle_remote_data(), parsing(), process_cisco_dtmf(), send_retransmit(), and udptl_build_packet().

enum { ... } sms_flags

Referenced by sms_exec().

enum { ... } sms_opt_args

struct ast_app_option sms_options[128] = { [ 's' ] = { .flag = OPTION_BE_SMSC }, [ 'a' ] = { .flag = OPTION_ANSWER }, [ 't' ] = { .flag = OPTION_TWO }, [ 'r' ] = { .flag = OPTION_SRR }, [ 'o' ] = { .flag = OPTION_DCS }, [ 'p' ] = { .flag = OPTION_PAUSE , .arg_index = OPTION_ARG_PAUSE + 1 }, } [static]

Definition at line 1739 of file app_sms.c.

Referenced by sms_exec().

struct ast_generator smsgen [static]

Initial value:

 {
   .alloc = sms_alloc,
   .release = sms_release,
   .generate = sms_generate,
}

Definition at line 1570 of file app_sms.c.

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

Definition at line 71 of file app_sms.c.

signed short wave[] [static]

Definition at line 104 of file app_sms.c.

Referenced by festival_exec().

const output_t* wave_out = wave [static]

Definition at line 120 of file app_sms.c.


Generated on Thu Jul 9 13:40:49 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7