diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2012-12-24 17:31:33 +0100 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2012-12-24 17:31:33 +0100 |
commit | cf76379aa96a4df0677f1d1485d38225a3d79c95 (patch) | |
tree | bccfa7978a2786bd337fdc0b9aaf654177837956 /src/plugins/relay | |
parent | 2e48874ce04d2adb537dec3c4725638c089404c5 (diff) | |
download | weechat-cf76379aa96a4df0677f1d1485d38225a3d79c95.zip |
relay: add backlog, options and server capability "server-time" for irc protocol (task #12076)
New options:
- relay.irc.backlog_max_minutes
- relay.irc.backlog_max_number
- relay.irc.backlog_since_last_disconnect
- relay.irc.backlog_tags
- relay.irc.backlog_time_format
Diffstat (limited to 'src/plugins/relay')
-rw-r--r-- | src/plugins/relay/irc/relay-irc.c | 597 | ||||
-rw-r--r-- | src/plugins/relay/irc/relay-irc.h | 22 | ||||
-rw-r--r-- | src/plugins/relay/relay-client.c | 16 | ||||
-rw-r--r-- | src/plugins/relay/relay-client.h | 1 | ||||
-rw-r--r-- | src/plugins/relay/relay-config.c | 135 | ||||
-rw-r--r-- | src/plugins/relay/relay-config.h | 8 | ||||
-rw-r--r-- | src/plugins/relay/relay-server.c | 73 | ||||
-rw-r--r-- | src/plugins/relay/relay-server.h | 3 | ||||
-rw-r--r-- | src/plugins/relay/relay-upgrade.c | 38 | ||||
-rw-r--r-- | src/plugins/relay/relay-upgrade.h | 1 | ||||
-rw-r--r-- | src/plugins/relay/relay.c | 2 |
11 files changed, 865 insertions, 31 deletions
diff --git a/src/plugins/relay/irc/relay-irc.c b/src/plugins/relay/irc/relay-irc.c index e94724ebd..ebe512801 100644 --- a/src/plugins/relay/irc/relay-irc.c +++ b/src/plugins/relay/irc/relay-irc.c @@ -35,10 +35,15 @@ #include "../relay-client.h" #include "../relay-config.h" #include "../relay-raw.h" +#include "../relay-server.h" char *relay_irc_relay_commands[] = { "privmsg", "notice", NULL }; -char *relay_irc_ignore_commands[] = { "pong", "quit", NULL }; +char *relay_irc_ignore_commands[] = { "cap", "pong", "quit", NULL }; +char *relay_irc_backlog_commands_tags[RELAY_IRC_NUM_CMD] = +{ "irc_join", "irc_part", "irc_quit", "irc_nick", "irc_privmsg" }; +char *relay_irc_server_capabilities[RELAY_IRC_NUM_CAPAB] = +{ "server-time" }; /* @@ -94,6 +99,49 @@ relay_irc_command_ignored (const char *irc_command) } /* + * Searches for a tag of a command (in backlog). + * + * Returns index of tag in enum t_relay_irc_command, -1 if tag is not found. + */ + +int +relay_irc_search_backlog_commands_tags (const char *tag) +{ + int i; + + for (i = 0; i < RELAY_IRC_NUM_CMD; i++) + { + if (strcmp (relay_irc_backlog_commands_tags[i], tag) == 0) + return i; + } + + /* tag not found */ + return -1; +} + +/* + * Searches for a server capability. + * + * Returns index of server capability in enum t_relay_irc_server_capab, -1 if + * server capability is not found. + */ + +int +relay_irc_search_server_capability (const char *capability) +{ + int i; + + for (i = 0; i < RELAY_IRC_NUM_CAPAB; i++) + { + if (strcmp (relay_irc_server_capabilities[i], capability) == 0) + return i; + } + + /* server capability not found */ + return -1; +} + +/* * Parses an IRC message. * * Returns hashtable with parsed message, NULL if error. @@ -272,7 +320,8 @@ relay_irc_signal_irc_in2_cb (void *data, const char *signal, } /* - * Gets id of client by looking for tag "relay_client_NNN" in list of tags (comma separated list). + * Gets id of client by looking for tag "relay_client_NNN" in list of tags + * (comma separated list). * * Returns number found (NNN), -1 if not found. */ @@ -397,7 +446,8 @@ relay_irc_signal_irc_outtags_cb (void *data, const char *signal, RELAY_IRC_DATA(client, nick)); host = NULL; - infolist_nick = weechat_infolist_get ("irc_nick", NULL, str_infolist_args); + infolist_nick = weechat_infolist_get ("irc_nick", NULL, + str_infolist_args); if (infolist_nick && weechat_infolist_next (infolist_nick)) host = weechat_infolist_string (infolist_nick, "host"); @@ -498,6 +548,381 @@ relay_irc_hsignal_irc_redir_cb (void *data, const char *signal, } /* + * Gets info about a line in a buffer: + * - irc command + * - date + * - nick + * - nick1 and nick2 (old and new nick for irc "nick" command) + * - host (without colors) + * - message (without colors). + * + * Arguments hdata_line_data and line_data must be non NULL, the other arguments + * can be NULL. + * + * Note: tags, host and message (if given and filled) must be freed after use. + */ + +void +relay_irc_get_line_info (struct t_relay_client *client, + struct t_gui_buffer *buffer, + struct t_hdata *hdata_line_data, void *line_data, + int *irc_command, int *irc_action, time_t *date, + const char **nick, const char **nick1, + const char **nick2, char **tags, char **host, + char **message) +{ + int i, num_tags, command, action, all_tags, length; + char str_tag[256], *pos, *pos2, *message_no_color, str_time[256]; + const char *ptr_tag, *ptr_message, *ptr_nick, *ptr_nick1, *ptr_nick2; + const char *localvar_nick, *time_format; + time_t msg_date; + struct tm *tm; + + if (irc_command) + *irc_command = -1; + if (irc_action) + *irc_action = 0; + if (date) + *date = 0; + if (nick) + *nick = NULL; + if (nick1) + *nick1 = NULL; + if (nick2) + *nick2 = NULL; + if (tags) + *tags = NULL; + if (host) + *host = NULL; + if (message) + *message = NULL; + + msg_date = weechat_hdata_time (hdata_line_data, line_data, "date"); + tm = localtime (&msg_date); + num_tags = weechat_hdata_get_var_array_size (hdata_line_data, line_data, + "tags_array"); + ptr_message = weechat_hdata_pointer (hdata_line_data, line_data, "message"); + + /* no tag found, or no message? just exit */ + if ((num_tags <= 0) || !ptr_message) + return; + + command = -1; + action = 0; + ptr_nick = NULL; + ptr_nick1 = NULL; + ptr_nick2 = NULL; + all_tags = weechat_hashtable_has_key (relay_config_hashtable_irc_backlog_tags, + "*"); + for (i = 0; i < num_tags; i++) + { + snprintf (str_tag, sizeof (str_tag), "%d|tags_array", i); + ptr_tag = weechat_hdata_string (hdata_line_data, line_data, str_tag); + if (ptr_tag) + { + if (strcmp (ptr_tag, "irc_action") == 0) + action = 1; + else if (strncmp (ptr_tag, "nick_", 5) == 0) + ptr_nick = ptr_tag + 5; + else if (strncmp (ptr_tag, "irc_nick1_", 10) == 0) + ptr_nick1 = ptr_tag + 10; + else if (strncmp (ptr_tag, "irc_nick2_", 10) == 0) + ptr_nick2 = ptr_tag + 10; + else if ((command < 0) + && (all_tags + || (weechat_hashtable_has_key (relay_config_hashtable_irc_backlog_tags, + ptr_tag)))) + { + command = relay_irc_search_backlog_commands_tags (ptr_tag); + } + } + } + + /* not a supported IRC command? */ + if (command < 0) + return; + + /* ignore join/part/quit from self nick */ + if ((command == RELAY_IRC_CMD_JOIN) || (command == RELAY_IRC_CMD_PART) + || (command == RELAY_IRC_CMD_QUIT)) + { + localvar_nick = weechat_buffer_get_string (buffer, "localvar_nick"); + if (localvar_nick && localvar_nick[0] + && (strcmp (ptr_nick, localvar_nick) == 0)) + { + command = -1; + return; + } + } + + /* fills variables with the line data */ + if (irc_command) + *irc_command = command; + if (irc_action) + *irc_action = action; + if (date) + *date = msg_date; + if (nick) + *nick = ptr_nick; + if (nick1) + *nick1 = ptr_nick1; + if (nick2) + *nick2 = ptr_nick2; + message_no_color = (ptr_message) ? + weechat_string_remove_color (ptr_message, NULL) : NULL; + if ((command == RELAY_IRC_CMD_PRIVMSG) && message && message_no_color) + { + pos = message_no_color; + if (action) + { + pos = strchr (message_no_color, ' '); + if (pos) + { + while (pos[0] == ' ') + { + pos++; + } + } + else + pos = message_no_color; + } + /* + * if server capability "server-time" is NOT enabled, and if the time + * format is not empty, add time inside message (before message) + */ + time_format = weechat_config_string (relay_config_irc_backlog_time_format); + if (!(RELAY_IRC_DATA(client, server_capabilities) & (1 << RELAY_IRC_CAPAB_SERVER_TIME)) + && time_format && time_format[0]) + { + strftime (str_time, sizeof (str_time), time_format, tm); + length = strlen (str_time) + strlen (pos) + 1; + *message = malloc (length); + if (*message) + snprintf (*message, length, "%s%s", str_time, pos); + } + else + *message = strdup (pos); + } + switch (command) + { + case RELAY_IRC_CMD_JOIN: + case RELAY_IRC_CMD_PART: + case RELAY_IRC_CMD_QUIT: + if (host && message && message_no_color) + { + pos = strstr (message_no_color, " ("); + if (pos) + { + pos2 = strchr (pos, ')'); + if (pos2) + *host = weechat_strndup (pos + 2, pos2 - pos - 2); + } + } + break; + default: + break; + } + /* if server capability "server-time" is enabled, add an irc tag with time */ + if (tags + && (RELAY_IRC_DATA(client, server_capabilities) & (1 << RELAY_IRC_CAPAB_SERVER_TIME))) + { + strftime (str_time, sizeof (str_time), "%Y-%m-%dT%H:%M:%S", tm); + snprintf (str_tag, sizeof (str_tag), "@time=%s.000Z ", str_time); + *tags = strdup (str_tag); + } + + if (message_no_color) + free (message_no_color); +} + +/* + * Sends channel backlog to client. + */ + +void +relay_irc_send_channel_backlog (struct t_relay_client *client, + const char *channel, + struct t_gui_buffer *buffer) +{ + struct t_relay_server *ptr_server; + void *ptr_own_lines, *ptr_line, *ptr_line_data; + void *ptr_hdata_line, *ptr_hdata_line_data; + char *tags, *host, *message; + const char *ptr_nick, *ptr_nick1, *ptr_nick2; + int irc_command, irc_action, count, max_number, max_minutes; + time_t date_min, date_min2, date; + + /* get pointer on "own_lines" in buffer */ + ptr_own_lines = weechat_hdata_pointer (weechat_hdata_get ("buffer"), + buffer, "own_lines"); + if (!ptr_own_lines) + return; + + /* get pointer on "last_line" in lines */ + ptr_line = weechat_hdata_pointer (weechat_hdata_get ("lines"), + ptr_own_lines, "last_line"); + if (!ptr_line) + return; + + /* get hdata "line" */ + ptr_hdata_line = weechat_hdata_get ("line"); + if (!ptr_hdata_line) + return; + + /* get hdata "line_data" */ + ptr_hdata_line_data = weechat_hdata_get ("line_data"); + if (!ptr_hdata_line_data) + return; + + max_number = weechat_config_integer (relay_config_irc_backlog_max_number); + max_minutes = weechat_config_integer (relay_config_irc_backlog_max_minutes); + date_min = (max_minutes > 0) ? time (NULL) - (max_minutes * 60) : 0; + if (weechat_config_boolean (relay_config_irc_backlog_since_last_disconnect)) + { + ptr_server = relay_server_search (client->protocol_string); + if (ptr_server && (ptr_server->last_client_disconnect > 0)) + { + date_min2 = ptr_server->last_client_disconnect; + if (date_min2 > date_min) + date_min = date_min2; + } + } + + /* + * loop on lines in buffer, from last to first, and stop when we have + * reached max number of lines (or max minutes) + */ + count = 0; + while (ptr_line) + { + ptr_line_data = weechat_hdata_pointer (ptr_hdata_line, + ptr_line, "data"); + if (ptr_line_data) + { + relay_irc_get_line_info (client, buffer, + ptr_hdata_line_data, ptr_line_data, + &irc_command, + NULL, /* irc_action */ + &date, + NULL, /* nick */ + NULL, /* nick1 */ + NULL, /* nick2 */ + NULL, /* tags */ + NULL, /* host */ + NULL); /* message */ + if (irc_command >= 0) + { + /* if we have reached max minutes, exit loop */ + if ((date_min > 0) && (date < date_min)) + break; + count++; + } + /* if we have reached max number of messages, exit loop */ + if ((max_number > 0) && (count > max_number)) + break; + } + ptr_line = weechat_hdata_move (ptr_hdata_line, ptr_line, -1); + } + + if (!ptr_line) + { + /* if we have reached beginning of buffer, start from first line */ + ptr_line = weechat_hdata_pointer (weechat_hdata_get ("lines"), + ptr_own_lines, "first_line"); + } + else + { + /* start from line + 1 (the current line must not be sent) */ + ptr_line = weechat_hdata_move (ptr_hdata_line, ptr_line, 1); + } + + /* + * loop on lines from line pointer until last line of buffer, and for each + * irc message, sends it to client + */ + while (ptr_line) + { + ptr_line_data = weechat_hdata_pointer (ptr_hdata_line, + ptr_line, "data"); + if (ptr_line_data) + { + relay_irc_get_line_info (client, buffer, + ptr_hdata_line_data, ptr_line_data, + &irc_command, + &irc_action, + &date, + &ptr_nick, + &ptr_nick1, + &ptr_nick2, + &tags, + &host, + &message); + switch (irc_command) + { + case RELAY_IRC_CMD_JOIN: + relay_irc_sendf (client, + "%s:%s%s%s JOIN :%s", + (tags) ? tags : "", + ptr_nick, + (host) ? "!" : "", + (host) ? host : "", + channel); + break; + case RELAY_IRC_CMD_PART: + relay_irc_sendf (client, + "%s:%s%s%s PART %s", + (tags) ? tags : "", + ptr_nick, + (host) ? "!" : "", + (host) ? host : "", + channel); + case RELAY_IRC_CMD_QUIT: + relay_irc_sendf (client, + "%s:%s%s%s QUIT", + (tags) ? tags : "", + ptr_nick, + (host) ? "!" : "", + (host) ? host : ""); + break; + case RELAY_IRC_CMD_NICK: + if (ptr_nick1 && ptr_nick2) + { + relay_irc_sendf (client, + "%s:%s NICK :%s", + (tags) ? tags : "", + ptr_nick1, + ptr_nick2); + } + break; + case RELAY_IRC_CMD_PRIVMSG: + if (ptr_nick && message) + { + relay_irc_sendf (client, + "%s:%s PRIVMSG %s :%s%s%s", + (tags) ? tags : "", + ptr_nick, + channel, + (irc_action) ? "\01ACTION " : "", + message, + (irc_action) ? "\01": ""); + } + break; + case RELAY_IRC_NUM_CMD: + /* make C compiler happy */ + break; + } + if (tags) + free (tags); + if (host) + free (host); + if (message) + free (message); + } + ptr_line = weechat_hdata_move (ptr_hdata_line, ptr_line, 1); + } +} + +/* * Sends IRC "JOIN" for a channel to client. */ @@ -510,6 +935,7 @@ relay_irc_send_join (struct t_relay_client *client, char *host; int length, length_nicks; struct t_infolist *infolist_nick, *infolist_channel, *infolist_nicks; + struct t_gui_buffer *buffer; length = strlen (client->protocol_args) + 1 + strlen (channel) + 1 + strlen (RELAY_IRC_DATA(client, nick)) + 1; @@ -533,6 +959,7 @@ relay_irc_send_join (struct t_relay_client *client, } weechat_infolist_free (infolist_nick); } + relay_irc_sendf (client, ":%s!%s JOIN %s", RELAY_IRC_DATA(client, nick), @@ -543,12 +970,15 @@ relay_irc_send_join (struct t_relay_client *client, snprintf (infolist_name, length, "%s,%s", client->protocol_args, channel); + + buffer = NULL; infolist_channel = weechat_infolist_get ("irc_channel", NULL, infolist_name); if (infolist_channel) { if (weechat_infolist_next (infolist_channel)) { + buffer = weechat_infolist_pointer (infolist_channel, "buffer"); topic = weechat_infolist_string (infolist_channel, "topic"); if (topic && topic[0]) { @@ -613,6 +1043,10 @@ relay_irc_send_join (struct t_relay_client *client, RELAY_IRC_DATA(client, nick), channel); free (infolist_name); + + /* send backlog to client */ + if (buffer) + relay_irc_send_channel_backlog (client, channel, buffer); } } @@ -739,6 +1173,99 @@ relay_irc_hook_signals (struct t_relay_client *client) } /* + * Timer called to hooks signals and send joins for all channels to client. + */ + +int +relay_irc_timer_hooks_and_joins_cb (void *data, int remaining_calls) +{ + /* make C compiler happy */ + (void) remaining_calls; + + if (relay_client_valid (data)) + { + /* hook signals */ + relay_irc_hook_signals (data); + + /* send JOIN for all channels on server to client */ + relay_irc_send_join_channels (data); + } + + return WEECHAT_RC_OK; +} + +/* + * Processes the "CAP" irc command (received from client) + */ + +void +relay_irc_recv_command_capab (struct t_relay_client *client, + const char *arguments) +{ + char str_capab[1024], **capabs; + const char *ptr_args; + int i, num_capabs, capability; + + if (weechat_strcasecmp (arguments, "ls") == 0) + { + /* return the list of supported server capabilities */ + str_capab[0] = '\0'; + for (i = 0; i < RELAY_IRC_NUM_CAPAB; i++) + { + if (str_capab[0]) + strcat (str_capab, " "); + strcat (str_capab, relay_irc_server_capabilities[i]); + relay_irc_sendf (client, + ":%s CAP %s LS :%s", + RELAY_IRC_DATA(client, address), + (RELAY_IRC_DATA(client, nick)) ? RELAY_IRC_DATA(client, nick) : "nick", + str_capab); + } + } + else if (weechat_strncasecmp (arguments, "req ", 4) == 0) + { + /* client is asking for one or more server capabilities */ + ptr_args = arguments + 4; + while (ptr_args[0] == ' ') + { + ptr_args++; + } + if (ptr_args[0] == ':') + ptr_args++; + capabs = weechat_string_split (ptr_args, " ", 0, 0, &num_capabs); + if (capabs) + { + str_capab[0] = '\0'; + for (i = 0; i < num_capabs; i++) + { + capability = relay_irc_search_server_capability (capabs[i]); + if (capability >= 0) + { + if (str_capab[0]) + strcat (str_capab, " "); + strcat (str_capab, + relay_irc_server_capabilities[capability]); + RELAY_IRC_DATA(client, server_capabilities) |= 1 << capability; + } + } + /* + * if at least one supported capability was enabled, send ACK to + * client + */ + if (str_capab[0]) + { + relay_irc_sendf (client, + ":%s CAP %s ACK :%s", + RELAY_IRC_DATA(client, address), + (RELAY_IRC_DATA(client, nick)) ? RELAY_IRC_DATA(client, nick) : "nick", + str_capab); + } + weechat_string_free_split (capabs); + } + } +} + +/* * Reads one message from client. */ @@ -786,7 +1313,10 @@ relay_irc_recv_one_msg (struct t_relay_client *client, char *data) if (irc_args) irc_argv = weechat_string_split (irc_args, " ", 0, 0, &irc_argc); - /* process the message */ + /* + * first process the "nick" command (it will be processed again in this + * function below) + */ if (irc_command && (weechat_strcasecmp (irc_command, "nick") == 0)) { if (irc_args && irc_args[0]) @@ -796,6 +1326,13 @@ relay_irc_recv_one_msg (struct t_relay_client *client, char *data) RELAY_IRC_DATA(client, nick) = strdup (irc_args); } } + /* server capabilities */ + if (irc_command && (weechat_strcasecmp (irc_command, "cap") == 0)) + { + if (irc_args) + relay_irc_recv_command_capab (client, irc_args); + } + /* if client is not yet "connected" */ if (!RELAY_IRC_DATA(client, connected)) { if (irc_command && (weechat_strcasecmp (irc_command, "pass") == 0)) @@ -942,11 +1479,17 @@ relay_irc_recv_one_msg (struct t_relay_client *client, char *data) RELAY_IRC_DATA(client, address), RELAY_IRC_DATA(client, nick)); - /* hook signals */ - relay_irc_hook_signals (client); - - /* send JOIN for all channels on server to client */ - relay_irc_send_join_channels (client); + /* + * hook a timer which will hook signals and send JOIN for all + * channels to client (a timer is needed because we may not have + * received the server capabilities yet, like server-time) + */ + if (RELAY_IRC_DATA(client, hook_timer_signals_joins)) + weechat_unhook (RELAY_IRC_DATA(client, hook_timer_signals_joins)); + RELAY_IRC_DATA(client, hook_timer_signals_joins) = + weechat_hook_timer (500, 0, 1, + &relay_irc_timer_hooks_and_joins_cb, + client); } } else @@ -1173,6 +1716,12 @@ void relay_irc_close_connection (struct t_relay_client *client) { RELAY_IRC_DATA(client, connected) = 0; + + if (RELAY_IRC_DATA(client, hook_timer_signals_joins)) + { + weechat_unhook (RELAY_IRC_DATA(client, hook_timer_signals_joins)); + RELAY_IRC_DATA(client, hook_timer_signals_joins) = NULL; + } if (RELAY_IRC_DATA(client, hook_signal_irc_in2)) { weechat_unhook (RELAY_IRC_DATA(client, hook_signal_irc_in2)); @@ -1215,6 +1764,8 @@ relay_irc_alloc (struct t_relay_client *client) RELAY_IRC_DATA(client, nick) = NULL; RELAY_IRC_DATA(client, user_received) = 0; RELAY_IRC_DATA(client, connected) = 0; + RELAY_IRC_DATA(client, server_capabilities) = 0; + RELAY_IRC_DATA(client, hook_timer_signals_joins) = NULL; RELAY_IRC_DATA(client, hook_signal_irc_in2) = NULL; RELAY_IRC_DATA(client, hook_signal_irc_outtags) = NULL; RELAY_IRC_DATA(client, hook_signal_irc_disc) = NULL; @@ -1245,6 +1796,8 @@ relay_irc_alloc_with_infolist (struct t_relay_client *client, RELAY_IRC_DATA(client, nick) = NULL; RELAY_IRC_DATA(client, user_received) = weechat_infolist_integer (infolist, "user_received"); RELAY_IRC_DATA(client, connected) = weechat_infolist_integer (infolist, "connected"); + RELAY_IRC_DATA(client, server_capabilities) = weechat_infolist_integer (infolist, "server_capabilities"); + RELAY_IRC_DATA(client, hook_timer_signals_joins) = NULL; if (RELAY_IRC_DATA(client, connected)) { relay_irc_hook_signals (client); @@ -1272,6 +1825,8 @@ relay_irc_free (struct t_relay_client *client) free (RELAY_IRC_DATA(client, address)); if (RELAY_IRC_DATA(client, nick)) free (RELAY_IRC_DATA(client, nick)); + if (RELAY_IRC_DATA(client, hook_timer_signals_joins)) + weechat_unhook (RELAY_IRC_DATA(client, hook_timer_signals_joins)); if (RELAY_IRC_DATA(client, hook_signal_irc_in2)) weechat_unhook (RELAY_IRC_DATA(client, hook_signal_irc_in2)); if (RELAY_IRC_DATA(client, hook_signal_irc_outtags)) @@ -1312,6 +1867,10 @@ relay_irc_add_to_infolist (struct t_infolist_item *item, return 0; if (!weechat_infolist_new_var_integer (item, "connected", RELAY_IRC_DATA(client, connected))) return 0; + if (!weechat_infolist_new_var_integer (item, "server_capabilities", RELAY_IRC_DATA(client, server_capabilities))) + return 0; + if (!weechat_infolist_new_var_pointer (item, "hook_timer_signals_joins", RELAY_IRC_DATA(client, hook_timer_signals_joins))) + return 0; if (!weechat_infolist_new_var_pointer (item, "hook_signal_irc_in2", RELAY_IRC_DATA(client, hook_signal_irc_in2))) return 0; if (!weechat_infolist_new_var_pointer (item, "hook_signal_irc_outtags", RELAY_IRC_DATA(client, hook_signal_irc_outtags))) @@ -1333,14 +1892,16 @@ relay_irc_print_log (struct t_relay_client *client) { if (client->protocol_data) { - weechat_log_printf (" address. . . . . . . . : '%s'", RELAY_IRC_DATA(client, address)); - weechat_log_printf (" password_ok. . . . . . : %d", RELAY_IRC_DATA(client, password_ok)); - weechat_log_printf (" nick . . . . . . . . . : '%s'", RELAY_IRC_DATA(client, nick)); - weechat_log_printf (" user_received. . . . . : %d", RELAY_IRC_DATA(client, user_received)); - weechat_log_printf (" connected. . . . . . . : %d", RELAY_IRC_DATA(client, connected)); - weechat_log_printf (" hook_signal_irc_in2. . : 0x%lx", RELAY_IRC_DATA(client, hook_signal_irc_in2)); - weechat_log_printf (" hook_signal_irc_outtags: 0x%lx", RELAY_IRC_DATA(client, hook_signal_irc_outtags)); - weechat_log_printf (" hook_signal_irc_disc . : 0x%lx", RELAY_IRC_DATA(client, hook_signal_irc_disc)); - weechat_log_printf (" hook_hsignal_irc_redir : 0x%lx", RELAY_IRC_DATA(client, hook_hsignal_irc_redir)); + weechat_log_printf (" address . . . . . . . . : '%s'", RELAY_IRC_DATA(client, address)); + weechat_log_printf (" password_ok . . . . . . : %d", RELAY_IRC_DATA(client, password_ok)); + weechat_log_printf (" nick. . . . . . . . . . : '%s'", RELAY_IRC_DATA(client, nick)); + weechat_log_printf (" user_received . . . . . : %d", RELAY_IRC_DATA(client, user_received)); + weechat_log_printf (" connected . . . . . . . : %d", RELAY_IRC_DATA(client, connected)); + weechat_log_printf (" server_capabilities . . : %d", RELAY_IRC_DATA(client, server_capabilities)); + weechat_log_printf (" hook_timer_signals_joins: 0x%lx", RELAY_IRC_DATA(client, hook_timer_signals_joins)); + weechat_log_printf (" hook_signal_irc_in2 . . : 0x%lx", RELAY_IRC_DATA(client, hook_signal_irc_in2)); + weechat_log_printf (" hook_signal_irc_outtags : 0x%lx", RELAY_IRC_DATA(client, hook_signal_irc_outtags)); + weechat_log_printf (" hook_signal_irc_disc. . : 0x%lx", RELAY_IRC_DATA(client, hook_signal_irc_disc)); + weechat_log_printf (" hook_hsignal_irc_redir. : 0x%lx", RELAY_IRC_DATA(client, hook_hsignal_irc_redir)); } } diff --git a/src/plugins/relay/irc/relay-irc.h b/src/plugins/relay/irc/relay-irc.h index 2235da1f1..a30e9cf1b 100644 --- a/src/plugins/relay/irc/relay-irc.h +++ b/src/plugins/relay/irc/relay-irc.h @@ -34,12 +34,34 @@ struct t_relay_irc_data int user_received; /* command "USER" received */ int connected; /* 1 if client is connected as IRC */ /* client */ + int server_capabilities; /* server capabilities enabled (one */ + /* bit per capability) */ + struct t_hook *hook_timer_signals_joins;/* timer to hooks signals and */ + /* send joins to client */ struct t_hook *hook_signal_irc_in2; /* signal "irc_in2" */ struct t_hook *hook_signal_irc_outtags; /* signal "irc_outtags" */ struct t_hook *hook_signal_irc_disc; /* signal "irc_disconnected" */ struct t_hook *hook_hsignal_irc_redir; /* hsignal "irc_redirection_..."*/ }; +enum t_relay_irc_command +{ + RELAY_IRC_CMD_JOIN = 0, + RELAY_IRC_CMD_PART, + RELAY_IRC_CMD_QUIT, + RELAY_IRC_CMD_NICK, + RELAY_IRC_CMD_PRIVMSG, + /* number of relay irc commands */ + RELAY_IRC_NUM_CMD, +}; + +enum t_relay_irc_server_capab +{ + RELAY_IRC_CAPAB_SERVER_TIME = 0, + /* number of server capabilities */ + RELAY_IRC_NUM_CAPAB, +}; + extern void relay_irc_recv (struct t_relay_client *client, const char *data); extern void relay_irc_close_connection (struct t_relay_client *client); diff --git a/src/plugins/relay/relay-client.c b/src/plugins/relay/relay-client.c index 7816accd1..7b2ac1605 100644 --- a/src/plugins/relay/relay-client.c +++ b/src/plugins/relay/relay-client.c @@ -647,6 +647,7 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server) new_client->address = strdup ((address) ? address : "?"); new_client->status = RELAY_STATUS_CONNECTED; new_client->protocol = server->protocol; + new_client->protocol_string = (server->protocol_string) ? strdup (server->protocol_string) : NULL; new_client->protocol_args = (server->protocol_args) ? strdup (server->protocol_args) : NULL; new_client->listen_start_time = server->start_time; new_client->start_time = time (NULL); @@ -794,6 +795,8 @@ relay_client_new_with_infolist (struct t_infolist *infolist) new_client->address = strdup (weechat_infolist_string (infolist, "address")); new_client->status = weechat_infolist_integer (infolist, "status"); new_client->protocol = weechat_infolist_integer (infolist, "protocol"); + str = weechat_infolist_string (infolist, "protocol_string"); + new_client->protocol_string = (str) ? strdup (str) : NULL; str = weechat_infolist_string (infolist, "protocol_args"); new_client->protocol_args = (str) ? strdup (str) : NULL; new_client->listen_start_time = weechat_infolist_time (infolist, "listen_start_time"); @@ -859,12 +862,18 @@ void relay_client_set_status (struct t_relay_client *client, enum t_relay_status status) { + struct t_relay_server *ptr_server; + client->status = status; if (RELAY_CLIENT_HAS_ENDED(client)) { client->end_time = time (NULL); + ptr_server = relay_server_search (client->protocol_string); + if (ptr_server) + ptr_server->last_client_disconnect = client->end_time; + relay_client_outqueue_free_all (client); if (client->hook_fd) @@ -951,8 +960,12 @@ relay_client_free (struct t_relay_client *client) (client->next_client)->prev_client = client->prev_client; /* free data */ + if (client->desc) + free (client->desc); if (client->address) free (client->address); + if (client->protocol_string) + free (client->protocol_string); if (client->protocol_args) free (client->protocol_args); #ifdef HAVE_GNUTLS @@ -1075,6 +1088,8 @@ relay_client_add_to_infolist (struct t_infolist *infolist, return 0; if (!weechat_infolist_new_var_string (ptr_item, "protocol_string", relay_protocol_string[client->protocol])) return 0; + if (!weechat_infolist_new_var_string (ptr_item, "protocol_string", client->protocol_string)) + return 0; if (!weechat_infolist_new_var_string (ptr_item, "protocol_args", client->protocol_args)) return 0; if (!weechat_infolist_new_var_time (ptr_item, "listen_start_time", client->listen_start_time)) @@ -1138,6 +1153,7 @@ relay_client_print_log () weechat_log_printf (" protocol. . . . . . . : %d (%s)", ptr_client->protocol, relay_protocol_string[ptr_client->protocol]); + weechat_log_printf (" protocol_string . . . : '%s'", ptr_client->protocol_string); weechat_log_printf (" protocol_args . . . . : '%s'", ptr_client->protocol_args); weechat_log_printf (" listen_start_time . . : %ld", ptr_client->listen_start_time); weechat_log_printf (" start_time. . . . . . : %ld", ptr_client->start_time); diff --git a/src/plugins/relay/relay-client.h b/src/plugins/relay/relay-client.h index 07a21b0b0..96b236439 100644 --- a/src/plugins/relay/relay-client.h +++ b/src/plugins/relay/relay-client.h @@ -70,6 +70,7 @@ struct t_relay_client char *address; /* string with IP address */ enum t_relay_status status; /* status (connecting, active,..) */ enum t_relay_protocol protocol; /* protocol (irc,..) */ + char *protocol_string; /* example: "ipv6.ssl.irc.freenode" */ char *protocol_args; /* arguments used for protocol */ /* example: server for irc protocol */ time_t listen_start_time; /* when listening started */ diff --git a/src/plugins/relay/relay-config.c b/src/plugins/relay/relay-config.c index 2f66e23b8..72790c698 100644 --- a/src/plugins/relay/relay-config.c +++ b/src/plugins/relay/relay-config.c @@ -58,9 +58,18 @@ struct t_config_option *relay_config_network_max_clients; struct t_config_option *relay_config_network_password; struct t_config_option *relay_config_network_ssl_cert_key; +/* relay config, irc section */ + +struct t_config_option *relay_config_irc_backlog_max_number; +struct t_config_option *relay_config_irc_backlog_max_minutes; +struct t_config_option *relay_config_irc_backlog_since_last_disconnect; +struct t_config_option *relay_config_irc_backlog_tags; +struct t_config_option *relay_config_irc_backlog_time_format; + /* other */ regex_t *relay_config_regex_allowed_ips = NULL; +struct t_hashtable *relay_config_hashtable_irc_backlog_tags = NULL; /* @@ -179,6 +188,46 @@ relay_config_change_network_ssl_cert_key (void *data, } /* + * Callback for changes on option "relay.irc.backlog_tags". + */ + +void +relay_config_change_irc_backlog_tags (void *data, + struct t_config_option *option) +{ + char **items; + int num_items, i; + + /* make C compiler happy */ + (void) data; + (void) option; + + if (!relay_config_hashtable_irc_backlog_tags) + { + relay_config_hashtable_irc_backlog_tags = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + } + else + weechat_hashtable_remove_all (relay_config_hashtable_irc_backlog_tags); + + items = weechat_string_split (weechat_config_string (relay_config_irc_backlog_tags), + ";", 0, 0, &num_items); + if (items) + { + for (i = 0; i < num_items; i++) + { + weechat_hashtable_set (relay_config_hashtable_irc_backlog_tags, + items[i], + NULL); + } + weechat_string_free_split (items); + } +} + +/* * Checks if a port is valid. * * Returns: @@ -401,6 +450,7 @@ relay_config_init () if (!relay_config_file) return 0; + /* section look */ ptr_section = weechat_config_new_section (relay_config_file, "look", 0, 0, NULL, NULL, NULL, NULL, @@ -424,6 +474,7 @@ relay_config_init () "closed (messages will be displayed when opening raw data buffer)"), NULL, 0, 65535, "256", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + /* section color */ ptr_section = weechat_config_new_section (relay_config_file, "color", 0, 0, NULL, NULL, NULL, NULL, @@ -490,6 +541,7 @@ relay_config_init () NULL, 0, 0, "lightred", NULL, 0, NULL, NULL, &relay_config_refresh_cb, NULL, NULL, NULL); + /* section network */ ptr_section = weechat_config_new_section (relay_config_file, "network", 0, 0, NULL, NULL, NULL, NULL, @@ -555,6 +607,56 @@ relay_config_init () NULL, 0, 0, "%h/ssl/relay.pem", NULL, 0, NULL, NULL, &relay_config_change_network_ssl_cert_key, NULL, NULL, NULL); + /* section irc */ + ptr_section = weechat_config_new_section (relay_config_file, "irc", + 0, 0, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL); + if (!ptr_section) + { + weechat_config_free (relay_config_file); + return 0; + } + + relay_config_irc_backlog_max_number = weechat_config_new_option ( + relay_config_file, ptr_section, + "backlog_max_number", "integer", + N_("maximum number of lines in backlog per IRC channel " + "(0 = unlimited)"), + NULL, 0, INT_MAX, "256", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + relay_config_irc_backlog_max_minutes = weechat_config_new_option ( + relay_config_file, ptr_section, + "backlog_max_minutes", "integer", + N_("maximum number of minutes in backlog per IRC channel " + "(0 = unlimited, examples: 1440 = one day, 10080 = one week, " + "43200 = one month, 525600 = one year)"), + NULL, 0, INT_MAX, "1440", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + relay_config_irc_backlog_since_last_disconnect = weechat_config_new_option ( + relay_config_file, ptr_section, + "backlog_since_last_disconnect", "boolean", + N_("display backlog starting from last client disconnect"), + NULL, 0, 0, "on", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + relay_config_irc_backlog_tags = weechat_config_new_option ( + relay_config_file, ptr_section, + "backlog_tags", "string", + N_("tags of messages which are displayed in backlog per IRC channel " + "(supported tags: \"irc_join\", \"irc_part\", \"irc_quit\", " + "\"irc_nick\", \"irc_privmsg\"), \"*\" = all supported tags"), + NULL, 0, 0, "irc_privmsg", NULL, 0, NULL, NULL, + &relay_config_change_irc_backlog_tags, NULL, NULL, NULL); + relay_config_irc_backlog_time_format = weechat_config_new_option ( + relay_config_file, ptr_section, + "backlog_time_format", "string", + N_("format for time in backlog messages (see man strftime for format) " + "(not used if server capability \"server-time\" was enabled by " + "client, because time is sent as irc tag); empty string = disable " + "time in backlog messages"), + NULL, 0, 0, "[%H:%M] ", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + + /* section port */ ptr_section = weechat_config_new_section (relay_config_file, "port", 1, 1, NULL, NULL, @@ -580,7 +682,15 @@ relay_config_init () int relay_config_read () { - return weechat_config_read (relay_config_file); + int rc; + + rc = weechat_config_read (relay_config_file); + if (rc == WEECHAT_CONFIG_READ_OK) + { + relay_config_change_network_allowed_ips (NULL, NULL); + relay_config_change_irc_backlog_tags (NULL, NULL); + } + return rc; } /* @@ -592,3 +702,26 @@ relay_config_write () { return weechat_config_write (relay_config_file); } + +/* + * Frees relay configuration. + */ + +void +relay_config_free () +{ + weechat_config_free (relay_config_file); + + if (relay_config_regex_allowed_ips) + { + regfree (relay_config_regex_allowed_ips); + free (relay_config_regex_allowed_ips); + relay_config_regex_allowed_ips = NULL; + } + + if (relay_config_hashtable_irc_backlog_tags) + { + weechat_hashtable_free (relay_config_hashtable_irc_backlog_tags); + relay_config_hashtable_irc_backlog_tags = NULL; + } +} diff --git a/src/plugins/relay/relay-config.h b/src/plugins/relay/relay-config.h index 8a54b75e1..c4499bc0d 100644 --- a/src/plugins/relay/relay-config.h +++ b/src/plugins/relay/relay-config.h @@ -44,7 +44,14 @@ extern struct t_config_option *relay_config_network_max_clients; extern struct t_config_option *relay_config_network_password; extern struct t_config_option *relay_config_network_ssl_cert_key; +extern struct t_config_option *relay_config_irc_backlog_max_number; +extern struct t_config_option *relay_config_irc_backlog_max_minutes; +extern struct t_config_option *relay_config_irc_backlog_since_last_disconnect; +extern struct t_config_option *relay_config_irc_backlog_tags; +extern struct t_config_option *relay_config_irc_backlog_time_format; + extern regex_t *relay_config_regex_allowed_ips; +extern struct t_hashtable *relay_config_hashtable_irc_backlog_tags; extern int relay_config_create_option_port (void *data, struct t_config_file *config_file, @@ -54,5 +61,6 @@ extern int relay_config_create_option_port (void *data, extern int relay_config_init (); extern int relay_config_read (); extern int relay_config_write (); +extern void relay_config_free (); #endif /* __WEECHAT_RELAY_CONFIG_H */ diff --git a/src/plugins/relay/relay-server.c b/src/plugins/relay/relay-server.c index 00d8f23cd..4ae749af1 100644 --- a/src/plugins/relay/relay-server.c +++ b/src/plugins/relay/relay-server.c @@ -501,6 +501,7 @@ relay_server_new (const char *protocol_string, enum t_relay_protocol protocol, new_server->sock = -1; new_server->hook_fd = NULL; new_server->start_time = 0; + new_server->last_client_disconnect = 0; if (!relay_server_create_socket (new_server)) { @@ -596,6 +597,53 @@ relay_server_free_all () } /* + * Adds a server in an infolist. + * + * Returns: + * 1: OK + * 0: error + */ + +int +relay_server_add_to_infolist (struct t_infolist *infolist, + struct t_relay_server *server) +{ + struct t_infolist_item *ptr_item; + + if (!infolist || !server) + return 0; + + ptr_item = weechat_infolist_new_item (infolist); + if (!ptr_item) + return 0; + + if (!weechat_infolist_new_var_string (ptr_item, "protocol_string", server->protocol_string)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "protocol", server->protocol)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "protocol_args", server->protocol_args)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "port", server->port)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "ipv4", server->ipv4)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "ipv6", server->ipv6)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "ssl", server->ssl)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "sock", server->sock)) + return 0; + if (!weechat_infolist_new_var_pointer (ptr_item, "hook_fd", server->hook_fd)) + return 0; + if (!weechat_infolist_new_var_time (ptr_item, "start_time", server->start_time)) + return 0; + if (!weechat_infolist_new_var_time (ptr_item, "last_client_disconnect", server->last_client_disconnect)) + return 0; + + return 1; +} + +/* * Prints servers in WeeChat log file (usually for crash dump). */ @@ -609,19 +657,20 @@ relay_server_print_log () { weechat_log_printf (""); weechat_log_printf ("[relay server (addr:0x%lx)]", ptr_server); - weechat_log_printf (" protocol_string . . : '%s'", ptr_server->protocol_string); - weechat_log_printf (" protocol. . . . . . : %d (%s)", + weechat_log_printf (" protocol_string . . . : '%s'", ptr_server->protocol_string); + weechat_log_printf (" protocol. . . . . . . : %d (%s)", ptr_server->protocol, relay_protocol_string[ptr_server->protocol]); - weechat_log_printf (" protocol_args . . . : '%s'", ptr_server->protocol_args); - weechat_log_printf (" port. . . . . . . . : %d", ptr_server->port); - weechat_log_printf (" ipv4. . . . . . . . : %d", ptr_server->ipv4); - weechat_log_printf (" ipv6. . . . . . . . : %d", ptr_server->ipv6); - weechat_log_printf (" ssl . . . . . . . . : %d", ptr_server->ssl); - weechat_log_printf (" sock. . . . . . . . : %d", ptr_server->sock); - weechat_log_printf (" hook_fd . . . . . . : 0x%lx", ptr_server->hook_fd); - weechat_log_printf (" start_time. . . . . : %ld", ptr_server->start_time); - weechat_log_printf (" prev_server . . . . : 0x%lx", ptr_server->prev_server); - weechat_log_printf (" next_server . . . . : 0x%lx", ptr_server->next_server); + weechat_log_printf (" protocol_args . . . . : '%s'", ptr_server->protocol_args); + weechat_log_printf (" port. . . . . . . . . : %d", ptr_server->port); + weechat_log_printf (" ipv4. . . . . . . . . : %d", ptr_server->ipv4); + weechat_log_printf (" ipv6. . . . . . . . . : %d", ptr_server->ipv6); + weechat_log_printf (" ssl . . . . . . . . . : %d", ptr_server->ssl); + weechat_log_printf (" sock. . . . . . . . . : %d", ptr_server->sock); + weechat_log_printf (" hook_fd . . . . . . . : 0x%lx", ptr_server->hook_fd); + weechat_log_printf (" start_time. . . . . . : %ld", ptr_server->start_time); + weechat_log_printf (" last_client_disconnect: %ld", ptr_server->last_client_disconnect); + weechat_log_printf (" prev_server . . . . . : 0x%lx", ptr_server->prev_server); + weechat_log_printf (" next_server . . . . . : 0x%lx", ptr_server->next_server); } } diff --git a/src/plugins/relay/relay-server.h b/src/plugins/relay/relay-server.h index f4af777e8..b5945bec7 100644 --- a/src/plugins/relay/relay-server.h +++ b/src/plugins/relay/relay-server.h @@ -37,6 +37,7 @@ struct t_relay_server int sock; /* socket for connection */ struct t_hook *hook_fd; /* hook for socket */ time_t start_time; /* start time */ + time_t last_client_disconnect; /* last time a client disconnected */ struct t_relay_server *prev_server;/* link to previous server */ struct t_relay_server *next_server;/* link to next server */ }; @@ -61,6 +62,8 @@ extern struct t_relay_server *relay_server_new (const char *protocol_string, extern void relay_server_update_port (struct t_relay_server *server, int port); extern void relay_server_free (struct t_relay_server *server); extern void relay_server_free_all (); +extern int relay_server_add_to_infolist (struct t_infolist *infolist, + struct t_relay_server *server); extern void relay_server_print_log (); #endif /* __WEECHAT_RELAY_SERVER_H */ diff --git a/src/plugins/relay/relay-upgrade.c b/src/plugins/relay/relay-upgrade.c index dadbfc5ac..d60968c69 100644 --- a/src/plugins/relay/relay-upgrade.c +++ b/src/plugins/relay/relay-upgrade.c @@ -29,6 +29,7 @@ #include "relay-buffer.h" #include "relay-client.h" #include "relay-raw.h" +#include "relay-server.h" /* @@ -43,10 +44,31 @@ int relay_upgrade_save_all_data (struct t_upgrade_file *upgrade_file) { struct t_infolist *infolist; + struct t_relay_server *ptr_server; struct t_relay_client *ptr_client; struct t_relay_raw_message *ptr_raw_message; int rc; + /* save servers */ + for (ptr_server = relay_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + infolist = weechat_infolist_new (); + if (!infolist) + return 0; + if (!relay_server_add_to_infolist (infolist, ptr_server)) + { + weechat_infolist_free (infolist); + return 0; + } + rc = weechat_upgrade_write_object (upgrade_file, + RELAY_UPGRADE_TYPE_SERVER, + infolist); + weechat_infolist_free (infolist); + if (!rc) + return 0; + } + /* save clients */ for (ptr_client = last_relay_client; ptr_client; ptr_client = ptr_client->prev_client) @@ -162,6 +184,9 @@ relay_upgrade_read_cb (void *data, int object_id, struct t_infolist *infolist) { + const char *str; + struct t_relay_server *ptr_server; + /* make C compiler happy */ (void) data; (void) upgrade_file; @@ -171,6 +196,19 @@ relay_upgrade_read_cb (void *data, { switch (object_id) { + case RELAY_UPGRADE_TYPE_SERVER: + str = weechat_infolist_string (infolist, "protocol_string"); + if (str) + { + ptr_server = relay_server_search (str); + if (ptr_server) + { + ptr_server->last_client_disconnect = + weechat_infolist_time (infolist, + "last_client_disconnect"); + } + } + break; case RELAY_UPGRADE_TYPE_CLIENT: relay_client_new_with_infolist (infolist); break; diff --git a/src/plugins/relay/relay-upgrade.h b/src/plugins/relay/relay-upgrade.h index c10726bd6..308c60f78 100644 --- a/src/plugins/relay/relay-upgrade.h +++ b/src/plugins/relay/relay-upgrade.h @@ -28,6 +28,7 @@ enum t_relay_upgrade_type { RELAY_UPGRADE_TYPE_CLIENT = 0, RELAY_UPGRADE_TYPE_RAW_MESSAGE, + RELAY_UPGRADE_TYPE_SERVER, }; extern int relay_upgrade_save (); diff --git a/src/plugins/relay/relay.c b/src/plugins/relay/relay.c index b5c3c4c16..3d9618e78 100644 --- a/src/plugins/relay/relay.c +++ b/src/plugins/relay/relay.c @@ -260,5 +260,7 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) relay_network_end (); + relay_config_free (); + return WEECHAT_RC_OK; } |