diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/demo/demo.c | 2 | ||||
-rw-r--r-- | src/plugins/relay/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/plugins/relay/Makefile.am | 10 | ||||
-rw-r--r-- | src/plugins/relay/relay-buffer.c | 21 | ||||
-rw-r--r-- | src/plugins/relay/relay-client.c | 234 | ||||
-rw-r--r-- | src/plugins/relay/relay-client.h | 12 | ||||
-rw-r--r-- | src/plugins/relay/relay-command.c | 166 | ||||
-rw-r--r-- | src/plugins/relay/relay-completion.c | 157 | ||||
-rw-r--r-- | src/plugins/relay/relay-completion.h (renamed from src/plugins/relay/relay-network.h) | 11 | ||||
-rw-r--r-- | src/plugins/relay/relay-config.c | 181 | ||||
-rw-r--r-- | src/plugins/relay/relay-config.h | 11 | ||||
-rw-r--r-- | src/plugins/relay/relay-network.c | 234 | ||||
-rw-r--r-- | src/plugins/relay/relay-protocol-irc.c | 545 | ||||
-rw-r--r-- | src/plugins/relay/relay-protocol-irc.h | 46 | ||||
-rw-r--r-- | src/plugins/relay/relay-protocol-weechat.c | 230 | ||||
-rw-r--r-- | src/plugins/relay/relay-protocol-weechat.h | 44 | ||||
-rw-r--r-- | src/plugins/relay/relay-server.c | 426 | ||||
-rw-r--r-- | src/plugins/relay/relay-server.h | 52 | ||||
-rw-r--r-- | src/plugins/relay/relay.c | 45 | ||||
-rw-r--r-- | src/plugins/relay/relay.h | 18 |
20 files changed, 2016 insertions, 434 deletions
diff --git a/src/plugins/demo/demo.c b/src/plugins/demo/demo.c index fe7abac61..e777f6866 100644 --- a/src/plugins/demo/demo.c +++ b/src/plugins/demo/demo.c @@ -388,7 +388,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) weechat_plugin = plugin; weechat_hook_command ("demo_printf", - N_("print some messages on current ubffer"), + N_("print some messages on current buffer"), N_("[text]"), N_("text: write this text"), "", diff --git a/src/plugins/relay/CMakeLists.txt b/src/plugins/relay/CMakeLists.txt index e42025b9d..382e336b3 100644 --- a/src/plugins/relay/CMakeLists.txt +++ b/src/plugins/relay/CMakeLists.txt @@ -19,9 +19,12 @@ relay.c relay.h relay-buffer.c relay-buffer.h relay-client.c relay-client.h relay-command.c relay-command.h +relay-completion.c relay-completion.h relay-config.c relay-config.h relay-info.c relay-info.h -relay-network.c relay-network.h +relay-protocol-irc.c relay-protocol-irc.h +relay-protocol-weechat.c relay-protocol-weechat.h +relay-server.c relay-server.h relay-upgrade.c relay-upgrade.h) SET_TARGET_PROPERTIES(relay PROPERTIES PREFIX "") diff --git a/src/plugins/relay/Makefile.am b/src/plugins/relay/Makefile.am index 9e21de7bb..60e8eb64e 100644 --- a/src/plugins/relay/Makefile.am +++ b/src/plugins/relay/Makefile.am @@ -28,12 +28,18 @@ relay_la_SOURCES = relay.c \ relay-client.h \ relay-command.c \ relay-command.h \ + relay-completion.c \ + relay-completion.h \ relay-config.c \ relay-config.h \ relay-info.c \ relay-info.h \ - relay-network.c \ - relay-network.h \ + relay-protocol-irc.c \ + relay-protocol-irc.h \ + relay-protocol-weechat.c \ + relay-protocol-weechat.h \ + relay-server.c \ + relay-server.h \ relay-upgrade.c \ relay-upgrade.h diff --git a/src/plugins/relay/relay-buffer.c b/src/plugins/relay/relay-buffer.c index e727a1f82..a3e22e6a4 100644 --- a/src/plugins/relay/relay-buffer.c +++ b/src/plugins/relay/relay-buffer.c @@ -43,7 +43,7 @@ void relay_buffer_refresh (const char *hotlist) { struct t_relay_client *ptr_client, *client_selected; - char str_color[256], status[64], date_start[128]; + char str_color[256], status[64], date_start[128], date_end[128]; char *str_recv, *str_sent; int i, length, line; struct tm *date_tmp; @@ -95,10 +95,17 @@ relay_buffer_refresh (const char *hotlist) date_tmp = localtime (&(ptr_client->start_time)); strftime (date_start, sizeof (date_start), "%a, %d %b %Y %H:%M:%S", date_tmp); + date_end[0] = '\0'; + if (ptr_client->end_time > 0) + { + date_tmp = localtime (&(ptr_client->end_time)); + strftime (date_end, sizeof (date_end), + "%a, %d %b %Y %H:%M:%S", date_tmp); + } /* first line with status and start time */ weechat_printf_y (relay_buffer, (line * 2) + 2, - _("%s%s[%s%s%s%s] %s (started on: %s)"), + _("%s%s[%s%s%s%s] %s (started on: %s%s%s%s)"), weechat_color(str_color), (line == relay_buffer_selected_line) ? "*** " : " ", @@ -107,15 +114,19 @@ relay_buffer_refresh (const char *hotlist) weechat_color ("reset"), weechat_color (str_color), ptr_client->address, - date_start); + date_start, + (ptr_client->end_time > 0) ? ", " : "", + (ptr_client->end_time > 0) ? _("ended on: ") : "", + (ptr_client->end_time > 0) ? date_end : ""); - /* second line with bytes recv/sent */ + /* second line with protocol and bytes recv/sent */ str_recv = weechat_string_format_size (ptr_client->bytes_recv); str_sent = weechat_string_format_size (ptr_client->bytes_sent); weechat_printf_y (relay_buffer, (line * 2) + 3, - _("%s%-26s received: %s, sent: %s"), + _("%s%-26s protocol: %s, received: %s, sent: %s"), weechat_color(str_color), " ", + relay_protocol_string[ptr_client->protocol], (str_recv) ? str_recv : "?", (str_sent) ? str_sent : "?"); if (str_recv) diff --git a/src/plugins/relay/relay-client.c b/src/plugins/relay/relay-client.c index 39dc7f6c5..4874fca97 100644 --- a/src/plugins/relay/relay-client.c +++ b/src/plugins/relay/relay-client.c @@ -34,6 +34,9 @@ #include "relay-client.h" #include "relay-config.h" #include "relay-buffer.h" +#include "relay-protocol-irc.h" +#include "relay-protocol-weechat.h" +#include "relay-server.h" char *relay_client_status_string[] = /* strings for status */ @@ -95,110 +98,6 @@ relay_client_search_by_number (int number) } /* - * relay_client_sendf: send formatted data to client - */ - -int -relay_client_sendf (struct t_relay_client *client, const char *format, ...) -{ - va_list args; - static char buffer[4096]; - char str_length[8]; - int length, num_sent; - - if (!client) - return 0; - - va_start (args, format); - vsnprintf (buffer + 7, sizeof (buffer) - 7 - 1, format, args); - va_end (args); - - length = strlen (buffer + 7); - snprintf (str_length, sizeof (str_length), "%07d", length); - memcpy (buffer, str_length, 7); - - num_sent = send (client->sock, buffer, length + 7, 0); - - client->bytes_sent += length + 7; - - if (num_sent < 0) - { - weechat_printf (NULL, - _("%s%s: error sending data to client %s"), - weechat_prefix ("error"), RELAY_PLUGIN_NAME, - strerror (errno)); - } - - return num_sent; -} - -/* - * relay_client_send_infolist: send infolist to client - */ - -void -relay_client_send_infolist (struct t_relay_client *client, - const char *name, - struct t_infolist *infolist) -{ - const char *fields; - char **argv; - int i, argc, size; - - relay_client_sendf (client, "name %s", name); - - while (weechat_infolist_next (infolist)) - { - fields = weechat_infolist_fields (infolist); - if (fields) - { - argv = weechat_string_split (fields, ",", 0, 0, &argc); - if (argv && (argc > 0)) - { - for (i = 0; i < argc; i++) - { - switch (argv[i][0]) - { - case 'i': - relay_client_sendf (client, "%s %c %d", - argv[i] + 2, argv[i][0], - weechat_infolist_integer (infolist, - argv[i] + 2)); - break; - case 's': - relay_client_sendf (client, "%s %c %s", - argv[i] + 2, argv[i][0], - weechat_infolist_string (infolist, - argv[i] + 2)); - break; - case 'p': - relay_client_sendf (client, "%s %c %lx", - argv[i] + 2, argv[i][0], - (long unsigned int)weechat_infolist_pointer (infolist, - argv[i] + 2)); - break; - case 'b': - relay_client_sendf (client, "%s %c %lx", - argv[i] + 2, argv[i][0], - (long unsigned int)weechat_infolist_buffer (infolist, - argv[i] + 2, - &size)); - break; - case 't': - relay_client_sendf (client, "%s %c %ld", - argv[i] + 2, argv[i][0], - weechat_infolist_time (infolist, argv[i] + 2)); - break; - } - } - } - if (argv) - weechat_string_free_split (argv); - } - } -} - -/* * relay_client_recv_cb: read data from a client */ @@ -207,7 +106,6 @@ relay_client_recv_cb (void *arg_client, int fd) { struct t_relay_client *client; static char buffer[4096 + 2]; - struct t_infolist *infolist; int num_read; /* make C compiler happy */ @@ -220,25 +118,16 @@ relay_client_recv_cb (void *arg_client, int fd) { client->bytes_recv += num_read; buffer[num_read] = '\0'; - if (buffer[num_read - 1] == '\n') - buffer[--num_read] = '\0'; - if (buffer[num_read - 1] == '\r') - buffer[--num_read] = '\0'; - if (weechat_relay_plugin->debug) - { - weechat_printf (NULL, "%s: data received from %s: \"%s\"", - RELAY_PLUGIN_NAME, client->address, buffer); - } - if (weechat_strcasecmp (buffer, "quit") == 0) - relay_client_set_status (client, RELAY_STATUS_DISCONNECTED); - else + switch (client->protocol) { - infolist = weechat_infolist_get (buffer, NULL, NULL); - if (infolist) - { - relay_client_send_infolist (client, buffer, infolist); - weechat_infolist_free (infolist); - } + case RELAY_PROTOCOL_WEECHAT: + relay_protocol_weechat_recv (client, buffer); + break; + case RELAY_PROTOCOL_IRC: + relay_protocol_irc_recv (client, buffer); + break; + case RELAY_NUM_PROTOCOLS: + break; } relay_buffer_refresh (NULL); } @@ -255,7 +144,7 @@ relay_client_recv_cb (void *arg_client, int fd) */ struct t_relay_client * -relay_client_new (int sock, char *address) +relay_client_new (int sock, char *address, struct t_relay_server *server) { struct t_relay_client *new_client; @@ -265,13 +154,30 @@ relay_client_new (int sock, char *address) new_client->sock = sock; new_client->address = strdup ((address) ? address : "?"); new_client->status = RELAY_STATUS_CONNECTED; + new_client->protocol = server->protocol; + new_client->protocol_string = strdup (server->protocol_string); + new_client->listen_start_time = server->start_time; new_client->start_time = time (NULL); + new_client->end_time = 0; new_client->hook_fd = NULL; new_client->hook_timer = NULL; new_client->last_activity = new_client->start_time; new_client->bytes_recv = 0; new_client->bytes_sent = 0; + new_client->protocol_data = NULL; + switch (new_client->protocol) + { + case RELAY_PROTOCOL_WEECHAT: + relay_protocol_weechat_alloc (new_client); + break; + case RELAY_PROTOCOL_IRC: + relay_protocol_irc_alloc (new_client); + break; + case RELAY_NUM_PROTOCOLS: + break; + } + new_client->prev_client = NULL; new_client->next_client = relay_clients; if (relay_clients) @@ -281,10 +187,15 @@ relay_client_new (int sock, char *address) relay_clients = new_client; weechat_printf (NULL, - _("%s: new client @ %s"), + _("%s: new client from %s%s%s on port %d (relaying: %s.%s)"), RELAY_PLUGIN_NAME, - new_client->address); - + RELAY_COLOR_CHAT_HOST, + new_client->address, + RELAY_COLOR_CHAT, + server->port, + relay_protocol_string[new_client->protocol], + new_client->protocol_string); + new_client->hook_fd = weechat_hook_fd (new_client->sock, 1, 0, 0, &relay_client_recv_cb, @@ -322,6 +233,8 @@ relay_client_set_status (struct t_relay_client *client, if (RELAY_CLIENT_HAS_ENDED(client->status)) { + client->end_time = time (NULL); + if (client->hook_fd) { weechat_unhook (client->hook_fd); @@ -336,14 +249,24 @@ relay_client_set_status (struct t_relay_client *client, { case RELAY_STATUS_AUTH_FAILED: weechat_printf (NULL, - _("%s%s: authentication failed with client @ %s"), - weechat_prefix ("error"), RELAY_PLUGIN_NAME, - client->address); + _("%s%s: authentication failed with client %s%s%s (%s.%s)"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_HOST, + client->address, + RELAY_COLOR_CHAT, + relay_protocol_string[client->protocol], + client->protocol_string); break; case RELAY_STATUS_DISCONNECTED: weechat_printf (NULL, - _("%s: disconnected from client @ %s"), - RELAY_PLUGIN_NAME, client->address); + _("%s: disconnected from client %s%s%s (%s.%s)"), + RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_HOST, + client->address, + RELAY_COLOR_CHAT, + relay_protocol_string[client->protocol], + client->protocol_string); break; default: break; @@ -387,10 +310,26 @@ relay_client_free (struct t_relay_client *client) /* free data */ if (client->address) free (client->address); + if (client->protocol_string) + free (client->protocol_string); if (client->hook_fd) weechat_unhook (client->hook_fd); if (client->hook_timer) weechat_unhook (client->hook_timer); + if (client->protocol_data) + { + switch (client->protocol) + { + case RELAY_PROTOCOL_WEECHAT: + relay_protocol_weechat_free (client); + break; + case RELAY_PROTOCOL_IRC: + relay_protocol_irc_free (client); + break; + case RELAY_NUM_PROTOCOLS: + break; + } + } free (client); @@ -405,6 +344,19 @@ relay_client_free (struct t_relay_client *client) } /* + * relay_client_free_all: remove all clients + */ + +void +relay_client_free_all () +{ + while (relay_clients) + { + relay_client_free (relay_clients); + } +} + +/* * relay_client_disconnect: disconnect one client */ @@ -497,12 +449,30 @@ relay_client_print_log () weechat_log_printf (" status. . . . . . . : %d (%s)", ptr_client->status, relay_client_status_string[ptr_client->status]); + 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 (" listen_start_time . : %ld", ptr_client->listen_start_time); weechat_log_printf (" start_time. . . . . : %ld", ptr_client->start_time); + weechat_log_printf (" end_time. . . . . . : %ld", ptr_client->end_time); weechat_log_printf (" hook_fd . . . . . . : 0x%lx", ptr_client->hook_fd); weechat_log_printf (" hook_timer. . . . . : 0x%lx", ptr_client->hook_timer); weechat_log_printf (" last_activity . . . : %ld", ptr_client->last_activity); weechat_log_printf (" bytes_recv. . . . . : %lu", ptr_client->bytes_recv); weechat_log_printf (" bytes_sent. . . . . : %lu", ptr_client->bytes_sent); + weechat_log_printf (" protocol_data . . . : 0x%lx", ptr_client->protocol_data); + switch (ptr_client->protocol) + { + case RELAY_PROTOCOL_WEECHAT: + relay_protocol_weechat_print_log (ptr_client); + break; + case RELAY_PROTOCOL_IRC: + relay_protocol_irc_print_log (ptr_client); + break; + case RELAY_NUM_PROTOCOLS: + break; + } weechat_log_printf (" prev_client . . . . : 0x%lx", ptr_client->prev_client); weechat_log_printf (" next_client . . . . : 0x%lx", ptr_client->next_client); } diff --git a/src/plugins/relay/relay-client.h b/src/plugins/relay/relay-client.h index 94e03b0ae..6cdcc5428 100644 --- a/src/plugins/relay/relay-client.h +++ b/src/plugins/relay/relay-client.h @@ -20,6 +20,8 @@ #ifndef __WEECHAT_RELAY_CLIENT_H #define __WEECHAT_RELAY_CLIENT_H 1 +struct t_relay_server; + /* relay status */ enum t_relay_status @@ -45,12 +47,18 @@ struct t_relay_client int sock; /* socket for connection */ char *address; /* string with IP address */ enum t_relay_status status; /* status (connecting, active,..) */ + enum t_relay_protocol protocol; /* protocol (irc,..) */ + char *protocol_string; /* string used for protocol */ + /* example: server for irc protocol */ + time_t listen_start_time; /* when listening started */ time_t start_time; /* time of client connection */ + time_t end_time; /* time of client disconnection */ struct t_hook *hook_fd; /* hook for socket or child pipe */ struct t_hook *hook_timer; /* timeout for recever accept */ time_t last_activity; /* time of last byte received/sent */ unsigned long bytes_recv; /* bytes received from client */ unsigned long bytes_sent; /* bytes sent to client */ + void *protocol_data; /* data depending on protocol used */ struct t_relay_client *prev_client;/* link to previous client */ struct t_relay_client *next_client;/* link to next client */ }; @@ -62,10 +70,12 @@ extern int relay_client_count; extern int relay_client_valid (struct t_relay_client *client); extern struct t_relay_client *relay_client_search_by_number (int number); -extern struct t_relay_client *relay_client_new (int sock, char *address); +extern struct t_relay_client *relay_client_new (int sock, char *address, + struct t_relay_server *server); extern void relay_client_set_status (struct t_relay_client *client, enum t_relay_status status); extern void relay_client_free (struct t_relay_client *client); +extern void relay_client_free_all (); extern void relay_client_disconnect (struct t_relay_client *client); extern void relay_client_disconnect_all (); extern int relay_client_add_to_infolist (struct t_infolist *infolist, diff --git a/src/plugins/relay/relay-command.c b/src/plugins/relay/relay-command.c index 1bdec5bcf..d2fd750c6 100644 --- a/src/plugins/relay/relay-command.c +++ b/src/plugins/relay/relay-command.c @@ -28,6 +28,7 @@ #include "relay-buffer.h" #include "relay-client.h" #include "relay-config.h" +#include "relay-server.h" /* @@ -61,10 +62,15 @@ relay_command_client_list (int full) if (full) { weechat_printf (NULL, - _("%3d. %s, started on: %s, last activity: %s, " - "bytes: %lu recv, %lu sent"), + _("%3d. %s%s%s (%s%s%s), started on: %s, last " + "activity: %s, bytes: %lu recv, %lu sent"), i, + RELAY_COLOR_CHAT_HOST, ptr_client->address, + RELAY_COLOR_CHAT, + RELAY_COLOR_CHAT_BUFFER, + relay_client_status_string[ptr_client->status], + RELAY_COLOR_CHAT, date_start, date_activity, ptr_client->bytes_recv, @@ -72,10 +78,16 @@ relay_command_client_list (int full) } else { - weechat_printf (NULL, - _("%3d. %s, started on: %s"), - i, - ptr_client->address); + if (!RELAY_CLIENT_HAS_ENDED(ptr_client->status)) + { + weechat_printf (NULL, + _("%3d. %s%s%s, started on: %s"), + i, + RELAY_COLOR_CHAT_HOST, + ptr_client->address, + RELAY_COLOR_CHAT, + date_start); + } } i++; } @@ -85,6 +97,49 @@ relay_command_client_list (int full) } /* + * relay_command_server_list: list servers (list of port on which we are + * listening) + */ + +void +relay_command_server_list () +{ + struct t_relay_server *ptr_server; + int i; + char date_start[128]; + struct tm *date_tmp; + + if (relay_servers) + { + weechat_printf (NULL, ""); + weechat_printf (NULL, _("Listening on ports:")); + i = 1; + for (ptr_server = relay_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + date_tmp = localtime (&(ptr_server->start_time)); + strftime (date_start, sizeof (date_start), + "%a, %d %b %Y %H:%M:%S", date_tmp); + + weechat_printf (NULL, + _("%3d. port %s%d%s, relay: %s%s.%s%s, started on: %s"), + i, + RELAY_COLOR_CHAT_BUFFER, + ptr_server->port, + RELAY_COLOR_CHAT, + RELAY_COLOR_CHAT_BUFFER, + relay_protocol_string[ptr_server->protocol], + ptr_server->protocol_string, + RELAY_COLOR_CHAT, + date_start); + i++; + } + } + else + weechat_printf (NULL, _("No server for relay")); +} + +/* * relay_command_relay: command /relay */ @@ -92,21 +147,80 @@ int relay_command_relay (void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) { + struct t_relay_server *ptr_server; + /* make C compiler happy */ (void) data; (void) buffer; (void) argv_eol; - if ((argc > 1) && (weechat_strcasecmp (argv[1], "list") == 0)) + if (argc > 1) { - relay_command_client_list (0); - return WEECHAT_RC_OK; - } - - if ((argc > 1) && (weechat_strcasecmp (argv[1], "listfull") == 0)) - { - relay_command_client_list (1); - return WEECHAT_RC_OK; + if (weechat_strcasecmp (argv[1], "list") == 0) + { + relay_command_client_list (0); + return WEECHAT_RC_OK; + } + + if (weechat_strcasecmp (argv[1], "listfull") == 0) + { + relay_command_client_list (1); + return WEECHAT_RC_OK; + } + + if (weechat_strcasecmp (argv[1], "listrelay") == 0) + { + relay_command_server_list (); + return WEECHAT_RC_OK; + } + if (weechat_strcasecmp (argv[1], "add") == 0) + { + if (argc >= 4) + { + relay_config_create_option_port (NULL, + relay_config_file, + relay_config_section_port, + argv[2], + argv_eol[3]); + } + else + { + weechat_printf (NULL, + _("%s%s: missing arguments for \"%s\" " + "command"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME, + "relay add"); + } + return WEECHAT_RC_OK; + } + if (weechat_strcasecmp (argv[1], "del") == 0) + { + if (argc >= 3) + { + ptr_server = relay_server_search (argv_eol[2]); + if (ptr_server) + { + relay_server_free (ptr_server); + } + else + { + weechat_printf (NULL, + _("%s%s: relay \"%s\" not found"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, + argv_eol[2]); + } + } + else + { + weechat_printf (NULL, + _("%s%s: missing arguments for \"%s\" " + "command"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME, + "relay add"); + } + return WEECHAT_RC_OK; + } } if (!relay_buffer) @@ -145,10 +259,24 @@ relay_command_init () { weechat_hook_command ("relay", N_("relay control"), - "[list | listfull]", - N_(" list: list relay clients\n" - "listfull: list relay clients (verbose)\n\n" + N_("[list | listfull | add protocol.name port | " + "del protocol.name]"), + N_(" list: list relay clients (only active " + "relays)\n" + " listfull: list relay clients (verbose, all " + "relays)\n" + " listrelay: list relays (name and port)\n" + " add: add relay for a protocol + name\n" + " del: remove relay for a protocol + name\n" + "protocol.name: protocol and name to relay\n" + " for example: irc.freenode\n" + " port: port used for relay\n\n" "Without argument, this command opens buffer " "with list of relay clients."), - "list|listfull", &relay_command_relay, NULL); + "list %(relay_relays)" + " || listfull %(relay_relays)" + " || listrelay" + " || add %(relay_protocol_name) %(relay_free_port)" + " || del %(relay_relays)", + &relay_command_relay, NULL); } diff --git a/src/plugins/relay/relay-completion.c b/src/plugins/relay/relay-completion.c new file mode 100644 index 000000000..38c73524b --- /dev/null +++ b/src/plugins/relay/relay-completion.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2003-2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program 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. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* relay-completion.c: completion for relay command */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "relay.h" +#include "relay-server.h" + + +/* + * relay_completion_protocol_name_cb: callback for completion with protocol and + * name + */ + +int +relay_completion_protocol_name_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + struct t_infolist *infolist; + char protocol_name[256]; + + /* make C compiler happy */ + (void) data; + (void) buffer; + (void) completion_item; + + infolist = weechat_infolist_get("irc_server", NULL, NULL); + if (infolist) + { + while (weechat_infolist_next (infolist)) + { + snprintf (protocol_name, sizeof (protocol_name), "irc.%s", + weechat_infolist_string (infolist, "name")); + weechat_hook_completion_list_add (completion, protocol_name, + 0, WEECHAT_LIST_POS_SORT); + } + weechat_infolist_free (infolist); + } + + weechat_hook_completion_list_add (completion, "weechat", + 0, WEECHAT_LIST_POS_SORT); + + return WEECHAT_RC_OK; +} + +/* + * relay_completion_relays_cb: callback for completion with protocol and name + * of current relays + */ + +int +relay_completion_relays_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + struct t_relay_server *ptr_server; + char protocol_name[256]; + + /* make C compiler happy */ + (void) data; + (void) buffer; + (void) completion_item; + + for (ptr_server = relay_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + snprintf (protocol_name, sizeof (protocol_name), "%s.%s", + relay_protocol_string[ptr_server->protocol], + ptr_server->protocol_string); + weechat_hook_completion_list_add (completion, protocol_name, + 0, WEECHAT_LIST_POS_SORT); + } + + return WEECHAT_RC_OK; +} + +/* + * relay_completion_free_port_cb: callback for completion with a free port + */ + +int +relay_completion_free_port_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + struct t_relay_server *ptr_server; + char str_port[16]; + int port_max; + + /* make C compiler happy */ + (void) data; + (void) buffer; + (void) completion_item; + + /* default port is 8000 */ + port_max = 8000 - 1; + + if (ptr_server) + { + port_max = -1; + for (ptr_server = relay_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (ptr_server->port > port_max) + port_max = ptr_server->port; + } + if (port_max < 0) + port_max = 8000 - 1; + } + + snprintf (str_port, sizeof (str_port), "%d", port_max + 1); + weechat_hook_completion_list_add (completion, str_port, + 0, WEECHAT_LIST_POS_SORT); + + return WEECHAT_RC_OK; +} + +/* + * relay_completion_init: init completion for relay plugin + */ + +void +relay_completion_init () +{ + weechat_hook_completion ("relay_protocol_name", + N_("all possible protocol.name for relay plugin"), + &relay_completion_protocol_name_cb, NULL); + weechat_hook_completion ("relay_relays", + N_("protocol.name of current relays for relay " + "plugin"), + &relay_completion_relays_cb, NULL); + weechat_hook_completion ("relay_free_port", + N_("first free port for relay plugin"), + &relay_completion_free_port_cb, NULL); +} diff --git a/src/plugins/relay/relay-network.h b/src/plugins/relay/relay-completion.h index 1714256e0..c70e2f66c 100644 --- a/src/plugins/relay/relay-network.h +++ b/src/plugins/relay/relay-completion.h @@ -17,12 +17,9 @@ */ -#ifndef __WEECHAT_RELAY_NETWORK_H -#define __WEECHAT_RELAY_NETWORK_H 1 +#ifndef __WEECHAT_RELAY_COMPLETION_H +#define __WEECHAT_RELAY_COMPLETION_H 1 -extern int relay_network_sock; +extern void relay_completion_init (); -extern int relay_network_init (); -extern void relay_network_end (); - -#endif /* relay-network.h */ +#endif /* relay-completion.h */ diff --git a/src/plugins/relay/relay-config.c b/src/plugins/relay/relay-config.c index ec1db436b..80c7e1193 100644 --- a/src/plugins/relay/relay-config.c +++ b/src/plugins/relay/relay-config.c @@ -27,10 +27,11 @@ #include "relay-config.h" #include "relay-client.h" #include "relay-buffer.h" -#include "relay-network.h" +#include "relay-server.h" struct t_config_file *relay_config_file = NULL; +struct t_config_section *relay_config_section_port = NULL; /* relay config, look section */ @@ -45,8 +46,7 @@ struct t_config_option *relay_config_color_status[RELAY_NUM_STATUS]; /* relay config, network section */ -struct t_config_option *relay_config_network_enabled; -struct t_config_option *relay_config_network_listen_port_range; +struct t_config_option *relay_config_network_max_clients; /* @@ -66,23 +66,149 @@ relay_config_refresh_cb (void *data, struct t_config_option *option) } /* - * relay_config_change_network_enabled_cb: callback called when user - * enables/disables relay + * relay_config_change_port_cb: callback called when relay port option is + * modified */ -void -relay_config_change_network_enabled_cb (void *data, - struct t_config_option *option) +int +relay_config_check_port_cb (void *data, struct t_config_option *option, + const char *value) { + char *error; + long port; + struct t_relay_server *ptr_server; + /* make C compiler happy */ (void) data; (void) option; - if ((weechat_config_boolean(relay_config_network_enabled) && relay_network_sock < 0) - || (!weechat_config_boolean(relay_config_network_enabled) && relay_network_sock >= 0)) + error = NULL; + port = strtol (value, &error, 10); + ptr_server = relay_server_search_port ((int)port); + if (ptr_server) + { + weechat_printf (NULL, _("%s%s: error: port \"%d\" is already used"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, (int)port); + return 0; + } + + return 1; +} + +/* + * relay_config_change_port_cb: callback called when relay port option is + * modified + */ + +void +relay_config_change_port_cb (void *data, struct t_config_option *option) +{ + struct t_relay_server *ptr_server; + + /* make C compiler happy */ + (void) data; + + ptr_server = relay_server_search (weechat_config_option_get_pointer (option, "name")); + if (ptr_server) + { + relay_server_update_port (ptr_server, + *((int *)weechat_config_option_get_pointer (option, "value"))); + } +} + +/* + * relay_config_delete_port_cb: callback called when relay port option is + * deleted + */ + +void +relay_config_delete_port_cb (void *data, struct t_config_option *option) +{ + struct t_relay_server *ptr_server; + + /* make C compiler happy */ + (void) data; + + ptr_server = relay_server_search (weechat_config_option_get_pointer (option, "name")); + if (ptr_server) + relay_server_free (ptr_server); +} + +/* + * relay_config_create_option_port: create a relay for a port + */ + +int +relay_config_create_option_port (void *data, + struct t_config_file *config_file, + struct t_config_section *section, + const char *option_name, + const char *value) +{ + int rc, protocol_number; + char *error, *protocol, *protocol_string; + long port; + struct t_relay_server *ptr_server; + + /* make C compiler happy */ + (void) data; + + rc = WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + + relay_server_get_protocol_string (option_name, + &protocol, &protocol_string); + + protocol_number = -1; + port = -1; + + if (protocol && protocol_string) + protocol_number = relay_protocol_search (protocol); + + if (protocol_number < 0) + { + weechat_printf (NULL, _("%s%s: error: unknown protocol \"%s\""), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, protocol); + rc = WEECHAT_CONFIG_OPTION_SET_ERROR; + } + + if (rc != WEECHAT_CONFIG_OPTION_SET_ERROR) + { + error = NULL; + port = strtol (value, &error, 10); + ptr_server = relay_server_search_port ((int)port); + if (ptr_server) + { + weechat_printf (NULL, _("%s%s: error: port \"%d\" is already used"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, (int)port); + rc = WEECHAT_CONFIG_OPTION_SET_ERROR; + } + } + + if (rc != WEECHAT_CONFIG_OPTION_SET_ERROR) { - relay_network_init (); + /* create config option */ + weechat_config_new_option ( + config_file, section, + option_name, "integer", NULL, + NULL, 0, 65535, "", value, 0, + &relay_config_check_port_cb, NULL, + &relay_config_change_port_cb, NULL, + &relay_config_delete_port_cb, NULL); + + relay_server_new (protocol_number, protocol_string, port); + + rc = WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; } + + if (protocol) + free (protocol); + if (protocol_string) + free (protocol_string); + + return rc; } /* @@ -201,20 +327,27 @@ relay_config_init () return 0; } - relay_config_network_enabled = weechat_config_new_option ( - relay_config_file, ptr_section, - "enabled", "boolean", - N_("enable relay"), - NULL, 0, 0, "off", NULL, 0, NULL, NULL, - &relay_config_change_network_enabled_cb, NULL, NULL, NULL); - relay_config_network_listen_port_range = weechat_config_new_option ( + relay_config_network_max_clients = weechat_config_new_option ( relay_config_file, ptr_section, - "listen_port_range", "string", - N_("port number (or range of ports) that relay plugin listens on " - "(syntax: a single port, ie. 5000 or a port " - "range, ie. 5000-5015, it's recommended to use ports greater than " - "1024, because only root can use ports below 1024)"), - NULL, 0, 0, "22373-22400", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + "max_clients", "integer", + N_("maximum number of clients connecting to a port"), + NULL, 1, 1024, "5", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + + ptr_section = weechat_config_new_section (relay_config_file, "port", + 1, 1, + NULL, NULL, + NULL, NULL, + NULL, NULL, + &relay_config_create_option_port, NULL, + NULL, NULL); + if (!ptr_section) + { + weechat_config_free (relay_config_file); + return 0; + } + + relay_config_section_port = ptr_section; return 1; } diff --git a/src/plugins/relay/relay-config.h b/src/plugins/relay/relay-config.h index 6671127a4..278e82312 100644 --- a/src/plugins/relay/relay-config.h +++ b/src/plugins/relay/relay-config.h @@ -22,7 +22,8 @@ #define RELAY_CONFIG_NAME "relay" -extern struct t_config_file *relay_config; +extern struct t_config_file *relay_config_file; +extern struct t_config_section *relay_config_section_port; extern struct t_config_option *relay_config_look_auto_open_buffer; @@ -31,9 +32,13 @@ extern struct t_config_option *relay_config_color_text_bg; extern struct t_config_option *relay_config_color_text_selected; extern struct t_config_option *relay_config_color_status[]; -extern struct t_config_option *relay_config_network_enabled; -extern struct t_config_option *relay_config_network_listen_port_range; +extern struct t_config_option *relay_config_network_max_clients; +extern int relay_config_create_option_port (void *data, + struct t_config_file *config_file, + struct t_config_section *section, + const char *option_name, + const char *value); extern int relay_config_init (); extern int relay_config_read (); extern int relay_config_write (); diff --git a/src/plugins/relay/relay-network.c b/src/plugins/relay/relay-network.c deleted file mode 100644 index 60ceddce0..000000000 --- a/src/plugins/relay/relay-network.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2003-2009 by FlashCode <flashcode@flashtux.org> - * See README for License detail, AUTHORS for developers list. - * - * This program 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. - * - * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/* relay-network.c: network functions for relay plugin */ - - -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include "../weechat-plugin.h" -#include "relay.h" -#include "relay-buffer.h" -#include "relay-client.h" -#include "relay-config.h" - - -int relay_network_sock = -1; /* socket used for listening and */ - /* waiting for clients */ -struct t_hook *relay_network_hook_fd = NULL; -int relay_network_listen_port = -1; /* listening port */ - - -/* - * relay_network_close_socket: close socket - */ - -void -relay_network_close_socket () -{ - if (relay_network_hook_fd) - { - weechat_unhook (relay_network_hook_fd); - relay_network_hook_fd = NULL; - } - if (relay_network_sock >= 0) - { - close (relay_network_sock); - relay_network_sock = -1; - weechat_printf (NULL, - _("%s: socket closed"), - RELAY_PLUGIN_NAME); - } -} - -/* - * relay_network_sock_cb: read data from a client which is connecting on socket - */ - -int -relay_network_sock_cb (void *data, int fd) -{ - struct sockaddr_in client_addr; - unsigned int client_length; - int client_fd; - char ipv4_address[INET_ADDRSTRLEN + 1], *ptr_address; - - /* make C compiler happy */ - (void) data; - (void) fd; - - client_length = sizeof (client_addr); - memset (&client_addr, 0, client_length); - - client_fd = accept (relay_network_sock, (struct sockaddr *) &client_addr, - &client_length); - if (client_fd < 0) - { - weechat_printf (NULL, - _("%s%s: cannot accept client"), - weechat_prefix ("error"), RELAY_PLUGIN_NAME); - return WEECHAT_RC_OK; - } - - ptr_address = NULL; - if (inet_ntop (AF_INET, - &(client_addr.sin_addr), - ipv4_address, - INET_ADDRSTRLEN)) - { - ptr_address = ipv4_address; - } - - relay_client_new (client_fd, ptr_address); - - return WEECHAT_RC_OK; -} - -/* - * relay_network_init: init socket and listen on port - * return 1 if ok, 0 if error - */ - -int -relay_network_init () -{ - int set, args, port, port_start, port_end; - struct sockaddr_in server_addr; - const char *port_range; - - relay_network_close_socket (); - - if (!weechat_config_boolean (relay_config_network_enabled)) - return 1; - - port_range = weechat_config_string (relay_config_network_listen_port_range); - if (!port_range || !port_range[0]) - { - weechat_printf (NULL, - _("%s%s: option \"listen_port_range\" is not defined"), - weechat_prefix ("error"), RELAY_PLUGIN_NAME); - return 0; - } - - relay_network_sock = socket (AF_INET, SOCK_STREAM, 0); - if (relay_network_sock < 0) - { - weechat_printf (NULL, - _("%s%s: cannot create socket"), - weechat_prefix ("error"), RELAY_PLUGIN_NAME); - return 0; - } - - set = 1; - if (setsockopt (relay_network_sock, SOL_SOCKET, SO_REUSEADDR, - (void *) &set, sizeof (set)) < 0) - { - weechat_printf (NULL, - _("%s%s: cannot set socket option " - "\"SO_REUSEADDR\""), - weechat_prefix ("error"), RELAY_PLUGIN_NAME); - close (relay_network_sock); - relay_network_sock = -1; - return 0; - } - - set = 1; - if (setsockopt (relay_network_sock, SOL_SOCKET, SO_KEEPALIVE, - (void *) &set, sizeof (set)) < 0) - { - weechat_printf (NULL, - _("%s%s: cannot set socket option " - "\"SO_KEEPALIVE\""), - weechat_prefix ("error"), RELAY_PLUGIN_NAME); - close (relay_network_sock); - relay_network_sock = -1; - return 0; - } - - memset(&server_addr, 0, sizeof(struct sockaddr_in)); - server_addr.sin_family = AF_INET; - server_addr.sin_addr.s_addr = INADDR_ANY; - - port = -1; - - /* find a free port in the specified range */ - args = sscanf (weechat_config_string (relay_config_network_listen_port_range), - "%d-%d", &port_start, &port_end); - if (args > 0) - { - port = port_start; - if (args == 1) - port_end = port_start; - - /* loop through the entire allowed port range */ - while (port <= port_end) - { - /* attempt to bind to the free port */ - server_addr.sin_port = htons (port); - if (bind (relay_network_sock, (struct sockaddr *) &server_addr, - sizeof (server_addr)) == 0) - break; - port++; - } - - if (port > port_end) - port = -1; - } - - if (port < 0) - { - weechat_printf (NULL, - _("%s%s: cannot find available port for listening"), - weechat_prefix ("error"), RELAY_PLUGIN_NAME); - close (relay_network_sock); - relay_network_sock = -1; - return 0; - } - - relay_network_listen_port = port; - - listen (relay_network_sock, 5); - - weechat_printf (NULL, - _("%s: listening on port %d"), - RELAY_PLUGIN_NAME, relay_network_listen_port); - - relay_network_hook_fd = weechat_hook_fd (relay_network_sock, - 1, 0, 0, - &relay_network_sock_cb, - NULL); - - return 1; -} - -/* - * relay_network_end: close main socket - */ - -void -relay_network_end () -{ - relay_network_close_socket (); -} diff --git a/src/plugins/relay/relay-protocol-irc.c b/src/plugins/relay/relay-protocol-irc.c new file mode 100644 index 000000000..ab9a45073 --- /dev/null +++ b/src/plugins/relay/relay-protocol-irc.c @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2003-2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program 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. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* relay-protocol-irc.c: IRC protocol for client + (relay acting as an IRC proxy/bouncer) */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> + +#include "../weechat-plugin.h" +#include "relay.h" +#include "relay-protocol-irc.h" +#include "relay-client.h" + + +/* + * relay_protocol_irc_search_buffer: search IRC buffer with server and channel + * name + */ + +struct t_gui_buffer * +relay_protocol_irc_search_buffer (const char *server, const char *channel) +{ + char string[256]; + long unsigned int value; + const char *str_ptr_buffer; + + snprintf (string, sizeof (string), "%s,%s", server, channel); + str_ptr_buffer = weechat_info_get ("irc_buffer", string); + if (str_ptr_buffer && str_ptr_buffer[0]) + { + sscanf (str_ptr_buffer, "%lx", &value); + return (struct t_gui_buffer *)value; + } + + return NULL; +} + +/* + * relay_protocol_irc_sendf: send formatted data to client + */ + +int +relay_protocol_irc_sendf (struct t_relay_client *client, const char *format, ...) +{ + va_list args; + static char buffer[4096]; + int length, num_sent; + + if (!client) + return 0; + + va_start (args, format); + vsnprintf (buffer, sizeof (buffer) - 3, format, args); + va_end (args); + + if (weechat_relay_plugin->debug) + { + weechat_printf (NULL, "relay: send: %s", buffer); + } + + length = strlen (buffer); + + buffer[length] = '\r'; + buffer[length + 1] = '\n'; + buffer[length + 2] = '\0'; + length += 2; + + num_sent = send (client->sock, buffer, length, 0); + + if (num_sent >= 0) + client->bytes_sent += num_sent; + else + { + weechat_printf (NULL, + _("%s%s: error sending data to client %s"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME, + strerror (errno)); + } + + return num_sent; +} + +/* + * relay_protocol_irc_signal_irc_in2_cb: callback for "irc_in2" IRC signal + */ + +int +relay_protocol_irc_signal_irc_in2_cb (void *data, const char *signal, + const char *type_data, void *signal_data) +{ + struct t_relay_client *client; + const char *ptr_msg; + char *host, *pos, *pos_end_nick; + + (void) signal; + (void) type_data; + + client = (struct t_relay_client *)data; + ptr_msg = (const char *)signal_data; + + if (weechat_relay_plugin->debug) + { + weechat_printf (NULL, "relay: irc_in2: client: %s, data: %s", + client->protocol_string, + ptr_msg); + } + + if (ptr_msg[0] == ':') + { + pos = strchr (ptr_msg, ' '); + if (pos) + { + host = weechat_strndup (ptr_msg + 1, pos - ptr_msg); + if (host) + { + pos_end_nick = strchr (host, '!'); + if (pos_end_nick) + pos_end_nick[0] = '\0'; + else + host[0] = '\0'; + + pos++; + while (pos[0] == ' ') + { + pos++; + } + + relay_protocol_irc_sendf (client, ":%s%s%s %s", + (host[0]) ? host : "", + (host[0]) ? "!" : "", + RELAY_IRC_DATA(client, address), + pos); + free (host); + } + return WEECHAT_RC_OK; + } + } + + relay_protocol_irc_sendf (client, "%s", ptr_msg); + + return WEECHAT_RC_OK; +} + +/* + * relay_protocol_irc_signal_irc_out_cb: callback for "irc_out" IRC signal + */ + +int +relay_protocol_irc_signal_irc_out_cb (void *data, const char *signal, + const char *type_data, void *signal_data) +{ + struct t_relay_client *client; + + (void) signal; + (void) type_data; + + client = (struct t_relay_client *)data; + + if (weechat_relay_plugin->debug) + { + weechat_printf (NULL, "relay: irc_out: client: %s, data: %s", + client->protocol_string, + (char *)signal_data); + } + + return WEECHAT_RC_OK; +} + +/* + * relay_protocol_irc_send_join: send join for a channel to client + */ + +void +relay_protocol_irc_send_join (struct t_relay_client *client, + const char *channel) +{ + char *infolist_name, *nicks; + const char *nick; + int length, length_nicks; + struct t_infolist *infolist_nicks; + + length = strlen (client->protocol_string) + 1 + strlen (channel) + 1; + infolist_name = malloc (length); + if (infolist_name) + { + relay_protocol_irc_sendf (client, + ":%s!%s@proxy JOIN %s", + RELAY_IRC_DATA(client, nick), + "weechat", + channel); + snprintf (infolist_name, length, "%s,%s", + client->protocol_string, + channel); + infolist_nicks = weechat_infolist_get ("irc_nick", NULL, infolist_name); + if (infolist_nicks) + { + length_nicks = 0; + nicks = NULL; + while (weechat_infolist_next (infolist_nicks)) + { + nick = weechat_infolist_string (infolist_nicks, "name"); + if (nick && nick[0]) + { + if (length_nicks == 0) + { + length_nicks = strlen (nick) + 1; + nicks = malloc (length_nicks); + strcpy (nicks, nick); + } + else + { + length_nicks += strlen (nick) + 1; + nicks = realloc (nicks, length_nicks); + strcat (nicks, " "); + strcat (nicks, nick); + } + } + } + if (nicks) + { + relay_protocol_irc_sendf (client, + ":%s 353 %s = %s :%s", + RELAY_IRC_DATA(client, address), + RELAY_IRC_DATA(client, nick), + channel, nicks); + free (nicks); + } + weechat_infolist_free (infolist_nicks); + } + relay_protocol_irc_sendf (client, + ":%s 366 %s %s :End of /NAMES list.", + RELAY_IRC_DATA(client, address), + RELAY_IRC_DATA(client, nick), + channel); + free (infolist_name); + } +} + +/* + * relay_protocol_irc_send_join_channels: send join for all channels of server + * to client + */ + +void +relay_protocol_irc_send_join_channels (struct t_relay_client *client) +{ + struct t_infolist *infolist_channels; + const char *channel; + + infolist_channels = weechat_infolist_get ("irc_channel", NULL, + client->protocol_string); + if (infolist_channels) + { + while (weechat_infolist_next (infolist_channels)) + { + channel = weechat_infolist_string (infolist_channels, "name"); + relay_protocol_irc_send_join (client, channel); + } + weechat_infolist_free (infolist_channels); + } +} + +/* + * relay_protocol_irc_recv_one_msg: read one message from client + */ + +void +relay_protocol_irc_recv_one_msg (struct t_relay_client *client, char *data) +{ + char *pos, str_time[128], **argv, **argv_eol, str_signal_name[128]; + char *command; + int argc, length; + const char *nick; + struct t_gui_buffer *ptr_buffer; + + pos = strchr (data, '\r'); + if (pos) + pos[0] = '\0'; + + if (weechat_relay_plugin->debug) + { + weechat_printf (NULL, "relay: recv from client: \"%s\"", data); + } + + argv = weechat_string_split (data, " ", 0, 0, &argc); + argv_eol = weechat_string_split (data, " ", 1, 0, &argc); + + if (!RELAY_IRC_DATA(client, connected)) + { + if (weechat_strncasecmp (data, "nick ", 5) == 0) + { + if (data[5]) + { + if (RELAY_IRC_DATA(client, nick)) + free (RELAY_IRC_DATA(client, nick)); + RELAY_IRC_DATA(client, nick) = strdup (data + 5); + } + } + if (weechat_strncasecmp (data, "user ", 5) == 0) + { + if (data[5]) + { + RELAY_IRC_DATA(client, user_received) = 1; + } + } + if (RELAY_IRC_DATA(client, nick) && RELAY_IRC_DATA(client, user_received)) + { + RELAY_IRC_DATA(client, connected) = 1; + + /* send nick to client if server nick is different of nick asked + by client with command NICK */ + nick = weechat_info_get ("irc_nick", client->protocol_string); + if (nick && (strcmp (nick, RELAY_IRC_DATA(client, nick)) != 0)) + { + relay_protocol_irc_sendf (client, + ":%s!proxy NICK :%s", + RELAY_IRC_DATA(client, nick), + nick); + free (RELAY_IRC_DATA(client, nick)); + RELAY_IRC_DATA(client, nick) = strdup (nick); + } + + relay_protocol_irc_sendf (client, + ":%s 001 %s :Welcome to the Internet " + "Relay Network %s!%s@proxy", + RELAY_IRC_DATA(client, address), + RELAY_IRC_DATA(client, nick), + RELAY_IRC_DATA(client, nick), + "weechat"); + relay_protocol_irc_sendf (client, + ":%s 002 %s :Your host is " + "weechat-relay-irc, running version %s", + RELAY_IRC_DATA(client, address), + RELAY_IRC_DATA(client, nick), + weechat_info_get("version", NULL)); + snprintf (str_time, sizeof (str_time), "%s", + ctime (&client->listen_start_time)); + if (str_time[0]) + str_time[strlen (str_time) - 1] = '\0'; + relay_protocol_irc_sendf (client, + ":%s 003 %s :This server was created " + "on %s", + RELAY_IRC_DATA(client, address), + RELAY_IRC_DATA(client, nick), + str_time); + relay_protocol_irc_sendf (client, + ":%s 004 %s %s %s oirw abiklmnopqstv", + RELAY_IRC_DATA(client, address), + RELAY_IRC_DATA(client, nick), + RELAY_IRC_DATA(client, address), + weechat_info_get("version", NULL)); + relay_protocol_irc_sendf (client, + ":%s 251 %s :There are %d users and 0 " + "invisible on 1 servers", + RELAY_IRC_DATA(client, address), + RELAY_IRC_DATA(client, nick), + relay_client_count); + relay_protocol_irc_sendf (client, + ":%s 255 %s :I have %d clients, 0 " + "services and 0 servers", + RELAY_IRC_DATA(client, address), + RELAY_IRC_DATA(client, nick), + relay_client_count); + relay_protocol_irc_sendf (client, + ":%s 422 %s :MOTD File is missing", + RELAY_IRC_DATA(client, address), + RELAY_IRC_DATA(client, nick)); + + /* hook signal "xxx,irc_in2_*" to catch IRC data received from + this server */ + snprintf (str_signal_name, sizeof (str_signal_name), + "%s,irc_in2_*", + client->protocol_string); + RELAY_IRC_DATA(client, hook_signal_irc_in2) = + weechat_hook_signal (str_signal_name, + &relay_protocol_irc_signal_irc_in2_cb, + client); + + /* hook signal "xxx,irc_out_*" to catch IRC data sent to + this server */ + snprintf (str_signal_name, sizeof (str_signal_name), + "%s,irc_out_*", + client->protocol_string); + RELAY_IRC_DATA(client, hook_signal_irc_out) = + weechat_hook_signal (str_signal_name, + &relay_protocol_irc_signal_irc_out_cb, + client); + + /* send JOIN for all channels on server to client */ + relay_protocol_irc_send_join_channels (client); + } + } + else + { + if (argc > 0) + { + if (weechat_strcasecmp (argv[0], "privmsg") == 0) + { + ptr_buffer = relay_protocol_irc_search_buffer (client->protocol_string, + argv[1]); + if (ptr_buffer) + { + weechat_printf (NULL, + "relay: send string \"%s\" on channel %s", + (argv_eol[2][0] == ':') ? argv_eol[2] + 1 : argv_eol[2], + argv[1]); + weechat_command (ptr_buffer, + (argv_eol[2][0] == ':') ? argv_eol[2] + 1 : argv_eol[2]); + } + else + { + weechat_printf (NULL, + _("%s%s: buffer not found for IRC server " + "\"%s\", channel \"%s\""), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, + client->protocol_string, + argv[1]); + } + } + else + { + length = 32 + strlen (client->protocol_string) + strlen (data); + command = malloc (length + 1); + if (command) + { + snprintf (command, length, "/quote -server %s %s", + client->protocol_string, + data); + weechat_command (NULL, command); + free (command); + } + } + } + } + + if (argv) + weechat_string_free_split (argv); + if (argv_eol) + weechat_string_free_split (argv_eol); +} + +/* + * relay_protocol_irc_recv: read data from client + */ + +void +relay_protocol_irc_recv (struct t_relay_client *client, const char *data) +{ + char **items; + int items_count, i; + + items = weechat_string_split (data, "\n", 0, 0, &items_count); + for (i = 0; i < items_count; i++) + { + relay_protocol_irc_recv_one_msg (client, items[i]); + } + if (items) + weechat_string_free_split (items); +} + +/* + * relay_protocol_irc_alloc: init relay data specific to IRC protocol + */ + +void +relay_protocol_irc_alloc (struct t_relay_client *client) +{ + struct t_relay_protocol_irc_data *irc_data; + + client->protocol_data = malloc (sizeof (*irc_data)); + if (client->protocol_data) + { + RELAY_IRC_DATA(client, address) = strdup ("weechat.relay.irc"); + RELAY_IRC_DATA(client, nick) = NULL; + RELAY_IRC_DATA(client, user_received) = 0; + RELAY_IRC_DATA(client, connected) = 0; + RELAY_IRC_DATA(client, hook_signal_irc_in2) = NULL; + RELAY_IRC_DATA(client, hook_signal_irc_out) = NULL; + } +} + +/* + * relay_protocol_irc_free: free relay data specific to IRC protocol + */ + +void +relay_protocol_irc_free (struct t_relay_client *client) +{ + if (client->protocol_data) + { + if (RELAY_IRC_DATA(client, address)) + free (RELAY_IRC_DATA(client, address)); + if (RELAY_IRC_DATA(client, nick)) + free (RELAY_IRC_DATA(client, nick)); + 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_out)) + weechat_unhook (RELAY_IRC_DATA(client, hook_signal_irc_out)); + + free (client->protocol_data); + } +} + +/* + * relay_protocol_irc_print_log: print IRC client infos in log (usually for + * crash dump) + */ + +void +relay_protocol_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 (" 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_out: 0x%lx", RELAY_IRC_DATA(client, hook_signal_irc_out)); + } +} diff --git a/src/plugins/relay/relay-protocol-irc.h b/src/plugins/relay/relay-protocol-irc.h new file mode 100644 index 000000000..25cd7a859 --- /dev/null +++ b/src/plugins/relay/relay-protocol-irc.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2003-2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program 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. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_RELAY_PROTOCOL_IRC_H +#define __WEECHAT_RELAY_PROTOCOL_IRC_H 1 + +struct t_relay_client; + +#define RELAY_IRC_DATA(client, var) \ + (((struct t_relay_protocol_irc_data *)client->protocol_data)->var) + +struct t_relay_protocol_irc_data +{ + char *address; /* client address (used when sending */ + /* data to client) */ + char *nick; /* nick for client */ + int user_received; /* command "USER" received */ + int connected; /* 1 if client is connected as IRC */ + /* client */ + struct t_hook *hook_signal_irc_in2;/* hook signal "irc_in2" */ + struct t_hook *hook_signal_irc_out;/* hook signal "irc_out" */ +}; + +extern void relay_protocol_irc_recv (struct t_relay_client *client, + const char *data); +extern void relay_protocol_irc_alloc (struct t_relay_client *client); +extern void relay_protocol_irc_free (struct t_relay_client *client); +extern void relay_protocol_irc_print_log (struct t_relay_client *client); + +#endif /* relay-protocol-irc.h */ diff --git a/src/plugins/relay/relay-protocol-weechat.c b/src/plugins/relay/relay-protocol-weechat.c new file mode 100644 index 000000000..682812bfc --- /dev/null +++ b/src/plugins/relay/relay-protocol-weechat.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2003-2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program 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. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* relay-protocol-weechat.c: WeeChat protocol for client */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> + +#include "../weechat-plugin.h" +#include "relay.h" +#include "relay-protocol-weechat.h" +#include "relay-client.h" + + +/* + * relay_protocol_weechat_sendf: send formatted data to client + */ + +int +relay_protocol_weechat_sendf (struct t_relay_client *client, + const char *format, ...) +{ + va_list args; + static char buffer[4096]; + char str_length[8]; + int length, num_sent; + + if (!client) + return 0; + + va_start (args, format); + vsnprintf (buffer + 7, sizeof (buffer) - 7 - 1, format, args); + va_end (args); + + length = strlen (buffer + 7); + snprintf (str_length, sizeof (str_length), "%07d", length); + memcpy (buffer, str_length, 7); + + num_sent = send (client->sock, buffer, length + 7, 0); + + client->bytes_sent += length + 7; + + if (num_sent < 0) + { + weechat_printf (NULL, + _("%s%s: error sending data to client %s"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME, + strerror (errno)); + } + + return num_sent; +} + +/* + * relay_protocol_weechat_send_infolist: send infolist to client + */ + +void +relay_protocol_weechat_send_infolist (struct t_relay_client *client, + const char *name, + struct t_infolist *infolist) +{ + const char *fields; + char **argv; + int i, argc, size; + + relay_protocol_weechat_sendf (client, "name %s", name); + + while (weechat_infolist_next (infolist)) + { + fields = weechat_infolist_fields (infolist); + if (fields) + { + argv = weechat_string_split (fields, ",", 0, 0, &argc); + if (argv && (argc > 0)) + { + for (i = 0; i < argc; i++) + { + switch (argv[i][0]) + { + case 'i': + relay_protocol_weechat_sendf (client, "%s %c %d", + argv[i] + 2, argv[i][0], + weechat_infolist_integer (infolist, + argv[i] + 2)); + break; + case 's': + relay_protocol_weechat_sendf (client, "%s %c %s", + argv[i] + 2, argv[i][0], + weechat_infolist_string (infolist, + argv[i] + 2)); + break; + case 'p': + relay_protocol_weechat_sendf (client, "%s %c %lx", + argv[i] + 2, argv[i][0], + (long unsigned int)weechat_infolist_pointer (infolist, + argv[i] + 2)); + break; + case 'b': + relay_protocol_weechat_sendf (client, "%s %c %lx", + argv[i] + 2, argv[i][0], + (long unsigned int)weechat_infolist_buffer (infolist, + argv[i] + 2, + &size)); + break; + case 't': + relay_protocol_weechat_sendf (client, "%s %c %ld", + argv[i] + 2, argv[i][0], + weechat_infolist_time (infolist, argv[i] + 2)); + break; + } + } + } + if (argv) + weechat_string_free_split (argv); + } + } +} + +/* + * relay_protocol_weechat_recv_one_msg: read one message from client + */ + +void +relay_protocol_weechat_recv_one_msg (struct t_relay_client *client, char *data) +{ + char *pos; + struct t_infolist *infolist; + + pos = strchr (data, '\r'); + if (pos) + pos[0] = '\0'; + + if (weechat_relay_plugin->debug) + { + weechat_printf (NULL, "relay: weechat: \"%s\"", data); + } + + if (weechat_strcasecmp (data, "quit") == 0) + relay_client_set_status (client, RELAY_STATUS_DISCONNECTED); + else + { + infolist = weechat_infolist_get (data, NULL, NULL); + if (infolist) + { + relay_protocol_weechat_send_infolist (client, data, infolist); + weechat_infolist_free (infolist); + } + } +} + +/* + * relay_protocol_weechat_recv: read data from client + */ + +void +relay_protocol_weechat_recv (struct t_relay_client *client, const char *data) +{ + char **items; + int items_count, i; + + items = weechat_string_split (data, "\n", 0, 0, &items_count); + for (i = 0; i < items_count; i++) + { + relay_protocol_weechat_recv_one_msg (client, items[i]); + } + if (items) + weechat_string_free_split (items); +} + +/* + * relay_protocol_weechat_alloc: init relay data specific to weechat protocol + */ + +void +relay_protocol_weechat_alloc (struct t_relay_client *client) +{ + struct t_relay_protocol_weechat_data *weechat_data; + + client->protocol_data = malloc (sizeof (*weechat_data)); + if (client->protocol_data) + { + /* ... */ + } +} + +/* + * relay_protocol_weechat_free: free relay data specific to weechat protocol + */ + +void +relay_protocol_weechat_free (struct t_relay_client *client) +{ + if (client->protocol_data) + free (client->protocol_data); +} + +/* + * relay_protocol_weechat_print_log: print weechat client infos in log (usually + * for crash dump) + */ + +void +relay_protocol_weechat_print_log (struct t_relay_client *client) +{ + if (client->protocol_data) + { + } +} diff --git a/src/plugins/relay/relay-protocol-weechat.h b/src/plugins/relay/relay-protocol-weechat.h new file mode 100644 index 000000000..b6881b602 --- /dev/null +++ b/src/plugins/relay/relay-protocol-weechat.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2003-2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program 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. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_RELAY_PROTOCOL_WEECHAT_H +#define __WEECHAT_RELAY_PROTOCOL_WEECHAT_H 1 + +struct t_relay_client; + +#define RELAY_WEECHAT_DATA(client, var) \ + (((struct t_relay_protocol_weechat_data *)client->protocol_data)->var) + +struct t_relay_protocol_weechat_data +{ + char *address; /* client address (used when sending */ + /* data to client) */ + char *nick; /* nick for client */ + int user_received; /* command "USER" received */ + int connected; /* 1 if client is connected as IRC */ + /* client */ +}; + +extern void relay_protocol_weechat_recv (struct t_relay_client *client, + const char *data); +extern void relay_protocol_weechat_alloc (struct t_relay_client *client); +extern void relay_protocol_weechat_free (struct t_relay_client *client); +extern void relay_protocol_weechat_print_log (struct t_relay_client *client); + +#endif /* relay-protocol-weechat.h */ diff --git a/src/plugins/relay/relay-server.c b/src/plugins/relay/relay-server.c new file mode 100644 index 000000000..6863fd178 --- /dev/null +++ b/src/plugins/relay/relay-server.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2003-2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program 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. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* relay-server.c: server functions for relay plugin */ + + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "../weechat-plugin.h" +#include "relay.h" +#include "relay-server.h" +#include "relay-buffer.h" +#include "relay-client.h" +#include "relay-config.h" + + +struct t_relay_server *relay_servers = NULL; +struct t_relay_server *last_relay_server = NULL; + + +/* + * relay_server_get_protocol_string: get protocol and string from a string with + * format "protocol.string" + * Note: *protocol and *string must be freed + * after use + */ + +void +relay_server_get_protocol_string (const char *protocol_and_string, + char **protocol, char **protocol_string) +{ + char *pos; + + pos = strchr (protocol_and_string, '.'); + if (pos) + { + *protocol = weechat_strndup (protocol_and_string, + pos - protocol_and_string); + *protocol_string = strdup (pos + 1); + } + else + { + *protocol = strdup (protocol_and_string); + *protocol_string = strdup ("*"); + } +} + +/* + * relay_server_search: search server by protocol.string + */ + +struct t_relay_server * +relay_server_search (const char *protocol_and_string) +{ + char *protocol, *protocol_string; + struct t_relay_server *ptr_server; + + relay_server_get_protocol_string (protocol_and_string, + &protocol, &protocol_string); + + ptr_server = NULL; + + if (protocol && protocol_string) + { + for (ptr_server = relay_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if ((strcmp (protocol, relay_protocol_string[ptr_server->protocol]) == 0) + && (strcmp (protocol_string, ptr_server->protocol_string) == 0)) + { + break; + } + } + } + + if (protocol) + free (protocol); + if (protocol_string) + free (protocol_string); + + return ptr_server; +} + +/* + * relay_server_search_port: search server by port + */ + +struct t_relay_server * +relay_server_search_port (int port) +{ + struct t_relay_server *ptr_server; + + for (ptr_server = relay_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (ptr_server->port == port) + return ptr_server; + } + + /* server not found */ + return NULL; +} + +/* + * relay_server_close_socket: close socket for a relay server + */ + +void +relay_server_close_socket (struct t_relay_server *server) +{ + if (server->hook_fd) + { + weechat_unhook (server->hook_fd); + server->hook_fd = NULL; + } + if (server->sock >= 0) + { + close (server->sock); + server->sock = -1; + + weechat_printf (NULL, + _("%s: socket closed for %s.%s (port %d)"), + RELAY_PLUGIN_NAME, + relay_protocol_string[server->protocol], + server->protocol_string, + server->port); + } +} + +/* + * relay_server_sock_cb: read data from a client which is connecting on socket + */ + +int +relay_server_sock_cb (void *data, int fd) +{ + struct t_relay_server *server; + struct sockaddr_in client_addr; + unsigned int client_length; + int client_fd; + char ipv4_address[INET_ADDRSTRLEN + 1], *ptr_address; + + /* make C compiler happy */ + (void) fd; + + server = (struct t_relay_server *)data; + + client_length = sizeof (client_addr); + memset (&client_addr, 0, client_length); + + client_fd = accept (server->sock, (struct sockaddr *) &client_addr, + &client_length); + if (client_fd < 0) + { + weechat_printf (NULL, + _("%s%s: cannot accept client on port %d (%s.%s)"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, + server->port, + relay_protocol_string[server->protocol], + server->protocol_string); + return WEECHAT_RC_OK; + } + + ptr_address = NULL; + if (inet_ntop (AF_INET, + &(client_addr.sin_addr), + ipv4_address, + INET_ADDRSTRLEN)) + { + ptr_address = ipv4_address; + } + + relay_client_new (client_fd, ptr_address, server); + + return WEECHAT_RC_OK; +} + +/* + * relay_server_create_socket: create socket and server on port + */ + +int +relay_server_create_socket (struct t_relay_server *server) +{ + int set, max_clients; + struct sockaddr_in server_addr; + + server->sock = socket (AF_INET, SOCK_STREAM, 0); + if (server->sock < 0) + { + weechat_printf (NULL, + _("%s%s: cannot create socket"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME); + return 0; + } + + set = 1; + if (setsockopt (server->sock, SOL_SOCKET, SO_REUSEADDR, + (void *) &set, sizeof (set)) < 0) + { + weechat_printf (NULL, + _("%s%s: cannot set socket option " + "\"SO_REUSEADDR\""), + weechat_prefix ("error"), RELAY_PLUGIN_NAME); + close (server->sock); + server->sock = -1; + return 0; + } + + set = 1; + if (setsockopt (server->sock, SOL_SOCKET, SO_KEEPALIVE, + (void *) &set, sizeof (set)) < 0) + { + weechat_printf (NULL, + _("%s%s: cannot set socket option " + "\"SO_KEEPALIVE\""), + weechat_prefix ("error"), RELAY_PLUGIN_NAME); + close (server->sock); + server->sock = -1; + return 0; + } + + memset(&server_addr, 0, sizeof(struct sockaddr_in)); + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons (server->port); + + if (bind (server->sock, (struct sockaddr *) &server_addr, + sizeof (server_addr)) < 0) + { + weechat_printf (NULL, + _("%s%s: error with \"bind\" on port %d (%s.%s)"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME, + server->port, + relay_protocol_string[server->protocol], + server->protocol_string); + close (server->sock); + server->sock = -1; + return 0; + } + + max_clients = weechat_config_integer (relay_config_network_max_clients); + + listen (server->sock, max_clients); + + weechat_printf (NULL, + _("%s: listening on port %d (relay: %s.%s, max %d clients)"), + RELAY_PLUGIN_NAME, + server->port, + relay_protocol_string[server->protocol], + server->protocol_string, + max_clients); + + server->hook_fd = weechat_hook_fd (server->sock, + 1, 0, 0, + &relay_server_sock_cb, + server); + + server->start_time = time (NULL); + + return 1; +} + +/* + * relay_server_new: add a socket relaying on a port + */ + +struct t_relay_server * +relay_server_new (enum t_relay_protocol protocol, + const char *protocol_string, + int port) +{ + struct t_relay_server *new_server; + + if (relay_server_search_port (port)) + { + weechat_printf (NULL, _("%s%s: error: port \"%d\" is already used"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, port); + return NULL; + } + + new_server = malloc (sizeof (*new_server)); + if (new_server) + { + new_server->protocol = protocol; + new_server->protocol_string = + (protocol_string) ? strdup (protocol_string) : strdup ("*"); + new_server->port = port; + new_server->sock = -1; + new_server->hook_fd = NULL; + new_server->start_time = 0; + + new_server->prev_server = NULL; + new_server->next_server = relay_servers; + if (relay_servers) + relay_servers->prev_server = new_server; + else + last_relay_server = new_server; + relay_servers = new_server; + + relay_server_create_socket (new_server); + } + else + { + weechat_printf (NULL, + _("%s%s: not enough memory for listening on new port"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME); + } + + return new_server; +} + +/* + * relay_server_update_port: update port in a server + */ + +void +relay_server_update_port (struct t_relay_server *server, int port) +{ + if (port != server->port) + { + relay_server_close_socket (server); + server->port = port; + relay_server_create_socket (server); + } +} + +/* + * relay_server_free: remove a server + */ + +void +relay_server_free (struct t_relay_server *server) +{ + struct t_relay_server *new_relay_servers; + + if (!server) + return; + + /* remove server from list */ + if (last_relay_server == server) + last_relay_server = server->prev_server; + if (server->prev_server) + { + (server->prev_server)->next_server = server->next_server; + new_relay_servers = relay_servers; + } + else + new_relay_servers = server->next_server; + if (server->next_server) + (server->next_server)->prev_server = server->prev_server; + + /* free data */ + relay_server_close_socket (server); + if (server->protocol_string) + free (server->protocol_string); + + free (server); + + relay_servers = new_relay_servers; +} + +/* + * relay_server_free_all: remove all servers + */ + +void +relay_server_free_all () +{ + while (relay_servers) + { + relay_server_free (relay_servers); + } +} + +/* + * relay_server_print_log: print server infos in log (usually for crash dump) + */ + +void +relay_server_print_log () +{ + struct t_relay_server *ptr_server; + + for (ptr_server = relay_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + weechat_log_printf (""); + weechat_log_printf ("[relay server (addr:0x%lx)]", ptr_server); + weechat_log_printf (" protocol. . . . . . : %d (%s)", + ptr_server->protocol, + relay_protocol_string[ptr_server->protocol]); + weechat_log_printf (" protocol_string . . : '%s'", ptr_server->protocol_string); + weechat_log_printf (" port. . . . . . . . : %d", ptr_server->port); + 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); + } +} diff --git a/src/plugins/relay/relay-server.h b/src/plugins/relay/relay-server.h new file mode 100644 index 000000000..a1cb39df2 --- /dev/null +++ b/src/plugins/relay/relay-server.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2003-2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program 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. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_RELAY_SERVER_H +#define __WEECHAT_RELAY_SERVER_H 1 + +struct t_relay_server +{ + enum t_relay_protocol protocol; /* protocol (irc,..) */ + char *protocol_string; /* string used for protocol */ + /* example: server for irc protocol */ + int port; /* listening on this port */ + int sock; /* socket for connection */ + struct t_hook *hook_fd; /* hook for socket */ + time_t start_time; /* start time */ + struct t_relay_server *prev_server;/* link to previous server */ + struct t_relay_server *next_server;/* link to next server */ +}; + +extern struct t_relay_server *relay_servers; +extern struct t_relay_server *last_relay_server; + +extern void relay_server_get_protocol_string (const char *protocol_and_string, + char **protocol, + char **protocol_string); +extern struct t_relay_server *relay_server_search (const char *protocol_and_string); +extern struct t_relay_server *relay_server_search_port (int port); +extern struct t_relay_server *relay_server_new (enum t_relay_protocol protocol, + const char *protocol_string, + int port); +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 void relay_server_print_log (); + +#endif /* relay-server.h */ diff --git a/src/plugins/relay/relay.c b/src/plugins/relay/relay.c index 901345da5..d0399fa25 100644 --- a/src/plugins/relay/relay.c +++ b/src/plugins/relay/relay.c @@ -23,11 +23,13 @@ #include "../weechat-plugin.h" #include "relay.h" +#include "relay-buffer.h" #include "relay-client.h" #include "relay-command.h" +#include "relay-completion.h" #include "relay-config.h" #include "relay-info.h" -#include "relay-network.h" +#include "relay-server.h" #include "relay-upgrade.h" @@ -42,6 +44,30 @@ struct t_weechat_plugin *weechat_relay_plugin = NULL; int relay_signal_upgrade_received = 0; /* signal "upgrade" received ? */ +char *relay_protocol_string[] = /* strings for protocols */ +{ "weechat", "irc" }; + + +/* + * relay_protocol_search: search a protocol by name + */ + +int +relay_protocol_search (const char *name) +{ + int i; + + for (i = 0; i < RELAY_NUM_PROTOCOLS; i++) + { + if (weechat_strcasecmp (relay_protocol_string[i], name) == 0) + { + return i; + } + } + + /* protocol not found */ + return -1; +} /* * relay_signal_upgrade_cb: callback for "upgrade" signal @@ -80,6 +106,7 @@ relay_debug_dump_cb (void *data, const char *signal, const char *type_data, weechat_log_printf ("***** \"%s\" plugin dump *****", weechat_plugin->name); + relay_server_print_log (); relay_client_print_log (); weechat_log_printf (""); @@ -110,13 +137,14 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) relay_command_init (); + /* hook completions */ + relay_completion_init (); + weechat_hook_signal ("upgrade", &relay_signal_upgrade_cb, NULL); weechat_hook_signal ("debug_dump", &relay_debug_dump_cb, NULL); relay_info_init (); - relay_network_init (); - return WEECHAT_RC_OK; } @@ -132,12 +160,19 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) relay_config_write (); - relay_network_end (); - if (relay_signal_upgrade_received) relay_upgrade_save (); else + { + /* remove all servers */ + relay_server_free_all (); + + /* remove all clients */ relay_client_disconnect_all (); + if (relay_buffer) + weechat_buffer_close (relay_buffer); + relay_client_free_all (); + } return WEECHAT_RC_OK; } diff --git a/src/plugins/relay/relay.h b/src/plugins/relay/relay.h index cc3b4c610..3e9a3b6e3 100644 --- a/src/plugins/relay/relay.h +++ b/src/plugins/relay/relay.h @@ -25,4 +25,22 @@ extern struct t_weechat_plugin *weechat_relay_plugin; +/* relay protocol */ + +enum t_relay_protocol +{ + RELAY_PROTOCOL_WEECHAT = 0, /* WeeChat protocol */ + RELAY_PROTOCOL_IRC, /* IRC protocol (IRC proxy) */ + /* number of relay protocols */ + RELAY_NUM_PROTOCOLS, +}; + +#define RELAY_COLOR_CHAT weechat_color("chat") +#define RELAY_COLOR_CHAT_HOST weechat_color("chat_host") +#define RELAY_COLOR_CHAT_BUFFER weechat_color("chat_buffer") + +extern char *relay_protocol_string[]; + +extern int relay_protocol_search (const char *name); + #endif /* relay.h */ |