summaryrefslogtreecommitdiff
path: root/src/phonebook.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/phonebook.c')
-rw-r--r--src/phonebook.c325
1 files changed, 325 insertions, 0 deletions
diff --git a/src/phonebook.c b/src/phonebook.c
new file mode 100644
index 0000000..80fbc0e
--- /dev/null
+++ b/src/phonebook.c
@@ -0,0 +1,325 @@
+/*
+ * Phonebook
+ *
+ * Copyright (C) 2010 by Multi-Tech Systems
+ *
+ * Author: James Maki <jmaki@multitech.com>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "global.h"
+#include "cmd_options.h"
+#include "phonebook.h"
+#include "utils.h"
+#include "atcmd.h"
+
+void phonebook_entry_free(struct phonebook_entry *entry)
+{
+ free(entry);
+}
+
+struct phonebook_entry *phonebook_entry_alloc(void)
+{
+ return malloc(sizeof(struct phonebook_entry));
+}
+
+struct phonebook_entry *phonebook_find_by_name(struct list_head *head,
+ const char *name)
+{
+ struct phonebook_entry *entry;
+
+ list_for_each_entry(entry, head, list) {
+ if (!strcmp(entry->name, name)) {
+ return entry;
+ }
+ }
+
+ return NULL;
+}
+
+struct phonebook_entry *phonebook_search_names_i(struct list_head *head,
+ const char *name)
+{
+ int tmp;
+ struct phonebook_entry *entry;
+ int matches_found = 0;
+
+ list_for_each_entry(entry, head, list) {
+ if (strstr(entry->name, name)) {
+ matches_found++;
+
+ tmp = user_yesno(USER_YESNO_YES, "Select contact '%s' (%s)",
+ entry->name, entry->addr);
+ if (tmp == USER_YESNO_YES) {
+ return entry;
+ }
+ }
+ }
+
+ if (!matches_found) {
+ log_notice("no matches for %s found in phonebook", name);
+ }
+
+ return NULL;
+}
+
+#define CPBR_HEADER_START "+CPBR: "
+
+static int process_header(struct phonebook_list_info *list_info, char *buf, size_t len)
+{
+ char *save = buf;
+ char *token;
+
+ struct phonebook_entry *entry;
+ int index;
+ char *addr;
+ int type;
+ char *name;
+
+ token = atcmd_response_brk(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at start");
+ return -1;
+ }
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at index");
+ return -2;
+ }
+ index = atoi(token);
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at addr");
+ return -3;
+ }
+ addr = token;
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at type");
+ return -4;
+ }
+ type = atoi(token);
+
+ token = atcmd_value_tok(&save);
+ if (!token) {
+ log_debug("response tokenizing failed at name");
+ return -4;
+ }
+ name = token;
+
+ entry = phonebook_entry_alloc();
+ if (!entry) {
+ log_error("out of memory");
+ return -6;
+ }
+
+ memset(entry, 0, sizeof(*entry));
+
+ entry->index = index;
+ snprintf(entry->addr, sizeof(entry->addr), "%s", addr);
+ entry->type = type;
+ snprintf(entry->name, sizeof(entry->name), "%s", name);
+
+ list_add_tail(&entry->list, &list_info->entry_list);
+
+ list_info->nr_entries++;
+
+ return 0;
+}
+
+static int print_list_yaml(struct phonebook_list_info *list_info)
+{
+ struct phonebook_entry *entry;
+ int indent;
+
+ indent = 0;
+
+ indentf(indent, "---\n");
+ indentf(indent, "\n");
+
+ indentf(indent, "contacts:\n");
+
+ list_for_each_entry(entry, &list_info->entry_list, list) {
+ indent = YAML_INDENT;
+
+ indentf(indent, "- index: %d\n", entry->index);
+ indent += YAML_INDENT;
+
+ indentf(indent, "addr: %s\n", entry->addr);
+ indentf(indent, "type: 0x%02X\n", entry->type);
+ indentf(indent, "name: %s\n", entry->name);
+ }
+
+ indent = 0;
+
+ if (Global.core.verbose) {
+ indentf(indent, "\n");
+
+ indentf(indent, "statistics:\n");
+ indent += YAML_INDENT;
+
+ indentf(indent, "total: %d\n", list_info->nr_entries);
+ indentf(indent, "\n");
+ }
+
+ indent = 0;
+
+ indentf(indent, "...\n");
+
+ return 1;
+}
+
+enum {
+ LIST_STATE_BLANK,
+ LIST_STATE_OPEN,
+ LIST_STATE_CLOSE,
+};
+
+static int list_info_callback(char *buf, size_t len, void *data)
+{
+ struct phonebook_list_info *list_info = (struct phonebook_list_info *) data;
+
+ list_info->nr_lines++;
+
+ switch (list_info->state) {
+ case LIST_STATE_BLANK:
+ log_debug("state: LIST_STATE_BLANK");
+
+ if (*buf) {
+ list_info->state = LIST_STATE_CLOSE;
+ log_debug("AT response error: %s", buf);
+ return -1;
+ }
+
+ list_info->state = LIST_STATE_OPEN;
+
+ return 0;
+
+ case LIST_STATE_OPEN:
+ log_debug("state: LIST_STATE_OPEN");
+
+ if (!strncmp(buf, CPBR_HEADER_START, strlen(CPBR_HEADER_START))) {
+ return process_header(list_info, buf, len);
+ } else if (!strcmp(buf, "OK")) {
+ list_info->state = LIST_STATE_CLOSE;
+ return 1;
+ } else if (*buf) {
+ list_info->state = LIST_STATE_CLOSE;
+
+ log_debug("AT response error: %s", buf);
+
+ return -1;
+ } else {
+ return 0;
+ }
+
+ default:
+ return -1;
+ }
+
+ return -1;
+}
+
+void phonebook_list_free(struct phonebook_list_info *list_info)
+{
+ struct phonebook_entry *entry;
+ struct phonebook_entry *entry_save;
+
+ list_for_each_entry_safe(entry, entry_save, &list_info->entry_list, list) {
+ list_del(&entry->list);
+ phonebook_entry_free(entry);
+ }
+}
+
+int phonebook_list_get(int fd, struct phonebook_list_info *list_info)
+{
+ int tmp;
+
+ INIT_LIST_HEAD(&list_info->entry_list);
+
+ if (*list_info->store_select) {
+ tmp = atcmd_plus_cpbs_write(fd, list_info->store_select);
+ if (tmp < 0) {
+ log_error("failed to get selected store info");
+ return -1;
+ }
+ }
+ tmp = atcmd_plus_cpbs_test(fd, &list_info->store.choices);
+ if (tmp < 0) {
+ log_error("failed to get selected store info");
+ return -1;
+ }
+ tmp = atcmd_plus_cpbs_read(fd, &list_info->store.selected);
+ if (tmp < 0) {
+ log_error("failed to get selected store info");
+ return -1;
+ }
+ tmp = atcmd_plus_cpbr_test(fd, &list_info->store);
+ if (tmp < 0) {
+ log_error("failed to get selected store info");
+ return -1;
+ }
+
+ atcmd_writeline(fd, "AT+CPBR=%d,%d",
+ list_info->store.index_min, list_info->store.index_max);
+ tmp = atcmd_response_foreach_line(fd, list_info_callback, list_info);
+ if (tmp < 0) {
+ log_error("listing failed");
+ phonebook_list_free(list_info);
+
+ return tmp;
+ }
+
+ return 0;
+}
+
+int print_phonebook_list(int fd, const char *store)
+{
+ int tmp;
+ struct phonebook_list_info list_info;
+
+ memset(&list_info, 0, sizeof(list_info));
+
+ if (store) {
+ strncpy(list_info.store_select, store, STORE_NAME_LEN);
+ }
+
+ tmp = phonebook_list_get(fd, &list_info);
+ if (tmp < 0) {
+ log_error("failed to get entry list");
+ return false;
+ }
+
+ print_list_yaml(&list_info);
+
+ phonebook_list_free(&list_info);
+
+ return true;
+}