Asterisk - The Open Source Telephony Project GIT-master-8b8a8c1
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
Itzan Huerta - Testing and debugging for Telefónica DOMO Mensajes (Spain) phones using protocol 2.

Definition in file app_sms.c.

Macro Definition Documentation

◆ __OUT_FMT

#define __OUT_FMT   ast_format_slin

Definition at line 155 of file app_sms.c.

◆ DIR_RX

#define DIR_RX   1

Definition at line 1491 of file app_sms.c.

◆ DIR_TX

#define DIR_TX   2

Definition at line 1492 of file app_sms.c.

◆ DLL2_ACK

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

◆ is16bit

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

Definition at line 289 of file app_sms.c.

◆ is7bit

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

Definition at line 287 of file app_sms.c.

◆ is8bit

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

Definition at line 288 of file app_sms.c.

◆ MAX_DEBUG_LEN

#define MAX_DEBUG_LEN   300

Definition at line 1255 of file app_sms.c.

◆ MAXSAMPLES

#define MAXSAMPLES   (800)

◆ OSYNC_BITS

#define OSYNC_BITS   80 /* initial sync bits */

Definition at line 158 of file app_sms.c.

◆ SMSLEN

#define SMSLEN   160

max SMS length

Definition at line 221 of file app_sms.c.

◆ SMSLEN_8

#define SMSLEN_8   140

max SMS length for 8-bit char

Definition at line 222 of file app_sms.c.

Typedef Documentation

◆ output_t

typedef signed short output_t

Definition at line 153 of file app_sms.c.

◆ sms_t

typedef struct sms_s sms_t

Enumeration Type Documentation

◆ message_types

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

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

Definition at line 167 of file app_sms.c.

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

◆ sms_flags

enum sms_flags
Enumerator
OPTION_BE_SMSC 
OPTION_ANSWER 
OPTION_TWO 
OPTION_PAUSE 
OPTION_SRR 
OPTION_DCS 
OPTIONS_NO_LOG 

Definition at line 1864 of file app_sms.c.

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

◆ sms_opt_args

Enumerator
OPTION_ARG_PAUSE 
OPTION_ARG_ARRAY_SIZE 

Definition at line 1874 of file app_sms.c.

1874 {
1875 OPTION_ARG_PAUSE = 0,
1877};
@ OPTION_ARG_PAUSE
Definition: app_sms.c:1875
@ OPTION_ARG_ARRAY_SIZE
Definition: app_sms.c:1876

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

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

References sms_s::omsg.

Referenced by putdummydata_proto2(), and sms_compose2().

◆ AST_MODULE_INFO_STANDARD_EXTENDED()

AST_MODULE_INFO_STANDARD_EXTENDED ( ASTERISK_GPL_KEY  ,
"SMS/PSTN handler  
)

◆ isodate()

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

static, return a date/time in ISO format

Definition at line 309 of file app_sms.c.

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

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

Referenced by sms_log(), and sms_writefile().

◆ load_module()

static int load_module ( void  )
static

Definition at line 2091 of file app_sms.c.

2092{
2093#ifdef OUTALAW
2094 int p;
2095 for (p = 0; p < 80; p++) {
2096 wavea[p] = AST_LIN2A(wave[p]);
2097 }
2098#endif
2099 snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR);
2101}
#define AST_LIN2A(a)
Definition: alaw.h:50
static int sms_exec(struct ast_channel *chan, const char *data)
Definition: app_sms.c:1889
static char * app
Definition: app_sms.c:130
static const signed short wave[]
Definition: app_sms.c:138
static char log_file[255]
Definition: app_sms.c:128
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
const char * ast_config_AST_LOG_DIR
Definition: options.c:160

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

◆ numcpy()

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

copy number, skipping non digits apart from leading +

Definition at line 294 of file app_sms.c.

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

References d.

Referenced by sms_readfile().

◆ packaddress()

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

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

Definition at line 752 of file app_sms.c.

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

Referenced by sms_compose1().

◆ packdate()

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

pack a date and return

Definition at line 559 of file app_sms.c.

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

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

Referenced by sms_compose1().

◆ packsms()

static int packsms ( unsigned char  dcs,
unsigned char *  base,
unsigned int  udhl,
unsigned char *  udh,
int  udl,
unsigned short *  ud 
)
static

general pack, with length and data, returns number of bytes of target used

Definition at line 526 of file app_sms.c.

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

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

Referenced by sms_compose1().

◆ packsms16()

static int packsms16 ( unsigned char *  o,
int  udhl,
unsigned char *  udh,
int  udl,
unsigned short *  ud 
)
static

takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 16 bit UCS-2 character codes The return value is the number of bytes packed in to o, which is internally limited to 140 o can be null, in which case this is used to validate or count only if the input contains invalid characters then the return value is -1

Definition at line 491 of file app_sms.c.

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

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

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

Referenced by packsms(), and sms_readfile().

◆ packsms8()

static int packsms8 ( unsigned char *  o,
int  udhl,
unsigned char *  udh,
int  udl,
unsigned short *  ud 
)
static

takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 8 bit character codes. The return value is the number of bytes packed in to o, which is internally limited to 140. o can be null, in which case this is used to validate or count only. if the input contains invalid characters then the return value is -1

Definition at line 452 of file app_sms.c.

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

References dummy(), NULL, and SMSLEN_8.

Referenced by packsms(), and sms_readfile().

◆ putdummydata_proto2()

static void putdummydata_proto2 ( sms_t h)
static

Definition at line 1212 of file app_sms.c.

1213{
1214 adddata_proto2(h, 0x10, "\0", 1); /* Media Identifier > SMS */
1215 adddata_proto2(h, 0x11, "\0\0\0\0\0\0", 6); /* Firmware version */
1216 adddata_proto2(h, 0x12, "\2\0\4", 3); /* SMS provider ID */
1217 adddata_proto2(h, 0x13, h->udtxt, h->udl); /* Body */
1218}
static void adddata_proto2(sms_t *h, unsigned char msg, char *data, int size)
Definition: app_sms.c:1195
char udtxt[SMSLEN]
Definition: app_sms.c:283
int udl
Definition: app_sms.c:238

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

Referenced by sms_compose2().

◆ readdirqueue()

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

read dir skipping dot files...

Definition at line 1109 of file app_sms.c.

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

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

1693{
1694 return sms_t_ptr;
1695}

◆ sms_compose1()

static void sms_compose1 ( sms_t h,
int  more 
)
static

compose a message for protocol 1

Definition at line 1407 of file app_sms.c.

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

References sms_s::da, sms_s::dcs, message_ref, sms_s::mr, sms_s::oa, sms_s::omsg, packaddress(), packdate(), packsms(), sms_s::pid, sms_s::rp, sms_s::scts, sms_s::smsc, sms_s::srr, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, sms_s::udl, and sms_s::vp.

Referenced by sms_nextoutgoing().

◆ sms_compose2()

static void sms_compose2 ( sms_t h,
int  more 
)
static

Definition at line 1220 of file app_sms.c.

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

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

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

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

Referenced by sms_messagerx(), and sms_messagetx().

◆ sms_exec()

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

Definition at line 1889 of file app_sms.c.

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

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

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

◆ sms_handleincoming()

static unsigned char sms_handleincoming ( sms_t h)
static

handle the incoming message

Definition at line 1119 of file app_sms.c.

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

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

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

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

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

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

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

Referenced by sms_messagerx(), and sms_messagerx2().

◆ sms_messagerx()

static void sms_messagerx ( sms_t h)
static

Definition at line 1511 of file app_sms.c.

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

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

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

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

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

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

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

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

◆ sms_readfile()

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

parse and delete a file

Definition at line 833 of file app_sms.c.

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

References ast_log, ast_mktime(), ast_tvnow(), d, sms_s::da, sms_s::dcs, is16bit, is7bit, is8bit, LOG_NOTICE, LOG_WARNING, sms_s::mr, NULL, numcpy(), sms_s::oa, packsms16(), packsms7(), packsms8(), sms_s::pid, sms_s::rp, sms_s::rx, S, sms_s::scts, SMSLEN, sms_s::srr, ast_tm::tm_hour, ast_tm::tm_isdst, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, ast_tm::tm_year, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, sms_s::udl, sms_s::udtxt, utf8decode(), and sms_s::vp.

Referenced by sms_nextoutgoing().

◆ sms_release()

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

Definition at line 1697 of file app_sms.c.

1698{
1699 return; /* nothing to do here. */
1700}

◆ sms_writefile()

static void sms_writefile ( sms_t h)
static

white a received text message to a file

Definition at line 1005 of file app_sms.c.

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

References ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_log, ast_mkdir(), ast_tvnow(), ast_tvzero(), buf, sms_s::da, sms_s::dcs, isodate(), LOG_NOTICE, sms_s::mr, NULL, sms_s::oa, sms_s::pid, sms_s::queue, sms_s::rp, sms_s::rx, sms_s::scts, seq, sms_s::smsc, sms_s::srr, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, sms_s::udl, and sms_s::vp.

Referenced by sms_handleincoming(), and sms_handleincoming_proto2().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 2086 of file app_sms.c.

2087{
2089}
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 734 of file app_sms.c.

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

Referenced by sms_handleincoming().

◆ unpackdate()

static struct timeval unpackdate ( unsigned char *  i)
static

unpack a date and return

Definition at line 585 of file app_sms.c.

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

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

Referenced by sms_handleincoming().

◆ unpacksms()

static int unpacksms ( unsigned char  dcs,
unsigned char *  i,
unsigned char *  udh,
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 718 of file app_sms.c.

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

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

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

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

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

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

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

Referenced by unpacksms().

◆ utf8decode()

static long utf8decode ( unsigned char **  pp)
static

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

Definition at line 321 of file app_sms.c.

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

Referenced by sms_readfile().

Variable Documentation

◆ app

char* app = "SMS"
static

Definition at line 130 of file app_sms.c.

Referenced by load_module(), and unload_module().

◆ defaultalphabet

const unsigned short defaultalphabet[]
static

Definition at line 197 of file app_sms.c.

Referenced by packsms7(), and unpacksms7().

◆ escapes

const unsigned short escapes[]
static

Definition at line 210 of file app_sms.c.

Referenced by packsms7(), and unpacksms7().

◆ log_file

char log_file[255]
static

Definition at line 128 of file app_sms.c.

Referenced by load_module(), and sms_log().

◆ message_ref

volatile unsigned char message_ref
static

Definition at line 125 of file app_sms.c.

Referenced by sms_compose1().

◆ seq

volatile unsigned int seq
static

◆ sms_options

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

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

Definition at line 1702 of file app_sms.c.

◆ wave

const signed short wave[]
static

Definition at line 138 of file app_sms.c.

Referenced by load_module(), and sms_process().

◆ wave_out

const output_t* wave_out = wave
static

Definition at line 154 of file app_sms.c.

Referenced by sms_generate().