diff -rdu a/include/h.h b/include/h.h
--- a/include/h.h	2016-02-05 21:36:45.000000000 +0300
+++ b/include/h.h	2016-02-08 23:22:58.000000000 +0300
@@ -264,6 +264,11 @@
 #define PREFIX_OP	0x4
 #define PREFIX_ADMIN	0x08
 #define PREFIX_OWNER	0x10
+extern void send_channel_join(aChannel *, aClient *, int notify);
+extern void sendto_channel_local_with_capability(aClient *from, unsigned int, unsigned int,
+	aChannel *chptr, char *pattern, ...) __attribute__((format(printf,5,6)));
+extern void sendto_channel_local_with_capability_butone(aClient *from, aClient *one, unsigned int, unsigned int,
+	aChannel *chptr, char *pattern, ...) __attribute__((format(printf,6,7)));
 extern void sendto_channelprefix_butone(aClient *one, aClient *from, aChannel *chptr,
     int prefix, char *pattern, ...) __attribute__((format(printf,5,6)));
 extern void sendto_channel_butone(aClient *, aClient *, aChannel *,
@@ -273,7 +278,7 @@
 extern void sendto_channel_butserv_butone(aChannel *chptr, aClient *from, aClient *one,
                                           char *pattern, ...) __attribute__((format(printf,4,5)));
 extern void sendto_common_channels(aClient *, char *, ...) __attribute__((format(printf,2,3)));
-extern void sendto_common_channels_local_butone(aClient *, int, char *, ...) __attribute__((format(printf,3,4)));
+extern void sendto_common_channels_local_butone(aClient *, unsigned int, unsigned int, char *, ...) __attribute__((format(printf,4,5)));
 extern void sendto_channel_butserv(aChannel *, aClient *, char *, ...) __attribute__((format(printf,3,4)));
 extern void sendto_match_servs(aChannel *, aClient *, char *, ...) __attribute__((format(printf,3,4)));
 extern void sendto_match_butone(aClient *, aClient *, char *, int,
diff -rdu a/include/proto.h b/include/proto.h
--- a/include/proto.h	2015-12-18 19:54:11.000000000 +0300
+++ b/include/proto.h	2016-02-08 22:48:49.000000000 +0300
@@ -40,6 +40,7 @@
 /* send.c */
 extern void sendto_one(aClient *, char *, ...) __attribute__((format(printf,2,3)));
 extern void sendto_chanops_butone(aClient *one, aChannel *chptr, char *pattern, ...) __attribute__((format(printf,3,4)));
+extern void sendto_chanops_with_capability_butone(aClient *one, aChannel *chptr, unsigned int, unsigned int, char *pattern, ...) __attribute__((format(printf,5,6)));
 extern void sendto_realops(char *pattern, ...) __attribute__((format(printf,1,2)));
 extern void sendto_channel_ntadmins(aClient *from, aChannel *chptr, char *pattern, ...) __attribute__((format(printf,3,4))); 
 
diff -rdu a/include/struct.h b/include/struct.h
--- a/include/struct.h	2015-12-18 19:54:11.000000000 +0300
+++ b/include/struct.h	2016-02-08 23:46:24.000000000 +0300
@@ -332,7 +332,8 @@
 #define	FLAGS_ID	(FLAGS_DOID|FLAGS_GOTID)
 
 #define PROTO_NOQUIT	0x0001	/* Negotiated NOQUIT protocol */
-#define PROTO_SJOIN		0x0004	/* Negotiated SJOIN protocol */
+#define PROTO_CHGHOST	0x0002	/* client supports chghost */
+#define PROTO_SJOIN	0x0004	/* Negotiated SJOIN protocol */
 #define PROTO_NICKv2	0x0008	/* Negotiated NICKv2 protocol */
 #define PROTO_SJOIN2	0x0010	/* Negotiated SJOIN2 protocol */
 #define PROTO_UMODE2	0x0020	/* Negotiated UMODE2 protocol */
@@ -345,7 +346,7 @@
 #define PROTO_TKLEXT	0x1000	/* TKL extension: 10 parameters instead of 8 (3.2RC2) */
 #define PROTO_NICKIP	0x2000  /* Send IP addresses in the NICK command */
 #define PROTO_NAMESX	0x4000  /* Send all rights in NAMES output */
-#define PROTO_CLK		0x8000	/* Send cloaked host in the NICK command (regardless of +x/-x) */
+#define PROTO_CLK	0x8000	/* Send cloaked host in the NICK command (regardless of +x/-x) */
 #define PROTO_UHNAMES	0x10000  /* Send n!u@h in NAMES */
 #define PROTO_CLICAP	0x20000  /* client capability negotiation in process */
 #define PROTO_STARTTLS	0x40000	 /* client supports STARTTLS */
@@ -354,6 +355,8 @@
 #define PROTO_ACCOUNT_NOTIFY	0x200000	/* client supports account-notify */
 #define PROTO_MLOCK		0x400000	/* server supports MLOCK */
 #define PROTO_EXTSWHOIS 0x800000	/* extended SWHOIS support */
+#define PROTO_EXTENDED_JOIN	0x1000000	/* client supports extended-join */
+
 
 /*
  * flags macros.
@@ -440,6 +443,8 @@
 /*
  * ProtoCtl options
  */
+#define NotCapable(x,cap)	(((x)->local->proto & (cap)) == 0)
+#define IsCapable(x,cap)	(((x)->local->proto & (cap)) == cap)
 #ifndef DEBUGMODE
 #define CHECKPROTO(x,y)	(((x)->local->proto & y) == y)
 #else
diff -rdu a/src/channel.c b/src/channel.c
--- a/src/channel.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/channel.c	2016-02-08 23:29:57.000000000 +0300
@@ -1297,9 +1297,11 @@
 		if ((i != 0) &&
 		    !(tmp->flags & (CHFL_CHANOWNER|CHFL_CHANPROT|CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE)))
 		{
-			sendto_chanops_butone(sptr, chptr, ":%s!%s@%s PART %s :%s", sptr->name, sptr->user->username, GetHost(sptr), chptr->chname, comment);
-		} else
-			sendto_channel_butserv_butone(chptr, sptr, sptr, ":%s PART %s :%s", sptr->name, chptr->chname, comment);
+			sendto_chanops_with_capability_butone(sptr, chptr, 0, PROTO_CHGHOST, ":%s!%s@%s PART %s :%s", sptr->name, sptr->user->username, GetHost(sptr),
+				chptr->chname, comment);
+		}
+		else
+			sendto_channel_local_with_capability_butone(sptr, sptr, 0, PROTO_CHGHOST, chptr, ":%s PART %s :%s", sptr->name, chptr->chname, comment);
 	}
 }
 
@@ -1338,9 +1340,18 @@
 		if ((k != 0) &&
 		    !(flags & (CHFL_CHANOWNER|CHFL_CHANPROT|CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE)))
 		{
-			sendto_chanops_butone(sptr, chptr, ":%s!%s@%s JOIN :%s", sptr->name, sptr->user->username, GetHost(sptr), chptr->chname);
-		} else
-			sendto_channel_butserv_butone(chptr, sptr, sptr, ":%s JOIN :%s", sptr->name, chptr->chname);
+			sendto_chanops_with_capability_butone(sptr, chptr, 0, PROTO_EXTENDED_JOIN|PROTO_CHGHOST, ":%s!%s@%s JOIN :%s",
+				sptr->name, sptr->user->username, GetHost(sptr), chptr->chname);
+			sendto_chanops_with_capability_butone(sptr, chptr, PROTO_EXTENDED_JOIN, PROTO_CHGHOST, ":%s!%s@%s JOIN %s %s :%s",
+				sptr->name, chptr->chname, (isdigit(*sptr->user->svid)) ? "*" : sptr->user->svid, sptr->info);
+		}
+		else
+		{
+			sendto_channel_local_with_capability_butone(sptr, sptr, 0, PROTO_EXTENDED_JOIN|PROTO_CHGHOST, chptr,
+				":%s JOIN :%s", sptr->name, chptr->chname);
+			sendto_channel_local_with_capability_butone(sptr, sptr, PROTO_EXTENDED_JOIN, PROTO_CHGHOST, chptr,
+				":%s JOIN %s %s :%s", sptr->name, chptr->chname, (isdigit(*sptr->user->svid)) ? "*" : sptr->user->svid, sptr->info);
+		}
 
 		/* Set the modes (if any) */
 		if (flags)
@@ -1367,13 +1378,17 @@
 					if (i < n - 1)
 						strcat(parabuf, " ");
 				}
-				sendto_channel_butserv_butone(chptr, &me, sptr, ":%s MODE %s +%s %s",
+				sendto_channel_local_with_capability_butone(&me, sptr, 0, PROTO_CHGHOST, chptr, ":%s MODE %s +%s %s",
 					me.name, chptr->chname, flagbuf, parabuf);
 			}
 		}
 		
 		tmp->flags &= ~CHFL_REJOINING; /* esthetics.. ;) */
 	}
+
+	/* Resend away message to away-notify enabled clients. */
+	if (sptr->user->away)
+		sendto_common_channels_local_butone(sptr, PROTO_AWAY_NOTIFY, PROTO_CHGHOST, ":%s AWAY :%s", sptr->name, sptr->user->away);
 }
 
 /* set_channel_mlock()
@@ -1532,3 +1547,48 @@
 		return 1;
 	}
 }
+
+void send_channel_join(aChannel *chptr, aClient *client_p, int notify)
+{
+	if (!IsClient(client_p))
+		return;
+
+	if (notify != 0)
+	{
+		if (MyClient(client_p))
+		{
+			if (IsCapable(client_p, PROTO_EXTENDED_JOIN))
+				sendto_one(client_p, ":%s!%s@%s JOIN %s %s :%s", client_p->name,
+					client_p->user->username, GetHost(client_p), chptr->chname,
+					(isdigit(*client_p->user->svid)) ? "*" : client_p->user->svid,
+					client_p->info);
+			else
+				sendto_one(client_p, ":%s!%s@%s JOIN :%s", client_p->name,
+					client_p->user->username, GetHost(client_p), chptr->chname);
+		}
+		sendto_chanops_with_capability_butone(NULL, chptr, 0, PROTO_EXTENDED_JOIN, ":%s!%s@%s JOIN :%s",
+			client_p->name, client_p->user->username, GetHost(client_p), chptr->chname);
+		sendto_chanops_with_capability_butone(NULL, chptr, PROTO_EXTENDED_JOIN, 0, ":%s!%s@%s JOIN %s %s :%s",
+			client_p->name, client_p->user->username, GetHost(client_p), chptr->chname,
+			(isdigit(*client_p->user->svid)) ? "*" : client_p->user->svid, client_p->info);
+	}
+	else
+	{
+		sendto_channel_local_with_capability(client_p, 0, PROTO_EXTENDED_JOIN, chptr, ":%s JOIN :%s",
+			client_p->name, chptr->chname);
+		sendto_channel_local_with_capability(client_p, PROTO_EXTENDED_JOIN, 0, chptr, ":%s JOIN %s %s :%s",
+			client_p->name, chptr->chname, (isdigit(*client_p->user->svid)) ? "*" : client_p->user->svid,
+			client_p->info);
+	}
+
+	/* Send away message to away-notify enabled clients. */
+	if (client_p->user->away)
+	{
+		if (notify != 0)
+			sendto_chanops_with_capability_butone(NULL, chptr, PROTO_AWAY_NOTIFY, 0, ":%s!%s@%s AWAY :%s",
+				client_p->name, client_p->user->username, GetHost(client_p), client_p->user->away);
+		else
+			sendto_channel_local_with_capability_butone(client_p, client_p, PROTO_AWAY_NOTIFY, 0, chptr, ":%s AWAY :%s",
+				client_p->name, client_p->user->away);
+	}
+}
diff -rdu a/src/modules/chanmodes/delayjoin.c b/src/modules/chanmodes/delayjoin.c
--- a/src/modules/chanmodes/delayjoin.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/modules/chanmodes/delayjoin.c	2016-02-09 00:18:42.000000000 +0300
@@ -203,8 +203,14 @@
 	for (i = chptr->members; i; i = i->next)
 	{
 		if (!is_skochanop(i->cptr,chptr) && i->cptr != sptr)
-			sendto_one(i->cptr,
-			    ":%s!%s@%s JOIN :%s", sptr->name, sptr->user->username, GetHost(sptr), chptr->chname);
+			if (IsCapable(i->cptr, PROTO_EXTENDED_JOIN))
+				sendto_one(i->cptr, ":%s!%s@%s JOIN %s %s :%s", sptr->name,
+					sptr->user->username, GetHost(sptr), chptr->chname,
+					(isdigit(*sptr->user->svid)) ? "*" : sptr->user->svid,
+					sptr->info);
+			else
+				sendto_one(i->cptr,
+					":%s!%s@%s JOIN :%s", sptr->name, sptr->user->username, GetHost(sptr), chptr->chname);
 	}
 }
 
@@ -316,7 +322,13 @@
 					if (i->cptr == user)
 						continue;
 					if (moded_user_invisible(i->cptr,chptr))
-						sendto_one(user,":%s!%s@%s JOIN :%s", i->cptr->name, i->cptr->user->username, GetHost(i->cptr), chptr->chname);
+						if (IsCapable(user, PROTO_EXTENDED_JOIN))
+							sendto_one(user,":%s!%s@%s JOIN %s %s :%s", i->cptr->name,
+								i->cptr->user->username, GetHost(i->cptr), chptr->chname,
+								(isdigit(*i->cptr->user->svid)) ? "*" : i->cptr->user->svid,
+								i->cptr->info);
+						else
+							sendto_one(user,":%s!%s@%s JOIN :%s", i->cptr->name, i->cptr->user->username, GetHost(i->cptr), chptr->chname);
 				}
 
 			}
diff -rdu a/src/modules/m_away.c b/src/modules/m_away.c
--- a/src/modules/m_away.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/modules/m_away.c	2016-02-08 23:41:14.000000000 +0300
@@ -107,7 +107,7 @@
 	                sendto_server(cptr, 0, 0, ":%s AWAY", sptr->name);
 	                hash_check_watch(cptr, RPL_NOTAWAY);
 
-			sendto_common_channels_local_butone(sptr, PROTO_AWAY_NOTIFY, ":%s AWAY", sptr->name);
+			sendto_common_channels_local_butone(sptr, PROTO_AWAY_NOTIFY, 0, ":%s AWAY", sptr->name);
                 }
                 /* hope this works XX */
                 if (MyConnect(sptr))
@@ -161,7 +161,7 @@
                 sendto_one(sptr, rpl_str(RPL_NOWAWAY), me.name, sptr->name);
 
 	hash_check_watch(cptr, wasaway ? RPL_REAWAY : RPL_GONEAWAY);
-	sendto_common_channels_local_butone(sptr, PROTO_AWAY_NOTIFY, ":%s AWAY :%s", sptr->name, away);
+	sendto_common_channels_local_butone(sptr, PROTO_AWAY_NOTIFY, 0, ":%s AWAY :%s", sptr->name, away);
 
 	RunHook2(HOOKTYPE_AWAY, sptr, away);
         return 0;
diff -rdu a/src/modules/m_cap.c b/src/modules/m_cap.c
--- a/src/modules/m_cap.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/modules/m_cap.c	2016-02-08 22:39:46.000000000 +0300
@@ -55,6 +55,16 @@
 	ClientCapabilityAdd(modinfo->handle, &c);
 
 	memset(&c, 0, sizeof(c));
+	c.name = "chghost";
+	c.cap = PROTO_CHGHOST;
+	ClientCapabilityAdd(modinfo->handle, &c);
+
+	memset(&c, 0, sizeof(c));
+	c.name = "extended-join";
+	c.cap = PROTO_EXTENDED_JOIN;
+	ClientCapabilityAdd(modinfo->handle, &c);
+
+	memset(&c, 0, sizeof(c));
 	c.name = "multi-prefix";
 	c.cap = PROTO_NAMESX;
 	ClientCapabilityAdd(modinfo->handle, &c);
diff -rdu a/src/modules/m_chghost.c b/src/modules/m_chghost.c
--- a/src/modules/m_chghost.c	2016-02-05 21:36:45.000000000 +0300
+++ b/src/modules/m_chghost.c	2016-02-08 23:42:01.000000000 +0300
@@ -160,7 +160,7 @@
 				/* join sent later when the host has been changed */
 				break;
 		}
-				
+		sendto_common_channels_local_butone(acptr, PROTO_CHGHOST, 0, ":%s CHGHOST %s %s", acptr->name, acptr->user->username, parv[2]);
 		if (!IsULine(sptr))
 		{
 			sendto_snomask(SNO_EYES,
diff -rdu a/src/modules/m_chgident.c b/src/modules/m_chgident.c
--- a/src/modules/m_chgident.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/modules/m_chgident.c	2016-02-08 23:42:13.000000000 +0300
@@ -163,6 +163,7 @@
 				/* join sent later when the ident has been changed */
 				break;
 		}
+		sendto_common_channels_local_butone(acptr, PROTO_CHGHOST, 0, ":%s CHGHOST %s %s", acptr->name, parv[2], GetHost(acptr));
 		if (!IsULine(sptr))
 		{
 			sendto_snomask(SNO_EYES,
diff -rdu a/src/modules/m_join.c b/src/modules/m_join.c
--- a/src/modules/m_join.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/modules/m_join.c	2016-02-08 23:30:57.000000000 +0300
@@ -211,19 +211,7 @@
 	/*
 	   ** notify all other users on the new channel
 	 */
-	if (i != 0)
-	{
-		if (MyClient(sptr))
-			sendto_one(sptr, ":%s!%s@%s JOIN :%s",
-			    sptr->name, sptr->user->username,
-			    GetHost(sptr), chptr->chname);
-		sendto_chanops_butone(NULL, chptr, ":%s!%s@%s JOIN :%s",
-		    sptr->name, sptr->user->username,
-		    GetHost(sptr), chptr->chname);
-	}
-	else
-		sendto_channel_butserv(chptr, sptr,
-		    ":%s JOIN :%s", sptr->name, chptr->chname);
+	send_channel_join(chptr, sptr, i);
 	
 	sendto_server(cptr, 0, PROTO_SJ3, ":%s JOIN :%s", sptr->name, chptr->chname);
 
diff -rdu a/src/modules/m_mode.c b/src/modules/m_mode.c
--- a/src/modules/m_mode.c	2016-02-05 21:36:45.000000000 +0300
+++ b/src/modules/m_mode.c	2016-02-08 23:42:35.000000000 +0300
@@ -1787,6 +1787,12 @@
 		if (!dontspread)
 			sendto_server(cptr, PROTO_VHP, 0, ":%s SETHOST :%s",
 				sptr->name, sptr->user->virthost);
+
+		sptr->umodes &= ~UMODE_HIDE;
+		sendto_common_channels_local_butone(sptr, PROTO_CHGHOST, 0, ":%s CHGHOST %s %s", sptr->name,
+			sptr->user->username, sptr->user->virthost);
+		sptr->umodes |= UMODE_HIDE;
+
 		if (UHOST_ALLOWED == UHALLOW_REJOIN)
 		{
 			/* LOL, this is ugly ;) */
@@ -1804,6 +1810,11 @@
 	/* -x */
 	if (!IsHidden(sptr) && (setflags & UMODE_HIDE))
 	{
+		sptr->umodes |= UMODE_HIDE;
+		sendto_common_channels_local_butone(sptr, PROTO_CHGHOST, 0, ":%s CHGHOST %s %s", sptr->name,
+			sptr->user->username, sptr->user->realhost);
+		sptr->umodes &= ~UMODE_HIDE;
+
 		if (UHOST_ALLOWED == UHALLOW_REJOIN)
 		{
 			/* LOL, this is ugly ;) */
diff -rdu a/src/modules/m_sethost.c b/src/modules/m_sethost.c
--- a/src/modules/m_sethost.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/modules/m_sethost.c	2016-02-08 23:43:09.000000000 +0300
@@ -172,6 +172,7 @@
 				break;
 		}
 
+		sendto_common_channels_local_butone(sptr, PROTO_CHGHOST, 0, ":%s CHGHOST %s %s", sptr->name, sptr->user->username, vhost);
 		/* hide it */
 		sptr->umodes |= UMODE_HIDE;
 		sptr->umodes |= UMODE_SETHOST;
diff -rdu a/src/modules/m_setident.c b/src/modules/m_setident.c
--- a/src/modules/m_setident.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/modules/m_setident.c	2016-02-08 23:43:22.000000000 +0300
@@ -198,6 +198,7 @@
 				break;
 		}
 
+		sendto_common_channels_local_butone(sptr, PROTO_CHGHOST, 0, ":%s CHGHOST %s %s", sptr->name, vident, GetHost(sptr));
 		/* get it in */
 		ircsnprintf(sptr->user->username, sizeof(sptr->user->username), "%s", vident);
 		/* spread it out */
diff -rdu a/src/modules/m_sjoin.c b/src/modules/m_sjoin.c
--- a/src/modules/m_sjoin.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/modules/m_sjoin.c	2016-02-08 23:39:03.000000000 +0300
@@ -507,12 +507,44 @@
 				if (k != 0)
 				{
 					if (modeflags & (CHFL_CHANOP|CHFL_CHANPROT|CHFL_CHANOWNER|CHFL_HALFOP|CHFL_VOICE))
-						sendto_channel_butserv(chptr, acptr, ":%s JOIN :%s", nick, chptr->chname);
+					{
+						sendto_channel_local_with_capability(acptr, 0, PROTO_EXTENDED_JOIN, chptr, ":%s JOIN :%s",
+							nick, chptr->chname);
+						sendto_channel_local_with_capability(acptr, PROTO_EXTENDED_JOIN, 0, chptr, ":%s JOIN %s %s :%s",
+							nick, chptr->chname, (isdigit(*acptr->user->svid)) ? "*" : acptr->user->svid, acptr->info);
+					}
 					else
-						sendto_chanops_butone(NULL, chptr, ":%s!%s@%s JOIN :%s",
+					{
+						sendto_chanops_with_capability_butone(NULL, chptr, 0, PROTO_EXTENDED_JOIN, ":%s!%s@%s JOIN :%s",
 							acptr->name, acptr->user->username, GetHost(acptr), chptr->chname);
-				} else
-					sendto_channel_butserv(chptr, acptr, ":%s JOIN :%s", nick, chptr->chname);
+						sendto_chanops_with_capability_butone(NULL, chptr, PROTO_EXTENDED_JOIN, 0, ":%s!%s@%s JOIN %s %s :%s",
+							acptr->name, acptr->user->username, GetHost(acptr), chptr->chname,
+							(isdigit(*acptr->user->svid)) ? "*" : acptr->user->svid, acptr->info);
+					}
+				}
+				else
+				{
+					sendto_channel_local_with_capability(acptr, 0, PROTO_EXTENDED_JOIN, chptr, ":%s JOIN :%s",
+						nick, chptr->chname);
+					sendto_channel_local_with_capability(acptr, PROTO_EXTENDED_JOIN, 0, chptr, ":%s JOIN %s %s :%s",
+						nick, chptr->chname, (isdigit(*acptr->user->svid)) ? "*" : acptr->user->svid, acptr->info);
+				}
+
+				if (acptr->user->away)
+				{
+					if (k != 0)
+					{
+						if (modeflags & (CHFL_CHANOP|CHFL_CHANPROT|CHFL_CHANOWNER|CHFL_HALFOP|CHFL_VOICE))
+							sendto_channel_local_with_capability_butone(acptr, acptr, PROTO_AWAY_NOTIFY, 0, chptr, ":%s AWAY :%s",
+								nick, acptr->user->away);
+						else
+							sendto_chanops_with_capability_butone(NULL, chptr, PROTO_AWAY_NOTIFY, 0, ":%s!%s@%s AWAY :%s",
+								acptr->name, acptr->user->username, GetHost(acptr), acptr->user->away);
+					}
+					else
+						sendto_channel_local_with_capability_butone(acptr, acptr, PROTO_AWAY_NOTIFY, 0, chptr, ":%s AWAY :%s",
+							nick, acptr->user->away);
+				}
 			}
 			sendto_server(cptr, 0, PROTO_SJOIN, ":%s JOIN %s",
 			    nick, chptr->chname);
diff -rdu a/src/modules/m_svsmode.c b/src/modules/m_svsmode.c
--- a/src/modules/m_svsmode.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/modules/m_svsmode.c	2016-02-08 23:42:47.000000000 +0300
@@ -482,7 +482,7 @@
 				if (parv[3])
 				{
 					strlcpy(acptr->user->svid, parv[3], sizeof(acptr->user->svid));
-					sendto_common_channels_local_butone(acptr, PROTO_ACCOUNT_NOTIFY, ":%s ACCOUNT %s",
+					sendto_common_channels_local_butone(acptr, PROTO_ACCOUNT_NOTIFY, 0, ":%s ACCOUNT %s",
 									    acptr->name,
 									    !isdigit(*acptr->user->svid) ? acptr->user->svid : "*");
 				}
diff -rdu a/src/modules/m_vhost.c b/src/modules/m_vhost.c
--- a/src/modules/m_vhost.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/modules/m_vhost.c	2016-02-08 23:41:33.000000000 +0300
@@ -132,6 +132,9 @@
 				/* join sent later when the host has been changed */
 				break;
 		}
+		sendto_common_channels_local_butone(sptr, PROTO_CHGHOST, 0, ":%s CHGHOST %s %s", sptr->name,
+			vhost->virtuser ? vhost->virtuser : sptr->user->username, vhost->virthost);
+
 		safestrdup(sptr->user->virthost, vhost->virthost);
 		if (vhost->virtuser)
 		{
diff -rdu a/src/s_user.c b/src/s_user.c
--- a/src/s_user.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/s_user.c	2016-02-08 23:19:22.000000000 +0300
@@ -67,6 +67,8 @@
 
 	if (UHOST_ALLOWED == UHALLOW_REJOIN)
 		rejoin_leave(sptr);
+
+	sendto_common_channels_local_butone(sptr, PROTO_CHGHOST, 0, ":%s CHGHOST %s %s", sptr->name, sptr->user->username, host);
 	if (sptr->user->virthost)
 	{
 		MyFree(sptr->user->virthost);
diff -rdu a/src/send.c b/src/send.c
--- a/src/send.c	2015-12-18 19:54:11.000000000 +0300
+++ b/src/send.c	2016-02-08 23:03:09.000000000 +0300
@@ -450,6 +450,30 @@
 	}
 }
 
+void sendto_chanops_with_capability_butone(aClient *one, aChannel *chptr, unsigned int caps, unsigned int negcaps, char *pattern, ...)
+{
+	va_list vl;
+	Member *lp;
+	aClient *acptr;
+
+	for (lp = chptr->members; lp; lp = lp->next)
+	{
+		acptr = lp->cptr;
+		if (acptr == one || !(lp->flags & (CHFL_CHANOP|CHFL_CHANOWNER|CHFL_CHANPROT)))
+			continue;	/* ...was the one I should skip
+					   or user not not a channel op */
+		if (MyConnect(acptr) && IsRegisteredUser(acptr))
+		{
+			if (!IsCapable(acptr, caps) ||
+			    !NotCapable(acptr, negcaps))
+				continue;
+
+			va_start(vl, pattern);
+			vsendto_one(acptr, pattern, vl);
+			va_end(vl);
+		}
+	}
+}
 
 /*
  * sendto_server
@@ -548,7 +572,7 @@
  * Sends a message to all people on local server who are
  * in same channel with user and have the specified capability.
  */
-void sendto_common_channels_local_butone(aClient *user, int cap, char *pattern, ...)
+void sendto_common_channels_local_butone(aClient *user, unsigned int cap, unsigned int negcap, char *pattern, ...)
 {
 	va_list vl;
 
@@ -573,7 +597,8 @@
 			{
 				cptr = users->cptr;
 				if (!MyConnect(cptr) || (cptr->local->serial == current_serial) ||
-				    !CHECKPROTO(cptr, cap))
+				    !IsCapable(cptr, cap) ||
+				    !NotCapable(cptr, negcap))
 					continue;
 				cptr->local->serial = current_serial;
 				sendbufto_one(cptr, sendbuf, sendlen);
@@ -612,6 +637,34 @@
 	return;
 }
 
+void sendto_channel_local_with_capability(aClient *from, unsigned int caps, unsigned int negcaps, aChannel *chptr, char *pattern, ...)
+{
+	va_list vl;
+	Member *lp;
+	aClient *acptr;
+	int sendlen;
+
+	/* We now create the buffer _before_ we send it to the clients. Rather than
+	 * rebuilding the buffer 1000 times for a 1000 local-users channel. -- Syzop
+	 */
+	*sendbuf = '\0';
+	va_start(vl, pattern);
+	sendlen = vmakebuf_local_withprefix(sendbuf, sizeof sendbuf, from, pattern, vl);
+	va_end(vl);
+
+	for (lp = chptr->members; lp; lp = lp->next)
+		if (MyConnect(acptr = lp->cptr))
+		{
+			if (!IsCapable(lp->cptr, caps) ||
+			    !NotCapable(lp->cptr, negcaps))
+				continue;
+
+			sendbufto_one(acptr, sendbuf, sendlen);
+		}
+
+	return;
+}
+
 void sendto_channel_butserv_butone(aChannel *chptr, aClient *from, aClient *one, char *pattern, ...)
 {
 	va_list vl;
@@ -632,6 +685,30 @@
 	}
 }
 
+void sendto_channel_local_with_capability_butone(aClient *from, aClient *one, unsigned int caps, unsigned int negcaps, aChannel *chptr, char *pattern, ...)
+{
+	va_list vl;
+	Member *lp;
+	aClient *acptr;
+
+	for (lp = chptr->members; lp; lp = lp->next)
+	{
+		if (lp->cptr == one)
+			continue;
+
+		if (MyConnect(acptr = lp->cptr))
+		{
+			if (!IsCapable(lp->cptr, caps) ||
+			    !NotCapable(lp->cptr, negcaps))
+				continue;
+
+			va_start(vl, pattern);
+			vsendto_prefix_one(acptr, from, pattern, vl);
+			va_end(vl);
+		}
+	}
+}
+
 /*
 ** send a msg to all ppl on servers/hosts that match a specified mask
 ** (used for enhanced PRIVMSGs)
