Mass refactor 💥

master
Håvard Pettersson 10 years ago
parent 6dfacdf04c
commit 8f1d0070c3

@ -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}

@ -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 "")

@ -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 <name>`. The data file is stored in `~/.weechat/tox/` by default.
- Connect your identity to the Tox network with `/tox connect <name>`.
- Create a new profile with `/tox create <name>`. The data file is stored in `~/.weechat/tox/` by default.
- Load your profile and connect to the Tox network with `/tox load <name>`.
- Change your name with `/name <new 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 <friend number>`. 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 <http://www.gnu.org/licenses/>.
[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

@ -1,225 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#include "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;
}

@ -1,70 +0,0 @@
/*
* Copyright (c) 2015 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_CHATS_H
#define TOX_WEECHAT_CHATS_H
#include <stdint.h>
#include <tox/tox.h>
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

@ -1,762 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#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> <port> <client id>",
" 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 <address> [<message>]"
" || remove <number>"
" || requests"
" || accept <number>|all"
" || decline <number>|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: message to send",
NULL, tox_weechat_cmd_me, NULL);
weechat_hook_command("msg",
"send a message to a Tox friend",
"<id> [<message>]",
" 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>",
"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>]",
"message: your new status message",
NULL, tox_weechat_cmd_statusmsg, NULL);
weechat_hook_command("tox",
"manage Tox identities",
"list"
" || create <name>"
" || delete <name> -yes|-keepdata"
" || connect [<name>...]"
" || disconnect [<name>...]",
" 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);
}

@ -1,59 +0,0 @@
#include <stdlib.h>
#include <inttypes.h>
#include <weechat/weechat-plugin.h>
#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);
}

@ -1,7 +0,0 @@
#ifndef TOX_WEECHAT_COMPLETION_H
#define TOX_WEECHAT_COMPLETION_H
void
tox_weechat_completion_init();
#endif // TOX_WEECHAT_COMPLETION_H

@ -1,257 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <weechat/weechat-plugin.h>
#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);
}

@ -1,301 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
/////// TODO //////////
// get rid of data from deleted/nonexisting identities so it doesn't accumulate
///////////////////////
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#include <jansson.h>
#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);
}

@ -1,152 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#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);
}

@ -1,62 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_FRIEND_REQUESTS_H
#define TOX_WEECHAT_FRIEND_REQUESTS_H
#include <stdint.h>
#include <tox/tox.h>
/**
* 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

@ -1,106 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#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);
}

@ -1,459 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>
#include <stdbool.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#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);
}

@ -1,100 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_IDENTITIES_H
#define TOX_WEECHAT_IDENTITIES_H
#include <stdint.h>
#include <stdbool.h>
#include <tox/tox.h>
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

@ -1,169 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <tox/tox.h>
#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)
{
}

@ -1,61 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_MESSAGES_H
#define TOX_WEECHAT_MESSAGES_H
#include <tox/tox.h>
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

@ -1,214 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#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);
}

@ -1,78 +0,0 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_TOX_CALLBACKS_H
#define TOX_WEECHAT_TOX_CALLBACKS_H
#include <stdint.h>
#include <tox/tox.h>
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

@ -0,0 +1,97 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <tox/tox.h>
#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]);
}

@ -0,0 +1,35 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_BOOTSTRAP_H
#define TOX_WEECHAT_BOOTSTRAP_H
#include <tox/tox.h>
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

@ -0,0 +1,261 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#include "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);
}

@ -0,0 +1,72 @@
/*
* Copyright (c) 2015 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_CHAT_H
#define TOX_WEECHAT_CHAT_H
#include <stdint.h>
#include <stdbool.h>
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

@ -0,0 +1,781 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#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 <address> <port> <key>
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 <Tox ID> [<message>]
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 <number>
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 <number>|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 <profile>
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 <profile>
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> <port> <Tox ID>",
"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 <address> [<message>]"
" || remove <number>"
" || requests"
" || accept <number>|all"
" || decline <number>|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: message to send",
NULL, twc_cmd_me, NULL);
weechat_hook_command("msg",
"send a message to a Tox friend",
"<id> [<message>]",
" 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>",
"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>]",
"message: your new status message",
NULL, twc_cmd_statusmsg, NULL);
weechat_hook_command("tox",
"manage Tox profiles",
"list"
" || create <name>"
" || delete <name> -yes|-keepdata"
" || load [<name>...]"
" || unload [<name>...]",
" 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);
}

@ -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

@ -0,0 +1,83 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <inttypes.h>
#include <weechat/weechat-plugin.h>
#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);
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_COMPLETION_H
#define TOX_WEECHAT_COMPLETION_H
void
twc_completion_init();
#endif // TOX_WEECHAT_COMPLETION_H

@ -0,0 +1,288 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <weechat/weechat-plugin.h>
#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);
}

@ -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

@ -0,0 +1,19 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/

@ -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

@ -0,0 +1,125 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#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);
}

@ -0,0 +1,60 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_FRIEND_REQUEST_H
#define TOX_WEECHAT_FRIEND_REQUEST_H
#include <stdint.h>
#include <tox/tox.h>
/**
* 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

@ -0,0 +1,109 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#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);
}

@ -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

@ -0,0 +1,187 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include "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;
}

@ -0,0 +1,87 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_LIST_H
#define TOX_WEECHAT_LIST_H
#include <stdlib.h>
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

@ -0,0 +1,166 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <time.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#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);
}

@ -0,0 +1,56 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_MESSAGE_QUEUE_H
#define TOX_WEECHAT_MESSAGE_QUEUE_H
#include <time.h>
#include <tox/tox.h>
#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

@ -0,0 +1,456 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>
#include <stdbool.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#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);
}

@ -0,0 +1,94 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_PROFILE_H
#define TOX_WEECHAT_PROFILE_H
#include <stdint.h>
#include <stdbool.h>
#include <tox/tox.h>
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

@ -0,0 +1,231 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#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);
}

@ -0,0 +1,79 @@
/*
* Copyright (c) 2014 Håvard Pettersson <haavard.pettersson@gmail.com>
*
* This file is part of Tox-WeeChat.
*
* Tox-WeeChat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox-WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox-WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOX_WEECHAT_TOX_CALLBACKS_H
#define TOX_WEECHAT_TOX_CALLBACKS_H
#include <stdint.h>
#include <tox/tox.h>
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

@ -25,28 +25,37 @@
#include <weechat/weechat-plugin.h>
#include <tox/tox.h>
#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;
}

@ -26,21 +26,25 @@
#include <tox/tox.h>
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

@ -21,15 +21,15 @@
#include <weechat/weechat-plugin.h>
#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;
}

@ -20,8 +20,7 @@
#ifndef TOX_WEECHAT_H
#define TOX_WEECHAT_H
#include <tox/tox.h>
extern struct t_weechat_plugin *weechat_plugin;
#endif // TOX_WEECHAT_H
Loading…
Cancel
Save