diff options
Diffstat (limited to 'src/phonebook.c')
-rw-r--r-- | src/phonebook.c | 325 |
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; +} |