summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/demo/demo.c2
-rw-r--r--src/plugins/relay/CMakeLists.txt5
-rw-r--r--src/plugins/relay/Makefile.am10
-rw-r--r--src/plugins/relay/relay-buffer.c21
-rw-r--r--src/plugins/relay/relay-client.c234
-rw-r--r--src/plugins/relay/relay-client.h12
-rw-r--r--src/plugins/relay/relay-command.c166
-rw-r--r--src/plugins/relay/relay-completion.c157
-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.c181
-rw-r--r--src/plugins/relay/relay-config.h11
-rw-r--r--src/plugins/relay/relay-network.c234
-rw-r--r--src/plugins/relay/relay-protocol-irc.c545
-rw-r--r--src/plugins/relay/relay-protocol-irc.h46
-rw-r--r--src/plugins/relay/relay-protocol-weechat.c230
-rw-r--r--src/plugins/relay/relay-protocol-weechat.h44
-rw-r--r--src/plugins/relay/relay-server.c426
-rw-r--r--src/plugins/relay/relay-server.h52
-rw-r--r--src/plugins/relay/relay.c45
-rw-r--r--src/plugins/relay/relay.h18
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 */