diff --git a/.travis.yml b/.travis.yml index d8b54db..191b379 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,19 +3,8 @@ language: c install: - _libsodium_version=0.7.0 - _weechat_version=v1.0 - - _libjansson_version=v2.5 - # install libjansson - - git clone git://github.com/akheron/jansson.git - - pushd jansson - - git checkout tags/${_libjansson_version} - - autoreconf -i - - ./configure --prefix=/usr - - make -j3 - - sudo make install - - popd - - # install libsodium (needed for libtoxcore) + # install libsodium (libtoxcore dependency) - git clone git://github.com/jedisct1/libsodium.git - pushd libsodium - git checkout tags/${_libsodium_version} diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f750f3..2452e80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,24 +32,24 @@ endif() set(INSTALL_PATH "${INSTALL_PATH}" CACHE PATH "Path to install the plugin binary to.") add_library(tox MODULE - src/tox-weechat.c - src/tox-weechat-identities.c - src/tox-weechat-chats.c - src/tox-weechat-friend-requests.c - src/tox-weechat-tox-callbacks.c - src/tox-weechat-commands.c - src/tox-weechat-gui.c - src/tox-weechat-utils.c - src/tox-weechat-config.c - src/tox-weechat-data.c - src/tox-weechat-completion.c - src/tox-weechat-messages.c + src/twc.c + src/twc-bootstrap.c + src/twc-chat.c + src/twc-commands.c + src/twc-completion.c + src/twc-config.c + src/twc-friend-request.c + src/twc-gui.c + src/twc-list.c + src/twc-message-queue.c + src/twc-profile.c + src/twc-tox-callbacks.c + src/twc-utils.c ) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -Werror-implicit-function-declaration -Wno-unused-parameter") target_link_libraries(tox toxcore) -target_link_libraries(tox jansson) # remove lib prefix (libtox.so -> tox.so) set_target_properties(tox PROPERTIES PREFIX "") diff --git a/README.md b/README.md index 83c008c..b2d6713 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Tox-WeeChat =========== -Tox-WeeChat is a C plugin for the [WeeChat][1] chat client that enables it to connect to the [Tox][2] network. It is functional, but fairly limited in features and not intended for general use yet. +Tox-WeeChat is a plugin for [WeeChat][1] that enables it to connect to the [Tox][2] network. It is functional, but currently only intended for experimental use. Current build status: [![Build Status](https://travis-ci.org/haavardp/tox-weechat.svg?branch=master)](https://travis-ci.org/haavardp/tox-weechat) @@ -8,37 +8,35 @@ Installation ------------ > Tox-WeeChat is available in the [AUR][3]. -Tox-WeeChat requires [WeeChat][1] >=1.0, [libjansson][4] >=2.5, and the latest-ish [libtoxcore][5]. 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 and the latest-ish [libtoxcore][4]. 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 .. $ make $ make install -This installs the plugin binary `tox.so` to the recommended location `~/.weechat/plugins`. Omitting the home folder flag installs to `/usr/local/lib/weechat/plugins`. Installing to a custom WeeChat home or similar is achieved by setting `INSTALL_PATH`. +This installs the plugin binary `tox.so` to the recommended location `~/.weechat/plugins`. Without the home folder flag, the binary is placed in `/usr/local/lib/weechat/plugins`. Installing to a custom WeeChat folder or elsewhere is achieved by setting `INSTALL_PATH`. Usage ----- - If the plugin does no automatically load, load it with `/plugin load tox`. You may have to specify the full path to the plugin binary. - - Create a new identity with `/tox create `. The data file is stored in `~/.weechat/tox/` by default. - - Connect your identity to the Tox network with `/tox connect `. + - Create a new profile with `/tox create `. The data file is stored in `~/.weechat/tox/` by default. + - Load your profile and connect to the Tox network with `/tox load `. - Change your name with `/name `. - Get your Tox ID with `/myid`. - To add friends or respond to friend requests, `/help friend` will get you started. - Message a friend with `/msg `. Get their friend number with `/friend list`. -A list of commands is available with `/help -list tox`. +Run `/help -list tox` to get a list of all available commands. -TODO & Implemented features +TODO ---- - - [x] Adding friends, one-to-one chats - - [x] Support multiple identities - - [x] Save friend requests - - [ ] Encrypted save files - - [ ] Tox DNS - - [ ] Group chats (awaiting libtoxcore implementation) - - [ ] Support proxies (TOR) - - [ ] A/V (long term) + - Persist data (friend requests etc.) + - Support encrypted save files + - Tox DNS + - Group chats + - Support proxies (e.g. TOR) + - A/V License --------- @@ -62,6 +60,5 @@ along with Tox-WeeChat. If not, see . [1]: http://weechat.org [2]: http://tox.im [3]: https://aur.archlinux.org/packages/tox-weechat-git -[4]: http://www.digip.org/jansson/ -[5]: https://github.com/irungentoo/toxcore +[4]: https://github.com/irungentoo/toxcore diff --git a/src/tox-weechat-chats.c b/src/tox-weechat-chats.c deleted file mode 100644 index 3241446..0000000 --- a/src/tox-weechat-chats.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * 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 "tox-weechat.h" -#include "tox-weechat-identities.h" -#include "tox-weechat-messages.h" -#include "tox-weechat-utils.h" - -#include "tox-weechat-chats.h" - -const char *tox_weechat_tag_unsent_message = "tox_unsent"; -const char *tox_weechat_tag_sent_message = "tox_sent"; -const char *tox_weechat_tag_received_message = "tox_received"; - -int tox_weechat_buffer_input_callback(void *data, - struct t_gui_buffer *buffer, - const char *input_data); - -int tox_weechat_buffer_close_callback(void *data, - struct t_gui_buffer *buffer); - -void -tox_weechat_chat_add(struct t_tox_weechat_identity *identity, - struct t_tox_weechat_chat *chat) -{ - chat->identity = identity; - - chat->prev_chat = identity->last_chat; - chat->next_chat = NULL; - - if (identity->chats == NULL) - identity->chats = chat; - else - identity->last_chat->next_chat = chat; - - identity->last_chat = chat; -} - -void -tox_weechat_chat_remove(struct t_tox_weechat_chat *chat) -{ - if (chat->prev_chat) - chat->prev_chat->next_chat = chat->next_chat; - if (chat->next_chat) - chat->next_chat->prev_chat = chat->prev_chat; - - if (chat == chat->identity->chats) - chat->identity->chats = chat->next_chat; - if (chat == chat->identity->last_chat) - chat->identity->last_chat = chat->prev_chat; - - free(chat); -} - -void -tox_weechat_chat_refresh(struct t_tox_weechat_chat *chat) -{ - char *name = tox_weechat_get_name_nt(chat->identity->tox, - chat->friend_number); - char *status_message = tox_weechat_get_status_message_nt(chat->identity->tox, - chat->friend_number); - - weechat_buffer_set(chat->buffer, "short_name", name); - weechat_buffer_set(chat->buffer, "title", status_message); - - free(name); - free(status_message); -} - -int -tox_weechat_chat_refresh_timer_callback(void *data, int remaining) -{ - struct t_tox_weechat_chat *chat = data; - tox_weechat_chat_refresh(chat); - - return WEECHAT_RC_OK; -} - -void -tox_weechat_chat_queue_refresh(struct t_tox_weechat_chat *chat) -{ - weechat_hook_timer(1, 0, 1, - tox_weechat_chat_refresh_timer_callback, chat); -} - -struct t_tox_weechat_chat * -tox_weechat_friend_chat_new(struct t_tox_weechat_identity *identity, - int32_t friend_number) -{ - struct t_tox_weechat_chat *chat = malloc(sizeof(*chat)); - chat->friend_number = friend_number; - chat->identity = identity; - - uint8_t client_id[TOX_CLIENT_ID_SIZE]; - tox_get_client_id(identity->tox, friend_number, client_id); - - // TODO: prepend identity name - char buffer_name[TOX_CLIENT_ID_SIZE * 2 + 1]; - tox_weechat_bin2hex(client_id, TOX_CLIENT_ID_SIZE, buffer_name); - - chat->buffer = weechat_buffer_new(buffer_name, - tox_weechat_buffer_input_callback, chat, - tox_weechat_buffer_close_callback, chat); - tox_weechat_chat_refresh(chat); - tox_weechat_chat_add(identity, chat); - - return chat; -} - -struct t_tox_weechat_chat * -tox_weechat_get_existing_friend_chat(struct t_tox_weechat_identity *identity, - int32_t friend_number) -{ - for (struct t_tox_weechat_chat *chat = identity->chats; - chat; - chat = chat->next_chat) - { - if (chat->friend_number == friend_number) - return chat; - } - - return NULL; -} - -struct t_tox_weechat_chat * -tox_weechat_get_friend_chat(struct t_tox_weechat_identity *identity, - int32_t friend_number) -{ - struct t_tox_weechat_chat *chat = tox_weechat_get_existing_friend_chat(identity, friend_number); - - if (chat) - return chat; - else - return tox_weechat_friend_chat_new(identity, friend_number); -} - -struct t_tox_weechat_chat * -tox_weechat_get_chat_for_buffer(struct t_gui_buffer *buffer) -{ - for (struct t_tox_weechat_identity *identity = tox_weechat_identities; - identity; - identity = identity->next_identity) - { - for (struct t_tox_weechat_chat *chat = identity->chats; - chat; - chat = chat->next_chat) - { - if (chat->buffer == buffer) - return chat; - } - } - - return NULL; -} - -void -tox_weechat_chat_print_message(struct t_tox_weechat_chat *chat, - const char *sender, - const char *message, - const char *tags) -{ - weechat_printf_tags(chat->buffer, tags, "%s\t%s", sender, message); -} - -void -tox_weechat_chat_print_action(struct t_tox_weechat_chat *chat, - const char *sender, - const char *message, - const char *tags) -{ - weechat_printf_tags(chat->buffer, tags, - "%s%s %s", - weechat_prefix("action"), - sender, message); -} - -int -tox_weechat_buffer_input_callback(void *data, - struct t_gui_buffer *weechat_buffer, - const char *input_data) -{ - struct t_tox_weechat_chat *chat = data; - int rc = tox_weechat_send_friend_message(chat->identity, - chat->friend_number, - input_data); - - char *name = tox_weechat_get_self_name_nt(chat->identity->tox); - tox_weechat_chat_print_message(chat, "", name, input_data); - free(name); - - return WEECHAT_RC_OK; -} - -int -tox_weechat_buffer_close_callback(void *data, - struct t_gui_buffer *weechat_buffer) -{ - struct t_tox_weechat_chat *chat = data; - tox_weechat_chat_remove(chat); - - return WEECHAT_RC_OK; -} - diff --git a/src/tox-weechat-chats.h b/src/tox-weechat-chats.h deleted file mode 100644 index 9f6711e..0000000 --- a/src/tox-weechat-chats.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2015 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 TOX_WEECHAT_CHATS_H -#define TOX_WEECHAT_CHATS_H - -#include - -#include - -extern const char *tox_weechat_tag_unsent_message; -extern const char *tox_weechat_tag_sent_message; -extern const char *tox_weechat_tag_received_message; - -struct t_tox_weechat_chat -{ - struct t_gui_buffer *buffer; - - int32_t friend_number; - - struct t_tox_weechat_identity *identity; - - struct t_tox_weechat_chat *next_chat; - struct t_tox_weechat_chat *prev_chat; -}; - -struct t_tox_weechat_chat * -tox_weechat_get_friend_chat(struct t_tox_weechat_identity *identity, - int32_t friend_number); - -struct t_tox_weechat_chat * -tox_weechat_get_existing_friend_chat(struct t_tox_weechat_identity *identity, - int32_t friend_number); - -struct t_tox_weechat_chat * -tox_weechat_get_chat_for_buffer(struct t_gui_buffer *target_buffer); - -void tox_weechat_chat_print_message(struct t_tox_weechat_chat *chat, - const char *sender, - const char *message, - const char *tags); - -void tox_weechat_chat_print_action(struct t_tox_weechat_chat *chat, - const char *sender, - const char *message, - const char *tags); - -void -tox_weechat_chat_refresh(struct t_tox_weechat_chat *chat); - -void -tox_weechat_chat_queue_refresh(struct t_tox_weechat_chat *chat); - -#endif // TOX_WEECHAT_CHATS_H diff --git a/src/tox-weechat-commands.c b/src/tox-weechat-commands.c deleted file mode 100644 index b5bf666..0000000 --- a/src/tox-weechat-commands.c +++ /dev/null @@ -1,762 +0,0 @@ -/* - * 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 "tox-weechat.h" -#include "tox-weechat-utils.h" -#include "tox-weechat-identities.h" -#include "tox-weechat-chats.h" -#include "tox-weechat-friend-requests.h" - -#include "tox-weechat-commands.h" - -// TODO: something -extern int -tox_weechat_bootstrap_tox(Tox *tox, char *address, uint16_t port, char *public_key); - -int -tox_weechat_cmd_bootstrap(void *data, struct t_gui_buffer *buffer, - int argc, char **argv, char **argv_eol) -{ - struct t_tox_weechat_identity *identity = tox_weechat_identity_for_buffer(buffer); - if (!identity) - { - weechat_printf(NULL, - "%s%s: command \"%s\" must be executed on a Tox buffer", - weechat_prefix("error"), - weechat_plugin->name, - argv[0]); - return WEECHAT_RC_OK; - } - - if (argc != 4) - return WEECHAT_RC_ERROR; - - char *address = argv[1]; - uint16_t port = atoi(argv[2]); - char *tox_address = argv[3]; - - if (!tox_weechat_bootstrap_tox(identity->tox, address, port, tox_address)) - { - weechat_printf(identity->buffer, - "%sInvalid arguments for bootstrap.", - weechat_prefix("error")); - } - - return WEECHAT_RC_OK; -} - -int -tox_weechat_cmd_friend(void *data, struct t_gui_buffer *buffer, - int argc, char **argv, char **argv_eol) -{ - struct t_tox_weechat_identity *identity = tox_weechat_identity_for_buffer(buffer); - if (!identity) - { - weechat_printf(NULL, - "%s%s: command \"%s\" must be executed on a Tox buffer", - weechat_prefix("error"), - weechat_plugin->name, - argv[0]); - return WEECHAT_RC_OK; - } - - if (argc == 1 || (argc == 2 && weechat_strcasecmp(argv[1], "list") == 0)) - { - size_t friend_count = tox_count_friendlist(identity->tox); - int32_t friend_numbers[friend_count]; - tox_get_friendlist(identity->tox, friend_numbers, friend_count); - - if (friend_count == 0) - { - weechat_printf(identity->buffer, - "%sYou have no friends :(", - weechat_prefix("network")); - return WEECHAT_RC_OK; - } - - weechat_printf(identity->buffer, - "%s[#] Name [client ID]", - weechat_prefix("network")); - - for (size_t i = 0; i < friend_count; ++i) - { - int32_t friend_number = friend_numbers[i]; - char *name = tox_weechat_get_name_nt(identity->tox, friend_number); - - uint8_t client_id[TOX_CLIENT_ID_SIZE]; - tox_get_client_id(identity->tox, friend_number, client_id); - char hex_address[TOX_CLIENT_ID_SIZE * 2 + 1]; - tox_weechat_bin2hex(client_id, - TOX_CLIENT_ID_SIZE, - hex_address); - - weechat_printf(identity->buffer, - "%s[%d] %s [%s]", - weechat_prefix("network"), - friend_number, name, hex_address); - - free(name); - } - - return WEECHAT_RC_OK; - } - - else if (argc >= 3 && (weechat_strcasecmp(argv[1], "add") == 0)) - { - char address[TOX_FRIEND_ADDRESS_SIZE]; - tox_weechat_hex2bin(argv[2], TOX_FRIEND_ADDRESS_SIZE * 2, address); - - char *message; - if (argc == 3 || strlen(argv_eol[3]) == 0) - message = "Hi! Please add me on Tox!"; - else - message = argv_eol[3]; - - int32_t result = tox_add_friend(identity->tox, - (uint8_t *)address, - (uint8_t *)message, - strlen(message)); - - switch (result) - { - case TOX_FAERR_TOOLONG: - weechat_printf(identity->buffer, - "%sFriend request message too long! Try again.", - weechat_prefix("error")); - break; - case TOX_FAERR_ALREADYSENT: - weechat_printf(identity->buffer, - "%sYou have already sent a friend request to that address.", - weechat_prefix("error")); - break; - case TOX_FAERR_OWNKEY: - weechat_printf(identity->buffer, - "%sYou can't add yourself as a friend.", - weechat_prefix("error")); - break; - case TOX_FAERR_BADCHECKSUM: - weechat_printf(identity->buffer, - "%sInvalid friend address - try again.", - weechat_prefix("error")); - break; - case TOX_FAERR_NOMEM: - weechat_printf(identity->buffer, - "%sCould not add friend (out of memory).", - weechat_prefix("error")); - break; - case TOX_FAERR_UNKNOWN: - case TOX_FAERR_SETNEWNOSPAM: - case TOX_FAERR_NOMESSAGE: - weechat_printf(identity->buffer, - "%sCould not add friend (unknown error).", - weechat_prefix("error")); - break; - default: - weechat_printf(identity->buffer, - "%sFriend request sent!", - weechat_prefix("network")); - break; - } - - return WEECHAT_RC_OK; - } - - else if (argc == 3 && (weechat_strcasecmp(argv[1], "remove") == 0)) - { - char *endptr; - unsigned long friend_number = strtoul(argv[2], &endptr, 10); - - if (endptr == argv[2] || !tox_friend_exists(identity->tox, friend_number)) - { - weechat_printf(identity->buffer, - "%sInvalid friend number.", - weechat_prefix("error")); - return WEECHAT_RC_OK; - } - - char *name = tox_weechat_get_name_nt(identity->tox, friend_number); - if (tox_del_friend(identity->tox, friend_number) == 0) - { - weechat_printf(identity->buffer, - "%sRemoved %s from friend list.", - weechat_prefix("network"), name); - } - else - { - weechat_printf(identity->buffer, - "%sCould not remove friend!", - weechat_prefix("error")); - } - - free(name); - - return WEECHAT_RC_OK; - } - - else if (argc == 3 && - (weechat_strcasecmp(argv[1], "accept") == 0 - || weechat_strcasecmp(argv[1], "decline") == 0)) - { - int accept = weechat_strcasecmp(argv[1], "accept") == 0; - - struct t_tox_weechat_friend_request *request; - if (weechat_strcasecmp(argv[2], "all") == 0) - { - int count = 0; - while ((request = tox_weechat_friend_request_with_num(identity, 0)) != NULL) - { - if (accept) - tox_weechat_accept_friend_request(request); - else - tox_weechat_decline_friend_request(request); - - ++count; - } - - weechat_printf(identity->buffer, - "%s%s %d friend requests.", - weechat_prefix("network"), - accept ? "Accepted" : "Declined", - count); - - return WEECHAT_RC_OK; - } - else - { - char *endptr; - unsigned long num = strtoul(argv[2], &endptr, 10); - if (endptr == argv[2] || (request = tox_weechat_friend_request_with_num(identity, num)) == NULL) - { - weechat_printf(identity->buffer, - "%sInvalid friend request ID.", - weechat_prefix("error")); - return WEECHAT_RC_OK; - } - - char hex_address[TOX_CLIENT_ID_SIZE * 2 + 1]; - tox_weechat_bin2hex(request->tox_id, - TOX_CLIENT_ID_SIZE, - hex_address); - - if (accept) - tox_weechat_accept_friend_request(request); - else - tox_weechat_decline_friend_request(request); - - weechat_printf(identity->buffer, - "%s%s friend request from %s.", - weechat_prefix("network"), - accept ? "Accepted" : "Declined", - hex_address); - - return WEECHAT_RC_OK; - } - } - - else if (argc == 2 && weechat_strcasecmp(argv[1], "requests") == 0) - { - if (identity->friend_requests == NULL) - { - weechat_printf(identity->buffer, - "%sNo pending friend requests :(", - weechat_prefix("network")); - } - else - { - weechat_printf(identity->buffer, - "%sPending friend requests:", - weechat_prefix("network")); - - int num = 0; - for (struct t_tox_weechat_friend_request *request = identity->friend_requests; - request; - request = request->next_request) - { - char hex_address[TOX_CLIENT_ID_SIZE * 2 + 1]; - tox_weechat_bin2hex(request->tox_id, - TOX_CLIENT_ID_SIZE, - hex_address); - - weechat_printf(identity->buffer, - "%s[%d] Address: %s\n" - "[%d] Message: %s", - weechat_prefix("network"), - num, hex_address, - num, request->message); - - ++num; - } - } - - return WEECHAT_RC_OK; - } - - return WEECHAT_RC_ERROR; -} - -int -tox_weechat_cmd_me(void *data, struct t_gui_buffer *buffer, - int argc, char **argv, char **argv_eol) -{ - if (argc == 1) - return WEECHAT_RC_ERROR; - - struct t_tox_weechat_identity *identity = tox_weechat_identity_for_buffer(buffer); - struct t_tox_weechat_chat *chat = tox_weechat_get_chat_for_buffer(buffer); - - if (!chat) - { - weechat_printf(NULL, - "%s%s: command \"%s\" must be executed in a chat buffer", - weechat_prefix("error"), - weechat_plugin->name, - argv[0]); - return WEECHAT_RC_OK; - } - - tox_send_action(identity->tox, - chat->friend_number, - (uint8_t *)argv_eol[1], - strlen(argv_eol[1])); - - char *name = tox_weechat_get_self_name_nt(identity->tox); - tox_weechat_chat_print_action(chat, "", name, argv_eol[1]); - - free(name); - - return WEECHAT_RC_OK; -} - -int -tox_weechat_cmd_msg(void *data, struct t_gui_buffer *buffer, - int argc, char **argv, char **argv_eol) -{ - if (argc == 1) - return WEECHAT_RC_ERROR; - - struct t_tox_weechat_identity *identity = tox_weechat_identity_for_buffer(buffer); - if (!identity) - { - weechat_printf(NULL, - "%s%s: command \"%s\" must be executed in a Tox buffer", - weechat_prefix("error"), - weechat_plugin->name, - argv[0]); - return WEECHAT_RC_OK; - } - - char *endptr; - unsigned long friend_number = strtoul(argv[1], &endptr, 10); - - if (endptr == argv[1] || !tox_friend_exists(identity->tox, friend_number)) - { - weechat_printf(identity->buffer, - "%sInvalid friend number.", - weechat_prefix("error")); - return WEECHAT_RC_OK; - } - - struct t_tox_weechat_chat *chat = tox_weechat_get_friend_chat(identity, friend_number); - if (argc >= 3) - { - tox_send_message(identity->tox, - friend_number, - (uint8_t *)argv_eol[2], - strlen(argv_eol[2])); - char *name = tox_weechat_get_self_name_nt(identity->tox); - tox_weechat_chat_print_message(chat, "", name, argv_eol[2]); - free(name); - } - - return WEECHAT_RC_OK; -} - -int -tox_weechat_cmd_myid(void *data, struct t_gui_buffer *buffer, - int argc, char **argv, char **argv_eol) -{ - struct t_tox_weechat_identity *identity = tox_weechat_identity_for_buffer(buffer); - if (!identity) - { - weechat_printf(NULL, - "%s%s: command \"%s\" must be executed in a Tox buffer", - weechat_prefix("error"), - weechat_plugin->name, - argv[0]); - return WEECHAT_RC_OK; - } - - uint8_t address[TOX_FRIEND_ADDRESS_SIZE]; - tox_get_address(identity->tox, address); - - char address_str[TOX_FRIEND_ADDRESS_SIZE * 2 + 1]; - tox_weechat_bin2hex(address, TOX_FRIEND_ADDRESS_SIZE, address_str); - - weechat_printf(identity->buffer, - "%sYour Tox address: %s", - weechat_prefix("network"), - address_str); - - return WEECHAT_RC_OK; -} - -int -tox_weechat_cmd_name(void *data, struct t_gui_buffer *buffer, - int argc, char **argv, char **argv_eol) -{ - if (argc == 1) - return WEECHAT_RC_ERROR; - - struct t_tox_weechat_identity *identity = tox_weechat_identity_for_buffer(buffer); - if (!identity) - { - weechat_printf(NULL, - "%s%s: command \"%s\" must be executed on a Tox buffer", - weechat_prefix("error"), - weechat_plugin->name, - argv[0]); - return WEECHAT_RC_OK; - } - - char *name = argv_eol[1]; - - int result = tox_set_name(identity->tox, (uint8_t *)name, strlen(name)); - if (result == -1) - { - weechat_printf(identity->buffer, - "%s%s", - weechat_prefix("error"), - "Could not change name."); - return WEECHAT_RC_OK; - } - - weechat_bar_item_update("input_prompt"); - - weechat_printf(identity->buffer, - "%sYou are now known as %s", - weechat_prefix("network"), - name); - - for (struct t_tox_weechat_chat *chat = identity->chats; - chat; - chat = chat->next_chat) - { - weechat_printf(chat->buffer, - "%sYou are now known as %s", - weechat_prefix("network"), - name); - } - - return WEECHAT_RC_OK; -} - -int -tox_weechat_cmd_status(void *data, struct t_gui_buffer *buffer, - int argc, char **argv, char **argv_eol) -{ - if (argc != 2) - return WEECHAT_RC_ERROR; - - struct t_tox_weechat_identity *identity = tox_weechat_identity_for_buffer(buffer); - if (!identity) - { - weechat_printf(NULL, - "%s%s: command \"%s\" must be executed in a Tox buffer", - weechat_prefix("error"), - weechat_plugin->name, - argv[0]); - return WEECHAT_RC_OK; - } - - TOX_USERSTATUS status = TOX_USERSTATUS_INVALID; - if (weechat_strcasecmp(argv[1], "online") == 0) - status = TOX_USERSTATUS_NONE; - else if (weechat_strcasecmp(argv[1], "busy") == 0) - status = TOX_USERSTATUS_BUSY; - else if (weechat_strcasecmp(argv[1], "away") == 0) - status = TOX_USERSTATUS_AWAY; - - if (status == TOX_USERSTATUS_INVALID) - return WEECHAT_RC_ERROR; - - tox_set_user_status(identity->tox, status); - weechat_bar_item_update("away"); - - return WEECHAT_RC_OK; -} - -int -tox_weechat_cmd_statusmsg(void *data, struct t_gui_buffer *buffer, - int argc, char **argv, char **argv_eol) -{ - struct t_tox_weechat_identity *identity = tox_weechat_identity_for_buffer(buffer); - if (!identity) - { - weechat_printf(NULL, - "%s%s: command \"%s\" must be executed in a Tox buffer", - weechat_prefix("error"), - weechat_plugin->name, - argv[0]); - return WEECHAT_RC_OK; - } - - char *message = argc > 1 ? argv_eol[1] : " "; - - int result = tox_set_status_message(identity->tox, - (uint8_t *)message, - strlen(message)); - if (result == -1) - { - weechat_printf(identity->buffer, - "%s%s", - weechat_prefix("error"), - "Could not set status message."); - } - - return WEECHAT_RC_OK; -} - -int -tox_weechat_cmd_tox(void *data, struct t_gui_buffer *buffer, - int argc, char **argv, char **argv_eol) -{ - if (argc == 1 || (argc == 2 && weechat_strcasecmp(argv[1], "list") == 0)) - { - weechat_printf(NULL, - "%sAll Tox identities:", - weechat_prefix("network")); - for (struct t_tox_weechat_identity *identity = tox_weechat_identities; - identity; - identity = identity->next_identity) - { - weechat_printf(NULL, - "%s%s", - weechat_prefix("network"), - identity->name); - } - - return WEECHAT_RC_OK; - } - - else if (argc == 3 && (weechat_strcasecmp(argv[1], "create") == 0)) - { - char *name = argv[2]; - - if (tox_weechat_identity_name_search(name)) - { - weechat_printf(NULL, - "%s%s: Identity \"%s\" already exists!", - weechat_prefix("error"), - weechat_plugin->name, - name); - return WEECHAT_RC_OK; - } - - struct t_tox_weechat_identity *identity = tox_weechat_identity_new(name); - weechat_printf(NULL, - "%s%s: Identity \"%s\" created!", - weechat_prefix("network"), - weechat_plugin->name, - identity->name); - - return WEECHAT_RC_OK; - } - - else if (argc >= 3 && argc <= 4 - && (weechat_strcasecmp(argv[1], "delete") == 0)) - { - char *name = argv[2]; - char *flag = argv[3]; - - struct t_tox_weechat_identity *identity; - if ((identity = tox_weechat_identity_name_search(name))) - { - if (argc == 4 && strcmp(flag, "-keepdata") == 0) - { - tox_weechat_identity_delete(identity, false); - } - else if (argc == 4 && strcmp(flag, "-yes") == 0) - { - tox_weechat_identity_delete(identity, true); - } - else - { - weechat_printf(NULL, - "%s%s: You must confirm deletion with either " - "\"-keepdata\" or \"-yes\" (see /help tox)", - weechat_prefix("error"), - weechat_plugin->name); - return WEECHAT_RC_OK; - } - - weechat_printf(NULL, - "%s%s: Identity \"%s\" has been deleted.", - weechat_prefix("error"), - weechat_plugin->name, - name); - } - else - { - weechat_printf(NULL, - "%s%s: Identity \"%s\" does not exist.", - weechat_prefix("error"), - weechat_plugin->name, - identity->name); - } - - return WEECHAT_RC_OK; - } - - else if (argc >= 3 && (weechat_strcasecmp(argv[1], "connect") == 0)) - { - for (int i = 2; i < argc; ++i) - { - char *name = argv[i]; - struct t_tox_weechat_identity *identity = tox_weechat_identity_name_search(name); - if (!identity) - { - weechat_printf(NULL, - "%s%s: Identity \"%s\" does not exist.", - weechat_prefix("error"), - weechat_plugin->name, - name); - } - else - { - tox_weechat_identity_connect(identity); - } - } - - return WEECHAT_RC_OK; - } - - else if (argc >= 3 && (weechat_strcasecmp(argv[1], "disconnect") == 0)) - { - for (int i = 2; i < argc; ++i) - { - char *name = argv[i]; - struct t_tox_weechat_identity *identity = tox_weechat_identity_name_search(name); - if (!identity) - { - weechat_printf(NULL, - "%s%s: Identity \"%s\" does not exist.", - weechat_prefix("error"), - weechat_plugin->name, - name); - } - else - { - tox_weechat_identity_disconnect(identity); - } - } - - return WEECHAT_RC_OK; - } - - return WEECHAT_RC_ERROR; -} - -void -tox_weechat_commands_init() -{ - weechat_hook_command("bootstrap", - "bootstrap the Tox DHT", - "
", - " address: internet address of node to bootstrap with\n" - " port: port of the node\n" - "client id: Tox client of the node", - NULL, tox_weechat_cmd_bootstrap, NULL); - - weechat_hook_command("friend", - "manage friends", - "list" - " || add
[]" - " || remove " - " || requests" - " || accept |all" - " || decline |all", - " list: list all friends\n" - " add: add a friend by their public Tox address\n" - "requests: list friend requests\n" - " accept: accept friend requests\n" - " decline: decline friend requests\n", - NULL, tox_weechat_cmd_friend, NULL); - - weechat_hook_command("me", - "send an action to the current chat", - "", - "message: message to send", - NULL, tox_weechat_cmd_me, NULL); - - weechat_hook_command("msg", - "send a message to a Tox friend", - " []", - " id: friend number of the person to message\n" - "message: message to send", - NULL, tox_weechat_cmd_msg, NULL); - - weechat_hook_command("myid", - "get your Tox ID to give to friends", - "", "", - NULL, tox_weechat_cmd_myid, NULL); - - weechat_hook_command("name", - "change your Tox name", - "", - "name: your new name", - NULL, tox_weechat_cmd_name, NULL); - - weechat_hook_command("status", - "change your Tox status", - "online|busy|away", - "", - NULL, tox_weechat_cmd_status, NULL); - - weechat_hook_command("statusmsg", - "change your Tox status message", - "[]", - "message: your new status message", - NULL, tox_weechat_cmd_statusmsg, NULL); - - weechat_hook_command("tox", - "manage Tox identities", - "list" - " || create " - " || delete -yes|-keepdata" - " || connect [...]" - " || disconnect [...]", - " list: list all Tox identity\n" - " create: create a new Tox identity\n" - " delete: delete a Tox identity; requires either " - "-yes to confirm deletion or -keepdata to delete the " - "identity but keep the Tox data file\n" - " connect: connect a Tox identity to the network\n" - "disconnect: connect a Tox identity to the network\n", - "list" - " || create" - " || delete %(tox_identities) -yes|-keepdata" - " || connect %(tox_disconnected_identities)|%*" - " || disconnect %(tox_connected_identities)|%*", - tox_weechat_cmd_tox, NULL); -} diff --git a/src/tox-weechat-completion.c b/src/tox-weechat-completion.c deleted file mode 100644 index 657b618..0000000 --- a/src/tox-weechat-completion.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include - -#include - -#include "tox-weechat.h" -#include "tox-weechat-identities.h" - -#include "tox-weechat-completion.h" - -enum -{ - TOX_WEECHAT_ALL_IDENTITIES, - TOX_WEECHAT_CONNECTED_IDENTITIES, - TOX_WEECHAT_DISCONNECTED_IDENTITIES, -}; - -int -tox_weechat_completion_identity(void *data, - const char *completion_item, - struct t_gui_buffer *buffer, - struct t_gui_completion *completion) -{ - int flag = (int)(intptr_t)data; - - for (struct t_tox_weechat_identity *identity = tox_weechat_identities; - identity; - identity = identity->next_identity) - { - if (flag == TOX_WEECHAT_ALL_IDENTITIES - || (flag == TOX_WEECHAT_CONNECTED_IDENTITIES && identity->tox != NULL) - || (flag == TOX_WEECHAT_DISCONNECTED_IDENTITIES && identity->tox == NULL)) - { - weechat_hook_completion_list_add(completion, - identity->name, - 0, - WEECHAT_LIST_POS_SORT); - } - } - - return WEECHAT_RC_OK; -} - -void -tox_weechat_completion_init() -{ - weechat_hook_completion("tox_identities", - "identity", - tox_weechat_completion_identity, - (void *)(intptr_t)TOX_WEECHAT_ALL_IDENTITIES); - weechat_hook_completion("tox_connected_identities", - "identity", - tox_weechat_completion_identity, - (void *)(intptr_t)TOX_WEECHAT_CONNECTED_IDENTITIES); - weechat_hook_completion("tox_disconnected_identities", - "identity", - tox_weechat_completion_identity, - (void *)(intptr_t)TOX_WEECHAT_DISCONNECTED_IDENTITIES); -} diff --git a/src/tox-weechat-completion.h b/src/tox-weechat-completion.h deleted file mode 100644 index 6122d8a..0000000 --- a/src/tox-weechat-completion.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef TOX_WEECHAT_COMPLETION_H -#define TOX_WEECHAT_COMPLETION_H - -void -tox_weechat_completion_init(); - -#endif // TOX_WEECHAT_COMPLETION_H diff --git a/src/tox-weechat-config.c b/src/tox-weechat-config.c deleted file mode 100644 index a8e3ec2..0000000 --- a/src/tox-weechat-config.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * 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 "tox-weechat.h" -#include "tox-weechat-identities.h" - -#include "tox-weechat-config.h" - -struct t_config_file *tox_weechat_config_file = NULL; -struct t_config_section *tox_weechat_config_section_identity = NULL; - -char *tox_weechat_identity_option_names[TOX_WEECHAT_IDENTITY_NUM_OPTIONS] = -{ - "save_file", - "autoconnect", - "max_friend_requests", -}; - -char *tox_weechat_identity_option_defaults[TOX_WEECHAT_IDENTITY_NUM_OPTIONS] = -{ - "%h/tox/%n", - "off", - "100", -}; - -int -tox_weechat_config_identity_option_search(const char *option_name) -{ - for (int i = 0; i < TOX_WEECHAT_IDENTITY_NUM_OPTIONS; ++i) - { - if (strcmp(tox_weechat_identity_option_names[i], option_name) == 0) - return i; - } - - return -1; -} - -int -tox_weechat_config_identity_read_callback(void *data, - struct t_config_file *config_file, - struct t_config_section *section, - const char *option_name, - const char *value) -{ - int rc = WEECHAT_CONFIG_OPTION_SET_ERROR; - - if (option_name) - { - char *dot_pos = strrchr(option_name, '.'); - if (dot_pos) - { - char *identity_name = weechat_strndup(option_name, - dot_pos-option_name); - char *option_name = dot_pos + 1; - if (identity_name) - { - int option_index = tox_weechat_config_identity_option_search(option_name); - if (option_index >= 0) - { - struct t_tox_weechat_identity *identity = - tox_weechat_identity_name_search(identity_name); - - if (!identity) - identity = tox_weechat_identity_new(identity_name); - - if (identity) - { - rc = weechat_config_option_set(identity->options[option_index], - value, 1); - } - else - { - weechat_printf(NULL, - "%s%s: error creating identity \"%s\"", - weechat_prefix("error"), - weechat_plugin->name, - identity_name); - } - } - - free(identity_name); - } - } - } - - if (rc == WEECHAT_CONFIG_OPTION_SET_ERROR) - { - weechat_printf(NULL, - "%s%s: error creating identity option \"%s\"", - weechat_prefix("error"), - weechat_plugin->name, - option_name); - } - - return rc; -} - -int -tox_weechat_config_identity_write_callback(void *data, - struct t_config_file *config_file, - const char *section_name) -{ - if (!weechat_config_write_line (config_file, section_name, NULL)) - return WEECHAT_CONFIG_WRITE_ERROR; - - for (struct t_tox_weechat_identity *identity = tox_weechat_identities; - identity; - identity = identity->next_identity) - { - for (int i = 0; i < TOX_WEECHAT_IDENTITY_NUM_OPTIONS; ++i) - { - if (!weechat_config_write_option(tox_weechat_config_file, - identity->options[i])) - { - return WEECHAT_CONFIG_WRITE_ERROR; - } - } - } - - return WEECHAT_CONFIG_WRITE_OK; -} - -int -tox_weechat_config_identity_check_value_callback(void *data, - struct t_config_option *option, - const char *value) -{ - return 1; // ok, 0 not ok -} - -void -tox_weechat_config_identity_change_callback(void *data, - struct t_config_option *option) -{ -} - -void -tox_weechat_config_init() -{ - - tox_weechat_config_file = weechat_config_new("tox", NULL, NULL); - - tox_weechat_config_section_identity = - weechat_config_new_section(tox_weechat_config_file, "identity", - 0, 0, - tox_weechat_config_identity_read_callback, NULL, - tox_weechat_config_identity_write_callback, NULL, - NULL, NULL, - NULL, NULL, - NULL, NULL); -} - -struct t_config_option * -tox_weechat_config_init_option(int option_index, const char *option_name) -{ - switch (option_index) - { - case TOX_WEECHAT_IDENTITY_OPTION_AUTOCONNECT: - return weechat_config_new_option( - tox_weechat_config_file, tox_weechat_config_section_identity, - option_name, "boolean", - "automatically connect to the Tox network when WeeChat starts", - NULL, 0, 0, - tox_weechat_identity_option_defaults[option_index], - NULL, - 0, - tox_weechat_config_identity_check_value_callback, NULL, - tox_weechat_config_identity_change_callback, NULL, - NULL, NULL); - case TOX_WEECHAT_IDENTITY_OPTION_MAX_FRIEND_REQUESTS: - return weechat_config_new_option( - tox_weechat_config_file, tox_weechat_config_section_identity, - option_name, "integer", - "maximum amount of friend requests to retain before dropping " - "new ones", - NULL, 0, INT_MAX, - tox_weechat_identity_option_defaults[option_index], - NULL, - 0, - tox_weechat_config_identity_check_value_callback, NULL, - tox_weechat_config_identity_change_callback, NULL, - NULL, NULL); - case TOX_WEECHAT_IDENTITY_OPTION_SAVEFILE: - return weechat_config_new_option( - tox_weechat_config_file, tox_weechat_config_section_identity, - option_name, "string", - "path to Tox data file (\"%h\" will be replaced by WeeChat " - "home, \"%n\" by the identity name); will be created if it does " - "not exist.", - NULL, 0, 0, - tox_weechat_identity_option_defaults[option_index], - NULL, - 0, - tox_weechat_config_identity_check_value_callback, NULL, - tox_weechat_config_identity_change_callback, NULL, - NULL, NULL); - default: - return NULL; - } -} - -void -tox_weechat_config_init_identity(struct t_tox_weechat_identity *identity) -{ - for (int i = 0; i < TOX_WEECHAT_IDENTITY_NUM_OPTIONS; ++i) - { - // length: name + . + option + \0 - size_t length = strlen(identity->name) + 1 - + strlen(tox_weechat_identity_option_names[i]) + 1; - - char *option_name = malloc(sizeof(*option_name) * length); - if (option_name) - { - snprintf(option_name, length, "%s.%s", - identity->name, - tox_weechat_identity_option_names[i]); - - identity->options[i] = tox_weechat_config_init_option(i, option_name); - free (option_name); - } - } -} - -int -tox_weechat_config_read() -{ - return weechat_config_read(tox_weechat_config_file); -} - -int -tox_weechat_config_write() -{ - return weechat_config_write(tox_weechat_config_file); -} diff --git a/src/tox-weechat-data.c b/src/tox-weechat-data.c deleted file mode 100644 index 43f708a..0000000 --- a/src/tox-weechat-data.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * 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 . - */ - - -/////// TODO ////////// -// get rid of data from deleted/nonexisting identities so it doesn't accumulate -/////////////////////// - -#include -#include -#include - -#include "tox-weechat.h" -#include "tox-weechat-identities.h" -#include "tox-weechat-friend-requests.h" -#include "tox-weechat-messages.h" -#include "tox-weechat-utils.h" - -#include "tox-weechat-data.h" - -#define TOX_WEECHAT_JSON_CONFIG_PATH "%h/tox/data.json" - -const char *tox_weechat_json_key_friend_requests = "friend_requests"; -const char *tox_weechat_json_friend_request_key_client_id = "client_id"; -const char *tox_weechat_json_friend_request_key_message = "message"; -const char *tox_weechat_json_key_unsent_messages = "unsent_messages"; -const char *tox_weechat_json_unsent_messages_key_recipient_id = "recipient_id"; - -json_t *tox_weechat_json_data = NULL; - -/** - * Return the full path to the JSON data file. - */ -char * -tox_weechat_json_data_file_path() -{ - const char *weechat_dir = weechat_info_get("weechat_dir", NULL); - return weechat_string_replace(TOX_WEECHAT_JSON_CONFIG_PATH, "%h", weechat_dir); -} - -/** - * Return the key used for an identity in the JSON data file. Must be freed. - */ -char * -tox_weechat_json_get_identity_key(struct t_tox_weechat_identity *identity) -{ - uint8_t address[TOX_FRIEND_ADDRESS_SIZE]; - tox_get_address(identity->tox, address); - - char *hex_id = malloc(TOX_CLIENT_ID_SIZE * 2 + 1); - tox_weechat_bin2hex(address, TOX_CLIENT_ID_SIZE, hex_id); - - return hex_id; -} - -/** - * Save an identity's friend requests into a json array. - */ -json_t * -tox_weechat_data_friend_requests_json(struct t_tox_weechat_identity *identity) -{ - json_t *friend_request_array = json_array(); - if (!friend_request_array) - return NULL; - - for (struct t_tox_weechat_friend_request *request = identity->friend_requests; - request; - request = request->next_request) - { - char hex_id[TOX_CLIENT_ID_SIZE * 2 + 1]; - tox_weechat_bin2hex(request->tox_id, TOX_CLIENT_ID_SIZE, hex_id); - - json_t *json_request = json_object(); - json_t *json_id = json_string(hex_id); - json_t *json_message = json_string(request->message); - if (!json_request || !json_id || !json_message) - break; - - json_object_set_new(json_request, - tox_weechat_json_friend_request_key_client_id, - json_id); - - json_object_set_new(json_request, - tox_weechat_json_friend_request_key_message, - json_message); - - json_array_append_new(friend_request_array, json_request); - } - - return friend_request_array; -} - -/** - * Save an identity's unsent messages into a json object. - */ -json_t * -tox_weechat_data_unsent_messages_json(struct t_tox_weechat_identity *identity) -{ - json_t *messages_object = json_object(); - if (!messages_object) - return NULL; - - for (struct t_tox_weechat_unsent_message_recipient *recipient = identity->unsent_message_recipients; - recipient; - recipient = recipient->next_recipient) - { - if (!(recipient->unsent_messages)) - continue; - - char hex_id[TOX_CLIENT_ID_SIZE * 2 + 1]; - tox_weechat_bin2hex(recipient->recipient_id, TOX_CLIENT_ID_SIZE, hex_id); - - json_t *json_messages = json_array(); - if (!json_messages) - break; - - for (struct t_tox_weechat_unsent_message *message = recipient->unsent_messages; - message; - message = message->next_message) - { - json_t *json_message = json_string(message->message); - if (!json_message) - break; - - json_array_append_new(json_messages, json_message); - } - - json_object_set_new(messages_object, hex_id, json_messages); - } - - return messages_object; -} - -/** - * Save an identity's data. - */ -void -tox_weechat_data_identity_save(struct t_tox_weechat_identity *identity) -{ - json_t *json_data = json_object(); - if (!json_data) - return; - - json_t *friend_requests = tox_weechat_data_friend_requests_json(identity); - json_object_set_new(json_data, - tox_weechat_json_key_friend_requests, - friend_requests); - - json_t *unsent_messages = tox_weechat_data_unsent_messages_json(identity); - json_object_set_new(json_data, - tox_weechat_json_key_unsent_messages, - unsent_messages); - - char *identity_key = tox_weechat_json_get_identity_key(identity); - json_object_set_new(tox_weechat_json_data, identity_key, json_data); - free(identity_key); -} - -/** - * Load friend requests from a json array. - */ -void -tox_weechat_data_load_friend_requests(struct t_tox_weechat_identity *identity, - json_t *friend_requests) -{ - tox_weechat_friend_request_free_identity(identity); - - size_t index; - json_t *json_request; - json_array_foreach(friend_requests, index, json_request) - { - char client_id[TOX_CLIENT_ID_SIZE]; - const char *message; - - json_t *json_id = json_object_get(json_request, - tox_weechat_json_friend_request_key_client_id); - json_t *json_message = json_object_get(json_request, - tox_weechat_json_friend_request_key_message); - - tox_weechat_hex2bin(json_string_value(json_id), TOX_CLIENT_ID_SIZE * 2, client_id); - message = json_string_value(json_message); - - tox_weechat_friend_request_add(identity, - (uint8_t *)client_id, - message); - } -} - -/** - * Load unsent messages from a json array. - */ -void -tox_weechat_data_load_unsent_messages(struct t_tox_weechat_identity *identity, - json_t *recipient_object) -{ - tox_weechat_unsent_messages_free(identity); - - const char *key; - json_t *message_array; - json_object_foreach(recipient_object, key, message_array) - { - uint8_t client_id[TOX_CLIENT_ID_SIZE]; - tox_weechat_hex2bin(key, TOX_CLIENT_ID_SIZE * 2, (char *)client_id); - - size_t index; - json_t *message; - json_array_foreach(message_array, index, message) - { - tox_weechat_add_unsent_message(identity, - client_id, - json_string_value(message)); - } - } -} - -/** - * Load an identity's data from a JSON object. - */ -void -tox_weechat_data_identity_load(struct t_tox_weechat_identity *identity) -{ - char *identity_key = tox_weechat_json_get_identity_key(identity); - json_t *identity_data = json_object_get(tox_weechat_json_data, identity_key); - free(identity_key); - - json_t *friend_requests = json_object_get(identity_data, - tox_weechat_json_key_friend_requests); - if (friend_requests) - tox_weechat_data_load_friend_requests(identity, friend_requests); - - json_t *unsent_messages = json_object_get(identity_data, - tox_weechat_json_key_unsent_messages); - if (unsent_messages) - tox_weechat_data_load_unsent_messages(identity, unsent_messages); -} - -/** - * Load the data on disk into memory. - */ -void -tox_weechat_data_load() -{ - char *full_path = tox_weechat_json_data_file_path(); - - - json_error_t error; - tox_weechat_json_data = json_load_file(full_path, 0, &error); - free(full_path); - - if (!tox_weechat_json_data) - { - weechat_printf(NULL, - "%s%s: could not load on-disk data", - weechat_prefix("error"), - weechat_plugin->name); - - tox_weechat_json_data = json_object(); - } -} - -/** - * Save all in-memory data to data on disk. Return 0 on success, -1 on - * error. - */ -int -tox_weechat_data_save() -{ - char *full_path = tox_weechat_json_data_file_path(); - int rc = json_dump_file(tox_weechat_json_data, - full_path, - 0); - free(full_path); - - return rc; -} - -/** - * Free in-memory JSON data. - */ -void -tox_weechat_data_free() -{ - json_decref(tox_weechat_json_data); -} - diff --git a/src/tox-weechat-friend-requests.c b/src/tox-weechat-friend-requests.c deleted file mode 100644 index 103d232..0000000 --- a/src/tox-weechat-friend-requests.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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 "tox-weechat.h" -#include "tox-weechat-identities.h" -#include "tox-weechat-utils.h" - -#include "tox-weechat-friend-requests.h" - -/** - * Add a new friend request to an identity. - * - * Returns 0 on success, -1 on a full friend list. - */ -int -tox_weechat_friend_request_add(struct t_tox_weechat_identity *identity, - const uint8_t *client_id, - const char *message) -{ - // check friend request count - struct t_config_option *option = - identity->options[TOX_WEECHAT_IDENTITY_OPTION_MAX_FRIEND_REQUESTS]; - unsigned int max_requests = weechat_config_integer(option); - - if (identity->friend_request_count >= max_requests) - return -1; - - struct t_tox_weechat_friend_request *request = malloc(sizeof(*request)); - request->identity = identity; - request->message = strdup(message); - memcpy(request->tox_id, client_id, TOX_CLIENT_ID_SIZE); - - // add to list - request->prev_request = identity->last_friend_request; - request->next_request = NULL; - - if (identity->friend_requests == NULL) - identity->friend_requests = request; - else - identity->last_friend_request->next_request = request; - - identity->last_friend_request = request; - ++(identity->friend_request_count); - - return 0; -} - -/** - * Remove and free a friend request from its identity. - */ -void -tox_weechat_friend_request_remove(struct t_tox_weechat_friend_request *request) -{ - struct t_tox_weechat_identity *identity = request->identity; - if (request == identity->last_friend_request) - identity->last_friend_request = request->prev_request; - - if (request->prev_request) - request->prev_request->next_request = request->next_request; - else - identity->friend_requests = request->next_request; - - if (request->next_request) - request->next_request->prev_request = request->prev_request; - - --(identity->friend_request_count); - - tox_weechat_friend_request_free(request); -} - -/** - * Accept a friend request. Remove and free the request. - */ -void -tox_weechat_accept_friend_request(struct t_tox_weechat_friend_request *request) -{ - tox_add_friend_norequest(request->identity->tox, request->tox_id); - tox_weechat_friend_request_remove(request); -} - -/** - * Decline a friend request. Remove and free the request. - */ -void -tox_weechat_decline_friend_request(struct t_tox_weechat_friend_request *request) -{ - tox_weechat_friend_request_remove(request); -} - -/** - * Return the friend request from the identity with the number num. - */ -struct t_tox_weechat_friend_request * -tox_weechat_friend_request_with_num(struct t_tox_weechat_identity *identity, - unsigned int num) -{ - if (num >= identity->friend_request_count) return NULL; - - unsigned int i = 0; - struct t_tox_weechat_friend_request *request = identity->friend_requests; - while (i != num && request->next_request) - { - request = request->next_request; - ++i; - } - - return request; -} - -/** - * Free a friend request. - */ -void -tox_weechat_friend_request_free(struct t_tox_weechat_friend_request *request) -{ - free(request->message); - free(request); -} - -/** - * Free all friend requests from an identity. - */ -void -tox_weechat_friend_request_free_identity(struct t_tox_weechat_identity *identity) -{ - while (identity->friend_requests) - tox_weechat_friend_request_remove(identity->friend_requests); -} - diff --git a/src/tox-weechat-friend-requests.h b/src/tox-weechat-friend-requests.h deleted file mode 100644 index df94276..0000000 --- a/src/tox-weechat-friend-requests.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 TOX_WEECHAT_FRIEND_REQUESTS_H -#define TOX_WEECHAT_FRIEND_REQUESTS_H - -#include - -#include - -/** - * Represents a friend request with a Tox ID and a message. - */ -struct t_tox_weechat_friend_request -{ - uint8_t tox_id[TOX_CLIENT_ID_SIZE]; - char *message; - - struct t_tox_weechat_identity *identity; - - struct t_tox_weechat_friend_request *next_request; - struct t_tox_weechat_friend_request *prev_request; -}; - -int -tox_weechat_friend_request_add(struct t_tox_weechat_identity *identity, - const uint8_t *client_id, - const char *message); - -void -tox_weechat_accept_friend_request(struct t_tox_weechat_friend_request *request); - -void -tox_weechat_decline_friend_request(struct t_tox_weechat_friend_request *request); - -struct t_tox_weechat_friend_request * -tox_weechat_friend_request_with_num(struct t_tox_weechat_identity *identity, - unsigned int num); - -void -tox_weechat_friend_request_free(struct t_tox_weechat_friend_request *request); - -void -tox_weechat_friend_request_free_identity(struct t_tox_weechat_identity *identity); - -#endif // TOX_WEECHAT_FRIEND_REQUESTS_H diff --git a/src/tox-weechat-gui.c b/src/tox-weechat-gui.c deleted file mode 100644 index 912a6c1..0000000 --- a/src/tox-weechat-gui.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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 "tox-weechat.h" -#include "tox-weechat-identities.h" -#include "tox-weechat-utils.h" - -#include "tox-weechat-gui.h" - -char * -bar_item_away(void *data, - struct t_gui_bar_item *item, - struct t_gui_window *window, - struct t_gui_buffer *buffer, - struct t_hashtable *extra_info) -{ - struct t_tox_weechat_identity *identity = tox_weechat_identity_for_buffer(buffer); - - if (!identity || !(identity->tox)) - return NULL; - - char *status = NULL;; - switch (tox_get_self_user_status(identity->tox)) - { - case TOX_USERSTATUS_BUSY: - status = strdup("busy"); - break; - case TOX_USERSTATUS_AWAY: - status = strdup("away"); - break; - } - - return status; -} - -char * -bar_item_input_prompt(void *data, - struct t_gui_bar_item *item, - struct t_gui_window *window, - struct t_gui_buffer *buffer, - struct t_hashtable *extra_info) -{ - struct t_tox_weechat_identity *identity = tox_weechat_identity_for_buffer(buffer); - - if (!identity || !(identity->tox)) - return NULL; - - return tox_weechat_get_self_name_nt(identity->tox); -} - -char * -bar_item_buffer_plugin(void *data, struct t_gui_bar_item *item, - struct t_gui_window *window, - struct t_gui_buffer *buffer, - struct t_hashtable *extra_info) -{ - struct t_tox_weechat_identity *identity = tox_weechat_identity_for_buffer(buffer); - - char string[256]; - - const char *plugin_name = weechat_plugin_get_name(weechat_plugin); - const char *identity_name = identity->name; - - snprintf(string, sizeof(string), - "%s%s/%s%s%s/%s%s", - plugin_name, - weechat_color("bar_delim"), - weechat_color("bar_fg"), - identity_name, - weechat_color("bar_delim"), - weechat_color("bar_fg"), - identity->tox_online ? "online" : "offline"); - - return strdup(string); -} - -void tox_weechat_gui_init() -{ - weechat_bar_item_new("away", bar_item_away, NULL); - weechat_bar_item_new("input_prompt", bar_item_input_prompt, NULL); - weechat_bar_item_new("buffer_plugin", bar_item_buffer_plugin, NULL); -} - diff --git a/src/tox-weechat-identities.c b/src/tox-weechat-identities.c deleted file mode 100644 index 33065bb..0000000 --- a/src/tox-weechat-identities.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * 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 -#include - -#include -#include - -#include "tox-weechat.h" -#include "tox-weechat-config.h" -#include "tox-weechat-friend-requests.h" -#include "tox-weechat-chats.h" -#include "tox-weechat-tox-callbacks.h" -#include "tox-weechat-utils.h" -#include "tox-weechat-data.h" - -#include "tox-weechat-identities.h" - -struct t_tox_weechat_identity *tox_weechat_identities = NULL; -struct t_tox_weechat_identity *tox_weechat_last_identity = NULL; - -char *tox_weechat_bootstrap_addresses[] = { - "192.254.75.98", - "31.7.57.236", - "107.161.17.51", - "144.76.60.215", - "23.226.230.47", - "37.59.102.176", - "37.187.46.132", - "178.21.112.187", - "192.210.149.121", - "54.199.139.199", - "63.165.243.15", -}; -uint16_t tox_weechat_bootstrap_ports[] = { - 33445, 443, 33445, 33445, 33445, - 33445, 33445, 33445, 33445, 33445, - 443, -}; - -char *tox_weechat_bootstrap_keys[] = { - "951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F", - "2A4B50D1D525DA2E669592A20C327B5FAD6C7E5962DC69296F9FEC77C4436E4E", - "7BE3951B97CA4B9ECDDA768E8C52BA19E9E2690AB584787BF4C90E04DBB75111", - "04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F", - "A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074", - "B98A2CEAA6C6A2FADC2C3632D284318B60FE5375CCB41EFA081AB67F500C1B0B", - "5EB67C51D3FF5A9D528D242B669036ED2A30F8A60E674C45E7D43010CB2E1331", - "4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057", - "F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67", - "7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029", - "8CD087E31C67568103E8C2A28653337E90E6B8EDA0D765D57C6B5172B4F1F04C", -}; - -int tox_weechat_bootstrap_count = sizeof(tox_weechat_bootstrap_addresses) - / sizeof(tox_weechat_bootstrap_addresses[0]); - -char * -tox_weechat_identity_data_file_path(struct t_tox_weechat_identity *identity) -{ - // expand path - const char *weechat_dir = weechat_info_get ("weechat_dir", NULL); - const char *base_path = weechat_config_string(identity->options[TOX_WEECHAT_IDENTITY_OPTION_SAVEFILE]); - char *home_expanded = weechat_string_replace(base_path, "%h", weechat_dir); - char *full_path = weechat_string_replace(home_expanded, "%n", identity->name); - free(home_expanded); - - return full_path; -} - -int -tox_weechat_load_identity_data_file(struct t_tox_weechat_identity *identity) -{ - char *full_path = tox_weechat_identity_data_file_path(identity); - - FILE *file = fopen(full_path, "r"); - free(full_path); - - if (file) - { - // get file size - fseek(file, 0, SEEK_END); - size_t size = ftell(file); - rewind(file); - - // allocate a buffer and read file into it - uint8_t *data = malloc(sizeof(*data) * size); - fread(data, sizeof(uint8_t), size, file); - fclose(file); - - // try loading the data - int status = tox_load(identity->tox, data, size); - free(data); - - return status; - } - - return -1; -} - -int -tox_weechat_save_identity_data_file(struct t_tox_weechat_identity *identity) -{ - char *full_path = tox_weechat_identity_data_file_path(identity); - - char *rightmost_slash = strrchr(full_path, '/'); - char *save_dir = weechat_strndup(full_path, rightmost_slash - full_path); - weechat_mkdir_parents(save_dir, 0755); - free(save_dir); - - // save Tox data to a buffer - uint32_t size = tox_size(identity->tox); - uint8_t *data = malloc(sizeof(*data) * size); - tox_save(identity->tox, data); - - // save buffer to a file - FILE *file = fopen(full_path, "w"); - if (file) - { - fwrite(data, sizeof(data[0]), size, file); - fclose(file); - - return 0; - } - - return -1; -} - -int -tox_weechat_identity_buffer_close_callback(void *data, - struct t_gui_buffer *buffer) -{ - struct t_tox_weechat_identity *identity = data; - identity->buffer = NULL; - - tox_weechat_identity_disconnect(identity); - - return WEECHAT_RC_OK; -} - - -int -tox_weechat_bootstrap_tox(Tox *tox, const char *address, uint16_t port, const char *public_key) -{ - char binary_key[TOX_FRIEND_ADDRESS_SIZE]; - tox_weechat_hex2bin(public_key, TOX_FRIEND_ADDRESS_SIZE * 2, binary_key); - - int result = tox_bootstrap_from_address(tox, - address, - port, - (uint8_t *)binary_key); - - return result; -} - -void -tox_weechat_bootstrap_random_node(Tox *tox) -{ - int i = rand() % tox_weechat_bootstrap_count; - tox_weechat_bootstrap_tox(tox, tox_weechat_bootstrap_addresses[i], - tox_weechat_bootstrap_ports[i], - tox_weechat_bootstrap_keys[i]); -} - -struct t_tox_weechat_identity * -tox_weechat_identity_new(const char *name) -{ - struct t_tox_weechat_identity *identity = malloc(sizeof(*identity)); - identity->name = strdup(name); - - // add to identity list - identity->prev_identity= tox_weechat_last_identity; - identity->next_identity = NULL; - - if (tox_weechat_identities == NULL) - tox_weechat_identities = identity; - else - tox_weechat_last_identity->next_identity = identity; - - tox_weechat_last_identity = identity; - - // set up internal vars - identity->tox = NULL; - identity->buffer = NULL; - identity->tox_do_timer = NULL; - identity->chats = identity->last_chat = NULL; - identity->friend_requests = identity->last_friend_request = NULL; - identity->unsent_message_recipients = identity->last_unsent_message_recipient = NULL; - identity->tox_online = false; - - // set up config - tox_weechat_config_init_identity(identity); - - return identity; -} - -void -tox_weechat_identity_connect(struct t_tox_weechat_identity *identity) -{ - if (identity->tox) - return; - - // create main buffer - if (identity->buffer == NULL) - { - identity->buffer = weechat_buffer_new(identity->name, - NULL, NULL, - tox_weechat_identity_buffer_close_callback, identity); - } - - weechat_printf(identity->buffer, - "%s%s: identity %s connecting...", - weechat_prefix("network"), - weechat_plugin->name, - identity->name); - - if (identity->friend_request_count > 0) - { - weechat_printf(identity->buffer, - "%sYou have %d pending friend requests.", - weechat_prefix("network"), - identity->friend_request_count); - } - - // create Tox - identity->tox = tox_new(NULL); - - // try loading Tox saved data - if (tox_weechat_load_identity_data_file(identity) == -1) - { - // we failed to load - set an initial name - char *name; - - struct passwd *user_pwd; - if ((user_pwd = getpwuid(geteuid()))) - name = user_pwd->pw_name; - else - name = "Tox-WeeChat User"; - - tox_set_name(identity->tox, - (uint8_t *)name, strlen(name)); - } - - // load data - tox_weechat_data_identity_load(identity); - - // bootstrap DHT - int max_bootstrap_nodes = 5; - int bootstrap_nodes = max_bootstrap_nodes > tox_weechat_bootstrap_count ? - tox_weechat_bootstrap_count : max_bootstrap_nodes; - for (int i = 0; i < bootstrap_nodes; ++i) - tox_weechat_bootstrap_random_node(identity->tox); - - // start Tox_do loop - tox_weechat_do_timer_cb(identity, 0); - - // register Tox callbacks - tox_callback_friend_message(identity->tox, tox_weechat_friend_message_callback, identity); - tox_callback_friend_action(identity->tox, tox_weechat_friend_action_callback, identity); - tox_callback_connection_status(identity->tox, tox_weechat_connection_status_callback, identity); - tox_callback_name_change(identity->tox, tox_weechat_name_change_callback, identity); - tox_callback_user_status(identity->tox, tox_weechat_user_status_callback, identity); - tox_callback_status_message(identity->tox, tox_weechat_status_message_callback, identity); - tox_callback_friend_request(identity->tox, tox_weechat_callback_friend_request, identity); -} - -void -tox_weechat_identity_disconnect(struct t_tox_weechat_identity *identity) -{ - // check that we're not already disconnected - if (!identity->tox) - return; - - // save data - tox_weechat_data_identity_save(identity); - - // save and kill tox - int result = tox_weechat_save_identity_data_file(identity); - tox_kill(identity->tox); - identity->tox = NULL; - - if (result == -1) - { - char *path = tox_weechat_identity_data_file_path(identity); - weechat_printf(NULL, - "%s%s: Could not save Tox identity %s to file: %s", - weechat_prefix("error"), - weechat_plugin->name, - identity->name, - path); - free(path); - } - - // stop Tox timer - weechat_unhook(identity->tox_do_timer); - - // have to refresh and hide bar items even if we were already offline - tox_weechat_identity_refresh_online_status(identity); - tox_weechat_identity_set_online_status(identity, false); -} - -void -tox_weechat_identity_autoconnect() -{ - for (struct t_tox_weechat_identity *identity = tox_weechat_identities; - identity; - identity = identity->next_identity) - { - if (weechat_config_boolean(identity->options[TOX_WEECHAT_IDENTITY_OPTION_AUTOCONNECT])) - tox_weechat_identity_connect(identity); - } -} - -void -tox_weechat_identity_refresh_online_status(struct t_tox_weechat_identity *identity) -{ - weechat_bar_item_update("buffer_plugin"); - weechat_bar_item_update("input_prompt"); - weechat_bar_item_update("away"); -} - -void -tox_weechat_identity_set_online_status(struct t_tox_weechat_identity *identity, - bool online) -{ - if (identity->tox_online ^ online) - { - identity->tox_online = online; - tox_weechat_identity_refresh_online_status(identity); - - struct t_gui_buffer *buffer = identity->buffer ?: NULL; - if (identity->tox_online) - { - weechat_printf(buffer, - "%s%s: identity %s connected", - weechat_prefix("network"), - weechat_plugin->name, - identity->name); - } - else - { - weechat_printf(buffer, - "%s%s: identity %s disconnected", - weechat_prefix("network"), - weechat_plugin->name, - identity->name); - } - } -} - -struct t_tox_weechat_identity * -tox_weechat_identity_name_search(const char *name) -{ - for (struct t_tox_weechat_identity *identity = tox_weechat_identities; - identity; - identity = identity->next_identity) - { - if (weechat_strcasecmp(identity->name, name) == 0) - return identity; - } - - return NULL; -} - -struct t_tox_weechat_identity * -tox_weechat_identity_for_buffer(struct t_gui_buffer *buffer) -{ - for (struct t_tox_weechat_identity *identity = tox_weechat_identities; - identity; - identity = identity->next_identity) - { - if (identity->buffer == buffer) - return identity; - - for (struct t_tox_weechat_chat *chat = identity->chats; - chat; - chat = chat->next_chat) - { - if (chat->buffer == buffer) - return identity; - } - } - - return NULL; -} - -void -tox_weechat_identity_delete(struct t_tox_weechat_identity *identity, - bool delete_data) -{ - char *data_path = tox_weechat_identity_data_file_path(identity); - - tox_weechat_identity_free(identity); - - if (delete_data) - unlink(data_path); -} - -void -tox_weechat_identity_free(struct t_tox_weechat_identity *identity) -{ - // save friend requests - tox_weechat_friend_request_free_identity(identity); - - // disconnect - tox_weechat_identity_disconnect(identity); - - // close buffer - if (identity->buffer) - { - weechat_buffer_set_pointer(identity->buffer, "close_callback", NULL); - weechat_buffer_close(identity->buffer); - } - - // remove from list - if (identity == tox_weechat_last_identity) - tox_weechat_last_identity = identity->prev_identity; - - if (identity->prev_identity) - identity->prev_identity->next_identity = identity->next_identity; - else - tox_weechat_identities = identity->next_identity; - - if (identity->next_identity) - identity->next_identity->prev_identity = identity->prev_identity; - - // free remaining vars - free(identity->name); - free(identity); -} - -void -tox_weechat_identity_free_all() -{ - while (tox_weechat_identities) - tox_weechat_identity_free(tox_weechat_identities); -} diff --git a/src/tox-weechat-identities.h b/src/tox-weechat-identities.h deleted file mode 100644 index 7db6e20..0000000 --- a/src/tox-weechat-identities.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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 TOX_WEECHAT_IDENTITIES_H -#define TOX_WEECHAT_IDENTITIES_H - -#include -#include - -#include - -enum t_tox_weechat_identity_option -{ - TOX_WEECHAT_IDENTITY_OPTION_SAVEFILE = 0, - TOX_WEECHAT_IDENTITY_OPTION_AUTOCONNECT, - TOX_WEECHAT_IDENTITY_OPTION_MAX_FRIEND_REQUESTS, - - TOX_WEECHAT_IDENTITY_NUM_OPTIONS, -}; - -struct t_tox_weechat_identity -{ - char *name; - struct t_config_option *options[TOX_WEECHAT_IDENTITY_NUM_OPTIONS]; - - struct Tox *tox; - int tox_online; - - struct t_gui_buffer *buffer; - struct t_hook *tox_do_timer; - - struct t_tox_weechat_chat *chats; - struct t_tox_weechat_chat *last_chat; - - struct t_tox_weechat_friend_request *friend_requests; - struct t_tox_weechat_friend_request *last_friend_request; - unsigned int friend_request_count; - - struct t_tox_weechat_unsent_message_recipient *unsent_message_recipients; - struct t_tox_weechat_unsent_message_recipient *last_unsent_message_recipient; - - struct t_tox_weechat_identity *next_identity; - struct t_tox_weechat_identity *prev_identity; -}; - -extern struct t_tox_weechat_identity *tox_weechat_identities; -extern struct t_tox_weechat_identity *tox_weechat_last_identity; - -struct t_tox_weechat_identity * -tox_weechat_identity_new(const char *name); - -void -tox_weechat_identity_connect(struct t_tox_weechat_identity *identity); - -void -tox_weechat_identity_disconnect(struct t_tox_weechat_identity *identity); - -void -tox_weechat_identity_autoconnect(); - -void -tox_weechat_identity_refresh_online_status(struct t_tox_weechat_identity *identity); - -void -tox_weechat_identity_set_online_status(struct t_tox_weechat_identity *identity, - bool online); - -struct t_tox_weechat_identity * -tox_weechat_identity_name_search(const char *name); - -struct t_tox_weechat_identity * -tox_weechat_identity_for_buffer(struct t_gui_buffer *buffer); - -void -tox_weechat_identity_delete(struct t_tox_weechat_identity *identity, - bool delete_data); - -void -tox_weechat_identity_free(struct t_tox_weechat_identity *identity); - -void -tox_weechat_identity_free_all(); - -#endif // TOX_WEECHAT_IDENTITIES_H diff --git a/src/tox-weechat-messages.c b/src/tox-weechat-messages.c deleted file mode 100644 index e17e670..0000000 --- a/src/tox-weechat-messages.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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 "tox-weechat-identities.h" -#include "tox-weechat-utils.h" - -#include "tox-weechat-messages.h" - -/** - * Return an existing unsent message recipient object or NULL. - */ -struct t_tox_weechat_unsent_message_recipient * -tox_weechat_unsent_message_recipient_with_id(struct t_tox_weechat_identity *identity, - const uint8_t *id) -{ - struct t_tox_weechat_unsent_message_recipient *recipient; - for (recipient = identity->unsent_message_recipients; - recipient; - recipient = recipient->next_recipient) - { - if (memcmp(recipient->recipient_id, id, TOX_CLIENT_ID_SIZE) == 0) - return recipient; - } - - return NULL; -} - -/** - * Create and return a new unsent message recipient object. - */ -struct t_tox_weechat_unsent_message_recipient * -tox_weechat_unsent_message_recipient_new(struct t_tox_weechat_identity *identity, - const uint8_t *id) -{ - struct t_tox_weechat_unsent_message_recipient *recipient = malloc(sizeof(*recipient)); - if (!recipient) - return NULL; - - memcpy(recipient->recipient_id, id, TOX_CLIENT_ID_SIZE); - recipient->identity = identity; - recipient->unsent_messages = recipient->last_unsent_message = NULL; - - recipient->prev_recipient = identity->last_unsent_message_recipient; - recipient->next_recipient = NULL; - - if (identity->unsent_message_recipients == NULL) - identity->unsent_message_recipients = recipient; - else - identity->last_unsent_message_recipient->next_recipient = recipient; - - identity->last_unsent_message_recipient = recipient; - - return recipient; -} - -/** - * Add a new message to the unsent messages queue. - */ -void -tox_weechat_add_unsent_message(struct t_tox_weechat_identity *identity, - const uint8_t *recipient_id, - const char *message) -{ - struct t_tox_weechat_unsent_message_recipient *recipient - = tox_weechat_unsent_message_recipient_with_id(identity, recipient_id); - if (!recipient) - recipient = tox_weechat_unsent_message_recipient_new(identity, recipient_id); - if (!recipient) - return; - - struct t_tox_weechat_unsent_message *unsent_message = malloc(sizeof(*unsent_message)); - if (!message) - return; - - unsent_message->message = strdup(message); - unsent_message->recipient = recipient; - - unsent_message->prev_message = recipient->last_unsent_message; - unsent_message->next_message = NULL; - - if (recipient->unsent_messages == NULL) - recipient->unsent_messages = unsent_message; - else - recipient->last_unsent_message->next_message = unsent_message; - - recipient->last_unsent_message = unsent_message; -} - -void -tox_weechat_remove_unsent_message(struct t_tox_weechat_unsent_message *message) -{ - struct t_tox_weechat_unsent_message_recipient *recipient = message->recipient; - if (message == recipient->last_unsent_message) - recipient->last_unsent_message = message->prev_message; - - if (message->prev_message) - message->prev_message->next_message = message->next_message; - else - recipient->unsent_messages = message->next_message; - - if (message->next_message) - message->next_message->prev_message = message->prev_message; - - free(message->message); - free(message); -} - -/** - * Sends a message to a friend. Does message splitting and queuing. - */ -uint32_t -tox_weechat_send_friend_message(struct t_tox_weechat_identity *identity, - int32_t friend_number, - const char *message) -{ - // TODO: split message - uint32_t rc = tox_send_message(identity->tox, - friend_number, - (uint8_t *)message, - strlen(message)); - - uint8_t recipient_id[TOX_CLIENT_ID_SIZE]; - tox_get_client_id(identity->tox, friend_number, recipient_id); - - if (rc == 0) - tox_weechat_add_unsent_message(identity, recipient_id, message); - - return rc; -} - -void -tox_weechat_unsent_messages_free(struct t_tox_weechat_identity *identity) -{ - struct t_tox_weechat_unsent_message_recipient *recipient; - for (recipient = identity->unsent_message_recipients; - recipient; - recipient = recipient->next_recipient) - { - while (recipient->unsent_messages) - tox_weechat_remove_unsent_message(recipient->unsent_messages); - } -} - -void -tox_weechat_attempt_message_flush(struct t_tox_weechat_identity *identity, - int32_t friend_number) -{ - -} diff --git a/src/tox-weechat-messages.h b/src/tox-weechat-messages.h deleted file mode 100644 index 88f9e46..0000000 --- a/src/tox-weechat-messages.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 TOX_WEECHAT_MESSAGES_H -#define TOX_WEECHAT_MESSAGES_H - -#include - -struct t_tox_weechat_identity; - -struct t_tox_weechat_unsent_message_recipient -{ - uint8_t recipient_id[TOX_CLIENT_ID_SIZE]; - struct t_tox_weechat_identity *identity; - - struct t_tox_weechat_unsent_message *unsent_messages; - struct t_tox_weechat_unsent_message *last_unsent_message; - - struct t_tox_weechat_unsent_message_recipient *next_recipient; - struct t_tox_weechat_unsent_message_recipient *prev_recipient; -}; - -struct t_tox_weechat_unsent_message -{ - char *message; - struct t_tox_weechat_unsent_message_recipient *recipient; - - struct t_tox_weechat_unsent_message *next_message; - struct t_tox_weechat_unsent_message *prev_message; -}; - -uint32_t -tox_weechat_send_friend_message(struct t_tox_weechat_identity *identity, - int32_t friend_number, - const char *message); - -void -tox_weechat_add_unsent_message(struct t_tox_weechat_identity *identity, - const uint8_t *recipient_id, - const char *message); - -void -tox_weechat_unsent_messages_free(struct t_tox_weechat_identity *identity); - -#endif // TOX_WEECHAT_MESSAGES_H diff --git a/src/tox-weechat-tox-callbacks.c b/src/tox-weechat-tox-callbacks.c deleted file mode 100644 index 50b227f..0000000 --- a/src/tox-weechat-tox-callbacks.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * 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 "tox-weechat.h" -#include "tox-weechat-identities.h" -#include "tox-weechat-chats.h" -#include "tox-weechat-friend-requests.h" -#include "tox-weechat-utils.h" - -#include "tox-weechat-tox-callbacks.h" - -int -tox_weechat_do_timer_cb(void *data, - int remaining_calls) -{ - struct t_tox_weechat_identity *identity = data; - - if (identity->tox) - { - tox_do(identity->tox); - struct t_hook *hook = weechat_hook_timer(tox_do_interval(identity->tox), 0, 1, - tox_weechat_do_timer_cb, identity); - identity->tox_do_timer = hook; - - // check connection status - int connected = tox_isconnected(identity->tox); - tox_weechat_identity_set_online_status(identity, connected); - } - - return WEECHAT_RC_OK; -} - -void -tox_weechat_friend_message_callback(Tox *tox, - int32_t friend_number, - const uint8_t *message, - uint16_t length, - void *data) -{ - struct t_tox_weechat_identity *identity = data; - struct t_tox_weechat_chat *chat = tox_weechat_get_friend_chat(identity, - friend_number); - - char *name = tox_weechat_get_name_nt(identity->tox, friend_number); - char *message_nt = tox_weechat_null_terminate(message, length); - - tox_weechat_chat_print_message(chat, "", name, message_nt); - - free(name); - free(message_nt); -} - -void -tox_weechat_friend_action_callback(Tox *tox, - int32_t friend_number, - const uint8_t *message, - uint16_t length, - void *data) -{ - struct t_tox_weechat_identity *identity = data; - struct t_tox_weechat_chat *chat = tox_weechat_get_friend_chat(identity, - friend_number); - - char *name = tox_weechat_get_name_nt(identity->tox, friend_number); - char *message_nt = tox_weechat_null_terminate(message, length); - - tox_weechat_chat_print_action(chat, "", name, message_nt); - - free(name); - free(message_nt); -} - -void -tox_weechat_connection_status_callback(Tox *tox, - int32_t friend_number, - uint8_t status, - void *data) -{ - struct t_tox_weechat_identity *identity = data; - char *name = tox_weechat_get_name_nt(identity->tox, friend_number); - - if (status == 0) - { - weechat_printf(identity->buffer, - "%s%s just went offline.", - weechat_prefix("network"), - name); - } - else if (status == 1) - { - weechat_printf(identity->buffer, - "%s%s just came online.", - weechat_prefix("network"), - name); - } - free(name); -} - -void -tox_weechat_name_change_callback(Tox *tox, - int32_t friend_number, - const uint8_t *name, - uint16_t length, - void *data) -{ - struct t_tox_weechat_identity *identity = data; - struct t_tox_weechat_chat *chat = tox_weechat_get_existing_friend_chat(identity, - friend_number); - - char *old_name = tox_weechat_get_name_nt(identity->tox, friend_number); - char *new_name = tox_weechat_null_terminate(name, length); - - if (strcmp(old_name, new_name) != 0) - { - if (chat) - { - tox_weechat_chat_queue_refresh(chat); - - weechat_printf(chat->buffer, - "%s%s is now known as %s", - weechat_prefix("network"), - old_name, new_name); - } - - weechat_printf(identity->buffer, - "%s%s is now known as %s", - weechat_prefix("network"), - old_name, new_name); - } - - free(old_name); - free(new_name); -} - -void -tox_weechat_user_status_callback(Tox *tox, - int32_t friend_number, - uint8_t status, - void *data) -{ - struct t_tox_weechat_identity *identity = data; - struct t_tox_weechat_chat *chat = tox_weechat_get_existing_friend_chat(identity, - friend_number); - if (chat) - tox_weechat_chat_queue_refresh(chat); -} - -void -tox_weechat_status_message_callback(Tox *tox, - int32_t friend_number, - const uint8_t *message, - uint16_t length, - void *data) -{ - struct t_tox_weechat_identity *identity = data; - struct t_tox_weechat_chat *chat = tox_weechat_get_existing_friend_chat(identity, - friend_number); - if (chat) - tox_weechat_chat_queue_refresh(chat); -} - -void -tox_weechat_callback_friend_request(Tox *tox, - const uint8_t *public_key, - const uint8_t *message, - uint16_t length, - void *data) -{ - struct t_tox_weechat_identity *identity = data; - - char *message_nt = tox_weechat_null_terminate(message, length); - int rc = tox_weechat_friend_request_add(identity, public_key, message_nt); - - if (rc == 0) - { - char hex_address[TOX_CLIENT_ID_SIZE * 2 + 1]; - tox_weechat_bin2hex(public_key, TOX_CLIENT_ID_SIZE, hex_address); - weechat_printf(identity->buffer, - "%sReceived a friend request from %s: \"%s\"", - weechat_prefix("network"), - hex_address, - message_nt); - } - else if (rc == -1) - { - weechat_printf(identity->buffer, - "%sReceived a friend request, but your friend request list is full!", - weechat_prefix("warning")); - } - - free(message_nt); -} - diff --git a/src/tox-weechat-tox-callbacks.h b/src/tox-weechat-tox-callbacks.h deleted file mode 100644 index c399f82..0000000 --- a/src/tox-weechat-tox-callbacks.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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 TOX_WEECHAT_TOX_CALLBACKS_H -#define TOX_WEECHAT_TOX_CALLBACKS_H - -#include - -#include - -int -tox_weechat_do_timer_cb(void *data, - int remaining_calls); - -void -tox_weechat_friend_message_callback(Tox *tox, - int32_t friend_number, - const uint8_t *message, - uint16_t length, - void *data); - -void -tox_weechat_friend_action_callback(Tox *tox, - int32_t friend_number, - const uint8_t *message, - uint16_t length, - void *data); - -void -tox_weechat_connection_status_callback(Tox *tox, - int32_t friend_number, - uint8_t status, - void *data); - -void -tox_weechat_name_change_callback(Tox *tox, - int32_t friend_number, - const uint8_t *name, - uint16_t length, - void *data); - -void -tox_weechat_user_status_callback(Tox *tox, - int32_t friend_number, - uint8_t status, - void *data); - -void -tox_weechat_status_message_callback(Tox *tox, - int32_t friend_number, - const uint8_t *message, - uint16_t length, - void *data); - -void -tox_weechat_callback_friend_request(Tox *tox, - const uint8_t *public_key, - const uint8_t *message, - uint16_t length, - void *data); - -#endif // TOX_WEECHAT_TOX_CALLBACKS_H diff --git a/src/twc-bootstrap.c b/src/twc-bootstrap.c new file mode 100644 index 0000000..d3e1f66 --- /dev/null +++ b/src/twc-bootstrap.c @@ -0,0 +1,97 @@ +/* + * 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 "twc-utils.h" + +#include "twc-bootstrap.h" + +char *twc_bootstrap_addresses[] = { + "192.254.75.98", + "31.7.57.236", + "107.161.17.51", + "144.76.60.215", + "23.226.230.47", + "37.59.102.176", + "37.187.46.132", + "178.21.112.187", + "192.210.149.121", + "54.199.139.199", + "63.165.243.15", +}; + +uint16_t twc_bootstrap_ports[] = { + 33445, 443, 33445, 33445, 33445, + 33445, 33445, 33445, 33445, 33445, + 443, +}; + +char *twc_bootstrap_keys[] = { + "951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F", + "2A4B50D1D525DA2E669592A20C327B5FAD6C7E5962DC69296F9FEC77C4436E4E", + "7BE3951B97CA4B9ECDDA768E8C52BA19E9E2690AB584787BF4C90E04DBB75111", + "04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F", + "A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074", + "B98A2CEAA6C6A2FADC2C3632D284318B60FE5375CCB41EFA081AB67F500C1B0B", + "5EB67C51D3FF5A9D528D242B669036ED2A30F8A60E674C45E7D43010CB2E1331", + "4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057", + "F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67", + "7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029", + "8CD087E31C67568103E8C2A28653337E90E6B8EDA0D765D57C6B5172B4F1F04C", +}; + +int twc_bootstrap_count = sizeof(twc_bootstrap_addresses) + / sizeof(twc_bootstrap_addresses[0]); + +/** + * Bootstrap a Tox object with a DHT bootstrap node. Returns the result of + * tox_bootstrap_from_address. + */ +int +twc_bootstrap_tox(Tox *tox, + const char *address, + uint16_t port, + const char *public_key) +{ + char binary_key[TOX_FRIEND_ADDRESS_SIZE]; + twc_hex2bin(public_key, TOX_FRIEND_ADDRESS_SIZE, binary_key); + + int result = tox_bootstrap_from_address(tox, + address, + port, + (uint8_t *)binary_key); + + return result; +} + +/** + * Bootstrap a Tox object with a random DHT bootstrap node. + */ +void +twc_bootstrap_random_node(Tox *tox) +{ + int i = rand() % twc_bootstrap_count; + twc_bootstrap_tox(tox, twc_bootstrap_addresses[i], + twc_bootstrap_ports[i], + twc_bootstrap_keys[i]); +} + diff --git a/src/twc-bootstrap.h b/src/twc-bootstrap.h new file mode 100644 index 0000000..1790579 --- /dev/null +++ b/src/twc-bootstrap.h @@ -0,0 +1,35 @@ +/* + * 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 TOX_WEECHAT_BOOTSTRAP_H +#define TOX_WEECHAT_BOOTSTRAP_H + +#include + +int +twc_bootstrap_tox(Tox *tox, + const char *address, + uint16_t port, + const char *public_key); + +void +twc_bootstrap_random_node(Tox *tox); + +#endif // TOX_WEECHAT_BOOTSTRAP_H + diff --git a/src/twc-chat.c b/src/twc-chat.c new file mode 100644 index 0000000..36256e1 --- /dev/null +++ b/src/twc-chat.c @@ -0,0 +1,261 @@ +/* + * 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 "twc.h" +#include "twc-profile.h" +#include "twc-message-queue.h" +#include "twc-list.h" +#include "twc-utils.h" + +#include "twc-chat.h" + +const char *twc_tag_unsent_message = "tox_unsent"; +const char *twc_tag_sent_message = "tox_sent"; +const char *twc_tag_received_message = "tox_received"; + +int +twc_chat_buffer_input_callback(void *data, + struct t_gui_buffer *weechat_buffer, + const char *input_data); +int +twc_chat_buffer_close_callback(void *data, + struct t_gui_buffer *weechat_buffer); + + +/** + * Create a new friend chat. + */ +struct t_twc_chat * +twc_chat_new_friend(struct t_twc_profile *profile, + int32_t friend_number) +{ + struct t_twc_chat *chat = malloc(sizeof(struct t_twc_chat)); + if (!chat) + return NULL; + + chat->friend_number = friend_number; + chat->profile = profile; + + uint8_t client_id[TOX_CLIENT_ID_SIZE]; + tox_get_client_id(profile->tox, friend_number, client_id); + + // TODO: prepend profile name + char buffer_name[TOX_CLIENT_ID_SIZE * 2 + 1]; + twc_bin2hex(client_id, TOX_CLIENT_ID_SIZE, buffer_name); + + chat->buffer = weechat_buffer_new(buffer_name, + twc_chat_buffer_input_callback, chat, + twc_chat_buffer_close_callback, chat); + + if (!(chat->buffer)) + { + free(chat); + return NULL; + } + + twc_chat_queue_refresh(chat); + twc_list_item_new_data_add(profile->chats, chat); + + return chat; +} + +/** + * Refresh a chat. Updates buffer short_name and title. + */ +void +twc_chat_refresh(struct t_twc_chat *chat) +{ + char *name = twc_get_name_nt(chat->profile->tox, + chat->friend_number); + char *status_message = twc_get_status_message_nt(chat->profile->tox, + chat->friend_number); + + weechat_buffer_set(chat->buffer, "short_name", name); + weechat_buffer_set(chat->buffer, "title", status_message); + + free(name); + free(status_message); +} + +/** + * Callback for twc_chat_queue_refresh. Simply calls twc_chat_refresh. + */ +int +twc_chat_refresh_timer_callback(void *data, int remaining) +{ + twc_chat_refresh(data); + + return WEECHAT_RC_OK; +} + +/** + * Queue a refresh of the buffer in 1ms (i.e. the next event loop tick). Done + * this way to allow data to update before refreshing interface. + */ +void +twc_chat_queue_refresh(struct t_twc_chat *chat) +{ + weechat_hook_timer(1, 0, 1, + twc_chat_refresh_timer_callback, chat); +} + +/** + * Find an existing chat object for a friend, and if not found, optionally + * create a new one. + */ +struct t_twc_chat * +twc_chat_search_friend(struct t_twc_profile *profile, + int32_t friend_number, + bool create_new) +{ + size_t index; + struct t_twc_list_item *item; + twc_list_foreach(profile->chats, index, item) + { + if (item->chat->friend_number == friend_number) + return item->chat; + } + + if (create_new) + { + return twc_chat_new_friend(profile, friend_number); + } + + return NULL; +} + +/** + * Find the chat object associated with a buffer, if it exists. + */ +struct t_twc_chat * +twc_chat_search_buffer(struct t_gui_buffer *buffer) +{ + size_t profile_index; + struct t_twc_list_item *profile_item; + twc_list_foreach(twc_profiles, profile_index, profile_item) + { + size_t chat_index; + struct t_twc_list_item *chat_item; + twc_list_foreach(profile_item->profile->chats, chat_index, chat_item) + { + if (chat_item->chat->buffer == buffer) + { + return chat_item->chat; + } + } + } + return NULL; +} + +/** + * Print a chat message to a chat's buffer. + */ +void +twc_chat_print_message(struct t_twc_chat *chat, + const char *tags, + const char *sender, + const char *message, + enum TWC_MESSAGE_TYPE message_type) +{ + switch (message_type) + { + case TWC_MESSAGE_TYPE_MESSAGE: + weechat_printf_tags(chat->buffer, tags, + "%s\t%s", + sender, message); + break; + case TWC_MESSAGE_TYPE_ACTION: + weechat_printf_tags(chat->buffer, tags, + "%s%s %s", + weechat_prefix("action"), + sender, message); + break; + } +} + +/** + * Send a message to the recipient(s) of a chat. + */ +void +twc_chat_send_message(struct t_twc_chat *chat, + const char *message, + enum TWC_MESSAGE_TYPE message_type) +{ + twc_message_queue_add_friend_message(chat->profile, + chat->friend_number, + message, message_type); + + char *name = twc_get_self_name_nt(chat->profile->tox); + twc_chat_print_message(chat, "", name, message, message_type); + free(name); +} + +/** + * Callback for a buffer receiving user input. + */ +int +twc_chat_buffer_input_callback(void *data, + struct t_gui_buffer *weechat_buffer, + const char *input_data) +{ + struct t_twc_chat *chat = data; + twc_chat_send_message(chat, input_data, TWC_MESSAGE_TYPE_MESSAGE); + + return WEECHAT_RC_OK; +} + +/** + * Callback for a buffer being closed. + */ +int +twc_chat_buffer_close_callback(void *data, + struct t_gui_buffer *weechat_buffer) +{ + struct t_twc_chat *chat = data; + + twc_list_remove_with_data(chat->profile->chats, chat); + + free(chat); + + return WEECHAT_RC_OK; +} + +/** + * Free all chats connected to a profile. + */ +void +twc_chat_free_profile(struct t_twc_profile *profile) +{ + struct t_twc_chat *chat; + while ((chat = twc_list_pop(profile->chats))) + { + weechat_buffer_set_pointer(chat->buffer, "close_callback", NULL); + weechat_buffer_close(chat->buffer); + free(chat); + } + + free(profile->chats); +} + diff --git a/src/twc-chat.h b/src/twc-chat.h new file mode 100644 index 0000000..d87247b --- /dev/null +++ b/src/twc-chat.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015 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 TOX_WEECHAT_CHAT_H +#define TOX_WEECHAT_CHAT_H + +#include +#include + +extern const char *twc_tag_unsent_message; +extern const char *twc_tag_sent_message; +extern const char *twc_tag_received_message; + +enum TWC_MESSAGE_TYPE +{ + TWC_MESSAGE_TYPE_MESSAGE, + TWC_MESSAGE_TYPE_ACTION, +}; + +struct t_twc_chat +{ + struct t_twc_profile *profile; + + struct t_gui_buffer *buffer; + int32_t friend_number; + +}; + +struct t_twc_chat * +twc_chat_search_friend(struct t_twc_profile *profile, + int32_t friend_number, + bool create_new); + +struct t_twc_chat * +twc_chat_search_buffer(struct t_gui_buffer *target_buffer); + +void +twc_chat_print_message(struct t_twc_chat *chat, + const char *tags, + const char *sender, + const char *message, + enum TWC_MESSAGE_TYPE message_type); + +void +twc_chat_send_message(struct t_twc_chat *chat, + const char *message, + enum TWC_MESSAGE_TYPE message_type); + +void +twc_chat_queue_refresh(struct t_twc_chat *chat); + +void +twc_chat_free_profile(struct t_twc_profile *profile); + +#endif // TOX_WEECHAT_CHAT_H + diff --git a/src/twc-commands.c b/src/twc-commands.c new file mode 100644 index 0000000..7c8f7fa --- /dev/null +++ b/src/twc-commands.c @@ -0,0 +1,781 @@ +/* + * 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 "twc.h" +#include "twc-utils.h" +#include "twc-profile.h" +#include "twc-chat.h" +#include "twc-friend-request.h" +#include "twc-bootstrap.h" +#include "twc-list.h" + +#include "twc-commands.h" + +/** + * Make sure a command is executed on a Tox profile buffer. If not, warn user + * and abort. + */ +#define TWC_CHECK_PROFILE(profile) \ + if (!profile) \ + { \ + weechat_printf(NULL, \ + "%s%s: command \"%s\" must be executed on a Tox buffer", \ + weechat_prefix("error"), weechat_plugin->name, \ + argv[0]); \ + return WEECHAT_RC_OK; \ + } \ + +/** + * Make sure a command is executed in a chat buffer. If not, warn user and + * abort. + */ +#define TWC_CHECK_CHAT(chat) \ + if (!chat) \ + { \ + weechat_printf(NULL, \ + "%s%s: command \"%s\" must be executed in a chat buffer", \ + weechat_prefix("error"), weechat_plugin->name, argv[0]); \ + return WEECHAT_RC_OK; \ + } + +/** + * Make sure a profile with the given name exists. If not, warn user and + * abort. + */ +#define TWC_CHECK_PROFILE_EXISTS(profile) \ + if (!profile) \ + { \ + weechat_printf(NULL, \ + "%s%s: profile \"%s\" does not exist.", \ + weechat_prefix("error"), weechat_plugin->name, \ + name); \ + return WEECHAT_RC_OK; \ + } + +/** + * Make sure a profile is loaded. + */ +#define TWC_CHECK_PROFILE_LOADED(profile) \ + if (!(profile->tox)) \ + { \ + weechat_printf(profile->buffer, \ + "%sprofile must be loaded for command \"%s\"", \ + weechat_prefix("error"), argv[0]); \ + return WEECHAT_RC_OK; \ + } + +/** + * Command /bootstrap callback. + */ +int +twc_cmd_bootstrap(void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol) +{ + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + TWC_CHECK_PROFILE(profile); + TWC_CHECK_PROFILE_LOADED(profile); + + // /bootstrap connect
+ if (argc == 5 && weechat_strcasecmp(argv[1], "connect") == 0) + { + char *address = argv[2]; + uint16_t port = atoi(argv[3]); + char *public_key = argv[4]; + + if (!twc_bootstrap_tox(profile->tox, address, port, public_key)) + { + weechat_printf(profile->buffer, + "%sBootstrap could not open address \"%s\"", + weechat_prefix("error"), address); + } + + return WEECHAT_RC_OK; + } + + return WEECHAT_RC_ERROR; +} + +/** + * Command /friend callback. + */ +int +twc_cmd_friend(void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol) +{ + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + TWC_CHECK_PROFILE(profile); + TWC_CHECK_PROFILE_LOADED(profile); + + // /friend or /friend list + if (argc == 1 || (argc == 2 && weechat_strcasecmp(argv[1], "list") == 0)) + { + size_t friend_count = tox_count_friendlist(profile->tox); + int32_t friend_numbers[friend_count]; + tox_get_friendlist(profile->tox, friend_numbers, friend_count); + + if (friend_count == 0) + { + weechat_printf(profile->buffer, + "%sYou have no friends :(", + weechat_prefix("network")); + return WEECHAT_RC_OK; + } + + weechat_printf(profile->buffer, + "%s[#] Name [Tox ID (short)]", + weechat_prefix("network")); + + for (size_t i = 0; i < friend_count; ++i) + { + int32_t friend_number = friend_numbers[i]; + char *name = twc_get_name_nt(profile->tox, friend_number); + char *hex_address = twc_get_friend_id_short(profile->tox, + friend_number); + + weechat_printf(profile->buffer, + "%s[%d] %s [%s]", + weechat_prefix("network"), + friend_number, name, hex_address); + + free(name); + free(hex_address); + } + + return WEECHAT_RC_OK; + } + + // /friend add [] + else if (argc >= 3 && weechat_strcasecmp(argv[1], "add") == 0) + { + if (strlen(argv[2]) != TOX_FRIEND_ADDRESS_SIZE * 2) + { + weechat_printf(profile->buffer, + "%sTox ID length invalid. Please try again.", + weechat_prefix("error")); + + return WEECHAT_RC_OK; + } + + char address[TOX_FRIEND_ADDRESS_SIZE]; + twc_hex2bin(argv[2], TOX_FRIEND_ADDRESS_SIZE, address); + + char *message; + if (argc == 3 || strlen(argv_eol[3]) == 0) + // TODO: default message as option + message = "Hi! Please add me on Tox!"; + else + message = argv_eol[3]; + + int32_t result = tox_add_friend(profile->tox, + (uint8_t *)address, + (uint8_t *)message, + strlen(message)); + + switch (result) + { + case TOX_FAERR_TOOLONG: + weechat_printf(profile->buffer, + "%sFriend request message too long! Try again.", + weechat_prefix("error")); + break; + case TOX_FAERR_ALREADYSENT: + weechat_printf(profile->buffer, + "%sYou have already sent a friend request to that address.", + weechat_prefix("error")); + break; + case TOX_FAERR_OWNKEY: + weechat_printf(profile->buffer, + "%sYou can't add yourself as a friend.", + weechat_prefix("error")); + break; + case TOX_FAERR_BADCHECKSUM: + weechat_printf(profile->buffer, + "%sInvalid friend address - try again.", + weechat_prefix("error")); + break; + case TOX_FAERR_NOMEM: + weechat_printf(profile->buffer, + "%sCould not add friend (out of memory).", + weechat_prefix("error")); + break; + case TOX_FAERR_UNKNOWN: + case TOX_FAERR_SETNEWNOSPAM: + case TOX_FAERR_NOMESSAGE: + weechat_printf(profile->buffer, + "%sCould not add friend (unknown error).", + weechat_prefix("error")); + break; + default: + weechat_printf(profile->buffer, + "%sFriend request sent!", + weechat_prefix("network")); + break; + } + + return WEECHAT_RC_OK; + } + + // /friend remove + else if (argc == 3 && (weechat_strcasecmp(argv[1], "remove") == 0)) + { + char *endptr; + unsigned long friend_number = strtoul(argv[2], &endptr, 10); + + if (endptr == argv[2] || !tox_friend_exists(profile->tox, friend_number)) + { + weechat_printf(profile->buffer, + "%sInvalid friend number.", + weechat_prefix("error")); + return WEECHAT_RC_OK; + } + + char *name = twc_get_name_nt(profile->tox, friend_number); + if (tox_del_friend(profile->tox, friend_number) == 0) + { + weechat_printf(profile->buffer, + "%sRemoved %s from friend list.", + weechat_prefix("network"), name); + } + else + { + weechat_printf(profile->buffer, + "%sCould not remove friend!", + weechat_prefix("error")); + } + + free(name); + + return WEECHAT_RC_OK; + } + + // friend accept|decline |all + else if (argc == 3 && + (weechat_strcasecmp(argv[1], "accept") == 0 + || weechat_strcasecmp(argv[1], "decline") == 0)) + { + int accept = weechat_strcasecmp(argv[1], "accept") == 0; + + 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) + { + if (accept) + twc_friend_request_accept(request); + else + twc_friend_request_remove(request); + + ++count; + } + + weechat_printf(profile->buffer, + "%s%s %d friend requests.", + weechat_prefix("network"), + accept ? "Accepted" : "Declined", + count); + + return WEECHAT_RC_OK; + } + else + { + char *endptr; + unsigned long num = strtoul(argv[2], &endptr, 10); + if (endptr == argv[2] || (request = twc_friend_request_with_index(profile, num)) == NULL) + { + weechat_printf(profile->buffer, + "%sInvalid friend request ID.", + weechat_prefix("error")); + return WEECHAT_RC_OK; + } + + char hex_address[TOX_CLIENT_ID_SIZE * 2 + 1]; + twc_bin2hex(request->tox_id, + TOX_CLIENT_ID_SIZE, + hex_address); + + if (accept) + twc_friend_request_accept(request); + else + twc_friend_request_remove(request); + + weechat_printf(profile->buffer, + "%s%s friend request from %s.", + weechat_prefix("network"), + accept ? "Accepted" : "Declined", + hex_address); + + return WEECHAT_RC_OK; + } + } + + // /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")); + + 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); + + weechat_printf(profile->buffer, + "%s[%d] Address: %s\n" + "[%d] Message: %s", + weechat_prefix("network"), + index, hex_address, + index, item->friend_request->message); + } + } + + return WEECHAT_RC_OK; + } + + return WEECHAT_RC_ERROR; +} + +/** + * Command /me callback. + */ +int +twc_cmd_me(void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol) +{ + if (argc == 1) + return WEECHAT_RC_ERROR; + + struct t_twc_chat *chat = twc_chat_search_buffer(buffer); + TWC_CHECK_CHAT(chat); + TWC_CHECK_PROFILE_LOADED(chat->profile); + + twc_chat_send_message(chat, argv_eol[1], TWC_MESSAGE_TYPE_ACTION); + + return WEECHAT_RC_OK; +} + +/** + * Command /msg callback. + */ +int +twc_cmd_msg(void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol) +{ + if (argc == 1) + return WEECHAT_RC_ERROR; + + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + TWC_CHECK_PROFILE(profile); + TWC_CHECK_PROFILE_LOADED(profile); + + char *endptr; + unsigned long friend_number = strtoul(argv[1], &endptr, 10); + + if (endptr == argv[1] || !tox_friend_exists(profile->tox, friend_number)) + { + weechat_printf(profile->buffer, + "%sInvalid friend number.", + weechat_prefix("error")); + return WEECHAT_RC_OK; + } + + // create chat buffer if it does not exist + struct t_twc_chat *chat = twc_chat_search_friend(profile, friend_number, true); + + // send a message if provided + if (argc >= 3) + twc_chat_send_message(chat, argv_eol[2], TWC_MESSAGE_TYPE_MESSAGE); + + return WEECHAT_RC_OK; +} + +/** + * Command /myid callback. + */ +int +twc_cmd_myid(void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol) +{ + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + TWC_CHECK_PROFILE(profile); + TWC_CHECK_PROFILE_LOADED(profile); + + uint8_t address[TOX_FRIEND_ADDRESS_SIZE]; + tox_get_address(profile->tox, address); + + char address_str[TOX_FRIEND_ADDRESS_SIZE * 2 + 1]; + twc_bin2hex(address, TOX_FRIEND_ADDRESS_SIZE, address_str); + + weechat_printf(profile->buffer, + "%sYour Tox address: %s", + weechat_prefix("network"), + address_str); + + return WEECHAT_RC_OK; +} + +/** + * Command /name callback. + */ +int +twc_cmd_name(void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol) +{ + if (argc == 1) + return WEECHAT_RC_ERROR; + + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + TWC_CHECK_PROFILE(profile); + TWC_CHECK_PROFILE_LOADED(profile); + + char *name = argv_eol[1]; + + int result = tox_set_name(profile->tox, (uint8_t *)name, strlen(name)); + if (result == -1) + { + weechat_printf(profile->buffer, + "%s%s", + weechat_prefix("error"), + "Could not change name."); + return WEECHAT_RC_OK; + } + + weechat_bar_item_update("input_prompt"); + + weechat_printf(profile->buffer, + "%sYou are now known as %s", + weechat_prefix("network"), + name); + + size_t index; + struct t_twc_list_item *item; + twc_list_foreach(profile->chats, index, item) + { + weechat_printf(item->chat->buffer, + "%sYou are now known as %s", + weechat_prefix("network"), + name); + } + + return WEECHAT_RC_OK; +} + +/** + * Command /status callback. + */ +int +twc_cmd_status(void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol) +{ + if (argc != 2) + return WEECHAT_RC_ERROR; + + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + TWC_CHECK_PROFILE(profile); + TWC_CHECK_PROFILE_LOADED(profile); + + TOX_USERSTATUS status = TOX_USERSTATUS_INVALID; + if (weechat_strcasecmp(argv[1], "online") == 0) + status = TOX_USERSTATUS_NONE; + else if (weechat_strcasecmp(argv[1], "busy") == 0) + status = TOX_USERSTATUS_BUSY; + else if (weechat_strcasecmp(argv[1], "away") == 0) + status = TOX_USERSTATUS_AWAY; + + if (status == TOX_USERSTATUS_INVALID) + return WEECHAT_RC_ERROR; + + tox_set_user_status(profile->tox, status); + weechat_bar_item_update("away"); + + return WEECHAT_RC_OK; +} + +/** + * Command /statusmsg callback. + */ +int +twc_cmd_statusmsg(void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol) +{ + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + TWC_CHECK_PROFILE(profile); + TWC_CHECK_PROFILE_LOADED(profile); + + char *message = argc > 1 ? argv_eol[1] : " "; + + int result = tox_set_status_message(profile->tox, + (uint8_t *)message, + strlen(message)); + if (result == -1) + { + weechat_printf(profile->buffer, + "%s%s", + weechat_prefix("error"), + "Could not set status message."); + } + + return WEECHAT_RC_OK; +} + +/** + * Command /tox callback. + */ +int +twc_cmd_tox(void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol) +{ + // /tox [list] + if (argc == 1 || (argc == 2 && weechat_strcasecmp(argv[1], "list") == 0)) + { + weechat_printf(NULL, + "%sAll Tox profiles:", + weechat_prefix("network")); + size_t index; + struct t_twc_list_item *item; + twc_list_foreach(twc_profiles, index, item) + { + weechat_printf(NULL, + "%s%s", + weechat_prefix("network"), + item->profile->name); + } + + return WEECHAT_RC_OK; + } + + // /tox create + else if (argc == 3 && (weechat_strcasecmp(argv[1], "create") == 0)) + { + char *name = argv[2]; + + if (twc_profile_search_name(name)) + { + weechat_printf(NULL, + "%s%s: profile \"%s\" already exists!", + weechat_prefix("error"), weechat_plugin->name, + name); + return WEECHAT_RC_OK; + } + + struct t_twc_profile *profile = twc_profile_new(name); + weechat_printf(NULL, + "%s%s: profile \"%s\" created!", + weechat_prefix("network"), weechat_plugin->name, + profile->name); + + return WEECHAT_RC_OK; + } + + // /tox delete + else if ((argc == 3 || argc == 4) + && (weechat_strcasecmp(argv[1], "delete") == 0)) + { + char *name = argv[2]; + char *flag = argv[3]; + + struct t_twc_profile *profile = twc_profile_search_name(name); + TWC_CHECK_PROFILE_EXISTS(profile); + + if (argc == 4 && strcmp(flag, "-keepdata") == 0) + { + twc_profile_delete(profile, false); + } + else if (argc == 4 && strcmp(flag, "-yes") == 0) + { + twc_profile_delete(profile, true); + } + else + { + weechat_printf(NULL, + "%s%s: You must confirm deletion with either " + "\"-keepdata\" or \"-yes\" (see /help tox)", + weechat_prefix("error"), weechat_plugin->name); + return WEECHAT_RC_OK; + } + + weechat_printf(NULL, + "%s%s: profile \"%s\" has been deleted.", + weechat_prefix("error"), weechat_plugin->name, + name); + + return WEECHAT_RC_OK; + } + + // /tox load + else if (argc >= 2 && (weechat_strcasecmp(argv[1], "load") == 0)) + { + if (argc == 2) + { + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + if (!profile) + return WEECHAT_RC_ERROR; + + twc_profile_load(profile); + } + else + { + for (int i = 2; i < argc; ++i) + { + char *name = argv[i]; + struct t_twc_profile *profile = twc_profile_search_name(name); + TWC_CHECK_PROFILE_EXISTS(profile); + + twc_profile_load(profile); + } + } + + return WEECHAT_RC_OK; + } + + // /tox unload + else if (argc >= 2 && (weechat_strcasecmp(argv[1], "unload") == 0)) + { + if (argc == 2) + { + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + if (!profile) + return WEECHAT_RC_ERROR; + + twc_profile_unload(profile); + } + else + { + for (int i = 2; i < argc; ++i) + { + char *name = argv[i]; + struct t_twc_profile *profile = twc_profile_search_name(name); + TWC_CHECK_PROFILE_EXISTS(profile); + + twc_profile_unload(profile); + } + } + + return WEECHAT_RC_OK; + } + + return WEECHAT_RC_ERROR; +} + +/** + * Register Tox-WeeChat commands. + */ +void +twc_commands_init() +{ + weechat_hook_command("bootstrap", + "manage bootstrap nodes", + "connect
", + "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); + + weechat_hook_command("friend", + "manage friends", + "list" + " || add
[]" + " || remove " + " || requests" + " || accept |all" + " || decline |all", + " list: list all friends\n" + " add: add a friend by their public Tox address\n" + "requests: list friend requests\n" + " accept: accept friend requests\n" + " decline: decline friend requests\n", + NULL, twc_cmd_friend, NULL); + + weechat_hook_command("me", + "send an action to the current chat", + "", + "message: message to send", + NULL, twc_cmd_me, NULL); + + weechat_hook_command("msg", + "send a message to a Tox friend", + " []", + " id: friend number of the person to message\n" + "message: message to send", + NULL, twc_cmd_msg, NULL); + + weechat_hook_command("myid", + "get your Tox ID to give to friends", + "", "", + NULL, twc_cmd_myid, NULL); + + weechat_hook_command("name", + "change your Tox name", + "", + "name: your new name", + NULL, twc_cmd_name, NULL); + + weechat_hook_command("status", + "change your Tox status", + "online|busy|away", + "", + NULL, twc_cmd_status, NULL); + + weechat_hook_command("statusmsg", + "change your Tox status message", + "[]", + "message: your new status message", + NULL, twc_cmd_statusmsg, NULL); + + weechat_hook_command("tox", + "manage Tox profiles", + "list" + " || create " + " || delete -yes|-keepdata" + " || load [...]" + " || unload [...]", + " list: list all Tox profile\n" + "create: create a new Tox profile\n" + "delete: delete a Tox profile; requires either -yes " + "to confirm deletion or -keepdata to delete the " + "profile but keep the Tox data file\n" + " load: load a Tox profile and connect to the network\n" + "unload: unload a Tox profile\n", + "list" + " || create" + " || delete %(tox_profiles) -yes|-keepdata" + " || load %(tox_unloaded_profiles)|%*" + " || unload %(tox_loaded_profiles)|%*", + twc_cmd_tox, NULL); +} + diff --git a/src/tox-weechat-commands.h b/src/twc-commands.h similarity index 92% rename from src/tox-weechat-commands.h rename to src/twc-commands.h index b54a8ea..a0fb650 100644 --- a/src/tox-weechat-commands.h +++ b/src/twc-commands.h @@ -20,9 +20,7 @@ #ifndef TOX_WEECHAT_COMMANDS_H #define TOX_WEECHAT_COMMANDS_H -/** - * Register command callbacks. - */ -void tox_weechat_commands_init(); +void twc_commands_init(); #endif // TOX_WEECHAT_COMMANDS_H + diff --git a/src/twc-completion.c b/src/twc-completion.c new file mode 100644 index 0000000..b69544a --- /dev/null +++ b/src/twc-completion.c @@ -0,0 +1,83 @@ +/* + * 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 "twc.h" +#include "twc-profile.h" +#include "twc-list.h" + +#include "twc-completion.h" + +enum +{ + TWC_ALL_PROFILES, + TWC_LOADED_PROFILES, + TWC_UNLOADED_PROFILES, +}; + +/** + * Complete a profile name, possibly filtering by loaded/unloaded profiles. + */ +int +twc_completion_profile(void *data, + const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + int flag = (int)(intptr_t)data; + + size_t index; + struct t_twc_list_item *item; + twc_list_foreach(twc_profiles, index, item) + { + if (flag == TWC_ALL_PROFILES + || (flag == TWC_LOADED_PROFILES && item->profile->tox != NULL) + || (flag == TWC_UNLOADED_PROFILES && item->profile->tox == NULL)) + { + weechat_hook_completion_list_add(completion, + item->profile->name, + 0, + WEECHAT_LIST_POS_SORT); + } + } + + return WEECHAT_RC_OK; +} + +void +twc_completion_init() +{ + weechat_hook_completion("tox_profiles", + "profile", + twc_completion_profile, + (void *)(intptr_t)TWC_ALL_PROFILES); + weechat_hook_completion("tox_loaded_profiles", + "profile", + twc_completion_profile, + (void *)(intptr_t)TWC_LOADED_PROFILES); + weechat_hook_completion("tox_unloaded_profiles", + "profile", + twc_completion_profile, + (void *)(intptr_t)TWC_UNLOADED_PROFILES); +} + diff --git a/src/twc-completion.h b/src/twc-completion.h new file mode 100644 index 0000000..86c9035 --- /dev/null +++ b/src/twc-completion.h @@ -0,0 +1,27 @@ +/* + * 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 TOX_WEECHAT_COMPLETION_H +#define TOX_WEECHAT_COMPLETION_H + +void +twc_completion_init(); + +#endif // TOX_WEECHAT_COMPLETION_H + diff --git a/src/twc-config.c b/src/twc-config.c new file mode 100644 index 0000000..2c30cdb --- /dev/null +++ b/src/twc-config.c @@ -0,0 +1,288 @@ +/* + * 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-config.h" + +struct t_config_file *twc_config_file = NULL; +struct t_config_section *twc_config_section_profile = NULL; + +char *twc_profile_option_names[TWC_PROFILE_NUM_OPTIONS] = +{ + "save_file", + "autoload", + "max_friend_requests", +}; + +char *twc_profile_option_defaults[TWC_PROFILE_NUM_OPTIONS] = +{ + "%h/tox/%p", + "off", + "100", +}; + +/** + * Get the index of a profile option name. + */ +int +twc_config_profile_option_search(const char *option_name) +{ + for (int i = 0; i < TWC_PROFILE_NUM_OPTIONS; ++i) + { + if (strcmp(twc_profile_option_names[i], option_name) == 0) + return i; + } + + return -1; +} + +/** + * Called when a profile option is read. + */ +int +twc_config_profile_read_callback(void *data, + struct t_config_file *config_file, + struct t_config_section *section, + const char *option_name, + const char *value) +{ + int rc = WEECHAT_CONFIG_OPTION_SET_ERROR; + + if (option_name) + { + char *dot_pos = strrchr(option_name, '.'); + if (dot_pos) + { + char *profile_name = weechat_strndup(option_name, + dot_pos-option_name); + char *option_name = dot_pos + 1; + if (profile_name) + { + int option_index = twc_config_profile_option_search(option_name); + if (option_index >= 0) + { + struct t_twc_profile *profile = + twc_profile_search_name(profile_name); + + if (!profile) + profile = twc_profile_new(profile_name); + + if (profile) + { + rc = weechat_config_option_set(profile->options[option_index], + value, 1); + } + else + { + weechat_printf(NULL, + "%s%s: error creating profile \"%s\"", + weechat_prefix("error"), + weechat_plugin->name, + profile_name); + } + } + + free(profile_name); + } + } + } + + if (rc == WEECHAT_CONFIG_OPTION_SET_ERROR) + { + weechat_printf(NULL, + "%s%s: error creating profile option \"%s\"", + weechat_prefix("error"), weechat_plugin->name, + option_name); + } + + return rc; +} + +/** + * Called when profile options should be written. + */ +int +twc_config_profile_write_callback(void *data, + struct t_config_file *config_file, + const char *section_name) +{ + if (!weechat_config_write_line (config_file, section_name, NULL)) + return WEECHAT_CONFIG_WRITE_ERROR; + + size_t index; + struct t_twc_list_item *item; + twc_list_foreach(twc_profiles, index, item) + { + for (int i = 0; i < TWC_PROFILE_NUM_OPTIONS; ++i) + { + if (!weechat_config_write_option(twc_config_file, + item->profile->options[i])) + { + return WEECHAT_CONFIG_WRITE_ERROR; + } + } + } + + return WEECHAT_CONFIG_WRITE_OK; +} + +/** + * Callback for checking an option value being set for a profile. + */ +int +twc_config_profile_check_value_callback(void *data, + struct t_config_option *option, + const char *value) +{ + return 1; // 1=ok, 0=not ok +} + +/** + * Callback for option being changed for a profile. + */ +void +twc_config_profile_change_callback(void *data, + struct t_config_option *option) +{ +} + +/** + * Initialize Tox-WeeChat config. Creates file and section objects. + */ +void +twc_config_init() +{ + twc_config_file = weechat_config_new("tox", NULL, NULL); + + twc_config_section_profile = + weechat_config_new_section(twc_config_file, "profile", + 0, 0, + twc_config_profile_read_callback, NULL, + twc_config_profile_write_callback, NULL, + NULL, NULL, + NULL, NULL, + NULL, NULL); +} + +/** + * Create a new option for a profile. + */ +struct t_config_option * +twc_config_init_option(int option_index, const char *option_name) +{ + switch (option_index) + { + case TWC_PROFILE_OPTION_AUTOLOAD: + return weechat_config_new_option( + twc_config_file, twc_config_section_profile, + option_name, "boolean", + "automatically load a profile and connect to the Tox network " + "when WeeChat starts", + NULL, 0, 0, + twc_profile_option_defaults[option_index], + NULL, + 0, + twc_config_profile_check_value_callback, NULL, + twc_config_profile_change_callback, NULL, + NULL, NULL); + case TWC_PROFILE_OPTION_MAX_FRIEND_REQUESTS: + return weechat_config_new_option( + twc_config_file, twc_config_section_profile, + option_name, "integer", + "maximum amount of friend requests to retain before dropping " + "new ones", + NULL, 0, INT_MAX, + twc_profile_option_defaults[option_index], + NULL, + 0, + twc_config_profile_check_value_callback, NULL, + twc_config_profile_change_callback, NULL, + NULL, NULL); + case TWC_PROFILE_OPTION_SAVEFILE: + return weechat_config_new_option( + twc_config_file, twc_config_section_profile, + option_name, "string", + "path to Tox data file (\"%h\" will be replaced by WeeChat " + "home, \"%p\" by the profile name); will be created if it does " + "not exist.", + NULL, 0, 0, + twc_profile_option_defaults[option_index], + NULL, + 0, + twc_config_profile_check_value_callback, NULL, + twc_config_profile_change_callback, NULL, + NULL, NULL); + default: + return NULL; + } +} + +/** + * Initialize options for a given profile. + */ +void +twc_config_init_profile(struct t_twc_profile *profile) +{ + for (int i = 0; i < TWC_PROFILE_NUM_OPTIONS; ++i) + { + // length: name + . + option + \0 + size_t length = strlen(profile->name) + 1 + + strlen(twc_profile_option_names[i]) + 1; + + char *option_name = malloc(sizeof(*option_name) * length); + if (option_name) + { + snprintf(option_name, length, "%s.%s", + profile->name, + twc_profile_option_names[i]); + + profile->options[i] = twc_config_init_option(i, option_name); + free (option_name); + } + } +} + +/** + * Read config data from file, creating profile objects for stored profiles. + */ +int +twc_config_read() +{ + return weechat_config_read(twc_config_file); +} + +/** + * Write config data to disk. + */ +int +twc_config_write() +{ + return weechat_config_write(twc_config_file); +} + diff --git a/src/tox-weechat-config.h b/src/twc-config.h similarity index 73% rename from src/tox-weechat-config.h rename to src/twc-config.h index fea56af..745075e 100644 --- a/src/tox-weechat-config.h +++ b/src/twc-config.h @@ -20,21 +20,19 @@ #ifndef TOX_WEECHAT_CONFIG_H #define TOX_WEECHAT_CONFIG_H -#include "tox-weechat-identities.h" - -extern struct t_config_file *tox_weechat_config_file; -extern struct t_config_section *tox_weechat_config_section_identity; +#include "twc-profile.h" void -tox_weechat_config_init(); +twc_config_init(); int -tox_weechat_config_read(); +twc_config_read(); int -tox_weechat_config_write(); +twc_config_write(); void -tox_weechat_config_init_identity(struct t_tox_weechat_identity *identity); +twc_config_init_profile(struct t_twc_profile *profile); #endif // TOX_WEECHAT_CONFIG_H + diff --git a/src/twc-data.c b/src/twc-data.c new file mode 100644 index 0000000..1574530 --- /dev/null +++ b/src/twc-data.c @@ -0,0 +1,19 @@ +/* + * 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 . + */ + diff --git a/src/tox-weechat-data.h b/src/twc-data.h similarity index 75% rename from src/tox-weechat-data.h rename to src/twc-data.h index d9d9b48..28f4310 100644 --- a/src/tox-weechat-data.h +++ b/src/twc-data.h @@ -20,21 +20,5 @@ #ifndef TOX_WEECHAT_DATA_H #define TOX_WEECHAT_DATA_H -struct t_tox_weechat_identity; - -void -tox_weechat_data_load(); - -void -tox_weechat_data_identity_save(struct t_tox_weechat_identity *identity); - -void -tox_weechat_data_identity_load(struct t_tox_weechat_identity *identity); - -int -tox_weechat_data_save(); - -void -tox_weechat_data_free(); - #endif // TOX_WEECHAT_DATA_H + diff --git a/src/twc-friend-request.c b/src/twc-friend-request.c new file mode 100644 index 0000000..6bdb57d --- /dev/null +++ b/src/twc-friend-request.c @@ -0,0 +1,125 @@ +/* + * 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-profile.h" +#include "twc-list.h" +#include "twc-utils.h" + +#include "twc-friend-request.h" + +/** + * Add a new friend request to an profile. + * + * Returns 0 on success, -1 on a full friend request list, -2 on other error. + */ +int +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)); + if (!request) + return -2; + + request->profile = profile; + request->message = strdup(message); + memcpy(request->tox_id, client_id, TOX_CLIENT_ID_SIZE); + + // add to list + twc_list_item_new_data_add(profile->friend_requests, request); + + return 0; +} + +/** + * Accept a friend request. Remove and free the request. + */ +void +twc_friend_request_accept(struct t_twc_friend_request *request) +{ + tox_add_friend_norequest(request->profile->tox, request->tox_id); + twc_friend_request_remove(request); +} + +/** + * Remove and free a friend request from its profile. + */ +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); +} + +/** + * Get friend request with a given index. + */ +struct t_twc_friend_request * +twc_friend_request_with_index(struct t_twc_profile *profile, + unsigned int index) +{ + struct t_twc_list_item *item = twc_list_get(profile->friend_requests, index); + if (item) + return item->friend_request; + else + return NULL; +} + +/** + * Free a friend request. + */ +void +twc_friend_request_free(struct t_twc_friend_request *request) +{ + free(request->message); + free(request); +} + +/** + * Free all friend requests from a profile. + */ +void +twc_friend_request_free_profile(struct t_twc_profile *profile) +{ + struct t_twc_friend_request *request; + + while ((request = twc_list_pop(profile->friend_requests))) + twc_friend_request_free(request); + + free(profile->friend_requests); +} + diff --git a/src/twc-friend-request.h b/src/twc-friend-request.h new file mode 100644 index 0000000..cc41c05 --- /dev/null +++ b/src/twc-friend-request.h @@ -0,0 +1,60 @@ +/* + * 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 TOX_WEECHAT_FRIEND_REQUEST_H +#define TOX_WEECHAT_FRIEND_REQUEST_H + +#include + +#include + +/** + * Represents a friend request with a Tox ID and a message. + */ +struct t_twc_friend_request +{ + struct t_twc_profile *profile; + + uint8_t tox_id[TOX_CLIENT_ID_SIZE]; + char *message; +}; + +int +twc_friend_request_add(struct t_twc_profile *profile, + const uint8_t *client_id, + const char *message); + +void +twc_friend_request_accept(struct t_twc_friend_request *request); + +void +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); + +void +twc_friend_request_free(struct t_twc_friend_request *request); + +void +twc_friend_request_free_profile(struct t_twc_profile *profile); + +#endif // TOX_WEECHAT_FRIEND_REQUEST_H + diff --git a/src/twc-gui.c b/src/twc-gui.c new file mode 100644 index 0000000..2c3ad25 --- /dev/null +++ b/src/twc-gui.c @@ -0,0 +1,109 @@ +/* + * 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-profile.h" +#include "twc-utils.h" + +#include "twc-gui.h" + +char * +twc_bar_item_away(void *data, + struct t_gui_bar_item *item, + struct t_gui_window *window, + struct t_gui_buffer *buffer, + struct t_hashtable *extra_info) +{ + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + + if (!profile || !(profile->tox)) + return NULL; + + char *status = NULL;; + switch (tox_get_self_user_status(profile->tox)) + { + case TOX_USERSTATUS_BUSY: + status = strdup("busy"); + break; + case TOX_USERSTATUS_AWAY: + status = strdup("away"); + break; + } + + return status; +} + +char * +twc_bar_item_input_prompt(void *data, + struct t_gui_bar_item *item, + struct t_gui_window *window, + struct t_gui_buffer *buffer, + struct t_hashtable *extra_info) +{ + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + + if (!profile || !(profile->tox)) + return NULL; + + return twc_get_self_name_nt(profile->tox); +} + +char * +twc_bar_item_buffer_plugin(void *data, struct t_gui_bar_item *item, + struct t_gui_window *window, + struct t_gui_buffer *buffer, + struct t_hashtable *extra_info) +{ + struct t_twc_profile *profile = twc_profile_search_buffer(buffer); + + char string[256]; + + const char *plugin_name = weechat_plugin_get_name(weechat_plugin); + + if (!profile) + return strdup(plugin_name); + + const char *profile_name = profile->name; + + snprintf(string, sizeof(string), + "%s%s/%s%s%s/%s%s", + plugin_name, + weechat_color("bar_delim"), + weechat_color("bar_fg"), + profile_name, + weechat_color("bar_delim"), + weechat_color("bar_fg"), + profile->tox_online ? "online" : "offline"); + + return strdup(string); +} + +void twc_gui_init() +{ + weechat_bar_item_new("away", twc_bar_item_away, NULL); + weechat_bar_item_new("input_prompt", twc_bar_item_input_prompt, NULL); + weechat_bar_item_new("buffer_plugin", twc_bar_item_buffer_plugin, NULL); +} + diff --git a/src/tox-weechat-gui.h b/src/twc-gui.h similarity index 96% rename from src/tox-weechat-gui.h rename to src/twc-gui.h index 77bc478..7dd05c7 100644 --- a/src/tox-weechat-gui.h +++ b/src/twc-gui.h @@ -20,6 +20,7 @@ #ifndef TOX_WEECHAT_GUI_H #define TOX_WEECHAT_GUI_H -void tox_weechat_gui_init(); +void twc_gui_init(); #endif // TOX_WEECHAT_GUI_H + diff --git a/src/twc-list.c b/src/twc-list.c new file mode 100644 index 0000000..973c044 --- /dev/null +++ b/src/twc-list.c @@ -0,0 +1,187 @@ +/* + * 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 "twc-list.h" + +/** + * Create and return a new list. + */ +struct t_twc_list * +twc_list_new() +{ + struct t_twc_list *list = malloc(sizeof(struct t_twc_list)); + + list->head = list->tail = NULL; + list->count = 0; + + return list; +} + +/** + * Create and return a new list item. + */ +struct t_twc_list_item * +twc_list_item_new() +{ + struct t_twc_list_item *item = malloc(sizeof(struct t_twc_list_item)); + + return item; +} + +/** + * Create and return a new list item with data. + */ +struct t_twc_list_item * +twc_list_item_new_data(const void *data) +{ + struct t_twc_list_item *item = twc_list_item_new(); + item->data = (void *)data; + + return item; +} + +/** + * Create a new list item, add it to a list and return the item. + */ +struct t_twc_list_item * +twc_list_item_new_add(struct t_twc_list *list) +{ + struct t_twc_list_item *item = twc_list_item_new(); + twc_list_add(list, item); + return item; +} + +/** + * Create a new list item with data, add it to a list and return the item. + */ +struct t_twc_list_item * +twc_list_item_new_data_add(struct t_twc_list *list, const void *data) +{ + struct t_twc_list_item *item = twc_list_item_new_data(data); + twc_list_add(list, item); + return item; +} + +/** + * Add an item to the list. + */ +void +twc_list_add(struct t_twc_list *list, + struct t_twc_list_item *item) +{ + item->list = list; + + item->prev_item = list->tail; + item->next_item = NULL; + + if (list->head == NULL) + list->head = item; + else + list->tail->next_item = item; + + list->tail = item; + + ++(list->count); +} + +/** + * Remove an item from the list it's in. Frees the item, but not the data + * associated with it. + * + * Returns the data of the removed item. + */ +void * +twc_list_remove(struct t_twc_list_item *item) +{ + struct t_twc_list *list = item->list; + + if (item == list->tail) + list->tail = item->prev_item; + + if (item->prev_item) + item->prev_item->next_item = item->next_item; + else + list->head = item->next_item; + + if (item->next_item) + item->next_item->prev_item = item->prev_item; + + --(list->count); + + void *data = item->data; + + free(item); + + return data; +} + +/** + * Remove an item with the given data from the list. Frees the item, but not + * the data. + */ +void +twc_list_remove_with_data(struct t_twc_list *list, const void *data) +{ + size_t index; + struct t_twc_list_item *item; + twc_list_foreach(list, index, item) + { + if (item->data == data) + { + twc_list_remove(item); + break; + } + } +} + +/** + * Remove the last item from the list. Frees the item, and returns the data + * associated with it. + */ +void * +twc_list_pop(struct t_twc_list *list) +{ + if (list->tail) + return twc_list_remove(list->tail); + else + return NULL; +} + +/** + * Return the list item at an index, or NULL if it does not exist. + */ +struct t_twc_list_item * +twc_list_get(struct t_twc_list *list, size_t index) +{ + if (index > list->count) + return NULL; + + size_t current_index; + struct t_twc_list_item *item; + twc_list_foreach(list, current_index, item) + { + if (current_index == index) + { + return item; + } + } + + return NULL; +} + diff --git a/src/twc-list.h b/src/twc-list.h new file mode 100644 index 0000000..5d09192 --- /dev/null +++ b/src/twc-list.h @@ -0,0 +1,87 @@ +/* + * 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 TOX_WEECHAT_LIST_H +#define TOX_WEECHAT_LIST_H + +#include + +struct t_twc_list +{ + size_t count; + struct t_twc_list_item *head; + struct t_twc_list_item *tail; +}; + +struct t_twc_list_item +{ + struct t_twc_list *list; + + // don't know if this is a good idea + // probably not + union + { + void *data; + struct t_twc_profile *profile; + struct t_twc_friend_request *friend_request; + struct t_twc_chat *chat; + struct t_twc_queued_message *queued_message; + }; + + struct t_twc_list_item *next_item; + struct t_twc_list_item *prev_item; +}; + +struct t_twc_list * +twc_list_new(); + +struct t_twc_list_item * +twc_list_item_new(); + +struct t_twc_list_item * +twc_list_item_new_data(const void *data); + +struct t_twc_list_item * +twc_list_item_new_add(struct t_twc_list *list); + +struct t_twc_list_item * +twc_list_item_new_data_add(struct t_twc_list *list, const void *data); + +void +twc_list_add(struct t_twc_list *list, struct t_twc_list_item *item); + +void * +twc_list_remove(struct t_twc_list_item *item); + +void +twc_list_remove_with_data(struct t_twc_list *list, const void *data); + +void * +twc_list_pop(struct t_twc_list *list); + +struct t_twc_list_item * +twc_list_get(struct t_twc_list *list, size_t index); + +#define twc_list_foreach(list, index, item) \ + for (item = list->head, index = 0; \ + item; \ + item = item->next_item, ++index) + +#endif // TOX_WEECHAT_LIST_H + diff --git a/src/twc-message-queue.c b/src/twc-message-queue.c new file mode 100644 index 0000000..a751121 --- /dev/null +++ b/src/twc-message-queue.c @@ -0,0 +1,166 @@ +/* + * 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 "twc.h" +#include "twc-profile.h" +#include "twc-utils.h" +#include "twc-list.h" + +#include "twc-message-queue.h" + +/** + * Get a message queue for a friend, or create one if it does not exist. + */ +struct t_twc_list * +twc_message_queue_get_or_create(struct t_twc_profile *profile, + int32_t friend_number) +{ + struct t_twc_list *message_queue = weechat_hashtable_get(profile->message_queues, &friend_number); + if (!message_queue) + { + message_queue = twc_list_new(); + weechat_hashtable_set(profile->message_queues, + &friend_number, + message_queue); + } + + return message_queue; +} + +/** + * Add a friend message to the message queue and tries to send it if the + * friend is online. Handles splitting of messages. (TODO: actually split messages) + */ +void +twc_message_queue_add_friend_message(struct t_twc_profile *profile, + int32_t friend_number, + const char *message, + enum TWC_MESSAGE_TYPE message_type) +{ + struct t_twc_queued_message *queued_message + = malloc(sizeof(struct t_twc_queued_message)); + + time_t rawtime = time(NULL); + queued_message->time = malloc(sizeof(struct tm)); + memcpy(queued_message->time, gmtime(&rawtime), sizeof(struct tm)); + + queued_message->message = strdup(message); + queued_message->message_type = message_type; + + // create a queue if needed and add message + struct t_twc_list *message_queue + = twc_message_queue_get_or_create(profile, friend_number); + twc_list_item_new_data_add(message_queue, queued_message); + + // flush if friend is online + if (profile->tox + && tox_get_friend_connection_status(profile->tox, friend_number) == 1) + twc_message_queue_flush_friend(profile, friend_number); +} + +/** + * Try sending queued messages for a friend. + */ +void +twc_message_queue_flush_friend(struct t_twc_profile *profile, + int32_t friend_number) +{ + struct t_twc_list *message_queue + = twc_message_queue_get_or_create(profile, friend_number); + + size_t index; + struct t_twc_list_item *item; + twc_list_foreach(message_queue, index, item) + { + struct t_twc_queued_message *queued_message = item->queued_message; + + // TODO: store and deal with message IDs + uint32_t rc; + switch(queued_message->message_type) + { + case TWC_MESSAGE_TYPE_MESSAGE: + rc = tox_send_message(profile->tox, + friend_number, + (uint8_t *)queued_message->message, + strlen(queued_message->message)); + break; + case TWC_MESSAGE_TYPE_ACTION: + rc = tox_send_action(profile->tox, + friend_number, + (uint8_t *)queued_message->message, + strlen(queued_message->message)); + break; + } + + if (rc == 0) + { + // break if message send failed + break; + } + else + { + // message was sent, free it + twc_message_queue_free_message(queued_message); + item->queued_message = NULL; + } + } + + // remove any now-empty items + while (message_queue->head && !(message_queue->head->queued_message)) + twc_list_remove(message_queue->head); +} + +/** + * Free a queued message. + */ +void +twc_message_queue_free_message(struct t_twc_queued_message *message) +{ + free(message->time); + free(message->message); + free(message); +} + +void +twc_message_queue_free_map_callback(void *data, struct t_hashtable *hashtable, + const void *key, const void *value) +{ + struct t_twc_list *message_queue = ((struct t_twc_list *)value); + + struct t_twc_queued_message *message; + while ((message = twc_list_pop(message_queue))) + twc_message_queue_free_message(message); + + free(message_queue); +} + +void +twc_message_queue_free_profile(struct t_twc_profile *profile) +{ + weechat_hashtable_map(profile->message_queues, + twc_message_queue_free_map_callback, NULL); + weechat_hashtable_free(profile->message_queues); +} + diff --git a/src/twc-message-queue.h b/src/twc-message-queue.h new file mode 100644 index 0000000..cc6d393 --- /dev/null +++ b/src/twc-message-queue.h @@ -0,0 +1,56 @@ +/* + * 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 TOX_WEECHAT_MESSAGE_QUEUE_H +#define TOX_WEECHAT_MESSAGE_QUEUE_H + +#include + +#include + +#include "twc-chat.h" + +struct t_twc_profile; +struct t_twc_list_item; + +struct t_twc_queued_message +{ + struct tm *time; + char *message; + enum TWC_MESSAGE_TYPE message_type; +}; + +void +twc_message_queue_add_friend_message(struct t_twc_profile *profile, + int32_t friend_number, + const char *message, + enum TWC_MESSAGE_TYPE message_type); + +void +twc_message_queue_flush_friend(struct t_twc_profile *profile, + int32_t friend_number); + +void +twc_message_queue_free_message(struct t_twc_queued_message *message); + +void +twc_message_queue_free_profile(struct t_twc_profile *profile); + +#endif // TOX_WEECHAT_MESSAGE_QUEUE_H + diff --git a/src/twc-profile.c b/src/twc-profile.c new file mode 100644 index 0000000..0b5f20e --- /dev/null +++ b/src/twc-profile.c @@ -0,0 +1,456 @@ +/* + * 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 +#include + +#include +#include + +#include "twc.h" +#include "twc-bootstrap.h" +#include "twc-list.h" +#include "twc-config.h" +#include "twc-friend-request.h" +#include "twc-message-queue.h" +#include "twc-chat.h" +#include "twc-tox-callbacks.h" +#include "twc-utils.h" +#include "twc-data.h" + +#include "twc-profile.h" + +struct t_twc_list *twc_profiles = NULL; + +/** + * Get a profile's expanded data path, replacing: + * - %h with WeeChat home + * - %p with profile name + * + * Returned string must be freed. + */ +char * +twc_profile_expanded_data_path(struct t_twc_profile *profile) +{ + const char *weechat_dir = weechat_info_get ("weechat_dir", NULL); + const char *base_path = weechat_config_string(profile->options[TWC_PROFILE_OPTION_SAVEFILE]); + char *home_expanded = weechat_string_replace(base_path, "%h", weechat_dir); + char *full_path = weechat_string_replace(home_expanded, "%p", profile->name); + free(home_expanded); + + return full_path; +} + +/** + * Try loading a Tox save file for a profile. + * + * Returns 0 on success, -1 on failure. + * + * TODO: support encrypted save files + */ +int +twc_profile_load_data(struct t_twc_profile *profile) +{ + char *full_path = twc_profile_expanded_data_path(profile); + FILE *file = fopen(full_path, "r"); + free(full_path); + + if (file) + { + // get file size + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + rewind(file); + + // allocate a buffer and read file into it + uint8_t *data = malloc(sizeof(*data) * size); + fread(data, sizeof(uint8_t), size, file); + fclose(file); + + // try loading the data + int status = tox_load(profile->tox, data, size); + free(data); + + return status; + } + + return -1; +} + +/** + * Save a profile's Tox data to disk. + * + * Returns 0 on success, -1 on failure. + * + * TODO: support encrypted save files + */ +int +twc_save_profile_data_file(struct t_twc_profile *profile) +{ + if (!(profile->tox)) + return -1; + + char *full_path = twc_profile_expanded_data_path(profile); + + // create containing folder if it doesn't exist + char *rightmost_slash = strrchr(full_path, '/'); + char *dir_path = weechat_strndup(full_path, rightmost_slash - full_path); + weechat_mkdir_parents(dir_path, 0755); + free(dir_path); + + // save Tox data to a buffer + uint32_t size = tox_size(profile->tox); + uint8_t *data = malloc(size); + tox_save(profile->tox, data); + + // save buffer to a file + FILE *file = fopen(full_path, "w"); + if (file) + { + size_t saved_size = fwrite(data, sizeof(data[0]), size, file); + fclose(file); + + return saved_size == size; + } + + return -1; +} + +/** + * Callback when a profile's main buffer is closed. Unloads the profile. + */ +int +twc_profile_buffer_close_callback(void *data, + struct t_gui_buffer *buffer) +{ + struct t_twc_profile *profile = data; + + profile->buffer = NULL; + twc_profile_unload(profile); + + return WEECHAT_RC_OK; +} + +/** + * Initialize the Tox profiles list. + */ +void +twc_profile_init() +{ + twc_profiles = twc_list_new(); +} + +/** + * Create a new profile object and add it to the list of profiles. + */ +struct t_twc_profile * +twc_profile_new(const char *name) +{ + struct t_twc_profile *profile = malloc(sizeof(struct t_twc_profile)); + profile->name = strdup(name); + + // add to profile list + twc_list_item_new_data_add(twc_profiles, profile); + + // set up internal vars + profile->tox = NULL; + profile->buffer = NULL; + profile->tox_do_timer = NULL; + profile->tox_online = false; + + profile->chats = twc_list_new(); + profile->friend_requests = twc_list_new(); + profile->message_queues = weechat_hashtable_new(10, + WEECHAT_HASHTABLE_INTEGER, + WEECHAT_HASHTABLE_POINTER, + NULL, NULL); + + // set up config + twc_config_init_profile(profile); + + return profile; +} + +/** + * Load a profile's Tox object, creating a new one if it can't be loaded from + * disk, and bootstraps the Tox DHT. + */ +void +twc_profile_load(struct t_twc_profile *profile) +{ + if (profile->tox) + return; + + if (!(profile->buffer)) + { + // create main buffer + profile->buffer = weechat_buffer_new(profile->name, + NULL, NULL, + twc_profile_buffer_close_callback, profile); + if (!(profile->buffer)) + return; + } + + weechat_printf(profile->buffer, + "%s%s: profile %s connecting", + 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)) + { + weechat_printf(profile->buffer, + "Could not create Tox instance!", + weechat_prefix("error"), weechat_plugin->name); + return; + } + + // try loading Tox saved data + if (twc_profile_load_data(profile) == -1) + { + // we failed to load - set some defaults + char *name; + struct passwd *user_pwd; + if ((user_pwd = getpwuid(geteuid()))) + name = user_pwd->pw_name; + else + name = "Tox-WeeChat User"; + + tox_set_name(profile->tox, + (uint8_t *)name, strlen(name)); + } + + // bootstrap DHT + // TODO: add count to config + int bootstrap_node_count = 5; + for (int i = 0; i < bootstrap_node_count; ++i) + twc_bootstrap_random_node(profile->tox); + + // start Tox_do loop + twc_do_timer_cb(profile, 0); + + // register Tox callbacks + tox_callback_friend_message(profile->tox, twc_friend_message_callback, profile); + tox_callback_friend_action(profile->tox, twc_friend_action_callback, profile); + tox_callback_connection_status(profile->tox, twc_connection_status_callback, profile); + tox_callback_name_change(profile->tox, twc_name_change_callback, profile); + tox_callback_user_status(profile->tox, twc_user_status_callback, profile); + tox_callback_status_message(profile->tox, twc_status_message_callback, profile); + tox_callback_friend_request(profile->tox, twc_friend_request_callback, profile); +} + +/** + * Unload a Tox profile. Disconnects from the network, saves data to disk. + */ +void +twc_profile_unload(struct t_twc_profile *profile) +{ + // check that we're not already disconnected + if (!(profile->tox)) + return; + + // save and kill tox + int result = twc_save_profile_data_file(profile); + tox_kill(profile->tox); + profile->tox = NULL; + + if (result == -1) + { + char *path = twc_profile_expanded_data_path(profile); + weechat_printf(NULL, + "%s%s: Could not save Tox data for profile %s to file: %s", + weechat_prefix("error"), weechat_plugin->name, + profile->name, + path); + free(path); + } + + // stop Tox timer + weechat_unhook(profile->tox_do_timer); + + // have to refresh and hide bar items even if we were already offline + // TODO + twc_profile_refresh_online_status(profile); + twc_profile_set_online_status(profile, false); +} + +/** + * Load profiles that should autoload. + */ +void +twc_profile_autoload() +{ + size_t index; + struct t_twc_list_item *item; + twc_list_foreach(twc_profiles, index, item) + { + if (weechat_config_boolean(item->profile->options[TWC_PROFILE_OPTION_AUTOLOAD])) + twc_profile_load(item->profile); + } +} + +void +twc_profile_refresh_online_status(struct t_twc_profile *profile) +{ + weechat_bar_item_update("buffer_plugin"); + weechat_bar_item_update("input_prompt"); + weechat_bar_item_update("away"); +} + +void +twc_profile_set_online_status(struct t_twc_profile *profile, + bool status) +{ + if (profile->tox_online ^ status) + { + profile->tox_online = status; + twc_profile_refresh_online_status(profile); + + if (profile->tox_online) + { + weechat_printf(profile->buffer, + "%s%s: profile %s connected", + weechat_prefix("network"), + weechat_plugin->name, + profile->name); + } + else + { + weechat_printf(profile->buffer, + "%s%s: profile %s disconnected", + weechat_prefix("network"), + weechat_plugin->name, + profile->name); + } + } +} + +/** + * Return the profile with a certain name. Case insensitive. + */ +struct t_twc_profile * +twc_profile_search_name(const char *name) +{ + size_t index; + struct t_twc_list_item *item; + twc_list_foreach(twc_profiles, index, item) + { + if (weechat_strcasecmp(item->profile->name, name) == 0) + return item->profile; + } + + return NULL; +} + +/** + * Return the profile associated with a buffer, if any. + */ +struct t_twc_profile * +twc_profile_search_buffer(struct t_gui_buffer *buffer) +{ + size_t profile_index; + struct t_twc_list_item *profile_item; + twc_list_foreach(twc_profiles, profile_index, profile_item) + { + if (profile_item->profile->buffer == buffer) + return profile_item->profile; + + size_t chat_index; + struct t_twc_list_item *chat_item; + twc_list_foreach(profile_item->profile->chats, chat_index, chat_item) + { + if (chat_item->chat->buffer == buffer) + return profile_item->profile; + } + } + + return NULL; +} + +/** + * Delete a profile. Unloads, frees and deletes everything. If delete_data is + * true, Tox data on disk is also deleted. + */ +void +twc_profile_delete(struct t_twc_profile *profile, + bool delete_data) +{ + char *data_path = twc_profile_expanded_data_path(profile); + + twc_profile_free(profile); + + if (delete_data) + unlink(data_path); +} + +/** + * Frees a profile. Unloads and frees all variables. + */ +void +twc_profile_free(struct t_twc_profile *profile) +{ + // unload if needed + twc_profile_unload(profile); + + // close buffer + if (profile->buffer) + { + weechat_buffer_set_pointer(profile->buffer, "close_callback", NULL); + weechat_buffer_close(profile->buffer); + } + + // free things + twc_friend_request_free_profile(profile); + twc_chat_free_profile(profile); + twc_message_queue_free_profile(profile); + free(profile->name); + free(profile); + + // remove from list + twc_list_remove_with_data(twc_profiles, profile); +} + +/** + * Free all profiles. + */ +void +twc_profile_free_all() +{ + struct t_twc_profile *profile; + while ((profile = twc_list_pop(twc_profiles))) + twc_profile_free(profile); + + free(twc_profiles); +} + diff --git a/src/twc-profile.h b/src/twc-profile.h new file mode 100644 index 0000000..97a62a7 --- /dev/null +++ b/src/twc-profile.h @@ -0,0 +1,94 @@ +/* + * 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 TOX_WEECHAT_PROFILE_H +#define TOX_WEECHAT_PROFILE_H + +#include +#include + +#include + +struct t_hashtable; + +enum t_twc_profile_option +{ + TWC_PROFILE_OPTION_SAVEFILE = 0, + TWC_PROFILE_OPTION_AUTOLOAD, + TWC_PROFILE_OPTION_MAX_FRIEND_REQUESTS, + + TWC_PROFILE_NUM_OPTIONS, +}; + +struct t_twc_profile +{ + char *name; + struct t_config_option *options[TWC_PROFILE_NUM_OPTIONS]; + + struct Tox *tox; + int tox_online; + + 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; +}; + +extern struct t_twc_list *twc_profiles; + +void +twc_profile_init(); + +struct t_twc_profile * +twc_profile_new(const char *name); + +void +twc_profile_load(struct t_twc_profile *profile); + +void +twc_profile_unload(struct t_twc_profile *profile); + +void +twc_profile_autoload(); + +void +twc_profile_refresh_online_status(struct t_twc_profile *profile); + +void +twc_profile_set_online_status(struct t_twc_profile *profile, bool online); + +struct t_twc_profile * +twc_profile_search_name(const char *name); + +struct t_twc_profile * +twc_profile_search_buffer(struct t_gui_buffer *buffer); + +void +twc_profile_delete(struct t_twc_profile *profile, bool delete_data); + +void +twc_profile_free(struct t_twc_profile *profile); + +void +twc_profile_free_all(); + +#endif // TOX_WEECHAT_PROFILE_H + diff --git a/src/twc-tox-callbacks.c b/src/twc-tox-callbacks.c new file mode 100644 index 0000000..95424a3 --- /dev/null +++ b/src/twc-tox-callbacks.c @@ -0,0 +1,231 @@ +/* + * 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 "twc.h" +#include "twc-profile.h" +#include "twc-chat.h" +#include "twc-friend-request.h" +#include "twc-message-queue.h" +#include "twc-utils.h" + +#include "twc-tox-callbacks.h" + +int +twc_do_timer_cb(void *data, + int remaining_calls) +{ + struct t_twc_profile *profile = data; + + tox_do(profile->tox); + struct t_hook *hook = weechat_hook_timer(tox_do_interval(profile->tox), 0, 1, + twc_do_timer_cb, profile); + profile->tox_do_timer = hook; + + // check connection status + int connected = tox_isconnected(profile->tox); + twc_profile_set_online_status(profile, connected); + + return WEECHAT_RC_OK; +} + +void +twc_friend_message_callback(Tox *tox, + int32_t friend_number, + const uint8_t *message, + uint16_t length, + void *data) +{ + struct t_twc_profile *profile = data; + struct t_twc_chat *chat = twc_chat_search_friend(profile, + friend_number, + true); + + char *name = twc_get_name_nt(profile->tox, friend_number); + char *message_nt = twc_null_terminate(message, length); + + twc_chat_print_message(chat, "", name, + message_nt, TWC_MESSAGE_TYPE_MESSAGE); + + free(name); + free(message_nt); +} + +void +twc_friend_action_callback(Tox *tox, + int32_t friend_number, + const uint8_t *message, + uint16_t length, + void *data) +{ + struct t_twc_profile *profile = data; + + struct t_twc_chat *chat = twc_chat_search_friend(profile, + friend_number, + true); + + char *name = twc_get_name_nt(profile->tox, friend_number); + char *message_nt = twc_null_terminate(message, length); + + twc_chat_print_message(chat, "", name, + message_nt, TWC_MESSAGE_TYPE_ACTION); + + free(name); + free(message_nt); +} + +void +twc_connection_status_callback(Tox *tox, + int32_t friend_number, + uint8_t status, + void *data) +{ + struct t_twc_profile *profile = data; + char *name = twc_get_name_nt(profile->tox, friend_number); + + // TODO: print in friend's buffer if it exists + if (status == 0) + { + weechat_printf(profile->buffer, + "%s%s just went offline.", + weechat_prefix("network"), + name); + } + else if (status == 1) + { + weechat_printf(profile->buffer, + "%s%s just came online.", + weechat_prefix("network"), + name); + twc_message_queue_flush_friend(profile, friend_number); + } + free(name); +} + +void +twc_name_change_callback(Tox *tox, + int32_t friend_number, + const uint8_t *name, + uint16_t length, + void *data) +{ + struct t_twc_profile *profile = data; + struct t_twc_chat *chat = twc_chat_search_friend(profile, + friend_number, + false); + + char *old_name = twc_get_name_nt(profile->tox, friend_number); + char *new_name = twc_null_terminate(name, length); + + if (strcmp(old_name, new_name) != 0) + { + if (chat) + { + twc_chat_queue_refresh(chat); + + weechat_printf(chat->buffer, + "%s%s is now known as %s", + weechat_prefix("network"), + old_name, new_name); + } + + weechat_printf(profile->buffer, + "%s%s is now known as %s", + weechat_prefix("network"), + old_name, new_name); + } + + free(old_name); + free(new_name); +} + +void +twc_user_status_callback(Tox *tox, + int32_t friend_number, + uint8_t status, + void *data) +{ + struct t_twc_profile *profile = data; + struct t_twc_chat *chat = twc_chat_search_friend(profile, + friend_number, + false); + if (chat) + twc_chat_queue_refresh(chat); +} + +void +twc_status_message_callback(Tox *tox, + int32_t friend_number, + const uint8_t *message, + uint16_t length, + void *data) +{ + struct t_twc_profile *profile = data; + struct t_twc_chat *chat = twc_chat_search_friend(profile, + friend_number, + false); + if (chat) + twc_chat_queue_refresh(chat); +} + +void +twc_friend_request_callback(Tox *tox, + const uint8_t *public_key, + const uint8_t *message, + uint16_t length, + void *data) +{ + struct t_twc_profile *profile = data; + + char *message_nt = twc_null_terminate(message, length); + int rc = twc_friend_request_add(profile, public_key, message_nt); + + if (rc == -1) + { + weechat_printf(profile->buffer, + "%sReceived a friend request, but your friend request list is full!", + weechat_prefix("warning")); + } + else + { + char hex_address[TOX_CLIENT_ID_SIZE * 2 + 1]; + twc_bin2hex(public_key, TOX_CLIENT_ID_SIZE, hex_address); + + weechat_printf(profile->buffer, + "%sReceived a friend request with message \"%s\" from %s", + weechat_prefix("network"), + message_nt, + hex_address); + + if (rc == -2) + { + weechat_printf(profile->buffer, + "%sFailed to save friend request, try manually " + "accepting with /friend add", + weechat_prefix("error")); + } + } + + free(message_nt); +} + diff --git a/src/twc-tox-callbacks.h b/src/twc-tox-callbacks.h new file mode 100644 index 0000000..e5b56db --- /dev/null +++ b/src/twc-tox-callbacks.h @@ -0,0 +1,79 @@ +/* + * 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 TOX_WEECHAT_TOX_CALLBACKS_H +#define TOX_WEECHAT_TOX_CALLBACKS_H + +#include + +#include + +int +twc_do_timer_cb(void *data, + int remaining_calls); + +void +twc_friend_message_callback(Tox *tox, + int32_t friend_number, + const uint8_t *message, + uint16_t length, + void *data); + +void +twc_friend_action_callback(Tox *tox, + int32_t friend_number, + const uint8_t *message, + uint16_t length, + void *data); + +void +twc_connection_status_callback(Tox *tox, + int32_t friend_number, + uint8_t status, + void *data); + +void +twc_name_change_callback(Tox *tox, + int32_t friend_number, + const uint8_t *name, + uint16_t length, + void *data); + +void +twc_user_status_callback(Tox *tox, + int32_t friend_number, + uint8_t status, + void *data); + +void +twc_status_message_callback(Tox *tox, + int32_t friend_number, + const uint8_t *message, + uint16_t length, + void *data); + +void +twc_friend_request_callback(Tox *tox, + const uint8_t *public_key, + const uint8_t *message, + uint16_t length, + void *data); + +#endif // TOX_WEECHAT_TOX_CALLBACKS_H + diff --git a/src/tox-weechat-utils.c b/src/twc-utils.c similarity index 53% rename from src/tox-weechat-utils.c rename to src/twc-utils.c index 76a70be..ca8eef3 100644 --- a/src/tox-weechat-utils.c +++ b/src/twc-utils.c @@ -25,28 +25,37 @@ #include #include -#include "tox-weechat.h" +#include "twc.h" -#include "tox-weechat-utils.h" +#include "twc-utils.h" +/** + * Convert a hex string to it's binary equivalent of max size bytes. + */ void -tox_weechat_hex2bin(const char *hex, size_t length, char *out) +twc_hex2bin(const char *hex, size_t size, char *out) { const char *position = hex; - for (size_t i = 0; i < length / 2; ++i) + size_t i; + for (i = 0; i < size; ++i) { sscanf(position, "%2hhx", &out[i]); position += 2; } } +/** + * Convert size bytes to a hex string. out must be at lesat size * 2 + 1 + * bytes. + */ void -tox_weechat_bin2hex(const uint8_t *bin, size_t size, char *out) +twc_bin2hex(const uint8_t *bin, size_t size, char *out) { char *position = out; - for (size_t i = 0; i < size; ++i) + size_t i; + for (i = 0; i < size; ++i) { sprintf(position, "%02X", bin[i]); position += 2; @@ -54,8 +63,11 @@ tox_weechat_bin2hex(const uint8_t *bin, size_t size, char *out) *position = 0; } +/** + * Return a null-terminated copy of str. Must be freed. + */ char * -tox_weechat_null_terminate(const uint8_t *str, size_t length) +twc_null_terminate(const uint8_t *str, size_t length) { char *str_null = malloc(length + 1); memcpy(str_null, str, length); @@ -64,44 +76,66 @@ tox_weechat_null_terminate(const uint8_t *str, size_t length) return str_null; } +/** + * Get the null-terminated name of a Tox friend. Must be freed. + */ char * -tox_weechat_get_name_nt(Tox *tox, int32_t friend_number) +twc_get_name_nt(Tox *tox, int32_t friend_number) { size_t length = tox_get_name_size(tox, friend_number); uint8_t name[length]; // if no name, return client ID instead if (!length) - { - uint8_t client_id[TOX_CLIENT_ID_SIZE]; - tox_get_client_id(tox, friend_number, client_id); - - char *hex = malloc(TOX_CLIENT_ID_SIZE * 2 + 1); - tox_weechat_bin2hex(client_id, TOX_CLIENT_ID_SIZE, hex); - - return hex; - } + return twc_get_friend_id_short(tox, friend_number); tox_get_name(tox, friend_number, name); - return tox_weechat_null_terminate(name, length); + return twc_null_terminate(name, length); } +/** + * Return the null-terminated status message of a Tox friend. Must be freed. + */ char * -tox_weechat_get_status_message_nt(Tox *tox, int32_t friend_number) +twc_get_status_message_nt(Tox *tox, int32_t friend_number) { size_t length = tox_get_status_message_size(tox, friend_number); uint8_t message[length]; tox_get_status_message(tox, friend_number, message, length); - return tox_weechat_null_terminate(message, length); + return twc_null_terminate(message, length); } +/** + * Return the users own name, null-terminated. Must be freed. + */ char * -tox_weechat_get_self_name_nt(Tox *tox) +twc_get_self_name_nt(Tox *tox) { size_t length = tox_get_self_name_size(tox); uint8_t name[length]; tox_get_self_name(tox, name); - return tox_weechat_null_terminate(name, length); + return twc_null_terminate(name, length); } + +/** + * Return a friend's Tox ID in short form. Return value must be freed. + */ +char * +twc_get_friend_id_short(Tox *tox, int32_t friend_number) +{ + uint8_t client_id[TOX_CLIENT_ID_SIZE]; + tox_get_client_id(tox, friend_number, client_id); + + // TODO: config + size_t short_id_length = 8; + + char *hex_address = malloc(short_id_length + 1); + twc_bin2hex(client_id, + short_id_length / 2, + hex_address); + + return hex_address; +} + diff --git a/src/tox-weechat-utils.h b/src/twc-utils.h similarity index 71% rename from src/tox-weechat-utils.h rename to src/twc-utils.h index 3f8a1fd..a8dbab0 100644 --- a/src/tox-weechat-utils.h +++ b/src/twc-utils.h @@ -26,21 +26,25 @@ #include void -tox_weechat_hex2bin(const char *hex, size_t length, char *out); +twc_hex2bin(const char *hex, size_t size, char *out); void -tox_weechat_bin2hex(const uint8_t *bin, size_t size, char *out); +twc_bin2hex(const uint8_t *bin, size_t size, char *out); char * -tox_weechat_null_terminate(const uint8_t *str, size_t length); +twc_null_terminate(const uint8_t *str, size_t length); char * -tox_weechat_get_name_nt(Tox *tox, int32_t friend_number); +twc_get_name_nt(Tox *tox, int32_t friend_number); char * -tox_weechat_get_status_message_nt(Tox *tox, int32_t friend_number); +twc_get_status_message_nt(Tox *tox, int32_t friend_number); char * -tox_weechat_get_self_name_nt(Tox *tox); +twc_get_self_name_nt(Tox *tox); + +char * +twc_get_friend_id_short(Tox *tox, int32_t friend_number); #endif // TOX_WEECHAT_UTILS_H + diff --git a/src/tox-weechat.c b/src/twc.c similarity index 65% rename from src/tox-weechat.c rename to src/twc.c index 42ebed1..90035b1 100644 --- a/src/tox-weechat.c +++ b/src/twc.c @@ -21,15 +21,15 @@ #include -#include "tox-weechat-identities.h" -#include "tox-weechat-commands.h" -#include "tox-weechat-gui.h" -#include "tox-weechat-friend-requests.h" -#include "tox-weechat-config.h" -#include "tox-weechat-data.h" -#include "tox-weechat-completion.h" +#include "twc-profile.h" +#include "twc-commands.h" +#include "twc-gui.h" +#include "twc-friend-request.h" +#include "twc-config.h" +#include "twc-data.h" +#include "twc-completion.h" -#include "tox-weechat.h" +#include "twc.h" WEECHAT_PLUGIN_NAME("tox"); WEECHAT_PLUGIN_DESCRIPTION("Tox protocol"); @@ -38,22 +38,22 @@ WEECHAT_PLUGIN_VERSION("0.1"); WEECHAT_PLUGIN_LICENSE("GPL3"); struct t_weechat_plugin *weechat_plugin = NULL; -struct t_gui_buffer *tox_main_buffer = NULL; -int tox_weechat_online_status = 0; int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[]) { weechat_plugin = plugin; - tox_weechat_config_init(); - tox_weechat_config_read(); - tox_weechat_data_load(); - tox_weechat_commands_init(); - tox_weechat_gui_init(); - tox_weechat_completion_init(); + twc_profile_init(); + twc_commands_init(); + twc_gui_init(); + twc_completion_init(); - tox_weechat_identity_autoconnect(); + twc_config_init(); + twc_config_read(); + + // TODO: respect weechat flag for no autoconnect + twc_profile_autoload(); return WEECHAT_RC_OK; } @@ -61,10 +61,10 @@ weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[]) int weechat_plugin_end(struct t_weechat_plugin *plugin) { - tox_weechat_config_write(); - tox_weechat_identity_free_all(); - tox_weechat_data_save(); - tox_weechat_data_free(); + twc_config_write(); + + twc_profile_free_all(); return WEECHAT_RC_OK; } + diff --git a/src/tox-weechat.h b/src/twc.h similarity index 97% rename from src/tox-weechat.h rename to src/twc.h index afd62a1..630b278 100644 --- a/src/tox-weechat.h +++ b/src/twc.h @@ -20,8 +20,7 @@ #ifndef TOX_WEECHAT_H #define TOX_WEECHAT_H -#include - extern struct t_weechat_plugin *weechat_plugin; #endif // TOX_WEECHAT_H +