atd

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/atd
Log | Files | Refs

commit d1bcbbf6707b357634f155b46be256bb2962db60
parent 75f83574291a3cd792a0035a8e150ebc7cc456f1
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Wed,  4 Aug 2021 19:04:47 -0500

atd: add submit command to send sms messages

This only works when the tty is clean on startup for some reason,
a later commit will fix this.

Diffstat:
Matd.c | 150++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Matd.h | 6++++++
2 files changed, 128 insertions(+), 28 deletions(-)

diff --git a/atd.c b/atd.c @@ -48,6 +48,7 @@ struct command_args cmddata[] = { [CMD_DIAL] = { ATD, { TYPE_STRING, TYPE_NONE} }, [CMD_ANSWER] = { ATA, { TYPE_NONE} }, [CMD_HANGUP] = { ATH, { TYPE_NONE} }, + [CMD_SUBMIT] = { ATCMGS, { TYPE_NONE} }, }; char *atcmds[] = { @@ -55,6 +56,7 @@ char *atcmds[] = { [ATA] = "ATA\r", [ATH] = "ATH\r", [CLCC] = "AT+CLCC\r", + [ATCMGS] = "AT+CMGS=%d\r", // requires extra PDU data to be sent }; char *argv0; @@ -86,6 +88,7 @@ ssize_t cmdadd(int index) { struct command cmd = {index, CMD_NONE, NULL}; char *ptr = fdbufs[index].out; size_t count = 0; + char *num, *msg, *raw; if (cmdq.count == QUEUE_SIZE) return -1; @@ -111,6 +114,38 @@ ssize_t cmdadd(int index) { calld = index; goto end; break; + case CMD_SUBMIT: + count = dec_str(ptr, &num); + if (count == -1) + return -1; + + ptr += count; + count = dec_str(ptr, &msg); + if (count == -1) + return -1; + + count = encode_pdu(NULL, num, msg); + raw = malloc(count); + if (!raw) + return -1; + + encode_pdu(raw, num, msg); + free(num); + free(msg); + + cmd.data.submit.len = count; + cmd.data.submit.pdu = malloc(2*count + 1); + if (!cmd.data.submit.pdu) + return -1; + + for (int i = 0; i < count; i++) { + htoa(&cmd.data.submit.pdu[2*i], raw[i]); + } + cmd.data.submit.pdu[2*count] = 0; + free(raw); + + fprintf(stderr, "received submit to number %s: %s\n", num, cmd.data.submit.pdu); + break; default: fprintf(stderr, "got code: %d\n", cmd.op); return -2; @@ -124,6 +159,34 @@ end: return count + 1; } +ssize_t +fdbuf_write(int idx) +{ + int wr = write(fds[idx].fd, &fdbufs[idx].in, fdbufs[idx].inlen); + if (wr == -1) + return -1; + + fdbufs[idx].inlen -= wr; + fdbufs[idx].inptr -= wr; + memmove(fdbufs[idx].in, fdbufs[idx].in + wr, BUFSIZE - wr); + + return wr; +} + +ssize_t +fdbuf_read(int idx) +{ + int r = read(fds[idx].fd, fdbufs[idx].outptr, BUFSIZE - fdbufs[idx].outlen); + if (r == -1) + return -1; + + fdbufs[idx].outlen += r; + fdbufs[idx].outptr += r; + + return r; +} + + int send_status(int fd, enum status status) { @@ -233,6 +296,47 @@ memspn(const char *mem, const char *valid, int n) } int +atcmgs2() +{ + char *loc; + int ret; + size_t before, after; + + /* this shouldn't be possible */ + if (!(loc = memchr(fdbufs[BACKEND].out, '>', fdbufs[BACKEND].outlen))) { + fprintf(stderr, "%s: prompt not found\n", __func__); + // TODO send \x1a + return -1; + } + + before = loc - fdbufs[BACKEND].out; + after = fdbufs[BACKEND].out + fdbufs[BACKEND].outlen - loc; + + ret = snprintf(fdbufs[BACKEND].in, BUFSIZE, "%s\x1a", currentcmd.data.submit.pdu); + + fdbufs[BACKEND].inptr = fdbufs[BACKEND].in; + if (ret > BUFSIZE) { + fdbufs[BACKEND].in[0] = '\x1a'; // \x1a will terminate read for a PDU + fdbufs[BACKEND].inlen = 1; + fprintf(stderr, "%s: PDU too long!\n", __func__); + } else { + fdbufs[BACKEND].inlen = ret; + } + + ret = fdbuf_write(BACKEND); + + // the prompt will be "> ", so remove the prompt from the buffer + memmove(fdbufs[BACKEND].out + before, loc + 2, after); + fdbufs[BACKEND].outlen -= 2; + fdbufs[BACKEND].outptr -= 2; + + free(currentcmd.data.submit.pdu); + currentcmd.data.submit.pdu = NULL; + + return ret; +} + +int nextline() { fprintf(stderr, "%s start\n", __func__); @@ -262,6 +366,15 @@ handle_resp(int fd) char *start = fdbufs[BACKEND].out; enum status status = 0; + // this must be put before nextline, because a prompt doesn't end + // in a newline, so nextline won't interpret it as a line + if (currentatcmd == ATCMGS && currentcmd.data.submit.pdu) { + if (atcmgs2() < 0) + return -1; + + return 2; + } + if (nextline() < 0) return 0; @@ -319,33 +432,6 @@ handle_resp(int fd) return curline_len; } -ssize_t -fdbuf_write(int idx) -{ - int wr = write(fds[idx].fd, &fdbufs[idx].in, fdbufs[idx].inlen); - if (wr == -1) - return -1; - - fdbufs[idx].inlen -= wr; - fdbufs[idx].inptr -= wr; - memmove(fdbufs[idx].in, fdbufs[idx].in + wr, BUFSIZE - wr); - - return wr; -} - -ssize_t -fdbuf_read(int idx) -{ - int r = read(fds[idx].fd, fdbufs[idx].outptr, BUFSIZE - fdbufs[idx].outlen); - if (r == -1) - return -1; - - fdbufs[idx].outlen += r; - fdbufs[idx].outptr += r; - - return r; -} - bool send_command(int idx, enum atcmd atcmd, union atdata atdata) { @@ -354,6 +440,8 @@ send_command(int idx, enum atcmd atcmd, union atdata atdata) if (atcmd == ATD) { ret = snprintf(fdbufs[idx].in, BUFSIZE, atcmds[atcmd], atdata.dial.num); free(atdata.dial.num); + } else if (atcmd == ATCMGS) { + ret = snprintf(fdbufs[idx].in, BUFSIZE, atcmds[atcmd], atdata.submit.len); } else { ret = snprintf(fdbufs[idx].in, BUFSIZE, atcmds[atcmd]); } @@ -369,6 +457,7 @@ send_command(int idx, enum atcmd atcmd, union atdata atdata) warn("failed to write to backend!"); return false; } + active_command = true; currentatcmd = atcmd; return true; @@ -568,7 +657,12 @@ int main(int argc, char *argv[]) } } - while (handle_resp(fds[cmd.index].fd)); + while ((ret = handle_resp(fds[cmd.index].fd)) != 0) { + if (ret < 0) { + fprintf(stderr, "atd: failure in atcmgs\n"); + goto error; + } + } /* send next command to modem */ if (fds[BACKEND].revents & POLLOUT) { diff --git a/atd.h b/atd.h @@ -14,6 +14,7 @@ enum ops { CMD_ANSWER, CMD_HANGUP, CMD_CALL_EVENTS, + CMD_SUBMIT, }; enum callstatus { @@ -38,12 +39,17 @@ enum atcmd { ATA, ATH, CLCC, + ATCMGS, }; union atdata { struct { char *num; } dial; + struct { + char len; + char *pdu; + } submit; }; struct command {