From 225e576d57be87e63607901a7c995fba7f3571de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Pettersson?= Date: Sat, 4 Oct 2014 19:42:30 +0200 Subject: [PATCH] Added SQLite persistent storage for friend requests. --- CMakeLists.txt | 2 + README.md | 4 +- src/twc-commands.c | 83 ++++---- src/twc-friend-request.c | 33 +-- src/twc-friend-request.h | 7 +- src/twc-profile.c | 26 ++- src/twc-profile.h | 1 - src/twc-sqlite.c | 430 +++++++++++++++++++++++++++++++++++++++ src/twc-sqlite.h | 58 ++++++ src/twc.c | 11 + 10 files changed, 578 insertions(+), 77 deletions(-) create mode 100644 src/twc-sqlite.c create mode 100644 src/twc-sqlite.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 08e39e7..411a54f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ add_library(tox MODULE src/twc-list.c src/twc-message-queue.c src/twc-profile.c + src/twc-sqlite.c src/twc-tox-callbacks.c src/twc-utils.c ) @@ -50,6 +51,7 @@ add_library(tox MODULE set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter") target_link_libraries(tox toxcore) +target_link_libraries(tox sqlite3) # remove lib prefix (libtox.so -> tox.so) set_target_properties(tox PROPERTIES PREFIX "") diff --git a/README.md b/README.md index c846d64..b6f6cc4 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Installation ------------ > Tox-WeeChat is available in the [AUR][4]. -Tox-WeeChat requires [WeeChat][1] >= 1.0.1, [libjansson][5] >= 2.5 and the latest-ish [libtoxcore][6]. It also requires CMake to be built. Installation is fairly simple; after getting the source, compile and install using CMake: +Tox-WeeChat requires [WeeChat][1] >= 1.0.1, [SQLite][5] >= 3.6.19 and the latest-ish [libtoxcore][6]. It also requires CMake to be built. Installation is fairly simple; after getting the source, compile and install using CMake: $ mkdir build && cd build $ cmake -DHOME_FOLDER_INSTALL=ON .. @@ -61,6 +61,6 @@ along with Tox-WeeChat. If not, see . [2]: http://weechat.org [3]: https://travis-ci.org/haavardp/tox-weechat [4]: https://aur.archlinux.org/packages/tox-weechat-git -[5]: http://www.digip.org/jansson +[5]: http://www.sqlite.org [6]: https://github.com/irungentoo/toxcore diff --git a/src/twc-commands.c b/src/twc-commands.c index ce90122..4b443cd 100644 --- a/src/twc-commands.c +++ b/src/twc-commands.c @@ -28,6 +28,7 @@ #include "twc-chat.h" #include "twc-friend-request.h" #include "twc-bootstrap.h" +#include "twc-sqlite.h" #include "twc-utils.h" #include "twc-commands.h" @@ -279,22 +280,22 @@ twc_cmd_friend(void *data, struct t_gui_buffer *buffer, struct t_twc_friend_request *request; if (weechat_strcasecmp(argv[2], "all") == 0) { - int count = 0; - while ((request = twc_friend_request_with_index(profile, 0)) != NULL) + struct t_twc_list *requests = twc_sqlite_friend_requests(profile); + size_t index; + struct t_twc_list_item *item; + twc_list_foreach(requests, index, item) { if (accept) - twc_friend_request_accept(request); + twc_friend_request_accept(item->friend_request); else - twc_friend_request_remove(request); - - ++count; + twc_friend_request_remove(item->friend_request); } weechat_printf(profile->buffer, "%s%s %d friend requests.", weechat_prefix("network"), accept ? "Accepted" : "Declined", - count); + index); return WEECHAT_RC_OK; } @@ -312,14 +313,16 @@ twc_cmd_friend(void *data, struct t_gui_buffer *buffer, char hex_address[TOX_CLIENT_ID_SIZE * 2 + 1]; twc_bin2hex(request->tox_id, - TOX_CLIENT_ID_SIZE, - hex_address); + TOX_CLIENT_ID_SIZE, + hex_address); if (accept) twc_friend_request_accept(request); else twc_friend_request_remove(request); + twc_friend_request_free(request); + weechat_printf(profile->buffer, "%s%s friend request from %s.", weechat_prefix("network"), @@ -333,37 +336,34 @@ twc_cmd_friend(void *data, struct t_gui_buffer *buffer, // /friend requests else if (argc == 2 && weechat_strcasecmp(argv[1], "requests") == 0) { - if (profile->friend_requests == NULL) - { - weechat_printf(profile->buffer, - "%sNo pending friend requests :(", - weechat_prefix("network")); - } - else - { - weechat_printf(profile->buffer, - "%sPending friend requests:", - weechat_prefix("network")); + weechat_printf(profile->buffer, + "%sPending friend requests:", + weechat_prefix("network")); - size_t index; - struct t_twc_list_item *item; - twc_list_foreach(profile->friend_requests, index, item) - { - // TODO: load short form address length from config - char hex_address[12 + 1]; - twc_bin2hex(item->friend_request->tox_id, - 6, - hex_address); + struct t_twc_list *friend_requests = twc_sqlite_friend_requests(profile); - weechat_printf(profile->buffer, - "%s[%d] Address: %s\n" - "[%d] Message: %s", - weechat_prefix("network"), - index, hex_address, - index, item->friend_request->message); - } + size_t index; + struct t_twc_list_item *item; + twc_list_foreach(friend_requests, index, item) + { + // TODO: load short form address length from config + char hex_address[12 + 1]; + twc_bin2hex(item->friend_request->tox_id, + 6, + hex_address); + + weechat_printf(profile->buffer, + "%s[%d] Address: %s\n" + "[%d] Message: %s", + weechat_prefix("network"), + item->friend_request->request_id, + hex_address, + item->friend_request->request_id, + item->friend_request->message); } + twc_friend_request_free_list(friend_requests); + return WEECHAT_RC_OK; } @@ -388,7 +388,6 @@ twc_cmd_me(void *data, struct t_gui_buffer *buffer, return WEECHAT_RC_OK; } - /** * Command /msg callback. */ @@ -704,7 +703,7 @@ twc_commands_init() "address: internet address of node to bootstrap with\n" " port: port of the node\n" " Tox ID: Tox ID of the node", - NULL, twc_cmd_bootstrap, NULL); + "connect", twc_cmd_bootstrap, NULL); weechat_hook_command("friend", "manage friends", @@ -719,7 +718,13 @@ twc_commands_init() "requests: list friend requests\n" " accept: accept friend requests\n" " decline: decline friend requests\n", - NULL, twc_cmd_friend, NULL); + "list" + " || add" + " || remove" + " || requests" + " || accept" + " || decline", + twc_cmd_friend, NULL); weechat_hook_command("me", "send an action to the current chat", diff --git a/src/twc-friend-request.c b/src/twc-friend-request.c index e25d884..77627b1 100644 --- a/src/twc-friend-request.c +++ b/src/twc-friend-request.c @@ -25,6 +25,7 @@ #include "twc.h" #include "twc-list.h" #include "twc-profile.h" +#include "twc-sqlite.h" #include "twc-utils.h" #include "twc-friend-request.h" @@ -39,14 +40,6 @@ twc_friend_request_add(struct t_twc_profile *profile, const uint8_t *client_id, const char *message) { - struct t_config_option *option = - profile->options[TWC_PROFILE_OPTION_MAX_FRIEND_REQUESTS]; - unsigned int max_requests = weechat_config_integer(option); - - // check for a full friend request list - if (profile->friend_requests->count >= max_requests) - return -1; - // create a new request struct t_twc_friend_request *request = malloc(sizeof(struct t_twc_friend_request)); @@ -58,7 +51,8 @@ twc_friend_request_add(struct t_twc_profile *profile, memcpy(request->tox_id, client_id, TOX_CLIENT_ID_SIZE); // add to list - twc_list_item_new_data_add(profile->friend_requests, request); + if (twc_sqlite_add_friend_request(profile, request) == -1) + return -2; return 0; } @@ -79,8 +73,8 @@ twc_friend_request_accept(struct t_twc_friend_request *request) void twc_friend_request_remove(struct t_twc_friend_request *request) { - twc_list_remove_with_data(request->profile->friend_requests, request); - twc_friend_request_free(request); + twc_sqlite_delete_friend_request_with_id(request->profile, + request->request_id); } /** @@ -88,13 +82,9 @@ twc_friend_request_remove(struct t_twc_friend_request *request) */ struct t_twc_friend_request * twc_friend_request_with_index(struct t_twc_profile *profile, - unsigned int index) + int64_t index) { - struct t_twc_list_item *item = twc_list_get(profile->friend_requests, index); - if (item) - return item->friend_request; - else - return NULL; + return twc_sqlite_friend_request_with_id(profile, index); } /** @@ -108,16 +98,15 @@ twc_friend_request_free(struct t_twc_friend_request *request) } /** - * Free all friend requests from a profile. + * Free all friend requests from a list. */ void -twc_friend_request_free_profile(struct t_twc_profile *profile) +twc_friend_request_free_list(struct t_twc_list *list) { struct t_twc_friend_request *request; - - while ((request = twc_list_pop(profile->friend_requests))) + while ((request = twc_list_pop(list))) twc_friend_request_free(request); - free(profile->friend_requests); + free(list); } diff --git a/src/twc-friend-request.h b/src/twc-friend-request.h index d381cf6..85e39f7 100644 --- a/src/twc-friend-request.h +++ b/src/twc-friend-request.h @@ -22,6 +22,8 @@ #include +struct t_twc_list; + /** * Represents a friend request with a Tox ID and a message. */ @@ -29,6 +31,7 @@ struct t_twc_friend_request { struct t_twc_profile *profile; + int request_id; uint8_t tox_id[TOX_CLIENT_ID_SIZE]; char *message; }; @@ -46,13 +49,13 @@ twc_friend_request_remove(struct t_twc_friend_request *request); struct t_twc_friend_request * twc_friend_request_with_index(struct t_twc_profile *profile, - unsigned int index); + int64_t index); void twc_friend_request_free(struct t_twc_friend_request *request); void -twc_friend_request_free_profile(struct t_twc_profile *profile); +twc_friend_request_free_list(struct t_twc_list *list); #endif // TOX_WEECHAT_FRIEND_REQUEST_H diff --git a/src/twc-profile.c b/src/twc-profile.c index b9cd614..607b3b0 100644 --- a/src/twc-profile.c +++ b/src/twc-profile.c @@ -33,6 +33,7 @@ #include "twc-message-queue.h" #include "twc-chat.h" #include "twc-tox-callbacks.h" +#include "twc-sqlite.h" #include "twc-utils.h" #include "twc-profile.h" @@ -176,7 +177,6 @@ twc_profile_new(const char *name) profile->tox_online = false; profile->chats = twc_list_new(); - profile->friend_requests = twc_list_new(); profile->message_queues = weechat_hashtable_new(32, WEECHAT_HASHTABLE_INTEGER, WEECHAT_HASHTABLE_POINTER, @@ -213,15 +213,6 @@ twc_profile_load(struct t_twc_profile *profile) weechat_prefix("network"), weechat_plugin->name, profile->name); - // TODO: this does nothing - if (profile->friend_requests->count > 0) - { - weechat_printf(profile->buffer, - "%sYou have %d pending friend requests.", - weechat_prefix("network"), - profile->friend_requests->count); - } - // create Tox profile->tox = tox_new(NULL); if (!(profile->tox)) @@ -233,6 +224,7 @@ twc_profile_load(struct t_twc_profile *profile) } // try loading Tox saved data + // TODO: this can return -1 even if it does not fail if (twc_profile_load_data(profile) == -1) { // we failed to load - set some defaults @@ -247,6 +239,18 @@ twc_profile_load(struct t_twc_profile *profile) (uint8_t *)name, strlen(name)); } + // register with sqlite + twc_sqlite_add_profile(profile); + + int friend_request_count = twc_sqlite_friend_request_count(profile); + if (friend_request_count > 0) + { + weechat_printf(profile->buffer, + "%sYou have %d pending friend requests.", + weechat_prefix("network"), + friend_request_count); + } + // bootstrap DHT // TODO: add count to config int bootstrap_node_count = 5; @@ -404,6 +408,7 @@ twc_profile_delete(struct t_twc_profile *profile, { char *data_path = twc_profile_expanded_data_path(profile); + twc_sqlite_delete_profile(profile); twc_profile_free(profile); if (delete_data) @@ -427,7 +432,6 @@ twc_profile_free(struct t_twc_profile *profile) } // free things - twc_friend_request_free_profile(profile); twc_chat_free_profile(profile); twc_message_queue_free_profile(profile); free(profile->name); diff --git a/src/twc-profile.h b/src/twc-profile.h index 4cd5c97..b186817 100644 --- a/src/twc-profile.h +++ b/src/twc-profile.h @@ -46,7 +46,6 @@ struct t_twc_profile struct t_gui_buffer *buffer; struct t_hook *tox_do_timer; - struct t_twc_list *friend_requests; struct t_twc_list *chats; struct t_hashtable *message_queues; }; diff --git a/src/twc-sqlite.c b/src/twc-sqlite.c new file mode 100644 index 0000000..202f666 --- /dev/null +++ b/src/twc-sqlite.c @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2014 Håvard Pettersson + * + * This file is part of Tox-WeeChat. + * + * Tox-WeeChat 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 3 of the License, or + * (at your option) any later version. + * + * Tox-WeeChat 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 Tox-WeeChat. If not, see . + */ + +#include +#include + +#include +#include +#include + +#include "twc.h" +#include "twc-list.h" +#include "twc-profile.h" +#include "twc-friend-request.h" + +#include "twc-sqlite.h" + +sqlite3 *twc_sqlite_db = NULL; +struct t_twc_list *twc_sqlite_statements = NULL; + +// TODO: move to config +#define TWC_SQLITE_PATH "%h/tox/data.db" + +#define TWC_SQLITE_DEBUG_RC(rc, expected_rc) \ + if (rc != expected_rc) \ + weechat_printf(NULL, \ + "%s%s: SQLite error in %s: error code %d", \ + weechat_prefix("error"), weechat_plugin->name, \ + __func__, rc); \ + +/** + * Create or reset an SQLite statement. + */ +#define TWC_SQLITE_STMT(statement, statement_str) \ + static sqlite3_stmt *statement = NULL; \ + if (!statement) \ + { \ + int rc = sqlite3_prepare_v2(twc_sqlite_db, \ + statement_str, \ + strlen(statement_str) + 1, \ + &statement, \ + NULL); \ + TWC_SQLITE_DEBUG_RC(rc, SQLITE_OK); \ + if (rc != SQLITE_OK) \ + statement = NULL; \ + else \ + twc_list_item_new_data_add(twc_sqlite_statements, statement); \ + } \ + else \ + { \ + sqlite3_reset(statement); \ + } + +/** + * Return the full path to our SQLite database file. Must be freed. + */ +char * +twc_sqlite_db_path() +{ + const char *weechat_dir = weechat_info_get("weechat_dir", NULL); + return weechat_string_replace(TWC_SQLITE_PATH, "%h", weechat_dir); +} + +/** + * Initialize profile table. Return 0 on success, -1 on errorh + */ +int +twc_sqlite_init_profiles() +{ + TWC_SQLITE_STMT(statement, + "CREATE TABLE IF NOT EXISTS profiles (" + "id INTEGER PRIMARY KEY," + "tox_id BLOB UNIQUE NOT NULL" + ")"); + + int rc = sqlite3_step(statement); + if (rc != SQLITE_DONE) + return -1; + else + return 0; +} + +/** + * Initialize friend request table. Return 0 on success, -1 on error. + */ +int +twc_sqlite_init_friend_requests() +{ + TWC_SQLITE_STMT(statement, + "CREATE TABLE IF NOT EXISTS friend_requests (" + "id INTEGER PRIMARY KEY," + "tox_id BLOB NOT NULL," + "message TEXT," + "profile_id INTEGER NOT NULL," + "FOREIGN KEY(profile_id) REFERENCES profiles(id) ON DELETE CASCADE," + "UNIQUE(tox_id, profile_id)" + ")"); + int rc = sqlite3_step(statement); + TWC_SQLITE_DEBUG_RC(rc, SQLITE_DONE) + if (rc != SQLITE_DONE) + return -1; + else + return 0; +} + +/** + * Add a profile, if it does not exist. + */ +int +twc_sqlite_add_profile(struct t_twc_profile *profile) +{ + TWC_SQLITE_STMT(statement, + "INSERT OR IGNORE INTO profiles (tox_id)" + "VALUES (?)"); + + uint8_t tox_id[TOX_FRIEND_ADDRESS_SIZE]; + tox_get_address(profile->tox, tox_id); + sqlite3_bind_blob(statement, 1, + tox_id, TOX_CLIENT_ID_SIZE, + NULL); + + int rc = sqlite3_step(statement); + TWC_SQLITE_DEBUG_RC(rc, SQLITE_DONE) + if (rc != SQLITE_DONE) + { + weechat_printf(NULL, "sqlite error in %s: %d", __func__, rc); + return -1; + } + else + return 0; +} + +/** + * Get the rowid of a profile. Returns true on success, false on error (e.g. + * not found). + */ +bool +twc_sqlite_profile_id(struct t_twc_profile *profile, int64_t *out) +{ + if (!(profile->tox)) + return false; + + TWC_SQLITE_STMT(statement, + "SELECT id FROM profiles WHERE tox_id == ?"); + + uint8_t tox_id[TOX_FRIEND_ADDRESS_SIZE]; + tox_get_address(profile->tox, tox_id); + sqlite3_bind_blob(statement, 1, + tox_id, TOX_CLIENT_ID_SIZE, + NULL); + + int rc = sqlite3_step(statement); + TWC_SQLITE_DEBUG_RC(rc, SQLITE_ROW) + if (rc != SQLITE_ROW) + { + return false; + } + else + { + *out = sqlite3_column_int(statement, 0); + return true; + } +} + +/** + * Delete a profile from persistent storage. + */ +int +twc_sqlite_delete_profile(struct t_twc_profile *profile) +{ + int64_t profile_id; + if (!twc_sqlite_profile_id(profile, &profile_id)) + { + weechat_printf(NULL, "missing profile!"); + return -1; + } + + TWC_SQLITE_STMT(statement, + "DELETE FROM profiles " + "WHERE id == ?"); + sqlite3_bind_int(statement, 1, + profile_id); + + int rc = sqlite3_step(statement); + TWC_SQLITE_DEBUG_RC(rc, SQLITE_DONE) + if (rc == SQLITE_DONE) + return 0; + else + return -1; +} + +/** + * Add a friend request. Return 0 on success, -1 on error. + */ +int +twc_sqlite_add_friend_request(struct t_twc_profile *profile, + struct t_twc_friend_request *friend_request) +{ + int64_t profile_id; + if (!twc_sqlite_profile_id(profile, &profile_id)) + { + weechat_printf(NULL, "missing profile!"); + return -1; + } + + TWC_SQLITE_STMT(statement, + "INSERT OR REPLACE INTO friend_requests (tox_id, message, profile_id)" + "VALUES (?, ?, ?)"); + sqlite3_bind_blob(statement, 1, + friend_request->tox_id, TOX_CLIENT_ID_SIZE, + NULL); + sqlite3_bind_text(statement, 2, + friend_request->message, strlen(friend_request->message) + 1, + NULL); + sqlite3_bind_int(statement, 3, + profile_id); + + int rc = sqlite3_step(statement); + TWC_SQLITE_DEBUG_RC(rc, SQLITE_DONE) + if (rc != SQLITE_DONE) + return -1; + else + return 0; +} + +/** + * Return the number of friend requests for a profile. + */ +int +twc_sqlite_friend_request_count(struct t_twc_profile *profile) +{ + int64_t profile_id; + if (!twc_sqlite_profile_id(profile, &profile_id)) + { + weechat_printf(NULL, "missing profile!"); + return -1; + } + + TWC_SQLITE_STMT(statement, + "SELECT COUNT(*) FROM friend_requests WHERE profile_id == ?"); + sqlite3_bind_int(statement, 1, + profile_id); + + int rc = sqlite3_step(statement); + TWC_SQLITE_DEBUG_RC(rc, SQLITE_ROW) + if (rc != SQLITE_ROW) + return 0; + else + return sqlite3_column_int(statement, 0); +} + +/** + * Convert a row from an SQLite statement to a friend request object. + */ +struct t_twc_friend_request * +twc_sqlite_friend_request_row(sqlite3_stmt *statement, + struct t_twc_profile *profile) +{ + struct t_twc_friend_request *request = malloc(sizeof(struct t_twc_friend_request)); + request->request_id = sqlite3_column_int(statement, 0); + memcpy(request->tox_id, + sqlite3_column_blob(statement, 1), + TOX_CLIENT_ID_SIZE); + request->message = strdup((const char *)sqlite3_column_text(statement, 2)); + request->profile = profile; + + return request; +} + +/** + * Return a list of all friend requests for the given profile. + */ +struct t_twc_list * +twc_sqlite_friend_requests(struct t_twc_profile *profile) +{ + int64_t profile_id; + if (!twc_sqlite_profile_id(profile, &profile_id)) + { + weechat_printf(NULL, "missing profile!"); + return NULL; + } + + TWC_SQLITE_STMT(statement, + "SELECT id, tox_id, message " + "FROM friend_requests " + "WHERE profile_id == ?"); + sqlite3_bind_int(statement, 1, + profile_id); + + struct t_twc_list *friend_requests = twc_list_new(); + + int rc; + while ((rc = sqlite3_step(statement)) == SQLITE_ROW) + { + struct t_twc_friend_request *request = + twc_sqlite_friend_request_row(statement, profile); + twc_list_item_new_data_add(friend_requests, request); + } + TWC_SQLITE_DEBUG_RC(rc, SQLITE_DONE) + + return friend_requests; +} + +struct t_twc_friend_request * +twc_sqlite_friend_request_with_id(struct t_twc_profile *profile, + int64_t id) +{ + int64_t profile_id; + if (!twc_sqlite_profile_id(profile, &profile_id)) + { + weechat_printf(NULL, "missing profile!"); + return NULL; + } + + TWC_SQLITE_STMT(statement, + "SELECT id, tox_id, message " + "FROM friend_requests " + "WHERE id == ? AND profile_id == ?"); + sqlite3_bind_int(statement, 1, + id); + sqlite3_bind_int(statement, 2, + profile_id); + + struct t_twc_friend_request *request; + int rc = sqlite3_step(statement); + if (rc == SQLITE_ROW) + { + request = twc_sqlite_friend_request_row(statement, profile); + return request; + } + else + TWC_SQLITE_DEBUG_RC(rc, SQLITE_DONE) + + return NULL; +} + +int +twc_sqlite_delete_friend_request_with_id(struct t_twc_profile *profile, + int64_t id) +{ + int64_t profile_id; + if (!twc_sqlite_profile_id(profile, &profile_id)) + { + weechat_printf(NULL, "missing profile!"); + return -1; + } + + TWC_SQLITE_STMT(statement, + "DELETE FROM friend_requests " + "WHERE id == ? AND profile_id == ?"); + sqlite3_bind_int(statement, 1, + id); + sqlite3_bind_int(statement, 2, + profile_id); + + int rc = sqlite3_step(statement); + TWC_SQLITE_DEBUG_RC(rc, SQLITE_DONE) + if (rc == SQLITE_DONE) + return 0; + else + return -1; +} + +/** + * Initialize connection to SQLite database and create tables if necessary. + * Returns 0 on success, -1 on failure. + */ +int +twc_sqlite_init() +{ + char *path = twc_sqlite_db_path(); + + int rc = sqlite3_open(path, &twc_sqlite_db); + free(path); + + TWC_SQLITE_DEBUG_RC(rc, SQLITE_OK) + if (rc != SQLITE_OK) + { + weechat_printf(NULL, + "%s: could not open database: %s\n", + weechat_plugin->name, + sqlite3_errmsg(twc_sqlite_db)); + sqlite3_close(twc_sqlite_db); + twc_sqlite_db = NULL; + + return -1; + } + + // statement list (so we can finalize later) + twc_sqlite_statements = twc_list_new(); + + // initialize tables + if (twc_sqlite_init_profiles() != 0 || + twc_sqlite_init_friend_requests() != 0) + return -1; + + return 0; +} + +/** + * Close connection to SQLite database. + */ +void +twc_sqlite_end() +{ + size_t index; + struct t_twc_list_item *item; + twc_list_foreach(twc_sqlite_statements, index, item) + sqlite3_finalize(item->data); + + int rc = sqlite3_close(twc_sqlite_db); + TWC_SQLITE_DEBUG_RC(rc, SQLITE_OK) +} + diff --git a/src/twc-sqlite.h b/src/twc-sqlite.h new file mode 100644 index 0000000..ab7db32 --- /dev/null +++ b/src/twc-sqlite.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 Håvard Pettersson + * + * This file is part of Tox-WeeChat. + * + * Tox-WeeChat 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 3 of the License, or + * (at your option) any later version. + * + * Tox-WeeChat 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 Tox-WeeChat. If not, see . + */ + +#ifndef TWC_SQLITE_H +#define TWC_SQLITE_H + +#include + +struct t_twc_profile; +struct t_twc_friend_request; + +int +twc_sqlite_init(); + +int +twc_sqlite_add_profile(struct t_twc_profile *profile); + +int +twc_sqlite_delete_profile(struct t_twc_profile *profile); + +int +twc_sqlite_add_friend_request(struct t_twc_profile *profile, + struct t_twc_friend_request *friend_request); + +int +twc_sqlite_friend_request_count(struct t_twc_profile *profile); + +struct t_twc_list * +twc_sqlite_friend_requests(struct t_twc_profile *profile); + +struct t_twc_friend_request * +twc_sqlite_friend_request_with_id(struct t_twc_profile *profile, + int64_t id); + +int +twc_sqlite_delete_friend_request_with_id(struct t_twc_profile *profile, + int64_t id); + +void +twc_sqlite_end(); + +#endif // TWC_SQLITE_H diff --git a/src/twc.c b/src/twc.c index 35856d1..b59b2aa 100644 --- a/src/twc.c +++ b/src/twc.c @@ -26,6 +26,7 @@ #include "twc-gui.h" #include "twc-config.h" #include "twc-completion.h" +#include "twc-sqlite.h" #include "twc.h" @@ -42,6 +43,14 @@ weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[]) { weechat_plugin = plugin; + if (twc_sqlite_init() != 0) + { + weechat_printf(NULL, + "%s%s: failed to initialize persistent storage, some " + "data will not be saved", + weechat_prefix("error"), weechat_plugin->name); + } + twc_profile_init(); twc_commands_init(); twc_gui_init(); @@ -63,6 +72,8 @@ weechat_plugin_end(struct t_weechat_plugin *plugin) twc_profile_free_all(); + twc_sqlite_end(); + return WEECHAT_RC_OK; }