summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorTingPing <tingping@fedoraproject.org>2014-06-14 12:07:47 -0400
committerTingPing <tingping@tingping.se>2014-12-30 06:35:42 -0500
commitfef580ed7faaba17e2c8fea504b8587850502220 (patch)
treef0a9be7563888a6cb321e167f700d2498bbd08ca
parent3bb717a3b58240209df8275a9a64ee77516f531a (diff)
Rewrite identd
- Use gio (which is cross platform)
- Properly support multiple users
- Allow configuring port
- Allow other plugins overriding
-rw-r--r--po/POTFILES.in1
-rw-r--r--src/common/Makefile.am3
-rw-r--r--src/common/cfgfiles.c2
-rw-r--r--src/common/common.vcxproj4
-rw-r--r--src/common/common.vcxproj.filters12
-rw-r--r--src/common/hexchat.c2
-rw-r--r--src/common/hexchat.h1
-rw-r--r--src/common/identd.c195
-rw-r--r--src/common/plugin-identd.c216
-rw-r--r--src/common/plugin-identd.h (renamed from src/common/identd.h)9
-rw-r--r--src/common/server.c49
11 files changed, 260 insertions, 234 deletions
diff --git a/po/POTFILES.in b/po/POTFILES.in
index fa918608..c2a5ede1 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -10,6 +10,7 @@ src/common/inbound.c
 src/common/notify.c
 src/common/outbound.c
 src/common/plugin.c
+src/common/plugin-identd.c
 src/common/plugin-timer.c
 src/common/server.c
 src/common/servlist.c
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 0cbf650b..ea941671 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -26,6 +26,7 @@ EXTRA_DIST = \
 	notify.h \
 	outbound.h \
 	plugin.h \
+	plugin-identd.h \
 	plugin-timer.h \
 	proto-irc.h \
 	server.h \
@@ -60,7 +61,7 @@ noinst_PROGRAMS = make-te
 
 libhexchatcommon_a_SOURCES = cfgfiles.c chanopt.c ctcp.c dcc.c hexchat.c \
 	history.c ignore.c inbound.c marshal.c modes.c network.c notify.c \
-	outbound.c plugin.c plugin-timer.c proto-irc.c server.c servlist.c \
+	outbound.c plugin.c plugin-identd.c plugin-timer.c proto-irc.c server.c servlist.c \
 	$(ssl_c) text.c tree.c url.c userlist.c util.c
 libhexchatcommon_a_CFLAGS = $(LIBPROXY_CFLAGS)
 
diff --git a/src/common/cfgfiles.c b/src/common/cfgfiles.c
index 54694452..8ed31c4f 100644
--- a/src/common/cfgfiles.c
+++ b/src/common/cfgfiles.c
@@ -477,6 +477,7 @@ const struct prefs vars[] =
 	{"gui_win_width", P_OFFINT (hex_gui_win_width), TYPE_INT},
 
 	{"identd", P_OFFINT (hex_identd), TYPE_BOOL},
+	{"identd_port", P_OFFINT (hex_identd_port), TYPE_INT},
 
 	{"input_balloon_chans", P_OFFINT (hex_input_balloon_chans), TYPE_BOOL},
 	{"input_balloon_hilight", P_OFFINT (hex_input_balloon_hilight), TYPE_BOOL},
@@ -772,7 +773,6 @@ load_default_config(void)
 	prefs.hex_gui_ulist_resizable = 1;
 	prefs.hex_gui_ulist_style = 1;
 	prefs.hex_gui_win_save = 1;
-	prefs.hex_identd = 1;
 	prefs.hex_input_flash_hilight = 1;
 	prefs.hex_input_flash_priv = 1;
 	prefs.hex_input_tray_hilight = 1;
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj
index 7746a866..b52b06c7 100644
--- a/src/common/common.vcxproj
+++ b/src/common/common.vcxproj
@@ -20,7 +20,6 @@
     <ClInclude Include="dcc.h" />

     <ClInclude Include="fe.h" />

     <ClInclude Include="history.h" />

-    <ClInclude Include="identd.h" />

     <ClInclude Include="ignore.h" />

     <ClInclude Include="inbound.h" />

     <ClInclude Include="inet.h" />

@@ -29,6 +28,7 @@
     <ClInclude Include="network.h" />

     <ClInclude Include="notify.h" />

     <ClInclude Include="outbound.h" />

+    <ClInclude Include="plugin-identd.h" />

     <ClInclude Include="plugin-timer.h" />

     <ClInclude Include="plugin.h" />

     <ClInclude Include="proto-irc.h" />

@@ -53,7 +53,7 @@
     <ClCompile Include="ctcp.c" />

     <ClCompile Include="dcc.c" />

     <ClCompile Include="history.c" />

-    <ClCompile Include="identd.c" />

+    <ClCompile Include="plugin-identd.c" />

     <ClCompile Include="ignore.c" />

     <ClCompile Include="inbound.c" />

     <ClCompile Include="marshal.c" />

diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters
index 5039f3d5..e80d9a63 100644
--- a/src/common/common.vcxproj.filters
+++ b/src/common/common.vcxproj.filters
@@ -29,9 +29,6 @@
     <ClInclude Include="history.h">

       <Filter>Header Files</Filter>

     </ClInclude>

-    <ClInclude Include="identd.h">

-      <Filter>Header Files</Filter>

-    </ClInclude>

     <ClInclude Include="ignore.h">

       <Filter>Header Files</Filter>

     </ClInclude>

@@ -110,6 +107,9 @@
     <ClInclude Include="marshal.h">

       <Filter>Header Files</Filter>

     </ClInclude>

+    <ClInclude Include="plugin-identd.h">

+      <Filter>Header Files</Filter>

+    </ClInclude>

   </ItemGroup>

   <ItemGroup>

     <ClCompile Include="cfgfiles.c">

@@ -127,9 +127,6 @@
     <ClCompile Include="history.c">

       <Filter>Source Files</Filter>

     </ClCompile>

-    <ClCompile Include="identd.c">

-      <Filter>Source Files</Filter>

-    </ClCompile>

     <ClCompile Include="ignore.c">

       <Filter>Source Files</Filter>

     </ClCompile>

@@ -187,6 +184,9 @@
     <ClCompile Include="marshal.c">

       <Filter>Source Files</Filter>

     </ClCompile>

+    <ClCompile Include="plugin-identd.c">

+      <Filter>Source Files</Filter>

+    </ClCompile>

   </ItemGroup>

   <ItemGroup>

     <None Include="..\..\win32\config.h.tt" />

diff --git a/src/common/hexchat.c b/src/common/hexchat.c
index 021c5838..71ea9791 100644
--- a/src/common/hexchat.c
+++ b/src/common/hexchat.c
@@ -42,6 +42,7 @@
 #include "ignore.h"
 #include "hexchat-plugin.h"
 #include "plugin.h"
+#include "plugin-identd.h"
 #include "plugin-timer.h"
 #include "notify.h"
 #include "server.h"
@@ -388,6 +389,7 @@ irc_init (session *sess)
 	done_init = TRUE;
 
 	plugin_add (sess, NULL, NULL, timer_plugin_init, NULL, NULL, FALSE);
+	plugin_add (sess, NULL, NULL, identd_plugin_init, identd_plugin_deinit, NULL, FALSE);
 
 #ifdef USE_PLUGIN
 	if (!arg_skip_plugins)
diff --git a/src/common/hexchat.h b/src/common/hexchat.h
index c1acfe45..dfb1c52f 100644
--- a/src/common/hexchat.h
+++ b/src/common/hexchat.h
@@ -263,6 +263,7 @@ struct hexchatprefs
 	int hex_gui_win_state;
 	int hex_gui_win_top;
 	int hex_gui_win_width;
+	int hex_identd_port;
 	int hex_input_balloon_time;
 	int hex_irc_ban_type;
 	int hex_irc_join_delay;
diff --git a/src/common/identd.c b/src/common/identd.c
deleted file mode 100644
index 183d4a0e..00000000
--- a/src/common/identd.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/* HexChat
- * Copyright (C) 1998-2010 Peter Zelezny.
- * Copyright (C) 2009-2013 Berke Viktor.
- *
- * 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 2 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* simple identd server for HexChat under Win32 */
-
-#include "inet.h"
-#include "hexchat.h"
-#include "hexchatc.h"
-#include "text.h"
-
-static int identd_is_running = FALSE;
-static int identd_ipv6_is_running = FALSE;
-
-static int
-identd (char *username)
-{
-	int sok, read_sok, len;
-	char *p;
-	char buf[256];
-	char outbuf[256];
-	char ipbuf[INET_ADDRSTRLEN];
-	struct sockaddr_in addr;
-
-	sok = socket (AF_INET, SOCK_STREAM, 0);
-	if (sok == INVALID_SOCKET)
-	{
-		g_free (username);
-		return 0;
-	}
-
-	len = 1;
-	setsockopt (sok, SOL_SOCKET, SO_REUSEADDR, (char *) &len, sizeof (len));
-
-	memset (&addr, 0, sizeof (addr));
-	addr.sin_family = AF_INET;
-	addr.sin_port = htons (113);
-
-	if (bind (sok, (struct sockaddr *) &addr, sizeof (addr)) == SOCKET_ERROR)
-	{
-		closesocket (sok);
-		g_free (username);
-		return 0;
-	}
-
-	if (listen (sok, 1) == SOCKET_ERROR)
-	{
-		closesocket (sok);
-		g_free (username);
-		return 0;
-	}
-
-	len = sizeof (addr);
-	read_sok = accept (sok, (struct sockaddr *) &addr, &len);
-	closesocket (sok);
-	if (read_sok == INVALID_SOCKET)
-	{
-		g_free (username);
-		return 0;
-	}
-
-	identd_is_running = FALSE;
-
-#if 0	/* causes random crashes, probably due to CreateThread */
-	EMIT_SIGNAL (XP_TE_IDENTD, current_sess, inet_ntoa (addr.sin_addr), username, NULL, NULL, 0);
-#endif
-	inet_ntop (AF_INET, &addr.sin_addr, ipbuf, sizeof (ipbuf));
-	g_snprintf (outbuf, sizeof (outbuf), "*\tServicing ident request from %s as %s\n", ipbuf, username);
-	PrintText (current_sess, outbuf);
-
-	recv (read_sok, buf, sizeof (buf) - 1, 0);
-	buf[sizeof (buf) - 1] = 0;	  /* ensure null termination */
-
-	p = strchr (buf, ',');
-	if (p)
-	{
-		g_snprintf (outbuf, sizeof (outbuf) - 1, "%d, %d : USERID : UNIX : %s\r\n",
-					 atoi (buf), atoi (p + 1), username);
-		outbuf[sizeof (outbuf) - 1] = 0;	/* ensure null termination */
-		send (read_sok, outbuf, strlen (outbuf), 0);
-	}
-
-	sleep (1);
-	closesocket (read_sok);
-	g_free (username);
-
-	return 0;
-}
-
-static int
-identd_ipv6 (char *username)
-{
-	int sok, read_sok, len;
-	char *p;
-	char buf[256];
-	char outbuf[256];
-	char ipbuf[INET6_ADDRSTRLEN];
-	struct sockaddr_in6 addr;
-
-	sok = socket (AF_INET6, SOCK_STREAM, 0);
-	if (sok == INVALID_SOCKET)
-	{
-		g_free (username);
-		return 0;
-	}
-
-	len = 1;
-	setsockopt (sok, SOL_SOCKET, SO_REUSEADDR, (char *) &len, sizeof (len));
-
-	memset (&addr, 0, sizeof (addr));
-	addr.sin6_family = AF_INET6;
-	addr.sin6_port = htons (113);
-
-	if (bind (sok, (struct sockaddr *) &addr, sizeof (addr)) == SOCKET_ERROR)
-	{
-		closesocket (sok);
-		g_free (username);
-		return 0;
-	}
-
-	if (listen (sok, 1) == SOCKET_ERROR)
-	{
-		closesocket (sok);
-		g_free (username);
-		return 0;
-	}
-
-	len = sizeof (addr);
-	read_sok = accept (sok, (struct sockaddr *) &addr, &len);
-	closesocket (sok);
-	if (read_sok == INVALID_SOCKET)
-	{
-		g_free (username);
-		return 0;
-	}
-
-	identd_ipv6_is_running = FALSE;
-
-	inet_ntop (AF_INET6, &addr.sin6_addr, ipbuf, sizeof (ipbuf));
-	g_snprintf (outbuf, sizeof (outbuf), "*\tServicing ident request from %s as %s\n", ipbuf, username);
-	PrintText (current_sess, outbuf);
-
-	recv (read_sok, buf, sizeof (buf) - 1, 0);
-	buf[sizeof (buf) - 1] = 0;	  /* ensure null termination */
-
-	p = strchr (buf, ',');
-	if (p)
-	{
-		g_snprintf (outbuf, sizeof (outbuf) - 1, "%d, %d : USERID : UNIX : %s\r\n", atoi (buf), atoi (p + 1), username);
-		outbuf[sizeof (outbuf) - 1] = 0;	/* ensure null termination */
-		send (read_sok, outbuf, strlen (outbuf), 0);
-	}
-
-	sleep (1);
-	closesocket (read_sok);
-	g_free (username);
-
-	return 0;
-}
-
-void
-identd_start (char *username)
-{
-	DWORD tid;
-
-	DWORD tidv6;
-	if (identd_ipv6_is_running == FALSE)
-	{
-		identd_ipv6_is_running = TRUE;
-		CloseHandle (CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) identd_ipv6,
-						 g_strdup (username), 0, &tidv6));
-	}
-
-	if (identd_is_running == FALSE)
-	{
-		identd_is_running = TRUE;
-		CloseHandle (CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) identd,
-						 g_strdup (username), 0, &tid));
-	}
-}
diff --git a/src/common/plugin-identd.c b/src/common/plugin-identd.c
new file mode 100644
index 00000000..753fde05
--- /dev/null
+++ b/src/common/plugin-identd.c
@@ -0,0 +1,216 @@
+/* HexChat
+*
+* 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 2 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, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+#include "config.h"
+
+#include <string.h>
+#include <gio/gio.h>
+#include "hexchat-plugin.h"
+
+#define _(x) hexchat_gettext(ph,x)
+
+static hexchat_plugin *ph;
+static GSocketService *service;
+static GHashTable *responses;
+
+struct ident_info
+{
+	GSocketConnection *conn;
+	gchar *username;
+	gchar read_buf[16];
+} typedef ident_info;
+
+static int
+identd_cleanup_response_cb (gpointer userdata)
+{
+	g_return_val_if_fail (responses != NULL, 0);
+
+	g_hash_table_remove (responses, userdata);
+
+	return 0;
+}
+
+static int
+identd_command_cb (char *word[], char *word_eol[], void *userdata)
+{
+	g_return_val_if_fail (responses != NULL, HEXCHAT_EAT_ALL);
+
+	if (word[2] && *word[2] && word[3] && *word[3])
+	{
+		guint64 port = g_ascii_strtoull (word[2], NULL, 0);
+
+		if (port && port <= G_MAXUINT16)
+		{
+			g_hash_table_insert (responses, GINT_TO_POINTER (port), g_strdup (word[3]));
+			/* Automatically remove entry after 30 seconds */
+			hexchat_hook_timer (ph, 30000, identd_cleanup_response_cb, GINT_TO_POINTER (port));
+		}
+	}
+	else
+	{
+		hexchat_command (ph, "HELP IDENTD");
+	}
+
+	return HEXCHAT_EAT_HEXCHAT;
+}
+
+static void
+identd_write_ready (GOutputStream *stream, GAsyncResult *res, ident_info *info)
+{
+	g_output_stream_write_finish (stream, res, NULL);
+
+	g_free (info->username);
+	g_object_unref (info->conn);
+	g_free (info);
+}
+
+static void
+identd_read_ready (GInputStream *in_stream, GAsyncResult *res, ident_info *info)
+{
+	GSocketAddress *sok_addr;
+	GOutputStream *out_stream;
+	guint64 local, remote;
+	gchar buf[512], *p;
+
+	if (g_input_stream_read_finish (in_stream, res, NULL))
+	{
+		local = g_ascii_strtoull (info->read_buf, NULL, 0);
+		p = strchr (info->read_buf, ',');
+		if (!p)
+			goto cleanup;
+
+		remote = g_ascii_strtoull (p + 1, NULL, 0);
+
+		if (!local || !remote || local > G_MAXUINT16 || remote > G_MAXUINT16)
+			goto cleanup;
+
+		info->username = g_strdup (g_hash_table_lookup (responses, GINT_TO_POINTER (local)));
+		if (!info->username)
+			goto cleanup;
+		g_hash_table_remove (responses, GINT_TO_POINTER (local));
+
+		if ((sok_addr = g_socket_connection_get_remote_address (info->conn, NULL)))
+		{
+			GInetAddress *inet_addr;
+			gchar *addr;
+
+			inet_addr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sok_addr));
+			addr = g_inet_address_to_string (inet_addr);
+
+			hexchat_printf (ph, _("*\tServicing ident request from %s as %s"), addr, info->username);
+
+			g_object_unref (sok_addr);
+			g_object_unref (inet_addr);
+			g_free (addr);
+		}
+
+		g_snprintf (buf, sizeof (buf), "%"G_GUINT16_FORMAT", %"G_GUINT16_FORMAT" : USERID : UNIX : %s\r\n", (guint16)local, (guint16)remote, info->username);
+		out_stream = g_io_stream_get_output_stream (G_IO_STREAM (info->conn));
+		g_output_stream_write_async (out_stream, buf, strlen (buf), G_PRIORITY_DEFAULT,
+									NULL, (GAsyncReadyCallback)identd_write_ready, info);
+	}
+
+	return;
+
+cleanup:
+	g_object_unref (info->conn);
+	g_free (info);
+}
+
+static gboolean
+identd_incoming_cb (GSocketService *service, GSocketConnection *conn,
+					GObject *source, gpointer userdata)
+{
+	GInputStream *stream;
+	ident_info *info;
+
+	info = g_new0 (ident_info, 1);
+
+	info->conn = conn;
+	g_object_ref (conn);
+
+	stream = g_io_stream_get_input_stream (G_IO_STREAM (conn));
+	g_input_stream_read_async (stream, info->read_buf, sizeof (info->read_buf), G_PRIORITY_DEFAULT,
+							NULL, (GAsyncReadyCallback)identd_read_ready, info);
+
+	return TRUE;
+}
+
+static gboolean
+identd_start_server (void)
+{
+	GError *error = NULL;
+	int enabled, port = 113;
+
+	if (hexchat_get_prefs (ph, "identd", NULL, &enabled) == 3 && enabled)
+	{
+		if (!enabled)
+			return TRUE; /*...*/
+	}
+	if (hexchat_get_prefs (ph, "identd_port", NULL, &port) == 2 && (port <= 0 || port > G_MAXUINT16))
+	{
+		port = 113;
+	}
+
+	service = g_socket_service_new ();
+
+	g_socket_listener_add_inet_port (G_SOCKET_LISTENER (service), port, NULL, &error);
+	if (error)
+	{
+		hexchat_printf (ph, _("*\tError starting identd server: %s"), error->message);
+
+		g_object_unref (service);
+		return FALSE;
+	}
+	/*hexchat_printf (ph, "*\tIdentd listening on port: %d", port); */
+
+	g_signal_connect (G_OBJECT (service), "incoming", G_CALLBACK(identd_incoming_cb), NULL);
+	g_socket_service_start (service);
+
+	return TRUE;
+}
+
+int
+identd_plugin_init (hexchat_plugin *plugin_handle, char **plugin_name,
+					char **plugin_desc, char **plugin_version, char *arg)
+{
+	ph = plugin_handle;
+	*plugin_name = "";
+	*plugin_desc = "";
+	*plugin_version = "";
+
+
+	responses = g_hash_table_new_full (NULL, NULL, NULL, g_free);
+	hexchat_hook_command (ph, "IDENTD", HEXCHAT_PRI_NORM, identd_command_cb,
+						_("IDENTD <port> <username>"), NULL);
+
+	return identd_start_server ();
+}
+
+int
+identd_plugin_deinit (void)
+{
+	if (service)
+	{
+		g_socket_service_stop (service);
+		g_object_unref (service);
+	}
+
+	g_hash_table_destroy (responses);
+
+	return 1;
+}
diff --git a/src/common/identd.h b/src/common/plugin-identd.h
index 3b29135f..5efc2600 100644
--- a/src/common/identd.h
+++ b/src/common/plugin-identd.h
@@ -17,9 +17,12 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#ifndef HEXCHAT_IDENTD_H
-#define HEXCHAT_IDENTD_H
+#ifndef HEXCHAT_PLUGIN_IDENTD_H
+#define HEXCHAT_PLUGIN_IDENTD_H
 
-void identd_start (char *username);
+int identd_plugin_init (hexchat_plugin *plugin_handle, char **plugin_name,
+				char **plugin_desc, char **plugin_version, char *arg);
+
+int identd_plugin_deinit ();
 
 #endif
diff --git a/src/common/server.c b/src/common/server.c
index f3633ce5..2b34dbde 100644
--- a/src/common/server.c
+++ b/src/common/server.c
@@ -61,10 +61,6 @@
 #include "ssl.h"
 #endif
 
-#ifdef WIN32
-#include "identd.h"
-#endif
-
 #ifdef USE_LIBPROXY
 #include <proxy.h>
 #endif
@@ -944,28 +940,6 @@ server_read_child (GIOChannel *source, GIOCondition condition, server *serv)
 		waitline2 (source, ip, sizeof ip);
 		waitline2 (source, outbuf, sizeof outbuf);
 		EMIT_SIGNAL (XP_TE_CONNECT, sess, host, ip, outbuf, NULL, 0);
-#ifdef WIN32
-		if (prefs.hex_identd)
-		{
-			if (serv->network && ((ircnet *)serv->network)->user)
-			{
-				identd_start (((ircnet *)serv->network)->user);
-			}
-			else
-			{
-				identd_start (prefs.hex_irc_user_name);
-			}
-		}
-#else
-		g_snprintf (outbuf, sizeof (outbuf), "%s/auth/xchat_auth",
-					 g_get_home_dir ());
-		if (access (outbuf, X_OK) == 0)
-		{
-			g_snprintf (outbuf, sizeof (outbuf), "exec -d %s/auth/xchat_auth %s",
-						 g_get_home_dir (), prefs.hex_irc_user_name);
-			handle_command (serv->server_session, outbuf, FALSE);
-		}
-#endif
 		break;
 	case '4':						  /* success */
 		waitline2 (source, tbuf, sizeof (tbuf));
@@ -982,6 +956,29 @@ server_read_child (GIOChannel *source, GIOCondition condition, server *serv)
 			else
 				closesocket (serv->proxy_sok4);
 		}
+
+		{
+			struct sockaddr addr;
+			int addr_len = sizeof (addr);
+			guint16 port;
+
+			if (!getsockname (serv->sok, &addr, &addr_len))
+			{
+				if (addr.sa_family == AF_INET)
+					port = ntohs(((struct sockaddr_in *)&addr)->sin_port);
+				else
+					port = ntohs(((struct sockaddr_in6 *)&addr)->sin6_port);
+
+				g_snprintf (outbuf, sizeof (outbuf), "IDENTD %"G_GUINT16_FORMAT" ", port);
+				if (serv->network && ((ircnet *)serv->network)->user)
+					g_strlcat (outbuf, ((ircnet *)serv->network)->user, sizeof (outbuf));
+				else
+					g_strlcat (outbuf, prefs.hex_irc_user_name, sizeof (outbuf));
+
+				handle_command (serv->server_session, outbuf, FALSE);
+			}
+		}
+
 		server_connect_success (serv);
 		break;
 	case '5':						  /* prefs ip discovered */