/* * Phonebook * * 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 #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, "list:\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); //CE910 reports an error if empty. Don't report error in this case if ((tmp < 0) && strcmp(Global.core.model, "CE910-DUAL")) { 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; }