summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/wee-command.c20
-rw-r--r--src/core/wee-hook.c100
-rw-r--r--src/core/wee-hook.h31
-rw-r--r--src/core/wee-network.c443
-rw-r--r--src/core/wee-network.h5
-rw-r--r--src/core/weechat.c4
-rw-r--r--src/gui/curses/Makefile.am3
-rw-r--r--src/gui/gtk/Makefile.am3
-rw-r--r--src/plugins/irc/irc-command.c16
-rw-r--r--src/plugins/irc/irc-config.c10
-rw-r--r--src/plugins/irc/irc-config.h2
-rw-r--r--src/plugins/irc/irc-display.c6
-rw-r--r--src/plugins/irc/irc-server.c485
-rw-r--r--src/plugins/irc/irc-server.h10
-rw-r--r--src/plugins/irc/irc.c17
-rw-r--r--src/plugins/irc/irc.h4
-rw-r--r--src/plugins/plugin.c1
-rw-r--r--src/plugins/weechat-plugin.h23
18 files changed, 705 insertions, 478 deletions
diff --git a/src/core/wee-command.c b/src/core/wee-command.c
index 296a7935d..94a7b05a9 100644
--- a/src/core/wee-command.c
+++ b/src/core/wee-command.c
@@ -1470,6 +1470,26 @@ command_plugin_list (char *name, int full)
HOOK_FD(ptr_hook, flags));
}
}
+
+ /* connect hooked */
+ hook_found = 0;
+ for (ptr_hook = weechat_hooks[HOOK_TYPE_CONNECT]; ptr_hook;
+ ptr_hook = ptr_hook->next_hook)
+ {
+ if (!ptr_hook->deleted && (ptr_hook->plugin == ptr_plugin))
+ {
+ if (!hook_found)
+ gui_chat_printf (NULL,
+ _(" connect hooked:"));
+ hook_found = 1;
+ gui_chat_printf (NULL,
+ _(" socket: %d, address: %s, "
+ "port: %d"),
+ HOOK_CONNECT(ptr_hook, sock),
+ HOOK_CONNECT(ptr_hook, address),
+ HOOK_CONNECT(ptr_hook, port));
+ }
+ }
/* prints hooked */
hook_found = 0;
diff --git a/src/core/wee-hook.c b/src/core/wee-hook.c
index b904b3cdc..8de5b8eec 100644
--- a/src/core/wee-hook.c
+++ b/src/core/wee-hook.c
@@ -23,14 +23,19 @@
#include "config.h"
#endif
+#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
#include "weechat.h"
#include "wee-hook.h"
#include "wee-log.h"
+#include "wee-network.h"
#include "wee-string.h"
#include "wee-util.h"
#include "../gui/gui-buffer.h"
@@ -38,6 +43,9 @@
#include "../plugins/plugin.h"
+char *hook_type_string[HOOK_NUM_TYPES] =
+{ "command", "timer", "fd", "connect", "print", "signal", "config",
+ "completion", "modifier" };
struct t_hook *weechat_hooks[HOOK_NUM_TYPES];
struct t_hook *last_weechat_hook[HOOK_NUM_TYPES];
int hook_exec_recursion = 0;
@@ -778,6 +786,54 @@ hook_fd_exec (fd_set *read_fds, fd_set *write_fds, fd_set *exception_fds)
}
/*
+ * hook_connect: hook a connection to peer (using fork)
+ */
+
+struct t_hook *
+hook_connect (struct t_weechat_plugin *plugin, char *address, int port,
+ int sock, int ipv6, void *gnutls_sess, char *local_hostname,
+ t_hook_callback_connect *callback, void *callback_data)
+{
+ struct t_hook *new_hook;
+ struct t_hook_connect *new_hook_connect;
+
+ if ((sock < 0) || !address || (port <= 0))
+ return NULL;
+
+ new_hook = malloc (sizeof (*new_hook));
+ if (!new_hook)
+ return NULL;
+ new_hook_connect = malloc (sizeof (*new_hook_connect));
+ if (!new_hook_connect)
+ {
+ free (new_hook);
+ return NULL;
+ }
+
+ hook_init_data (new_hook, plugin, HOOK_TYPE_CONNECT, callback_data);
+
+ new_hook->hook_data = new_hook_connect;
+ new_hook_connect->callback = callback;
+ new_hook_connect->address = strdup (address);
+ new_hook_connect->port = port;
+ new_hook_connect->sock = sock;
+ new_hook_connect->ipv6 = ipv6;
+ new_hook_connect->gnutls_sess = gnutls_sess;
+ new_hook_connect->local_hostname = (local_hostname) ?
+ strdup (local_hostname) : NULL;
+ new_hook_connect->child_read = -1;
+ new_hook_connect->child_write = -1;
+ new_hook_connect->child_pid = 0;
+ new_hook_connect->hook_fd = NULL;
+
+ hook_add_to_list (new_hook);
+
+ network_connect_with_fork (new_hook);
+
+ return new_hook;
+}
+
+/*
* hook_print: hook a message printed by WeeChat
*/
@@ -1273,6 +1329,22 @@ unhook (struct t_hook *hook)
case HOOK_TYPE_FD:
free ((struct t_hook_fd *)hook->hook_data);
break;
+ case HOOK_TYPE_CONNECT:
+ if (HOOK_CONNECT(hook, address))
+ free (HOOK_CONNECT(hook, address));
+ if (HOOK_CONNECT(hook, hook_fd))
+ unhook (HOOK_CONNECT(hook, hook_fd));
+ if (HOOK_CONNECT(hook, child_pid) > 0)
+ {
+ kill (HOOK_CONNECT(hook, child_pid), SIGKILL);
+ waitpid (HOOK_CONNECT(hook, child_pid), NULL, 0);
+ }
+ if (HOOK_CONNECT(hook, child_read) != -1)
+ close (HOOK_CONNECT(hook, child_read));
+ if (HOOK_CONNECT(hook, child_write) != -1)
+ close (HOOK_CONNECT(hook, child_write));
+ free ((struct t_hook_connect *)hook->hook_data);
+ break;
case HOOK_TYPE_PRINT:
if (HOOK_PRINT(hook, message))
free (HOOK_PRINT(hook, message));
@@ -1388,11 +1460,12 @@ hook_print_log ()
(ptr_hook->plugin) ? ptr_hook->plugin->name : "");
log_printf (" deleted. . . . . . . . : %d", ptr_hook->deleted);
log_printf (" running. . . . . . . . : %d", ptr_hook->running);
+ log_printf (" type . . . . . . . . . : %d (%s)",
+ ptr_hook->type, hook_type_string[ptr_hook->type]);
+ log_printf (" callback_data. . . . . : 0x%x", ptr_hook->callback_data);
switch (ptr_hook->type)
{
case HOOK_TYPE_COMMAND:
- log_printf (" type . . . . . . . . . : %d (command)", ptr_hook->type);
- log_printf (" callback_data. . . . . : 0x%x", ptr_hook->callback_data);
if (!ptr_hook->deleted)
{
log_printf (" command data:");
@@ -1406,8 +1479,6 @@ hook_print_log ()
}
break;
case HOOK_TYPE_TIMER:
- log_printf (" type . . . . . . . . . : %d (timer)", ptr_hook->type);
- log_printf (" callback_data. . . . . : 0x%x", ptr_hook->callback_data);
if (!ptr_hook->deleted)
{
log_printf (" timer data:");
@@ -1430,8 +1501,15 @@ hook_print_log ()
}
break;
case HOOK_TYPE_FD:
- log_printf (" type . . . . . . . . . : %d (fd)", ptr_hook->type);
- log_printf (" callback_data. . . . . : 0x%x", ptr_hook->callback_data);
+ if (!ptr_hook->deleted)
+ {
+ log_printf (" fd data:");
+ log_printf (" callback . . . . . . : 0x%x", HOOK_FD(ptr_hook, callback));
+ log_printf (" fd . . . . . . . . . : %ld", HOOK_FD(ptr_hook, fd));
+ log_printf (" flags. . . . . . . . : %ld", HOOK_FD(ptr_hook, flags));
+ }
+ break;
+ case HOOK_TYPE_CONNECT:
if (!ptr_hook->deleted)
{
log_printf (" fd data:");
@@ -1441,8 +1519,6 @@ hook_print_log ()
}
break;
case HOOK_TYPE_PRINT:
- log_printf (" type . . . . . . . . . : %d (print)", ptr_hook->type);
- log_printf (" callback_data. . . . . : 0x%x", ptr_hook->callback_data);
if (!ptr_hook->deleted)
{
log_printf (" print data:");
@@ -1452,8 +1528,6 @@ hook_print_log ()
}
break;
case HOOK_TYPE_SIGNAL:
- log_printf (" type . . . . . . . . . : %d (signal)", ptr_hook->type);
- log_printf (" callback_data. . . . . : 0x%x", ptr_hook->callback_data);
if (!ptr_hook->deleted)
{
log_printf (" signal data:");
@@ -1462,8 +1536,6 @@ hook_print_log ()
}
break;
case HOOK_TYPE_CONFIG:
- log_printf (" type . . . . . . . . . : %d (config)", ptr_hook->type);
- log_printf (" callback_data. . . . . : 0x%x", ptr_hook->callback_data);
if (!ptr_hook->deleted)
{
log_printf (" config data:");
@@ -1472,8 +1544,6 @@ hook_print_log ()
}
break;
case HOOK_TYPE_COMPLETION:
- log_printf (" type . . . . . . . . . : %d (completion)", ptr_hook->type);
- log_printf (" callback_data. . . . . : 0x%x", ptr_hook->callback_data);
if (!ptr_hook->deleted)
{
log_printf (" completion data:");
@@ -1482,8 +1552,6 @@ hook_print_log ()
}
break;
case HOOK_TYPE_MODIFIER:
- log_printf (" type . . . . . . . . . : %d (modifier)", ptr_hook->type);
- log_printf (" callback_data. . . . . : 0x%x", ptr_hook->callback_data);
if (!ptr_hook->deleted)
{
log_printf (" modifier data:");
diff --git a/src/core/wee-hook.h b/src/core/wee-hook.h
index 7c54e4eea..7959f0232 100644
--- a/src/core/wee-hook.h
+++ b/src/core/wee-hook.h
@@ -20,6 +20,10 @@
#ifndef __WEECHAT_HOOK_H
#define __WEECHAT_HOOK_H 1
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
struct t_gui_buffer;
struct t_weelist;
@@ -30,6 +34,7 @@ enum t_hook_type
HOOK_TYPE_COMMAND = 0, /* new command */
HOOK_TYPE_TIMER, /* timer */
HOOK_TYPE_FD, /* socket of file descriptor */
+ HOOK_TYPE_CONNECT, /* connect to peer with fork */
HOOK_TYPE_PRINT, /* printed message */
HOOK_TYPE_SIGNAL, /* signal */
HOOK_TYPE_CONFIG, /* config option */
@@ -46,6 +51,7 @@ enum t_hook_type
#define HOOK_COMMAND(hook, var) (((struct t_hook_command *)hook->hook_data)->var)
#define HOOK_TIMER(hook, var) (((struct t_hook_timer *)hook->hook_data)->var)
#define HOOK_FD(hook, var) (((struct t_hook_fd *)hook->hook_data)->var)
+#define HOOK_CONNECT(hook, var) (((struct t_hook_connect *)hook->hook_data)->var)
#define HOOK_PRINT(hook, var) (((struct t_hook_print *)hook->hook_data)->var)
#define HOOK_SIGNAL(hook, var) (((struct t_hook_signal *)hook->hook_data)->var)
#define HOOK_CONFIG(hook, var) (((struct t_hook_config *)hook->hook_data)->var)
@@ -103,6 +109,25 @@ struct t_hook_fd
int flags; /* fd flags (read,write,..) */
};
+typedef int (t_hook_callback_connect)(void *data, int status);
+
+struct t_hook_connect
+{
+ t_hook_callback_connect *callback; /* connect callback */
+ char *address; /* peer address */
+ int port; /* peer port */
+ int sock; /* socket (created by caller) */
+ int ipv6; /* IPv6 connection ? */
+#ifdef HAVE_GNUTLS
+ gnutls_session_t *gnutls_sess; /* GnuTLS session (SSL connection) */
+#endif
+ char *local_hostname; /* force local hostname (optional) */
+ int child_read; /* to read into child pipe */
+ int child_write; /* to write into child pipe */
+ pid_t child_pid; /* pid of child process (connecting) */
+ struct t_hook *hook_fd; /* pointer to fd hook */
+};
+
typedef int (t_hook_callback_print)(void *data, struct t_gui_buffer *buffer,
time_t date, int tags_count,
char **tags, char *prefix,
@@ -191,6 +216,12 @@ extern int hook_fd_set (fd_set *read_fds, fd_set *write_fds,
fd_set *exception_fds);
extern void hook_fd_exec (fd_set *read_fds, fd_set *write_fds,
fd_set *exception_fds);
+extern struct t_hook *hook_connect (struct t_weechat_plugin *plugin,
+ char *address, int port,
+ int sock, int ipv6, void *gnutls_session,
+ char *local_hostname,
+ t_hook_callback_connect * callback,
+ void *callback_data);
extern struct t_hook *hook_print (struct t_weechat_plugin *plugin,
struct t_gui_buffer *buffer,
char *tags, char *message,
diff --git a/src/core/wee-network.c b/src/core/wee-network.c
index 1c9e5dc63..3bfab7215 100644
--- a/src/core/wee-network.c
+++ b/src/core/wee-network.c
@@ -23,6 +23,7 @@
#include "config.h"
#endif
+#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@@ -32,11 +33,57 @@
#include <netdb.h>
#include <errno.h>
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
#include "weechat.h"
#include "wee-network.h"
+#include "wee-hook.h"
#include "wee-config.h"
#include "wee-string.h"
+#include "../plugins/plugin.h"
+
+
+#ifdef HAVE_GNUTLS
+gnutls_certificate_credentials gnutls_xcred; /* GnuTLS client credentials */
+const int gnutls_cert_type_prio[] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010700
+ const int gnutls_prot_prio[] = { GNUTLS_TLS1_2, GNUTLS_TLS1_1,
+ GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
+#else
+ const int gnutls_prot_prio[] = { GNUTLS_TLS1_1, GNUTLS_TLS1_0,
+ GNUTLS_SSL3, 0 };
+#endif
+#endif
+
+
+/*
+ * network_init: init network
+ */
+
+void
+network_init ()
+{
+#ifdef HAVE_GNUTLS
+ gnutls_global_init ();
+ gnutls_certificate_allocate_credentials (&gnutls_xcred);
+ gnutls_certificate_set_x509_trust_file (gnutls_xcred, "ca.pem", GNUTLS_X509_FMT_PEM);
+#endif
+}
+
+/*
+ * network_end: end network
+ */
+void
+network_end ()
+{
+#ifdef HAVE_GNUTLS
+ gnutls_certificate_free_credentials (gnutls_xcred);
+ gnutls_global_deinit();
+#endif
+}
/*
* network_convbase64_8x3_to_6x4 : convert 3 bytes of 8 bits in 4 bytes of 6 bits
@@ -101,9 +148,8 @@ network_base64encode (char *from, char *to)
/*
* network_pass_httpproxy: establish connection/authentification to an
* http proxy
- * return :
- * - 0 if connexion throw proxy was successful
- * - 1 if connexion fails
+ * return 1 if connection is ok
+ * 0 if error
*/
int
@@ -135,26 +181,26 @@ network_pass_httpproxy (int sock, char *address, int port)
m = send (sock, buffer, n, 0);
if (n != m)
- return 1;
+ return 0;
n = recv (sock, buffer, sizeof (buffer), 0);
/* success result must be like: "HTTP/1.0 200 OK" */
if (n < 12)
- return 1;
+ return 0;
if (memcmp (buffer, "HTTP/", 5) || memcmp (buffer + 9, "200", 3))
- return 1;
+ return 0;
- return 0;
+ /* connection ok */
+ return 1;
}
/*
* network_resolve: resolve hostname on its IP address
* (works with ipv4 and ipv6)
- * return :
- * - 0 if resolution was successful
- * - 1 if resolution fails
+ * return 1 if resolution is ok
+ * 0 if error
*/
int
@@ -169,16 +215,16 @@ network_resolve (char *hostname, char *ip, int *version)
res = NULL;
if (getaddrinfo (hostname, NULL, NULL, &res) != 0)
- return 1;
+ return 0;
if (!res)
- return 1;
+ return 0;
if (getnameinfo (res->ai_addr, res->ai_addrlen, ipbuffer, sizeof(ipbuffer),
NULL, 0, NI_NUMERICHOST) != 0)
{
freeaddrinfo (res);
- return 1;
+ return 0;
}
if ((res->ai_family == AF_INET) && (version != NULL))
@@ -190,15 +236,15 @@ network_resolve (char *hostname, char *ip, int *version)
freeaddrinfo (res);
- return 0;
+ /* resolution ok */
+ return 1;
}
/*
* network_pass_socks4proxy: establish connection/authentification thru a
* socks4 proxy
- * return :
- * - 0 if connexion thru proxy was successful
- * - 1 if connexion fails
+ * return 1 if connection is ok
+ * 0 if error
*/
int
@@ -232,18 +278,19 @@ network_pass_socks4proxy (int sock, char *address, int port)
send (sock, (char *) &socks4, 8 + strlen (socks4.user) + 1, 0);
recv (sock, buffer, sizeof (buffer), 0);
- if (buffer[0] == 0 && buffer[1] == 90)
- return 0;
+ /* connection ok */
+ if ((buffer[0] == 0) && (buffer[1] == 90))
+ return 1;
- return 1;
+ /* connection failed */
+ return 0;
}
/*
* network_pass_socks5proxy: establish connection/authentification thru a
* socks5 proxy
- * return :
- * - 0 if connexion thru proxy was successful
- * - 1 if connexion fails
+ * return 1 if connection is ok
+ * 0 if error
*/
int
@@ -276,7 +323,7 @@ network_pass_socks5proxy (int sock, char *address, int port)
send (sock, (char *) &socks5, sizeof(socks5), 0);
/* server socks5 must respond with 2 bytes */
if (recv (sock, buffer, 2, 0) != 2)
- return 1;
+ return 0;
if (CONFIG_STRING(config_proxy_username)
&& CONFIG_STRING(config_proxy_username)[0])
@@ -288,7 +335,7 @@ network_pass_socks5proxy (int sock, char *address, int port)
*/
if (buffer[0] != 5 || buffer[1] != 2)
- return 1;
+ return 0;
/* authentication as in RFC 1929 */
username_len = strlen (CONFIG_STRING(config_proxy_username));
@@ -306,11 +353,11 @@ network_pass_socks5proxy (int sock, char *address, int port)
/* server socks5 must respond with 2 bytes */
if (recv (sock, buffer, 2, 0) != 2)
- return 1;
+ return 0;
/* buffer[1] = auth state, must be 0 for success */
if (buffer[1] != 0)
- return 1;
+ return 0;
}
else
{
@@ -319,8 +366,8 @@ network_pass_socks5proxy (int sock, char *address, int port)
* - socks version (buffer[0]) = 5 => socks5
* - socks method (buffer[1]) = 0 => no authentication
*/
- if (!(buffer[0] == 5 && buffer[1] == 0))
- return 1;
+ if (!((buffer[0] == 5) && (buffer[1] == 0)))
+ return 0;
}
/* authentication successful then giving address/port to connect */
@@ -328,7 +375,7 @@ network_pass_socks5proxy (int sock, char *address, int port)
addr_buffer_len = 4 + 1 + addr_len + 2;
addr_buffer = malloc (addr_buffer_len * sizeof(*addr_buffer));
if (!addr_buffer)
- return 1;
+ return 0;
addr_buffer[0] = 5; /* version 5 */
addr_buffer[1] = 1; /* command: 1 for connect */
addr_buffer[2] = 0; /* reserved */
@@ -342,10 +389,10 @@ network_pass_socks5proxy (int sock, char *address, int port)
/* dialog with proxy server */
if (recv (sock, buffer, 4, 0) != 4)
- return 1;
+ return 0;
- if (!(buffer[0] == 5 && buffer[1] == 0))
- return 1;
+ if (!((buffer[0] == 5) && (buffer[1] == 0)))
+ return 0;
/* buffer[3] = address type */
switch (buffer[3])
@@ -356,7 +403,7 @@ network_pass_socks5proxy (int sock, char *address, int port)
* address of 4 bytes and port of 2 bytes (= 6 bytes)
*/
if (recv (sock, buffer, 6, 0) != 6)
- return 1;
+ return 0;
break;
case 3:
/* domainname
@@ -364,11 +411,11 @@ network_pass_socks5proxy (int sock, char *address, int port)
*/
/* reading address length */
if (recv (sock, buffer, 1, 0) != 1)
- return 1;
+ return 0;
addr_len = buffer[0];
/* reading address + port = addr_len + 2 */
if (recv (sock, buffer, addr_len + 2, 0) != (addr_len + 2))
- return 1;
+ return 0;
break;
case 4:
/* ipv6
@@ -376,20 +423,20 @@ network_pass_socks5proxy (int sock, char *address, int port)
* address of 16 bytes and port of 2 bytes (= 18 bytes)
*/
if (recv (sock, buffer, 18, 0) != 18)
- return 1;
+ return 0;
break;
default:
- return 1;
+ return 0;
}
- return 0;
+ /* connection ok */
+ return 1;
}
/*
* network_pass_proxy: establish connection/authentification to a proxy
- * return :
- * - 0 if connexion throw proxy was successful
- * - 1 if connexion fails
+ * return 1 if connection is ok
+ * 0 if error
*/
int
@@ -397,8 +444,8 @@ network_pass_proxy (int sock, char *address, int port)
{
int rc;
- rc = 1;
- if (CONFIG_BOOLEAN(config_proxy_type))
+ rc = 0;
+ if (CONFIG_BOOLEAN(config_proxy_use))
{
if (string_strcasecmp (CONFIG_STRING(config_proxy_type), "http") == 0)
rc = network_pass_httpproxy (sock, address, port);
@@ -412,7 +459,8 @@ network_pass_proxy (int sock, char *address, int port)
/*
* network_connect_to: connect to a remote host
- * return 1 if ok, 0 if failed
+ * return 1 if connection is ok
+ * 0 if error
*/
int
@@ -423,7 +471,7 @@ network_connect_to (int sock, unsigned long address, int port)
char *ip4;
int ret;
- if (CONFIG_BOOLEAN(config_proxy_type))
+ if (CONFIG_BOOLEAN(config_proxy_use))
{
memset (&addr, 0, sizeof (addr));
addr.sin_addr.s_addr = htonl (address);
@@ -435,11 +483,11 @@ network_connect_to (int sock, unsigned long address, int port)
hostent = gethostbyname (CONFIG_STRING(config_proxy_address));
if (!hostent)
return 0;
- memcpy(&(addr.sin_addr),*(hostent->h_addr_list), sizeof(struct in_addr));
+ memcpy(&(addr.sin_addr), *(hostent->h_addr_list), sizeof(struct in_addr));
ret = connect (sock, (struct sockaddr *) &addr, sizeof (addr));
if ((ret == -1) && (errno != EINPROGRESS))
return 0;
- if (network_pass_proxy (sock, ip4, port) == -1)
+ if (!network_pass_proxy (sock, ip4, port))
return 0;
}
else
@@ -454,3 +502,302 @@ network_connect_to (int sock, unsigned long address, int port)
}
return 1;
}
+
+/*
+ * network_connect_child: child process trying to connect to peer
+ */
+
+void
+network_connect_child (struct t_hook *hook_connect)
+{
+ struct addrinfo hints, *res, *res_local;
+ char status_str[2];
+ int rc;
+
+ res = NULL;
+ res_local = NULL;
+ status_str[1] = '\0';
+
+ if (CONFIG_BOOLEAN(config_proxy_use))
+ {
+ /* get info about peer */
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = (CONFIG_BOOLEAN(config_proxy_ipv6)) ? AF_INET6 : AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo (CONFIG_STRING(config_proxy_address), NULL, &hints, &res) !=0)
+ {
+ /* address not found */
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND;
+ write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
+ return;
+ }
+ if (!res)
+ {
+ /* adddress not found */
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND;
+ write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
+ return;
+ }
+ if ((CONFIG_BOOLEAN(config_proxy_ipv6) && (res->ai_family != AF_INET6))
+ || ((!CONFIG_BOOLEAN(config_proxy_ipv6) && (res->ai_family != AF_INET))))
+ {
+ /* IP address not found */
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND;
+ write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
+ freeaddrinfo (res);
+ return;
+ }
+
+ if (CONFIG_BOOLEAN(config_proxy_ipv6))
+ ((struct sockaddr_in6 *)(res->ai_addr))->sin6_port = htons (CONFIG_INTEGER(config_proxy_port));
+ else
+ ((struct sockaddr_in *)(res->ai_addr))->sin_port = htons (CONFIG_INTEGER(config_proxy_port));
+
+ /* connect to peer */
+ if (connect (HOOK_CONNECT(hook_connect, sock),
+ res->ai_addr, res->ai_addrlen) != 0)
+ {
+ /* connection refused */
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED;
+ write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
+ freeaddrinfo (res);
+ return;
+ }
+
+ if (!network_pass_proxy (HOOK_CONNECT(hook_connect, sock),
+ HOOK_CONNECT(hook_connect, address),
+ HOOK_CONNECT(hook_connect, port)))
+ {
+ /* proxy fails to connect to peer */
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_PROXY_ERROR;
+ write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
+ freeaddrinfo (res);
+ return;
+ }
+ }
+ else
+ {
+ /* set local hostname/IP if asked by user */
+ if (HOOK_CONNECT(hook_connect, local_hostname)
+ && HOOK_CONNECT(hook_connect, local_hostname[0]))
+ {
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_family = (HOOK_CONNECT(hook_connect, ipv6)) ? AF_INET6 : AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ rc = getaddrinfo (HOOK_CONNECT(hook_connect, local_hostname),
+ NULL, &hints, &res_local);
+ if ((rc != 0) || !res_local
+ || (HOOK_CONNECT(hook_connect, ipv6)
+ && (res_local->ai_family != AF_INET6))
+ || ((!HOOK_CONNECT(hook_connect, ipv6)
+ && (res_local->ai_family != AF_INET))))
+ {
+ /* fails to set local hostname/IP */
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR;
+ write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
+ if (res_local)
+ freeaddrinfo (res_local);
+ return;
+ }
+ if (bind (HOOK_CONNECT(hook_connect, sock),
+ res_local->ai_addr, res_local->ai_addrlen) < 0)
+ {
+ /* fails to set local hostname/IP */
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR;
+ write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
+ if (res_local)
+ freeaddrinfo (res_local);
+ return;
+ }
+ }
+
+ /* get info about peer */
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_family = (HOOK_CONNECT(hook_connect, ipv6)) ? AF_INET6 : AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ rc = getaddrinfo (HOOK_CONNECT(hook_connect, address),
+ NULL, &hints, &res);
+ if ((rc != 0) || !res)
+ {
+ /* address not found */
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND;
+ write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
+ if (res)
+ freeaddrinfo (res);
+ return;
+ }
+ if ((HOOK_CONNECT(hook_connect, ipv6) && (res->ai_family != AF_INET6))
+ || ((!HOOK_CONNECT(hook_connect, ipv6) && (res->ai_family != AF_INET))))
+ {
+ /* IP address not found */
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND;
+ write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
+ if (res)
+ freeaddrinfo (res);
+ if (res_local)
+ freeaddrinfo (res_local);
+ return;
+ }
+
+ /* connect to peer */
+ if (HOOK_CONNECT(hook_connect, ipv6))
+ ((struct sockaddr_in6 *)(res->ai_addr))->sin6_port =
+ htons (HOOK_CONNECT(hook_connect, port));
+ else
+ ((struct sockaddr_in *)(res->ai_addr))->sin_port =
+ htons (HOOK_CONNECT(hook_connect, port));
+
+ if (connect (HOOK_CONNECT(hook_connect, sock),
+ res->ai_addr, res->ai_addrlen) != 0)
+ {
+ /* connection refused */
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED;
+ write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
+ if (res)
+ freeaddrinfo (res);
+ if (res_local)
+ freeaddrinfo (res_local);
+ return;
+ }
+ }
+
+ /* connection ok */
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_OK;
+ write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
+ if (res)
+ freeaddrinfo (res);
+ if (res_local)
+ freeaddrinfo (res_local);
+}
+
+/*
+ * network_connect_child_read_cb: read connection progress from child process
+ */
+
+int
+network_connect_child_read_cb (void *arg_hook_connect)
+{
+ struct t_hook *hook_connect;
+ char buffer[1];
+ int num_read, rc;
+
+ hook_connect = (struct t_hook *)arg_hook_connect;
+
+ num_read = read (HOOK_CONNECT(hook_connect, child_read),
+ buffer, sizeof (buffer));
+ if (num_read > 0)
+ {
+ if (buffer[0] - '0' == WEECHAT_HOOK_CONNECT_OK)
+ {
+#ifdef HAVE_GNUTLS
+ if (HOOK_CONNECT(hook_connect, gnutls_sess))
+ {
+ gnutls_transport_set_ptr (*HOOK_CONNECT(hook_connect, gnutls_sess),
+ (gnutls_transport_ptr) ((unsigned long) HOOK_CONNECT(hook_connect, sock)));
+ while (1)
+ {
+ rc = gnutls_handshake (*HOOK_CONNECT(hook_connect, gnutls_sess));
+ if ((rc == GNUTLS_E_SUCCESS)
+ || ((rc != GNUTLS_E_AGAIN) && (rc != GNUTLS_E_INTERRUPTED)))
+ break;
+ usleep (1000);
+ }
+ if (rc != GNUTLS_E_SUCCESS)
+ {
+ (void) (HOOK_CONNECT(hook_connect, callback))
+ (hook_connect->callback_data, WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR);
+ unhook (hook_connect);
+ return WEECHAT_RC_OK;
+ }
+ }
+#endif
+ }
+ (void) (HOOK_CONNECT(hook_connect, callback))
+ (hook_connect->callback_data, buffer[0] - '0');
+ unhook (hook_connect);
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * network_connect_with_fork: connect with fork (called by hook_connect() only!)
+ */
+
+void
+network_connect_with_fork (struct t_hook *hook_connect)
+{
+ int child_pipe[2];
+#ifndef __CYGWIN__
+ pid_t pid;
+#endif
+
+#ifdef HAVE_GNUTLS
+ /* initialize GnuTLS if SSL asked */
+ if (HOOK_CONNECT(hook_connect, gnutls_sess))
+ {
+ if (gnutls_init (HOOK_CONNECT(hook_connect, gnutls_sess), GNUTLS_CLIENT) != 0)
+ {
+ (void) (HOOK_CONNECT(hook_connect, callback))
+ (hook_connect->callback_data,
+ '0' + WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR);
+ unhook (hook_connect);
+ return;
+ }
+ gnutls_set_default_priority (*HOOK_CONNECT(hook_connect, gnutls_sess));
+ gnutls_certificate_type_set_priority (*HOOK_CONNECT(hook_connect, gnutls_sess),
+ gnutls_cert_type_prio);
+ gnutls_protocol_set_priority (*HOOK_CONNECT(hook_connect, gnutls_sess),
+ gnutls_prot_prio);
+ gnutls_credentials_set (*HOOK_CONNECT(hook_connect, gnutls_sess),
+ GNUTLS_CRD_CERTIFICATE,
+ gnutls_xcred);
+ gnutls_transport_set_ptr (*HOOK_CONNECT(hook_connect, gnutls_sess),
+ (gnutls_transport_ptr) ((unsigned long) HOOK_CONNECT(hook_connect, sock)));
+ }
+#endif
+
+ /* create pipe for child process */
+ if (pipe (child_pipe) < 0)
+ {
+ (void) (HOOK_CONNECT(hook_connect, callback))
+ (hook_connect->callback_data,
+ '0' + WEECHAT_HOOK_CONNECT_MEMORY_ERROR);
+ unhook (hook_connect);
+ return;
+ }
+ HOOK_CONNECT(hook_connect, child_read) = child_pipe[0];
+ HOOK_CONNECT(hook_connect, child_write) = child_pipe[1];
+
+#ifdef __CYGWIN__
+ /* connection may block under Cygwin, there's no other known way
+ to do better today, since connect() in child process seems not to work
+ any suggestion is welcome to improve that!
+ */
+ network_connect_child (hook_connect);
+ network_connect_child_read_cb (hook_connect);
+#else
+ switch (pid = fork ())
+ {
+ /* fork failed */
+ case -1:
+ (void) (HOOK_CONNECT(hook_connect, callback))
+ (hook_connect->callback_data,
+ '0' + WEECHAT_HOOK_CONNECT_MEMORY_ERROR);
+ unhook (hook_connect);
+ return;
+ /* child process */
+ case 0:
+ setuid (getuid ());
+ network_connect_child (hook_connect);
+ _exit (EXIT_SUCCESS);
+ }
+ /* parent process */
+ HOOK_CONNECT(hook_connect, child_pid) = pid;
+ HOOK_CONNECT(hook_connect, hook_fd) = hook_fd (NULL,
+ HOOK_CONNECT(hook_connect, child_read),
+ 1, 0, 0,
+ network_connect_child_read_cb,
+ hook_connect);
+#endif
+}
diff --git a/src/core/wee-network.h b/src/core/wee-network.h
index cf4c61f73..1b6e4cf5c 100644
--- a/src/core/wee-network.h
+++ b/src/core/wee-network.h
@@ -20,7 +20,12 @@
#ifndef __WEECHAT_NETWORK_H
#define __WEECHAT_NETWORK_H 1
+struct t_hook;
+
+extern void network_init ();
+extern void network_end ();
extern int network_pass_proxy (int sock, char *address, int port);
extern int network_connect_to (int sock, unsigned long address, int port);
+extern void network_connect_with_fork (struct t_hook *);
#endif /* wee-network.h */
diff --git a/src/core/weechat.c b/src/core/weechat.c
index 44f622cad..8a4fa6388 100644
--- a/src/core/weechat.c
+++ b/src/core/weechat.c
@@ -56,6 +56,7 @@
#include "wee-debug.h"
#include "wee-hook.h"
#include "wee-log.h"
+#include "wee-network.h"
#include "wee-string.h"
#include "wee-utf8.h"
#include "wee-util.h"
@@ -347,6 +348,8 @@ weechat_shutdown (int return_code, int crash)
log_close ();
if (weechat_local_charset)
free (weechat_local_charset);
+
+ network_end ();
if (crash)
abort();
@@ -374,6 +377,7 @@ main (int argc, char *argv[])
weechat_local_charset = strdup ("");
#endif
utf8_init ();
+ network_init ();
util_catch_signal (SIGINT, SIG_IGN); /* ignore SIGINT signal */
util_catch_signal (SIGQUIT, SIG_IGN); /* ignore SIGQUIT signal */
diff --git a/src/gui/curses/Makefile.am b/src/gui/curses/Makefile.am
index afaa1227c..7f2b59d5f 100644
--- a/src/gui/curses/Makefile.am
+++ b/src/gui/curses/Makefile.am
@@ -25,7 +25,8 @@ weechat_curses_LDADD = ./../../core/lib_weechat_core.a \
../lib_weechat_gui_common.a \
../../core/lib_weechat_core.a \
$(PLUGINS_LFLAGS) \
- $(NCURSES_LFLAGS)
+ $(NCURSES_LFLAGS) \
+ $(GNUTLS_LFLAGS)
weechat_curses_SOURCES = gui-curses-bar.c \
gui-curses-chat.c \
diff --git a/src/gui/gtk/Makefile.am b/src/gui/gtk/Makefile.am
index 03192e8cc..a3b89bc17 100644
--- a/src/gui/gtk/Makefile.am
+++ b/src/gui/gtk/Makefile.am
@@ -25,7 +25,8 @@ weechat_gtk_LDADD = ./../../core/lib_weechat_core.a \
../lib_weechat_gui_common.a \
../../core/lib_weechat_core.a \
$(PLUGINS_LFLAGS) \
- $(GTK_LFLAGS)
+ $(GTK_LFLAGS) \
+ $(GNUTLS_LFLAGS)
weechat_gtk_SOURCES = gui-gtk-bar.c \
gui-gtk-chat.c \
diff --git a/src/plugins/irc/irc-command.c b/src/plugins/irc/irc-command.c
index dbb6d1644..4498fceac 100644
--- a/src/plugins/irc/irc-command.c
+++ b/src/plugins/irc/irc-command.c
@@ -496,7 +496,7 @@ irc_command_connect_one_server (struct t_irc_server *server, int no_join)
server->name);
return 0;
}
- if (server->child_pid > 0)
+ if (server->hook_connect)
{
weechat_printf (NULL,
_("%s%s: currently connecting to server "
@@ -576,7 +576,7 @@ irc_command_connect (void *data, struct t_gui_buffer *buffer, int argc,
ptr_server = ptr_server->next_server)
{
nb_connect++;
- if (!ptr_server->is_connected && (ptr_server->child_pid == 0))
+ if (!ptr_server->is_connected && (!ptr_server->hook_connect))
{
if (!irc_command_connect_one_server (ptr_server, no_join))
connect_ok = 0;
@@ -615,7 +615,7 @@ irc_command_connect (void *data, struct t_gui_buffer *buffer, int argc,
server_tmp.nicks,
server_tmp.username,
server_tmp.realname,
- server_tmp.hostname,
+ server_tmp.local_hostname,
server_tmp.command,
1, /* command_delay */
server_tmp.autojoin,
@@ -1138,7 +1138,7 @@ irc_command_disconnect_one_server (struct t_irc_server *server)
if (!server)
return 0;
- if ((!server->is_connected) && (server->child_pid == 0)
+ if ((!server->is_connected) && (!server->hook_connect)
&& (server->reconnect_start == 0))
{
weechat_printf (server->buffer,
@@ -1186,7 +1186,7 @@ irc_command_disconnect (void *data, struct t_gui_buffer *buffer, int argc,
for (ptr_server = irc_servers; ptr_server;
ptr_server = ptr_server->next_server)
{
- if ((ptr_server->is_connected) || (ptr_server->child_pid != 0)
+ if ((ptr_server->is_connected) || (ptr_server->hook_connect)
|| (ptr_server->reconnect_start != 0))
{
if (!irc_command_disconnect_one_server (ptr_server))
@@ -2373,7 +2373,7 @@ irc_command_reconnect_one_server (struct t_irc_server *server, int no_join)
if (!server)
return 0;
- if ((!server->is_connected) && (server->child_pid == 0))
+ if ((!server->is_connected) && (!server->hook_connect))
{
weechat_printf (server->buffer,
_("%s%s: not connected to server \"%s\"!"),
@@ -2427,7 +2427,7 @@ irc_command_reconnect (void *data, struct t_gui_buffer *buffer, int argc,
ptr_server = ptr_server->next_server)
{
nb_reconnect++;
- if ((ptr_server->is_connected) || (ptr_server->child_pid != 0))
+ if ((ptr_server->is_connected) || (ptr_server->hook_connect))
{
if (!irc_command_reconnect_one_server (ptr_server, no_join))
reconnect_ok = 0;
@@ -2771,7 +2771,7 @@ irc_command_server (void *data, struct t_gui_buffer *buffer, int argc,
server_tmp.nicks,
server_tmp.username,
server_tmp.realname,
- server_tmp.hostname,
+ server_tmp.local_hostname,
server_tmp.command,
1, /* command_delay */
server_tmp.autojoin,
diff --git a/src/plugins/irc/irc-config.c b/src/plugins/irc/irc-config.c
index d55719c8e..603f0a0c9 100644
--- a/src/plugins/irc/irc-config.c
+++ b/src/plugins/irc/irc-config.c
@@ -35,8 +35,8 @@
char *irc_config_server_option_string[IRC_CONFIG_NUM_SERVER_OPTIONS] =
{ "autoconnect", "autoreconnect", "autoreconnect_delay", "addresses", "ipv6",
- "ssl", "password", "nicks", "username", "realname", "hostname", "command",
- "command_delay", "autojoin", "autorejoin", "notify_levels"
+ "ssl", "password", "nicks", "username", "realname", "local_hostname",
+ "command", "command_delay", "autojoin", "autorejoin", "notify_levels"
};
char *irc_config_server_option_default[IRC_CONFIG_NUM_SERVER_OPTIONS] =
{ "off", "on", "30", "", "off", "off", "", "", "", "", "", "", "0", "",
@@ -614,12 +614,12 @@ irc_config_server_new_option (struct t_config_file *config_file,
callback_change, callback_change_data,
callback_delete, callback_delete_data);
break;
- case IRC_CONFIG_SERVER_HOSTNAME:
+ case IRC_CONFIG_SERVER_LOCAL_HOSTNAME:
new_option = weechat_config_new_option (
config_file, section,
option_name, "string",
- N_("custom hostname/IP for server (optional, if empty local hostname "
- "is used)"),
+ N_("custom local hostname/IP for server (optional, if empty "
+ "local hostname is used)"),
NULL, 0, 0, value, NULL, NULL,
callback_change, callback_change_data,
callback_delete, callback_delete_data);
diff --git a/src/plugins/irc/irc-config.h b/src/plugins/irc/irc-config.h
index dc161d94a..2610749af 100644
--- a/src/plugins/irc/irc-config.h
+++ b/src/plugins/irc/irc-config.h
@@ -38,7 +38,7 @@ enum t_irc_config_server_option
IRC_CONFIG_SERVER_NICKS,
IRC_CONFIG_SERVER_USERNAME,
IRC_CONFIG_SERVER_REALNAME,
- IRC_CONFIG_SERVER_HOSTNAME,
+ IRC_CONFIG_SERVER_LOCAL_HOSTNAME,
IRC_CONFIG_SERVER_COMMAND,
IRC_CONFIG_SERVER_COMMAND_DELAY,
IRC_CONFIG_SERVER_AUTOJOIN,
diff --git a/src/plugins/irc/irc-display.c b/src/plugins/irc/irc-display.c
index 855652fd6..fa4034360 100644
--- a/src/plugins/irc/irc-display.c
+++ b/src/plugins/irc/irc-display.c
@@ -193,9 +193,9 @@ irc_display_server (struct t_irc_server *server, int with_detail)
weechat_printf (NULL, " realname . . . . . : %s",
(server->realname && server->realname[0]) ?
server->realname : "");
- weechat_printf (NULL, " hostname . . . . . : %s",
- (server->hostname && server->hostname[0]) ?
- server->hostname : "");
+ weechat_printf (NULL, " local_hostname . . : %s",
+ (server->local_hostname && server->local_hostname[0]) ?
+ server->local_hostname : "");
if (server->command && server->command[0])
string = strdup (server->command);
else
diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c
index 63270e728..651b05fc8 100644
--- a/src/plugins/irc/irc-server.c
+++ b/src/plugins/irc/irc-server.c
@@ -22,18 +22,11 @@
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
-#include <signal.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <time.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
#include "../weechat-plugin.h"
#include "irc.h"
@@ -53,17 +46,6 @@ struct t_irc_server *last_irc_server = NULL;
struct t_irc_message *irc_recv_msgq = NULL;
struct t_irc_message *irc_msgq_last_msg = NULL;
-#ifdef HAVE_GNUTLS
-const int gnutls_cert_type_prio[] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010700
- const int gnutls_prot_prio[] = { GNUTLS_TLS1_2, GNUTLS_TLS1_1,
- GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
-#else
- const int gnutls_prot_prio[] = { GNUTLS_TLS1_1, GNUTLS_TLS1_0,
- GNUTLS_SSL3, 0 };
-#endif
-#endif
-
/*
* irc_server_set_addresses: set addresses for server
@@ -205,10 +187,10 @@ irc_server_set_with_option (struct t_irc_server *server,
free (server->realname);
server->realname = strdup (weechat_config_string (option));
break;
- case IRC_CONFIG_SERVER_HOSTNAME:
- if (server->hostname)
- free (server->hostname);
- server->hostname = strdup (weechat_config_string (option));
+ case IRC_CONFIG_SERVER_LOCAL_HOSTNAME:
+ if (server->local_hostname)
+ free (server->local_hostname);
+ server->local_hostname = strdup (weechat_config_string (option));
break;
case IRC_CONFIG_SERVER_COMMAND:
if (server->command)
@@ -280,7 +262,7 @@ irc_server_init (struct t_irc_server *server)
server->nicks = NULL;
server->username = NULL;
server->realname = NULL;
- server->hostname = NULL;
+ server->local_hostname = NULL;
server->command = NULL;
server->command_delay = IRC_CONFIG_SERVER_DEFAULT_COMMAND_DELAY;
server->autojoin = NULL;
@@ -293,10 +275,8 @@ irc_server_init (struct t_irc_server *server)
server->addresses_array = NULL;
server->ports_array = NULL;
server->current_address = 0;
- server->child_pid = 0;
- server->child_read = -1;
- server->child_write = -1;
server->sock = -1;
+ server->hook_connect = NULL;
server->hook_fd = NULL;
server->is_connected = 0;
server->ssl_connected = 0;
@@ -598,8 +578,8 @@ irc_server_free_data (struct t_irc_server *server)
free (server->username);
if (server->realname)
free (server->realname);
- if (server->hostname)
- free (server->hostname);
+ if (server->local_hostname)
+ free (server->local_hostname);
if (server->command)
free (server->command);
if (server->autojoin)
@@ -677,7 +657,7 @@ struct t_irc_server *
irc_server_new (char *name, int autoconnect, int autoreconnect,
int autoreconnect_delay, int temp_server, char *addresses,
int ipv6, int ssl, char *password, char *nicks,
- char *username, char *realname, char *hostname,
+ char *username, char *realname, char *local_hostname,
char *command, int command_delay, char *autojoin,
int autorejoin, char *notify_levels)
{
@@ -690,12 +670,12 @@ irc_server_new (char *name, int autoconnect, int autoreconnect,
{
weechat_log_printf ("Creating new server (name:%s, addresses:%s, "
"pwd:%s, nicks:%s, username:%s, realname:%s, "
- "hostname: %s, command:%s, autojoin:%s, "
+ "local_hostname: %s, command:%s, autojoin:%s, "
"autorejoin:%s, notify_levels:%s)",
name, addresses, (password) ? password : "",
(nicks) ? nicks : "", (username) ? username : "",
(realname) ? realname : "",
- (hostname) ? hostname : "",
+ (local_hostname) ? local_hostname : "",
(command) ? command : "",
(autojoin) ? autojoin : "",
(autorejoin) ? "on" : "off",
@@ -719,8 +699,8 @@ irc_server_new (char *name, int autoconnect, int autoreconnect,
(username) ? strdup (username) : strdup ("weechat");
new_server->realname =
(realname) ? strdup (realname) : strdup ("realname");
- new_server->hostname =
- (hostname) ? strdup (hostname) : NULL;
+ new_server->local_hostname =
+ (local_hostname) ? strdup (local_hostname) : NULL;
new_server->command =
(command) ? strdup (command) : NULL;
new_server->command_delay = command_delay;
@@ -763,7 +743,7 @@ irc_server_duplicate (struct t_irc_server *server, char *new_name)
server->nicks,
server->username,
server->realname,
- server->hostname,
+ server->local_hostname,
server->command,
server->command_delay,
server->autojoin,
@@ -1599,47 +1579,22 @@ irc_server_timer_check_away (void *empty)
}
/*
- * irc_server_child_kill: kill child process and close pipe
- */
-
-void
-irc_server_child_kill (struct t_irc_server *server)
-{
- /* kill process */
- if (server->child_pid > 0)
- {
- kill (server->child_pid, SIGKILL);
- waitpid (server->child_pid, NULL, 0);
- server->child_pid = 0;
- }
-
- /* close pipe used with child */
- if (server->child_read != -1)
- {
- close (server->child_read);
- server->child_read = -1;
- }
- if (server->child_write != -1)
- {
- close (server->child_write);
- server->child_write = -1;
- }
-}
-
-/*
* irc_server_close_connection: close server connection
- * (kill child, close socket/pipes)
*/
void
irc_server_close_connection (struct t_irc_server *server)
{
+ if (server->hook_connect)
+ {
+ weechat_unhook (server->hook_connect);
+ server->hook_connect = NULL;
+ }
if (server->hook_fd)
{
weechat_unhook (server->hook_fd);
server->hook_fd = NULL;
}
- irc_server_child_kill (server);
/* close network socket */
if (server->sock != -1)
@@ -1743,257 +1698,102 @@ irc_server_switch_address (struct t_irc_server *server)
}
/*
- * irc_server_child_read_cb: read connection progress from child process
+ * irc_server_connect_cb: read connection status
*/
int
-irc_server_child_read_cb (void *arg_server)
+irc_server_connect_cb (void *arg_server, int status)
{
struct t_irc_server *server;
- char buffer[1];
- int num_read;
int config_proxy_use;
server = (struct t_irc_server *)arg_server;
- num_read = read (server->child_read, buffer, sizeof (buffer));
- if (num_read > 0)
- {
- config_proxy_use = weechat_config_boolean (
- weechat_config_get ("weechat.proxy.use"));
- switch (buffer[0])
- {
- /* connection OK */
- case '0':
- /* enable SSL if asked */
-#ifdef HAVE_GNUTLS
- if (server->ssl_connected)
- {
- gnutls_transport_set_ptr (server->gnutls_sess,
- (gnutls_transport_ptr) ((unsigned long) server->sock));
- if (gnutls_handshake (server->gnutls_sess) < 0)
- {
- weechat_printf (server->buffer,
- _("%s%s: GnuTLS handshake failed"),
- weechat_prefix ("error"), "irc");
- irc_server_close_connection (server);
- irc_server_switch_address (server);
- return WEECHAT_RC_OK;
- }
- }
-#endif
- /* kill child and login to server */
- weechat_unhook (server->hook_fd);
- irc_server_child_kill (server);
- irc_server_login (server);
- server->hook_fd = weechat_hook_fd (server->sock,
- 1, 0, 0,
- irc_server_recv_cb,
- server);
- break;
- /* adress not found */
- case '1':
- weechat_printf (server->buffer,
- (config_proxy_use) ?
- _("%s%s: proxy address \"%s\" not found") :
- _("%s%s: address \"%s\" not found"),
- weechat_prefix ("error"), "irc",
- server->addresses_array[server->current_address]);
- irc_server_close_connection (server);
- irc_server_switch_address (server);
- break;
- /* IP address not found */
- case '2':
- weechat_printf (server->buffer,
- (config_proxy_use) ?
- _("%s%s: proxy IP address not found") :
- _("%s%s: IP address not found"),
- weechat_prefix ("error"), "irc");
- irc_server_close_connection (server);
- irc_server_switch_address (server);
- break;
- /* connection refused */
- case '3':
- weechat_printf (server->buffer,
- (config_proxy_use) ?
- _("%s%s: proxy connection refused") :
- _("%s%s: connection refused"),
- weechat_prefix ("error"), "irc");
- irc_server_close_connection (server);
- irc_server_switch_address (server);
- break;
- /* proxy fails to connect to server */
- case '4':
- weechat_printf (server->buffer,
- _("%s%s: proxy fails to establish "
- "connection to server "
- "(check username/password if used "
- "and if IRC server address/port is "
- "allowed by proxy)"),
- weechat_prefix ("error"), "irc");
- irc_server_close_connection (server);
- irc_server_switch_address (server);
- break;
- /* fails to set local hostname/IP */
- case '5':
- weechat_printf (server->buffer,
- _("%s%s: unable to set local hostname/IP"),
- weechat_prefix ("error"), "irc");
- irc_server_close_connection (server);
- irc_server_reconnect_schedule (server);
- break;
- }
- }
-
- return WEECHAT_RC_OK;
-}
-
-/*
- * irc_server_child: child process trying to connect to server
- */
-
-int
-irc_server_child (struct t_irc_server *server)
-{
- struct addrinfo hints, *res, *res_local;
- int rc;
- int config_proxy_use, config_proxy_ipv6, config_proxy_port;
- char *config_proxy_address;
+ server->hook_connect = NULL;
- res = NULL;
- res_local = NULL;
-
config_proxy_use = weechat_config_boolean (
weechat_config_get ("weechat.proxy.use"));
- config_proxy_ipv6 = weechat_config_integer (
- weechat_config_get ("weechat.proxy.ipv6"));
- config_proxy_port = weechat_config_integer (
- weechat_config_get ("weechat.proxy.port"));
- config_proxy_address = weechat_config_string (
- weechat_config_get ("weechat.proxy.address"));
- if (config_proxy_use)
- {
- /* get info about server */
- memset (&hints, 0, sizeof (hints));
- hints.ai_family = (config_proxy_ipv6) ? AF_INET6 : AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- if (getaddrinfo (config_proxy_address, NULL, &hints, &res) !=0)
- {
- write (server->child_write, "1", 1);
- return 0;
- }
- if (!res)
- {
- write (server->child_write, "1", 1);
- return 0;
- }
- if ((config_proxy_ipv6 && (res->ai_family != AF_INET6))
- || ((!config_proxy_ipv6 && (res->ai_family != AF_INET))))
- {
- write (server->child_write, "2", 1);
- freeaddrinfo (res);
- return 0;
- }
-
- if (config_proxy_ipv6)
- ((struct sockaddr_in6 *)(res->ai_addr))->sin6_port = htons (config_proxy_port);
- else
- ((struct sockaddr_in *)(res->ai_addr))->sin_port = htons (config_proxy_port);
-
- /* connect to server */
- if (connect (server->sock, res->ai_addr, res->ai_addrlen) != 0)
- {
- write (server->child_write, "3", 1);
- freeaddrinfo (res);
- return 0;
- }
-
- if (weechat_network_pass_proxy (server->sock,
- server->addresses_array[server->current_address],
- server->ports_array[server->current_address]))
- {
- write (server->child_write, "4", 1);
- freeaddrinfo (res);
- return 0;
- }
- }
- else
+ switch (status)
{
- /* set local hostname/IP if asked by user */
- if (server->hostname && server->hostname[0])
- {
- memset (&hints, 0, sizeof(hints));
- hints.ai_family = (server->ipv6) ? AF_INET6 : AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- rc = getaddrinfo (server->hostname, NULL, &hints, &res_local);
- if ((rc != 0) || !res_local
- || (server->ipv6 && (res_local->ai_family != AF_INET6))
- || ((!server->ipv6 && (res_local->ai_family != AF_INET))))
- {
- write (server->child_write, "5", 1);
- if (res_local)
- freeaddrinfo (res_local);
- return 0;
- }
- if (bind (server->sock, res_local->ai_addr, res_local->ai_addrlen) < 0)
- {
- write (server->child_write, "5", 1);
- if (res_local)
- freeaddrinfo (res_local);
- return 0;
- }
- }
-
- /* get info about server */
- memset (&hints, 0, sizeof(hints));
- hints.ai_family = (server->ipv6) ? AF_INET6 : AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- rc = getaddrinfo (server->addresses_array[server->current_address],
- NULL, &hints, &res);
- if ((rc != 0) || !res)
- {
- write (server->child_write, "1", 1);
- if (res)
- freeaddrinfo (res);
- return 0;
- }
- if ((server->ipv6 && (res->ai_family != AF_INET6))
- || ((!server->ipv6 && (res->ai_family != AF_INET))))
- {
- write (server->child_write, "2", 1);
- if (res)
- freeaddrinfo (res);
- if (res_local)
- freeaddrinfo (res_local);
- return 0;
- }
-
- /* connect to server */
- if (server->ipv6)
- ((struct sockaddr_in6 *)(res->ai_addr))->sin6_port =
- htons (server->ports_array[server->current_address]);
- else
- ((struct sockaddr_in *)(res->ai_addr))->sin_port =
- htons (server->ports_array[server->current_address]);
-
- if (connect (server->sock, res->ai_addr, res->ai_addrlen) != 0)
- {
- write (server->child_write, "3", 1);
- if (res)
- freeaddrinfo (res);
- if (res_local)
- freeaddrinfo (res_local);
- return 0;
- }
+ case WEECHAT_HOOK_CONNECT_OK:
+ /* login to server */
+ irc_server_login (server);
+ server->hook_fd = weechat_hook_fd (server->sock,
+ 1, 0, 0,
+ irc_server_recv_cb,
+ server);
+ break;
+ case WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND:
+ weechat_printf (server->buffer,
+ (config_proxy_use) ?
+ _("%s%s: proxy address \"%s\" not found") :
+ _("%s%s: address \"%s\" not found"),
+ weechat_prefix ("error"), "irc",
+ server->addresses_array[server->current_address]);
+ irc_server_close_connection (server);
+ irc_server_switch_address (server);
+ break;
+ case WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND:
+ weechat_printf (server->buffer,
+ (config_proxy_use) ?
+ _("%s%s: proxy IP address not found") :
+ _("%s%s: IP address not found"),
+ weechat_prefix ("error"), "irc");
+ irc_server_close_connection (server);
+ irc_server_switch_address (server);
+ break;
+ case WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED:
+ weechat_printf (server->buffer,
+ (config_proxy_use) ?
+ _("%s%s: proxy connection refused") :
+ _("%s%s: connection refused"),
+ weechat_prefix ("error"), "irc");
+ irc_server_close_connection (server);
+ irc_server_switch_address (server);
+ break;
+ case WEECHAT_HOOK_CONNECT_PROXY_ERROR:
+ weechat_printf (server->buffer,
+ _("%s%s: proxy fails to establish "
+ "connection to server "
+ "(check username/password if used "
+ "and if IRC server address/port is "
+ "allowed by proxy)"),
+ weechat_prefix ("error"), "irc");
+ irc_server_close_connection (server);
+ irc_server_switch_address (server);
+ break;
+ case WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR:
+ weechat_printf (server->buffer,
+ _("%s%s: unable to set local hostname/IP"),
+ weechat_prefix ("error"), "irc");
+ irc_server_close_connection (server);
+ irc_server_reconnect_schedule (server);
+ break;
+ case WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR:
+ weechat_printf (server->buffer,
+ _("%s%s: GnuTLS init error"),
+ weechat_prefix ("error"), "irc");
+ irc_server_close_connection (server);
+ irc_server_reconnect_schedule (server);
+ break;
+ case WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR:
+ weechat_printf (server->buffer,
+ _("%s%s: GnuTLS handshake failed"),
+ weechat_prefix ("error"), "irc");
+ irc_server_close_connection (server);
+ irc_server_switch_address (server);
+ break;
+ case WEECHAT_HOOK_CONNECT_MEMORY_ERROR:
+ weechat_printf (server->buffer,
+ _("%s%s: not enough memory"),
+ weechat_prefix ("error"), "irc");
+ irc_server_close_connection (server);
+ irc_server_reconnect_schedule (server);
+ break;
}
- write (server->child_write, "0", 1);
- if (res)
- freeaddrinfo (res);
- if (res_local)
- freeaddrinfo (res_local);
- return 0;
+ return WEECHAT_RC_OK;
}
/*
@@ -2005,10 +1805,7 @@ irc_server_child (struct t_irc_server *server)
int
irc_server_connect (struct t_irc_server *server, int disable_autojoin)
{
- int child_pipe[2], set;
-#ifndef __CYGWIN__
- pid_t pid;
-#endif
+ int set;
char *config_proxy_type, *config_proxy_address;
int config_proxy_use, config_proxy_ipv6, config_proxy_port;
@@ -2105,42 +1902,9 @@ irc_server_connect (struct t_irc_server *server, int disable_autojoin)
(server->ssl) ? " (SSL)" : "");
}
- /* close any opened connection and kill child process if running */
+ /* close connection if open */
irc_server_close_connection (server);
- /* init SSL if asked */
- server->ssl_connected = 0;
-#ifdef HAVE_GNUTLS
- if (server->ssl)
- {
- if (gnutls_init (&server->gnutls_sess, GNUTLS_CLIENT) != 0)
- {
- weechat_printf (server->buffer,
- _("%s%s: GnuTLS init error"),
- weechat_prefix ("error"), "irc");
- return 0;
- }
- gnutls_set_default_priority (server->gnutls_sess);
- gnutls_certificate_type_set_priority (server->gnutls_sess,
- gnutls_cert_type_prio);
- gnutls_protocol_set_priority (server->gnutls_sess, gnutls_prot_prio);
- gnutls_credentials_set (server->gnutls_sess, GNUTLS_CRD_CERTIFICATE,
- gnutls_xcred);
- server->ssl_connected = 1;
- }
-#endif
-
- /* create pipe for child process */
- if (pipe (child_pipe) < 0)
- {
- weechat_printf (server->buffer,
- _("%s%s: cannot create pipe"),
- weechat_prefix ("error"), "irc");
- return 0;
- }
- server->child_read = child_pipe[0];
- server->child_write = child_pipe[1];
-
/* create socket and set options */
if (config_proxy_use)
server->sock = socket ((config_proxy_ipv6) ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
@@ -2175,38 +1939,25 @@ irc_server_connect (struct t_irc_server *server, int disable_autojoin)
"\"SO_KEEPALIVE\""),
weechat_prefix ("error"), "irc");
}
-
-#ifdef __CYGWIN__
- /* connection may block under Cygwin, there's no other known way
- to do better today, since connect() in child process seems not to work
- any suggestion is welcome to improve that!
- */
- irc_server_child (server);
- server->child_pid = 0;
- irc_server_child_read (server);
-#else
- switch (pid = fork ())
- {
- /* fork failed */
- case -1:
- irc_server_close_connection (server);
- return 0;
- /* child process */
- case 0:
- setuid (getuid ());
- irc_server_child (server);
- _exit (EXIT_SUCCESS);
- }
- /* parent process */
- server->child_pid = pid;
- server->hook_fd = weechat_hook_fd (server->child_read,
- 1, 0, 0,
- irc_server_child_read_cb,
- server);
+
+ /* init SSL if asked */
+ server->ssl_connected = 0;
+#ifdef HAVE_GNUTLS
+ if (server->ssl)
+ server->ssl_connected = 1;
#endif
server->disable_autojoin = disable_autojoin;
+ server->hook_connect = weechat_hook_connect (server->addresses_array[server->current_address],
+ server->ports_array[server->current_address],
+ server->sock,
+ server->ipv6,
+ (server->ssl_connected) ? &server->gnutls_sess : NULL,
+ server->local_hostname,
+ irc_server_connect_cb,
+ server);
+
return 1;
}
@@ -2809,10 +2560,8 @@ irc_server_print_log ()
weechat_log_printf (" addresses_count . . : %d", ptr_server->addresses_count);
weechat_log_printf (" addresses_array . . : 0x%x", ptr_server->addresses_array);
weechat_log_printf (" ports_array . . . . : 0x%x", ptr_server->ports_array);
- weechat_log_printf (" child_pid . . . . . : %d", ptr_server->child_pid);
- weechat_log_printf (" child_read . . . . : %d", ptr_server->child_read);
- weechat_log_printf (" child_write . . . . : %d", ptr_server->child_write);
weechat_log_printf (" sock. . . . . . . . : %d", ptr_server->sock);
+ weechat_log_printf (" hook_connect. . . . : 0x%x", ptr_server->hook_connect);
weechat_log_printf (" hook_fd . . . . . . : 0x%x", ptr_server->hook_fd);
weechat_log_printf (" is_connected. . . . : %d", ptr_server->is_connected);
weechat_log_printf (" ssl_connected . . . : %d", ptr_server->ssl_connected);
diff --git a/src/plugins/irc/irc-server.h b/src/plugins/irc/irc-server.h
index b63c18526..136ddf022 100644
--- a/src/plugins/irc/irc-server.h
+++ b/src/plugins/irc/irc-server.h
@@ -69,7 +69,7 @@ struct t_irc_server
char *nicks; /* nicknames as one string */
char *username; /* user name */
char *realname; /* real name */
- char *hostname; /* custom hostname */
+ char *local_hostname; /* custom local hostname */
char *command; /* command to run once connected */
int command_delay; /* delay after execution of command */
char *autojoin; /* channels to automatically join */
@@ -82,15 +82,13 @@ struct t_irc_server
char **addresses_array; /* exploded addresses */
int *ports_array; /* ports for addresses */
int current_address; /* current address index in array */
- pid_t child_pid; /* pid of child process (connecting) */
- int child_read; /* to read into child pipe */
- int child_write; /* to write into child pipe */
int sock; /* socket for server (IPv4 or IPv6) */
- struct t_hook *hook_fd; /* hook for server socket or child pipe */
+ struct t_hook *hook_connect; /* connection hook */
+ struct t_hook *hook_fd; /* hook for server socket */
int is_connected; /* 1 if WeeChat is connected to server */
int ssl_connected; /* = 1 if connected with SSL */
#ifdef HAVE_GNUTLS
- gnutls_session gnutls_sess; /* gnutls session (only if SSL is used) */
+ gnutls_session_t gnutls_sess; /* gnutls session (only if SSL is used) */
#endif
char *unterminated_message; /* beginning of a message in input buf */
int nicks_count; /* number of nicknames */
diff --git a/src/plugins/irc/irc.c b/src/plugins/irc/irc.c
index c07e5ce1d..ee9f24481 100644
--- a/src/plugins/irc/irc.c
+++ b/src/plugins/irc/irc.c
@@ -46,10 +46,6 @@ struct t_weechat_plugin *weechat_irc_plugin = NULL;
struct t_hook *irc_hook_timer = NULL;
struct t_hook *irc_hook_timer_check_away = NULL;
-#ifdef HAVE_GNUTLS
-gnutls_certificate_credentials gnutls_xcred; /* gnutls client credentials */
-#endif
-
/*
* irc_signal_quit_cb: callback for "quit" signal
@@ -89,13 +85,6 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[])
weechat_plugin = plugin;
-#ifdef HAVE_GNUTLS
- /* init GnuTLS */
- gnutls_global_init ();
- gnutls_certificate_allocate_credentials (&gnutls_xcred);
- gnutls_certificate_set_x509_trust_file (gnutls_xcred, "ca.pem", GNUTLS_X509_FMT_PEM);
-#endif
-
if (!irc_config_init ())
return WEECHAT_RC_ERROR;
@@ -168,11 +157,5 @@ weechat_plugin_end (struct t_weechat_plugin *plugin)
//irc_dcc_end ();
irc_server_free_all ();
-#ifdef HAVE_GNUTLS
- /* GnuTLS end */
- gnutls_certificate_free_credentials (gnutls_xcred);
- gnutls_global_deinit();
-#endif
-
return WEECHAT_RC_OK;
}
diff --git a/src/plugins/irc/irc.h b/src/plugins/irc/irc.h
index f00c7922f..38b54d446 100644
--- a/src/plugins/irc/irc.h
+++ b/src/plugins/irc/irc.h
@@ -68,8 +68,4 @@ extern struct t_hook *irc_hook_timer_check_away;
extern int irc_debug;
-#ifdef HAVE_GNUTLS
-extern gnutls_certificate_credentials gnutls_xcred;
-#endif
-
#endif /* irc.h */
diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c
index 250c0481f..734385c47 100644
--- a/src/plugins/plugin.c
+++ b/src/plugins/plugin.c
@@ -364,6 +364,7 @@ plugin_load (char *filename)
new_plugin->hook_command = &hook_command;
new_plugin->hook_timer = &hook_timer;
new_plugin->hook_fd = &hook_fd;
+ new_plugin->hook_connect = &hook_connect;
new_plugin->hook_print = &hook_print;
new_plugin->hook_signal = &hook_signal;
new_plugin->hook_signal_send = &hook_signal_send;
diff --git a/src/plugins/weechat-plugin.h b/src/plugins/weechat-plugin.h
index 8d49971a7..68e89b3ce 100644
--- a/src/plugins/weechat-plugin.h
+++ b/src/plugins/weechat-plugin.h
@@ -58,6 +58,17 @@ struct t_weelist;
#define WEECHAT_HOTLIST_PRIVATE "2"
#define WEECHAT_HOTLIST_HIGHLIGHT "3"
+/* connect status for connection hooked */
+#define WEECHAT_HOOK_CONNECT_OK 0
+#define WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND 1
+#define WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND 2
+#define WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED 3
+#define WEECHAT_HOOK_CONNECT_PROXY_ERROR 4
+#define WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR 5
+#define WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR 6
+#define WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR 7
+#define WEECHAT_HOOK_CONNECT_MEMORY_ERROR 8
+
/* type of data for signal hooked */
#define WEECHAT_HOOK_SIGNAL_STRING "string"
#define WEECHAT_HOOK_SIGNAL_INT "int"
@@ -280,6 +291,12 @@ struct t_weechat_plugin
int flag_exception,
int (*callback)(void *data),
void *callback_data);
+ struct t_hook *(*hook_connect) (struct t_weechat_plugin *plugin,
+ char *address, int port,
+ int sock, int ipv6, void *gnutls_sess,
+ char *local_hostname,
+ int (*callback)(void *data, int status),
+ void *callback_data);
struct t_hook *(*hook_print) (struct t_weechat_plugin *plugin,
struct t_gui_buffer *buffer,
char *tags, char *message,
@@ -711,6 +728,12 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin);
weechat_plugin->hook_fd(weechat_plugin, __fd, __flag_read, \
__flag_write, __flag_exception, __callback, \
__data)
+#define weechat_hook_connect(__address, __port, __sock, __ipv6, \
+ __gnutls_sess, __local_hostname, \
+ __callback, __data) \
+ weechat_plugin->hook_connect(weechat_plugin, __address, __port, \
+ __sock, __ipv6, __gnutls_sess, \
+ __local_hostname, __callback, __data)
#define weechat_hook_print(__buffer, __tags, __msg, __strip__colors, \
__callback, __data) \
weechat_plugin->hook_print(weechat_plugin, __buffer, __tags, \