/* * btxml.c * * Creates a backup of the Nokia 6310i via bluetooth. Outputs data to * stdout in xml format. This is plug'n'play, no need to enter any data * on the host or phone side. * Just saw that it somehow works for Ericsson T610 and T68i, too. They * don't support text mode sms... :-( * * Copyright (C) 2004 by Andreas Oberritter * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * rev 0.3 (2004/02/14) * - ATE0 to disable echo on ericsson * * rev 0.2 (2004/02/14) * - set auth & encrypt to off * * rev 0.1 (2004/02/12) * - initial release * * TODO: pdu parser for sms */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************/ #define CACHE_TIMEOUT 60 #define CACHE_SIZE_MAX 0x10000 struct cache_item { bdaddr_t addr; time_t time; bool valid; }; static enum { MANUF_UNKNOWN, MANUF_ERICSSON, MANUF_NOKIA, } manuf; static struct cache_item cache[CACHE_SIZE_MAX]; static size_t cache_size; /******************************************************************************/ static void bt_cache_add(bdaddr_t *addr) { struct cache_item *item; for (item = &cache[0]; item < &cache[CACHE_SIZE_MAX]; item++) { if (item->valid) continue; bacpy(&item->addr, addr); item->time = time(NULL); item->valid = true; cache_size++; } } /******************************************************************************/ static void bt_cache_clear(void) { struct cache_item *item; time_t now; size_t removed = 0; size_t count = 0; now = time(NULL); for (item = &cache[0]; item < &cache[CACHE_SIZE_MAX]; item++) { if (count == cache_size) break; if (!item->valid) continue; count++; if (now - item->time < CACHE_TIMEOUT) continue; item->valid = false; removed++; } cache_size -= removed; } /******************************************************************************/ static bool bt_cache_find(bdaddr_t *addr) { struct cache_item *item; size_t count = 0; for (item = &cache[0]; item < &cache[CACHE_SIZE_MAX]; item++) { if (count == cache_size) break; if (!item->valid) continue; if (!bacmp(&item->addr, addr)) return true; count++; } return false; } /******************************************************************************/ static void at_send(FILE *fp, const char *fmt, va_list ap) { fprintf(fp, "AT"); vfprintf(fp, fmt, ap); fprintf(fp, "\r\n"); } /******************************************************************************/ static ssize_t at_recv(FILE *fp, char *dest) { char *line = NULL; size_t len = 0; size_t ret = 0; ssize_t read; while ((read = getline(&line, &len, fp)) != -1) { if (!read) continue; if ((line[read - 1] == '\n') && (--read == 0)) continue; if ((line[read - 1] == '\r') && (--read == 0)) continue; line[read++] = '\0'; if (!strcmp(line, "OK")) break; if ((!strcmp(line, "ERROR")) || (!strncmp(line, "+CME ERROR:", 10)) || (!strncmp(line, "+CMS ERROR:", 10))) { ret = -1; break; } if (dest) { if (ret) dest[-1] = ' '; memcpy(dest, line, read); dest += read; } ret++; } free(line); return ret; } /******************************************************************************/ static int at_cmd(FILE *fp, char *buf, const char *fmt, ...) { va_list ap; va_start(ap, fmt); at_send(fp, fmt, ap); va_end(ap); return at_recv(fp, buf); } /******************************************************************************/ static int at_parse_phonebook_entry(FILE *fp, size_t num) { char buf[0x1000], *ptr, *start, *end; char *number_ptr, *name_ptr; ssize_t number_len, name_len; if (at_cmd(fp, buf, "+CPBR=%u", num) != 1) return -1; ptr = buf; if (!strncmp(ptr, "+CPBR: ", 7)) ptr += 7; puts("\t\t"); if (((start = strchr(ptr, '\"'))) && (end = strchr(++start, '\"'))) { number_ptr = start; number_len = end - start; } else { number_ptr = NULL; } if (((start = strchr(++end, '\"'))) && (end = strrchr(&ptr[strlen(ptr) - 1], '\"'))) { name_ptr = ++start; name_len = end - start; } else { name_ptr = NULL; } if ((number_ptr) && (name_ptr)) { printf("\t\t\t%.*s\n", name_len, name_ptr); printf("\t\t\t%.*s\n", number_len, number_ptr); } else { printf("\t\t\t%s\n", ptr); } puts("\t\t"); fflush(stdout); return 0; } /******************************************************************************/ static int at_parse_phonebook(FILE *fp, const char *name) { char buf[0x1000], *ptr; size_t start, end, used, size, i, found; if (at_cmd(fp, NULL, "+CPBS=%s", name) != 0) return -1; if ((manuf == MANUF_NOKIA) || (manuf == MANUF_UNKNOWN)) { if (at_cmd(fp, buf, "+CPBS?") != 1) return -1; if (!(ptr = strchr(buf, ','))) return -1; if (sscanf(++ptr, "%u,%u", &used, &size) != 2) return -1; if (!used) return -1; } if (at_cmd(fp, buf, "+CPBR=?") != 1) return -1; if (sscanf(buf, "+CPBR: (%u-%u)", &start, &end) != 2) return -1; if (manuf == MANUF_ERICSSON) { // FIXME used = size = end; } printf("\t\n", name, size); for (i = start, found = 0; i <= end && found < used; i++) if (!at_parse_phonebook_entry(fp, i)) found++; printf("\t\n"); fflush(stdout); return 0; } /******************************************************************************/ static int at_parse_brackets(FILE *fp, char *buf, int (*cb)(FILE*, const char*)) { char *start, *end, *str; if ((!(start = strchr(buf, '('))) || (!(end = strchr(++start, ')')))) return -1; *end = '\0'; while ((str = strsep(&start, ","))) cb(fp, str); return 0; } /******************************************************************************/ static int at_parse_phonebook_list(FILE *fp) { char buf[0x1000]; if (at_cmd(fp, buf, "+CPBS=?") != 1) return -1; return at_parse_brackets(fp, buf, at_parse_phonebook); } /******************************************************************************/ static int at_parse_manufacturer_identification(FILE *fp) { char buf[0x1000]; if (at_cmd(fp, buf, "+GMI") < 1) return -1; if (strstr(buf, "Ericsson")) manuf = MANUF_ERICSSON; else if (strstr(buf, "Nokia")) manuf = MANUF_NOKIA; else manuf = MANUF_UNKNOWN; printf("\t%s\n", buf); return 0; } /******************************************************************************/ static int at_parse_model_identification(FILE *fp) { char buf[0x1000]; if (at_cmd(fp, buf, "+GMM") < 1) return -1; printf("\t%s\n", buf); return 0; } /******************************************************************************/ static int at_parse_revision_identification(FILE *fp) { char buf[0x1000]; if (at_cmd(fp, buf, "+GMR") < 1) return -1; printf("\t%s\n", buf); return 0; } /******************************************************************************/ static int at_parse_psn_identification(FILE *fp) { char buf[0x1000]; if (at_cmd(fp, buf, "+GSN") < 1) return -1; printf("\t%s\n", buf); return 0; } /******************************************************************************/ static int at_parse_identification(FILE *fp) { at_parse_manufacturer_identification(fp); at_parse_model_identification(fp); at_parse_revision_identification(fp); at_parse_psn_identification(fp); fflush(stdout); return 0; } /******************************************************************************/ static int at_parse_message(FILE *fp, size_t num) { char buf[0x1000], *ptr; if (at_cmd(fp, buf, "+CMGR=%u", num) < 1) return -1; ptr = buf; if (!strncmp(ptr, "+CMGR: ", 7)) ptr += 7; printf("\t\t%s\n", ptr); fflush(stdout); return 0; } /******************************************************************************/ static int at_parse_message_storage(FILE *fp, const char *name) { char buf[0x1000]; size_t i, msgnum, size; if (at_cmd(fp, buf, "+CPMS=%s", name) != 1) return -1; if (sscanf(buf, "+CPMS: %u,%u", &msgnum, &size) != 2) return -1; printf("\t\n", name); for (i = 1; i <= msgnum; i++) at_parse_message(fp, i); puts("\t"); return 0; } /******************************************************************************/ static int at_parse_message_list(FILE *fp) { char buf[0x1000]; if (at_cmd(fp, NULL, "+CMGF=1") != 0) return -1; if (at_cmd(fp, buf, "+CPMS=?") != 1) return -1; return at_parse_brackets(fp, buf, at_parse_message_storage); } static int at_disable_echo(FILE *fp) { at_cmd(fp, NULL, "E0"); } /******************************************************************************/ static int bt_rfcomm_config(int fd) { struct termios t; int ret; if ((ret = tcgetattr(fd, &t))) perror("tcgetattr"); else { t.c_iflag = IGNBRK; t.c_oflag = 0; t.c_cflag = CLOCAL | CREAD | CS8 | B115200; t.c_lflag = 0; t.c_line = 0; t.c_ispeed = B115200; t.c_ospeed = B115200; if ((ret = tcsetattr(fd, TCSADRAIN, &t))) perror("tcsetattr"); } return ret; } /******************************************************************************/ static int bt_rfcomm(int dev_id) { static const char *rfcomm_fmt = "/dev/bluetooth/rfcomm/%u"; char filename[FILENAME_MAX]; FILE *fp = NULL; snprintf(filename, FILENAME_MAX, rfcomm_fmt, dev_id); if (!(fp = fopen(filename, "r+"))) { perror(filename); return -1; } if (bt_rfcomm_config(fileno(fp)) == 0) { at_disable_echo(fp); at_parse_identification(fp); at_parse_phonebook_list(fp); at_parse_message_list(fp); sleep(1); } fclose(fp); return 0; } /******************************************************************************/ static int bt_release(int sock, int dev_id) { struct rfcomm_dev_req req; int ret; req.dev_id = dev_id; req.flags = 0; bacpy(&req.src, BDADDR_ANY); bacpy(&req.dst, BDADDR_ANY); req.channel = 0; if ((ret = ioctl(sock, RFCOMMRELEASEDEV, &req))) perror("RFCOMMRELEASEDEV"); return ret; } /******************************************************************************/ static int bt_bind(int sock, int dev_id, bdaddr_t *bdaddr) { struct rfcomm_dev_req req; int ret; req.dev_id = dev_id; req.flags = 0; bacpy(&req.src, BDADDR_ANY); bacpy(&req.dst, bdaddr); req.channel = 17; // 18 if (ioctl(sock, RFCOMMCREATEDEV, &req) == 0) return 0; if (errno != EADDRINUSE) perror("RFCOMMCREATEDEV"); else if ((ret = bt_release(sock, dev_id))) ; else if ((ret = ioctl(sock, RFCOMMCREATEDEV, &req))) perror("RFCOMMCREATEDEV"); return ret; } /******************************************************************************/ static int scan(int dev_id, int s) { inquiry_info *info = NULL; int max, len, flags; char addr[18], name[256]; int i, sock; len = 4; max = 100; flags = IREQ_CACHE_FLUSH; max = hci_inquiry(dev_id, len, max, NULL, &info, flags); if (max == -1) { perror("hci_inquiry"); return -1; } for (i = 0; i < max; i++) { if (bt_cache_find(&info[i].bdaddr)) continue; sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM); if (sock == -1) { perror("socket"); continue; } if (bt_bind(sock, dev_id, &info[i].bdaddr)) continue; if (hci_read_remote_name(s, &info[i].bdaddr, sizeof(name), name, 2)) name[0] = '\0'; ba2str(&info[i].bdaddr, addr); printf("\n", addr, name); fflush(stdout); bt_rfcomm(dev_id); bt_release(sock, dev_id); close(sock); puts(""); fflush(stdout); bt_cache_add(&info[i].bdaddr); } free(info); return 0; } /******************************************************************************/ static bool bt_set_auth(int dev_id, int s) { struct hci_dev_req dr; int ret; dr.dev_id = dev_id; dr.dev_opt = AUTH_DISABLED; if ((ret = ioctl(s, HCISETAUTH, &dr))) perror("HCISETAUTH"); return (ret == 0); } /******************************************************************************/ static bool bt_set_encrypt(int dev_id, int s) { struct hci_dev_req dr; int ret; dr.dev_id = dev_id; dr.dev_opt = ENCRYPT_DISABLED; if ((ret = ioctl(s, HCISETENCRYPT, &dr))) perror("HCISETENCRYPT"); return (ret == 0); } /******************************************************************************/ static bool bt_set_name(int s) { change_local_name_cp cp; int ret; memset(cp.name, ' ', CHANGE_LOCAL_NAME_CP_SIZE); ret = hci_send_cmd(s, OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME, CHANGE_LOCAL_NAME_CP_SIZE, (void *) &cp); if (ret == -1) perror("OCF_CHANGE_LOCAL_NAME"); return (ret == 0); } /******************************************************************************/ static bool bt_configure(int dev_id, int s) { return (bt_set_auth(dev_id, s) && bt_set_encrypt(dev_id, s) && bt_set_name(s)); } /******************************************************************************/ int main(void) { int dev_id, s; time_t now, prev; if ((dev_id = hci_get_route(NULL)) == -1) { perror("hci_get_route"); return EXIT_FAILURE; } if ((s = hci_open_dev(dev_id)) == -1) { perror("hci_open_dev"); return -1; } bt_configure(dev_id, s); prev = time(NULL); puts(""); while (1) { scan(dev_id, s); now = time(NULL); if (now != prev) { bt_cache_clear(); prev = now; } else { usleep(0); } } if (hci_close_dev(s)) perror("hci_close_dev"); return EXIT_SUCCESS; }
<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            ÑÇÖÞÅ·ÃÀÔÚÏß