From 14fb44b17123b27e562379f51b75ee889982688d Mon Sep 17 00:00:00 2001 From: James Maki Date: Fri, 23 Apr 2010 11:58:20 -0500 Subject: initial commit --- src/sms_send.c | 392 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 src/sms_send.c (limited to 'src/sms_send.c') diff --git a/src/sms_send.c b/src/sms_send.c new file mode 100644 index 0000000..3cae12e --- /dev/null +++ b/src/sms_send.c @@ -0,0 +1,392 @@ +/* + * SMS Send + * + * Copyright (C) 2010 by Multi-Tech Systems + * + * Author: James Maki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "global.h" +#include "utils.h" +#include "cmd_options.h" +#include "sms_utils.h" +#include "atcmd.h" +#include "sms_send.h" +#include "pdu_encode.h" +#include "phonebook.h" + +struct send_options { + char *file; + int alphabet; + const char *smsc_addr; + int cmgw_first; +}; + +static int auto_fill_smsc(int fd, struct pdu_addr *addr) +{ + char buf[ATCMD_LINE_SIZE]; + char *save; + char *token; + char *addr_str; + int type; + int tmp; + + atcmd_writeline(fd, "AT+CSCA?"); + tmp = atcmd_expect_line(fd, buf, sizeof(buf), "+CSCA: "); + if (tmp <= 0) { + if (*buf) { + log_debug("expected +CPMS: but got %s", buf); + } else { + log_debug("expected +CPMS"); + } + return -1; + } + + save = buf; + token = atcmd_response_brk(&save); + if (!token) { + log_debug("response tokenizing failed"); + return -1; + } + + token = atcmd_value_tok(&save); + if (!token) { + log_debug("addr token not present"); + return -1; + } + addr_str = token; + + token = atcmd_value_tok(&save); + if (!token) { + log_debug("addr-len token not present"); + return -1; + } + type = atoi(token); + + tmp = atcmd_expect_line(fd, buf, sizeof(buf), "OK"); + if (tmp <= 0) { + if (*buf) { + log_debug("expected OK but got %s", buf); + } else { + log_debug("expected OK"); + } + return -1; + } + + return pdu_addr_fill(addr, addr_str, type); +} + +static int fill_addr(struct phonebook_list_info *list_info, + struct pdu_addr *addr, const char *addr_str) +{ + struct phonebook_entry *entry; + int type; + int tmp; + + type = pdu_addr_type_infer(addr_str); + if (type != SMS_ADDR_TEXT) { + goto fill; + } + + log_debug("text addr found: searching phonebook for match"); + + if (Global.core.interactive) { + entry = phonebook_search_names_i(&list_info->entry_list, addr_str); + if (!entry) { + return -1; + } + } else { + entry = phonebook_find_by_name(&list_info->entry_list, addr_str); + if (!entry) { + log_notice("%s not found in phonebook", addr_str); + return -1; + } + } + addr_str = entry->addr; + +fill: + + tmp = pdu_addr_fill(addr, addr_str, SMS_ADDR_UNSPEC); + if (tmp < 0) { + log_debug("pdu fill failed with addr %s", addr_str); + return -1; + } + + return 0; +} + +static int fill_user_data(struct send_options *options, struct pdu_info *pdu) +{ + int fd; + int tmp; + + if (options->file) { + fd = open(options->file, O_RDONLY); + if (fd < 0) { + log_error("failed to open %s for reading", options->file); + return -1; + } + } else if (Global.core.interactive && Global.core.edit_file && Global.core.editor) { + tmp = systemf("%s %s", Global.core.editor, Global.core.edit_file); + if (tmp < 0 || !WIFEXITED(tmp) || WEXITSTATUS(tmp)) { + log_error("edit failed"); + return -1; + } + + char *path = shell_path_expand(Global.core.edit_file); + if (!path) { + return -1; + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + log_error("failed to open %s for reading", path); + free(path); + return -1; + } + free(path); + } else { + fd = fileno(stdin); + } + + tmp = pdu_user_data_read(fd, pdu); + + close(fd); + + if (tmp < 0) { + log_error("read user data failed"); + return -1; + } + + return 0; +} + +static int do_send(int fd, struct send_options *options, int argc, char **argv) +{ + char buf[PDU_BUFFER_SIZE]; + struct pdu_info pdu; + struct phonebook_list_info list_info; + int failed = 0; + int mem_index = 0; + int tmp; + int i; + + if (argc < 1) { + log_error("at least one recipient addr is required"); + return false; + } + + memset(&pdu, 0, sizeof(pdu)); + + pdu.type.msg_type = PDU_MTI_SUBMIT; + pdu.type.validity_period_format = PDU_VPF_RELATIVE; + pdu.validity_period = PDU_VPF_RELATIVE_2DAYS; + pdu.data_coding.general.alphabet = options->alphabet; + + if (options->smsc_addr) { + tmp = pdu_addr_fill(&pdu.smsc_addr, options->smsc_addr, SMS_ADDR_UNSPEC); + if (tmp < 0) { + return false; + } + } + + tmp = fill_user_data(options, &pdu); + if (tmp < 0) { + log_error("read user data failed"); + return false; + } + + if (Global.core.verbose) { + printf("preparing for send...\n"); + } + + tmp = atcmd_plus_cmgf_write(fd, SMS_PDU_MODE); + if (tmp < 0) { + log_error("setting pdu mode failed"); + return false; + } + + if (options->cmgw_first) { + tmp = pdu_encode(buf, sizeof(buf), &pdu); + if (tmp < 0) { + log_error("pdu encode failed"); + return false; + } + + if (Global.core.verbose) { + printf("writing message to memory\n"); + } + + mem_index = atcmd_plus_cmgw_write(fd, buf, pdu.msg_len); + if (mem_index < 0) { + log_error("write message to memory failed"); + return false; + } + } + + memset(&list_info, 0, sizeof(list_info)); + + if (Global.core.pb_store) { + strncpy(list_info.store_select, Global.core.pb_store, STORE_NAME_LEN); + } + tmp = phonebook_list_get(fd, &list_info); + if (tmp < 0) { + log_error("failed to get phonebook list"); + return false; + } + + for (i = 0; i < argc; i++) { + if (Global.core.verbose) { + printf("sending message to %s\n", argv[i]); + } + + tmp = fill_addr(&list_info, &pdu.addr, argv[i]); + if (tmp < 0) { + printf("sending message to %s failed\n", argv[i]); + failed++; + continue; + } + + if (options->cmgw_first) { + tmp = atcmd_plus_cmss_write(fd, mem_index, + pdu.addr.addr, SMS_ADDR_UNSPEC); + if (tmp < 0) { + printf("sending message to %s failed\n", argv[i]); + failed++; + continue; + } + } else { + tmp = pdu_encode(buf, sizeof(buf), &pdu); + if (tmp < 0) { + printf("sending message to %s failed\n", argv[i]); + failed++; + continue; + } + + tmp = atcmd_plus_cmgs_write(fd, buf, pdu.msg_len); + if (tmp < 0) { + printf("sending message to %s failed\n", argv[i]); + failed++; + continue; + } + } + } + + if (!failed && Global.core.interactive && Global.core.edit_file) { + systemf("rm -f %s", Global.core.edit_file); + } + + phonebook_list_free(&list_info); + + return failed ? false : true; +} + +static char *short_options = __CMD_OPT_FILE; +static struct option long_options[] = { + {"alphabet", 1, NULL, CMD_OPT_ALPHABET}, + {"file", 1, NULL, CMD_OPT_FILE}, + {"smsc-addr", 1, NULL, CMD_OPT_SMSC_ADDR}, + {"cmgw-first", 0, NULL, CMD_OPT_CMGW_FIRST}, + {NULL, 0, NULL, 0}, +}; + +void sms_send_help(FILE *out) { + fprintf(out, "usage: send [ OPTIONS ... ] \n"); + fprintf(out, "where OPTIONS := { \n"); + fprintf(out, " --alphabet { seven-bit | eight-bit } |\n"); + fprintf(out, " -f, --file |\n"); + fprintf(out, " --smsc-addr |\n"); + fprintf(out, " --cmgw-first\n"); + fprintf(out, " }\n"); + fprintf(out, "\n"); +} + +int sms_send(int argc, char **argv) +{ + int i; + int option_index; + int ret; + int fd; + + struct send_options options; + options.alphabet = PDU_ALPHABET_DEFAULT; + options.file = NULL; + options.cmgw_first = false; + options.smsc_addr = NULL; + options.cmgw_first = false; + + while ((i = getopt_long(argc, argv, short_options, long_options, &option_index)) >= 0) { + switch (i) { + case 0: + break; + + case CMD_OPT_ALPHABET: + if (!strcmp(optarg, "seven-bit")) { + options.alphabet = PDU_ALPHABET_DEFAULT; + } else if (!strcmp(optarg, "eight-bit")) { + options.alphabet = PDU_ALPHABET_EIGHT; + } + break; + + case CMD_OPT_FILE: + options.file = optarg; + break; + + case CMD_OPT_SMSC_ADDR: + options.smsc_addr = optarg; + break; + + case CMD_OPT_CMGW_FIRST: + options.cmgw_first = true; + break; + + default: + sms_send_help(stderr); + return false; + } + } + + if (optind >= argc) { + sms_send_help(stderr); + return false; + } + argc -= optind; + argv += optind; + + fd = tty_open(Global.core.device, Global.core.baud_rate); + if (fd < 0) { + fprintf(stderr, "failed to open tty device %s\n", Global.core.device); + return false; + } + atcmd_init(fd, Global.core.read_timeout); + + ret = do_send(fd, &options, argc, argv); + + tty_close(fd); + + return ret; +} -- cgit v1.2.3