Wed Aug 18 22:34:02 2010

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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, }
static char * app = "SMS"
static 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 1446 of file app_sms.c.

Referenced by sms_debug(), and sms_messagerx().

#define DIR_TX   2

Definition at line 1447 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 1212 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.

Referenced by sms_messagetx().

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

01813      {
01814    OPTION_BE_SMSC = (1 << 0),             /* act as sms center */
01815    OPTION_ANSWER  = (1 << 1),             /* answer on incoming calls */
01816    OPTION_TWO  = (1 << 2),                 /* Use Protocol Two */
01817    OPTION_PAUSE   = (1 << 3),             /* pause before sending data, in ms */
01818    OPTION_SRR  = (1 << 4),                 /* set srr */
01819    OPTION_DCS  = (1 << 5),                 /* set dcs */
01820 } sms_flags;

anonymous enum

Enumerator:
OPTION_ARG_PAUSE 
OPTION_ARG_ARRAY_SIZE 

Definition at line 1822 of file app_sms.c.

01822      {
01823    OPTION_ARG_PAUSE = 0,
01824    OPTION_ARG_ARRAY_SIZE
01825 } 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 2042 of file app_sms.c.

static void __unreg_module ( void   )  [static]

Definition at line 2042 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 1152 of file app_sms.c.

References sms_s::omsg.

Referenced by putdummydata_proto2(), and sms_compose2().

01153 {
01154    int x = h->omsg[1] + 2;                 /* Get current position */
01155    if (x == 2) {
01156       x += 2;                             /* First: skip Payload length (set later) */
01157    }
01158    h->omsg[x++] = msg;                     /* Message code */
01159    h->omsg[x++] = (unsigned char)size;     /* Data size Low */
01160    h->omsg[x++] = 0;                       /* Data size Hi */
01161    for (; size > 0 ; size--) {
01162       h->omsg[x++] = *data++;
01163    }
01164    h->omsg[1] = x - 2;                     /* Frame size */
01165    h->omsg[2] = x - 4;                     /* Payload length (Lo) */
01166    h->omsg[3] = 0;                         /* Payload length (Hi) */
01167 }

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

static, return a date/time in ISO format

Definition at line 273 of file app_sms.c.

References ast_localtime(), and ast_strftime().

Referenced by sms_log(), and sms_writefile().

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

static int load_module ( void   )  [static]

Definition at line 2030 of file app_sms.c.

References app, ast_config_AST_LOG_DIR, AST_LIN2A, ast_register_application, descrip, log_file, sms_exec(), synopsis, and wave.

02031 {
02032 #ifdef OUTALAW
02033    int p;
02034    for (p = 0; p < 80; p++) {
02035       wavea[p] = AST_LIN2A(wave[p]);
02036    }
02037 #endif
02038    snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR);
02039    return ast_register_application(app, sms_exec, synopsis, descrip);
02040 }

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    }
00263    while (*s) {
00264       if (isdigit(*s)) {
00265          *d++ = *s;
00266       }
00267       s++;
00268    }
00269    *d = 0;
00270 }

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

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

Definition at line 715 of file app_sms.c.

Referenced by sms_compose1().

00716 {
00717    unsigned char p = 2;
00718    o[0] = 0;                               /* number of bytes */
00719    if (*i == '+') {                        /* record as bit 0 in byte 1 */
00720       i++;
00721       o[1] = 0x91;
00722    } else {
00723       o[1] = 0x81;
00724    }
00725    for ( ; *i ; i++) {
00726       if (!isdigit(*i)) {                 /* ignore non-digits */
00727          continue;
00728       }
00729       if (o[0] & 1) {
00730          o[p++] |= ((*i & 0xF) << 4);
00731       } else {
00732          o[p] = (*i & 0xF);
00733       }
00734       o[0]++;
00735    }
00736    if (o[0] & 1) {
00737       o[p++] |= 0xF0;                     /* pad */
00738    }
00739    return p;
00740 }

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

pack a date and return

Definition at line 523 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().

00524 {
00525    struct ast_tm t;
00526    struct timeval topack = { w, 0 };
00527    int z;
00528 
00529    ast_localtime(&topack, &t, NULL);
00530 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) || defined(__CYGWIN__)
00531    z = -t.tm_gmtoff / 60 / 15;
00532 #else
00533    z = timezone / 60 / 15;
00534 #endif
00535    *o++ = ((t.tm_year % 10) << 4) + (t.tm_year % 100) / 10;
00536    *o++ = (((t.tm_mon + 1) % 10) << 4) + (t.tm_mon + 1) / 10;
00537    *o++ = ((t.tm_mday % 10) << 4) + t.tm_mday / 10;
00538    *o++ = ((t.tm_hour % 10) << 4) + t.tm_hour / 10;
00539    *o++ = ((t.tm_min % 10) << 4) + t.tm_min / 10;
00540    *o++ = ((t.tm_sec % 10) << 4) + t.tm_sec / 10;
00541    if (z < 0) {
00542       *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
00543    } else {
00544       *o++ = ((z % 10) << 4) + z / 10;
00545    }
00546 }

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

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

Referenced by sms_compose1().

00491 {
00492    unsigned char *p = base;
00493    if (udl == 0) {
00494       *p++ = 0;                           /* no user data */
00495    } else {
00496       
00497       int l = 0;
00498       if (is7bit(dcs)) {                  /* 7 bit */
00499          if ((l = packsms7(p + 1, udhl, udh, udl, ud)) < 0) {
00500             l = 0;
00501          }
00502          *p++ = l;
00503          p += (l * 7 + 7) / 8;
00504       } else if (is8bit(dcs)) {           /* 8 bit */
00505          if ((l = packsms8(p + 1, udhl, udh, udl, ud)) < 0) {
00506             l = 0;
00507          }
00508          *p++ = l;
00509          p += l;
00510       } else {                            /* UCS-2 */
00511          if ((l = packsms16(p + 1, udhl, udh, udl, ud)) < 0) {
00512             l = 0;
00513          }
00514          *p++ = l;
00515          p += l;
00516       }
00517    }
00518    return p - base;
00519 }

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

References dummy(), and SMSLEN_8.

Referenced by packsms(), and sms_readfile().

00456 {
00457    unsigned char p = 0;
00458    unsigned char dummy[SMSLEN_8];
00459 
00460    if (o == NULL) {
00461       o = dummy;
00462    }
00463    /* header - no encoding */
00464    if (udhl) {
00465       o[p++] = udhl;
00466       while (udhl--) {
00467          o[p++] = *udh++;
00468          if (p >= SMSLEN_8) {
00469             return p;
00470          }
00471       }
00472    }
00473    while (udl--) {
00474       long u;
00475       u = *ud++;
00476       o[p++] = (u >> 8);
00477       if (p >= SMSLEN_8) {
00478          return p - 1;                   /* could not fit last character */
00479       }
00480       o[p++] = u;
00481       if (p >= SMSLEN_8) {
00482          return p;
00483       }
00484    }
00485    return p;
00486 }

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

References dummy(), and SMSLEN.

Referenced by packsms(), and sms_readfile().

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

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

References dummy(), and SMSLEN_8.

Referenced by packsms(), and sms_readfile().

00417 {
00418    unsigned char p = 0;
00419    unsigned char dummy[SMSLEN_8];
00420 
00421    if (o == NULL)
00422       o = dummy;
00423    /* header - no encoding */
00424    if (udhl) {
00425       o[p++] = udhl;
00426       while (udhl--) {
00427          o[p++] = *udh++;
00428          if (p >= SMSLEN_8) {
00429             return p;
00430          }
00431       }
00432    }
00433    while (udl--) {
00434       long u;
00435       u = *ud++;
00436       if (u < 0 || u > 0xFF) {
00437          return -1;                      /* not valid */
00438       }
00439       o[p++] = u;
00440       if (p >= SMSLEN_8) {
00441          return p;
00442       }
00443    }
00444    return p;
00445 }

static void putdummydata_proto2 ( sms_t h  )  [static]

Definition at line 1169 of file app_sms.c.

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

Referenced by sms_compose2().

01170 {
01171    adddata_proto2(h, 0x10, "\0", 1);           /* Media Identifier > SMS */
01172    adddata_proto2(h, 0x11, "\0\0\0\0\0\0", 6); /* Firmware version */
01173    adddata_proto2(h, 0x12, "\2\0\4", 3);       /* SMS provider ID */
01174    adddata_proto2(h, 0x13, h->udtxt, h->udl);  /* Body */
01175 }

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

read dir skipping dot files...

Definition at line 1066 of file app_sms.c.

References f.

Referenced by sms_nextoutgoing().

01067 {
01068    struct dirent *f;
01069    do {
01070       f = readdir(d);
01071    } while (f && (*f->d_name == '.' || strncmp(f->d_name, queue, strlen(queue)) || f->d_name[strlen(queue)] != '.'));
01072    return f;
01073 }

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

01646 {
01647    return sms_t_ptr;
01648 }

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

compose a message for protocol 1

Definition at line 1364 of file app_sms.c.

References sms_s::da, sms_s::dcs, message_ref, 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().

01365 {
01366    unsigned int p = 2;                     /* next byte to write. Skip type and len */
01367 
01368    h->omsg[0] = 0x91;                      /* SMS_DATA */
01369    if (h->smsc) {                          /* deliver */
01370       h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
01371       p += packaddress(h->omsg + p, h->oa);
01372       h->omsg[p++] = h->pid;
01373       h->omsg[p++] = h->dcs;
01374       packdate(h->omsg + p, h->scts.tv_sec);
01375       p += 7;
01376       p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01377    } else {                                /* submit */
01378       h->omsg[p++] =
01379          0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
01380       if (h->mr < 0) {
01381          h->mr = message_ref++;
01382       }
01383       h->omsg[p++] = h->mr;
01384       p += packaddress(h->omsg + p, h->da);
01385       h->omsg[p++] = h->pid;
01386       h->omsg[p++] = h->dcs;
01387       if (h->vp) {                        /* relative VP */
01388          if (h->vp < 720) {
01389             h->omsg[p++] = (h->vp + 4) / 5 - 1;
01390          } else if (h->vp < 1440) {
01391             h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
01392          } else if (h->vp < 43200) {
01393             h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
01394          } else if (h->vp < 635040) {
01395             h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
01396          } else {
01397             h->omsg[p++] = 255;         /* max */
01398          }
01399       }
01400       p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
01401    }
01402    h->omsg[1] = p - 2;
01403 }

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

Definition at line 1177 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().

01178 {
01179    struct ast_tm tm;
01180    struct timeval now = h->scts;
01181    char stm[9];
01182 
01183    h->omsg[0] = 0x00;                      /* set later... */
01184    h->omsg[1] = 0;
01185    putdummydata_proto2(h);
01186    if (h->smsc) {                          /* deliver */
01187       h->omsg[0] = 0x11;                  /* SMS_DELIVERY */
01188       /* Required: 10 11 12 13 14 15 17 (seems they must be ordered!) */
01189       ast_localtime(&now, &tm, NULL);
01190       sprintf(stm, "%02d%02d%02d%02d", tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min);  /* Date mmddHHMM */
01191       adddata_proto2(h, 0x14, stm, 8);    /* Date */
01192       if (*h->oa == 0) {
01193          strcpy(h->oa, "00000000");
01194       }
01195       adddata_proto2(h, 0x15, h->oa, strlen(h->oa)); /* Originator */
01196       adddata_proto2(h, 0x17, "\1", 1);   /* Calling Terminal ID */
01197    } else {                                /* submit */
01198       h->omsg[0] = 0x10;                  /* SMS_SUBMIT */
01199       /* Required: 10 11 12 13 17 18 1B 1C (seems they must be ordered!) */
01200       adddata_proto2(h, 0x17, "\1", 1);   /* Calling Terminal ID */
01201       if (*h->da == 0) {
01202          strcpy(h->da, "00000000");
01203       }
01204       adddata_proto2(h, 0x18, h->da, strlen(h->da)); /* Originator */
01205       adddata_proto2(h, 0x1B, "\1", 1);         /* Called Terminal ID */
01206       adddata_proto2(h, 0x1C, "\0\0\0", 3);    /* Notification */
01207    }
01208 }

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

Definition at line 1448 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().

01449 {
01450    char txt[259 * 3 + 1];
01451    char *p = txt;                          /* always long enough */
01452    unsigned char *msg = (dir == DIR_RX) ? h->imsg : h->omsg;
01453    int n = (dir == DIR_RX) ? h->ibytep : msg[1] + 2;
01454    int q = 0;
01455    while (q < n && q < 30) {
01456       sprintf(p, " %02X", msg[q++]);
01457       p += 3;
01458    }
01459    if (q < n) {
01460       sprintf(p, "...");
01461    }
01462    ast_verb(3, "SMS %s%s\n", dir == DIR_RX ? "RX" : "TX", txt);
01463 }

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

Definition at line 1836 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, ast_flags::flags, 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_options, sms_s::smsc, and sms_s::srr.

Referenced by load_module().

01837 {
01838    int res = -1;
01839    sms_t h = { 0 };
01840    /* argument parsing support */
01841    struct ast_flags flags;
01842    char *parse, *sms_opts[OPTION_ARG_ARRAY_SIZE] = { 0, };
01843    char *p;
01844    AST_DECLARE_APP_ARGS(sms_args,
01845       AST_APP_ARG(queue);
01846       AST_APP_ARG(options);
01847       AST_APP_ARG(addr);
01848       AST_APP_ARG(body);
01849    );
01850 
01851    if (!data) {
01852       ast_log(LOG_ERROR, "Requires queue name at least\n");
01853       return -1;
01854    }
01855 
01856    parse = ast_strdupa(data);              /* create a local copy */
01857    AST_STANDARD_APP_ARGS(sms_args, parse);
01858    if (sms_args.argc > 1) {
01859       ast_app_parse_options(sms_options, &flags, sms_opts, sms_args.options);
01860    }
01861 
01862    ast_verb(1, "sms argc %d queue <%s> opts <%s> addr <%s> body <%s>\n",
01863       sms_args.argc, S_OR(sms_args.queue, ""),
01864       S_OR(sms_args.options, ""),
01865       S_OR(sms_args.addr, ""),
01866       S_OR(sms_args.body, "") );
01867 
01868    h.ipc0 = h.ipc1 = 20;                   /* phase for cosine */
01869    h.dcs = 0xF1;                           /* default */
01870 
01871    if (chan->cid.cid_num)
01872       ast_copy_string(h.cli, chan->cid.cid_num, sizeof(h.cli));
01873 
01874    if (ast_strlen_zero(sms_args.queue)) {
01875       ast_log(LOG_ERROR, "Requires queue name\n");
01876       goto done;
01877    }
01878    if (strlen(sms_args.queue) >= sizeof(h.queue)) {
01879       ast_log(LOG_ERROR, "Queue name too long\n");
01880       goto done;
01881    }
01882    ast_copy_string(h.queue, sms_args.queue, sizeof(h.queue));
01883 
01884    for (p = h.queue; *p; p++) {
01885       if (!isalnum(*p)) {
01886          *p = '-';                       /* make very safe for filenames */
01887       }
01888    }
01889 
01890    h.smsc = ast_test_flag(&flags, OPTION_BE_SMSC);
01891    h.protocol = ast_test_flag(&flags, OPTION_TWO) ? 2 : 1;
01892    if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE])) {
01893       h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]);
01894    }
01895    if (h.opause_0 < 25 || h.opause_0 > 2000) {
01896       h.opause_0 = 300;                   /* default 300ms */
01897    }
01898    ast_verb(1, "initial delay %dms\n", h.opause_0);
01899 
01900 
01901    /* the following apply if there is an arg3/4 and apply to the created message file */
01902    if (ast_test_flag(&flags, OPTION_SRR)) {
01903       h.srr = 1;
01904    }
01905    if (ast_test_flag(&flags, OPTION_DCS)) {
01906       h.dcs = 1;
01907    }
01908 #if 0 
01909       case '1':
01910       case '2':
01911       case '3':
01912       case '4':
01913       case '5':
01914       case '6':
01915       case '7':                           /* set the pid for saved local message */
01916          h.pid = 0x40 + (*d & 0xF);
01917          break;
01918       }
01919 #endif
01920    if (sms_args.argc > 2) {
01921       unsigned char *up;
01922 
01923       /* submitting a message, not taking call. */
01924       /* deprecated, use smsq instead */
01925       h.scts = ast_tvnow();
01926       if (ast_strlen_zero(sms_args.addr) || strlen(sms_args.addr) >= sizeof(h.oa)) {
01927          ast_log(LOG_ERROR, "Address too long %s\n", sms_args.addr);
01928          goto done;
01929       }
01930       if (h.smsc) {
01931          ast_copy_string(h.oa, sms_args.addr, sizeof(h.oa));
01932       } else {
01933          ast_copy_string(h.da, sms_args.addr, sizeof(h.da));
01934          ast_copy_string(h.oa, h.cli, sizeof(h.oa));
01935       }
01936       h.udl = 0;
01937       if (ast_strlen_zero(sms_args.body)) {
01938          ast_log(LOG_ERROR, "Missing body for %s\n", sms_args.addr);
01939          goto done;
01940       }
01941       up = (unsigned char *)sms_args.body;
01942       while (*up && h.udl < SMSLEN) {
01943          h.ud[h.udl++] = utf8decode(&up);
01944       }
01945       if (is7bit(h.dcs) && packsms7(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
01946          ast_log(LOG_WARNING, "Invalid 7 bit GSM data\n");
01947          goto done;
01948       }
01949       if (is8bit(h.dcs) && packsms8(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
01950          ast_log(LOG_WARNING, "Invalid 8 bit data\n");
01951          goto done;
01952       }
01953       if (is16bit(h.dcs) && packsms16(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
01954          ast_log(LOG_WARNING, "Invalid 16 bit data\n");
01955          goto done;
01956       }
01957       h.rx = 0;                           /* sent message */
01958       h.mr = -1;
01959       sms_writefile(&h);
01960       res = h.err;
01961       goto done;
01962    }
01963    
01964    if (chan->_state != AST_STATE_UP) {    /* make sure channel is answered before any TX */
01965       ast_answer(chan);
01966    }
01967 
01968    if (ast_test_flag(&flags, OPTION_ANSWER)) {
01969       h.framenumber = 1;                  /* Proto 2 */
01970       /* set up SMS_EST initial message */
01971       if (h.protocol == 2) {
01972          h.omsg[0] = DLL2_SMS_EST;
01973          h.omsg[1] = 0;
01974       } else {
01975          h.omsg[0] = DLL1_SMS_EST | DLL1_SMS_COMPLETE;
01976          h.omsg[1] = 0;
01977       }
01978       sms_messagetx(&h);
01979    }
01980 
01981    res = ast_set_write_format(chan, __OUT_FMT);
01982    if (res >= 0) {
01983       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
01984    }
01985    if (res < 0) {
01986       ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n");
01987       goto done;
01988    }
01989 
01990    if ( (res = ast_activate_generator(chan, &smsgen, &h)) < 0) {
01991       ast_log(LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
01992       goto done;
01993    }
01994 
01995    /* Do our thing here */
01996    for (;;) {
01997       struct ast_frame *f;
01998       int i = ast_waitfor(chan, -1);
01999       if (i < 0) {
02000          ast_log(LOG_NOTICE, "waitfor failed\n");
02001          break;
02002       }
02003       if (h.hangup) {
02004          ast_log(LOG_NOTICE, "channel hangup\n");
02005          break;
02006       }
02007       f = ast_read(chan);
02008       if (!f) {
02009          ast_log(LOG_NOTICE, "ast_read failed\n");
02010          break;
02011       }
02012       if (f->frametype == AST_FRAME_VOICE) {
02013          sms_process(&h, f->samples, f->data.ptr);
02014       }
02015 
02016       ast_frfree(f);
02017    }
02018    res = h.err;                            /* XXX */
02019 
02020    sms_log(&h, '?');                       /* log incomplete message */
02021 done:
02022    return (res);
02023 }

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

References __OUT_FMT, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), buf, f, LOG_WARNING, MAXSAMPLES, sms_s::obyte, sms_s::obyten, sms_s::opause, sms_s::ophase, sms_s::ophasep, sms_s::oseizure, sms_s::osync, and wave_out.

01568 {
01569    struct ast_frame f = { 0 };
01570 #define MAXSAMPLES (800)
01571    output_t *buf;
01572    sms_t *h = data;
01573    int i;
01574 
01575    if (samples > MAXSAMPLES) {
01576       ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n",
01577           MAXSAMPLES, samples);
01578       samples = MAXSAMPLES;
01579    }
01580    len = samples * sizeof(*buf) + AST_FRIENDLY_OFFSET;
01581    buf = alloca(len);
01582 
01583    f.frametype = AST_FRAME_VOICE;
01584    f.subclass = __OUT_FMT;
01585    f.datalen = samples * sizeof(*buf);
01586    f.offset = AST_FRIENDLY_OFFSET;
01587    f.mallocd = 0;
01588    f.data.ptr = buf;
01589    f.samples = samples;
01590    f.src = "app_sms";
01591    /* create a buffer containing the digital sms pattern */
01592    for (i = 0; i < samples; i++) {
01593       buf[i] = wave_out[0];               /* default is silence */
01594 
01595       if (h->opause) {
01596          h->opause--;
01597       } else if (h->obyten || h->osync) { /* sending data */
01598          buf[i] = wave_out[h->ophase];
01599          h->ophase += (h->obyte & 1) ? 13 : 21; /* compute next phase */
01600          if (h->ophase >= 80)
01601             h->ophase -= 80;
01602          if ((h->ophasep += 12) >= 80) { /* time to send the next bit */
01603             h->ophasep -= 80;
01604             if (h->oseizure > 0) {      /* sending channel seizure (proto 2) */
01605                h->oseizure--;
01606                h->obyte ^= 1;          /* toggle low bit */
01607             } else if (h->osync) {
01608                h->obyte = 1;           /* send mark as sync bit */
01609                h->osync--;             /* sending sync bits */
01610                if (h->osync == 0 && h->protocol == 2 && h->omsg[0] == DLL2_SMS_EST) {
01611                   h->obytep = h->obyten = 0; /* we are done */
01612                }
01613             } else {
01614                h->obitp++;
01615                if (h->obitp == 1) {
01616                   h->obyte = 0;       /* start bit; */
01617                } else if (h->obitp == 2) {
01618                   h->obyte = h->omsg[h->obytep];
01619                } else if (h->obitp == 10) {
01620                   h->obyte = 1; /* stop bit */
01621                   h->obitp = 0;
01622                   h->obytep++;
01623                   if (h->obytep == h->obyten) {
01624                      h->obytep = h->obyten = 0; /* sent */
01625                      h->osync = 10;   /* trailing marks */
01626                   }
01627                } else {
01628                   h->obyte >>= 1;
01629                }
01630             }
01631          }
01632       }
01633    }
01634    if (ast_write(chan, &f) < 0) {
01635       ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
01636       return -1;
01637    }
01638    return 0;
01639 #undef MAXSAMPLES
01640 }

static unsigned char sms_handleincoming ( sms_t h  )  [static]

handle the incoming message

Definition at line 1076 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().

01077 {
01078    unsigned char p = 3;
01079    if (h->smsc) {                          /* SMSC */
01080       if ((h->imsg[2] & 3) == 1) {        /* SMS-SUBMIT */
01081          h->udhl = h->udl = 0;
01082          h->vp = 0;
01083          h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
01084          h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
01085          h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
01086          ast_copy_string(h->oa, h->cli, sizeof(h->oa));
01087          h->scts = ast_tvnow();
01088          h->mr = h->imsg[p++];
01089          p += unpackaddress(h->da, h->imsg + p);
01090          h->pid = h->imsg[p++];
01091          h->dcs = h->imsg[p++];
01092          if ((h->imsg[2] & 0x18) == 0x10) {       /* relative VP */
01093             if (h->imsg[p] < 144) {
01094                h->vp = (h->imsg[p] + 1) * 5;
01095             } else if (h->imsg[p] < 168) {
01096                h->vp = 720 + (h->imsg[p] - 143) * 30;
01097             } else if (h->imsg[p] < 197) {
01098                h->vp = (h->imsg[p] - 166) * 1440;
01099             } else {
01100                h->vp = (h->imsg[p] - 192) * 10080;
01101             }
01102             p++;
01103          } else if (h->imsg[2] & 0x18) {
01104             p += 7;                     /* ignore enhanced / absolute VP */
01105          }
01106          p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
01107          h->rx = 1;                      /* received message */
01108          sms_writefile(h);               /* write the file */
01109          if (p != h->imsg[1] + 2) {
01110             ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
01111             return 0xFF;        /* duh! */
01112          }
01113       } else {
01114          ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
01115          return 0xFF;
01116       }
01117    } else {                                /* client */
01118       if (!(h->imsg[2] & 3)) {            /* SMS-DELIVER */
01119          *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
01120          h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
01121          h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
01122          h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
01123          h->mr = -1;
01124          p += unpackaddress(h->oa, h->imsg + p);
01125          h->pid = h->imsg[p++];
01126          h->dcs = h->imsg[p++];
01127          h->scts = unpackdate(h->imsg + p);
01128          p += 7;
01129          p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
01130          h->rx = 1;                      /* received message */
01131          sms_writefile(h);               /* write the file */
01132          if (p != h->imsg[1] + 2) {
01133             ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
01134             return 0xFF;                /* duh! */
01135          }
01136       } else {
01137          ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
01138          return 0xFF;
01139       }
01140    }
01141    return 0;                               /* no error */
01142 }

static int sms_handleincoming_proto2 ( sms_t h  )  [static]

sms_handleincoming_proto2: handle the incoming message

Definition at line 1226 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::scts, sms_hexdump(), 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().

01227 {
01228    int f, i, sz = 0;
01229    int msg, msgsz;
01230    struct ast_tm tm;
01231    struct timeval now = { 0, 0 };
01232    char debug_buf[MAX_DEBUG_LEN * 3 + 1];
01233 
01234    sz = h->imsg[1] + 2;
01235    /* ast_verb(3, "SMS-P2 Frame: %s\n", sms_hexdump(h->imsg, sz, debug_buf)); */
01236 
01237    /* Parse message body (called payload) */
01238    now = h->scts = ast_tvnow();
01239    for (f = 4; f < sz; ) {
01240       msg = h->imsg[f++];
01241       msgsz = h->imsg[f++];
01242       msgsz += (h->imsg[f++] * 256);
01243       switch (msg) {
01244       case 0x13:                          /* Body */
01245          ast_verb(3, "SMS-P2 Body#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
01246          if (msgsz >= sizeof(h->imsg)) {
01247             msgsz = sizeof(h->imsg) - 1;
01248          }
01249          for (i = 0; i < msgsz; i++) {
01250             h->ud[i] = h->imsg[f + i];
01251          }
01252          h->udl = msgsz;
01253          break;
01254       case 0x14:                          /* Date SCTS */
01255          now = h->scts = ast_tvnow();
01256          ast_localtime(&now, &tm, NULL);
01257          tm.tm_mon = ( (h->imsg[f] * 10) + h->imsg[f + 1] ) - 1;
01258          tm.tm_mday = ( (h->imsg[f + 2] * 10) + h->imsg[f + 3] );
01259          tm.tm_hour = ( (h->imsg[f + 4] * 10) + h->imsg[f + 5] );
01260          tm.tm_min = ( (h->imsg[f + 6] * 10) + h->imsg[f + 7] );
01261          tm.tm_sec = 0;
01262          h->scts = ast_mktime(&tm, NULL);
01263          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);
01264          break;
01265       case 0x15:                          /* Calling line (from SMSC) */
01266          if (msgsz >= 20) {
01267             msgsz = 20 - 1;
01268          }
01269          ast_verb(3, "SMS-P2 Origin#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
01270          ast_copy_string(h->oa, (char *)(&h->imsg[f]), msgsz + 1);
01271          break;
01272       case 0x18:                          /* Destination(from TE/phone) */
01273          if (msgsz >= 20) {
01274             msgsz = 20 - 1;
01275          }
01276          ast_verb(3, "SMS-P2 Destination#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
01277          ast_copy_string(h->da, (char *)(&h->imsg[f]), msgsz + 1);
01278          break;
01279       case 0x1C:                          /* Notify */
01280          ast_verb(3, "SMS-P2 Notify#%02X=%s\n", msg, sms_hexdump(&h->imsg[f], 3, debug_buf));
01281          break;
01282       default:
01283          ast_verb(3, "SMS-P2 Par#%02X [%d]: %s\n", msg, msgsz, sms_hexdump(&h->imsg[f], msgsz, debug_buf));
01284          break;
01285       }
01286       f+=msgsz;                           /* Skip to next */
01287    }
01288    h->rx = 1;                              /* received message */
01289    sms_writefile(h);                       /* write the file */
01290    return 0;                               /* no error */
01291 }

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

Definition at line 1213 of file app_sms.c.

References f, and MAX_DEBUG_LEN.

Referenced by sms_handleincoming_proto2().

01214 {
01215    char *p;
01216    int f;
01217 
01218    for (p = s, f = 0; f < size && f < MAX_DEBUG_LEN; f++, p += 3) {
01219       sprintf(p, "%02X ", (unsigned char)buf[f]);
01220    }
01221    return(s);
01222 }

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

Log the output, and remove file.

Definition at line 743 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().

00744 {
00745    int o;
00746 
00747    if (*h->oa == '\0' && *h->da == '\0') {
00748       return;
00749    }
00750    o = open(log_file, O_CREAT | O_APPEND | O_WRONLY, AST_FILE_MODE);
00751    if (o >= 0) {
00752       char line[1000], mrs[3] = "", *p;
00753       char buf[30];
00754       unsigned char n;
00755 
00756       if (h->mr >= 0) {
00757          snprintf(mrs, sizeof(mrs), "%02X", h->mr);
00758       }
00759       snprintf(line, sizeof(line), "%s %c%c%c%s %s %s %s ",
00760          isodate(time(NULL), buf, sizeof(buf)),
00761          status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue,
00762          S_OR(h->oa, "-"), S_OR(h->da, "-") );
00763       p = line + strlen(line);
00764       for (n = 0; n < h->udl; n++) {
00765          if (h->ud[n] == '\\') {
00766             *p++ = '\\';
00767             *p++ = '\\';
00768          } else if (h->ud[n] == '\n') {
00769             *p++ = '\\';
00770             *p++ = 'n';
00771          } else if (h->ud[n] == '\r') {
00772             *p++ = '\\';
00773             *p++ = 'r';
00774          } else if (h->ud[n] < 32 || h->ud[n] == 127) {
00775             *p++ = 191;
00776          } else {
00777             *p++ = h->ud[n];
00778          }
00779       }
00780       *p++ = '\n';
00781       *p = 0;
00782       if (write(o, line, strlen(line)) < 0) {
00783          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00784       }
00785       close(o);
00786    }
00787    *h->oa = *h->da = h->udl = 0;
00788 }

static void sms_messagerx ( sms_t h  )  [static]

Definition at line 1466 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().

01467 {
01468    int cause;
01469 
01470    sms_debug (DIR_RX, h);
01471    if (h->protocol == 2) {
01472       sms_messagerx2(h);
01473       return;
01474    }
01475    /* parse incoming message for Protocol 1 */
01476    switch (h->imsg[0]) {
01477    case 0x91:                              /* SMS_DATA */
01478       cause = sms_handleincoming (h);
01479       if (!cause) {
01480          sms_log(h, 'Y');
01481          h->omsg[0] = 0x95;              /* SMS_ACK */
01482          h->omsg[1] = 0x02;
01483          h->omsg[2] = 0x00;              /* deliver report */
01484          h->omsg[3] = 0x00;              /* no parameters */
01485       } else {                            /* NACK */
01486          sms_log(h, 'N');
01487          h->omsg[0] = 0x96;              /* SMS_NACK */
01488          h->omsg[1] = 3;
01489          h->omsg[2] = 0;                 /* delivery report */
01490          h->omsg[3] = cause;             /* cause */
01491          h->omsg[4] = 0;                 /* no parameters */
01492       }
01493       sms_messagetx(h);
01494       break;
01495 
01496    case 0x92:                              /* SMS_ERROR */
01497       h->err = 1;
01498       sms_messagetx(h);                   /* send whatever we sent again */
01499       break;
01500    case 0x93:                              /* SMS_EST */
01501       sms_nextoutgoing (h);
01502       break;
01503    case 0x94:                              /* SMS_REL */
01504       h->hangup = 1;                      /* hangup */
01505       break;
01506    case 0x95:                              /* SMS_ACK */
01507       sms_log(h, 'Y');
01508       sms_nextoutgoing (h);
01509       break;
01510    case 0x96:                              /* SMS_NACK */
01511       h->err = 1;
01512       sms_log(h, 'N');
01513       sms_nextoutgoing (h);
01514       break;
01515    default:                                /* Unknown */
01516       h->omsg[0] = 0x92;                  /* SMS_ERROR */
01517       h->omsg[1] = 1;
01518       h->omsg[2] = 3;                     /* unknown message type */
01519       sms_messagetx(h);
01520       break;
01521    }
01522 }

static void sms_messagerx2 ( sms_t h  )  [static]

Definition at line 1307 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().

01308 {
01309    int p = h->imsg[0] & DLL_SMS_MASK ; /* mask the high bit */
01310    int cause;
01311 
01312 #define DLL2_ACK(h) ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1)
01313    switch (p) {
01314    case DLL2_SMS_EST:                      /* Protocol 2: Connection ready (fake): send message  */
01315       sms_nextoutgoing (h);
01316       /* 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 "); */
01317       break;
01318 
01319    case DLL2_SMS_INFO_MO:                  /* transport SMS_SUBMIT */
01320    case DLL2_SMS_INFO_MT:                  /* transport SMS_DELIVERY */
01321       cause = sms_handleincoming_proto2(h);
01322       if (!cause) {                       /* ACK */
01323          sms_log(h, 'Y');
01324       }
01325       h->omsg[0] = DLL2_ACK(h);
01326       h->omsg[1] = 0x06;                  /* msg len */
01327       h->omsg[2] = 0x04;                  /* payload len */
01328       h->omsg[3] = 0x00;                  /* payload len */
01329       h->omsg[4] = 0x1f;                  /* Response type */
01330       h->omsg[5] = 0x01;                  /* parameter len */
01331       h->omsg[6] = 0x00;                  /* parameter len */
01332       h->omsg[7] = cause;                 /* CONFIRM or error */
01333       sms_messagetx(h);
01334       break;
01335 
01336    case DLL2_SMS_NACK:                     /* Protocol 2: SMS_NAK */
01337       h->omsg[0] = DLL2_SMS_REL;          /* SMS_REL */
01338       h->omsg[1] = 0x00;                  /* msg len */
01339       sms_messagetx(h);
01340       break;
01341 
01342    case DLL2_SMS_ACK0:
01343    case DLL2_SMS_ACK1:
01344       /* SMS_ACK also transport SMS_SUBMIT or SMS_DELIVERY */
01345       if ( (h->omsg[0] & DLL_SMS_MASK) == DLL2_SMS_REL) {
01346          /* a response to our Release, just hangup */
01347          h->hangup = 1;                  /* hangup */
01348       } else {
01349          /* XXX depending on what we are.. */
01350          ast_log(LOG_NOTICE, "SMS_SUBMIT or SMS_DELIVERY");
01351          sms_nextoutgoing (h);
01352       }
01353       break;
01354 
01355    case DLL2_SMS_REL:                      /* Protocol 2: SMS_REL (hangup req) */
01356       h->omsg[0] = DLL2_ACK(h);
01357       h->omsg[1] = 0;
01358       sms_messagetx(h);
01359       break;
01360    }
01361 }

static void sms_messagetx ( sms_t h  )  [static]

Definition at line 1524 of file app_sms.c.

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

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

01525 {
01526    unsigned char c = 0, p;
01527    int len = h->omsg[1] + 2;               /* total message length excluding checksum */
01528 
01529    for (p = 0; p < len; p++) {             /* compute checksum */
01530       c += h->omsg[p];
01531    }
01532    h->omsg[len] = 0 - c;                   /* actually, (256 - (c & 0fxx)) & 0xff) */
01533    sms_debug(DIR_TX, h);
01534    h->framenumber++;                       /* Proto 2 */
01535    h->obytep = 0;
01536    h->obitp = 0;
01537    if (h->protocol == 2) {                 /* Proto 2: */
01538       h->oseizure = 300;                  /* 300bits (or more ?) */
01539       h->obyte = 0;                       /* Seizure starts with  space (0) */
01540       if (h->omsg[0] == 0x7F) {
01541          h->opause = 8 * h->opause_0;    /* initial message delay */
01542       } else {
01543          h->opause = 400;
01544       }
01545    } else {                                /* Proto 1: */
01546       h->oseizure = 0;                    /* No seizure */
01547       h->obyte = 1;                       /* send mark ('1') at the beginning */
01548       /* Change the initial message delay. BT requires 300ms,
01549        * but for others this might be way too much and the phone
01550        * could time out. XXX make it configurable.
01551       */
01552       if (h->omsg[0] == 0x93) {
01553          h->opause = 8 * h->opause_0;    /* initial message delay */
01554       } else {
01555          h->opause = 200;
01556       }
01557    }
01558    /* Note - setting osync triggers the generator */
01559    h->osync = OSYNC_BITS;                  /* 80 sync bits */
01560    h->obyten = len + 1;                    /* bytes to send (including checksum) */
01561 }

static void sms_nextoutgoing ( sms_t h  )  [static]

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

Definition at line 1406 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().

01407 {    
01408    char fn[100 + NAME_MAX] = "";
01409    DIR *d;
01410    char more = 0;
01411 
01412    *h->da = *h->oa = '\0';                 /* clear destinations */
01413    h->rx = 0;                              /* outgoing message */
01414    snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? "mttx" : "motx");
01415    ast_mkdir(fn, 0777);                    /* ensure it exists */
01416    d = opendir(fn);
01417    if (d) {
01418       struct dirent *f = readdirqueue(d, h->queue);
01419       if (f) {
01420          snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", f->d_name);
01421          sms_readfile(h, fn);
01422          if (readdirqueue(d, h->queue)) {
01423             more = 1;                   /* more to send */
01424          }
01425       }
01426       closedir(d);
01427    }
01428    if (*h->da || *h->oa) {                 /* message to send */
01429       if (h->protocol == 2) {
01430          sms_compose2(h, more);
01431       } else {
01432          sms_compose1(h, more);
01433       }
01434    } else {                                /* no message */
01435       if (h->protocol == 2) {
01436          h->omsg[0] = 0x17;              /* SMS_REL */
01437          h->omsg[1] = 0;
01438       } else {
01439          h->omsg[0] = 0x94;              /* SMS_REL */
01440          h->omsg[1] = 0;
01441       }
01442    }
01443    sms_messagetx(h);
01444 }

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

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

01674 {
01675    int bit;
01676 
01677    /*
01678     * Ignore incoming audio while a packet is being transmitted,
01679     * the protocol is half-duplex.
01680     * Unfortunately this means that if the outbound and incoming
01681     * transmission overlap (which is an error condition anyways),
01682     * we may miss some data and this makes debugging harder.
01683     */
01684    if (h->obyten || h->osync) {
01685       return;
01686    }
01687    for ( ; samples-- ; data++) {
01688       unsigned long long m0, m1;
01689       if (abs(*data) > h->imag) {
01690          h->imag = abs(*data);
01691       } else {
01692          h->imag = h->imag * 7 / 8;
01693       }
01694       if (h->imag <= 500) {               /* below [arbitrary] threahold: lost carrier */
01695          if (h->idle++ == 80000) {       /* nothing happening */
01696             ast_log(LOG_NOTICE, "No data, hanging up\n");
01697             h->hangup = 1;
01698             h->err = 1;
01699          }
01700          if (h->ierr) {                  /* error */
01701             ast_log(LOG_NOTICE, "Error %d, hanging up\n", h->ierr);
01702             /* Protocol 1 */
01703             h->err = 1;
01704             h->omsg[0] = 0x92;          /* error */
01705             h->omsg[1] = 1;
01706             h->omsg[2] = h->ierr;
01707             sms_messagetx(h);           /* send error */
01708          }
01709          h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01710          continue;
01711       }
01712       h->idle = 0;
01713 
01714       /* multiply signal by the two carriers. */
01715       h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
01716       h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
01717       h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
01718       h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
01719       /* compute the amplitudes */
01720       m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
01721       m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
01722 
01723       /* advance the sin/cos pointers */
01724       if ((h->ips0 += 21) >= 80) {
01725          h->ips0 -= 80;
01726       }
01727       if ((h->ipc0 += 21) >= 80) {
01728          h->ipc0 -= 80;
01729       }
01730       if ((h->ips1 += 13) >= 80) {
01731          h->ips1 -= 80;
01732       }
01733       if ((h->ipc1 += 13) >= 80) {
01734          h->ipc1 -= 80;
01735       }
01736 
01737       /* set new bit to 1 or 0 depending on which value is stronger */
01738       h->ibith <<= 1;
01739       if (m1 > m0) {
01740          h->ibith |= 1;
01741       }
01742       if (h->ibith & 8) {
01743          h->ibitt--;
01744       }
01745       if (h->ibith & 1) {
01746          h->ibitt++;
01747       }
01748       bit = ((h->ibitt > 1) ? 1 : 0);
01749       if (bit != h->ibitl) {
01750          h->ibitc = 1;
01751       } else {
01752          h->ibitc++;
01753       }
01754       h->ibitl = bit;
01755       if (!h->ibitn && h->ibitc == 4 && !bit) {
01756          h->ibitn = 1;
01757          h->iphasep = 0;
01758       }
01759       if (bit && h->ibitc == 200) {       /* sync, restart message */
01760          /* Protocol 2: empty connection ready (I am master) */
01761          if (h->framenumber < 0 && h->ibytec >= 160 && !memcmp(h->imsg, "UUUUUUUUUUUUUUUUUUUU", 20)) {
01762             h->framenumber = 1;
01763             ast_verb(3, "SMS protocol 2 detected\n");
01764             h->protocol = 2;
01765             h->imsg[0] = 0xff;          /* special message (fake) */
01766             h->imsg[1] = h->imsg[2] = 0x00;
01767             h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01768             sms_messagerx(h);
01769          }
01770          h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
01771       }
01772       if (h->ibitn) {
01773          h->iphasep += 12;
01774          if (h->iphasep >= 80) {         /* next bit */
01775             h->iphasep -= 80;
01776             if (h->ibitn++ == 9) {      /* end of byte */
01777                if (!bit) {             /* bad stop bit */
01778                   ast_log(LOG_NOTICE, "bad stop bit");
01779                   h->ierr = 0xFF;     /* unknown error */
01780                } else {
01781                   if (h->ibytep < sizeof(h->imsg)) {
01782                      h->imsg[h->ibytep] = h->ibytev;
01783                      h->ibytec += h->ibytev;
01784                      h->ibytep++;
01785                   } else if (h->ibytep == sizeof(h->imsg)) {
01786                      ast_log(LOG_NOTICE, "msg too large");
01787                      h->ierr = 2;    /* bad message length */
01788                   }
01789                   if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
01790                      if (!h->ibytec) {
01791                         sms_messagerx(h);
01792                      } else {
01793                         ast_log(LOG_NOTICE, "bad checksum");
01794                         h->ierr = 1; /* bad checksum */
01795                      }
01796                   }
01797                }
01798                h->ibitn = 0;
01799             }
01800             h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
01801          }
01802       }
01803    }
01804 }

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

parse and delete a file

Definition at line 791 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().

00792 {
00793    char line[1000];
00794    FILE *s;
00795    char dcsset = 0;                        /* if DSC set */
00796    ast_log(LOG_EVENT, "Sending %s\n", fn);
00797    h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
00798    h->mr = -1;
00799    h->dcs = 0xF1;                          /* normal messages class 1 */
00800    h->scts = ast_tvnow();
00801    s = fopen(fn, "r");
00802    if (s) {
00803       if (unlink(fn)) {                   /* concurrent access, we lost */
00804          fclose(s);
00805          return;
00806       }
00807       while (fgets (line, sizeof(line), s)) {   /* process line in file */
00808          char *p;
00809          void *pp = &p;
00810          for (p = line; *p && *p != '\n' && *p != '\r'; p++);
00811          *p = 0;                         /* strip eoln */
00812          p = line;
00813          if (!*p || *p == ';') {
00814             continue;                   /* blank line or comment, ignore */
00815          }
00816          while (isalnum(*p)) {
00817             *p = tolower (*p);
00818             p++;
00819          }
00820          while (isspace (*p)) {
00821             *p++ = 0;
00822          }
00823          if (*p == '=') {
00824             *p++ = 0;
00825             if (!strcmp(line, "ud")) {  /* parse message (UTF-8) */
00826                unsigned char o = 0;
00827                memcpy(h->udtxt, p, SMSLEN); /* for protocol 2 */
00828                while (*p && o < SMSLEN) {
00829                   h->ud[o++] = utf8decode(pp);
00830                }
00831                h->udl = o;
00832                if (*p) {
00833                   ast_log(LOG_WARNING, "UD too long in %s\n", fn);
00834                }
00835             } else {
00836                while (isspace (*p)) {
00837                   p++;
00838                }
00839                if (!strcmp(line, "oa") && strlen(p) < sizeof(h->oa)) {
00840                   numcpy (h->oa, p);
00841                } else if (!strcmp(line, "da") && strlen(p) < sizeof(h->oa)) {
00842                   numcpy (h->da, p);
00843                } else if (!strcmp(line, "pid")) {
00844                   h->pid = atoi(p);
00845                } else if (!strcmp(line, "dcs")) {
00846                   h->dcs = atoi(p);
00847                   dcsset = 1;
00848                } else if (!strcmp(line, "mr")) {
00849                   h->mr = atoi(p);
00850                } else if (!strcmp(line, "srr")) {
00851                   h->srr = (atoi(p) ? 1 : 0);
00852                } else if (!strcmp(line, "vp")) {
00853                   h->vp = atoi(p);
00854                } else if (!strcmp(line, "rp")) {
00855                   h->rp = (atoi(p) ? 1 : 0);
00856                } else if (!strcmp(line, "scts")) {    /* get date/time */
00857                   int Y, m, d, H, M, S;
00858                   /* XXX Why aren't we using ast_strptime here? */
00859                   if (sscanf(p, "%4d-%2d-%2dT%2d:%2d:%2d", &Y, &m, &d, &H, &M, &S) == 6) {
00860                      struct ast_tm t = { 0, };
00861                      t.tm_year = Y - 1900;
00862                      t.tm_mon = m - 1;
00863                      t.tm_mday = d;
00864                      t.tm_hour = H;
00865                      t.tm_min = M;
00866                      t.tm_sec = S;
00867                      t.tm_isdst = -1;
00868                      h->scts = ast_mktime(&t, NULL);
00869                      if (h->scts.tv_sec == 0) {
00870                         ast_log(LOG_WARNING, "Bad date/timein %s: %s", fn, p);
00871                      }
00872                   }
00873                } else {
00874                   ast_log(LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
00875                }
00876             }
00877          } else if (*p == '#') {                   /* raw hex format */
00878             *p++ = 0;
00879             if (*p == '#') {
00880                p++;
00881                if (!strcmp(line, "ud")) {        /* user data */
00882                   int o = 0;
00883                   while (*p && o < SMSLEN) {
00884                      if (isxdigit(*p) && isxdigit(p[1]) && isxdigit(p[2]) && isxdigit(p[3])) {
00885                         h->ud[o++] =
00886                            (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 12) +
00887                            (((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
00888                            (((isalpha(p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha(p[3]) ? 9 : 0) + (p[3] & 0xF));
00889                         p += 4;
00890                      } else
00891                         break;
00892                   }
00893                   h->udl = o;
00894                   if (*p)
00895                      ast_log(LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
00896                } else
00897                   ast_log(LOG_WARNING, "Only ud can use ## format, %s\n", fn);
00898             } else if (!strcmp(line, "ud")) {       /* user data */
00899                int o = 0;
00900                while (*p && o < SMSLEN) {
00901                   if (isxdigit(*p) && isxdigit(p[1])) {
00902                      h->ud[o++] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
00903                      p += 2;
00904                   } else {
00905                      break;
00906                   }
00907                }
00908                h->udl = o;
00909                if (*p) {
00910                   ast_log(LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
00911                }
00912             } else if (!strcmp(line, "udh")) {      /* user data header */
00913                unsigned char o = 0;
00914                h->udhi = 1;
00915                while (*p && o < SMSLEN) {
00916                   if (isxdigit(*p) && isxdigit(p[1])) {
00917                      h->udh[o] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
00918                      o++;
00919                      p += 2;
00920                   } else {
00921                      break;
00922                   }
00923                }
00924                h->udhl = o;
00925                if (*p) {
00926                   ast_log(LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
00927                }
00928             } else {
00929                ast_log(LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
00930             }
00931          } else {
00932             ast_log(LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
00933          }
00934       }
00935       fclose(s);
00936       if (!dcsset && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00937          if (packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00938             if (packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00939                ast_log(LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
00940             } else {
00941                h->dcs = 0x08;          /* default to 16 bit */
00942                ast_log(LOG_WARNING, "Sending in 16 bit format(%s)\n", fn);
00943             }
00944          } else {
00945             h->dcs = 0xF5;              /* default to 8 bit */
00946             ast_log(LOG_WARNING, "Sending in 8 bit format(%s)\n", fn);
00947          }
00948       }
00949       if (is7bit(h->dcs) && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00950          ast_log(LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
00951       }
00952       if (is8bit(h->dcs) && packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00953          ast_log(LOG_WARNING, "Invalid 8 bit data %s\n", fn);
00954       }
00955       if (is16bit(h->dcs) && packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
00956          ast_log(LOG_WARNING, "Invalid 16 bit data %s\n", fn);
00957       }
00958    }
00959 }

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

Definition at line 1650 of file app_sms.c.

01651 {
01652    return;  /* nothing to do here. */
01653 }

static void sms_writefile ( sms_t h  )  [static]

white a received text message to a file

Definition at line 962 of file app_sms.c.

References ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_mkdir(), ast_tvnow(), ast_tvzero(), buf, sms_s::da, isodate(), sms_s::oa, sms_s::queue, sms_s::rx, sms_s::scts, seq, sms_s::smsc, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, and sms_s::udl.

Referenced by sms_handleincoming().

00963 {
00964    char fn[200] = "", fn2[200] = "";
00965    char buf[30];
00966    FILE *o;
00967 
00968    if (ast_tvzero(h->scts)) {
00969       h->scts = ast_tvnow();
00970    }
00971    snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
00972    ast_mkdir(fn, 0777);                    /* ensure it exists */
00973    ast_copy_string(fn2, fn, sizeof(fn2));
00974    snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%s.%s-%d", h->queue, isodate(h->scts.tv_sec, buf, sizeof(buf)), seq++);
00975    snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1);
00976    if ((o = fopen(fn, "w")) == NULL) {
00977       return;
00978    }
00979 
00980    if (*h->oa) {
00981       fprintf(o, "oa=%s\n", h->oa);
00982    }
00983    if (*h->da) {
00984       fprintf(o, "da=%s\n", h->da);
00985    }
00986    if (h->udhi) {
00987       unsigned int p;
00988       fprintf(o, "udh#");
00989       for (p = 0; p < h->udhl; p++) {
00990          fprintf(o, "%02X", h->udh[p]);
00991       }
00992       fprintf(o, "\n");
00993    }
00994    if (h->udl) {
00995       unsigned int p;
00996       for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
00997       if (p < h->udl) {
00998          fputc(';', o);                  /* cannot use ud=, but include as a comment for human readable */
00999       }
01000       fprintf(o, "ud=");
01001       for (p = 0; p < h->udl; p++) {
01002          unsigned short v = h->ud[p];
01003          if (v < 32) {
01004             fputc(191, o);
01005          } else if (v < 0x80) {
01006             fputc(v, o);
01007          } else if (v < 0x800) {
01008             fputc(0xC0 + (v >> 6), o);
01009             fputc(0x80 + (v & 0x3F), o);
01010          } else {
01011             fputc(0xE0 + (v >> 12), o);
01012             fputc(0x80 + ((v >> 6) & 0x3F), o);
01013             fputc(0x80 + (v & 0x3F), o);
01014          }
01015       }
01016       fprintf(o, "\n");
01017       for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
01018       if (p < h->udl) {
01019          for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
01020          if (p == h->udl) {              /* can write in ucs-1 hex */
01021             fprintf(o, "ud#");
01022             for (p = 0; p < h->udl; p++) {
01023                fprintf(o, "%02X", h->ud[p]);
01024             }
01025             fprintf(o, "\n");
01026          } else {                        /* write in UCS-2 */
01027             fprintf(o, "ud##");
01028             for (p = 0; p < h->udl; p++) {
01029                fprintf(o, "%04X", h->ud[p]);
01030             }
01031             fprintf(o, "\n");
01032          }
01033       }
01034    }
01035    if (h->scts.tv_sec) {
01036       char datebuf[30];
01037       fprintf(o, "scts=%s\n", isodate(h->scts.tv_sec, datebuf, sizeof(datebuf)));
01038    }
01039    if (h->pid) {
01040       fprintf(o, "pid=%d\n", h->pid);
01041    }
01042    if (h->dcs != 0xF1) {
01043       fprintf(o, "dcs=%d\n", h->dcs);
01044    }
01045    if (h->vp) {
01046       fprintf(o, "vp=%d\n", h->vp);
01047    }
01048    if (h->srr) {
01049       fprintf(o, "srr=1\n");
01050    }
01051    if (h->mr >= 0) {
01052       fprintf(o, "mr=%d\n", h->mr);
01053    }
01054    if (h->rp) {
01055       fprintf(o, "rp=1\n");
01056    }
01057    fclose(o);
01058    if (rename(fn, fn2)) {
01059       unlink(fn);
01060    } else {
01061       ast_log(LOG_EVENT, "Received to %s\n", fn2);
01062    }
01063 }

static int unload_module ( void   )  [static]

Definition at line 2025 of file app_sms.c.

References app, and ast_unregister_application().

02026 {
02027    return ast_unregister_application(app);
02028 }

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

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

Definition at line 697 of file app_sms.c.

Referenced by sms_handleincoming().

00698 {
00699    unsigned char l = i[0], p;
00700    if (i[1] == 0x91) {
00701       *o++ = '+';
00702    }
00703    for (p = 0; p < l; p++) {
00704       if (p & 1) {
00705          *o++ = (i[2 + p / 2] >> 4) + '0';
00706       } else {
00707          *o++ = (i[2 + p / 2] & 0xF) + '0';
00708       }
00709    }
00710    *o = 0;
00711    return (l + 5) / 2;
00712 }

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

unpack a date and return

Definition at line 549 of file app_sms.c.

References ast_mktime().

Referenced by sms_handleincoming().

00550 {
00551    struct ast_tm t;
00552 
00553    t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
00554    t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
00555    t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
00556    t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
00557    t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
00558    t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
00559    t.tm_isdst = 0;
00560    if (i[6] & 0x08) {
00561       t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
00562    } else {
00563       t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
00564    }
00565 
00566    return ast_mktime(&t, NULL);
00567 }

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

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

Referenced by sms_handleincoming().

00683 {
00684    int l = *i++;
00685    if (is7bit(dcs)) {
00686       unpacksms7(i, l, udh, udhl, ud, udl, udhi);
00687       l = (l * 7 + 7) / 8;                /* adjust length to return */
00688    } else if (is8bit(dcs)) {
00689       unpacksms8(i, l, udh, udhl, ud, udl, udhi);
00690    } else {
00691       unpacksms16(i, l, udh, udhl, ud, udl, udhi);
00692    }
00693    return l + 1;
00694 }

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

Referenced by unpacksms().

00655 {
00656    unsigned short *o = ud;
00657    *udhl = 0;
00658    if (udhi) {
00659       int n = *i;
00660       *udhl = n;
00661       if (n) {
00662          i++;
00663          l--;
00664          while (l && n) {
00665             l--;
00666             n--;
00667             *udh++ = *i++;
00668          }
00669       }
00670    }
00671    while (l--) {
00672       int v = *i++;
00673       if (l--) {
00674          v = (v << 8) + *i++;
00675       }
00676       *o++ = v;
00677    }
00678    *udl = (o - ud);
00679 }

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

Referenced by unpacksms().

00573 {
00574    unsigned char b = 0, p = 0;
00575    unsigned short *o = ud;
00576    *udhl = 0;
00577    if (udhi && l) {                        /* header */
00578       int h = i[p];
00579       *udhl = h;
00580       if (h) {
00581          b = 1;
00582          p++;
00583          l--;
00584          while (h-- && l) {
00585             *udh++ = i[p++];
00586             b += 8;
00587             while (b >= 7) {
00588                b -= 7;
00589                l--;
00590                if (!l) {
00591                   break;
00592                }
00593             }
00594          }
00595          /* adjust for fill, septets */
00596          if (b) {
00597             b = 7 - b;
00598             l--;
00599          }
00600       }
00601    }
00602    while (l--) {
00603       unsigned char v;
00604       if (b < 2) {
00605          v = ((i[p] >> b) & 0x7F);       /* everything in one byte */
00606       } else {
00607          v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
00608       }
00609       b += 7;
00610       if (b >= 8) {
00611          b -= 8;
00612          p++;
00613       }
00614       /* 0x00A0 is the encoding of ESC (27) in defaultalphabet */
00615       if (o > ud && o[-1] == 0x00A0 && escapes[v]) {
00616          o[-1] = escapes[v];
00617       } else {
00618          *o++ = defaultalphabet[v];
00619       }
00620    }
00621    *udl = (o - ud);
00622 }

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

Referenced by unpacksms().

00629 {
00630    unsigned short *o = ud;
00631    *udhl = 0;
00632    if (udhi) {
00633       int n = *i;
00634       *udhl = n;
00635       if (n) {
00636          i++;
00637          l--;
00638          while (l && n) {
00639             l--;
00640             n--;
00641             *udh++ = *i++;
00642          }
00643       }
00644    }
00645    while (l--) {
00646       *o++ = *i++;                        /* not to UTF-8 as explicitly 8 bit coding in DCS */
00647    }
00648    *udl = (o - ud);
00649 }

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

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

Definition at line 285 of file app_sms.c.

Referenced by sms_readfile().

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


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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static]

Definition at line 2042 of file app_sms.c.

char* app = "SMS" [static]

Definition at line 69 of file app_sms.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2042 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.

Referenced by load_module().

volatile unsigned char message_ref [static]

Definition at line 64 of file app_sms.c.

Referenced by sms_compose1().

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(), sms_writefile(), statpost(), and udptl_build_packet().

enum { ... } sms_flags

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 1834 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 1655 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(), and load_module().

const output_t* wave_out = wave [static]

Definition at line 120 of file app_sms.c.

Referenced by sms_generate().


Generated on Wed Aug 18 22:34:02 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7