diff -urN ./doc/example.conf ../ircd-hybrid-gate/doc/example.conf
--- ./doc/example.conf	Mon May 12 14:09:22 2003
+++ ../ircd-hybrid-gate/doc/example.conf	Thu May 15 00:25:15 2003
@@ -490,6 +490,11 @@
 	 */
 	use_except = yes;
 
+	/* talk by host: Enable/disable channel mode +H, a n!u@h of masks
+	 * that can to allow talking on channel.
+	 */
+        use_talk_by_host = yes;
+	     
 	/* knock: Allows users to request an invite to a channel that
 	 * is locked somehow (+ikl).  If the channel is +p or you are banned
 	 * the knock will not be sent.
diff -urN ./doc/example.conf.quick ../ircd-hybrid-gate/doc/example.conf.quick
--- ./doc/example.conf.quick	Mon May 12 14:09:22 2003
+++ ../ircd-hybrid-gate/doc/example.conf.quick	Thu May 15 00:25:53 2003
@@ -250,6 +250,7 @@
 channel {
 	use_invex = yes;
 	use_except = yes;
+	use_talk_by_host = yes;
 	use_knock = yes;
 	knock_delay = 5 minutes;
 	knock_delay_channel = 1 minute;
diff -urN ./include/channel.h ../ircd-hybrid-gate/include/channel.h
--- ./include/channel.h	Mon May 12 14:34:22 2003
+++ ../ircd-hybrid-gate/include/channel.h	Wed May 14 21:11:33 2003
@@ -74,6 +74,7 @@
   dlink_list      banlist;
   dlink_list      exceptlist;
   dlink_list      invexlist;
+  dlink_list      talkbyhostlist;
 
   time_t          first_received_message_time; /* channel flood control */
   int             received_number_of_privmsgs;
@@ -88,6 +89,7 @@
 extern void init_channels(void);
 extern int can_send (struct Channel *chptr, struct Client *who);
 extern int is_banned (struct Channel *chptr, struct Client *who);
+extern int is_talkbyhost (struct Channel *chptr, struct Client *who);
 extern int can_join(struct Client *source_p, struct Channel *chptr, char *key);
 extern int is_chan_op(struct Channel *chptr,struct Client *who);
 extern int is_voiced(struct Channel *chptr,struct Client *who);
diff -urN ./include/channel_mode.h ../ircd-hybrid-gate/include/channel_mode.h
--- ./include/channel_mode.h	Mon May 12 14:09:26 2003
+++ ../ircd-hybrid-gate/include/channel_mode.h	Wed May 14 20:55:00 2003
@@ -62,6 +62,7 @@
 #define CHFL_BAN        0x0010 /* ban channel flag */
 #define CHFL_EXCEPTION  0x0020 /* exception to ban channel flag */
 #define CHFL_INVEX      0x0080
+#define CHFL_TALKBYHOST 0x0100
 
 /* Channel Visibility macros */
 
@@ -80,6 +81,7 @@
 #define MODE_BAN        0x0400
 #define MODE_EXCEPTION  0x0800
 #define MODE_INVEX	0x2000
+#define MODE_TALKBYHOST 0x4000
 
 /*
  * mode flags which take another parameter (With PARAmeterS)
diff -urN ./include/numeric.h ../ircd-hybrid-gate/include/numeric.h
--- ./include/numeric.h	Sat May 10 03:38:13 2003
+++ ../ircd-hybrid-gate/include/numeric.h	Wed May 14 23:46:09 2003
@@ -261,6 +261,8 @@
 #define RPL_INVITING         341
 /*	RPL_SUMMONING        342	   removed from RFC1459 */
 
+#define RPL_TALKBYHOSTLIST   344
+#define RPL_ENDOFTALKBYHOSTLIST 345
 #define RPL_INVITELIST       346
 #define RPL_ENDOFINVITELIST  347	/* IRCnet, Undernet extension */
 #define RPL_EXCEPTLIST       348
diff -urN ./include/s_conf.h ../ircd-hybrid-gate/include/s_conf.h
--- ./include/s_conf.h	Mon May 12 14:09:26 2003
+++ ../ircd-hybrid-gate/include/s_conf.h	Wed May 14 23:30:52 2003
@@ -254,6 +254,7 @@
   int use_except;
   int use_invex;
   int use_knock;
+  int use_talk_by_host;
   int knock_delay;
   int knock_delay_channel;
   unsigned int max_bans;
diff -urN ./src/channel.c ../ircd-hybrid-gate/src/channel.c
--- ./src/channel.c	Tue May 13 11:13:07 2003
+++ ../ircd-hybrid-gate/src/channel.c	Wed May 14 23:02:02 2003
@@ -806,6 +806,47 @@
   return((actualBan ? CHFL_BAN : 0));
 }
 
+/* is_talkbyhost()
+ *
+ * inputs       - pointer to channel block
+ *              - pointer to client to check access fo
+ * output       - returns an int 0 if host present or
+ *                talkbyhost list is empty
+ *
+ */
+int
+is_talkbyhost(struct Channel *chptr, struct Client *who)
+{
+  dlink_node *talkbyhost;
+  struct Ban *s_talkbyhost = NULL;
+  char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
+  char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
+  int present = NULL;
+
+  if (!IsPerson(who))
+    return(0);
+
+  ircsprintf(src_host,"%s!%s@%s", who->name, who->username, who->host);
+  ircsprintf(src_iphost,"%s!%s@%s", who->name, who->username,
+	     who->localClient->sockhost);
+
+  DLINK_FOREACH(talkbyhost, chptr->talkbyhostlist.head)
+  {
+    present++;
+    s_talkbyhost = talkbyhost->data;
+
+    if (match(s_talkbyhost->banstr, src_host) || 
+    	match(s_talkbyhost->banstr, src_iphost) ||
+        match_cidr(s_talkbyhost->banstr, src_iphost))
+      return(0);
+  }
+
+  if (present)
+    return(1);
+  else
+    return(0);
+}
+
 /* can_join()
  *
  * inputs       -
@@ -944,6 +985,11 @@
 
   if (chptr->mode.mode & MODE_NOPRIVMSGS && !IsMember(source_p, chptr))
     return(CAN_SEND_NO);
+
+  if (is_talkbyhost(chptr, source_p) && MyClient(source_p))
+  {
+    return(CAN_SEND_NO);
+  }
 
   return(CAN_SEND_NONOP);
 }
diff -urN ./src/channel_mode.c ../ircd-hybrid-gate/src/channel_mode.c
--- ./src/channel_mode.c	Wed May 14 00:19:34 2003
+++ ../ircd-hybrid-gate/src/channel_mode.c	Wed May 14 23:20:59 2003
@@ -94,6 +94,10 @@
                       int, int *, char **, int *, int, int, char, void *,
                       const char *chname);
 
+static void chm_talkbyhost(struct Client *, struct Client *, struct Channel *,
+                      int, int *, char **, int *, int, int, char, void *,
+                      const char *chname);
+
 static void send_cap_mode_changes(struct Client *, struct Client *,
                                   struct Channel *, int, int);
 
@@ -204,6 +208,9 @@
     case CHFL_INVEX:
       list = &chptr->invexlist;
       break;
+    case CHFL_TALKBYHOST:
+      list = &chptr->talkbyhostlist;
+      break;
     default:
       sendto_realops_flags(UMODE_ALL, L_ALL,
                            "add_id() called with unknown ban type %d!", type);
@@ -278,6 +285,9 @@
     case CHFL_INVEX:
       list = &chptr->invexlist;
       break;
+    case CHFL_TALKBYHOST:
+      list = &chptr->talkbyhostlist;
+      break;
     default:
       sendto_realops_flags(UMODE_ALL, L_ALL,
                            "del_id() called with unknown ban type %d!", type);
@@ -1097,6 +1107,108 @@
 }
 
 static void
+chm_talkbyhost(struct Client *client_p, struct Client *source_p,
+          struct Channel *chptr, int parc, int *parn,
+          char **parv, int *errors, int alev, int dir, char c, void *d,
+          const char *chname)
+{
+  char *mask, *raw_mask;
+  dlink_node *ptr;
+  struct Ban *banptr;
+
+  if(!ConfigChannel.use_talk_by_host && MyClient(source_p) && 
+    (dir == MODE_ADD) && (parc > *parn))
+  {
+    if((*errors & SM_ERR_RPL_I) != 0)
+      return;
+    
+    *errors |= SM_ERR_RPL_I;
+    return;
+  }
+
+  if (alev < CHACCESS_CHANOP)
+  {
+    if (!(*errors & SM_ERR_NOOPS))
+      sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), me.name,
+                 source_p->name, chname);
+    *errors |= SM_ERR_NOOPS;
+    return;
+  }
+
+  if ((dir == MODE_QUERY) || parc <= *parn)
+  {
+    if ((*errors & SM_ERR_RPL_I) != 0)
+      return;
+    *errors |= SM_ERR_RPL_I;
+
+    DLINK_FOREACH(ptr, chptr->talkbyhostlist.head)
+    {
+      banptr = ptr->data;
+      sendto_one(client_p, form_str(RPL_TALKBYHOSTLIST), me.name,
+                 client_p->name, chname, banptr->banstr,
+                 banptr->who, banptr->when);
+    }
+    sendto_one(source_p, form_str(RPL_ENDOFTALKBYHOSTLIST), me.name,
+               source_p->name, chname);
+    return;
+  }
+
+  if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
+    return;
+
+  raw_mask = parv[(*parn)++];
+  if (IsServer(client_p))
+    mask = raw_mask;
+  else
+    mask = pretty_mask(raw_mask);
+
+  if(dir == MODE_ADD)
+  {
+    if((add_id(source_p, chptr, mask, CHFL_TALKBYHOST) == 0))
+      return;
+
+    mode_changes[mode_count].letter = c;
+    mode_changes[mode_count].dir = MODE_ADD;
+    mode_changes[mode_count].caps = CAP_IE;
+    mode_changes[mode_count].nocaps = 0;
+    
+    if(ConfigChannel.use_talk_by_host)
+      mode_changes[mode_count].mems = ONLY_CHANOPS;
+    else
+      mode_changes[mode_count].mems = ONLY_SERVERS;
+
+    mode_changes[mode_count].id = NULL;
+    mode_changes[mode_count++].arg = mask;
+  }
+  else if (dir == MODE_DEL)
+  {
+    if (del_id(chptr, mask, CHFL_TALKBYHOST) == 0)
+    {
+      /* mask isn't a valid ban, check raw_mask */
+      if((del_id(chptr, raw_mask, CHFL_TALKBYHOST) == 0) && MyClient(source_p))
+      {
+        /* nope */
+        return;
+      }
+      mask = raw_mask;
+    }
+
+    mode_changes[mode_count].letter = c;
+    mode_changes[mode_count].dir = MODE_DEL;
+    mode_changes[mode_count].caps = CAP_IE;
+    mode_changes[mode_count].nocaps = 0;
+
+    if(ConfigChannel.use_talk_by_host)
+      mode_changes[mode_count].mems = ONLY_CHANOPS;
+    else
+      mode_changes[mode_count].mems = ONLY_SERVERS;
+
+    mode_changes[mode_count].id = NULL;
+    mode_changes[mode_count++].arg = mask;
+  }
+}
+
+static void
 chm_op(struct Client *client_p, struct Client *source_p,
        struct Channel *chptr, int parc, int *parn,
        char **parv, int *errors, int alev, int dir, char c, void *d,
@@ -1467,7 +1579,7 @@
   {chm_nosuch, NULL},                             /* E */
   {chm_nosuch, NULL},                             /* F */
   {chm_nosuch, NULL},                             /* G */
-  {chm_nosuch, NULL},                             /* H */
+  {chm_talkbyhost, NULL},                         /* H */
   {chm_invex, NULL},                              /* I */
   {chm_nosuch, NULL},                             /* J */
   {chm_nosuch, NULL},                             /* K */
diff -urN ./src/ircd_lexer.l ../ircd-hybrid-gate/src/ircd_lexer.l
--- ./src/ircd_lexer.l	Mon May 12 14:09:33 2003
+++ ../ircd-hybrid-gate/src/ircd_lexer.l	Wed May 14 23:24:38 2003
@@ -259,6 +259,7 @@
 use_except	{ return USE_EXCEPT; }
 use_invex	{ return USE_INVEX; }
 use_knock	{ return USE_KNOCK; }
+use_talk_by_host { return USE_TALK_BY_HOST; }
 throttle_time { return THROTTLE_TIME; }
 user		{ return USER;} 
 vhost	{ return VHOST; }
diff -urN ./src/ircd_parser.y ../ircd-hybrid-gate/src/ircd_parser.y
--- ./src/ircd_parser.y	Mon May 12 14:09:33 2003
+++ ../ircd-hybrid-gate/src/ircd_parser.y	Thu May 15 00:38:17 2003
@@ -278,6 +278,7 @@
 %token  USE_EXCEPT
 %token  USE_INVEX
 %token  USE_KNOCK
+%token  USE_TALK_BY_HOST
 %token  VHOST
 %token  VHOST6
 %token  WARN
@@ -2663,6 +2664,7 @@
 channel_item:       channel_use_except |
                     channel_use_invex |
                     channel_use_knock |
+		    channel_use_talk_by_host |
                     channel_max_bans |
                     channel_knock_delay |
 		    channel_knock_delay_channel |
@@ -2702,6 +2704,16 @@
 {
   if (ypass == 2)
     ConfigChannel.use_knock = 0;
+};
+
+channel_use_talk_by_host: USE_TALK_BY_HOST '=' TYES ';'
+{
+  if (ypass == 2)
+    ConfigChannel.use_talk_by_host = 1;
+} | USE_TALK_BY_HOST '=' TNO ';'
+{
+  if (ypass == 2)
+    ConfigChannel.use_talk_by_host = 0;
 };
 
 channel_knock_delay: KNOCK_DELAY '=' timespec ';'
diff -urN ./src/messages.tab ../ircd-hybrid-gate/src/messages.tab
--- ./src/messages.tab	Mon May 12 04:04:50 2003
+++ ../ircd-hybrid-gate/src/messages.tab	Wed May 14 23:48:50 2003
@@ -364,8 +364,8 @@
 /* 341 */  {"RPL_INVITING", ":%s 341 %s %s %s", NULL},
 /* 342 */  {"RPL_SUMMONING", NULL, NULL},
 /* 343 */  {NULL, NULL, NULL},
-/* 344 */  {NULL, NULL, NULL},
-/* 345 */  {NULL, NULL, NULL},
+/* 344 */  {"RPL_TALKBYHOSTLIST", ":%s 344 %s %s %s %s %lu", NULL},
+/* 345 */  {"RPL_ENDOFTALKBYHOSTLIST", ":%s 345 %s %s :End of Channel TalkByHost List", NULL},
 /* 346 */  {"RPL_INVEXLIST", ":%s 346 %s %s %s %s %lu", NULL},
 /* 347 */  {"RPL_ENDOFINVEXLIST", ":%s 347 %s %s :End of Channel Invite List", NULL},
 /* 348 */  {"RPL_EXCEPTLIST", ":%s 348 %s %s %s %s %lu", NULL},
