Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 152 of file app_sms.c.

◆ DIR_RX

#define DIR_RX   1

Definition at line 1486 of file app_sms.c.

◆ DIR_TX

#define DIR_TX   2

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

◆ is7bit

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

Definition at line 284 of file app_sms.c.

◆ is8bit

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

Definition at line 285 of file app_sms.c.

◆ MAX_DEBUG_LEN

#define MAX_DEBUG_LEN   300

Definition at line 1251 of file app_sms.c.

◆ MAXSAMPLES

#define MAXSAMPLES   (800)

◆ OSYNC_BITS

#define OSYNC_BITS   80 /* initial sync bits */

Definition at line 155 of file app_sms.c.

◆ SMSLEN

#define SMSLEN   160

max SMS length

Definition at line 218 of file app_sms.c.

◆ SMSLEN_8

#define SMSLEN_8   140

max SMS length for 8-bit char

Definition at line 219 of file app_sms.c.

Typedef Documentation

◆ output_t

typedef signed short output_t

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

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

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

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

◆ sms_opt_args

Enumerator
OPTION_ARG_PAUSE 
OPTION_ARG_ARRAY_SIZE 

Definition at line 1869 of file app_sms.c.

1869 {
1870 OPTION_ARG_PAUSE = 0,
1872};
@ OPTION_ARG_PAUSE
Definition: app_sms.c:1870
@ OPTION_ARG_ARRAY_SIZE
Definition: app_sms.c:1871

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

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

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

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

2087{
2088#ifdef OUTALAW
2089 int p;
2090 for (p = 0; p < 80; p++) {
2091 wavea[p] = AST_LIN2A(wave[p]);
2092 }
2093#endif
2094 snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR);
2096}
#define AST_LIN2A(a)
Definition: alaw.h:50
static int sms_exec(struct ast_channel *chan, const char *data)
Definition: app_sms.c:1884
static char * app
Definition: app_sms.c:127
static const signed short wave[]
Definition: app_sms.c:135
static char log_file[255]
Definition: app_sms.c:125
#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 291 of file app_sms.c.

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

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

Referenced by sms_compose1().

◆ packdate()

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

pack a date and return

Definition at line 556 of file app_sms.c.

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

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

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

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

489{
490 unsigned char p = 0;
491 unsigned char dummy[SMSLEN_8];
492
493 if (o == NULL) {
494 o = dummy;
495 }
496 /* header - no encoding */
497 if (udhl) {
498 o[p++] = udhl;
499 while (udhl--) {
500 o[p++] = *udh++;
501 if (p >= SMSLEN_8) {
502 return p;
503 }
504 }
505 }
506 while (udl--) {
507 long u;
508 u = *ud++;
509 o[p++] = (u >> 8);
510 if (p >= SMSLEN_8) {
511 return p - 1; /* could not fit last character */
512 }
513 o[p++] = u;
514 if (p >= SMSLEN_8) {
515 return p;
516 }
517 }
518 return p;
519}
#define SMSLEN_8
Definition: app_sms.c:219
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 372 of file app_sms.c.

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

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

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

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

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

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

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

1688{
1689 return sms_t_ptr;
1690}

◆ sms_compose1()

static void sms_compose1 ( sms_t h,
int  more 
)
static

compose a message for protocol 1

Definition at line 1403 of file app_sms.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1693{
1694 return; /* nothing to do here. */
1695}

◆ sms_writefile()

static void sms_writefile ( sms_t h)
static

white a received text message to a file

Definition at line 1001 of file app_sms.c.

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

2082{
2084}
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 731 of file app_sms.c.

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

Referenced by sms_handleincoming().

◆ unpackdate()

static struct timeval unpackdate ( unsigned char *  i)
static

unpack a date and return

Definition at line 582 of file app_sms.c.

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

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

716{
717 int l = *i++;
718 if (is7bit(dcs)) {
719 unpacksms7(i, l, udh, udhl, ud, udl, udhi);
720 l = (l * 7 + 7) / 8; /* adjust length to return */
721 } else if (is8bit(dcs)) {
722 unpacksms8(i, l, udh, udhl, ud, udl, udhi);
723 } else {
724 l += l % 2;
725 unpacksms16(i, l, udh, udhl, ud, udl, udhi);
726 }
727 return l + 1;
728}
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:661
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:605
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:687

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

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

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

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

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

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

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

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

Referenced by sms_readfile().

Variable Documentation

◆ app

char* app = "SMS"
static

Definition at line 127 of file app_sms.c.

Referenced by load_module(), and unload_module().

◆ defaultalphabet

const unsigned short defaultalphabet[]
static

Definition at line 194 of file app_sms.c.

Referenced by packsms7(), and unpacksms7().

◆ escapes

const unsigned short escapes[]
static

Definition at line 207 of file app_sms.c.

Referenced by packsms7(), and unpacksms7().

◆ log_file

char log_file[255]
static

Definition at line 125 of file app_sms.c.

Referenced by load_module(), and sms_log().

◆ message_ref

volatile unsigned char message_ref
static

Definition at line 122 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 1882 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:1687
static void sms_release(struct ast_channel *chan, void *data)
Definition: app_sms.c:1692
static int sms_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_sms.c:1607

Definition at line 1697 of file app_sms.c.

◆ wave

const signed short wave[]
static

Definition at line 135 of file app_sms.c.

Referenced by load_module(), and sms_process().

◆ wave_out

const output_t* wave_out = wave
static

Definition at line 151 of file app_sms.c.

Referenced by sms_generate().