Index: include/client.h
===================================================================
RCS file: /cvsroot/ircd-ratbox/include/client.h,v
retrieving revision 7.206.2.9
diff -u -r7.206.2.9 client.h
--- include/client.h	25 Mar 2004 00:30:45 -0000	7.206.2.9
+++ include/client.h	12 Jun 2004 14:26:01 -0000
@@ -353,6 +353,10 @@
 #define FLAGS_MARK	   0x20000	/* marked client */
 #define FLAGS_HIDDEN       0x40000	/* hidden server */
 #define FLAGS_EOB          0x80000	/* EOB */
+#ifdef ENABLE_FAKE_CLIENTS
+#define FLAGS_FAKE        0x400000
+#define FLAGS_FAKEPERSIST  0x800000
+#endif
 /* umodes, settable flags */
 
 #define UMODE_SERVNOTICE   0x0001	/* server notices such as kill */
@@ -458,7 +462,10 @@
 #define ClearEob(x)		((x)->flags &= ~FLAGS_EOB)
 #define SetEob(x)		((x)->flags |= FLAGS_EOB)
 #define HasSentEob(x)		((x)->flags & FLAGS_EOB)
-
+#ifdef ENABLE_FAKE_CLIENTS
+#define IsFake(x)		((x)->flags & FLAGS_FAKE)
+#define IsFakePersist(x)	((x)->flags & FLAGS_FAKEPERSIST)
+#endif
 
 /* oper flags */
 #define MyOper(x)               (MyConnect(x) && IsOper(x))
@@ -591,5 +598,13 @@
 extern struct User *make_user(struct Client *);
 extern struct Server *make_server(struct Client *);
 
+#ifdef ENABLE_FAKE_CLIENTS
+extern struct Client *create_fake_client(const char *name, const char *username,
+					const char *host, const char *gecos, int);
+extern void destroy_fake_client(struct Client *);
+
+extern struct Client *create_fake_server(const char *name, const char *gecos, int persist);
+extern void destroy_fake_server(struct Client *, int send_squit);
+#endif
 
 #endif /* INCLUDED_client_h */
Index: include/hook.h
===================================================================
RCS file: /cvsroot/ircd-ratbox/include/hook.h,v
retrieving revision 1.22.2.4
diff -u -r1.22.2.4 hook.h
--- include/hook.h	28 Mar 2004 01:31:12 -0000	1.22.2.4
+++ include/hook.h	12 Jun 2004 14:26:01 -0000
@@ -82,6 +82,15 @@
 	struct Channel *chptr;
 };
 
+#ifdef ENABLE_FAKE_CLIENTS
+struct h_fake_message_data
+{
+	struct Client *target_p;
+	const char *message;
+	int direct;
+	int notice;
+};
+#endif
 
 int hook_add_event(const char *, int *);
 int hook_add_hook(const char *, hookfn );
@@ -105,5 +114,12 @@
 extern int h_doing_stats_id;
 extern int h_doing_stats_p_id;
 extern int h_doing_trace_id;
+#ifdef ENABLE_FAKE_CLIENTS
+extern int h_fake_kill_id;
+extern int h_fake_skill_id;
+extern int h_fake_squit_id;
+extern int h_fake_message_id;
+extern int h_fake_collision_id;
+#endif
 
 #endif
Index: modules/m_whois.c
===================================================================
RCS file: /cvsroot/ircd-ratbox/modules/m_whois.c,v
retrieving revision 1.120.2.8
diff -u -r1.120.2.8 m_whois.c
--- modules/m_whois.c	20 May 2004 12:06:37 -0000	1.120.2.8
+++ modules/m_whois.c	12 Jun 2004 14:26:01 -0000
@@ -355,7 +355,11 @@
 				   GlobalSetOptions.operstring);
 	}
 
+#ifdef ENABLE_FAKE_CLIENTS
+	if(MyClient(target_p) && !IsFake(target_p))
+#else
 	if(MyClient(target_p))
+#endif
 	{
 	  /* send idle if its global, source == target, or source and target
 	   * are both local and theres no serverhiding or source is opered
Index: modules/core/m_kill.c
===================================================================
RCS file: /cvsroot/ircd-ratbox/modules/core/m_kill.c,v
retrieving revision 1.82.2.9
diff -u -r1.82.2.9 m_kill.c
--- modules/core/m_kill.c	20 May 2004 12:06:44 -0000	1.82.2.9
+++ modules/core/m_kill.c	12 Jun 2004 14:26:01 -0000
@@ -40,6 +40,8 @@
 #include "msg.h"
 #include "parse.h"
 #include "modules.h"
+#include "s_user.h"
+#include "hook.h"
 
 
 static char buf[BUFSIZE];
@@ -129,6 +131,15 @@
 		return;
 	}
 
+#ifdef ENABLE_FAKE_CLIENTS
+	if(IsFake(target_p))
+	{
+		sendto_one(source_p, ":%s NOTICE %s :Cannot kill a service",
+				me.name, source_p->name);
+		return;
+	}
+#endif
+
 	if(MyConnect(target_p))
 		sendto_one(target_p, ":%s!%s@%s KILL %s :%s",
 			   source_p->name, source_p->username, source_p->host,
@@ -278,6 +289,20 @@
 
 	relay_kill(client_p, source_p, target_p, path, reason);
 
+#ifdef ENABLE_FAKE_CLIENTS
+	/* let the kill relay everywhere, then reintroduce client */
+	if(IsFake(target_p))
+	{
+		introduce_client(NULL, target_p, target_p->user, target_p->name);
+
+		if(IsServer(source_p))
+			hook_call_event(h_fake_skill_id, target_p);
+		else
+			hook_call_event(h_fake_kill_id, target_p);
+		return;
+	}
+#endif
+
 	/* FLAGS_KILLED prevents a quit being sent out */
 	target_p->flags |= FLAGS_KILLED;
 
Index: modules/core/m_message.c
===================================================================
RCS file: /cvsroot/ircd-ratbox/modules/core/m_message.c,v
retrieving revision 1.131.2.7
diff -u -r1.131.2.7 m_message.c
--- modules/core/m_message.c	20 May 2004 12:06:44 -0000	1.131.2.7
+++ modules/core/m_message.c	12 Jun 2004 14:26:01 -0000
@@ -44,7 +44,7 @@
 #include "class.h"
 #include "msg.h"
 #include "packet.h"
-
+#include "hook.h"
 
 struct entity
 {
@@ -535,6 +535,20 @@
 		sendto_one(source_p, form_str(RPL_AWAY), me.name,
 			   source_p->name, target_p->name, target_p->user->away);
 
+#ifdef ENABLE_FAKE_CLIENTS
+	if(IsFake(target_p))
+	{
+		struct h_fake_message_data hd;
+		hd.target_p = target_p;
+		hd.message = text;
+		hd.direct = 1;
+		hd.notice = p_or_n;
+
+		hook_call_event(h_fake_message_id, &hd);
+		return;
+	}
+#endif
+		
 	if(MyClient(target_p))
 	{
 		/* XXX Controversial? allow opers always to send through a +g */
@@ -794,6 +808,20 @@
 			if(host != NULL)
 				*--host = '%';
 
+#ifdef ENABLE_FAKE_CLIENTS
+			if(IsFake(target_p))
+			{	
+				struct h_fake_message_data hd;
+				hd.target_p = target_p;
+				hd.message = text;
+				hd.direct = 0;
+				hd.notice = p_or_n;
+
+				hook_call_event(h_fake_message_id, &hd);
+				return;
+			}
+#endif
+				
 			if(count == 1)
 				sendto_anywhere(target_p, source_p, "%s %s :%s", command,
 						nick, text);
Index: modules/core/m_nick.c
===================================================================
RCS file: /cvsroot/ircd-ratbox/modules/core/m_nick.c,v
retrieving revision 1.122.2.6
diff -u -r1.122.2.6 m_nick.c
--- modules/core/m_nick.c	20 May 2004 12:06:44 -0000	1.122.2.6
+++ modules/core/m_nick.c	12 Jun 2004 14:26:01 -0000
@@ -47,7 +47,7 @@
 #include "modules.h"
 #include "common.h"
 #include "packet.h"
-
+#include "hook.h"
 
 static void mr_nick(struct Client *, struct Client *, int, char **);
 static void m_nick(struct Client *, struct Client *, int, char **);
@@ -643,6 +643,17 @@
 					     "Nick collision on %s(%s <- %s)(both killed)",
 					     target_p->name, target_p->from->name, client_p->name);
 
+#ifdef ENABLE_FAKE_CLIENTS
+			if(IsFake(target_p))
+			{
+				kill_client_serv_butone(NULL, target_p, 
+							"%s (Nickname Collision)", me.name);
+				introduce_client(NULL, target_p, target_p->user, target_p->name);
+				hook_call_event(h_fake_collision_id, target_p);
+				return 0;
+			}
+#endif
+
 			kill_client_serv_butone(NULL, target_p,
 						"%s (Nick collision (new))", me.name);
 			ServerStats->is_kill++;
@@ -681,6 +692,18 @@
 							     target_p->name, target_p->from->name,
 							     client_p->name);
 
+#ifdef ENABLE_FAKE_CLIENTS
+				if(IsFake(target_p))
+				{
+					kill_client_serv_butone(NULL, target_p,
+								"%s (Nickname Collision)",
+								me.name);
+					introduce_client(NULL, target_p, target_p->user, target_p->name);
+					hook_call_event(h_fake_collision_id, target_p);
+					return 0;
+				}
+#endif
+
 				ServerStats->is_kill++;
 				sendto_one(target_p, form_str(ERR_NICKCOLLISION),
 					   me.name, target_p->name, target_p->name);
@@ -709,20 +732,33 @@
 				     client_p->name);
 
 		ServerStats->is_kill++;
-		sendto_one(target_p, form_str(ERR_NICKCOLLISION),
-			   me.name, target_p->name, target_p->name);
 
 		/* if we got the message from a LL, it knows about source_p */
 		kill_client_serv_butone(NULL, source_p, "%s (Nick change collision)", me.name);
 
+		source_p->flags |= FLAGS_KILLED;
+		exit_client(client_p, source_p, &me, "Nick collision(old)");
+
+#ifdef ENABLE_FAKE_CLIENTS
+		if(IsFake(target_p))
+		{
+			kill_client_serv_butone(NULL, target_p,
+						"%s (Nickname collision)", me.name);
+			introduce_client(NULL, target_p, target_p->user, target_p->name);
+			hook_call_event(h_fake_collision_id, target_p);
+			return 0;
+		}
+#endif
+
+		sendto_one(target_p, form_str(ERR_NICKCOLLISION),
+			   me.name, target_p->name, target_p->name);
+
 		ServerStats->is_kill++;
 
 		kill_client_serv_butone(NULL, target_p, "%s (Nick change collision)", me.name);
 
 		target_p->flags |= FLAGS_KILLED;
 		exit_client(NULL, target_p, &me, "Nick collision(new)");
-		source_p->flags |= FLAGS_KILLED;
-		exit_client(client_p, source_p, &me, "Nick collision(old)");
 		return 0;
 	}
 	else
@@ -771,6 +807,18 @@
 						     target_p->name, target_p->from->name,
 						     client_p->name);
 
+#ifdef ENABLE_FAKE_CLIENTS
+			if(IsFake(target_p))
+			{
+				kill_client_serv_butone(NULL, target_p, 
+							"%s (Nickname collision)",
+							me.name);
+				introduce_client(NULL, target_p, target_p->user, target_p->name);
+				hook_call_event(h_fake_collision_id, target_p);
+				return 0;
+			}
+#endif
+
 			kill_client_serv_butone(source_p, target_p, "%s (Nick collision)", me.name);
 
 			ServerStats->is_kill++;
Index: modules/core/m_squit.c
===================================================================
RCS file: /cvsroot/ircd-ratbox/modules/core/m_squit.c,v
retrieving revision 1.67.2.3
diff -u -r1.67.2.3 m_squit.c
--- modules/core/m_squit.c	20 May 2004 12:06:45 -0000	1.67.2.3
+++ modules/core/m_squit.c	12 Jun 2004 14:26:01 -0000
@@ -38,6 +38,7 @@
 #include "msg.h"
 #include "parse.h"
 #include "modules.h"
+#include "hook.h"
 
 static void ms_squit(struct Client *, struct Client *, int, char **);
 static void mo_squit(struct Client *, struct Client *, int, char **);
@@ -96,6 +97,15 @@
 
 	if((found_squit = find_squit(client_p, source_p, parv[1])))
 	{
+#ifdef ENABLE_FAKE_CLIENTS
+		if(IsFake(found_squit->target_p))
+		{
+			sendto_one(source_p, ":%s NOTICE %s :Cannot squit a service",
+					me.name, source_p->name);
+			return;
+		}
+#endif
+				
 		if(MyConnect(found_squit->target_p))
 		{
 			sendto_realops_flags(UMODE_ALL, L_ALL,
@@ -135,6 +145,42 @@
 
 	if((found_squit = find_squit(client_p, source_p, parv[1])))
 	{
+#ifdef ENABLE_FAKE_CLIENTS
+		if(IsFake(found_squit->target_p))
+		{
+			if(!IsFakePersist(found_squit->target_p))
+				hook_call_event(h_fake_squit_id, found_squit->target_p);
+
+			sendto_wallops_flags(UMODE_WALLOP, &me,
+					     "Remote SQUIT %s from %s (%s)",
+					     found_squit->server_name, source_p->name, comment);
+
+			sendto_server(NULL, NULL, NOCAPS, NOCAPS,
+				      ":%s WALLOPS :Remote SQUIT %s from %s (%s)",
+				      me.name, found_squit->server_name, source_p->name, comment);
+
+			ilog(L_TRACE, "SQUIT From %s : %s (%s)", parv[0],
+			     found_squit->server_name, comment);
+
+			sendto_server(client_p, NULL, NOCAPS, NOCAPS,
+					"SQUIT %s :%s",
+					found_squit->target_p->name, me.name);
+
+			if(IsFakePersist(found_squit->target_p))
+			{
+				sendto_server(NULL, NULL, NOCAPS, NOCAPS,
+						":%s SERVER %s 2 :%s",
+						me.name, found_squit->target_p->name,
+						found_squit->target_p->info);
+				hook_call_event(h_fake_squit_id, found_squit->target_p);
+			}
+			else
+				destroy_fake_server(found_squit->target_p, 0);
+
+			return;
+		}
+#endif
+
 		/*
 		 **  Notify all opers, if my local link is remotely squitted
 		 */
Index: src/client.c
===================================================================
RCS file: /cvsroot/ircd-ratbox/src/client.c,v
retrieving revision 7.385.2.15
diff -u -r7.385.2.15 client.c
--- src/client.c	25 Mar 2004 00:30:54 -0000	7.385.2.15
+++ src/client.c	12 Jun 2004 14:26:01 -0000
@@ -2072,3 +2072,137 @@
 		BlockHeapFree(user_heap, user);
 	}
 }
+
+#ifdef ENABLE_FAKE_CLIENTS
+struct Client *
+create_fake_client(const char *name, const char *username, const char *host,
+		const char *gecos, int opered)
+{
+	struct Client *fake_p;
+
+	if((fake_p = find_client(name)))
+	{
+		kill_client_serv_butone(NULL, fake_p,
+					"%s (In use by services)", me.name);
+		fake_p->flags |= FLAGS_KILLED;
+		exit_client(NULL, fake_p, &me, "In use by services");
+	}
+
+	fake_p = BlockHeapAlloc(client_heap);
+	memset(fake_p, 0, sizeof(struct Client));
+
+	make_user(fake_p);
+
+	fake_p->localClient = (struct LocalUser *) BlockHeapAlloc(lclient_heap);
+	memset(fake_p->localClient, 0, sizeof(struct LocalUser));
+
+	fake_p->from = fake_p;
+
+	strlcpy(fake_p->name, name, sizeof(fake_p->name));
+	strlcpy(fake_p->username, username, sizeof(fake_p->username));
+	strlcpy(fake_p->host, host, sizeof(fake_p->host));
+	strlcpy(fake_p->info, gecos, sizeof(fake_p->info));
+
+	fake_p->hopcount = 0;
+	fake_p->tsinfo = 1;
+	fake_p->flags = FLAGS_FAKE;
+	fake_p->localClient->fd = -1;
+
+	fake_p->umodes = UMODE_INVISIBLE;
+	
+	if(opered)
+		fake_p->umodes |= UMODE_OPER;
+
+	fake_p->user->server = me.name;
+	fake_p->servptr = find_server(me.name);
+
+	add_to_client_hash_table(fake_p->name, fake_p);
+
+	SetClient(fake_p);
+	SetDead(fake_p);
+
+	dlinkAddTail(fake_p, &fake_p->node, &global_client_list);
+
+	introduce_client(NULL, fake_p, fake_p->user, fake_p->name);
+
+	return fake_p;
+}
+
+void
+destroy_fake_client(struct Client *fake_p)
+{
+	sendto_server(NULL, NULL, NOCAPS, NOCAPS,
+			":%s QUIT :Service unloaded", fake_p->name);
+
+	del_from_client_hash_table(fake_p->name, fake_p);
+
+	dlinkDelete(&fake_p->node, &global_client_list);
+	free_user(fake_p->user, fake_p);
+	BlockHeapFree(lclient_heap, fake_p->localClient);
+	BlockHeapFree(client_heap, fake_p);
+}
+
+struct Client *
+create_fake_server(const char *name, const char *gecos, int persist)
+{
+	struct Client *fake_p;
+
+	if((fake_p = find_server(name)))
+		return NULL;
+
+	fake_p = BlockHeapAlloc(client_heap);
+	memset(fake_p, 0, sizeof(struct Client));
+
+	make_server(fake_p);
+
+	fake_p->localClient = BlockHeapAlloc(lclient_heap);
+	memset(fake_p->localClient, 0, sizeof(struct LocalUser));
+
+	fake_p->from = fake_p;
+	fake_p->serv->up = me.name;
+	fake_p->servptr = &me;
+
+	strlcpy(fake_p->name, name, sizeof(fake_p->name));
+	strlcpy(fake_p->info, gecos, sizeof(fake_p->info));
+
+	fake_p->hopcount = 1;
+	fake_p->flags = FLAGS_FAKE;
+	fake_p->localClient->fd = -1;
+
+	if(persist)
+		fake_p->flags |= FLAGS_FAKEPERSIST;
+
+	add_to_client_hash_table(fake_p->name, fake_p);
+
+	SetServer(fake_p);
+	SetDead(fake_p);
+
+	dlinkAddTail(fake_p, &fake_p->node, &global_client_list);
+	dlinkAddTailAlloc(fake_p, &global_serv_list);
+
+	sendto_server(NULL, NULL, NOCAPS, NOCAPS,
+			":%s SERVER %s 2 :%s",
+			me.name, fake_p->name, fake_p->info);
+
+	return fake_p;
+}
+
+void
+destroy_fake_server(struct Client *fake_p, int send_squit)
+{
+	if(send_squit)
+		sendto_server(NULL, NULL, NOCAPS, NOCAPS,
+				":%s SQUIT %s :Service unloaded",
+				me.name, fake_p->name);
+
+	del_from_client_hash_table(fake_p->name, fake_p);
+
+	dlinkDelete(&fake_p->node, &global_client_list);
+	dlinkFindDestroy(&global_serv_list, fake_p);
+
+	MyFree(fake_p->serv);
+	BlockHeapFree(lclient_heap, fake_p->localClient);
+	BlockHeapFree(client_heap, fake_p);
+}
+#endif
+
Index: src/hook.c
===================================================================
RCS file: /cvsroot/ircd-ratbox/src/hook.c,v
retrieving revision 7.28.2.2
diff -u -r7.28.2.2 hook.c
--- src/hook.c	27 Mar 2004 23:02:13 -0000	7.28.2.2
+++ src/hook.c	12 Jun 2004 14:26:02 -0000
@@ -51,6 +51,13 @@
 int h_doing_stats_id;
 int h_doing_stats_p_id;
 int h_doing_trace_id;
+#ifdef ENABLE_FAKE_CLIENTS
+int h_fake_kill_id;
+int h_fake_skill_id;
+int h_fake_message_id;
+int h_fake_squit_id;
+int h_fake_collision_id;
+#endif
 
 void
 init_hooks(void)
@@ -71,6 +78,13 @@
 	hook_add_event("doing_stats", &h_doing_stats_id);
 	hook_add_event("doing_stats_p", &h_doing_stats_p_id);
 	hook_add_event("doing_trace", &h_doing_trace_id);
+#ifdef ENABLE_FAKE_CLIENTS
+	hook_add_event("fake_kill", &h_fake_kill_id);
+	hook_add_event("fake_skill", &h_fake_skill_id);
+	hook_add_event("fake_message", &h_fake_message_id);
+	hook_add_event("fake_squit", &h_fake_squit_id);
+	hook_add_event("fake_collision", &h_fake_collision_id);
+#endif
 }
 
 static int hook_curid = 0;
Index: src/send.c
===================================================================
RCS file: /cvsroot/ircd-ratbox/src/send.c,v
retrieving revision 7.246.2.12
diff -u -r7.246.2.12 send.c
--- src/send.c	5 Apr 2004 00:29:46 -0000	7.246.2.12
+++ src/send.c	12 Jun 2004 14:26:02 -0000
@@ -137,6 +137,11 @@
 		return 0;
 	}
 
+#ifdef ENABLE_FAKE_CLIENTS
+	if(IsFake(to))
+		return 0;
+#endif
+
 	if(IsDead(to) || to->localClient->fd == -1)
 		return 0;
 
@@ -252,6 +257,11 @@
 	if(IsDead(to))
 		return;
 
+#ifdef ENABLE_FAKE_CLIENTS
+	if(IsFake(to))
+		return;
+#endif
+
 	/* Next, lets try to write some data */
 #ifndef NDEBUG
 	hdata.connection = to;
@@ -380,6 +390,11 @@
 	if(IsDead(to))
 		return;		/* This socket has already been marked as dead */
 
+#ifdef ENABLE_FAKE_CLIENTS
+	if(IsFake(to))
+		return;
+#endif
+
 	/* send remote if to->from non NULL */
 	if(to->from)
 		to = to->from;
@@ -485,6 +500,11 @@
 		if(target_p->from == one || IsDead(target_p))
 			continue;
 
+#ifdef ENABLE_FAKE_CLIENTS
+		if(IsFake(target_p))
+			continue;
+#endif
+
 		if(MyConnect(target_p) && IsRegisteredUser(target_p))
 		{
 			if(target_p->serial != current_serial)
@@ -894,6 +914,11 @@
 		if(IsMe(target_p) || target_p->from == source_p->from)
 			continue;
 
+#ifdef ENABLE_FAKE_CLIENTS
+		if(IsFake(target_p))
+			continue;
+#endif
+
 		if(target_p->from->serial == current_serial)
 			continue;
 
