summaryrefslogtreecommitdiff
path: root/src/sms_list.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sms_list.c')
-rw-r--r--src/sms_list.c274
1 files changed, 259 insertions, 15 deletions
diff --git a/src/sms_list.c b/src/sms_list.c
index 0ccec15..e6f29f1 100644
--- a/src/sms_list.c
+++ b/src/sms_list.c
@@ -42,6 +42,236 @@
#define CMGL_HEADER_START "+CMGL: "
#define CMGR_HEADER_START "+CMGR: "
+static int decode_timestamp_text_mode(const char *str, struct tm *tm)
+{
+ char *cp;
+ struct tm tm_now;
+ time_t now = time(NULL);
+
+ localtime_r(&now, &tm_now);
+
+ memset(tm, 0, sizeof(*tm));
+
+ cp = (char *) strptime(str, "%y/%m/%d,%H:%M:%S", tm);
+ if (!cp || *cp) {
+ log_error("timestamp could not be converted to tm");
+ return -1;
+ }
+
+ tm->tm_gmtoff = tm_now.tm_gmtoff;
+
+ return 0;
+}
+
+static int process_header_text_mode(struct msg_list_info *list_info, char *buf, size_t len)
+{
+ char *save = buf;
+ char *token;
+
+ struct sms_msg *msg;
+ int index;
+ int status;
+ char *name;
+ char *timestamp = NULL;
+ int msg_len;
+
+ token = atcmd_response_brk(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at start");
+ return -1;
+ }
+
+ switch (list_info->cmd_type) {
+ case CMD_TYPE_CMGL:
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at index");
+ return -1;
+ }
+ index = atoi(token);
+
+ break;
+ case CMD_TYPE_CMGR:
+ index = list_info->index;
+ break;
+ default:
+ return false;
+ }
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at msg-status");
+ return -1;
+ }
+ status = msg_status_name_to_value(token);
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at name");
+ return -1;
+ }
+ name = token;
+
+ if (list_info->cmd_type == CMD_TYPE_CMGR) {
+ timestamp = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at timestamp");
+ return -1;
+ }
+ }
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at lang");
+ return -1;
+ }
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at encode");
+ return -1;
+ }
+
+ if (list_info->cmd_type == CMD_TYPE_CMGR) {
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at prio");
+ return -1;
+ }
+ if (*save == '\"') {
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at callback");
+ return -1;
+ }
+ }
+ }
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at msg-len");
+ return -1;
+ }
+ msg_len = atoi(token);
+
+ switch (status) {
+ case SMS_MSG_REC_UNREAD:
+ list_info->nr_unread++;
+ break;
+ case SMS_MSG_REC_READ:
+ list_info->nr_read++;
+ break;
+ case SMS_MSG_STO_UNSENT:
+ list_info->nr_unsent++;
+ break;
+ case SMS_MSG_STO_SENT:
+ list_info->nr_sent++;
+ break;
+ default:
+ log_warning("msg-status unknown");
+ list_info->nr_unknown++;
+ }
+
+ msg = sms_msg_alloc();
+ if (!msg) {
+ log_error("out of memory");
+ return -1;
+ }
+
+ memset(msg, 0, sizeof(*msg));
+
+ msg->index = index;
+ msg->status = status;
+ snprintf(msg->name, sizeof(msg->name), "%s", name);
+ msg->len = msg_len;
+ if (timestamp) {
+ decode_timestamp_text_mode(timestamp, &msg->pdu.timestamp);
+ }
+
+ list_add_tail(&msg->list, &list_info->msg_list);
+
+ list_info->nr_msgs++;
+
+ return 0;
+}
+
+static ssize_t readn(int fd, void *buf, size_t len)
+{
+ ssize_t cc;
+ ssize_t total;
+
+ total = 0;
+
+ while (len) {
+ cc = read(fd, buf, len);
+ if (cc <= 0) {
+ return cc;
+ }
+
+ total += cc;
+ buf = buf + cc;
+ len -= cc;
+ }
+
+ log_debug("read: \"%.*J\"", len, buf);
+
+ return total;
+}
+
+static int sms_list_text_mode(int fd, struct msg_list_info *list_info)
+{
+ char buf[ATCMD_LINE_SIZE];
+ int tmp;
+ struct sms_msg *msg;
+
+ while (1) {
+ tmp = atcmd_readline(fd, buf, sizeof(buf));
+ if (tmp <= 0) {
+ return -1;
+ }
+
+ list_info->nr_lines++;
+
+ if (!strncmp(buf, CMGL_HEADER_START, strlen(CMGL_HEADER_START)) ||
+ !strncmp(buf, CMGR_HEADER_START, strlen(CMGR_HEADER_START))) {
+ tmp = process_header_text_mode(list_info, buf, sizeof(buf));
+ if (tmp < 0) {
+ log_debug("process_header_text_mode failed");
+ return -1;
+ }
+
+ if (list_empty(&list_info->msg_list)) {
+ log_debug("empty list");
+ return -1;
+ }
+
+ msg = list_entry(list_info->msg_list.prev, typeof(*msg), list);
+ if (msg->len <= 0) {
+ continue;
+ }
+ if (msg->len >= PDU_UD_SIZE) {
+ continue;
+ }
+
+ list_info->nr_lines++;
+
+ tmp = readn(fd, msg->pdu.user_data, msg->len);
+ if (tmp <= 0) {
+ log_debug("read message failed");
+ return -1;
+ }
+
+ msg->pdu.user_data_len = msg->len;
+ } else if (!strcmp(buf, "OK")) {
+ return 0;
+ } else if (*buf) {
+ log_debug("AT response error: %s", buf);
+
+ return -1;
+ }
+ }
+}
+
static int process_header(struct msg_list_info *list_info, char *buf, size_t len)
{
char *save = buf;
@@ -221,8 +451,8 @@ static int print_list_yaml(struct msg_list_info *list_info)
enum {
LIST_STATE_BLANK,
- LIST_STATE_OPEN,
- LIST_STATE_PDU,
+ LIST_STATE_HEADER,
+ LIST_STATE_DATA,
LIST_STATE_CLOSE,
};
@@ -244,16 +474,16 @@ static int list_info_callback(char *buf, size_t len, void *data)
return -1;
}
- list_info->state = LIST_STATE_OPEN;
+ list_info->state = LIST_STATE_HEADER;
return 0;
- case LIST_STATE_OPEN:
- log_debug("state: LIST_STATE_OPEN");
+ case LIST_STATE_HEADER:
+ log_debug("state: LIST_STATE_HEADER");
if (!strncmp(buf, CMGL_HEADER_START, strlen(CMGL_HEADER_START)) ||
!strncmp(buf, CMGR_HEADER_START, strlen(CMGR_HEADER_START))) {
- list_info->state = LIST_STATE_PDU;
+ list_info->state = LIST_STATE_DATA;
return process_header(list_info, buf, len);
} else if (!strcmp(buf, "OK")) {
@@ -269,8 +499,8 @@ static int list_info_callback(char *buf, size_t len, void *data)
return 0;
}
- case LIST_STATE_PDU:
- log_debug("state: LIST_STATE_PDU");
+ case LIST_STATE_DATA:
+ log_debug("state: LIST_STATE_DATA");
if (list_empty(&list_info->msg_list)) {
log_debug("empty list");
@@ -285,7 +515,7 @@ static int list_info_callback(char *buf, size_t len, void *data)
}
}
- list_info->state = LIST_STATE_OPEN;
+ list_info->state = LIST_STATE_HEADER;
return 0;
@@ -324,7 +554,11 @@ int sms_list_get(int fd, struct msg_list_info *list_info)
switch (list_info->cmd_type) {
case CMD_TYPE_CMGL:
- atcmd_writeline(fd, "AT+CMGL=%d", list_info->status);
+ if (Global.core.sms_mode == SMS_TEXT_MODE) {
+ atcmd_writeline(fd, "AT+CMGL=\"%s\"", msg_status_value_to_name(list_info->status));
+ } else {
+ atcmd_writeline(fd, "AT+CMGL=%d", list_info->status);
+ }
break;
case CMD_TYPE_CMGR:
@@ -335,12 +569,22 @@ int sms_list_get(int fd, struct msg_list_info *list_info)
return -1;
}
- tmp = atcmd_response_foreach_line(fd, list_info_callback, list_info);
- if (tmp < 0) {
- log_error("listing failed");
- sms_list_free(list_info);
+ if (Global.core.sms_mode == SMS_TEXT_MODE) {
+ tmp = sms_list_text_mode(fd, list_info);
+ if (tmp < 0) {
+ log_error("listing failed");
+ sms_list_free(list_info);
- return tmp;
+ return tmp;
+ }
+ } else if (Global.core.sms_mode == SMS_PDU_MODE) {
+ tmp = atcmd_response_foreach_line(fd, list_info_callback, list_info);
+ if (tmp < 0) {
+ log_error("listing failed");
+ sms_list_free(list_info);
+
+ return tmp;
+ }
}
return 0;