Asterisk - The Open Source Telephony Project GIT-master-5467495
Loading...
Searching...
No Matches
Data Structures | Macros | Typedefs | Enumerations | Functions | Variables
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"
#include "asterisk/format_cache.h"
Include dependency graph for app_sms.c:

Go to the source code of this file.

Data Structures

struct  sms_s
 

Macros

#define __OUT_FMT   ast_format_slin
 
#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 /* initial sync bits */
 
#define SMSLEN   160
 
#define SMSLEN_8   140
 

Typedefs

typedef signed short output_t
 
typedef struct sms_s sms_t
 

Enumerations

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
}
 
enum  sms_flags {
  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) , OPTIONS_NO_LOG = (1 << 6)
}
 
enum  sms_opt_args { OPTION_ARG_PAUSE = 0 , OPTION_ARG_ARRAY_SIZE }
 

Functions

static void adddata_proto2 (sms_t *h, unsigned char msg, char *data, int size)
 
 AST_MODULE_INFO_STANDARD_EXTENDED (ASTERISK_GPL_KEY, "SMS/PSTN handler")
 
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, const char *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, size_t o_size, 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, size_t udh_size, int *udhl, unsigned short *ud, size_t ud_size, 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, size_t udh_size, int *udhl, unsigned short *ud, size_t ud_size, 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, size_t udh_size, int *udhl, unsigned short *ud, size_t ud_size, 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, size_t udh_size, int *udhl, unsigned short *ud, size_t ud_size, 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 char * app = "SMS"
 
static const unsigned short defaultalphabet []
 
static const unsigned short escapes []
 
static char log_file [255]
 
static volatile unsigned char message_ref
 
static volatile unsigned int seq
 
static const 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 }, [ 'n' ] = { .flag = OPTIONS_NO_LOG }, [ 'p' ] = { .flag = OPTION_PAUSE , .arg_index = OPTION_ARG_PAUSE + 1 }, }
 
static struct ast_generator smsgen
 
static const 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
Itzan Huerta - Testing and debugging for Telefónica DOMO Mensajes (Spain) phones using protocol 2.

Definition in file app_sms.c.

Macro Definition Documentation

◆ __OUT_FMT

#define __OUT_FMT   ast_format_slin

Definition at line 155 of file app_sms.c.

◆ DIR_RX

#define DIR_RX   1

Definition at line 1535 of file app_sms.c.

◆ DIR_TX

#define DIR_TX   2

Definition at line 1536 of file app_sms.c.

◆ DLL2_ACK

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

◆ is16bit

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

Definition at line 289 of file app_sms.c.

◆ is7bit

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

Definition at line 287 of file app_sms.c.

◆ is8bit

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

Definition at line 288 of file app_sms.c.

◆ MAX_DEBUG_LEN

#define MAX_DEBUG_LEN   300

Definition at line 1299 of file app_sms.c.

◆ MAXSAMPLES

#define MAXSAMPLES   (800)

◆ OSYNC_BITS

#define OSYNC_BITS   80 /* initial sync bits */

Definition at line 158 of file app_sms.c.

◆ SMSLEN

#define SMSLEN   160

max SMS length

Definition at line 221 of file app_sms.c.

◆ SMSLEN_8

#define SMSLEN_8   140

max SMS length for 8-bit char

Definition at line 222 of file app_sms.c.

Typedef Documentation

◆ output_t

typedef signed short output_t

Definition at line 153 of file app_sms.c.

◆ sms_t

typedef struct sms_s sms_t

Enumeration Type Documentation

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

167 {
168 DLL_SMS_MASK = 0x7f, /* mask for the valid bits */
169
170 /* Protocol 1 values */
171 DLL1_SMS_DATA = 0x11, /* data packet */
172 DLL1_SMS_ERROR = 0x12,
173 DLL1_SMS_EST = 0x13, /* start the connection */
174 DLL1_SMS_REL = 0x14, /* end the connection */
175 DLL1_SMS_ACK = 0x15,
176 DLL1_SMS_NACK = 0x16,
177
178 DLL1_SMS_COMPLETE = 0x80, /* packet is complete */
179 DLL1_SMS_MORE = 0x00, /* more data to follow */
180
181 /* Protocol 2 values */
182 DLL2_SMS_EST = 0x7f, /* magic number. No message body */
183 DLL2_SMS_INFO_MO = 0x10,
184 DLL2_SMS_INFO_MT = 0x11,
185 DLL2_SMS_INFO_STA = 0x12,
186 DLL2_SMS_NACK = 0x13,
187 DLL2_SMS_ACK0 = 0x14, /* ack even-numbered frame */
188 DLL2_SMS_ACK1 = 0x15, /* ack odd-numbered frame */
189 DLL2_SMS_ENQ = 0x16,
190 DLL2_SMS_REL = 0x17, /* end the connection */
191
192 DLL2_SMS_COMPLETE = 0x00, /* packet is complete */
193 DLL2_SMS_MORE = 0x80, /* more data to follow */
194};
@ DLL2_SMS_INFO_MT
Definition app_sms.c:184
@ DLL2_SMS_ACK1
Definition app_sms.c:188
@ DLL1_SMS_MORE
Definition app_sms.c:179
@ DLL2_SMS_ACK0
Definition app_sms.c:187
@ DLL1_SMS_ERROR
Definition app_sms.c:172
@ DLL2_SMS_INFO_STA
Definition app_sms.c:185
@ DLL2_SMS_MORE
Definition app_sms.c:193
@ DLL1_SMS_DATA
Definition app_sms.c:171
@ DLL2_SMS_INFO_MO
Definition app_sms.c:183
@ DLL2_SMS_REL
Definition app_sms.c:190
@ DLL2_SMS_EST
Definition app_sms.c:182
@ DLL1_SMS_NACK
Definition app_sms.c:176
@ DLL1_SMS_ACK
Definition app_sms.c:175
@ DLL1_SMS_COMPLETE
Definition app_sms.c:178
@ DLL1_SMS_EST
Definition app_sms.c:173
@ DLL_SMS_MASK
Definition app_sms.c:168
@ DLL2_SMS_COMPLETE
Definition app_sms.c:192
@ DLL2_SMS_NACK
Definition app_sms.c:186
@ DLL2_SMS_ENQ
Definition app_sms.c:189
@ DLL1_SMS_REL
Definition app_sms.c:174

◆ sms_flags

enum sms_flags
Enumerator
OPTION_BE_SMSC 
OPTION_ANSWER 
OPTION_TWO 
OPTION_PAUSE 
OPTION_SRR 
OPTION_DCS 
OPTIONS_NO_LOG 

Definition at line 1908 of file app_sms.c.

1908 {
1909 OPTION_BE_SMSC = (1 << 0), /* act as sms center */
1910 OPTION_ANSWER = (1 << 1), /* answer on incoming calls */
1911 OPTION_TWO = (1 << 2), /* Use Protocol Two */
1912 OPTION_PAUSE = (1 << 3), /* pause before sending data, in ms */
1913 OPTION_SRR = (1 << 4), /* set srr */
1914 OPTION_DCS = (1 << 5), /* set dcs */
1915 OPTIONS_NO_LOG = (1 << 6), /* Don't log SMS content */
1916};
@ OPTION_ANSWER
Definition app_sms.c:1910
@ OPTION_SRR
Definition app_sms.c:1913
@ OPTIONS_NO_LOG
Definition app_sms.c:1915
@ OPTION_TWO
Definition app_sms.c:1911
@ OPTION_BE_SMSC
Definition app_sms.c:1909
@ OPTION_PAUSE
Definition app_sms.c:1912
@ OPTION_DCS
Definition app_sms.c:1914

◆ sms_opt_args

Enumerator
OPTION_ARG_PAUSE 
OPTION_ARG_ARRAY_SIZE 

Definition at line 1918 of file app_sms.c.

1918 {
1919 OPTION_ARG_PAUSE = 0,
1921};
@ OPTION_ARG_PAUSE
Definition app_sms.c:1919
@ OPTION_ARG_ARRAY_SIZE
Definition app_sms.c:1920

Function Documentation

◆ adddata_proto2()

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

1240{
1241 int x = h->omsg[1] + 2; /* Get current position */
1242 if (x == 2) {
1243 x += 2; /* First: skip Payload length (set later) */
1244 }
1245 h->omsg[x++] = msg; /* Message code */
1246 h->omsg[x++] = (unsigned char)size; /* Data size Low */
1247 h->omsg[x++] = 0; /* Data size Hi */
1248 for (; size > 0 ; size--) {
1249 h->omsg[x++] = *data++;
1250 }
1251 h->omsg[1] = x - 2; /* Frame size */
1252 h->omsg[2] = x - 4; /* Payload length (Lo) */
1253 h->omsg[3] = 0; /* Payload length (Hi) */
1254}
unsigned char omsg[256]
Definition app_sms.c:255

References sms_s::omsg.

Referenced by putdummydata_proto2(), and sms_compose2().

◆ AST_MODULE_INFO_STANDARD_EXTENDED()

AST_MODULE_INFO_STANDARD_EXTENDED ( ASTERISK_GPL_KEY  ,
"SMS/PSTN handler"   
)

◆ isodate()

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

static, return a date/time in ISO format

Definition at line 309 of file app_sms.c.

310{
311 struct ast_tm tm;
312 struct timeval local = { t, 0 };
313 ast_localtime(&local, &tm, NULL);
314 ast_strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm);
315 return buf;
316}
char buf[BUFSIZE]
Definition eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition localtime.c:1739
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition localtime.c:2524
#define NULL
Definition resample.c:96

References ast_localtime(), ast_strftime(), buf, len(), and NULL.

Referenced by sms_log(), and sms_writefile().

◆ load_module()

static int load_module ( void  )
static

Definition at line 2135 of file app_sms.c.

2136{
2137#ifdef OUTALAW
2138 int p;
2139 for (p = 0; p < 80; p++) {
2140 wavea[p] = AST_LIN2A(wave[p]);
2141 }
2142#endif
2143 snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR);
2145}
#define AST_LIN2A(a)
Definition alaw.h:50
static int sms_exec(struct ast_channel *chan, const char *data)
Definition app_sms.c:1933
static char * app
Definition app_sms.c:130
static const signed short wave[]
Definition app_sms.c:138
static char log_file[255]
Definition app_sms.c:128
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640
const char * ast_config_AST_LOG_DIR
Definition options.c:160

References app, ast_config_AST_LOG_DIR, AST_LIN2A, ast_register_application_xml, log_file, sms_exec(), and wave.

◆ numcpy()

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

copy number, skipping non digits apart from leading +

Definition at line 294 of file app_sms.c.

295{
296 if (*s == '+') {
297 *d++ = *s++;
298 }
299 while (*s) {
300 if (isdigit(*s)) {
301 *d++ = *s;
302 }
303 s++;
304 }
305 *d = 0;
306}
static struct test_val d

References d.

Referenced by sms_readfile().

◆ packaddress()

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

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

Definition at line 796 of file app_sms.c.

797{
798 unsigned char p = 2;
799 o[0] = 0; /* number of bytes */
800 if (*i == '+') { /* record as bit 0 in byte 1 */
801 i++;
802 o[1] = 0x91;
803 } else {
804 o[1] = 0x81;
805 }
806 for ( ; *i ; i++) {
807 if (!isdigit(*i)) { /* ignore non-digits */
808 continue;
809 }
810 if (o[0] & 1) {
811 o[p++] |= ((*i & 0xF) << 4);
812 } else {
813 o[p] = (*i & 0xF);
814 }
815 o[0]++;
816 }
817 if (o[0] & 1) {
818 o[p++] |= 0xF0; /* pad */
819 }
820 return p;
821}

Referenced by sms_compose1().

◆ packdate()

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

pack a date and return

Definition at line 559 of file app_sms.c.

560{
561 struct ast_tm t;
562 struct timeval topack = { w, 0 };
563 int z;
564
565 ast_localtime(&topack, &t, NULL);
566#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) || defined(__CYGWIN__)
567 z = -t.tm_gmtoff / 60 / 15;
568#else
569 z = timezone / 60 / 15;
570#endif
571 *o++ = ((t.tm_year % 10) << 4) + (t.tm_year % 100) / 10;
572 *o++ = (((t.tm_mon + 1) % 10) << 4) + (t.tm_mon + 1) / 10;
573 *o++ = ((t.tm_mday % 10) << 4) + t.tm_mday / 10;
574 *o++ = ((t.tm_hour % 10) << 4) + t.tm_hour / 10;
575 *o++ = ((t.tm_min % 10) << 4) + t.tm_min / 10;
576 *o++ = ((t.tm_sec % 10) << 4) + t.tm_sec / 10;
577 if (z < 0) {
578 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
579 } else {
580 *o++ = ((z % 10) << 4) + z / 10;
581 }
582}

References ast_localtime(), NULL, 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().

◆ packsms()

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

527{
528 unsigned char *p = base;
529 if (udl == 0) {
530 *p++ = 0; /* no user data */
531 } else {
532
533 int l = 0;
534 if (is7bit(dcs)) { /* 7 bit */
535 if ((l = packsms7(p + 1, udhl, udh, udl, ud)) < 0) {
536 l = 0;
537 }
538 *p++ = l;
539 p += (l * 7 + 7) / 8;
540 } else if (is8bit(dcs)) { /* 8 bit */
541 if ((l = packsms8(p + 1, udhl, udh, udl, ud)) < 0) {
542 l = 0;
543 }
544 *p++ = l;
545 p += l;
546 } else { /* UCS-2 */
547 if ((l = packsms16(p + 1, udhl, udh, udl, ud)) < 0) {
548 l = 0;
549 }
550 *p++ = l;
551 p += l;
552 }
553 }
554 return p - base;
555}
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 ...
Definition app_sms.c:375
#define is7bit(dcs)
Definition app_sms.c:287
#define is8bit(dcs)
Definition app_sms.c:288
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 ...
Definition app_sms.c:491
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 ...
Definition app_sms.c:452

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

Referenced by sms_compose1().

◆ packsms16()

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

492{
493 unsigned char p = 0;
494 unsigned char dummy[SMSLEN_8];
495
496 if (o == NULL) {
497 o = dummy;
498 }
499 /* header - no encoding */
500 if (udhl) {
501 o[p++] = udhl;
502 while (udhl--) {
503 o[p++] = *udh++;
504 if (p >= SMSLEN_8) {
505 return p;
506 }
507 }
508 }
509 while (udl--) {
510 long u;
511 u = *ud++;
512 o[p++] = (u >> 8);
513 if (p >= SMSLEN_8) {
514 return p - 1; /* could not fit last character */
515 }
516 o[p++] = u;
517 if (p >= SMSLEN_8) {
518 return p;
519 }
520 }
521 return p;
522}
#define SMSLEN_8
Definition app_sms.c:222
static void dummy(char *unused,...)

References dummy(), NULL, and SMSLEN_8.

Referenced by packsms(), and sms_readfile().

◆ packsms7()

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

376{
377 unsigned char p = 0; /* output pointer (bytes) */
378 unsigned char b = 0; /* bit position */
379 unsigned char n = 0; /* output character count */
380 unsigned char dummy[SMSLEN];
381
382 if (o == NULL) { /* output to a dummy buffer if o not set */
383 o = dummy;
384 }
385
386 if (udhl) { /* header */
387 o[p++] = udhl;
388 b = 1;
389 n = 1;
390 while (udhl--) {
391 o[p++] = *udh++;
392 b += 8;
393 while (b >= 7) {
394 b -= 7;
395 n++;
396 }
397 if (n >= SMSLEN)
398 return n;
399 }
400 if (b) {
401 b = 7 - b;
402 if (++n >= SMSLEN)
403 return n;
404 } /* filling to septet boundary */
405 }
406 o[p] = 0;
407 /* message */
408 while (udl--) {
409 long u;
410 unsigned char v;
411 u = *ud++;
412 /* XXX 0 is invalid ? */
413 /* look up in defaultalphabet[]. If found, v is the 7-bit code */
414 for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
415 if (v == 128 /* not found */ && u && n + 1 < SMSLEN) {
416 /* if not found, look in the escapes table (we need 2 bytes) */
417 for (v = 0; v < 128 && escapes[v] != u; v++);
418 if (v < 128) { /* escaped sequence, esc + v */
419 /* store the low (8-b) bits in o[p], the remaining bits in o[p+1] */
420 o[p] |= (27 << b); /* the low bits go into o[p] */
421 b += 7;
422 if (b >= 8) {
423 b -= 8;
424 p++;
425 o[p] = (27 >> (7 - b));
426 }
427 n++;
428 }
429 }
430 if (v == 128)
431 return -1; /* invalid character */
432 /* store, same as above */
433 o[p] |= (v << b);
434 b += 7;
435 if (b >= 8) {
436 b -= 8;
437 p++;
438 o[p] = (v >> (7 - b));
439 }
440 if (++n >= SMSLEN)
441 return n;
442 }
443 return n;
444}
static const unsigned short defaultalphabet[]
Definition app_sms.c:197
static const unsigned short escapes[]
Definition app_sms.c:210
#define SMSLEN
Definition app_sms.c:221
static struct test_val b

References b, defaultalphabet, dummy(), escapes, NULL, and SMSLEN.

Referenced by packsms(), and sms_readfile().

◆ packsms8()

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

453{
454 unsigned char p = 0;
455 unsigned char dummy[SMSLEN_8];
456
457 if (o == NULL)
458 o = dummy;
459 /* header - no encoding */
460 if (udhl) {
461 o[p++] = udhl;
462 while (udhl--) {
463 o[p++] = *udh++;
464 if (p >= SMSLEN_8) {
465 return p;
466 }
467 }
468 }
469 while (udl--) {
470 long u;
471 u = *ud++;
472 if (u < 0 || u > 0xFF) {
473 return -1; /* not valid */
474 }
475 o[p++] = u;
476 if (p >= SMSLEN_8) {
477 return p;
478 }
479 }
480 return p;
481}

References dummy(), NULL, and SMSLEN_8.

Referenced by packsms(), and sms_readfile().

◆ putdummydata_proto2()

static void putdummydata_proto2 ( sms_t h)
static

Definition at line 1256 of file app_sms.c.

1257{
1258 adddata_proto2(h, 0x10, "\0", 1); /* Media Identifier > SMS */
1259 adddata_proto2(h, 0x11, "\0\0\0\0\0\0", 6); /* Firmware version */
1260 adddata_proto2(h, 0x12, "\2\0\4", 3); /* SMS provider ID */
1261 adddata_proto2(h, 0x13, h->udtxt, h->udl); /* Body */
1262}
static void adddata_proto2(sms_t *h, unsigned char msg, char *data, int size)
Definition app_sms.c:1239
char udtxt[SMSLEN]
Definition app_sms.c:283
int udl
Definition app_sms.c:238

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

Referenced by sms_compose2().

◆ readdirqueue()

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

read dir skipping dot files...

Definition at line 1153 of file app_sms.c.

1154{
1155 struct dirent *f;
1156 do {
1157 f = readdir(d);
1158 } while (f && (*f->d_name == '.' || strncmp(f->d_name, queue, strlen(queue)) || f->d_name[strlen(queue)] != '.'));
1159 return f;
1160}

References d.

Referenced by sms_nextoutgoing().

◆ sms_alloc()

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

1737{
1738 return sms_t_ptr;
1739}

◆ sms_compose1()

static void sms_compose1 ( sms_t h,
int  more 
)
static

compose a message for protocol 1

Definition at line 1451 of file app_sms.c.

1452{
1453 unsigned int p = 2; /* next byte to write. Skip type and len */
1454
1455 h->omsg[0] = 0x91; /* SMS_DATA */
1456 if (h->smsc) { /* deliver */
1457 h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
1458 p += packaddress(h->omsg + p, h->oa);
1459 h->omsg[p++] = h->pid;
1460 h->omsg[p++] = h->dcs;
1461 packdate(h->omsg + p, h->scts.tv_sec);
1462 p += 7;
1463 p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1464 } else { /* submit */
1465 h->omsg[p++] =
1466 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
1467 if (h->mr < 0) {
1468 h->mr = message_ref++;
1469 }
1470 h->omsg[p++] = h->mr;
1471 p += packaddress(h->omsg + p, h->da);
1472 h->omsg[p++] = h->pid;
1473 h->omsg[p++] = h->dcs;
1474 if (h->vp) { /* relative VP */
1475 if (h->vp < 720) {
1476 h->omsg[p++] = (h->vp + 4) / 5 - 1;
1477 } else if (h->vp < 1440) {
1478 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
1479 } else if (h->vp < 43200) {
1480 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
1481 } else if (h->vp < 635040) {
1482 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
1483 } else {
1484 h->omsg[p++] = 255; /* max */
1485 }
1486 }
1487 p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1488 }
1489 h->omsg[1] = p - 2;
1490}
static volatile unsigned char message_ref
Definition app_sms.c:125
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
Definition app_sms.c:526
static void packdate(unsigned char *o, time_t w)
pack a date and return
Definition app_sms.c:559
static unsigned char packaddress(unsigned char *o, char *i)
store an address at o, and return number of bytes used
Definition app_sms.c:796
unsigned char srr
Definition app_sms.c:240
unsigned char dcs
Definition app_sms.c:236
char da[20]
Definition app_sms.c:233
unsigned char pid
Definition app_sms.c:235
char oa[20]
Definition app_sms.c:232
unsigned char udh[SMSLEN]
Definition app_sms.c:245
short mr
Definition app_sms.c:237
struct timeval scts
Definition app_sms.c:234
int udhl
Definition app_sms.c:239
unsigned char smsc
Definition app_sms.c:228
unsigned int vp
Definition app_sms.c:243
unsigned short ud[SMSLEN]
Definition app_sms.c:244

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().

◆ sms_compose2()

static void sms_compose2 ( sms_t h,
int  more 
)
static

Definition at line 1264 of file app_sms.c.

1265{
1266 struct ast_tm tm;
1267 struct timeval now = h->scts;
1268 char stm[45];
1269
1270 h->omsg[0] = 0x00; /* set later... */
1271 h->omsg[1] = 0;
1273 if (h->smsc) { /* deliver */
1274 h->omsg[0] = 0x11; /* SMS_DELIVERY */
1275 /* Required: 10 11 12 13 14 15 17 (seems they must be ordered!) */
1276 ast_localtime(&now, &tm, NULL);
1277 sprintf(stm, "%02d%02d%02d%02d", tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min); /* Date mmddHHMM */
1278 adddata_proto2(h, 0x14, stm, 8); /* Date */
1279 if (*h->oa == 0) {
1280 strcpy(h->oa, "00000000");
1281 }
1282 adddata_proto2(h, 0x15, h->oa, strlen(h->oa)); /* Originator */
1283 adddata_proto2(h, 0x17, "\1", 1); /* Calling Terminal ID */
1284 } else { /* submit */
1285 h->omsg[0] = 0x10; /* SMS_SUBMIT */
1286 /* Required: 10 11 12 13 17 18 1B 1C (seems they must be ordered!) */
1287 adddata_proto2(h, 0x17, "\1", 1); /* Calling Terminal ID */
1288 if (*h->da == 0) {
1289 strcpy(h->da, "00000000");
1290 }
1291 adddata_proto2(h, 0x18, h->da, strlen(h->da)); /* Originator */
1292 adddata_proto2(h, 0x1B, "\1", 1); /* Called Terminal ID */
1293 adddata_proto2(h, 0x1C, "\0\0\0", 3); /* Notification */
1294 }
1295}
static void putdummydata_proto2(sms_t *h)
Definition app_sms.c:1256

References adddata_proto2(), ast_localtime(), sms_s::da, NULL, 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().

◆ sms_debug()

static void sms_debug ( int  dir,
sms_t h 
)
static

Definition at line 1537 of file app_sms.c.

1538{
1539 char txt[259 * 3 + 1];
1540 char *p = txt; /* always long enough */
1541 unsigned char *msg = (dir == DIR_RX) ? h->imsg : h->omsg;
1542 int n = (dir == DIR_RX) ? h->ibytep : msg[1] + 2;
1543 int q = 0;
1544 while (q < n && q < 30) {
1545 sprintf(p, " %02hhX", msg[q++]);
1546 p += 3;
1547 }
1548 if (q < n) {
1549 sprintf(p, "...");
1550 }
1551 ast_verb(3, "SMS %s%s\n", dir == DIR_RX ? "RX" : "TX", txt);
1552}
#define DIR_RX
Definition app_sms.c:1535
#define ast_verb(level,...)
unsigned char ibytep
Definition app_sms.c:272
unsigned char imsg[250]
Definition app_sms.c:256

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

Referenced by sms_messagerx(), and sms_messagetx().

◆ sms_exec()

static int sms_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 1933 of file app_sms.c.

1934{
1935 int res = -1;
1936 sms_t h = { 0 };
1937 /* argument parsing support */
1938 struct ast_flags flags = { 0 };
1939 char *parse, *sms_opts[OPTION_ARG_ARRAY_SIZE] = { 0, };
1940 char *p;
1941 AST_DECLARE_APP_ARGS(sms_args,
1942 AST_APP_ARG(queue);
1944 AST_APP_ARG(addr);
1945 AST_APP_ARG(body);
1946 );
1947
1948 if (!data) {
1949 ast_log(LOG_ERROR, "Requires queue name at least\n");
1950 return -1;
1951 }
1952
1953 parse = ast_strdupa(data); /* create a local copy */
1954 AST_STANDARD_APP_ARGS(sms_args, parse);
1955 if (sms_args.argc > 1) {
1956 ast_app_parse_options(sms_options, &flags, sms_opts, sms_args.options);
1957 }
1958
1959 ast_verb(1, "sms argc %u queue <%s> opts <%s> addr <%s> body <%s>\n",
1960 sms_args.argc, S_OR(sms_args.queue, ""),
1961 S_OR(sms_args.options, ""),
1962 S_OR(sms_args.addr, ""),
1963 S_OR(sms_args.body, "") );
1964
1965 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1966 h.dcs = 0xF1; /* default */
1967
1969 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
1970 sizeof(h.cli));
1971
1972 if (ast_strlen_zero(sms_args.queue)) {
1973 ast_log(LOG_ERROR, "Requires queue name\n");
1974 goto done;
1975 }
1976 if (strlen(sms_args.queue) >= sizeof(h.queue)) {
1977 ast_log(LOG_ERROR, "Queue name too long\n");
1978 goto done;
1979 }
1980 ast_copy_string(h.queue, sms_args.queue, sizeof(h.queue));
1981
1982 for (p = h.queue; *p; p++) {
1983 if (!isalnum(*p)) {
1984 *p = '-'; /* make very safe for filenames */
1985 }
1986 }
1987
1989 h.protocol = ast_test_flag(&flags, OPTION_TWO) ? 2 : 1;
1990 h.nolog = ast_test_flag(&flags, OPTIONS_NO_LOG) ? 1 : 0;
1991 if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE])) {
1992 h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]);
1993 }
1994 if (h.opause_0 < 25 || h.opause_0 > 2000) {
1995 h.opause_0 = 300; /* default 300ms */
1996 }
1997 ast_verb(1, "initial delay %dms\n", h.opause_0);
1998
1999
2000 /* the following apply if there is an arg3/4 and apply to the created message file */
2002 h.srr = 1;
2003 }
2005 h.dcs = 1;
2006 }
2007#if 0
2008 case '1':
2009 case '2':
2010 case '3':
2011 case '4':
2012 case '5':
2013 case '6':
2014 case '7': /* set the pid for saved local message */
2015 h.pid = 0x40 + (*d & 0xF);
2016 break;
2017 }
2018#endif
2019 if (sms_args.argc > 2) {
2020 unsigned char *up;
2021
2022 /* submitting a message, not taking call. */
2023 /* deprecated, use smsq instead */
2024 h.scts = ast_tvnow();
2025 if (ast_strlen_zero(sms_args.addr) || strlen(sms_args.addr) >= sizeof(h.oa)) {
2026 ast_log(LOG_ERROR, "Address too long %s\n", sms_args.addr);
2027 goto done;
2028 }
2029 if (h.smsc) {
2030 ast_copy_string(h.oa, sms_args.addr, sizeof(h.oa));
2031 } else {
2032 ast_copy_string(h.da, sms_args.addr, sizeof(h.da));
2033 ast_copy_string(h.oa, h.cli, sizeof(h.oa));
2034 }
2035 h.udl = 0;
2036 if (ast_strlen_zero(sms_args.body)) {
2037 ast_log(LOG_ERROR, "Missing body for %s\n", sms_args.addr);
2038 goto done;
2039 }
2040 up = (unsigned char *)sms_args.body;
2041 while (*up && h.udl < SMSLEN) {
2042 h.ud[h.udl++] = utf8decode(&up);
2043 }
2044 if (is7bit(h.dcs) && packsms7(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
2045 ast_log(LOG_WARNING, "Invalid 7 bit GSM data\n");
2046 goto done;
2047 }
2048 if (is8bit(h.dcs) && packsms8(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
2049 ast_log(LOG_WARNING, "Invalid 8 bit data\n");
2050 goto done;
2051 }
2052 if (is16bit(h.dcs) && packsms16(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
2053 ast_log(LOG_WARNING, "Invalid 16 bit data\n");
2054 goto done;
2055 }
2056 h.rx = 0; /* sent message */
2057 h.mr = -1;
2058 sms_writefile(&h);
2059 res = h.err;
2060 goto done;
2061 }
2062
2063 if (ast_channel_state(chan) != AST_STATE_UP) { /* make sure channel is answered before any TX */
2064 ast_answer(chan);
2065 }
2066
2068 h.framenumber = 1; /* Proto 2 */
2069 /* set up SMS_EST initial message */
2070 if (h.protocol == 2) {
2071 h.omsg[0] = DLL2_SMS_EST;
2072 h.omsg[1] = 0;
2073 } else {
2075 h.omsg[1] = 0;
2076 }
2077 sms_messagetx(&h);
2078 }
2079
2080 res = ast_set_write_format(chan, __OUT_FMT);
2081 if (res >= 0) {
2083 }
2084 if (res < 0) {
2085 ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n");
2086 goto done;
2087 }
2088
2089 if ( (res = ast_activate_generator(chan, &smsgen, &h)) < 0) {
2090 ast_log(LOG_ERROR, "Failed to activate generator on '%s'\n", ast_channel_name(chan));
2091 goto done;
2092 }
2093
2094 /* Do our thing here */
2095 for (;;) {
2096 struct ast_frame *f;
2097 int i = ast_waitfor(chan, -1);
2098 if (i < 0) {
2099 ast_log(LOG_NOTICE, "waitfor failed\n");
2100 break;
2101 }
2102 if (h.hangup) {
2103 ast_log(LOG_NOTICE, "channel hangup\n");
2104 break;
2105 }
2106 f = ast_read(chan);
2107 if (!f) {
2108 ast_log(LOG_NOTICE, "ast_read failed\n");
2109 break;
2110 }
2111 if (f->frametype == AST_FRAME_VOICE) {
2112 sms_process(&h, f->samples, f->data.ptr);
2113 }
2114
2115 ast_frfree(f);
2116 }
2117 res = h.err; /* XXX */
2118
2119 /*
2120 * The SMS generator data is on the stack. We _MUST_ make sure the generator
2121 * is stopped before returning from this function.
2122 */
2124
2125 sms_log(&h, '?'); /* log incomplete message */
2126done:
2127 return (res);
2128}
static struct ast_generator smsgen
Definition app_sms.c:1746
static long utf8decode(unsigned char **pp)
Reads next UCS character from NUL terminated UTF-8 string and advance pointer.
Definition app_sms.c:321
static void sms_messagetx(sms_t *h)
Definition app_sms.c:1613
#define __OUT_FMT
Definition app_sms.c:155
#define is16bit(dcs)
Definition app_sms.c:289
static void sms_process(sms_t *h, int samples, signed short *data)
Definition app_sms.c:1764
static const struct ast_app_option sms_options[128]
Definition app_sms.c:1931
static void sms_log(sms_t *h, char status)
Log the output, and remove file.
Definition app_sms.c:824
static void sms_writefile(sms_t *h)
white a received text message to a file
Definition app_sms.c:1049
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_log
Definition astobj2.c:42
const char * ast_channel_name(const struct ast_channel *chan)
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition channel.c:2955
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3166
void ast_deactivate_generator(struct ast_channel *chan)
Definition channel.c:2892
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4278
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition channel.c:5785
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition channel.c:5826
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition channel.c:2805
ast_channel_state
ast_channel states
@ AST_STATE_UP
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition main/app.c:3067
#define ast_frfree(fr)
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
Structure used to handle boolean flags.
Definition utils.h:220
unsigned int flags
Definition utils.h:221
Data structure associated with a single frame of data.
enum ast_frame_type frametype
union ast_frame::@237 data
Number structure.
int opause_0
Definition app_sms.c:279
unsigned char err
Definition app_sms.c:226
char cli[20]
Definition app_sms.c:246
unsigned char nolog
Definition app_sms.c:230
unsigned char ipc1
Definition app_sms.c:266
int framenumber
Definition app_sms.c:282
int protocol
Definition app_sms.c:280
unsigned char hangup
Definition app_sms.c:225
unsigned char rx
Definition app_sms.c:229
unsigned char ipc0
Definition app_sms.c:265
char queue[30]
Definition app_sms.c:231
int done
static struct test_options options
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
#define ast_test_flag(p, flag)
Definition utils.h:64

References AST_APP_ARG, ast_app_parse_options(), ast_channel_caller(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, sms_s::cli, d, sms_s::dcs, done, ast_flags::flags, sms_s::ipc0, sms_s::ipc1, LOG_ERROR, sms_s::nolog, sms_s::opause_0, OPTION_ARG_ARRAY_SIZE, OPTION_ARG_PAUSE, OPTION_BE_SMSC, OPTION_DCS, OPTION_SRR, OPTION_TWO, options, OPTIONS_NO_LOG, sms_s::pid, sms_s::protocol, sms_s::queue, S_COR, S_OR, sms_options, sms_s::smsc, and sms_s::srr.

Referenced by load_module().

◆ sms_generate()

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

1657{
1658 struct ast_frame f = { 0 };
1659#define MAXSAMPLES (800)
1660 output_t *buf;
1661 sms_t *h = data;
1662 int i, res;
1663
1664 if (samples > MAXSAMPLES) {
1665 ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n",
1668 }
1669 len = samples * sizeof(*buf) + AST_FRIENDLY_OFFSET;
1670 buf = ast_alloca(len);
1671
1674 f.datalen = samples * sizeof(*buf);
1676 f.mallocd = 0;
1677 f.data.ptr = buf;
1678 f.samples = samples;
1679 f.src = "app_sms";
1680 /* create a buffer containing the digital sms pattern */
1681 for (i = 0; i < samples; i++) {
1682 buf[i] = wave_out[0]; /* default is silence */
1683
1684 if (h->opause) {
1685 h->opause--;
1686 } else if (h->obyten || h->osync) { /* sending data */
1687 buf[i] = wave_out[h->ophase];
1688 h->ophase += (h->obyte & 1) ? 13 : 21; /* compute next phase */
1689 if (h->ophase >= 80)
1690 h->ophase -= 80;
1691 if ((h->ophasep += 12) >= 80) { /* time to send the next bit */
1692 h->ophasep -= 80;
1693 if (h->oseizure > 0) { /* sending channel seizure (proto 2) */
1694 h->oseizure--;
1695 h->obyte ^= 1; /* toggle low bit */
1696 } else if (h->osync) {
1697 h->obyte = 1; /* send mark as sync bit */
1698 h->osync--; /* sending sync bits */
1699 if (h->osync == 0 && h->protocol == 2 && h->omsg[0] == DLL2_SMS_EST) {
1700 h->obytep = h->obyten = 0; /* we are done */
1701 }
1702 } else {
1703 h->obitp++;
1704 if (h->obitp == 1) {
1705 h->obyte = 0; /* start bit; */
1706 } else if (h->obitp == 2) {
1707 h->obyte = h->omsg[h->obytep];
1708 } else if (h->obitp == 10) {
1709 h->obyte = 1; /* stop bit */
1710 h->obitp = 0;
1711 h->obytep++;
1712 if (h->obytep == h->obyten) {
1713 h->obytep = h->obyten = 0; /* sent */
1714 h->osync = 10; /* trailing marks */
1715 }
1716 } else {
1717 h->obyte >>= 1;
1718 }
1719 }
1720 }
1721 }
1722 }
1723 res = ast_write(chan, &f);
1724 ast_frfree(&f);
1725 if (res < 0) {
1726 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
1727 return -1;
1728 }
1729 return 0;
1730#undef MAXSAMPLES
1731}
static const output_t * wave_out
Definition app_sms.c:154
signed short output_t
Definition app_sms.c:153
#define MAXSAMPLES
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition channel.c:5167
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
int errno
struct ast_format * format
struct ast_frame_subclass subclass
unsigned char obyten
Definition app_sms.c:254
unsigned char osync
Definition app_sms.c:252
unsigned char ophasep
Definition app_sms.c:248
unsigned int opause
Definition app_sms.c:250
int oseizure
Definition app_sms.c:281
unsigned char obytep
Definition app_sms.c:253
unsigned char obyte
Definition app_sms.c:249
unsigned char obitp
Definition app_sms.c:251
unsigned char ophase
Definition app_sms.c:247

References __OUT_FMT, ast_alloca, ast_channel_name(), AST_FRAME_VOICE, ast_frfree, AST_FRIENDLY_OFFSET, ast_log, ast_write(), buf, ast_frame::data, ast_frame::datalen, DLL2_SMS_EST, errno, ast_frame_subclass::format, ast_frame::frametype, len(), LOG_WARNING, ast_frame::mallocd, MAXSAMPLES, sms_s::obitp, sms_s::obyte, sms_s::obyten, sms_s::obytep, ast_frame::offset, sms_s::omsg, sms_s::opause, sms_s::ophase, sms_s::ophasep, sms_s::oseizure, sms_s::osync, sms_s::protocol, ast_frame::ptr, ast_frame::samples, ast_frame::src, ast_frame::subclass, and wave_out.

◆ sms_handleincoming()

static unsigned char sms_handleincoming ( sms_t h)
static

handle the incoming message

Definition at line 1163 of file app_sms.c.

1164{
1165 unsigned char p = 3;
1166 if (h->smsc) { /* SMSC */
1167 if ((h->imsg[2] & 3) == 1) { /* SMS-SUBMIT */
1168 h->udhl = h->udl = 0;
1169 h->vp = 0;
1170 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
1171 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1172 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1173 ast_copy_string(h->oa, h->cli, sizeof(h->oa));
1174 h->scts = ast_tvnow();
1175 h->mr = h->imsg[p++];
1176 p += unpackaddress(h->da, ARRAY_LEN(h->da), h->imsg + p);
1177 h->pid = h->imsg[p++];
1178 h->dcs = h->imsg[p++];
1179 if ((h->imsg[2] & 0x18) == 0x10) { /* relative VP */
1180 if (h->imsg[p] < 144) {
1181 h->vp = (h->imsg[p] + 1) * 5;
1182 } else if (h->imsg[p] < 168) {
1183 h->vp = 720 + (h->imsg[p] - 143) * 30;
1184 } else if (h->imsg[p] < 197) {
1185 h->vp = (h->imsg[p] - 166) * 1440;
1186 } else {
1187 h->vp = (h->imsg[p] - 192) * 10080;
1188 }
1189 p++;
1190 } else if (h->imsg[2] & 0x18) {
1191 p += 7; /* ignore enhanced / absolute VP */
1192 }
1193 p += unpacksms(h->dcs, h->imsg + p, h->udh, ARRAY_LEN(h->udh), &h->udhl, h->ud, ARRAY_LEN(h->ud), &h->udl, h->udhi);
1194 h->rx = 1; /* received message */
1195 sms_writefile(h); /* write the file */
1196 if (p != h->imsg[1] + 2) {
1197 ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1198 return 0xFF; /* duh! */
1199 }
1200 } else {
1201 ast_log(LOG_WARNING, "Unknown message type %02hhX\n", h->imsg[2]);
1202 return 0xFF;
1203 }
1204 } else { /* client */
1205 if (!(h->imsg[2] & 3)) { /* SMS-DELIVER */
1206 *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
1207 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
1208 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1209 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1210 h->mr = -1;
1211 p += unpackaddress(h->oa, ARRAY_LEN(h->oa), h->imsg + p);
1212 h->pid = h->imsg[p++];
1213 h->dcs = h->imsg[p++];
1214 h->scts = unpackdate(h->imsg + p);
1215 p += 7;
1216 p += unpacksms(h->dcs, h->imsg + p, h->udh, ARRAY_LEN(h->udh), &h->udhl, h->ud, ARRAY_LEN(h->ud), &h->udl, h->udhi);
1217 h->rx = 1; /* received message */
1218 sms_writefile(h); /* write the file */
1219 if (p != h->imsg[1] + 2) {
1220 ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1221 return 0xFF; /* duh! */
1222 }
1223 } else {
1224 ast_log(LOG_WARNING, "Unknown message type %02hhX\n", h->imsg[2]);
1225 return 0xFF;
1226 }
1227 }
1228 return 0; /* no error */
1229}
static int unpacksms(unsigned char dcs, unsigned char *i, unsigned char *udh, size_t udh_size, int *udhl, unsigned short *ud, size_t ud_size, int *udl, char udhi)
general unpack - starts with length byte (octet or septet) and returns number of bytes used,...
Definition app_sms.c:750
static struct timeval unpackdate(unsigned char *i)
unpack a date and return
Definition app_sms.c:585
static unsigned char unpackaddress(char *o, size_t o_size, unsigned char *i)
unpack an address from i, return byte length, unpack to o
Definition app_sms.c:767
unsigned char udhi
Definition app_sms.c:241
unsigned char rp
Definition app_sms.c:242
#define ARRAY_LEN(a)
Definition utils.h:706

References ARRAY_LEN, 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().

◆ sms_handleincoming_proto2()

static int sms_handleincoming_proto2 ( sms_t h)
static

sms_handleincoming_proto2: handle the incoming message

Definition at line 1313 of file app_sms.c.

1314{
1315 int f, i, sz = 0;
1316 int msg, msgsz;
1317 struct ast_tm tm;
1318 struct timeval now = { 0, 0 };
1319 char debug_buf[MAX_DEBUG_LEN * 3 + 1];
1320
1321 sz = h->imsg[1] + 2;
1322 /* ast_verb(3, "SMS-P2 Frame: %s\n", sms_hexdump(h->imsg, sz, debug_buf)); */
1323
1324 /* Parse message body (called payload) */
1325 now = h->scts = ast_tvnow();
1326 for (f = 4; f < sz; ) {
1327 msg = h->imsg[f++];
1328 msgsz = h->imsg[f++];
1329 msgsz += (h->imsg[f++] * 256);
1330 switch (msg) {
1331 case 0x13: /* Body */
1332 ast_verb(3, "SMS-P2 Body#%02X=[%.*s]\n", (unsigned)msg, msgsz, &h->imsg[f]);
1333 if (msgsz >= sizeof(h->ud)) {
1334 msgsz = sizeof(h->ud) - 1;
1335 }
1336 for (i = 0; i < msgsz; i++) {
1337 h->ud[i] = h->imsg[f + i];
1338 }
1339 h->udl = msgsz;
1340 break;
1341 case 0x14: /* Date SCTS */
1342 now = h->scts = ast_tvnow();
1343 ast_localtime(&now, &tm, NULL);
1344 tm.tm_mon = ( (h->imsg[f] * 10) + h->imsg[f + 1] ) - 1;
1345 tm.tm_mday = ( (h->imsg[f + 2] * 10) + h->imsg[f + 3] );
1346 tm.tm_hour = ( (h->imsg[f + 4] * 10) + h->imsg[f + 5] );
1347 tm.tm_min = ( (h->imsg[f + 6] * 10) + h->imsg[f + 7] );
1348 tm.tm_sec = 0;
1349 h->scts = ast_mktime(&tm, NULL);
1350 ast_verb(3, "SMS-P2 Date#%02X=%02d/%02d %02d:%02d\n", (unsigned)msg, tm.tm_mday, tm.tm_mon + 1, tm.tm_hour, tm.tm_min);
1351 break;
1352 case 0x15: /* Calling line (from SMSC) */
1353 if (msgsz >= 20) {
1354 msgsz = 20 - 1;
1355 }
1356 ast_verb(3, "SMS-P2 Origin#%02X=[%.*s]\n", (unsigned)msg, msgsz, &h->imsg[f]);
1357 ast_copy_string(h->oa, (char *)(&h->imsg[f]), msgsz + 1);
1358 break;
1359 case 0x18: /* Destination(from TE/phone) */
1360 if (msgsz >= 20) {
1361 msgsz = 20 - 1;
1362 }
1363 ast_verb(3, "SMS-P2 Destination#%02X=[%.*s]\n", (unsigned)msg, msgsz, &h->imsg[f]);
1364 ast_copy_string(h->da, (char *)(&h->imsg[f]), msgsz + 1);
1365 break;
1366 case 0x1C: /* Notify */
1367 ast_verb(3, "SMS-P2 Notify#%02X=%s\n", (unsigned)msg, sms_hexdump(&h->imsg[f], 3, debug_buf));
1368 break;
1369 default:
1370 ast_verb(3, "SMS-P2 Par#%02X [%d]: %s\n", (unsigned)msg, msgsz, sms_hexdump(&h->imsg[f], msgsz, debug_buf));
1371 break;
1372 }
1373 f+=msgsz; /* Skip to next */
1374 }
1375 h->rx = 1; /* received message */
1376 sms_writefile(h); /* write the file */
1377 return 0; /* no error */
1378}
static char * sms_hexdump(unsigned char buf[], int size, char *s)
Definition app_sms.c:1300
#define MAX_DEBUG_LEN
Definition app_sms.c:1299
struct timeval ast_mktime(struct ast_tm *const tmp, const char *zone)
Timezone-independent version of mktime(3).
Definition localtime.c:2357

References ast_copy_string(), ast_localtime(), ast_mktime(), ast_tvnow(), ast_verb, sms_s::da, sms_s::imsg, MAX_DEBUG_LEN, NULL, 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().

◆ sms_hexdump()

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

Definition at line 1300 of file app_sms.c.

1301{
1302 char *p;
1303 int f;
1304
1305 for (p = s, f = 0; f < size && f < MAX_DEBUG_LEN; f++, p += 3) {
1306 sprintf(p, "%02hhX ", (unsigned char)buf[f]);
1307 }
1308 return(s);
1309}

References buf, and MAX_DEBUG_LEN.

Referenced by sms_handleincoming_proto2().

◆ sms_log()

static void sms_log ( sms_t h,
char  status 
)
static

Log the output, and remove file.

Definition at line 824 of file app_sms.c.

825{
826 int o;
827
828 if (*h->oa == '\0' && *h->da == '\0') {
829 return;
830 }
831 o = open(log_file, O_CREAT | O_APPEND | O_WRONLY, AST_FILE_MODE);
832 if (o >= 0) {
833 char line[1000], mrs[3] = "", *p;
834 char buf[30];
835 unsigned char n;
836
837 if (h->mr >= 0) {
838 snprintf(mrs, sizeof(mrs), "%02hhX", (unsigned char)h->mr);
839 }
840 snprintf(line, sizeof(line), "%s %c%c%c%s %s %s %s ",
841 isodate(time(NULL), buf, sizeof(buf)),
842 status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue,
843 S_OR(h->oa, "-"), S_OR(h->da, "-") );
844 p = line + strlen(line);
845
846 if (h->nolog) {
847 p += snprintf(p, 1000 - strlen(line), "udl=%d", h->udl);
848 } else {
849 for (n = 0; n < h->udl; n++) {
850 if (h->ud[n] == '\\') {
851 *p++ = '\\';
852 *p++ = '\\';
853 } else if (h->ud[n] == '\n') {
854 *p++ = '\\';
855 *p++ = 'n';
856 } else if (h->ud[n] == '\r') {
857 *p++ = '\\';
858 *p++ = 'r';
859 } else if (h->ud[n] < 32 || h->ud[n] == 127) {
860 *p++ = 0xbf;
861 } else {
862 *p++ = h->ud[n];
863 }
864 }
865 }
866 *p++ = '\n';
867 *p = 0;
868 if (write(o, line, strlen(line)) < 0) {
869 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
870 }
871 close(o);
872 }
873 *h->oa = *h->da = h->udl = 0;
874}
jack_status_t status
Definition app_jack.c:149
static char * isodate(time_t t, char *buf, int len)
static, return a date/time in ISO format
Definition app_sms.c:309
#define AST_FILE_MODE
Definition asterisk.h:32

References AST_FILE_MODE, ast_log, buf, sms_s::da, errno, isodate(), log_file, LOG_WARNING, sms_s::mr, sms_s::nolog, NULL, sms_s::oa, sms_s::queue, sms_s::rx, S_OR, sms_s::smsc, status, sms_s::ud, and sms_s::udl.

Referenced by sms_messagerx(), and sms_messagerx2().

◆ sms_messagerx()

static void sms_messagerx ( sms_t h)
static

Definition at line 1555 of file app_sms.c.

1556{
1557 int cause;
1558
1559 sms_debug (DIR_RX, h);
1560 if (h->protocol == 2) {
1561 sms_messagerx2(h);
1562 return;
1563 }
1564 /* parse incoming message for Protocol 1 */
1565 switch (h->imsg[0]) {
1566 case 0x91: /* SMS_DATA */
1567 cause = sms_handleincoming (h);
1568 if (!cause) {
1569 sms_log(h, 'Y');
1570 h->omsg[0] = 0x95; /* SMS_ACK */
1571 h->omsg[1] = 0x02;
1572 h->omsg[2] = 0x00; /* deliver report */
1573 h->omsg[3] = 0x00; /* no parameters */
1574 } else { /* NACK */
1575 sms_log(h, 'N');
1576 h->omsg[0] = 0x96; /* SMS_NACK */
1577 h->omsg[1] = 3;
1578 h->omsg[2] = 0; /* delivery report */
1579 h->omsg[3] = cause; /* cause */
1580 h->omsg[4] = 0; /* no parameters */
1581 }
1582 sms_messagetx(h);
1583 break;
1584
1585 case 0x92: /* SMS_ERROR */
1586 h->err = 1;
1587 sms_messagetx(h); /* send whatever we sent again */
1588 break;
1589 case 0x93: /* SMS_EST */
1590 sms_nextoutgoing (h);
1591 break;
1592 case 0x94: /* SMS_REL */
1593 h->hangup = 1; /* hangup */
1594 break;
1595 case 0x95: /* SMS_ACK */
1596 sms_log(h, 'Y');
1597 sms_nextoutgoing (h);
1598 break;
1599 case 0x96: /* SMS_NACK */
1600 h->err = 1;
1601 sms_log(h, 'N');
1602 sms_nextoutgoing (h);
1603 break;
1604 default: /* Unknown */
1605 h->omsg[0] = 0x92; /* SMS_ERROR */
1606 h->omsg[1] = 1;
1607 h->omsg[2] = 3; /* unknown message type */
1608 sms_messagetx(h);
1609 break;
1610 }
1611}
static unsigned char sms_handleincoming(sms_t *h)
handle the incoming message
Definition app_sms.c:1163
static void sms_messagerx2(sms_t *h)
Definition app_sms.c:1394
static void sms_nextoutgoing(sms_t *h)
find and fill in next message, or send a REL if none waiting
Definition app_sms.c:1493
static void sms_debug(int dir, sms_t *h)
Definition app_sms.c:1537

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().

Referenced by sms_process().

◆ sms_messagerx2()

static void sms_messagerx2 ( sms_t h)
static

Definition at line 1394 of file app_sms.c.

1395{
1396 int p = h->imsg[0] & DLL_SMS_MASK ; /* mask the high bit */
1397 int cause;
1398
1399#define DLL2_ACK(h) ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1)
1400 switch (p) {
1401 case DLL2_SMS_EST: /* Protocol 2: Connection ready (fake): send message */
1402 sms_nextoutgoing (h);
1403 /* 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 "); */
1404 break;
1405
1406 case DLL2_SMS_INFO_MO: /* transport SMS_SUBMIT */
1407 case DLL2_SMS_INFO_MT: /* transport SMS_DELIVERY */
1408 cause = sms_handleincoming_proto2(h);
1409 if (!cause) { /* ACK */
1410 sms_log(h, 'Y');
1411 }
1412 h->omsg[0] = DLL2_ACK(h);
1413 h->omsg[1] = 0x06; /* msg len */
1414 h->omsg[2] = 0x04; /* payload len */
1415 h->omsg[3] = 0x00; /* payload len */
1416 h->omsg[4] = 0x1f; /* Response type */
1417 h->omsg[5] = 0x01; /* parameter len */
1418 h->omsg[6] = 0x00; /* parameter len */
1419 h->omsg[7] = cause; /* CONFIRM or error */
1420 sms_messagetx(h);
1421 break;
1422
1423 case DLL2_SMS_NACK: /* Protocol 2: SMS_NAK */
1424 h->omsg[0] = DLL2_SMS_REL; /* SMS_REL */
1425 h->omsg[1] = 0x00; /* msg len */
1426 sms_messagetx(h);
1427 break;
1428
1429 case DLL2_SMS_ACK0:
1430 case DLL2_SMS_ACK1:
1431 /* SMS_ACK also transport SMS_SUBMIT or SMS_DELIVERY */
1432 if ( (h->omsg[0] & DLL_SMS_MASK) == DLL2_SMS_REL) {
1433 /* a response to our Release, just hangup */
1434 h->hangup = 1; /* hangup */
1435 } else {
1436 /* XXX depending on what we are.. */
1437 ast_log(LOG_NOTICE, "SMS_SUBMIT or SMS_DELIVERY\n");
1438 sms_nextoutgoing (h);
1439 }
1440 break;
1441
1442 case DLL2_SMS_REL: /* Protocol 2: SMS_REL (hangup req) */
1443 h->omsg[0] = DLL2_ACK(h);
1444 h->omsg[1] = 0;
1445 sms_messagetx(h);
1446 break;
1447 }
1448}
#define DLL2_ACK(h)
static int sms_handleincoming_proto2(sms_t *h)
sms_handleincoming_proto2: handle the incoming message
Definition app_sms.c:1313

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::hangup, sms_s::imsg, LOG_NOTICE, sms_s::omsg, sms_handleincoming_proto2(), sms_log(), sms_messagetx(), and sms_nextoutgoing().

Referenced by sms_messagerx().

◆ sms_messagetx()

static void sms_messagetx ( sms_t h)
static

Definition at line 1613 of file app_sms.c.

1614{
1615 unsigned char c = 0, p;
1616 int len = h->omsg[1] + 2; /* total message length excluding checksum */
1617
1618 for (p = 0; p < len; p++) { /* compute checksum */
1619 c += h->omsg[p];
1620 }
1621 h->omsg[len] = 0 - c; /* actually, (256 - (c & 0fxx)) & 0xff) */
1622 sms_debug(DIR_TX, h);
1623 h->framenumber++; /* Proto 2 */
1624 h->obytep = 0;
1625 h->obitp = 0;
1626 if (h->protocol == 2) { /* Proto 2: */
1627 h->oseizure = 300; /* 300bits (or more ?) */
1628 h->obyte = 0; /* Seizure starts with space (0) */
1629 if (h->omsg[0] == 0x7F) {
1630 h->opause = 8 * h->opause_0; /* initial message delay */
1631 } else {
1632 h->opause = 400;
1633 }
1634 } else { /* Proto 1: */
1635 h->oseizure = 0; /* No seizure */
1636 h->obyte = 1; /* send mark ('1') at the beginning */
1637 /* Change the initial message delay. BT requires 300ms,
1638 * but for others this might be way too much and the phone
1639 * could time out. XXX make it configurable.
1640 */
1641 if (h->omsg[0] == 0x93) {
1642 h->opause = 8 * h->opause_0; /* initial message delay */
1643 } else {
1644 h->opause = 200;
1645 }
1646 }
1647 /* Note - setting osync triggers the generator */
1648 h->osync = OSYNC_BITS; /* 80 sync bits */
1649 h->obyten = len + 1; /* bytes to send (including checksum) */
1650}
#define OSYNC_BITS
Definition app_sms.c:158
#define DIR_TX
Definition app_sms.c:1536
static struct test_val c

References c, 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(), sms_nextoutgoing(), and sms_process().

◆ sms_nextoutgoing()

static void sms_nextoutgoing ( sms_t h)
static

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

Definition at line 1493 of file app_sms.c.

1494{
1495 char fn[100 + NAME_MAX] = "";
1496 DIR *d;
1497 char more = 0;
1498
1499 *h->da = *h->oa = '\0'; /* clear destinations */
1500 h->rx = 0; /* outgoing message */
1501 snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? "mttx" : "motx");
1502 ast_mkdir(fn, 0777); /* ensure it exists */
1503 d = opendir(fn);
1504 if (d) {
1505 struct dirent *f = readdirqueue(d, h->queue);
1506 if (f) {
1507 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", f->d_name);
1508 sms_readfile(h, fn);
1509 if (readdirqueue(d, h->queue)) {
1510 more = 1; /* more to send */
1511 }
1512 }
1513 closedir(d);
1514 }
1515 if (*h->da || *h->oa) { /* message to send */
1516 if (h->protocol == 2) {
1517 sms_compose2(h, more);
1518 } else {
1519 sms_compose1(h, more);
1520 }
1521 } else { /* no message */
1522 if (h->protocol == 2) {
1523 h->omsg[0] = 0x17; /* SMS_REL */
1524 h->omsg[1] = 0;
1525 h->sent_rel = 1;
1526 } else {
1527 h->omsg[0] = 0x94; /* SMS_REL */
1528 h->omsg[1] = 0;
1529 h->sent_rel = 1;
1530 }
1531 }
1532 sms_messagetx(h);
1533}
static void sms_compose1(sms_t *h, int more)
compose a message for protocol 1
Definition app_sms.c:1451
static void sms_readfile(sms_t *h, char *fn)
parse and delete a file
Definition app_sms.c:877
static void sms_compose2(sms_t *h, int more)
Definition app_sms.c:1264
static struct dirent * readdirqueue(DIR *d, char *queue)
read dir skipping dot files...
Definition app_sms.c:1153
const char * ast_config_AST_SPOOL_DIR
Definition options.c:155
unsigned char sent_rel
Definition app_sms.c:227
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition utils.c:2513

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

Referenced by sms_messagerx(), and sms_messagerx2().

◆ sms_process()

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

1765{
1766 int bit;
1767
1768 /*
1769 * Ignore incoming audio while a packet is being transmitted,
1770 * the protocol is half-duplex.
1771 * Unfortunately this means that if the outbound and incoming
1772 * transmission overlap (which is an error condition anyways),
1773 * we may miss some data and this makes debugging harder.
1774 */
1775 if (h->obyten || h->osync) {
1776 return;
1777 }
1778 for ( ; samples-- ; data++) {
1779 unsigned long long m0, m1;
1780 if (abs(*data) > h->imag) {
1781 h->imag = abs(*data);
1782 } else {
1783 h->imag = h->imag * 7 / 8;
1784 }
1785 if (h->imag <= 500) { /* below [arbitrary] threahold: lost carrier */
1786 if (h->idle++ == 80000) { /* nothing happening */
1787 ast_log(LOG_NOTICE, "No data, hanging up\n");
1788 h->hangup = 1;
1789 h->err = 1;
1790 }
1791 if (h->ierr) { /* error */
1792 ast_log(LOG_NOTICE, "Error %d, hanging up\n", h->ierr);
1793 /* Protocol 1 */
1794 h->err = 1;
1795 h->omsg[0] = 0x92; /* error */
1796 h->omsg[1] = 1;
1797 h->omsg[2] = h->ierr;
1798 sms_messagetx(h); /* send error */
1799 }
1800 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1801 continue;
1802 }
1803 h->idle = 0;
1804
1805 /* multiply signal by the two carriers. */
1806 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
1807 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
1808 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
1809 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
1810 /* compute the amplitudes */
1811 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
1812 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
1813
1814 /* advance the sin/cos pointers */
1815 if ((h->ips0 += 21) >= 80) {
1816 h->ips0 -= 80;
1817 }
1818 if ((h->ipc0 += 21) >= 80) {
1819 h->ipc0 -= 80;
1820 }
1821 if ((h->ips1 += 13) >= 80) {
1822 h->ips1 -= 80;
1823 }
1824 if ((h->ipc1 += 13) >= 80) {
1825 h->ipc1 -= 80;
1826 }
1827
1828 /* set new bit to 1 or 0 depending on which value is stronger */
1829 h->ibith <<= 1;
1830 if (m1 > m0) {
1831 h->ibith |= 1;
1832 }
1833 if (h->ibith & 8) {
1834 h->ibitt--;
1835 }
1836 if (h->ibith & 1) {
1837 h->ibitt++;
1838 }
1839 bit = ((h->ibitt > 1) ? 1 : 0);
1840 if (bit != h->ibitl) {
1841 h->ibitc = 1;
1842 } else {
1843 h->ibitc++;
1844 }
1845 h->ibitl = bit;
1846 if (!h->ibitn && h->ibitc == 4 && !bit) {
1847 h->ibitn = 1;
1848 h->iphasep = 0;
1849 }
1850 if (bit && h->ibitc == 200) { /* sync, restart message */
1851 /* Protocol 2: empty connection ready (I am master) */
1852 if (h->framenumber <= 0 && h->ibytec >= 160 && !memcmp(h->imsg, "UUUUUUUUUUUUUUUUUUUU", 20)) {
1853 h->framenumber = 1;
1854 ast_verb(3, "SMS protocol 2 detected\n");
1855 h->protocol = 2;
1856 h->imsg[0] = 0xff; /* special message (fake) */
1857 h->imsg[1] = h->imsg[2] = 0x00;
1858 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1859 sms_messagerx(h);
1860 }
1861 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1862 }
1863 if (h->ibitn) {
1864 h->iphasep += 12;
1865 if (h->iphasep >= 80) { /* next bit */
1866 h->iphasep -= 80;
1867 if (h->ibitn++ == 9) { /* end of byte */
1868 if (!bit) { /* bad stop bit */
1869 if (h->sent_rel) {
1870 h->hangup = 1;
1871 } else {
1872 ast_log(LOG_NOTICE, "Bad stop bit\n");
1873 h->ierr = 0xFF; /* unknown error */
1874 }
1875 } else {
1876 if (h->ibytep < sizeof(h->imsg)) {
1877 h->imsg[h->ibytep] = h->ibytev;
1878 h->ibytec += h->ibytev;
1879 h->ibytep++;
1880 } else if (h->ibytep == sizeof(h->imsg)) {
1881 ast_log(LOG_NOTICE, "msg too large\n");
1882 h->ierr = 2; /* bad message length */
1883 }
1884 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
1885 if (!h->ibytec) {
1886 sms_messagerx(h);
1887 } else {
1888 ast_log(LOG_NOTICE, "bad checksum\n");
1889 h->ierr = 1; /* bad checksum */
1890 }
1891 }
1892 }
1893 h->ibitn = 0;
1894 }
1895 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1896 }
1897 }
1898 }
1899}
static void sms_messagerx(sms_t *h)
Definition app_sms.c:1555
#define abs(x)
Definition f2c.h:195
unsigned char ibitt
Definition app_sms.c:276
signed long long imc0
Definition app_sms.c:258
unsigned char ibith
Definition app_sms.c:275
signed long long imc1
Definition app_sms.c:260
unsigned char ips0
Definition app_sms.c:263
unsigned char ibitn
Definition app_sms.c:270
unsigned char ibitc
Definition app_sms.c:268
signed long long ims1
Definition app_sms.c:259
unsigned char ibytev
Definition app_sms.c:271
unsigned char iphasep
Definition app_sms.c:269
unsigned char ibytec
Definition app_sms.c:273
unsigned char ibitl
Definition app_sms.c:267
unsigned char ierr
Definition app_sms.c:274
unsigned char ips1
Definition app_sms.c:264
unsigned int idle
Definition app_sms.c:261
signed long long ims0
Definition app_sms.c:257
unsigned short imag
Definition app_sms.c:262

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

◆ sms_readfile()

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

parse and delete a file

Definition at line 877 of file app_sms.c.

878{
879 char line[1000];
880 FILE *s;
881 char dcsset = 0; /* if DSC set */
882 ast_log(LOG_NOTICE, "Sending %s\n", fn);
883 h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
884 h->mr = -1;
885 h->dcs = 0xF1; /* normal messages class 1 */
886 h->scts = ast_tvnow();
887 s = fopen(fn, "r");
888 if (s) {
889 if (unlink(fn)) { /* concurrent access, we lost */
890 fclose(s);
891 return;
892 }
893 while (fgets (line, sizeof(line), s)) { /* process line in file */
894 char *p;
895 void *pp = &p;
896 for (p = line; *p && *p != '\n' && *p != '\r'; p++);
897 *p = 0; /* strip eoln */
898 p = line;
899 if (!*p || *p == ';') {
900 continue; /* blank line or comment, ignore */
901 }
902 while (isalnum(*p)) {
903 *p = tolower (*p);
904 p++;
905 }
906 while (isspace (*p)) {
907 *p++ = 0;
908 }
909 if (*p == '=') {
910 *p++ = 0;
911 if (!strcmp(line, "ud")) { /* parse message (UTF-8) */
912 unsigned char o = 0;
913 memcpy(h->udtxt, p, SMSLEN); /* for protocol 2 */
914 while (*p && o < SMSLEN) {
915 h->ud[o++] = utf8decode(pp);
916 p++;
917 }
918 h->udl = o;
919 if (*p) {
920 ast_log(LOG_WARNING, "UD too long in %s\n", fn);
921 }
922 } else {
923 while (isspace (*p)) {
924 p++;
925 }
926 if (!strcmp(line, "oa") && strlen(p) < sizeof(h->oa)) {
927 numcpy (h->oa, p);
928 } else if (!strcmp(line, "da") && strlen(p) < sizeof(h->oa)) {
929 numcpy (h->da, p);
930 } else if (!strcmp(line, "pid")) {
931 h->pid = atoi(p);
932 } else if (!strcmp(line, "dcs")) {
933 h->dcs = atoi(p);
934 dcsset = 1;
935 } else if (!strcmp(line, "mr")) {
936 h->mr = atoi(p);
937 } else if (!strcmp(line, "srr")) {
938 h->srr = (atoi(p) ? 1 : 0);
939 } else if (!strcmp(line, "vp")) {
940 h->vp = atoi(p);
941 } else if (!strcmp(line, "rp")) {
942 h->rp = (atoi(p) ? 1 : 0);
943 } else if (!strcmp(line, "scts")) { /* get date/time */
944 int Y, m, d, H, M, S;
945 /* XXX Why aren't we using ast_strptime here? */
946 if (sscanf(p, "%4d-%2d-%2dT%2d:%2d:%2d", &Y, &m, &d, &H, &M, &S) == 6) {
947 struct ast_tm t = { 0, };
948 t.tm_year = Y - 1900;
949 t.tm_mon = m - 1;
950 t.tm_mday = d;
951 t.tm_hour = H;
952 t.tm_min = M;
953 t.tm_sec = S;
954 t.tm_isdst = -1;
955 h->scts = ast_mktime(&t, NULL);
956 if (h->scts.tv_sec == 0) {
957 ast_log(LOG_WARNING, "Bad date/timein %s: %s", fn, p);
958 }
959 }
960 } else {
961 ast_log(LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
962 }
963 }
964 } else if (*p == '#') { /* raw hex format */
965 *p++ = 0;
966 if (*p == '#') {
967 p++;
968 if (!strcmp(line, "ud")) { /* user data */
969 int o = 0;
970 while (*p && o < SMSLEN) {
971 if (isxdigit(*p) && isxdigit(p[1]) && isxdigit(p[2]) && isxdigit(p[3])) {
972 h->ud[o++] =
973 (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 12) +
974 (((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
975 (((isalpha(p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha(p[3]) ? 9 : 0) + (p[3] & 0xF));
976 p += 4;
977 } else
978 break;
979 }
980 h->udl = o;
981 if (*p)
982 ast_log(LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
983 } else
984 ast_log(LOG_WARNING, "Only ud can use ## format, %s\n", fn);
985 } else if (!strcmp(line, "ud")) { /* user data */
986 int o = 0;
987 while (*p && o < SMSLEN) {
988 if (isxdigit(*p) && isxdigit(p[1])) {
989 h->ud[o++] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
990 p += 2;
991 } else {
992 break;
993 }
994 }
995 h->udl = o;
996 if (*p) {
997 ast_log(LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
998 }
999 } else if (!strcmp(line, "udh")) { /* user data header */
1000 unsigned char o = 0;
1001 h->udhi = 1;
1002 while (*p && o < SMSLEN) {
1003 if (isxdigit(*p) && isxdigit(p[1])) {
1004 h->udh[o] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
1005 o++;
1006 p += 2;
1007 } else {
1008 break;
1009 }
1010 }
1011 h->udhl = o;
1012 if (*p) {
1013 ast_log(LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
1014 }
1015 } else {
1016 ast_log(LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
1017 }
1018 } else {
1019 ast_log(LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
1020 }
1021 }
1022 fclose(s);
1023 if (!dcsset && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
1024 if (packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
1025 if (packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
1026 ast_log(LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
1027 } else {
1028 h->dcs = 0x08; /* default to 16 bit */
1029 ast_log(LOG_WARNING, "Sending in 16 bit format(%s)\n", fn);
1030 }
1031 } else {
1032 h->dcs = 0xF5; /* default to 8 bit */
1033 ast_log(LOG_WARNING, "Sending in 8 bit format(%s)\n", fn);
1034 }
1035 }
1036 if (is7bit(h->dcs) && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
1037 ast_log(LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
1038 }
1039 if (is8bit(h->dcs) && packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
1040 ast_log(LOG_WARNING, "Invalid 8 bit data %s\n", fn);
1041 }
1042 if (is16bit(h->dcs) && packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
1043 ast_log(LOG_WARNING, "Invalid 16 bit data %s\n", fn);
1044 }
1045 }
1046}
#define S(e)
static void numcpy(char *d, char *s)
copy number, skipping non digits apart from leading +
Definition app_sms.c:294
int tm_mday
Definition localtime.h:39
int tm_sec
Definition localtime.h:36
int tm_hour
Definition localtime.h:38
int tm_isdst
Definition localtime.h:44
int tm_min
Definition localtime.h:37
int tm_year
Definition localtime.h:41
int tm_mon
Definition localtime.h:40

References ast_log, ast_mktime(), ast_tvnow(), d, sms_s::da, sms_s::dcs, is16bit, is7bit, is8bit, LOG_NOTICE, LOG_WARNING, sms_s::mr, NULL, numcpy(), sms_s::oa, packsms16(), packsms7(), packsms8(), sms_s::pid, sms_s::rp, sms_s::rx, 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().

◆ sms_release()

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

Definition at line 1741 of file app_sms.c.

1742{
1743 return; /* nothing to do here. */
1744}

◆ sms_writefile()

static void sms_writefile ( sms_t h)
static

white a received text message to a file

Definition at line 1049 of file app_sms.c.

1050{
1051 char fn[200] = "", fn2[200] = "";
1052 char buf[30];
1053 FILE *o;
1054
1055 if (ast_tvzero(h->scts)) {
1056 h->scts = ast_tvnow();
1057 }
1058 snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
1059 ast_mkdir(fn, 0777); /* ensure it exists */
1060 ast_copy_string(fn2, fn, sizeof(fn2));
1061 snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%s.%s-%u", h->queue, isodate(h->scts.tv_sec, buf, sizeof(buf)), seq++);
1062 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1);
1063 if ((o = fopen(fn, "w")) == NULL) {
1064 return;
1065 }
1066
1067 if (*h->oa) {
1068 fprintf(o, "oa=%s\n", h->oa);
1069 }
1070 if (*h->da) {
1071 fprintf(o, "da=%s\n", h->da);
1072 }
1073 if (h->udhi) {
1074 unsigned int p;
1075 fprintf(o, "udh#");
1076 for (p = 0; p < h->udhl; p++) {
1077 fprintf(o, "%02hhX", (unsigned char)h->udh[p]);
1078 }
1079 fprintf(o, "\n");
1080 }
1081 if (h->udl) {
1082 unsigned int p;
1083 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
1084 if (p < h->udl) {
1085 fputc(';', o); /* cannot use ud=, but include as a comment for human readable */
1086 }
1087 fprintf(o, "ud=");
1088 for (p = 0; p < h->udl; p++) {
1089 unsigned short v = h->ud[p];
1090 if (v < 32) {
1091 fputc(191, o);
1092 } else if (v < 0x80) {
1093 fputc(v, o);
1094 } else if (v < 0x800) {
1095 fputc(0xC0 + (v >> 6), o);
1096 fputc(0x80 + (v & 0x3F), o);
1097 } else {
1098 fputc(0xE0 + (v >> 12), o);
1099 fputc(0x80 + ((v >> 6) & 0x3F), o);
1100 fputc(0x80 + (v & 0x3F), o);
1101 }
1102 }
1103 fprintf(o, "\n");
1104 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
1105 if (p < h->udl) {
1106 for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
1107 if (p == h->udl) { /* can write in ucs-1 hex */
1108 fprintf(o, "ud#");
1109 for (p = 0; p < h->udl; p++) {
1110 fprintf(o, "%02hhX", (unsigned char)h->ud[p]);
1111 }
1112 fprintf(o, "\n");
1113 } else { /* write in UCS-2 */
1114 fprintf(o, "ud##");
1115 for (p = 0; p < h->udl; p++) {
1116 fprintf(o, "%04X", (unsigned)h->ud[p]);
1117 }
1118 fprintf(o, "\n");
1119 }
1120 }
1121 }
1122 if (h->scts.tv_sec) {
1123 char datebuf[30];
1124 fprintf(o, "scts=%s\n", isodate(h->scts.tv_sec, datebuf, sizeof(datebuf)));
1125 }
1126 if (h->pid) {
1127 fprintf(o, "pid=%d\n", h->pid);
1128 }
1129 if (h->dcs != 0xF1) {
1130 fprintf(o, "dcs=%d\n", h->dcs);
1131 }
1132 if (h->vp) {
1133 fprintf(o, "vp=%u\n", h->vp);
1134 }
1135 if (h->srr) {
1136 fprintf(o, "srr=1\n");
1137 }
1138 if (h->mr >= 0) {
1139 fprintf(o, "mr=%d\n", h->mr);
1140 }
1141 if (h->rp) {
1142 fprintf(o, "rp=1\n");
1143 }
1144 fclose(o);
1145 if (rename(fn, fn2)) {
1146 unlink(fn);
1147 } else {
1148 ast_log(LOG_NOTICE, "Received to %s\n", fn2);
1149 }
1150}
static volatile unsigned int seq
Definition app_sms.c:126
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition time.h:117

References ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_log, ast_mkdir(), ast_tvnow(), ast_tvzero(), buf, sms_s::da, sms_s::dcs, isodate(), LOG_NOTICE, sms_s::mr, NULL, sms_s::oa, sms_s::pid, sms_s::queue, sms_s::rp, sms_s::rx, sms_s::scts, seq, 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_handleincoming(), and sms_handleincoming_proto2().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 2130 of file app_sms.c.

2131{
2133}
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:404

References app, and ast_unregister_application().

◆ unpackaddress()

static unsigned char unpackaddress ( char *  o,
size_t  o_size,
unsigned char *  i 
)
static

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

Definition at line 767 of file app_sms.c.

768{
769 unsigned char l = i[0], p;
770 char *o_end;
771
772 if (!o_size) {
773 return (l + 5) / 2;
774 }
775
776 o_end = o + o_size - 1;
777 if (i[1] == 0x91) {
778 if (o < o_end) {
779 *o++ = '+';
780 }
781 }
782 for (p = 0; p < l; p++) {
783 if (o < o_end) {
784 if (p & 1) {
785 *o++ = (i[2 + p / 2] >> 4) + '0';
786 } else {
787 *o++ = (i[2 + p / 2] & 0xF) + '0';
788 }
789 }
790 }
791 *o = 0;
792 return (l + 5) / 2;
793}

Referenced by sms_handleincoming().

◆ unpackdate()

static struct timeval unpackdate ( unsigned char *  i)
static

unpack a date and return

Definition at line 585 of file app_sms.c.

586{
587 struct ast_tm t;
588
589 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
590 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
591 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
592 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
593 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
594 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
595 t.tm_isdst = 0;
596 if (i[6] & 0x08) {
597 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
598 } else {
599 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
600 }
601
602 return ast_mktime(&t, NULL);
603}

References ast_mktime(), NULL, ast_tm::tm_hour, ast_tm::tm_isdst, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, and ast_tm::tm_year.

Referenced by sms_handleincoming().

◆ unpacksms()

static int unpacksms ( unsigned char  dcs,
unsigned char *  i,
unsigned char *  udh,
size_t  udh_size,
int *  udhl,
unsigned short *  ud,
size_t  ud_size,
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 750 of file app_sms.c.

752{
753 int l = *i++;
754 if (is7bit(dcs)) {
755 unpacksms7(i, l, udh, udh_size, udhl, ud, ud_size, udl, udhi);
756 l = (l * 7 + 7) / 8; /* adjust length to return */
757 } else if (is8bit(dcs)) {
758 unpacksms8(i, l, udh, udh_size, udhl, ud, ud_size, udl, udhi);
759 } else {
760 l += l % 2;
761 unpacksms16(i, l, udh, udh_size, udhl, ud, ud_size, udl, udhi);
762 }
763 return l + 1;
764}
static void unpacksms8(unsigned char *i, unsigned char l, unsigned char *udh, size_t udh_size, int *udhl, unsigned short *ud, size_t ud_size, int *udl, char udhi)
unpacks bytes (8 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl....
Definition app_sms.c:673
static void unpacksms7(unsigned char *i, unsigned char l, unsigned char *udh, size_t udh_size, int *udhl, unsigned short *ud, size_t ud_size, int *udl, char udhi)
unpacks bytes (7 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl....
Definition app_sms.c:608
static void unpacksms16(unsigned char *i, unsigned char l, unsigned char *udh, size_t udh_size, int *udhl, unsigned short *ud, size_t ud_size, int *udl, char udhi)
unpacks bytes (16 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl....
Definition app_sms.c:711

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

Referenced by sms_handleincoming().

◆ unpacksms16()

static void unpacksms16 ( unsigned char *  i,
unsigned char  l,
unsigned char *  udh,
size_t  udh_size,
int *  udhl,
unsigned short *  ud,
size_t  ud_size,
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 711 of file app_sms.c.

713{
714 unsigned short *o = ud;
715 unsigned short *o_end = ud + ud_size;
716 unsigned char *h = udh;
717 unsigned char *h_end = udh + udh_size;
718 size_t stored_udhl = 0;
719 *udhl = 0;
720 if (udhi) {
721 int n = *i;
722 if (n) {
723 i++;
724 l--;
725 while (l && n) {
726 l--;
727 n--;
728 if (h < h_end) {
729 *h++ = *i;
730 stored_udhl++;
731 }
732 i++;
733 }
734 }
735 }
736 while (l--) {
737 int v = *i++;
738 if (l && l--) {
739 v = (v << 8) + *i++;
740 }
741 if (o < o_end) {
742 *o++ = v;
743 }
744 }
745 *udl = o - ud;
746 *udhl = stored_udhl;
747}

Referenced by unpacksms().

◆ unpacksms7()

static void unpacksms7 ( unsigned char *  i,
unsigned char  l,
unsigned char *  udh,
size_t  udh_size,
int *  udhl,
unsigned short *  ud,
size_t  ud_size,
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 608 of file app_sms.c.

610{
611 unsigned char b = 0, p = 0;
612 unsigned short *o = ud;
613 unsigned short *o_end = ud + ud_size;
614 unsigned char *h = udh;
615 unsigned char *h_end = udh + udh_size;
616 size_t stored_udhl = 0;
617 *udhl = 0;
618 if (udhi && l) { /* header */
619 int hlen = i[p];
620 if (hlen) {
621 b = 1;
622 p++;
623 l--;
624 while (hlen-- && l) {
625 if (h < h_end) {
626 *h++ = i[p];
627 stored_udhl++;
628 }
629 p++;
630 b += 8;
631 while (b >= 7) {
632 b -= 7;
633 l--;
634 if (!l) {
635 break;
636 }
637 }
638 }
639 /* adjust for fill, septets */
640 if (b) {
641 b = 7 - b;
642 l--;
643 }
644 }
645 }
646 while (l--) {
647 unsigned char v;
648 if (b < 2) {
649 v = ((i[p] >> b) & 0x7F); /* everything in one byte */
650 } else {
651 v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
652 }
653 b += 7;
654 if (b >= 8) {
655 b -= 8;
656 p++;
657 }
658 /* 0x00A0 is the encoding of ESC (27) in defaultalphabet */
659 if (o > ud && o[-1] == 0x00A0 && escapes[v]) {
660 o[-1] = escapes[v];
661 } else if (o < o_end) {
662 *o++ = defaultalphabet[v];
663 }
664 }
665 *udl = o - ud;
666 *udhl = stored_udhl;
667}

References b, defaultalphabet, and escapes.

Referenced by unpacksms().

◆ unpacksms8()

static void unpacksms8 ( unsigned char *  i,
unsigned char  l,
unsigned char *  udh,
size_t  udh_size,
int *  udhl,
unsigned short *  ud,
size_t  ud_size,
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 673 of file app_sms.c.

675{
676 unsigned short *o = ud;
677 unsigned short *o_end = ud + ud_size;
678 unsigned char *h = udh;
679 unsigned char *h_end = udh + udh_size;
680 size_t stored_udhl = 0;
681 *udhl = 0;
682 if (udhi) {
683 int n = *i;
684 if (n) {
685 i++;
686 l--;
687 while (l && n) {
688 l--;
689 n--;
690 if (h < h_end) {
691 *h++ = *i;
692 stored_udhl++;
693 }
694 i++;
695 }
696 }
697 }
698 while (l--) {
699 if (o < o_end) {
700 *o++ = *i; /* not to UTF-8 as explicitly 8 bit coding in DCS */
701 }
702 i++;
703 }
704 *udl = o - ud;
705 *udhl = stored_udhl;
706}

Referenced by unpacksms().

◆ utf8decode()

static long utf8decode ( unsigned char **  pp)
static

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

Definition at line 321 of file app_sms.c.

322{
323 unsigned char *p = *pp;
324 if (!*p) {
325 return 0; /* null termination of string */
326 }
327 (*pp)++;
328 if (*p < 0xC0) {
329 return *p; /* ascii or continuation character */
330 }
331 if (*p < 0xE0) {
332 if (*p < 0xC2 || (p[1] & 0xC0) != 0x80) {
333 return *p; /* not valid UTF-8 */
334 }
335 (*pp)++;
336 return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
337 }
338 if (*p < 0xF0) {
339 if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80) {
340 return *p; /* not valid UTF-8 */
341 }
342 (*pp) += 2;
343 return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
344 }
345 if (*p < 0xF8) {
346 if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80) {
347 return *p; /* not valid UTF-8 */
348 }
349 (*pp) += 3;
350 return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
351 }
352 if (*p < 0xFC) {
353 if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
354 || (p[4] & 0xC0) != 0x80) {
355 return *p; /* not valid UTF-8 */
356 }
357 (*pp) += 4;
358 return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
359 }
360 if (*p < 0xFE) {
361 if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
362 || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80) {
363 return *p; /* not valid UTF-8 */
364 }
365 (*pp) += 5;
366 return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F);
367 }
368 return *p; /* not sensible */
369}

Referenced by sms_readfile().

Variable Documentation

◆ app

char* app = "SMS"
static

Definition at line 130 of file app_sms.c.

Referenced by load_module(), and unload_module().

◆ defaultalphabet

const unsigned short defaultalphabet[]
static

Definition at line 197 of file app_sms.c.

197 {
198 0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
199 0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
200 0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
201 0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
202 ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
203 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
204 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
205 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
206 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
207 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
208};

Referenced by packsms7(), and unpacksms7().

◆ escapes

const unsigned short escapes[]
static

Definition at line 210 of file app_sms.c.

210 {
211 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
212 0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
213 0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
214 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
215 0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
216 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
217 0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
219};

Referenced by packsms7(), and unpacksms7().

◆ log_file

char log_file[255]
static

Definition at line 128 of file app_sms.c.

Referenced by load_module(), and sms_log().

◆ message_ref

volatile unsigned char message_ref
static

Definition at line 125 of file app_sms.c.

Referenced by sms_compose1().

◆ seq

volatile unsigned int seq
static

◆ sms_options

const 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 }, [ 'n' ] = { .flag = OPTIONS_NO_LOG }, [ 'p' ] = { .flag = OPTION_PAUSE , .arg_index = OPTION_ARG_PAUSE + 1 }, }
static

Definition at line 1931 of file app_sms.c.

Referenced by sms_exec().

◆ smsgen

struct ast_generator smsgen
static
Initial value:
= {
.alloc = sms_alloc,
.release = sms_release,
.generate = sms_generate,
}
static void * sms_alloc(struct ast_channel *chan, void *sms_t_ptr)
Definition app_sms.c:1736
static void sms_release(struct ast_channel *chan, void *data)
Definition app_sms.c:1741
static int sms_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition app_sms.c:1656

Definition at line 1746 of file app_sms.c.

1746 {
1747 .alloc = sms_alloc,
1748 .release = sms_release,
1749 .generate = sms_generate,
1750};

◆ wave

const signed short wave[]
static

Definition at line 138 of file app_sms.c.

138 {
139 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
140 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
141 0, -392, -782, -1167,
142 -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
143 -4985, -4938, -4862,
144 -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
145};

Referenced by load_module(), and sms_process().

◆ wave_out

const output_t* wave_out = wave
static

Definition at line 154 of file app_sms.c.

Referenced by sms_generate().