From a145b3afa71aa7a8e2a06bbb11c41daba1b1eb9c Mon Sep 17 00:00:00 2001 From: ketmar Date: Wed, 7 Nov 2012 07:34:49 +0200 Subject: [PATCH] new sms code --- src/main.c | 152 +++++++++++++++++++++++++++++++----------------------------- src/pnpty.c | 99 +++++++++++++++++++++++++++++++++++++++ src/pnpty.h | 2 + 3 files changed, 179 insertions(+), 74 deletions(-) diff --git a/src/main.c b/src/main.c index c844f45..e55e8eb 100644 --- a/src/main.c +++ b/src/main.c @@ -9,6 +9,7 @@ * http://sam.zoy.org/wtfpl/COPYING for more details. */ #include +#include #include #include #include @@ -247,51 +248,64 @@ static int cmdCommand (PnPty *pd, int argc, char *argv[]) { } +static char *str2hex (const char *encoding, const char *str) { + iconv_t cd; + char *outs = NULL, *ibuf, *obuf, *ress; + size_t il, ol, ool; + // + if (str == NULL) return NULL; + if (encoding == NULL) encoding = "KOI8-U"; + if ((cd = iconv_open("UCS-2BE", encoding)) == (iconv_t)-1) return NULL; // invalid encoding + ibuf = (char *)str; + il = strlen(str); + outs = malloc(il*2+8); + obuf = outs; + ool = ol = il*2+2; + il = iconv(cd, &ibuf, &il, &obuf, &ol); + if (il == (size_t)-1) goto error; + //if (reslen) *reslen = ool-ol; + iconv_close(cd); + if ((ress = calloc(ool-ol+1, 2)) == NULL) { free(outs); return NULL; } + for (size_t f = 0; f < ool-ol; ++f) sprintf(ress+f*2, "%02X", (unsigned char)(outs[f])); + free(outs); + return ress; +error: + iconv_close(cd); + free(outs); + return NULL; +} + + +enum { + MAXSMSLEN = 160-6 // 6 octets for UDHI +}; + + static int cmdSMS (PnPty *pd, int argc, char *argv[]) { - char *res = NULL, *mbuf = NULL, *d; - int mlen; + char *res = NULL; + int msglen, msgmax; + char *hexstr; + int msgid = 42; // if (!argv[2][0] || !argv[1][0]) { fprintf(stderr, "BAD: invalid args\n"); return 1; } // - mlen = strlen(argv[2]); - // - // check if we have only latin chars in message - // we can use iconv eventually, but i'm soooo lazy... - for (char *p = argv[2]; *p; ++p) { - if (*p == '\t') *p = ' '; - else if (*p == '"') *p = '\''; - else if (*p != '\n') { - if (*p < 32 || *p > 126) { - fprintf(stderr, "BAD: invalid chars in SMS message\n"); - return 1; - } - } - } - // message should be unicode, hex-encoded (4 digits per char, upcase) - if ((mbuf = malloc(mlen*4+8)) == NULL) goto error; - // - d = mbuf; - for (const char *p = argv[2]; *p; ++p) { - sprintf(d, "%04X", (unsigned char)(*p)); - d += 4; + if ((hexstr = str2hex(NULL, argv[2])) == NULL) { + fprintf(stderr, "BAD: invalid text\n"); + return 1; } - // - // 0: PDU mode; 1: text mode - res = pnptySendCommand(pd, "AT+CMGF=0"); - if (res == NULL || res[0] == 1) { - fprintf(stderr, "ERROR: CMGF\n"); - goto error; + msglen = strlen(hexstr)/2; + msgmax = (msglen+MAXSMSLEN-1)/MAXSMSLEN; + if (msgmax > 250) { + free(hexstr); + fprintf(stderr, "BAD: text too long\n"); + return 1; } - free(res); // res = pnptySendCommand(pd, "AT+CSCS=\"HEX\""); - if (res == NULL || res[0] == 1) { - fprintf(stderr, "ERROR: CSCS\n"); - goto error; - } + if (res == NULL || res[0] == 1) { free(hexstr); fprintf(stderr, "ERROR: CSCS\n"); goto error; } free(res); // // for delivery report to work the program should be listening until the message is delivered: @@ -308,51 +322,41 @@ static int cmdSMS (PnPty *pd, int argc, char *argv[]) { // // 17: options (32 -- with delivery report?) // 167: validity - // 8: dcs (24 for flash SMS) - res = pnptySendCommand(pd, "AT+CSMP=%d,%d,0,%d", 81, 167, 8); - if (res == NULL || res[0] == 1) { - fprintf(stderr, "ERROR: CSMP\n"); - goto error; - } - free(res); - // - // number and text - //fprintf(stderr, "number: [%s] text: [%s]\n", argv[1], mbuf); - // - //res = pnptySendCommand(pd, "AT+CMGS=\"%s\"\r%s", argv[1], mbuf); - // CMGS replies with "> " - char xbuf[1024]; - // - sprintf(xbuf, "AT+CMGS=\"%s\"\r050003000101", argv[1]); - // - //res = pnptySendCommand(pd, "%s%s\x1a", xbuf, mbuf); - res = pnptySendCommand(pd, "%s%s\x1a", xbuf, - "041A0430043A002004430442043E043C043" - "804420435043B044C043D043E0020043F0440043804340443043C044B043204300442044C002" - "004420435043A0441044200200434043B044F0020043F04400438043C04350440043000200434" - "043B0438043D043D043E0433043E00200441043A043B04350435043D043D043E0433043E002" - "00441"); - if (res == NULL || res[0] == 1) { - fprintf(stderr, "ERROR: CMGS\n"); - if (res != NULL) fprintf(stderr, "%s\n", res+1); - goto error; + // 8: dcs (24 for flash SMS) -- Data Coding Scheme + // see http://www.dreamfabric.com/sms/dcs.html + // 00 0 0 10 00: normal USC + // 00 0 1 10 00: alert + for (int f = 0; f < msgmax; ++f) { + char msg[400]; + const char *mpos; + int mlen; + // + // make UDHI + memset(msg, 0, sizeof(msg)); + sprintf(msg, "050003%02X%02X%02X", msgid, msgmax, f+1); + // append text part + mpos = hexstr+f*MAXSMSLEN*2; + mlen = strlen(mpos); + if (mlen > MAXSMSLEN) mlen = MAXSMSLEN; + memcpy(msg+strlen(msg), mpos, mlen); + // + // 0: PDU mode; 1: text mode + res = pnptySendCommand(pd, "AT+CMGF=1"); + if (res == NULL || res[0] == 1) { free(hexstr); fprintf(stderr, "ERROR: CMGF\n"); goto error; } + free(res); + // + res = pnptySendCommand(pd, "AT+CSMP=%d,%d,0,%d", 81, 167, 8); + if (res == NULL || res[0] == 1) { fprintf(stderr, "ERROR: CSMP\n"); goto error; } + free(res); + // + if (pnptySendSMSCommand(pd, argv[0], msg) < 0) { fprintf(stderr, "ERROR: SMS\n"); goto error; } } - fprintf(stderr, "0: [%s]\n", res); - free(res); // - /* - res = pnptySendCommand(pd, "%s", mbuf); - if (res == NULL || res[0] == 1) goto error; - fprintf(stderr, "1: [%s]\n", res); - free(res); - */ - // - if (res != NULL) free(res); - if (mbuf != NULL) free(mbuf); + free(hexstr); return 0; error: if (res != NULL) free(res); - if (mbuf != NULL) free(mbuf); + free(hexstr); fprintf(stderr, "BAD: some error occured.\n"); return 1; // error } diff --git a/src/pnpty.c b/src/pnpty.c index fb2bde4..ce085c8 100644 --- a/src/pnpty.c +++ b/src/pnpty.c @@ -327,3 +327,102 @@ __attribute__((format(printf,2,3))) char *pnptySendCommand (PnPty *pt, const cha // return res; } + + +int pnptySendSMSCommand (PnPty *pt, const char *number, const char *str) { + if (pt != NULL && pt->fd >= 0 && pt->pid > 0 && number != NULL && number[0] && str != NULL && str[0]) { + //static const char *eol = "\r"; + static const char *cmd0 = "AT+CMGS=\""; + static const char *cmd1 = "\"\r"; + static const char *ctrlz = "\x1a"; + // + int waitcnt = 0; + char repbuf[64]; + int reppos; + int sz; + // + if (setNonBlock(pt->fd, 0) < 0) return -1; + if ((sz = write(pt->fd, cmd0, strlen(cmd0))) < 0) return -1; + if ((sz = write(pt->fd, number, strlen(number))) < 0) return -1; + if ((sz = write(pt->fd, cmd1, strlen(cmd1))) < 0) return -1; + // + // now we should receive "> " or some shit (?) + if (setNonBlock(pt->fd, 1) < 0) return -1; + // + reppos = 0; + while (reppos < 2) { + int rd; + // + if ((rd = read(pt->fd, repbuf+reppos, 1)) <= 0) { + const char *msg; + // + if (errno == EINTR) continue; + if (errno == EAGAIN) { + if (waitcnt++ < TIMEOUT) { usleep(1000); continue; } + } + // + msg = strerror(errno); + fprintf(stderr, "rd: %d; [%s]\n", rd, msg); + fprintf(stderr, "ERROR!\n"); + return -1; + } + ++reppos; + } + // + if (repbuf[0] != '>' || repbuf[1] != ' ') { + // invalid answer; read till EOL and return error + for (;;) { + int rd; + // + if ((rd = read(pt->fd, repbuf, 1)) <= 0) { + const char *msg; + // + if (errno == EINTR) continue; + if (errno == EAGAIN) { + if (waitcnt++ < TIMEOUT) { usleep(1000); continue; } + } + // + msg = strerror(errno); + fprintf(stderr, "rd: %d; [%s]\n", rd, msg); + fprintf(stderr, "ERROR!\n"); + return -1; + } + if (repbuf[0] == '\n') return -1; // done + } + } + // now send text + if (setNonBlock(pt->fd, 0) < 0) return -1; + if ((sz = write(pt->fd, str, strlen(str))) < 0) return -1; + if ((sz = write(pt->fd, ctrlz, strlen(ctrlz))) < 0) return -1; + // now read 'OK' + reppos = 0; + for (;;) { + int rd; + // + if ((rd = read(pt->fd, repbuf+reppos, 1)) <= 0) { + const char *msg; + // + if (errno == EINTR) continue; + if (errno == EAGAIN) { + if (waitcnt++ < TIMEOUT) { usleep(1000); continue; } + } + // + msg = strerror(errno); + fprintf(stderr, "rd: %d; [%s]\n", rd, msg); + fprintf(stderr, "ERROR!\n"); + return -1; + } + if (reppos == 0 && (repbuf[0] == '\n' || repbuf[0] == '\r')) continue; // skip all newlines + if (repbuf[reppos] == '\n') { + repbuf[reppos+1] = 0; + fprintf(stderr, "SMSREP: %s", repbuf); + break; + } + if (reppos < sizeof(repbuf)-2) ++reppos; + } + // + return 0; + } + // + return -2; +} diff --git a/src/pnpty.h b/src/pnpty.h index 473bf96..57439c0 100644 --- a/src/pnpty.h +++ b/src/pnpty.h @@ -31,6 +31,8 @@ extern void pnptyFree (PnPty *pt); extern char *pnptySendCommandVA (PnPty *pt, const char *fmt, va_list args); extern char *pnptySendCommand (PnPty *pt, const char *fmt, ...) __attribute__((format(printf,2,3))); +extern int pnptySendSMSCommand (PnPty *pt, const char *number, const char *str); + #ifdef __cplusplus } -- 2.11.4.GIT