Merge "AST-2018-005: Fix tdata leaks when calling pjsip_endpt_send_response(2)"
[asterisk/asterisk.git] / apps / app_sms.c
index 0c53391..c50a686 100644 (file)
@@ -17,7 +17,7 @@
 /*! \file
  *
  * \brief SMS application - ETSI ES 201 912 protocol 1 implementation
- * 
+ *
  * \par Development notes
  * \note The ETSI standards are available free of charge from ETSI at
  *     http://pda.etsi.org/pda/queryform.asp
@@ -26,7 +26,7 @@
  *     ES 201 912      SMS for PSTN/ISDN
  *     TS 123 040      Technical realization of SMS
  *
- * 
+ *
  * \ingroup applications
  *
  * \author Adrian Kennard (for the original protocol 1 code)
  *                Not fully tested, under development
  */
 
-#include "asterisk.h"
+/*** MODULEINFO
+       <support_level>extended</support_level>
+ ***/
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+#include "asterisk.h"
 
 #include <dirent.h>
 #include <ctype.h>
@@ -52,6 +54,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/callerid.h"
 #include "asterisk/utils.h"
 #include "asterisk/app.h"
+#include "asterisk/format_cache.h"
 
 /*** DOCUMENTATION
        <application name="SMS" language="en_US">
@@ -83,6 +86,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                                        <option name="o">
                                                <para>The body should be coded as octets not 7-bit symbols.</para>
                                        </option>
+                                       <option name="n">
+                                               <para>Do not log any SMS content to log file (privacy).</para>
+                                       </option>
                                </optionlist>
                        </parameter>
                        <parameter name="addr" />
@@ -123,7 +129,7 @@ static char *app = "SMS";
  * To pick the two carriers (1300Hz for '1' and 2100 Hz for '0') used by
  * the modulation, we should take one every 13 and 21 samples respectively.
  */
-static signed short wave[] = {
+static const signed short wave[] = {
        0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
        5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
        0, -392, -782, -1167,
@@ -136,11 +142,11 @@ static signed short wave[] = {
 static unsigned char wavea[80];
 typedef unsigned char output_t;
 static const output_t *wave_out = wavea;    /* outgoing samples */
-#define __OUT_FMT AST_FORMAT_ALAW;
+#define __OUT_FMT ast_format_alaw
 #else
 typedef signed short output_t;
 static const output_t *wave_out = wave;     /* outgoing samples */
-#define __OUT_FMT AST_FORMAT_SLINEAR
+#define __OUT_FMT ast_format_slin
 #endif
 
 #define OSYNC_BITS     80                      /* initial sync bits */
@@ -212,8 +218,10 @@ static const unsigned short escapes[] = {
 typedef struct sms_s {
        unsigned char hangup;        /*!< we are done... */
        unsigned char err;           /*!< set for any errors */
+       unsigned char sent_rel:1;     /*!< have sent REL message... */
        unsigned char smsc:1;        /*!< we are SMSC */
        unsigned char rx:1;          /*!< this is a received message */
+       unsigned char nolog:1;       /*!< do not log plain text SMS content (privacy) */
        char queue[30];              /*!< queue name */
        char oa[20];                 /*!< originating address */
        char da[20];                 /*!< destination address */
@@ -403,7 +411,7 @@ static int packsms7(unsigned char *o, int udhl, unsigned char *udh, int udl, uns
                        for (v = 0; v < 128 && escapes[v] != u; v++);
                        if (v < 128) {  /* escaped sequence, esc + v */
                                /* store the low (8-b) bits in o[p], the remaining bits in o[p+1] */
-                               o[p] |= (27 << b);          /* the low bits go into o[p] */ 
+                               o[p] |= (27 << b);          /* the low bits go into o[p] */
                                b += 7;
                                if (b >= 8) {
                                        b -= 8;
@@ -466,13 +474,13 @@ static int packsms8(unsigned char *o, int udhl, unsigned char *udh, int udl, uns
        return p;
 }
 
-/*! \brief 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 
+/*! \brief takes a binary header (udhl bytes at udh) and UCS-2
+       message (udl characters at ud) and packs in to o using 16 bit
+       UCS-2 character codes
+       The return value is the number of bytes packed in to o, which is
+       internally limited to 140
+       o can be null, in which case this is used to validate or count
+       only if the input contains invalid characters then
        the return value is -1 */
 static int packsms16(unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
 {
@@ -507,7 +515,7 @@ static int packsms16(unsigned char *o, int udhl, unsigned char *udh, int udl, un
        return p;
 }
 
-/*! \brief general pack, with length and data, 
+/*! \brief general pack, with length and data,
        returns number of bytes of target used */
 static int packsms(unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
 {
@@ -515,7 +523,7 @@ static int packsms(unsigned char dcs, unsigned char *base, unsigned int udhl, un
        if (udl == 0) {
                *p++ = 0;                           /* no user data */
        } else {
-               
+
                int l = 0;
                if (is7bit(dcs)) {                  /* 7 bit */
                        if ((l = packsms7(p + 1, udhl, udh, udl, ud)) < 0) {
@@ -588,8 +596,8 @@ static struct timeval unpackdate(unsigned char *i)
        return ast_mktime(&t, NULL);
 }
 
-/*! \brief unpacks bytes (7 bit encoding) at i, len l septets, 
-       and places in udh and ud setting udhl and udl. udh not used 
+/*! \brief unpacks bytes (7 bit encoding) at i, len l septets,
+       and places in udh and ud setting udhl and udl. udh not used
        if udhi not set */
 static void unpacksms7(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
 {
@@ -643,8 +651,8 @@ static void unpacksms7(unsigned char *i, unsigned char l, unsigned char *udh, in
        *udl = (o - ud);
 }
 
-/*! \brief unpacks bytes (8 bit encoding) at i, len l septets, 
- *  and places in udh and ud setting udhl and udl. udh not used 
+/*! \brief unpacks bytes (8 bit encoding) at i, len l septets,
+ *  and places in udh and ud setting udhl and udl. udh not used
  *  if udhi not set.
  */
 static void unpacksms8(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
@@ -671,7 +679,7 @@ static void unpacksms8(unsigned char *i, unsigned char l, unsigned char *udh, in
 }
 
 /*! \brief unpacks bytes (16 bit encoding) at i, len l septets,
-        and places in udh and ud setting udhl and udl. 
+        and places in udh and ud setting udhl and udl.
        udh not used if udhi not set */
 static void unpacksms16(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
 {
@@ -692,7 +700,7 @@ static void unpacksms16(unsigned char *i, unsigned char l, unsigned char *udh, i
        }
        while (l--) {
                int v = *i++;
-               if (l--) {
+               if (l && l--) {
                        v = (v << 8) + *i++;
                }
                *o++ = v;
@@ -710,6 +718,7 @@ static int unpacksms(unsigned char dcs, unsigned char *i, unsigned char *udh, in
        } else if (is8bit(dcs)) {
                unpacksms8(i, l, udh, udhl, ud, udl, udhi);
        } else {
+               l += l % 2;
                unpacksms16(i, l, udh, udhl, ud, udl, udhi);
        }
        return l + 1;
@@ -776,27 +785,32 @@ static void sms_log(sms_t * h, char status)
                unsigned char n;
 
                if (h->mr >= 0) {
-                       snprintf(mrs, sizeof(mrs), "%02X", h->mr);
+                       snprintf(mrs, sizeof(mrs), "%02hhX", (unsigned char)h->mr);
                }
                snprintf(line, sizeof(line), "%s %c%c%c%s %s %s %s ",
                        isodate(time(NULL), buf, sizeof(buf)),
                        status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue,
                        S_OR(h->oa, "-"), S_OR(h->da, "-") );
                p = line + strlen(line);
-               for (n = 0; n < h->udl; n++) {
-                       if (h->ud[n] == '\\') {
-                               *p++ = '\\';
-                               *p++ = '\\';
-                       } else if (h->ud[n] == '\n') {
-                               *p++ = '\\';
-                               *p++ = 'n';
-                       } else if (h->ud[n] == '\r') {
-                               *p++ = '\\';
-                               *p++ = 'r';
-                       } else if (h->ud[n] < 32 || h->ud[n] == 127) {
-                               *p++ = 191;
-                       } else {
-                               *p++ = h->ud[n];
+
+               if (h->nolog) {
+                       p += snprintf(p, 1000 - strlen(line), "udl=%d", h->udl);
+               } else {
+                       for (n = 0; n < h->udl; n++) {
+                               if (h->ud[n] == '\\') {
+                                       *p++ = '\\';
+                                       *p++ = '\\';
+                               } else if (h->ud[n] == '\n') {
+                                       *p++ = '\\';
+                                       *p++ = 'n';
+                               } else if (h->ud[n] == '\r') {
+                                       *p++ = '\\';
+                                       *p++ = 'r';
+                               } else if (h->ud[n] < 32 || h->ud[n] == 127) {
+                                       *p++ = 0xbf;
+                               } else {
+                                       *p++ = h->ud[n];
+                               }
                        }
                }
                *p++ = '\n';
@@ -878,7 +892,7 @@ static void sms_readfile(sms_t * h, char *fn)
                                        } else if (!strcmp(line, "scts")) {    /* get date/time */
                                                int Y, m, d, H, M, S;
                                                /* XXX Why aren't we using ast_strptime here? */
-                                               if (sscanf(p, "%d-%d-%dT%d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6) {
+                                               if (sscanf(p, "%4d-%2d-%2dT%2d:%2d:%2d", &Y, &m, &d, &H, &M, &S) == 6) {
                                                        struct ast_tm t = { 0, };
                                                        t.tm_year = Y - 1900;
                                                        t.tm_mon = m - 1;
@@ -993,7 +1007,7 @@ static void sms_writefile(sms_t * h)
        snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
        ast_mkdir(fn, 0777);                    /* ensure it exists */
        ast_copy_string(fn2, fn, sizeof(fn2));
-       snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%s.%s-%d", h->queue, isodate(h->scts.tv_sec, buf, sizeof(buf)), seq++);
+       snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%s.%s-%u", h->queue, isodate(h->scts.tv_sec, buf, sizeof(buf)), seq++);
        snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1);
        if ((o = fopen(fn, "w")) == NULL) {
                return;
@@ -1009,7 +1023,7 @@ static void sms_writefile(sms_t * h)
                unsigned int p;
                fprintf(o, "udh#");
                for (p = 0; p < h->udhl; p++) {
-                       fprintf(o, "%02X", h->udh[p]);
+                       fprintf(o, "%02hhX", (unsigned char)h->udh[p]);
                }
                fprintf(o, "\n");
        }
@@ -1042,13 +1056,13 @@ static void sms_writefile(sms_t * h)
                        if (p == h->udl) {              /* can write in ucs-1 hex */
                                fprintf(o, "ud#");
                                for (p = 0; p < h->udl; p++) {
-                                       fprintf(o, "%02X", h->ud[p]);
+                                       fprintf(o, "%02hhX", (unsigned char)h->ud[p]);
                                }
                                fprintf(o, "\n");
                        } else {                        /* write in UCS-2 */
                                fprintf(o, "ud##");
                                for (p = 0; p < h->udl; p++) {
-                                       fprintf(o, "%04X", h->ud[p]);
+                                       fprintf(o, "%04X", (unsigned)h->ud[p]);
                                }
                                fprintf(o, "\n");
                        }
@@ -1065,7 +1079,7 @@ static void sms_writefile(sms_t * h)
                fprintf(o, "dcs=%d\n", h->dcs);
        }
        if (h->vp) {
-               fprintf(o, "vp=%d\n", h->vp);
+               fprintf(o, "vp=%u\n", h->vp);
        }
        if (h->srr) {
                fprintf(o, "srr=1\n");
@@ -1133,7 +1147,7 @@ static unsigned char sms_handleincoming (sms_t * h)
                                return 0xFF;              /* duh! */
                        }
                } else {
-                       ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
+                       ast_log(LOG_WARNING, "Unknown message type %02hhX\n", h->imsg[2]);
                        return 0xFF;
                }
        } else {                                /* client */
@@ -1156,7 +1170,7 @@ static unsigned char sms_handleincoming (sms_t * h)
                                return 0xFF;                /* duh! */
                        }
                } else {
-                       ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
+                       ast_log(LOG_WARNING, "Unknown message type %02hhX\n", h->imsg[2]);
                        return 0xFF;
                }
        }
@@ -1238,7 +1252,7 @@ static char *sms_hexdump(unsigned char buf[], int size, char *s /* destination *
        int f;
 
        for (p = s, f = 0; f < size && f < MAX_DEBUG_LEN; f++, p += 3) {
-               sprintf(p, "%02X ", (unsigned char)buf[f]);
+               sprintf(p, "%02hhX ", (unsigned char)buf[f]);
        }
        return(s);
 }
@@ -1264,9 +1278,9 @@ static int sms_handleincoming_proto2(sms_t *h)
                msgsz += (h->imsg[f++] * 256);
                switch (msg) {
                case 0x13:                          /* Body */
-                       ast_verb(3, "SMS-P2 Body#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
-                       if (msgsz >= sizeof(h->imsg)) {
-                               msgsz = sizeof(h->imsg) - 1;
+                       ast_verb(3, "SMS-P2 Body#%02X=[%.*s]\n", (unsigned)msg, msgsz, &h->imsg[f]);
+                       if (msgsz >= sizeof(h->ud)) {
+                               msgsz = sizeof(h->ud) - 1;
                        }
                        for (i = 0; i < msgsz; i++) {
                                h->ud[i] = h->imsg[f + i];
@@ -1282,27 +1296,27 @@ static int sms_handleincoming_proto2(sms_t *h)
                        tm.tm_min = ( (h->imsg[f + 6] * 10) + h->imsg[f + 7] );
                        tm.tm_sec = 0;
                        h->scts = ast_mktime(&tm, NULL);
-                       ast_verb(3, "SMS-P2 Date#%02X=%02d/%02d %02d:%02d\n", msg, tm.tm_mday, tm.tm_mon + 1, tm.tm_hour, tm.tm_min);
+                       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);
                        break;
                case 0x15:                          /* Calling line (from SMSC) */
                        if (msgsz >= 20) {
                                msgsz = 20 - 1;
                        }
-                       ast_verb(3, "SMS-P2 Origin#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
+                       ast_verb(3, "SMS-P2 Origin#%02X=[%.*s]\n", (unsigned)msg, msgsz, &h->imsg[f]);
                        ast_copy_string(h->oa, (char *)(&h->imsg[f]), msgsz + 1);
                        break;
                case 0x18:                          /* Destination(from TE/phone) */
                        if (msgsz >= 20) {
                                msgsz = 20 - 1;
                        }
-                       ast_verb(3, "SMS-P2 Destination#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]);
+                       ast_verb(3, "SMS-P2 Destination#%02X=[%.*s]\n", (unsigned)msg, msgsz, &h->imsg[f]);
                        ast_copy_string(h->da, (char *)(&h->imsg[f]), msgsz + 1);
                        break;
                case 0x1C:                          /* Notify */
-                       ast_verb(3, "SMS-P2 Notify#%02X=%s\n", msg, sms_hexdump(&h->imsg[f], 3, debug_buf));
+                       ast_verb(3, "SMS-P2 Notify#%02X=%s\n", (unsigned)msg, sms_hexdump(&h->imsg[f], 3, debug_buf));
                        break;
                default:
-                       ast_verb(3, "SMS-P2 Par#%02X [%d]: %s\n", msg, msgsz, sms_hexdump(&h->imsg[f], msgsz, debug_buf));
+                       ast_verb(3, "SMS-P2 Par#%02X [%d]: %s\n", (unsigned)msg, msgsz, sms_hexdump(&h->imsg[f], msgsz, debug_buf));
                        break;
                }
                f+=msgsz;                           /* Skip to next */
@@ -1369,7 +1383,7 @@ static void sms_messagerx2(sms_t * h)
                        h->hangup = 1;                  /* hangup */
                } else {
                        /* XXX depending on what we are.. */
-                       ast_log(LOG_NOTICE, "SMS_SUBMIT or SMS_DELIVERY");
+                       ast_log(LOG_NOTICE, "SMS_SUBMIT or SMS_DELIVERY\n");
                        sms_nextoutgoing (h);
                }
                break;
@@ -1426,7 +1440,7 @@ static void sms_compose1(sms_t *h, int more)
 
 /*! \brief find and fill in next message, or send a REL if none waiting */
 static void sms_nextoutgoing (sms_t * h)
-{        
+{
        char fn[100 + NAME_MAX] = "";
        DIR *d;
        char more = 0;
@@ -1460,6 +1474,7 @@ static void sms_nextoutgoing (sms_t * h)
                } else {
                        h->omsg[0] = 0x94;              /* SMS_REL */
                        h->omsg[1] = 0;
+                       h->sent_rel = 1;
                }
        }
        sms_messagetx(h);
@@ -1475,7 +1490,7 @@ static void sms_debug (int dir, sms_t *h)
        int n = (dir == DIR_RX) ? h->ibytep : msg[1] + 2;
        int q = 0;
        while (q < n && q < 30) {
-               sprintf(p, " %02X", msg[q++]);
+               sprintf(p, " %02hhX", msg[q++]);
                p += 3;
        }
        if (q < n) {
@@ -1592,7 +1607,7 @@ static int sms_generate(struct ast_channel *chan, void *data, int len, int sampl
 #define MAXSAMPLES (800)
        output_t *buf;
        sms_t *h = data;
-       int i;
+       int i, res;
 
        if (samples > MAXSAMPLES) {
                ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n",
@@ -1600,10 +1615,10 @@ static int sms_generate(struct ast_channel *chan, void *data, int len, int sampl
                samples = MAXSAMPLES;
        }
        len = samples * sizeof(*buf) + AST_FRIENDLY_OFFSET;
-       buf = alloca(len);
+       buf = ast_alloca(len);
 
        f.frametype = AST_FRAME_VOICE;
-       f.subclass = __OUT_FMT;
+       f.subclass.format = __OUT_FMT;
        f.datalen = samples * sizeof(*buf);
        f.offset = AST_FRIENDLY_OFFSET;
        f.mallocd = 0;
@@ -1653,8 +1668,10 @@ static int sms_generate(struct ast_channel *chan, void *data, int len, int sampl
                        }
                }
        }
-       if (ast_write(chan, &f) < 0) {
-               ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
+       res = ast_write(chan, &f);
+       ast_frfree(&f);
+       if (res < 0) {
+               ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
                return -1;
        }
        return 0;
@@ -1779,7 +1796,7 @@ static void sms_process(sms_t * h, int samples, signed short *data)
                        h->iphasep = 0;
                }
                if (bit && h->ibitc == 200) {       /* sync, restart message */
-                       /* Protocol 2: empty connnection ready (I am master) */
+                       /* Protocol 2: empty connection ready (I am master) */
                        if (h->framenumber < 0 && h->ibytec >= 160 && !memcmp(h->imsg, "UUUUUUUUUUUUUUUUUUUU", 20)) {
                                h->framenumber = 1;
                                ast_verb(3, "SMS protocol 2 detected\n");
@@ -1797,22 +1814,26 @@ static void sms_process(sms_t * h, int samples, signed short *data)
                                h->iphasep -= 80;
                                if (h->ibitn++ == 9) {      /* end of byte */
                                        if (!bit) {             /* bad stop bit */
-                                               ast_log(LOG_NOTICE, "bad stop bit");
-                                               h->ierr = 0xFF;     /* unknown error */
+                                               if (h->sent_rel) {
+                                                       h->hangup = 1;
+                                               } else {
+                                                       ast_log(LOG_NOTICE, "Bad stop bit\n");
+                                                       h->ierr = 0xFF;     /* unknown error */
+                                               }
                                        } else {
                                                if (h->ibytep < sizeof(h->imsg)) {
                                                        h->imsg[h->ibytep] = h->ibytev;
                                                        h->ibytec += h->ibytev;
                                                        h->ibytep++;
                                                } else if (h->ibytep == sizeof(h->imsg)) {
-                                                       ast_log(LOG_NOTICE, "msg too large");
+                                                       ast_log(LOG_NOTICE, "msg too large\n");
                                                        h->ierr = 2;    /* bad message length */
                                                }
                                                if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
                                                        if (!h->ibytec) {
                                                                sms_messagerx(h);
                                                        } else {
-                                                               ast_log(LOG_NOTICE, "bad checksum");
+                                                               ast_log(LOG_NOTICE, "bad checksum\n");
                                                                h->ierr = 1; /* bad checksum */
                                                        }
                                                }
@@ -1832,19 +1853,20 @@ static void sms_process(sms_t * h, int samples, signed short *data)
  *     - AST_APP_OPTIONS() to drive the parsing routine
  *     - in the function, AST_DECLARE_APP_ARGS(...) for the arguments.
  */
-enum {
+enum sms_flags {
        OPTION_BE_SMSC  = (1 << 0),             /* act as sms center */
        OPTION_ANSWER   = (1 << 1),             /* answer on incoming calls */
        OPTION_TWO      = (1 << 2),                 /* Use Protocol Two */
        OPTION_PAUSE    = (1 << 3),             /* pause before sending data, in ms */
        OPTION_SRR      = (1 << 4),                 /* set srr */
        OPTION_DCS      = (1 << 5),                 /* set dcs */
-} sms_flags;
+       OPTIONS_NO_LOG  = (1 << 6),             /* Don't log SMS content */
+};
 
-enum {
+enum sms_opt_args {
        OPTION_ARG_PAUSE = 0,
        OPTION_ARG_ARRAY_SIZE
-} sms_opt_args;
+};
 
 AST_APP_OPTIONS(sms_options, {
        AST_APP_OPTION('s', OPTION_BE_SMSC),
@@ -1852,15 +1874,16 @@ AST_APP_OPTIONS(sms_options, {
        AST_APP_OPTION('t', OPTION_TWO),
        AST_APP_OPTION('r', OPTION_SRR),
        AST_APP_OPTION('o', OPTION_DCS),
+       AST_APP_OPTION('n', OPTIONS_NO_LOG),
        AST_APP_OPTION_ARG('p', OPTION_PAUSE, OPTION_ARG_PAUSE),
        } );
 
-static int sms_exec(struct ast_channel *chan, void *data)
+static int sms_exec(struct ast_channel *chan, const char *data)
 {
        int res = -1;
        sms_t h = { 0 };
        /* argument parsing support */
-       struct ast_flags flags;
+       struct ast_flags flags = { 0 };
        char *parse, *sms_opts[OPTION_ARG_ARRAY_SIZE] = { 0, };
        char *p;
        AST_DECLARE_APP_ARGS(sms_args,
@@ -1881,7 +1904,7 @@ static int sms_exec(struct ast_channel *chan, void *data)
                ast_app_parse_options(sms_options, &flags, sms_opts, sms_args.options);
        }
 
-       ast_verb(1, "sms argc %d queue <%s> opts <%s> addr <%s> body <%s>\n",
+       ast_verb(1, "sms argc %u queue <%s> opts <%s> addr <%s> body <%s>\n",
                sms_args.argc, S_OR(sms_args.queue, ""),
                S_OR(sms_args.options, ""),
                S_OR(sms_args.addr, ""),
@@ -1890,8 +1913,9 @@ static int sms_exec(struct ast_channel *chan, void *data)
        h.ipc0 = h.ipc1 = 20;                   /* phase for cosine */
        h.dcs = 0xF1;                           /* default */
 
-       if (chan->cid.cid_num)
-               ast_copy_string(h.cli, chan->cid.cid_num, sizeof(h.cli));
+       ast_copy_string(h.cli,
+               S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
+               sizeof(h.cli));
 
        if (ast_strlen_zero(sms_args.queue)) {
                ast_log(LOG_ERROR, "Requires queue name\n");
@@ -1911,6 +1935,7 @@ static int sms_exec(struct ast_channel *chan, void *data)
 
        h.smsc = ast_test_flag(&flags, OPTION_BE_SMSC);
        h.protocol = ast_test_flag(&flags, OPTION_TWO) ? 2 : 1;
+       h.nolog = ast_test_flag(&flags, OPTIONS_NO_LOG) ? 1 : 0;
        if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE])) {
                h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]);
        }
@@ -1927,7 +1952,7 @@ static int sms_exec(struct ast_channel *chan, void *data)
        if (ast_test_flag(&flags, OPTION_DCS)) {
                h.dcs = 1;
        }
-#if 0  
+#if 0
                case '1':
                case '2':
                case '3':
@@ -1982,8 +2007,8 @@ static int sms_exec(struct ast_channel *chan, void *data)
                res = h.err;
                goto done;
        }
-       
-       if (chan->_state != AST_STATE_UP) {             /* make sure channel is answered before any TX */
+
+       if (ast_channel_state(chan) != AST_STATE_UP) {          /* make sure channel is answered before any TX */
                ast_answer(chan);
        }
 
@@ -2002,7 +2027,7 @@ static int sms_exec(struct ast_channel *chan, void *data)
 
        res = ast_set_write_format(chan, __OUT_FMT);
        if (res >= 0) {
-               res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
+               res = ast_set_read_format(chan, ast_format_slin);
        }
        if (res < 0) {
                ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n");
@@ -2010,7 +2035,7 @@ static int sms_exec(struct ast_channel *chan, void *data)
        }
 
        if ( (res = ast_activate_generator(chan, &smsgen, &h)) < 0) {
-               ast_log(LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
+               ast_log(LOG_ERROR, "Failed to activate generator on '%s'\n", ast_channel_name(chan));
                goto done;
        }
 
@@ -2039,6 +2064,12 @@ static int sms_exec(struct ast_channel *chan, void *data)
        }
        res = h.err;                            /* XXX */
 
+       /*
+        * The SMS generator data is on the stack.  We _MUST_ make sure the generator
+        * is stopped before returning from this function.
+        */
+       ast_deactivate_generator(chan);
+
        sms_log(&h, '?');                       /* log incomplete message */
 done:
        return (res);
@@ -2061,4 +2092,4 @@ static int load_module(void)
        return ast_register_application_xml(app, sms_exec);
 }
 
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SMS/PSTN handler");
+AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "SMS/PSTN handler");