diff --git a/CMakeLists.txt b/CMakeLists.txt index 3bc79d4..b97397d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ add_library(tox MODULE src/tox-weechat-commands.c src/tox-weechat-gui.c src/tox-weechat-utils.c + src/tox-weechat-config.c ) add_definitions(-D_GNU_SOURCE) diff --git a/README.md b/README.md index 853415c..85b89b7 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,12 @@ Usage ----- In WeeChat, load the plugin: `/plugin load tox`. In cases where WeeChat can't find the plugin, try specifying the full path to the binary. You should get a new buffer called tox. This is the core Tox buffer, where output from commands will appear. + - In WeeChat, load the plugin with `/plugin load tox`. If it fails, try specifying the full path to the binary. + - Create a new identity with `/tox add `. The data file is created in `/tox/` by default. Can be changed with `/set tox.identity..save_file`. + - Connect your new identity to the Tox network with `/tox connect `. + +The following commands must be executed on a Tox buffer: + - To change your name, `/name `. - Get your Tox address with `/myaddress`. - To add friends or respond to friend requests, `/help friend` will get you started. @@ -36,10 +42,11 @@ A list of commands is available with `/help -list tox`. TODO ---- - - [ ] Support multiple identities (in progress) + - [x] Support multiple identities - [ ] Preserve friend requests when closing - [ ] Group chats - [ ] Polish and reach a "stable" release + - [ ] Add autocomplete to all commands License --------- diff --git a/src/tox-weechat-chats.c b/src/tox-weechat-chats.c index c3f4653..6ad2e83 100644 --- a/src/tox-weechat-chats.c +++ b/src/tox-weechat-chats.c @@ -77,7 +77,7 @@ tox_weechat_chat_refresh_timer_callback(void *data, int remaining) void tox_weechat_chat_queue_refresh(struct t_tox_weechat_chat *chat) { - weechat_hook_timer(0, 0, 1, + weechat_hook_timer(1, 0, 1, tox_weechat_chat_refresh_timer_callback, chat); } @@ -87,6 +87,7 @@ tox_weechat_friend_chat_new(struct t_tox_weechat_identity *identity, { 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); diff --git a/src/tox-weechat-commands.c b/src/tox-weechat-commands.c index a4db067..6b8cae3 100644 --- a/src/tox-weechat-commands.c +++ b/src/tox-weechat-commands.c @@ -20,6 +20,15 @@ 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; @@ -43,8 +52,16 @@ 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; + } - // /friend [list] if (argc == 1 || (argc == 2 && weechat_strcasecmp(argv[1], "list") == 0)) { size_t friend_count = tox_count_friendlist(identity->tox); @@ -87,7 +104,7 @@ tox_weechat_cmd_friend(void *data, struct t_gui_buffer *buffer, return WEECHAT_RC_OK; } - if (argc >= 3 && (weechat_strcasecmp(argv[1], "add") == 0)) + else if (argc >= 3 && (weechat_strcasecmp(argv[1], "add") == 0)) { char *address = malloc(TOX_FRIEND_ADDRESS_SIZE); tox_weechat_hex2bin(argv[2], address); @@ -147,7 +164,7 @@ tox_weechat_cmd_friend(void *data, struct t_gui_buffer *buffer, return WEECHAT_RC_OK; } - if (argc == 3 && (weechat_strcasecmp(argv[1], "remove") == 0)) + else if (argc == 3 && (weechat_strcasecmp(argv[1], "remove") == 0)) { char *endptr; unsigned long friend_number = strtoul(argv[2], &endptr, 10); @@ -179,8 +196,7 @@ tox_weechat_cmd_friend(void *data, struct t_gui_buffer *buffer, return WEECHAT_RC_OK; } - // /friend accept - if (argc == 3 && + else if (argc == 3 && (weechat_strcasecmp(argv[1], "accept") == 0 || weechat_strcasecmp(argv[1], "decline") == 0)) { @@ -240,7 +256,7 @@ tox_weechat_cmd_friend(void *data, struct t_gui_buffer *buffer, } } - if (argc == 2 && weechat_strcasecmp(argv[1], "requests") == 0) + else if (argc == 2 && weechat_strcasecmp(argv[1], "requests") == 0) { if (identity->friend_requests == NULL) { @@ -291,9 +307,18 @@ tox_weechat_cmd_me(void *data, struct t_gui_buffer *buffer, 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], @@ -315,6 +340,15 @@ tox_weechat_cmd_msg(void *data, struct t_gui_buffer *buffer, 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); @@ -332,10 +366,10 @@ tox_weechat_cmd_msg(void *data, struct t_gui_buffer *buffer, { tox_send_message(identity->tox, friend_number, - (uint8_t *)argv_eol[1], + (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[1]); + tox_weechat_chat_print_message(chat, name, argv_eol[2]); free(name); } @@ -347,6 +381,15 @@ tox_weechat_cmd_myaddress(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); @@ -372,6 +415,15 @@ tox_weechat_cmd_name(void *data, struct t_gui_buffer *buffer, 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]; @@ -413,6 +465,15 @@ tox_weechat_cmd_status(void *data, struct t_gui_buffer *buffer, 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) @@ -436,6 +497,15 @@ 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] : " "; @@ -453,6 +523,75 @@ tox_weechat_cmd_statusmsg(void *data, struct t_gui_buffer *buffer, 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], "add") == 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); + } + + 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 && (weechat_strcasecmp(argv[1], "connect") == 0)) + { + char *name = argv[2]; + + 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; + } + + return WEECHAT_RC_ERROR; +} + void tox_weechat_commands_init() { @@ -514,4 +653,16 @@ tox_weechat_commands_init() "[]", "message: your new status message", NULL, tox_weechat_cmd_statusmsg, NULL); + + weechat_hook_command("tox", + "manage Tox identities", + "list" + " || add " + " || del " + " || connect ", + " list: list all Tox identity\n" + " add: create a new Tox identity\n" + " del: delete a Tox identity\n" + "connect: connect a Tox identity to the network\n", + NULL, tox_weechat_cmd_tox, NULL); } diff --git a/src/tox-weechat-config.c b/src/tox-weechat-config.c index df562c4..9462e39 100644 --- a/src/tox-weechat-config.c +++ b/src/tox-weechat-config.c @@ -1,15 +1,42 @@ +#include +#include +#include +#include + #include #include "tox-weechat.h" +#include "tox-weechat-identities.h" + +#include "tox-weechat-config.h" struct t_config_file *tox_weechat_config_file = NULL; struct t_config_section *tox_weechat_config_section_identity = NULL; -int -tox_weechat_config_reload_callback(void *data, - struct t_config_file *config_file) +char *tox_weechat_identity_option_names[TOX_WEECHAT_IDENTITY_NUM_OPTIONS] = { - return WEECHAT_RC_OK; + "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 @@ -19,10 +46,57 @@ tox_weechat_config_identity_read_callback(void *data, const char *option_name, const char *value) { - return WEECHAT_CONFIG_OPTION_SET_OK_CHANGED; - /* return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; */ - /* return WEECHAT_CONFIG_OPTION_SET_OPTION_NOT_FOUND; */ - /* return WEECHAT_CONFIG_OPTION_SET_ERROR; */ + 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 @@ -30,65 +104,135 @@ 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; - /* return WEECHAT_CONFIG_WRITE_ERROR; */ } int -tox_weechat_config_identity_write_default_callback(void *data, - struct t_config_file *config_file, - const char *section_name) +tox_weechat_config_identity_check_value_callback(void *data, + struct t_config_option *option, + const char *value) { - return WEECHAT_CONFIG_WRITE_OK; - /* return WEECHAT_CONFIG_WRITE_ERROR; */ -} - -int -tox_weechat_config_server_name_check_callback(void *data, - struct t_config_option *option, - const char *value) -{ - return 1; + return 1; // ok, 0 not ok } void -tox_weechat_config_server_name_change_callback(void *data, - struct t_config_option *option) +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", - tox_weechat_config_reload_callback, NULL); + 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, - tox_weechat_config_identity_write_default_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(const char *name) +tox_weechat_config_init_identity(struct t_tox_weechat_identity *identity) { - struct t_config_option *option = - weechat_config_new_option(tox_weechat_config_file, - tox_weechat_config_section_identity, - "name", "string", - "identity name", - NULL, 0, 0, - name, name, - 0, - tox_weechat_config_identity_name_check_callback, NULL, - tox_weechat_config_identity_name_change_callback, NULL, - NULL, NULL); + for (int i = 0; i < TOX_WEECHAT_IDENTITY_NUM_OPTIONS; ++i) + { + // length: name + . + option + \0 + size_t length = strlen(identity->name) + 1 + + strlen(tox_weechat_identity_option_names[i]) + 1; + + char *option_name = malloc(sizeof(*option_name) * length); + if (option_name) + { + snprintf(option_name, length, "%s.%s", + identity->name, + tox_weechat_identity_option_names[i]); + + identity->options[i] = tox_weechat_config_init_option(i, option_name); + free (option_name); + } + } +} + +int +tox_weechat_config_read() +{ + return weechat_config_read(tox_weechat_config_file); +} + +int +tox_weechat_config_write() +{ + return weechat_config_write(tox_weechat_config_file); } diff --git a/src/tox-weechat-config.h b/src/tox-weechat-config.h index a67ccfe..40af529 100644 --- a/src/tox-weechat-config.h +++ b/src/tox-weechat-config.h @@ -1,7 +1,21 @@ #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; + void tox_weechat_config_init(); +int +tox_weechat_config_read(); + +int +tox_weechat_config_write(); + +void +tox_weechat_config_init_identity(struct t_tox_weechat_identity *identity); + #endif // TOX_WEECHAT_CONFIG_H diff --git a/src/tox-weechat-gui.c b/src/tox-weechat-gui.c index d595bcd..82d273f 100644 --- a/src/tox-weechat-gui.c +++ b/src/tox-weechat-gui.c @@ -62,11 +62,14 @@ bar_item_buffer_plugin(void *data, struct t_gui_bar_item *item, const char *identity_name = identity->name; snprintf(string, sizeof(string), - "%s%s/%s%s", + "%s%s/%s%s%s/%s%s", plugin_name, weechat_color("bar_delim"), weechat_color("bar_fg"), - identity_name); + identity_name, + weechat_color("bar_delim"), + weechat_color("bar_fg"), + identity->tox_online ? "online" : "offline"); return strdup(string); } diff --git a/src/tox-weechat-identities.c b/src/tox-weechat-identities.c index df11646..106d27e 100644 --- a/src/tox-weechat-identities.c +++ b/src/tox-weechat-identities.c @@ -3,11 +3,14 @@ #include #include #include +#include +#include #include #include #include "tox-weechat.h" +#include "tox-weechat-config.h" #include "tox-weechat-chats.h" #include "tox-weechat-tox-callbacks.h" #include "tox-weechat-utils.h" @@ -17,32 +20,27 @@ struct t_tox_weechat_identity *tox_weechat_identities = NULL; struct t_tox_weechat_identity *tox_weechat_last_identity = NULL; -/** - * Return the default data file path for an identity name. Must be freed. - */ char * -tox_weechat_default_data_path(const char *name) +tox_weechat_identity_data_file_path(struct t_tox_weechat_identity *identity) { - const char *weechat_dir = weechat_info_get("weechat_dir", NULL); - const char *tox_dir = "/tox/"; + // 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); - weechat_mkdir_home("tox", 0755); - - int path_length = strlen(weechat_dir) + strlen(tox_dir) + strlen(name) + 1; - char *tox_data_path = malloc(sizeof(*tox_data_path) + path_length); - - strcpy(tox_data_path, weechat_dir); - strcat(tox_data_path, tox_dir); - strcat(tox_data_path, name); - tox_data_path[path_length-1] = 0; - - return tox_data_path; + return full_path; } int -tox_weechat_load_data_file(Tox *tox, char *path) +tox_weechat_load_identity_data_file(struct t_tox_weechat_identity *identity) { - FILE *file = fopen(path, "r"); + char *full_path = tox_weechat_identity_data_file_path(identity); + + FILE *file = fopen(full_path, "r"); + free(full_path); + if (file) { // get file size @@ -56,8 +54,7 @@ tox_weechat_load_data_file(Tox *tox, char *path) fclose(file); // try loading the data - int status = tox_load(tox, data, size); - + int status = tox_load(identity->tox, data, size); free(data); return status; @@ -67,15 +64,17 @@ tox_weechat_load_data_file(Tox *tox, char *path) } int -tox_weechat_save_data_file(Tox *tox, char *path) +tox_weechat_save_identity_data_file(struct t_tox_weechat_identity *identity) { + char *full_path = tox_weechat_identity_data_file_path(identity); + // save Tox data to a buffer - uint32_t size = tox_size(tox); + uint32_t size = tox_size(identity->tox); uint8_t *data = malloc(sizeof(*data) * size); - tox_save(tox, data); + tox_save(identity->tox, data); // save buffer to a file - FILE *file = fopen(path, "w"); + FILE *file = fopen(full_path, "w"); if (file) { fwrite(data, sizeof(data[0]), size, file); @@ -94,7 +93,7 @@ tox_weechat_identity_buffer_close_callback(void *data, struct t_tox_weechat_identity *identity = data; identity->buffer = NULL; - tox_weechat_identity_free(data); + tox_weechat_identity_disconnect(identity); return WEECHAT_RC_OK; } @@ -124,7 +123,6 @@ tox_weechat_identity_new(const char *name) { struct t_tox_weechat_identity *identity = malloc(sizeof(*identity)); identity->name = strdup(name); - identity->data_file_path = tox_weechat_default_data_path(name); // add to identity list identity->prev_identity= tox_weechat_last_identity; @@ -138,31 +136,49 @@ tox_weechat_identity_new(const char *name) 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; + // TODO: load from disk identity->friend_requests = identity->last_friend_request = NULL; identity->friend_request_count = 0; + // 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 identity->buffer = weechat_buffer_new(identity->name, NULL, NULL, - tox_weechat_identity_buffer_close_callback, NULL); + tox_weechat_identity_buffer_close_callback, identity); // create Tox identity->tox = tox_new(NULL); // try loading Tox saved data - if (tox_weechat_load_data_file(identity->tox, identity->data_file_path) == -1) + if (tox_weechat_load_identity_data_file(identity) == -1) { - // couldn't load Tox, set a default name + // 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 User"; + tox_set_name(identity->tox, - (uint8_t *)"WeeChatter", strlen("WeeChatter")); + (uint8_t *)name, strlen(name)); } // bootstrap DHT @@ -183,6 +199,60 @@ tox_weechat_identity_connect(struct t_tox_weechat_identity *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 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); +} + +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); + } +} + +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) { @@ -208,6 +278,9 @@ tox_weechat_identity_for_buffer(struct t_gui_buffer *buffer) void tox_weechat_identity_free(struct t_tox_weechat_identity *identity) { + // disconnect + tox_weechat_identity_disconnect(identity); + // remove from list if (identity == tox_weechat_last_identity) tox_weechat_last_identity = identity->prev_identity; @@ -220,24 +293,7 @@ tox_weechat_identity_free(struct t_tox_weechat_identity *identity) if (identity->next_identity) identity->next_identity->prev_identity = identity->prev_identity; - // save and kill tox - int result = tox_weechat_save_data_file(identity->tox, - identity->data_file_path); - tox_kill(identity->tox); - - if (result == -1) - { - weechat_printf(NULL, - "%sCould not save Tox identity %s to file: %s", - weechat_prefix("error"), - identity->name, - identity->data_file_path); - } - - if (identity->buffer) - weechat_buffer_close(identity->buffer); - - // TODO: free config, free friend reqs/chats + // TODO: free more things free(identity->name); free(identity); diff --git a/src/tox-weechat-identities.h b/src/tox-weechat-identities.h index 50cc772..07d50ff 100644 --- a/src/tox-weechat-identities.h +++ b/src/tox-weechat-identities.h @@ -14,19 +14,15 @@ enum t_tox_weechat_identity_option struct t_tox_weechat_identity { - struct Tox *tox; - char *name; - struct t_config_option *options[TOX_WEECHAT_IDENTITY_NUM_OPTIONS]; - // TODO: move to option - char *data_file_path; - unsigned int max_friend_requests; + struct Tox *tox; struct t_gui_buffer *buffer; + struct t_hook *tox_do_timer; - int is_connected; + int tox_online; struct t_tox_weechat_chat *chats; struct t_tox_weechat_chat *last_chat; @@ -48,6 +44,15 @@ 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(); + +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); diff --git a/src/tox-weechat-tox-callbacks.c b/src/tox-weechat-tox-callbacks.c index af1ef42..1fcbf7c 100644 --- a/src/tox-weechat-tox-callbacks.c +++ b/src/tox-weechat-tox-callbacks.c @@ -17,15 +17,21 @@ tox_weechat_do_timer_cb(void *data, { struct t_tox_weechat_identity *identity = data; - tox_do(identity->tox); - weechat_hook_timer(tox_do_interval(identity->tox), 0, 1, - tox_weechat_do_timer_cb, identity); - - // check connection status - int connected = tox_isconnected(identity->tox); - if (connected ^ identity->is_connected) + if (identity->tox) { - identity->is_connected = connected; + 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); + weechat_printf(NULL, "%p connected: %d", identity->tox, connected); + if (connected ^ identity->tox_online) + { + identity->tox_online = connected; + weechat_bar_item_update("buffer_plugin"); + } } return WEECHAT_RC_OK; @@ -159,7 +165,10 @@ tox_weechat_callback_friend_request(Tox *tox, { struct t_tox_weechat_identity *identity = data; - if (identity->friend_request_count >= identity->max_friend_requests) + 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) { weechat_printf(identity->buffer, "%sReceived a friend request, but your friend request list is full!", diff --git a/src/tox-weechat.c b/src/tox-weechat.c index 418eeb4..631f2ce 100644 --- a/src/tox-weechat.c +++ b/src/tox-weechat.c @@ -6,6 +6,7 @@ #include "tox-weechat-commands.h" #include "tox-weechat-gui.h" #include "tox-weechat-friend-requests.h" +#include "tox-weechat-config.h" #include "tox-weechat.h" @@ -24,17 +25,20 @@ weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[]) { weechat_plugin = plugin; - struct t_tox_weechat_identity *identity = tox_weechat_identity_new("tox"); - tox_weechat_identity_connect(identity); + tox_weechat_config_init(); + tox_weechat_config_read(); tox_weechat_commands_init(); tox_weechat_gui_init(); + tox_weechat_identity_autoconnect(); + return WEECHAT_RC_OK; } int weechat_plugin_end(struct t_weechat_plugin *plugin) { + tox_weechat_config_write(); tox_weechat_identity_free_all(); return WEECHAT_RC_OK;