Asterisk - The Open Source Telephony Project GIT-master-f3e88d3
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 More...
 
static int load_module (void)
 
static void numcpy (char *d, char *s)
 copy number, skipping non digits apart from leading + More...
 
static unsigned char packaddress (unsigned char *o, char *i)
 store an address at o, and return number of bytes used More...
 
static void packdate (unsigned char *o, time_t w)
 pack a date and return More...
 
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 More...
 
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 More...
 
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 More...
 
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 More...
 
static void putdummydata_proto2 (sms_t *h)
 
static struct dirent * readdirqueue (DIR *d, char *queue)
 read dir skipping dot files... More...
 
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 More...
 
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 More...
 
static int sms_handleincoming_proto2 (sms_t *h)
 sms_handleincoming_proto2: handle the incoming message More...
 
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. More...
 
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 More...
 
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 More...
 
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 More...
 
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 More...
 
static struct timeval unpackdate (unsigned char *i)
 unpack a date and return More...
 
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 More...
 
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 More...
 
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 More...
 
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. More...
 
static long utf8decode (unsigned char **pp)
 Reads next UCS character from NUL terminated UTF-8 string and advance pointer. More...
 

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

Definition in file app_sms.c.

Macro Definition Documentation

◆ __OUT_FMT

#define __OUT_FMT   ast_format_slin

Definition at line 149 of file app_sms.c.

◆ DIR_RX

#define DIR_RX   1

Definition at line 1483 of file app_sms.c.

◆ DIR_TX

#define DIR_TX   2

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

◆ is7bit

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

Definition at line 281 of file app_sms.c.

◆ is8bit

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

Definition at line 282 of file app_sms.c.

◆ MAX_DEBUG_LEN

#define MAX_DEBUG_LEN   300

Definition at line 1248 of file app_sms.c.

◆ MAXSAMPLES

#define MAXSAMPLES   (800)

◆ OSYNC_BITS

#define OSYNC_BITS   80 /* initial sync bits */

Definition at line 152 of file app_sms.c.

◆ SMSLEN

#define SMSLEN   160

max SMS length

Definition at line 215 of file app_sms.c.

◆ SMSLEN_8

#define SMSLEN_8   140

max SMS length for 8-bit char

Definition at line 216 of file app_sms.c.

Typedef Documentation

◆ output_t

typedef signed short output_t

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

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

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

1856 {
1857 OPTION_BE_SMSC = (1 << 0), /* act as sms center */
1858 OPTION_ANSWER = (1 << 1), /* answer on incoming calls */
1859 OPTION_TWO = (1 << 2), /* Use Protocol Two */
1860 OPTION_PAUSE = (1 << 3), /* pause before sending data, in ms */
1861 OPTION_SRR = (1 << 4), /* set srr */
1862 OPTION_DCS = (1 << 5), /* set dcs */
1863 OPTIONS_NO_LOG = (1 << 6), /* Don't log SMS content */
1864};
@ OPTION_ANSWER
Definition: app_sms.c:1858
@ OPTION_SRR
Definition: app_sms.c:1861
@ OPTIONS_NO_LOG
Definition: app_sms.c:1863
@ OPTION_TWO
Definition: app_sms.c:1859
@ OPTION_BE_SMSC
Definition: app_sms.c:1857
@ OPTION_PAUSE
Definition: app_sms.c:1860
@ OPTION_DCS
Definition: app_sms.c:1862

◆ sms_opt_args

Enumerator
OPTION_ARG_PAUSE 
OPTION_ARG_ARRAY_SIZE 

Definition at line 1866 of file app_sms.c.

1866 {
1867 OPTION_ARG_PAUSE = 0,
1869};
@ OPTION_ARG_PAUSE
Definition: app_sms.c:1867
@ OPTION_ARG_ARRAY_SIZE
Definition: app_sms.c:1868

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

1189{
1190 int x = h->omsg[1] + 2; /* Get current position */
1191 if (x == 2) {
1192 x += 2; /* First: skip Payload length (set later) */
1193 }
1194 h->omsg[x++] = msg; /* Message code */
1195 h->omsg[x++] = (unsigned char)size; /* Data size Low */
1196 h->omsg[x++] = 0; /* Data size Hi */
1197 for (; size > 0 ; size--) {
1198 h->omsg[x++] = *data++;
1199 }
1200 h->omsg[1] = x - 2; /* Frame size */
1201 h->omsg[2] = x - 4; /* Payload length (Lo) */
1202 h->omsg[3] = 0; /* Payload length (Hi) */
1203}
unsigned char omsg[256]
Definition: app_sms.c:249

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

304{
305 struct ast_tm tm;
306 struct timeval local = { t, 0 };
307 ast_localtime(&local, &tm, NULL);
308 ast_strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm);
309 return buf;
310}
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 2083 of file app_sms.c.

2084{
2085#ifdef OUTALAW
2086 int p;
2087 for (p = 0; p < 80; p++) {
2088 wavea[p] = AST_LIN2A(wave[p]);
2089 }
2090#endif
2091 snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR);
2093}
#define AST_LIN2A(a)
Definition: alaw.h:50
static int sms_exec(struct ast_channel *chan, const char *data)
Definition: app_sms.c:1881
static char * app
Definition: app_sms.c:124
static const signed short wave[]
Definition: app_sms.c:132
static char log_file[255]
Definition: app_sms.c:122
#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:159

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

289{
290 if (*s == '+') {
291 *d++ = *s++;
292 }
293 while (*s) {
294 if (isdigit(*s)) {
295 *d++ = *s;
296 }
297 s++;
298 }
299 *d = 0;
300}
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 746 of file app_sms.c.

747{
748 unsigned char p = 2;
749 o[0] = 0; /* number of bytes */
750 if (*i == '+') { /* record as bit 0 in byte 1 */
751 i++;
752 o[1] = 0x91;
753 } else {
754 o[1] = 0x81;
755 }
756 for ( ; *i ; i++) {
757 if (!isdigit(*i)) { /* ignore non-digits */
758 continue;
759 }
760 if (o[0] & 1) {
761 o[p++] |= ((*i & 0xF) << 4);
762 } else {
763 o[p] = (*i & 0xF);
764 }
765 o[0]++;
766 }
767 if (o[0] & 1) {
768 o[p++] |= 0xF0; /* pad */
769 }
770 return p;
771}

Referenced by sms_compose1().

◆ packdate()

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

pack a date and return

Definition at line 553 of file app_sms.c.

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

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

521{
522 unsigned char *p = base;
523 if (udl == 0) {
524 *p++ = 0; /* no user data */
525 } else {
526
527 int l = 0;
528 if (is7bit(dcs)) { /* 7 bit */
529 if ((l = packsms7(p + 1, udhl, udh, udl, ud)) < 0) {
530 l = 0;
531 }
532 *p++ = l;
533 p += (l * 7 + 7) / 8;
534 } else if (is8bit(dcs)) { /* 8 bit */
535 if ((l = packsms8(p + 1, udhl, udh, udl, ud)) < 0) {
536 l = 0;
537 }
538 *p++ = l;
539 p += l;
540 } else { /* UCS-2 */
541 if ((l = packsms16(p + 1, udhl, udh, udl, ud)) < 0) {
542 l = 0;
543 }
544 *p++ = l;
545 p += l;
546 }
547 }
548 return p - base;
549}
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:369
#define is7bit(dcs)
Definition: app_sms.c:281
#define is8bit(dcs)
Definition: app_sms.c:282
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:485
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:446

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

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

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

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

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

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

1206{
1207 adddata_proto2(h, 0x10, "\0", 1); /* Media Identifier > SMS */
1208 adddata_proto2(h, 0x11, "\0\0\0\0\0\0", 6); /* Firmware version */
1209 adddata_proto2(h, 0x12, "\2\0\4", 3); /* SMS provider ID */
1210 adddata_proto2(h, 0x13, h->udtxt, h->udl); /* Body */
1211}
static void adddata_proto2(sms_t *h, unsigned char msg, char *data, int size)
Definition: app_sms.c:1188
char udtxt[SMSLEN]
Definition: app_sms.c:277
int udl
Definition: app_sms.c:232

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

1103{
1104 struct dirent *f;
1105 do {
1106 f = readdir(d);
1107 } while (f && (*f->d_name == '.' || strncmp(f->d_name, queue, strlen(queue)) || f->d_name[strlen(queue)] != '.'));
1108 return f;
1109}

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

1685{
1686 return sms_t_ptr;
1687}

◆ sms_compose1()

static void sms_compose1 ( sms_t h,
int  more 
)
static

compose a message for protocol 1

Definition at line 1400 of file app_sms.c.

1401{
1402 unsigned int p = 2; /* next byte to write. Skip type and len */
1403
1404 h->omsg[0] = 0x91; /* SMS_DATA */
1405 if (h->smsc) { /* deliver */
1406 h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
1407 p += packaddress(h->omsg + p, h->oa);
1408 h->omsg[p++] = h->pid;
1409 h->omsg[p++] = h->dcs;
1410 packdate(h->omsg + p, h->scts.tv_sec);
1411 p += 7;
1412 p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1413 } else { /* submit */
1414 h->omsg[p++] =
1415 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
1416 if (h->mr < 0) {
1417 h->mr = message_ref++;
1418 }
1419 h->omsg[p++] = h->mr;
1420 p += packaddress(h->omsg + p, h->da);
1421 h->omsg[p++] = h->pid;
1422 h->omsg[p++] = h->dcs;
1423 if (h->vp) { /* relative VP */
1424 if (h->vp < 720) {
1425 h->omsg[p++] = (h->vp + 4) / 5 - 1;
1426 } else if (h->vp < 1440) {
1427 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
1428 } else if (h->vp < 43200) {
1429 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
1430 } else if (h->vp < 635040) {
1431 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
1432 } else {
1433 h->omsg[p++] = 255; /* max */
1434 }
1435 }
1436 p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1437 }
1438 h->omsg[1] = p - 2;
1439}
static volatile unsigned char message_ref
Definition: app_sms.c:119
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:520
static void packdate(unsigned char *o, time_t w)
pack a date and return
Definition: app_sms.c:553
static unsigned char packaddress(unsigned char *o, char *i)
store an address at o, and return number of bytes used
Definition: app_sms.c:746
unsigned char srr
Definition: app_sms.c:234
unsigned char dcs
Definition: app_sms.c:230
char da[20]
Definition: app_sms.c:227
unsigned char pid
Definition: app_sms.c:229
char oa[20]
Definition: app_sms.c:226
unsigned char udh[SMSLEN]
Definition: app_sms.c:239
short mr
Definition: app_sms.c:231
struct timeval scts
Definition: app_sms.c:228
unsigned char udhi
Definition: app_sms.c:235
int udhl
Definition: app_sms.c:233
unsigned char rp
Definition: app_sms.c:236
unsigned char smsc
Definition: app_sms.c:222
unsigned int vp
Definition: app_sms.c:237
unsigned short ud[SMSLEN]
Definition: app_sms.c:238

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

1214{
1215 struct ast_tm tm;
1216 struct timeval now = h->scts;
1217 char stm[45];
1218
1219 h->omsg[0] = 0x00; /* set later... */
1220 h->omsg[1] = 0;
1222 if (h->smsc) { /* deliver */
1223 h->omsg[0] = 0x11; /* SMS_DELIVERY */
1224 /* Required: 10 11 12 13 14 15 17 (seems they must be ordered!) */
1225 ast_localtime(&now, &tm, NULL);
1226 sprintf(stm, "%02d%02d%02d%02d", tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min); /* Date mmddHHMM */
1227 adddata_proto2(h, 0x14, stm, 8); /* Date */
1228 if (*h->oa == 0) {
1229 strcpy(h->oa, "00000000");
1230 }
1231 adddata_proto2(h, 0x15, h->oa, strlen(h->oa)); /* Originator */
1232 adddata_proto2(h, 0x17, "\1", 1); /* Calling Terminal ID */
1233 } else { /* submit */
1234 h->omsg[0] = 0x10; /* SMS_SUBMIT */
1235 /* Required: 10 11 12 13 17 18 1B 1C (seems they must be ordered!) */
1236 adddata_proto2(h, 0x17, "\1", 1); /* Calling Terminal ID */
1237 if (*h->da == 0) {
1238 strcpy(h->da, "00000000");
1239 }
1240 adddata_proto2(h, 0x18, h->da, strlen(h->da)); /* Originator */
1241 adddata_proto2(h, 0x1B, "\1", 1); /* Called Terminal ID */
1242 adddata_proto2(h, 0x1C, "\0\0\0", 3); /* Notification */
1243 }
1244}
static void putdummydata_proto2(sms_t *h)
Definition: app_sms.c:1205

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

1486{
1487 char txt[259 * 3 + 1];
1488 char *p = txt; /* always long enough */
1489 unsigned char *msg = (dir == DIR_RX) ? h->imsg : h->omsg;
1490 int n = (dir == DIR_RX) ? h->ibytep : msg[1] + 2;
1491 int q = 0;
1492 while (q < n && q < 30) {
1493 sprintf(p, " %02hhX", msg[q++]);
1494 p += 3;
1495 }
1496 if (q < n) {
1497 sprintf(p, "...");
1498 }
1499 ast_verb(3, "SMS %s%s\n", dir == DIR_RX ? "RX" : "TX", txt);
1500}
#define DIR_RX
Definition: app_sms.c:1483
#define ast_verb(level,...)
unsigned char ibytep
Definition: app_sms.c:266
unsigned char imsg[250]
Definition: app_sms.c:250

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

1882{
1883 int res = -1;
1884 sms_t h = { 0 };
1885 /* argument parsing support */
1886 struct ast_flags flags = { 0 };
1887 char *parse, *sms_opts[OPTION_ARG_ARRAY_SIZE] = { 0, };
1888 char *p;
1889 AST_DECLARE_APP_ARGS(sms_args,
1890 AST_APP_ARG(queue);
1892 AST_APP_ARG(addr);
1893 AST_APP_ARG(body);
1894 );
1895
1896 if (!data) {
1897 ast_log(LOG_ERROR, "Requires queue name at least\n");
1898 return -1;
1899 }
1900
1901 parse = ast_strdupa(data); /* create a local copy */
1902 AST_STANDARD_APP_ARGS(sms_args, parse);
1903 if (sms_args.argc > 1) {
1904 ast_app_parse_options(sms_options, &flags, sms_opts, sms_args.options);
1905 }
1906
1907 ast_verb(1, "sms argc %u queue <%s> opts <%s> addr <%s> body <%s>\n",
1908 sms_args.argc, S_OR(sms_args.queue, ""),
1909 S_OR(sms_args.options, ""),
1910 S_OR(sms_args.addr, ""),
1911 S_OR(sms_args.body, "") );
1912
1913 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1914 h.dcs = 0xF1; /* default */
1915
1917 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
1918 sizeof(h.cli));
1919
1920 if (ast_strlen_zero(sms_args.queue)) {
1921 ast_log(LOG_ERROR, "Requires queue name\n");
1922 goto done;
1923 }
1924 if (strlen(sms_args.queue) >= sizeof(h.queue)) {
1925 ast_log(LOG_ERROR, "Queue name too long\n");
1926 goto done;
1927 }
1928 ast_copy_string(h.queue, sms_args.queue, sizeof(h.queue));
1929
1930 for (p = h.queue; *p; p++) {
1931 if (!isalnum(*p)) {
1932 *p = '-'; /* make very safe for filenames */
1933 }
1934 }
1935
1937 h.protocol = ast_test_flag(&flags, OPTION_TWO) ? 2 : 1;
1938 h.nolog = ast_test_flag(&flags, OPTIONS_NO_LOG) ? 1 : 0;
1939 if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE])) {
1940 h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]);
1941 }
1942 if (h.opause_0 < 25 || h.opause_0 > 2000) {
1943 h.opause_0 = 300; /* default 300ms */
1944 }
1945 ast_verb(1, "initial delay %dms\n", h.opause_0);
1946
1947
1948 /* the following apply if there is an arg3/4 and apply to the created message file */
1950 h.srr = 1;
1951 }
1953 h.dcs = 1;
1954 }
1955#if 0
1956 case '1':
1957 case '2':
1958 case '3':
1959 case '4':
1960 case '5':
1961 case '6':
1962 case '7': /* set the pid for saved local message */
1963 h.pid = 0x40 + (*d & 0xF);
1964 break;
1965 }
1966#endif
1967 if (sms_args.argc > 2) {
1968 unsigned char *up;
1969
1970 /* submitting a message, not taking call. */
1971 /* deprecated, use smsq instead */
1972 h.scts = ast_tvnow();
1973 if (ast_strlen_zero(sms_args.addr) || strlen(sms_args.addr) >= sizeof(h.oa)) {
1974 ast_log(LOG_ERROR, "Address too long %s\n", sms_args.addr);
1975 goto done;
1976 }
1977 if (h.smsc) {
1978 ast_copy_string(h.oa, sms_args.addr, sizeof(h.oa));
1979 } else {
1980 ast_copy_string(h.da, sms_args.addr, sizeof(h.da));
1981 ast_copy_string(h.oa, h.cli, sizeof(h.oa));
1982 }
1983 h.udl = 0;
1984 if (ast_strlen_zero(sms_args.body)) {
1985 ast_log(LOG_ERROR, "Missing body for %s\n", sms_args.addr);
1986 goto done;
1987 }
1988 up = (unsigned char *)sms_args.body;
1989 while (*up && h.udl < SMSLEN) {
1990 h.ud[h.udl++] = utf8decode(&up);
1991 }
1992 if (is7bit(h.dcs) && packsms7(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
1993 ast_log(LOG_WARNING, "Invalid 7 bit GSM data\n");
1994 goto done;
1995 }
1996 if (is8bit(h.dcs) && packsms8(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
1997 ast_log(LOG_WARNING, "Invalid 8 bit data\n");
1998 goto done;
1999 }
2000 if (is16bit(h.dcs) && packsms16(0, h.udhl, h.udh, h.udl, h.ud) < 0) {
2001 ast_log(LOG_WARNING, "Invalid 16 bit data\n");
2002 goto done;
2003 }
2004 h.rx = 0; /* sent message */
2005 h.mr = -1;
2006 sms_writefile(&h);
2007 res = h.err;
2008 goto done;
2009 }
2010
2011 if (ast_channel_state(chan) != AST_STATE_UP) { /* make sure channel is answered before any TX */
2012 ast_answer(chan);
2013 }
2014
2016 h.framenumber = 1; /* Proto 2 */
2017 /* set up SMS_EST initial message */
2018 if (h.protocol == 2) {
2019 h.omsg[0] = DLL2_SMS_EST;
2020 h.omsg[1] = 0;
2021 } else {
2023 h.omsg[1] = 0;
2024 }
2025 sms_messagetx(&h);
2026 }
2027
2028 res = ast_set_write_format(chan, __OUT_FMT);
2029 if (res >= 0) {
2031 }
2032 if (res < 0) {
2033 ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n");
2034 goto done;
2035 }
2036
2037 if ( (res = ast_activate_generator(chan, &smsgen, &h)) < 0) {
2038 ast_log(LOG_ERROR, "Failed to activate generator on '%s'\n", ast_channel_name(chan));
2039 goto done;
2040 }
2041
2042 /* Do our thing here */
2043 for (;;) {
2044 struct ast_frame *f;
2045 int i = ast_waitfor(chan, -1);
2046 if (i < 0) {
2047 ast_log(LOG_NOTICE, "waitfor failed\n");
2048 break;
2049 }
2050 if (h.hangup) {
2051 ast_log(LOG_NOTICE, "channel hangup\n");
2052 break;
2053 }
2054 f = ast_read(chan);
2055 if (!f) {
2056 ast_log(LOG_NOTICE, "ast_read failed\n");
2057 break;
2058 }
2059 if (f->frametype == AST_FRAME_VOICE) {
2060 sms_process(&h, f->samples, f->data.ptr);
2061 }
2062
2063 ast_frfree(f);
2064 }
2065 res = h.err; /* XXX */
2066
2067 /*
2068 * The SMS generator data is on the stack. We _MUST_ make sure the generator
2069 * is stopped before returning from this function.
2070 */
2072
2073 sms_log(&h, '?'); /* log incomplete message */
2074done:
2075 return (res);
2076}
static struct ast_generator smsgen
Definition: app_sms.c:1694
static long utf8decode(unsigned char **pp)
Reads next UCS character from NUL terminated UTF-8 string and advance pointer.
Definition: app_sms.c:315
static void sms_messagetx(sms_t *h)
Definition: app_sms.c:1561
#define __OUT_FMT
Definition: app_sms.c:149
#define is16bit(dcs)
Definition: app_sms.c:283
static void sms_process(sms_t *h, int samples, signed short *data)
Definition: app_sms.c:1712
static const struct ast_app_option sms_options[128]
Definition: app_sms.c:1879
static void sms_log(sms_t *h, char status)
Log the output, and remove file.
Definition: app_sms.c:774
static void sms_writefile(sms_t *h)
white a received text message to a file
Definition: app_sms.c:998
while(1)
Definition: ast_expr2f.c:880
#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:2951
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3162
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2893
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5762
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5803
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
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
#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:3056
#define ast_frfree(fr)
@ AST_FRAME_VOICE
#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:199
unsigned int flags
Definition: utils.h:200
Data structure associated with a single frame of data.
union ast_frame::@226 data
enum ast_frame_type frametype
Number structure.
Definition: app_followme.c:154
Definition: app_sms.c:218
int opause_0
Definition: app_sms.c:273
unsigned char err
Definition: app_sms.c:220
char cli[20]
Definition: app_sms.c:240
unsigned char nolog
Definition: app_sms.c:224
unsigned char ipc1
Definition: app_sms.c:260
int framenumber
Definition: app_sms.c:276
int protocol
Definition: app_sms.c:274
unsigned char hangup
Definition: app_sms.c:219
unsigned char rx
Definition: app_sms.c:223
unsigned char ipc0
Definition: app_sms.c:259
char queue[30]
Definition: app_sms.c:225
int done
Definition: test_amihooks.c:48
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:63

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

1605{
1606 struct ast_frame f = { 0 };
1607#define MAXSAMPLES (800)
1608 output_t *buf;
1609 sms_t *h = data;
1610 int i, res;
1611
1612 if (samples > MAXSAMPLES) {
1613 ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n",
1616 }
1617 len = samples * sizeof(*buf) + AST_FRIENDLY_OFFSET;
1618 buf = ast_alloca(len);
1619
1622 f.datalen = samples * sizeof(*buf);
1624 f.mallocd = 0;
1625 f.data.ptr = buf;
1626 f.samples = samples;
1627 f.src = "app_sms";
1628 /* create a buffer containing the digital sms pattern */
1629 for (i = 0; i < samples; i++) {
1630 buf[i] = wave_out[0]; /* default is silence */
1631
1632 if (h->opause) {
1633 h->opause--;
1634 } else if (h->obyten || h->osync) { /* sending data */
1635 buf[i] = wave_out[h->ophase];
1636 h->ophase += (h->obyte & 1) ? 13 : 21; /* compute next phase */
1637 if (h->ophase >= 80)
1638 h->ophase -= 80;
1639 if ((h->ophasep += 12) >= 80) { /* time to send the next bit */
1640 h->ophasep -= 80;
1641 if (h->oseizure > 0) { /* sending channel seizure (proto 2) */
1642 h->oseizure--;
1643 h->obyte ^= 1; /* toggle low bit */
1644 } else if (h->osync) {
1645 h->obyte = 1; /* send mark as sync bit */
1646 h->osync--; /* sending sync bits */
1647 if (h->osync == 0 && h->protocol == 2 && h->omsg[0] == DLL2_SMS_EST) {
1648 h->obytep = h->obyten = 0; /* we are done */
1649 }
1650 } else {
1651 h->obitp++;
1652 if (h->obitp == 1) {
1653 h->obyte = 0; /* start bit; */
1654 } else if (h->obitp == 2) {
1655 h->obyte = h->omsg[h->obytep];
1656 } else if (h->obitp == 10) {
1657 h->obyte = 1; /* stop bit */
1658 h->obitp = 0;
1659 h->obytep++;
1660 if (h->obytep == h->obyten) {
1661 h->obytep = h->obyten = 0; /* sent */
1662 h->osync = 10; /* trailing marks */
1663 }
1664 } else {
1665 h->obyte >>= 1;
1666 }
1667 }
1668 }
1669 }
1670 }
1671 res = ast_write(chan, &f);
1672 ast_frfree(&f);
1673 if (res < 0) {
1674 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
1675 return -1;
1676 }
1677 return 0;
1678#undef MAXSAMPLES
1679}
static const output_t * wave_out
Definition: app_sms.c:148
signed short output_t
Definition: app_sms.c:147
#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:5144
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
int errno
struct ast_format * format
struct ast_frame_subclass subclass
const char * src
unsigned char obyten
Definition: app_sms.c:248
unsigned char osync
Definition: app_sms.c:246
unsigned char ophasep
Definition: app_sms.c:242
unsigned int opause
Definition: app_sms.c:244
int oseizure
Definition: app_sms.c:275
unsigned char obytep
Definition: app_sms.c:247
unsigned char obyte
Definition: app_sms.c:243
unsigned char obitp
Definition: app_sms.c:245
unsigned char ophase
Definition: app_sms.c:241

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

1113{
1114 unsigned char p = 3;
1115 if (h->smsc) { /* SMSC */
1116 if ((h->imsg[2] & 3) == 1) { /* SMS-SUBMIT */
1117 h->udhl = h->udl = 0;
1118 h->vp = 0;
1119 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
1120 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1121 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1122 ast_copy_string(h->oa, h->cli, sizeof(h->oa));
1123 h->scts = ast_tvnow();
1124 h->mr = h->imsg[p++];
1125 p += unpackaddress(h->da, h->imsg + p);
1126 h->pid = h->imsg[p++];
1127 h->dcs = h->imsg[p++];
1128 if ((h->imsg[2] & 0x18) == 0x10) { /* relative VP */
1129 if (h->imsg[p] < 144) {
1130 h->vp = (h->imsg[p] + 1) * 5;
1131 } else if (h->imsg[p] < 168) {
1132 h->vp = 720 + (h->imsg[p] - 143) * 30;
1133 } else if (h->imsg[p] < 197) {
1134 h->vp = (h->imsg[p] - 166) * 1440;
1135 } else {
1136 h->vp = (h->imsg[p] - 192) * 10080;
1137 }
1138 p++;
1139 } else if (h->imsg[2] & 0x18) {
1140 p += 7; /* ignore enhanced / absolute VP */
1141 }
1142 p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1143 h->rx = 1; /* received message */
1144 sms_writefile(h); /* write the file */
1145 if (p != h->imsg[1] + 2) {
1146 ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1147 return 0xFF; /* duh! */
1148 }
1149 } else {
1150 ast_log(LOG_WARNING, "Unknown message type %02hhX\n", h->imsg[2]);
1151 return 0xFF;
1152 }
1153 } else { /* client */
1154 if (!(h->imsg[2] & 3)) { /* SMS-DELIVER */
1155 *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
1156 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
1157 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1158 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1159 h->mr = -1;
1160 p += unpackaddress(h->oa, h->imsg + p);
1161 h->pid = h->imsg[p++];
1162 h->dcs = h->imsg[p++];
1163 h->scts = unpackdate(h->imsg + p);
1164 p += 7;
1165 p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1166 h->rx = 1; /* received message */
1167 sms_writefile(h); /* write the file */
1168 if (p != h->imsg[1] + 2) {
1169 ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1170 return 0xFF; /* duh! */
1171 }
1172 } else {
1173 ast_log(LOG_WARNING, "Unknown message type %02hhX\n", h->imsg[2]);
1174 return 0xFF;
1175 }
1176 }
1177 return 0; /* no error */
1178}
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,...
Definition: app_sms.c:712
static struct timeval unpackdate(unsigned char *i)
unpack a date and return
Definition: app_sms.c:579
static unsigned char unpackaddress(char *o, unsigned char *i)
unpack an address from i, return byte length, unpack to o
Definition: app_sms.c:728

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

◆ sms_handleincoming_proto2()

static int sms_handleincoming_proto2 ( sms_t h)
static

sms_handleincoming_proto2: handle the incoming message

Definition at line 1262 of file app_sms.c.

1263{
1264 int f, i, sz = 0;
1265 int msg, msgsz;
1266 struct ast_tm tm;
1267 struct timeval now = { 0, 0 };
1268 char debug_buf[MAX_DEBUG_LEN * 3 + 1];
1269
1270 sz = h->imsg[1] + 2;
1271 /* ast_verb(3, "SMS-P2 Frame: %s\n", sms_hexdump(h->imsg, sz, debug_buf)); */
1272
1273 /* Parse message body (called payload) */
1274 now = h->scts = ast_tvnow();
1275 for (f = 4; f < sz; ) {
1276 msg = h->imsg[f++];
1277 msgsz = h->imsg[f++];
1278 msgsz += (h->imsg[f++] * 256);
1279 switch (msg) {
1280 case 0x13: /* Body */
1281 ast_verb(3, "SMS-P2 Body#%02X=[%.*s]\n", (unsigned)msg, msgsz, &h->imsg[f]);
1282 if (msgsz >= sizeof(h->ud)) {
1283 msgsz = sizeof(h->ud) - 1;
1284 }
1285 for (i = 0; i < msgsz; i++) {
1286 h->ud[i] = h->imsg[f + i];
1287 }
1288 h->udl = msgsz;
1289 break;
1290 case 0x14: /* Date SCTS */
1291 now = h->scts = ast_tvnow();
1292 ast_localtime(&now, &tm, NULL);
1293 tm.tm_mon = ( (h->imsg[f] * 10) + h->imsg[f + 1] ) - 1;
1294 tm.tm_mday = ( (h->imsg[f + 2] * 10) + h->imsg[f + 3] );
1295 tm.tm_hour = ( (h->imsg[f + 4] * 10) + h->imsg[f + 5] );
1296 tm.tm_min = ( (h->imsg[f + 6] * 10) + h->imsg[f + 7] );
1297 tm.tm_sec = 0;
1298 h->scts = ast_mktime(&tm, NULL);
1299 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);
1300 break;
1301 case 0x15: /* Calling line (from SMSC) */
1302 if (msgsz >= 20) {
1303 msgsz = 20 - 1;
1304 }
1305 ast_verb(3, "SMS-P2 Origin#%02X=[%.*s]\n", (unsigned)msg, msgsz, &h->imsg[f]);
1306 ast_copy_string(h->oa, (char *)(&h->imsg[f]), msgsz + 1);
1307 break;
1308 case 0x18: /* Destination(from TE/phone) */
1309 if (msgsz >= 20) {
1310 msgsz = 20 - 1;
1311 }
1312 ast_verb(3, "SMS-P2 Destination#%02X=[%.*s]\n", (unsigned)msg, msgsz, &h->imsg[f]);
1313 ast_copy_string(h->da, (char *)(&h->imsg[f]), msgsz + 1);
1314 break;
1315 case 0x1C: /* Notify */
1316 ast_verb(3, "SMS-P2 Notify#%02X=%s\n", (unsigned)msg, sms_hexdump(&h->imsg[f], 3, debug_buf));
1317 break;
1318 default:
1319 ast_verb(3, "SMS-P2 Par#%02X [%d]: %s\n", (unsigned)msg, msgsz, sms_hexdump(&h->imsg[f], msgsz, debug_buf));
1320 break;
1321 }
1322 f+=msgsz; /* Skip to next */
1323 }
1324 h->rx = 1; /* received message */
1325 sms_writefile(h); /* write the file */
1326 return 0; /* no error */
1327}
static char * sms_hexdump(unsigned char buf[], int size, char *s)
Definition: app_sms.c:1249
#define MAX_DEBUG_LEN
Definition: app_sms.c:1248
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 1249 of file app_sms.c.

1250{
1251 char *p;
1252 int f;
1253
1254 for (p = s, f = 0; f < size && f < MAX_DEBUG_LEN; f++, p += 3) {
1255 sprintf(p, "%02hhX ", (unsigned char)buf[f]);
1256 }
1257 return(s);
1258}

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

775{
776 int o;
777
778 if (*h->oa == '\0' && *h->da == '\0') {
779 return;
780 }
781 o = open(log_file, O_CREAT | O_APPEND | O_WRONLY, AST_FILE_MODE);
782 if (o >= 0) {
783 char line[1000], mrs[3] = "", *p;
784 char buf[30];
785 unsigned char n;
786
787 if (h->mr >= 0) {
788 snprintf(mrs, sizeof(mrs), "%02hhX", (unsigned char)h->mr);
789 }
790 snprintf(line, sizeof(line), "%s %c%c%c%s %s %s %s ",
791 isodate(time(NULL), buf, sizeof(buf)),
792 status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue,
793 S_OR(h->oa, "-"), S_OR(h->da, "-") );
794 p = line + strlen(line);
795
796 if (h->nolog) {
797 p += snprintf(p, 1000 - strlen(line), "udl=%d", h->udl);
798 } else {
799 for (n = 0; n < h->udl; n++) {
800 if (h->ud[n] == '\\') {
801 *p++ = '\\';
802 *p++ = '\\';
803 } else if (h->ud[n] == '\n') {
804 *p++ = '\\';
805 *p++ = 'n';
806 } else if (h->ud[n] == '\r') {
807 *p++ = '\\';
808 *p++ = 'r';
809 } else if (h->ud[n] < 32 || h->ud[n] == 127) {
810 *p++ = 0xbf;
811 } else {
812 *p++ = h->ud[n];
813 }
814 }
815 }
816 *p++ = '\n';
817 *p = 0;
818 if (write(o, line, strlen(line)) < 0) {
819 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
820 }
821 close(o);
822 }
823 *h->oa = *h->da = h->udl = 0;
824}
jack_status_t status
Definition: app_jack.c:146
static char * isodate(time_t t, char *buf, int len)
static, return a date/time in ISO format
Definition: app_sms.c:303
#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 1503 of file app_sms.c.

1504{
1505 int cause;
1506
1507 sms_debug (DIR_RX, h);
1508 if (h->protocol == 2) {
1509 sms_messagerx2(h);
1510 return;
1511 }
1512 /* parse incoming message for Protocol 1 */
1513 switch (h->imsg[0]) {
1514 case 0x91: /* SMS_DATA */
1515 cause = sms_handleincoming (h);
1516 if (!cause) {
1517 sms_log(h, 'Y');
1518 h->omsg[0] = 0x95; /* SMS_ACK */
1519 h->omsg[1] = 0x02;
1520 h->omsg[2] = 0x00; /* deliver report */
1521 h->omsg[3] = 0x00; /* no parameters */
1522 } else { /* NACK */
1523 sms_log(h, 'N');
1524 h->omsg[0] = 0x96; /* SMS_NACK */
1525 h->omsg[1] = 3;
1526 h->omsg[2] = 0; /* delivery report */
1527 h->omsg[3] = cause; /* cause */
1528 h->omsg[4] = 0; /* no parameters */
1529 }
1530 sms_messagetx(h);
1531 break;
1532
1533 case 0x92: /* SMS_ERROR */
1534 h->err = 1;
1535 sms_messagetx(h); /* send whatever we sent again */
1536 break;
1537 case 0x93: /* SMS_EST */
1538 sms_nextoutgoing (h);
1539 break;
1540 case 0x94: /* SMS_REL */
1541 h->hangup = 1; /* hangup */
1542 break;
1543 case 0x95: /* SMS_ACK */
1544 sms_log(h, 'Y');
1545 sms_nextoutgoing (h);
1546 break;
1547 case 0x96: /* SMS_NACK */
1548 h->err = 1;
1549 sms_log(h, 'N');
1550 sms_nextoutgoing (h);
1551 break;
1552 default: /* Unknown */
1553 h->omsg[0] = 0x92; /* SMS_ERROR */
1554 h->omsg[1] = 1;
1555 h->omsg[2] = 3; /* unknown message type */
1556 sms_messagetx(h);
1557 break;
1558 }
1559}
static unsigned char sms_handleincoming(sms_t *h)
handle the incoming message
Definition: app_sms.c:1112
static void sms_messagerx2(sms_t *h)
Definition: app_sms.c:1343
static void sms_nextoutgoing(sms_t *h)
find and fill in next message, or send a REL if none waiting
Definition: app_sms.c:1442
static void sms_debug(int dir, sms_t *h)
Definition: app_sms.c:1485

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

1344{
1345 int p = h->imsg[0] & DLL_SMS_MASK ; /* mask the high bit */
1346 int cause;
1347
1348#define DLL2_ACK(h) ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1)
1349 switch (p) {
1350 case DLL2_SMS_EST: /* Protocol 2: Connection ready (fake): send message */
1351 sms_nextoutgoing (h);
1352 /* 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 "); */
1353 break;
1354
1355 case DLL2_SMS_INFO_MO: /* transport SMS_SUBMIT */
1356 case DLL2_SMS_INFO_MT: /* transport SMS_DELIVERY */
1357 cause = sms_handleincoming_proto2(h);
1358 if (!cause) { /* ACK */
1359 sms_log(h, 'Y');
1360 }
1361 h->omsg[0] = DLL2_ACK(h);
1362 h->omsg[1] = 0x06; /* msg len */
1363 h->omsg[2] = 0x04; /* payload len */
1364 h->omsg[3] = 0x00; /* payload len */
1365 h->omsg[4] = 0x1f; /* Response type */
1366 h->omsg[5] = 0x01; /* parameter len */
1367 h->omsg[6] = 0x00; /* parameter len */
1368 h->omsg[7] = cause; /* CONFIRM or error */
1369 sms_messagetx(h);
1370 break;
1371
1372 case DLL2_SMS_NACK: /* Protocol 2: SMS_NAK */
1373 h->omsg[0] = DLL2_SMS_REL; /* SMS_REL */
1374 h->omsg[1] = 0x00; /* msg len */
1375 sms_messagetx(h);
1376 break;
1377
1378 case DLL2_SMS_ACK0:
1379 case DLL2_SMS_ACK1:
1380 /* SMS_ACK also transport SMS_SUBMIT or SMS_DELIVERY */
1381 if ( (h->omsg[0] & DLL_SMS_MASK) == DLL2_SMS_REL) {
1382 /* a response to our Release, just hangup */
1383 h->hangup = 1; /* hangup */
1384 } else {
1385 /* XXX depending on what we are.. */
1386 ast_log(LOG_NOTICE, "SMS_SUBMIT or SMS_DELIVERY\n");
1387 sms_nextoutgoing (h);
1388 }
1389 break;
1390
1391 case DLL2_SMS_REL: /* Protocol 2: SMS_REL (hangup req) */
1392 h->omsg[0] = DLL2_ACK(h);
1393 h->omsg[1] = 0;
1394 sms_messagetx(h);
1395 break;
1396 }
1397}
#define DLL2_ACK(h)
static int sms_handleincoming_proto2(sms_t *h)
sms_handleincoming_proto2: handle the incoming message
Definition: app_sms.c:1262

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

1562{
1563 unsigned char c = 0, p;
1564 int len = h->omsg[1] + 2; /* total message length excluding checksum */
1565
1566 for (p = 0; p < len; p++) { /* compute checksum */
1567 c += h->omsg[p];
1568 }
1569 h->omsg[len] = 0 - c; /* actually, (256 - (c & 0fxx)) & 0xff) */
1570 sms_debug(DIR_TX, h);
1571 h->framenumber++; /* Proto 2 */
1572 h->obytep = 0;
1573 h->obitp = 0;
1574 if (h->protocol == 2) { /* Proto 2: */
1575 h->oseizure = 300; /* 300bits (or more ?) */
1576 h->obyte = 0; /* Seizure starts with space (0) */
1577 if (h->omsg[0] == 0x7F) {
1578 h->opause = 8 * h->opause_0; /* initial message delay */
1579 } else {
1580 h->opause = 400;
1581 }
1582 } else { /* Proto 1: */
1583 h->oseizure = 0; /* No seizure */
1584 h->obyte = 1; /* send mark ('1') at the beginning */
1585 /* Change the initial message delay. BT requires 300ms,
1586 * but for others this might be way too much and the phone
1587 * could time out. XXX make it configurable.
1588 */
1589 if (h->omsg[0] == 0x93) {
1590 h->opause = 8 * h->opause_0; /* initial message delay */
1591 } else {
1592 h->opause = 200;
1593 }
1594 }
1595 /* Note - setting osync triggers the generator */
1596 h->osync = OSYNC_BITS; /* 80 sync bits */
1597 h->obyten = len + 1; /* bytes to send (including checksum) */
1598}
#define OSYNC_BITS
Definition: app_sms.c:152
#define DIR_TX
Definition: app_sms.c:1484
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 1442 of file app_sms.c.

1443{
1444 char fn[100 + NAME_MAX] = "";
1445 DIR *d;
1446 char more = 0;
1447
1448 *h->da = *h->oa = '\0'; /* clear destinations */
1449 h->rx = 0; /* outgoing message */
1450 snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? "mttx" : "motx");
1451 ast_mkdir(fn, 0777); /* ensure it exists */
1452 d = opendir(fn);
1453 if (d) {
1454 struct dirent *f = readdirqueue(d, h->queue);
1455 if (f) {
1456 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", f->d_name);
1457 sms_readfile(h, fn);
1458 if (readdirqueue(d, h->queue)) {
1459 more = 1; /* more to send */
1460 }
1461 }
1462 closedir(d);
1463 }
1464 if (*h->da || *h->oa) { /* message to send */
1465 if (h->protocol == 2) {
1466 sms_compose2(h, more);
1467 } else {
1468 sms_compose1(h, more);
1469 }
1470 } else { /* no message */
1471 if (h->protocol == 2) {
1472 h->omsg[0] = 0x17; /* SMS_REL */
1473 h->omsg[1] = 0;
1474 } else {
1475 h->omsg[0] = 0x94; /* SMS_REL */
1476 h->omsg[1] = 0;
1477 h->sent_rel = 1;
1478 }
1479 }
1480 sms_messagetx(h);
1481}
static void sms_compose1(sms_t *h, int more)
compose a message for protocol 1
Definition: app_sms.c:1400
static void sms_readfile(sms_t *h, char *fn)
parse and delete a file
Definition: app_sms.c:827
static void sms_compose2(sms_t *h, int more)
Definition: app_sms.c:1213
static struct dirent * readdirqueue(DIR *d, char *queue)
read dir skipping dot files...
Definition: app_sms.c:1102
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:154
unsigned char sent_rel
Definition: app_sms.c:221
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: utils.c:2479

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

1713{
1714 int bit;
1715
1716 /*
1717 * Ignore incoming audio while a packet is being transmitted,
1718 * the protocol is half-duplex.
1719 * Unfortunately this means that if the outbound and incoming
1720 * transmission overlap (which is an error condition anyways),
1721 * we may miss some data and this makes debugging harder.
1722 */
1723 if (h->obyten || h->osync) {
1724 return;
1725 }
1726 for ( ; samples-- ; data++) {
1727 unsigned long long m0, m1;
1728 if (abs(*data) > h->imag) {
1729 h->imag = abs(*data);
1730 } else {
1731 h->imag = h->imag * 7 / 8;
1732 }
1733 if (h->imag <= 500) { /* below [arbitrary] threahold: lost carrier */
1734 if (h->idle++ == 80000) { /* nothing happening */
1735 ast_log(LOG_NOTICE, "No data, hanging up\n");
1736 h->hangup = 1;
1737 h->err = 1;
1738 }
1739 if (h->ierr) { /* error */
1740 ast_log(LOG_NOTICE, "Error %d, hanging up\n", h->ierr);
1741 /* Protocol 1 */
1742 h->err = 1;
1743 h->omsg[0] = 0x92; /* error */
1744 h->omsg[1] = 1;
1745 h->omsg[2] = h->ierr;
1746 sms_messagetx(h); /* send error */
1747 }
1748 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1749 continue;
1750 }
1751 h->idle = 0;
1752
1753 /* multiply signal by the two carriers. */
1754 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
1755 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
1756 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
1757 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
1758 /* compute the amplitudes */
1759 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
1760 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
1761
1762 /* advance the sin/cos pointers */
1763 if ((h->ips0 += 21) >= 80) {
1764 h->ips0 -= 80;
1765 }
1766 if ((h->ipc0 += 21) >= 80) {
1767 h->ipc0 -= 80;
1768 }
1769 if ((h->ips1 += 13) >= 80) {
1770 h->ips1 -= 80;
1771 }
1772 if ((h->ipc1 += 13) >= 80) {
1773 h->ipc1 -= 80;
1774 }
1775
1776 /* set new bit to 1 or 0 depending on which value is stronger */
1777 h->ibith <<= 1;
1778 if (m1 > m0) {
1779 h->ibith |= 1;
1780 }
1781 if (h->ibith & 8) {
1782 h->ibitt--;
1783 }
1784 if (h->ibith & 1) {
1785 h->ibitt++;
1786 }
1787 bit = ((h->ibitt > 1) ? 1 : 0);
1788 if (bit != h->ibitl) {
1789 h->ibitc = 1;
1790 } else {
1791 h->ibitc++;
1792 }
1793 h->ibitl = bit;
1794 if (!h->ibitn && h->ibitc == 4 && !bit) {
1795 h->ibitn = 1;
1796 h->iphasep = 0;
1797 }
1798 if (bit && h->ibitc == 200) { /* sync, restart message */
1799 /* Protocol 2: empty connection ready (I am master) */
1800 if (h->framenumber < 0 && h->ibytec >= 160 && !memcmp(h->imsg, "UUUUUUUUUUUUUUUUUUUU", 20)) {
1801 h->framenumber = 1;
1802 ast_verb(3, "SMS protocol 2 detected\n");
1803 h->protocol = 2;
1804 h->imsg[0] = 0xff; /* special message (fake) */
1805 h->imsg[1] = h->imsg[2] = 0x00;
1806 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1807 sms_messagerx(h);
1808 }
1809 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1810 }
1811 if (h->ibitn) {
1812 h->iphasep += 12;
1813 if (h->iphasep >= 80) { /* next bit */
1814 h->iphasep -= 80;
1815 if (h->ibitn++ == 9) { /* end of byte */
1816 if (!bit) { /* bad stop bit */
1817 if (h->sent_rel) {
1818 h->hangup = 1;
1819 } else {
1820 ast_log(LOG_NOTICE, "Bad stop bit\n");
1821 h->ierr = 0xFF; /* unknown error */
1822 }
1823 } else {
1824 if (h->ibytep < sizeof(h->imsg)) {
1825 h->imsg[h->ibytep] = h->ibytev;
1826 h->ibytec += h->ibytev;
1827 h->ibytep++;
1828 } else if (h->ibytep == sizeof(h->imsg)) {
1829 ast_log(LOG_NOTICE, "msg too large\n");
1830 h->ierr = 2; /* bad message length */
1831 }
1832 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
1833 if (!h->ibytec) {
1834 sms_messagerx(h);
1835 } else {
1836 ast_log(LOG_NOTICE, "bad checksum\n");
1837 h->ierr = 1; /* bad checksum */
1838 }
1839 }
1840 }
1841 h->ibitn = 0;
1842 }
1843 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1844 }
1845 }
1846 }
1847}
static void sms_messagerx(sms_t *h)
Definition: app_sms.c:1503
#define abs(x)
Definition: f2c.h:195
unsigned char ibitt
Definition: app_sms.c:270
signed long long imc0
Definition: app_sms.c:252
unsigned char ibith
Definition: app_sms.c:269
signed long long imc1
Definition: app_sms.c:254
unsigned char ips0
Definition: app_sms.c:257
unsigned char ibitn
Definition: app_sms.c:264
unsigned char ibitc
Definition: app_sms.c:262
signed long long ims1
Definition: app_sms.c:253
unsigned char ibytev
Definition: app_sms.c:265
unsigned char iphasep
Definition: app_sms.c:263
unsigned char ibytec
Definition: app_sms.c:267
unsigned char ibitl
Definition: app_sms.c:261
unsigned char ierr
Definition: app_sms.c:268
unsigned char ips1
Definition: app_sms.c:258
unsigned int idle
Definition: app_sms.c:255
signed long long ims0
Definition: app_sms.c:251
unsigned short imag
Definition: app_sms.c:256

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

828{
829 char line[1000];
830 FILE *s;
831 char dcsset = 0; /* if DSC set */
832 ast_log(LOG_NOTICE, "Sending %s\n", fn);
833 h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
834 h->mr = -1;
835 h->dcs = 0xF1; /* normal messages class 1 */
836 h->scts = ast_tvnow();
837 s = fopen(fn, "r");
838 if (s) {
839 if (unlink(fn)) { /* concurrent access, we lost */
840 fclose(s);
841 return;
842 }
843 while (fgets (line, sizeof(line), s)) { /* process line in file */
844 char *p;
845 void *pp = &p;
846 for (p = line; *p && *p != '\n' && *p != '\r'; p++);
847 *p = 0; /* strip eoln */
848 p = line;
849 if (!*p || *p == ';') {
850 continue; /* blank line or comment, ignore */
851 }
852 while (isalnum(*p)) {
853 *p = tolower (*p);
854 p++;
855 }
856 while (isspace (*p)) {
857 *p++ = 0;
858 }
859 if (*p == '=') {
860 *p++ = 0;
861 if (!strcmp(line, "ud")) { /* parse message (UTF-8) */
862 unsigned char o = 0;
863 memcpy(h->udtxt, p, SMSLEN); /* for protocol 2 */
864 while (*p && o < SMSLEN) {
865 h->ud[o++] = utf8decode(pp);
866 }
867 h->udl = o;
868 if (*p) {
869 ast_log(LOG_WARNING, "UD too long in %s\n", fn);
870 }
871 } else {
872 while (isspace (*p)) {
873 p++;
874 }
875 if (!strcmp(line, "oa") && strlen(p) < sizeof(h->oa)) {
876 numcpy (h->oa, p);
877 } else if (!strcmp(line, "da") && strlen(p) < sizeof(h->oa)) {
878 numcpy (h->da, p);
879 } else if (!strcmp(line, "pid")) {
880 h->pid = atoi(p);
881 } else if (!strcmp(line, "dcs")) {
882 h->dcs = atoi(p);
883 dcsset = 1;
884 } else if (!strcmp(line, "mr")) {
885 h->mr = atoi(p);
886 } else if (!strcmp(line, "srr")) {
887 h->srr = (atoi(p) ? 1 : 0);
888 } else if (!strcmp(line, "vp")) {
889 h->vp = atoi(p);
890 } else if (!strcmp(line, "rp")) {
891 h->rp = (atoi(p) ? 1 : 0);
892 } else if (!strcmp(line, "scts")) { /* get date/time */
893 int Y, m, d, H, M, S;
894 /* XXX Why aren't we using ast_strptime here? */
895 if (sscanf(p, "%4d-%2d-%2dT%2d:%2d:%2d", &Y, &m, &d, &H, &M, &S) == 6) {
896 struct ast_tm t = { 0, };
897 t.tm_year = Y - 1900;
898 t.tm_mon = m - 1;
899 t.tm_mday = d;
900 t.tm_hour = H;
901 t.tm_min = M;
902 t.tm_sec = S;
903 t.tm_isdst = -1;
904 h->scts = ast_mktime(&t, NULL);
905 if (h->scts.tv_sec == 0) {
906 ast_log(LOG_WARNING, "Bad date/timein %s: %s", fn, p);
907 }
908 }
909 } else {
910 ast_log(LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
911 }
912 }
913 } else if (*p == '#') { /* raw hex format */
914 *p++ = 0;
915 if (*p == '#') {
916 p++;
917 if (!strcmp(line, "ud")) { /* user data */
918 int o = 0;
919 while (*p && o < SMSLEN) {
920 if (isxdigit(*p) && isxdigit(p[1]) && isxdigit(p[2]) && isxdigit(p[3])) {
921 h->ud[o++] =
922 (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 12) +
923 (((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
924 (((isalpha(p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha(p[3]) ? 9 : 0) + (p[3] & 0xF));
925 p += 4;
926 } else
927 break;
928 }
929 h->udl = o;
930 if (*p)
931 ast_log(LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
932 } else
933 ast_log(LOG_WARNING, "Only ud can use ## format, %s\n", fn);
934 } else if (!strcmp(line, "ud")) { /* user data */
935 int o = 0;
936 while (*p && o < SMSLEN) {
937 if (isxdigit(*p) && isxdigit(p[1])) {
938 h->ud[o++] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
939 p += 2;
940 } else {
941 break;
942 }
943 }
944 h->udl = o;
945 if (*p) {
946 ast_log(LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
947 }
948 } else if (!strcmp(line, "udh")) { /* user data header */
949 unsigned char o = 0;
950 h->udhi = 1;
951 while (*p && o < SMSLEN) {
952 if (isxdigit(*p) && isxdigit(p[1])) {
953 h->udh[o] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF));
954 o++;
955 p += 2;
956 } else {
957 break;
958 }
959 }
960 h->udhl = o;
961 if (*p) {
962 ast_log(LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
963 }
964 } else {
965 ast_log(LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
966 }
967 } else {
968 ast_log(LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
969 }
970 }
971 fclose(s);
972 if (!dcsset && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
973 if (packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
974 if (packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
975 ast_log(LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
976 } else {
977 h->dcs = 0x08; /* default to 16 bit */
978 ast_log(LOG_WARNING, "Sending in 16 bit format(%s)\n", fn);
979 }
980 } else {
981 h->dcs = 0xF5; /* default to 8 bit */
982 ast_log(LOG_WARNING, "Sending in 8 bit format(%s)\n", fn);
983 }
984 }
985 if (is7bit(h->dcs) && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
986 ast_log(LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
987 }
988 if (is8bit(h->dcs) && packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
989 ast_log(LOG_WARNING, "Invalid 8 bit data %s\n", fn);
990 }
991 if (is16bit(h->dcs) && packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) {
992 ast_log(LOG_WARNING, "Invalid 16 bit data %s\n", fn);
993 }
994 }
995}
#define S(e)
static void numcpy(char *d, char *s)
copy number, skipping non digits apart from leading +
Definition: app_sms.c:288
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 1689 of file app_sms.c.

1690{
1691 return; /* nothing to do here. */
1692}

◆ sms_writefile()

static void sms_writefile ( sms_t h)
static

white a received text message to a file

Definition at line 998 of file app_sms.c.

999{
1000 char fn[200] = "", fn2[200] = "";
1001 char buf[30];
1002 FILE *o;
1003
1004 if (ast_tvzero(h->scts)) {
1005 h->scts = ast_tvnow();
1006 }
1007 snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
1008 ast_mkdir(fn, 0777); /* ensure it exists */
1009 ast_copy_string(fn2, fn, sizeof(fn2));
1010 snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%s.%s-%u", h->queue, isodate(h->scts.tv_sec, buf, sizeof(buf)), seq++);
1011 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1);
1012 if ((o = fopen(fn, "w")) == NULL) {
1013 return;
1014 }
1015
1016 if (*h->oa) {
1017 fprintf(o, "oa=%s\n", h->oa);
1018 }
1019 if (*h->da) {
1020 fprintf(o, "da=%s\n", h->da);
1021 }
1022 if (h->udhi) {
1023 unsigned int p;
1024 fprintf(o, "udh#");
1025 for (p = 0; p < h->udhl; p++) {
1026 fprintf(o, "%02hhX", (unsigned char)h->udh[p]);
1027 }
1028 fprintf(o, "\n");
1029 }
1030 if (h->udl) {
1031 unsigned int p;
1032 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
1033 if (p < h->udl) {
1034 fputc(';', o); /* cannot use ud=, but include as a comment for human readable */
1035 }
1036 fprintf(o, "ud=");
1037 for (p = 0; p < h->udl; p++) {
1038 unsigned short v = h->ud[p];
1039 if (v < 32) {
1040 fputc(191, o);
1041 } else if (v < 0x80) {
1042 fputc(v, o);
1043 } else if (v < 0x800) {
1044 fputc(0xC0 + (v >> 6), o);
1045 fputc(0x80 + (v & 0x3F), o);
1046 } else {
1047 fputc(0xE0 + (v >> 12), o);
1048 fputc(0x80 + ((v >> 6) & 0x3F), o);
1049 fputc(0x80 + (v & 0x3F), o);
1050 }
1051 }
1052 fprintf(o, "\n");
1053 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
1054 if (p < h->udl) {
1055 for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
1056 if (p == h->udl) { /* can write in ucs-1 hex */
1057 fprintf(o, "ud#");
1058 for (p = 0; p < h->udl; p++) {
1059 fprintf(o, "%02hhX", (unsigned char)h->ud[p]);
1060 }
1061 fprintf(o, "\n");
1062 } else { /* write in UCS-2 */
1063 fprintf(o, "ud##");
1064 for (p = 0; p < h->udl; p++) {
1065 fprintf(o, "%04X", (unsigned)h->ud[p]);
1066 }
1067 fprintf(o, "\n");
1068 }
1069 }
1070 }
1071 if (h->scts.tv_sec) {
1072 char datebuf[30];
1073 fprintf(o, "scts=%s\n", isodate(h->scts.tv_sec, datebuf, sizeof(datebuf)));
1074 }
1075 if (h->pid) {
1076 fprintf(o, "pid=%d\n", h->pid);
1077 }
1078 if (h->dcs != 0xF1) {
1079 fprintf(o, "dcs=%d\n", h->dcs);
1080 }
1081 if (h->vp) {
1082 fprintf(o, "vp=%u\n", h->vp);
1083 }
1084 if (h->srr) {
1085 fprintf(o, "srr=1\n");
1086 }
1087 if (h->mr >= 0) {
1088 fprintf(o, "mr=%d\n", h->mr);
1089 }
1090 if (h->rp) {
1091 fprintf(o, "rp=1\n");
1092 }
1093 fclose(o);
1094 if (rename(fn, fn2)) {
1095 unlink(fn);
1096 } else {
1097 ast_log(LOG_NOTICE, "Received to %s\n", fn2);
1098 }
1099}
static volatile unsigned int seq
Definition: app_sms.c:120
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 2078 of file app_sms.c.

2079{
2081}
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392

References app, and ast_unregister_application().

◆ unpackaddress()

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

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

Definition at line 728 of file app_sms.c.

729{
730 unsigned char l = i[0], p;
731 if (i[1] == 0x91) {
732 *o++ = '+';
733 }
734 for (p = 0; p < l; p++) {
735 if (p & 1) {
736 *o++ = (i[2 + p / 2] >> 4) + '0';
737 } else {
738 *o++ = (i[2 + p / 2] & 0xF) + '0';
739 }
740 }
741 *o = 0;
742 return (l + 5) / 2;
743}

Referenced by sms_handleincoming().

◆ unpackdate()

static struct timeval unpackdate ( unsigned char *  i)
static

unpack a date and return

Definition at line 579 of file app_sms.c.

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

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

713{
714 int l = *i++;
715 if (is7bit(dcs)) {
716 unpacksms7(i, l, udh, udhl, ud, udl, udhi);
717 l = (l * 7 + 7) / 8; /* adjust length to return */
718 } else if (is8bit(dcs)) {
719 unpacksms8(i, l, udh, udhl, ud, udl, udhi);
720 } else {
721 l += l % 2;
722 unpacksms16(i, l, udh, udhl, ud, udl, udhi);
723 }
724 return l + 1;
725}
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....
Definition: app_sms.c:658
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....
Definition: app_sms.c:602
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....
Definition: app_sms.c:684

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

Referenced by sms_handleincoming().

◆ unpacksms16()

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

685{
686 unsigned short *o = ud;
687 *udhl = 0;
688 if (udhi) {
689 int n = *i;
690 *udhl = n;
691 if (n) {
692 i++;
693 l--;
694 while (l && n) {
695 l--;
696 n--;
697 *udh++ = *i++;
698 }
699 }
700 }
701 while (l--) {
702 int v = *i++;
703 if (l && l--) {
704 v = (v << 8) + *i++;
705 }
706 *o++ = v;
707 }
708 *udl = (o - ud);
709}

Referenced by unpacksms().

◆ unpacksms7()

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

603{
604 unsigned char b = 0, p = 0;
605 unsigned short *o = ud;
606 *udhl = 0;
607 if (udhi && l) { /* header */
608 int h = i[p];
609 *udhl = h;
610 if (h) {
611 b = 1;
612 p++;
613 l--;
614 while (h-- && l) {
615 *udh++ = i[p++];
616 b += 8;
617 while (b >= 7) {
618 b -= 7;
619 l--;
620 if (!l) {
621 break;
622 }
623 }
624 }
625 /* adjust for fill, septets */
626 if (b) {
627 b = 7 - b;
628 l--;
629 }
630 }
631 }
632 while (l--) {
633 unsigned char v;
634 if (b < 2) {
635 v = ((i[p] >> b) & 0x7F); /* everything in one byte */
636 } else {
637 v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
638 }
639 b += 7;
640 if (b >= 8) {
641 b -= 8;
642 p++;
643 }
644 /* 0x00A0 is the encoding of ESC (27) in defaultalphabet */
645 if (o > ud && o[-1] == 0x00A0 && escapes[v]) {
646 o[-1] = escapes[v];
647 } else {
648 *o++ = defaultalphabet[v];
649 }
650 }
651 *udl = (o - ud);
652}

References b, defaultalphabet, and escapes.

Referenced by unpacksms().

◆ unpacksms8()

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

659{
660 unsigned short *o = ud;
661 *udhl = 0;
662 if (udhi) {
663 int n = *i;
664 *udhl = n;
665 if (n) {
666 i++;
667 l--;
668 while (l && n) {
669 l--;
670 n--;
671 *udh++ = *i++;
672 }
673 }
674 }
675 while (l--) {
676 *o++ = *i++; /* not to UTF-8 as explicitly 8 bit coding in DCS */
677 }
678 *udl = (o - ud);
679}

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

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

Referenced by sms_readfile().

Variable Documentation

◆ app

char* app = "SMS"
static

Definition at line 124 of file app_sms.c.

Referenced by load_module(), and unload_module().

◆ defaultalphabet

const unsigned short defaultalphabet[]
static

Definition at line 191 of file app_sms.c.

Referenced by packsms7(), and unpacksms7().

◆ escapes

const unsigned short escapes[]
static

Definition at line 204 of file app_sms.c.

Referenced by packsms7(), and unpacksms7().

◆ log_file

char log_file[255]
static

Definition at line 122 of file app_sms.c.

Referenced by load_module(), and sms_log().

◆ message_ref

volatile unsigned char message_ref
static

Definition at line 119 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 1879 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:1684
static void sms_release(struct ast_channel *chan, void *data)
Definition: app_sms.c:1689
static int sms_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_sms.c:1604

Definition at line 1694 of file app_sms.c.

◆ wave

const signed short wave[]
static

Definition at line 132 of file app_sms.c.

Referenced by load_module(), and sms_process().

◆ wave_out

const output_t* wave_out = wave
static

Definition at line 148 of file app_sms.c.

Referenced by sms_generate().