Added SQLite persistent storage for friend requests.
This commit is contained in:
parent
b0e91b7b5b
commit
225e576d57
@ -43,6 +43,7 @@ add_library(tox MODULE
|
|||||||
src/twc-list.c
|
src/twc-list.c
|
||||||
src/twc-message-queue.c
|
src/twc-message-queue.c
|
||||||
src/twc-profile.c
|
src/twc-profile.c
|
||||||
|
src/twc-sqlite.c
|
||||||
src/twc-tox-callbacks.c
|
src/twc-tox-callbacks.c
|
||||||
src/twc-utils.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")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter")
|
||||||
|
|
||||||
target_link_libraries(tox toxcore)
|
target_link_libraries(tox toxcore)
|
||||||
|
target_link_libraries(tox sqlite3)
|
||||||
|
|
||||||
# remove lib prefix (libtox.so -> tox.so)
|
# remove lib prefix (libtox.so -> tox.so)
|
||||||
set_target_properties(tox PROPERTIES PREFIX "")
|
set_target_properties(tox PROPERTIES PREFIX "")
|
||||||
|
@ -8,7 +8,7 @@ Installation
|
|||||||
------------
|
------------
|
||||||
> Tox-WeeChat is available in the [AUR][4].
|
> 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
|
$ mkdir build && cd build
|
||||||
$ cmake -DHOME_FOLDER_INSTALL=ON ..
|
$ cmake -DHOME_FOLDER_INSTALL=ON ..
|
||||||
@ -61,6 +61,6 @@ along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
[2]: http://weechat.org
|
[2]: http://weechat.org
|
||||||
[3]: https://travis-ci.org/haavardp/tox-weechat
|
[3]: https://travis-ci.org/haavardp/tox-weechat
|
||||||
[4]: https://aur.archlinux.org/packages/tox-weechat-git
|
[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
|
[6]: https://github.com/irungentoo/toxcore
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "twc-chat.h"
|
#include "twc-chat.h"
|
||||||
#include "twc-friend-request.h"
|
#include "twc-friend-request.h"
|
||||||
#include "twc-bootstrap.h"
|
#include "twc-bootstrap.h"
|
||||||
|
#include "twc-sqlite.h"
|
||||||
#include "twc-utils.h"
|
#include "twc-utils.h"
|
||||||
|
|
||||||
#include "twc-commands.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;
|
struct t_twc_friend_request *request;
|
||||||
if (weechat_strcasecmp(argv[2], "all") == 0)
|
if (weechat_strcasecmp(argv[2], "all") == 0)
|
||||||
{
|
{
|
||||||
int count = 0;
|
struct t_twc_list *requests = twc_sqlite_friend_requests(profile);
|
||||||
while ((request = twc_friend_request_with_index(profile, 0)) != NULL)
|
size_t index;
|
||||||
|
struct t_twc_list_item *item;
|
||||||
|
twc_list_foreach(requests, index, item)
|
||||||
{
|
{
|
||||||
if (accept)
|
if (accept)
|
||||||
twc_friend_request_accept(request);
|
twc_friend_request_accept(item->friend_request);
|
||||||
else
|
else
|
||||||
twc_friend_request_remove(request);
|
twc_friend_request_remove(item->friend_request);
|
||||||
|
|
||||||
++count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
weechat_printf(profile->buffer,
|
weechat_printf(profile->buffer,
|
||||||
"%s%s %d friend requests.",
|
"%s%s %d friend requests.",
|
||||||
weechat_prefix("network"),
|
weechat_prefix("network"),
|
||||||
accept ? "Accepted" : "Declined",
|
accept ? "Accepted" : "Declined",
|
||||||
count);
|
index);
|
||||||
|
|
||||||
return WEECHAT_RC_OK;
|
return WEECHAT_RC_OK;
|
||||||
}
|
}
|
||||||
@ -320,6 +321,8 @@ twc_cmd_friend(void *data, struct t_gui_buffer *buffer,
|
|||||||
else
|
else
|
||||||
twc_friend_request_remove(request);
|
twc_friend_request_remove(request);
|
||||||
|
|
||||||
|
twc_friend_request_free(request);
|
||||||
|
|
||||||
weechat_printf(profile->buffer,
|
weechat_printf(profile->buffer,
|
||||||
"%s%s friend request from %s.",
|
"%s%s friend request from %s.",
|
||||||
weechat_prefix("network"),
|
weechat_prefix("network"),
|
||||||
@ -332,22 +335,16 @@ twc_cmd_friend(void *data, struct t_gui_buffer *buffer,
|
|||||||
|
|
||||||
// /friend requests
|
// /friend requests
|
||||||
else if (argc == 2 && weechat_strcasecmp(argv[1], "requests") == 0)
|
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,
|
weechat_printf(profile->buffer,
|
||||||
"%sPending friend requests:",
|
"%sPending friend requests:",
|
||||||
weechat_prefix("network"));
|
weechat_prefix("network"));
|
||||||
|
|
||||||
|
struct t_twc_list *friend_requests = twc_sqlite_friend_requests(profile);
|
||||||
|
|
||||||
size_t index;
|
size_t index;
|
||||||
struct t_twc_list_item *item;
|
struct t_twc_list_item *item;
|
||||||
twc_list_foreach(profile->friend_requests, index, item)
|
twc_list_foreach(friend_requests, index, item)
|
||||||
{
|
{
|
||||||
// TODO: load short form address length from config
|
// TODO: load short form address length from config
|
||||||
char hex_address[12 + 1];
|
char hex_address[12 + 1];
|
||||||
@ -359,11 +356,14 @@ twc_cmd_friend(void *data, struct t_gui_buffer *buffer,
|
|||||||
"%s[%d] Address: %s\n"
|
"%s[%d] Address: %s\n"
|
||||||
"[%d] Message: %s",
|
"[%d] Message: %s",
|
||||||
weechat_prefix("network"),
|
weechat_prefix("network"),
|
||||||
index, hex_address,
|
item->friend_request->request_id,
|
||||||
index, item->friend_request->message);
|
hex_address,
|
||||||
}
|
item->friend_request->request_id,
|
||||||
|
item->friend_request->message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
twc_friend_request_free_list(friend_requests);
|
||||||
|
|
||||||
return WEECHAT_RC_OK;
|
return WEECHAT_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,7 +388,6 @@ twc_cmd_me(void *data, struct t_gui_buffer *buffer,
|
|||||||
|
|
||||||
return WEECHAT_RC_OK;
|
return WEECHAT_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command /msg callback.
|
* Command /msg callback.
|
||||||
*/
|
*/
|
||||||
@ -704,7 +703,7 @@ twc_commands_init()
|
|||||||
"address: internet address of node to bootstrap with\n"
|
"address: internet address of node to bootstrap with\n"
|
||||||
" port: port of the node\n"
|
" port: port of the node\n"
|
||||||
" Tox ID: Tox ID of the node",
|
" Tox ID: Tox ID of the node",
|
||||||
NULL, twc_cmd_bootstrap, NULL);
|
"connect", twc_cmd_bootstrap, NULL);
|
||||||
|
|
||||||
weechat_hook_command("friend",
|
weechat_hook_command("friend",
|
||||||
"manage friends",
|
"manage friends",
|
||||||
@ -719,7 +718,13 @@ twc_commands_init()
|
|||||||
"requests: list friend requests\n"
|
"requests: list friend requests\n"
|
||||||
" accept: accept friend requests\n"
|
" accept: accept friend requests\n"
|
||||||
" decline: decline 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",
|
weechat_hook_command("me",
|
||||||
"send an action to the current chat",
|
"send an action to the current chat",
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "twc.h"
|
#include "twc.h"
|
||||||
#include "twc-list.h"
|
#include "twc-list.h"
|
||||||
#include "twc-profile.h"
|
#include "twc-profile.h"
|
||||||
|
#include "twc-sqlite.h"
|
||||||
#include "twc-utils.h"
|
#include "twc-utils.h"
|
||||||
|
|
||||||
#include "twc-friend-request.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 uint8_t *client_id,
|
||||||
const char *message)
|
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
|
// create a new request
|
||||||
struct t_twc_friend_request *request
|
struct t_twc_friend_request *request
|
||||||
= malloc(sizeof(struct t_twc_friend_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);
|
memcpy(request->tox_id, client_id, TOX_CLIENT_ID_SIZE);
|
||||||
|
|
||||||
// add to list
|
// 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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -79,8 +73,8 @@ twc_friend_request_accept(struct t_twc_friend_request *request)
|
|||||||
void
|
void
|
||||||
twc_friend_request_remove(struct t_twc_friend_request *request)
|
twc_friend_request_remove(struct t_twc_friend_request *request)
|
||||||
{
|
{
|
||||||
twc_list_remove_with_data(request->profile->friend_requests, request);
|
twc_sqlite_delete_friend_request_with_id(request->profile,
|
||||||
twc_friend_request_free(request);
|
request->request_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,13 +82,9 @@ twc_friend_request_remove(struct t_twc_friend_request *request)
|
|||||||
*/
|
*/
|
||||||
struct t_twc_friend_request *
|
struct t_twc_friend_request *
|
||||||
twc_friend_request_with_index(struct t_twc_profile *profile,
|
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);
|
return twc_sqlite_friend_request_with_id(profile, index);
|
||||||
if (item)
|
|
||||||
return item->friend_request;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -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
|
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;
|
struct t_twc_friend_request *request;
|
||||||
|
while ((request = twc_list_pop(list)))
|
||||||
while ((request = twc_list_pop(profile->friend_requests)))
|
|
||||||
twc_friend_request_free(request);
|
twc_friend_request_free(request);
|
||||||
|
|
||||||
free(profile->friend_requests);
|
free(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include <tox/tox.h>
|
#include <tox/tox.h>
|
||||||
|
|
||||||
|
struct t_twc_list;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a friend request with a Tox ID and a message.
|
* 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;
|
struct t_twc_profile *profile;
|
||||||
|
|
||||||
|
int request_id;
|
||||||
uint8_t tox_id[TOX_CLIENT_ID_SIZE];
|
uint8_t tox_id[TOX_CLIENT_ID_SIZE];
|
||||||
char *message;
|
char *message;
|
||||||
};
|
};
|
||||||
@ -46,13 +49,13 @@ twc_friend_request_remove(struct t_twc_friend_request *request);
|
|||||||
|
|
||||||
struct t_twc_friend_request *
|
struct t_twc_friend_request *
|
||||||
twc_friend_request_with_index(struct t_twc_profile *profile,
|
twc_friend_request_with_index(struct t_twc_profile *profile,
|
||||||
unsigned int index);
|
int64_t index);
|
||||||
|
|
||||||
void
|
void
|
||||||
twc_friend_request_free(struct t_twc_friend_request *request);
|
twc_friend_request_free(struct t_twc_friend_request *request);
|
||||||
|
|
||||||
void
|
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
|
#endif // TOX_WEECHAT_FRIEND_REQUEST_H
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "twc-message-queue.h"
|
#include "twc-message-queue.h"
|
||||||
#include "twc-chat.h"
|
#include "twc-chat.h"
|
||||||
#include "twc-tox-callbacks.h"
|
#include "twc-tox-callbacks.h"
|
||||||
|
#include "twc-sqlite.h"
|
||||||
#include "twc-utils.h"
|
#include "twc-utils.h"
|
||||||
|
|
||||||
#include "twc-profile.h"
|
#include "twc-profile.h"
|
||||||
@ -176,7 +177,6 @@ twc_profile_new(const char *name)
|
|||||||
profile->tox_online = false;
|
profile->tox_online = false;
|
||||||
|
|
||||||
profile->chats = twc_list_new();
|
profile->chats = twc_list_new();
|
||||||
profile->friend_requests = twc_list_new();
|
|
||||||
profile->message_queues = weechat_hashtable_new(32,
|
profile->message_queues = weechat_hashtable_new(32,
|
||||||
WEECHAT_HASHTABLE_INTEGER,
|
WEECHAT_HASHTABLE_INTEGER,
|
||||||
WEECHAT_HASHTABLE_POINTER,
|
WEECHAT_HASHTABLE_POINTER,
|
||||||
@ -213,15 +213,6 @@ twc_profile_load(struct t_twc_profile *profile)
|
|||||||
weechat_prefix("network"), weechat_plugin->name,
|
weechat_prefix("network"), weechat_plugin->name,
|
||||||
profile->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
|
// create Tox
|
||||||
profile->tox = tox_new(NULL);
|
profile->tox = tox_new(NULL);
|
||||||
if (!(profile->tox))
|
if (!(profile->tox))
|
||||||
@ -233,6 +224,7 @@ twc_profile_load(struct t_twc_profile *profile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// try loading Tox saved data
|
// try loading Tox saved data
|
||||||
|
// TODO: this can return -1 even if it does not fail
|
||||||
if (twc_profile_load_data(profile) == -1)
|
if (twc_profile_load_data(profile) == -1)
|
||||||
{
|
{
|
||||||
// we failed to load - set some defaults
|
// we failed to load - set some defaults
|
||||||
@ -247,6 +239,18 @@ twc_profile_load(struct t_twc_profile *profile)
|
|||||||
(uint8_t *)name, strlen(name));
|
(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
|
// bootstrap DHT
|
||||||
// TODO: add count to config
|
// TODO: add count to config
|
||||||
int bootstrap_node_count = 5;
|
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);
|
char *data_path = twc_profile_expanded_data_path(profile);
|
||||||
|
|
||||||
|
twc_sqlite_delete_profile(profile);
|
||||||
twc_profile_free(profile);
|
twc_profile_free(profile);
|
||||||
|
|
||||||
if (delete_data)
|
if (delete_data)
|
||||||
@ -427,7 +432,6 @@ twc_profile_free(struct t_twc_profile *profile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// free things
|
// free things
|
||||||
twc_friend_request_free_profile(profile);
|
|
||||||
twc_chat_free_profile(profile);
|
twc_chat_free_profile(profile);
|
||||||
twc_message_queue_free_profile(profile);
|
twc_message_queue_free_profile(profile);
|
||||||
free(profile->name);
|
free(profile->name);
|
||||||
|
@ -46,7 +46,6 @@ struct t_twc_profile
|
|||||||
struct t_gui_buffer *buffer;
|
struct t_gui_buffer *buffer;
|
||||||
struct t_hook *tox_do_timer;
|
struct t_hook *tox_do_timer;
|
||||||
|
|
||||||
struct t_twc_list *friend_requests;
|
|
||||||
struct t_twc_list *chats;
|
struct t_twc_list *chats;
|
||||||
struct t_hashtable *message_queues;
|
struct t_hashtable *message_queues;
|
||||||
};
|
};
|
||||||
|
430
src/twc-sqlite.c
Normal file
430
src/twc-sqlite.c
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <weechat/weechat-plugin.h>
|
||||||
|
#include <tox/tox.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
#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)
|
||||||
|
}
|
||||||
|
|
58
src/twc-sqlite.h
Normal file
58
src/twc-sqlite.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TWC_SQLITE_H
|
||||||
|
#define TWC_SQLITE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
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
|
11
src/twc.c
11
src/twc.c
@ -26,6 +26,7 @@
|
|||||||
#include "twc-gui.h"
|
#include "twc-gui.h"
|
||||||
#include "twc-config.h"
|
#include "twc-config.h"
|
||||||
#include "twc-completion.h"
|
#include "twc-completion.h"
|
||||||
|
#include "twc-sqlite.h"
|
||||||
|
|
||||||
#include "twc.h"
|
#include "twc.h"
|
||||||
|
|
||||||
@ -42,6 +43,14 @@ weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
weechat_plugin = plugin;
|
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_profile_init();
|
||||||
twc_commands_init();
|
twc_commands_init();
|
||||||
twc_gui_init();
|
twc_gui_init();
|
||||||
@ -63,6 +72,8 @@ weechat_plugin_end(struct t_weechat_plugin *plugin)
|
|||||||
|
|
||||||
twc_profile_free_all();
|
twc_profile_free_all();
|
||||||
|
|
||||||
|
twc_sqlite_end();
|
||||||
|
|
||||||
return WEECHAT_RC_OK;
|
return WEECHAT_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user