diff -uNrd ircd-hybrid-6.dist/include/m_commands.h ircd-hybrid-6/include/m_commands.h
--- ircd-hybrid-6.dist/include/m_commands.h	Wed Aug 22 23:14:41 2001
+++ ircd-hybrid-6/include/m_commands.h	Wed Aug 22 23:51:25 2001
@@ -33,8 +33,10 @@
 extern int m_kline(struct Client *,struct Client *,int,char **);
 extern int m_unkline(struct Client *,struct Client *,int,char **);
 extern int m_dline(struct Client *,struct Client *,int,char **);
+extern int m_undline(struct Client *,struct Client *,int,char **);
 
 extern int m_gline(struct Client *,struct Client *,int,char **);
+extern int m_ungline(struct Client *,struct Client *,int,char **);
 
 extern int m_locops(struct Client *,struct Client *,int,char **);
 
diff -uNrd ircd-hybrid-6.dist/include/m_gline.h ircd-hybrid-6/include/m_gline.h
--- ircd-hybrid-6.dist/include/m_gline.h	Wed Aug 22 23:14:41 2001
+++ ircd-hybrid-6/include/m_gline.h	Wed Aug 22 23:51:30 2001
@@ -44,6 +44,7 @@
 extern struct ConfItem* find_is_glined(const char *, const char *);
 extern void   flush_glines(void);             
 extern void   report_glines(struct Client *); 
+extern int    remove_gline_match(const char* user, const char* host);
 
 typedef struct gline_pending
 {
diff -uNrd ircd-hybrid-6.dist/include/msg.h ircd-hybrid-6/include/msg.h
--- ircd-hybrid-6.dist/include/msg.h	Wed Aug 22 23:14:41 2001
+++ ircd-hybrid-6/include/msg.h	Wed Aug 22 23:52:38 2001
@@ -115,10 +115,12 @@
 #define MSG_KLINE    "KLINE"    /* KLINE */
 #define MSG_UNKLINE  "UNKLINE"  /* UNKLINE */
 #define MSG_DLINE    "DLINE"    /* DLINE */
+#define MSG_UNDLINE  "UNDLINE"  /* UNDLINE */
 #define MSG_HTM      "HTM"      /* HTM */
 #define MSG_SET      "SET"      /* SET */
 
 #define MSG_GLINE    "GLINE"    /* GLINE */
+#define MSG_UNGLINE  "UNGLINE"  /* UNGLINE */
 
 #define MSG_LOCOPS   "LOCOPS"   /* LOCOPS */
 #ifdef LWALLOPS
@@ -242,7 +244,9 @@
   { MSG_KLINE,   m_kline,    0, MAXPARA, 1, 0, 0, 0L },
   { MSG_UNKLINE, m_unkline,  0, MAXPARA, 1, 0, 0, 0L },
   { MSG_DLINE,   m_dline,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_UNDLINE, m_undline,  0, MAXPARA, 1, 0, 0, 0L },
   { MSG_GLINE,   m_gline,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_UNGLINE, m_ungline,  0, MAXPARA, 1, 0, 0, 0L },
   { MSG_HASH,    m_hash,     0, MAXPARA, 1, 0, 0, 0L },
   { MSG_DNS,     m_dns,      0, MAXPARA, 1, 0, 0, 0L },
   { MSG_REHASH,  m_rehash,   0, MAXPARA, 1, 0, 0, 0L },
diff -uNrd ircd-hybrid-6.dist/opers.txt ircd-hybrid-6/opers.txt
--- ircd-hybrid-6.dist/opers.txt	Wed Aug 22 23:14:43 2001
+++ ircd-hybrid-6/opers.txt	Wed Aug 22 23:51:35 2001
@@ -189,6 +189,9 @@
                   In order to use <nick> rather than <ip>, <nick> must
                   be on your server.
 
++ UNDLINE       - UNDLINE <ip>
+                  Will attempt to undline the given <ip>
+
 + HTM           - HTM [option]
                   When no [option] is given, HTM shows the current 
                   High Traffic Mode rate and whether HTM is on or off.
@@ -252,6 +255,12 @@
                    It takes three different opers on three different 
                    servers to do the same GLINE within a short interval,
                    to have a GLINE triggered for a compiled time of hours.
+
++ UNGLINE        - UNGLINE <user@host>
+                   -- if compiled with GLINE --
+                   Will attempt to remove gline matching <user@host>
+                   This will only remove the gline from YOUR server, it
+                   does not try to remove it globally.
 
 + TESTLINE       - TESTLINE <user@host>|ip
                    -- Looks up given user@host or user@ip 
diff -uNrd ircd-hybrid-6.dist/src/m_gline.c ircd-hybrid-6/src/m_gline.c
--- ircd-hybrid-6.dist/src/m_gline.c	Wed Aug 22 23:14:29 2001
+++ ircd-hybrid-6/src/m_gline.c	Wed Aug 22 23:51:43 2001
@@ -763,6 +763,58 @@
 }
 
 /*
+ * remove_gline_match
+ *
+ * inputs       - user@host
+ * output       - 1 if successfully removed, otherwise 0
+ * side effects -
+ */
+int remove_gline_match(const char* user, const char* host)
+{
+  aConfItem *kill_list_ptr;     /* used for the link list only */
+  aConfItem *last_list_ptr;
+  aConfItem *tmp_list_ptr;
+
+  if(glines)
+    {
+      kill_list_ptr = last_list_ptr = glines;
+
+      while(kill_list_ptr)
+        {
+          if(!irccmp(kill_list_ptr->host,host) &&
+             !irccmp(kill_list_ptr->name,user))  /* this gline matches */
+            {
+              if(glines == kill_list_ptr)
+                {
+                  /* Its pointing to first one in link list*/
+                  /* so, bypass this one, remember bad things can happen
+                     if you try to use an already freed pointer.. */
+
+                  glines = last_list_ptr = tmp_list_ptr =
+                    kill_list_ptr->next;
+                }
+              else
+                {
+                  /* its in the middle of the list, so link around it */
+                  tmp_list_ptr = last_list_ptr->next = kill_list_ptr->next;
+                }
+              free_conf(kill_list_ptr);
+              kill_list_ptr = tmp_list_ptr;
+              return 1;
+            }
+          else
+            {
+              last_list_ptr = kill_list_ptr;
+              kill_list_ptr = kill_list_ptr->next;
+            }
+        }
+      return 0;
+    }
+  else
+    return 0;
+}
+
+/*
  * expire_pending_glines
  * 
  * inputs       - NONE
diff -uNrd ircd-hybrid-6.dist/src/m_unkline.c ircd-hybrid-6/src/m_unkline.c
--- ircd-hybrid-6.dist/src/m_unkline.c	Wed Aug 22 23:14:31 2001
+++ ircd-hybrid-6/src/m_unkline.c	Wed Aug 22 23:59:34 2001
@@ -23,6 +23,9 @@
  *
  *   $Id: m_unkline.c,v 1.42 2001/08/05 16:06:00 leeh Exp $
  */
+#ifdef GLINES
+#include "m_gline.h"
+#endif
 #include "m_commands.h"
 #include "channel.h"
 #include "client.h"
@@ -406,7 +409,8 @@
       else
       {
         last_kill_ptr = kill_list_ptr;
-	kill_list_ptr = kill_list_ptr->next;
+
+        kill_list_ptr = kill_list_ptr->next;
       }
     }
 
@@ -436,4 +440,298 @@
     }
     return NO;
   }
+}
+
+/*
+** m_undline
+** added May 28th 2000 by Toby Verrall <toot@melnet.co.uk>
+** based totally on m_unkline
+**
+**      parv[0] = sender nick
+**      parv[1] = dline to remove
+*/
+int m_undline (aClient *cptr,aClient *sptr,int parc,char *parv[])
+{
+  FBFILE* in;
+  FBFILE* out;
+  int   pairme = NO;
+  char  buf[BUFSIZE];
+  char  buff[BUFSIZE];  /* matches line definition in s_conf.c */
+  char  temppath[256];
+
+  const char  *filename;                /* filename to use for undline */
+
+  char  *cidr;
+  char  *p;
+  unsigned long ip_host;
+  unsigned long ip_mask;
+  int   error_on_write = NO;
+  mode_t oldumask;
+
+  ircsprintf(temppath, "%s.tmp", ConfigFileEntry.dlinefile);
+
+  if (check_registered(sptr))
+    {
+      return -1;
+    }
+
+  if (!IsAnOper(sptr))
+    {
+      sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name,
+                 parv[0]);
+      return 0;
+    }
+
+  if (!IsSetOperUnkline(sptr))
+    {
+      sendto_one(sptr,":%s NOTICE %s :You have no U flag",me.name,
+                 parv[0]);
+      return 0;
+    }
+
+  if ( parc < 2 )
+    {
+      sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
+                 me.name, parv[0], "UNDLINE");
+      return 0;
+    }
+  
+  cidr = parv[1];
+
+  if (!is_address(cidr,&ip_host,&ip_mask))
+    {
+      sendto_one(sptr, ":%s NOTICE %s :Invalid parameters",
+                 me.name, parv[0]);
+      return 0;
+    }
+
+  filename = get_conf_name(DLINE_TYPE);
+
+  if( (in = fbopen(filename, "r")) == 0)
+    {
+      sendto_one(sptr, ":%s NOTICE %s :Cannot open %s",
+        me.name,parv[0],filename);
+      return 0;
+    }
+
+  oldumask = umask(0);                  /* ircd is normally too paranoid */
+  if( (out = fbopen(temppath, "w")) == 0)
+    {
+      sendto_one(sptr, ":%s NOTICE %s :Cannot open %s",
+        me.name,parv[0],temppath);
+      fbclose(in);
+      umask(oldumask);                  /* Restore the old umask */
+      return 0;
+    }
+  umask(oldumask);                    /* Restore the old umask */
+
+
+/*
+#toot!~toot@127.0.0.1 D'd: 123.4.5.0/24:test (2000/05/28 12.48)
+D:123.4.5.0/24:test (2000/05/28 12.48)
+*/
+
+  while(fbgets(buf, sizeof(buf), in))
+    {
+      if((buf[1] == ':') && ((buf[0] == 'd') || (buf[0] == 'D')))
+        {
+          /* its a D: line */
+          char *found_cidr;
+
+          strncpy_irc(buff, buf, BUFSIZE);      /* extra paranoia */
+
+          p = strchr(buff,'\n');
+          if(p)
+            *p = '\0';
+
+          found_cidr = buff + 2;        /* point past the D: */
+          p = strchr(found_cidr,':');
+          if(p == (char *)NULL)
+            {
+              sendto_one(sptr, ":%s NOTICE %s :D-Line file corrupted",
+                         me.name, parv[0]);
+              sendto_one(sptr, ":%s NOTICE %s :Couldn't find CIDR",
+                         me.name, parv[0]);
+              if(!error_on_write)
+                error_on_write = flush_write(sptr, out, buf, temppath);
+              continue;         /* This D line is corrupted ignore */
+            }
+         *p = '\0';   
+         
+         if(irccmp(cidr,found_cidr))
+            {
+              if(!error_on_write)
+                error_on_write = flush_write(sptr, out, buf, temppath);
+            }
+          else
+            pairme++;
+
+        } 
+      else if(buf[0] == '#')
+        {
+          char *found_cidr;
+
+          strncpy_irc(buff, buf, BUFSIZE);
+
+/*
+#toot!~toot@127.0.0.1 D'd: 123.4.5.0/24:test (2000/05/28 12.48)
+D:123.4.5.0/24:test (2000/05/28 12.48)
+
+If its a comment coment line, i.e.
+#ignore this line
+Then just ignore the line
+*/
+
+          p = strchr(buff,':');
+          if(p == (char *)NULL)
+            {
+              if(!error_on_write)
+                error_on_write = flush_write(sptr, out, buf, temppath);
+              continue;
+            }
+          *p = '\0';
+          p++;
+
+          found_cidr = p;
+          p = strchr(found_cidr,':');
+
+          if(p == (char *)NULL)
+            {
+              if(!error_on_write)
+                error_on_write = flush_write(sptr, out, buf, temppath);
+              continue;
+            }
+          *p = '\0';
+
+          while(*found_cidr == ' ')
+            found_cidr++;
+
+
+          if( (irccmp(found_cidr,cidr)))
+            {
+              if(!error_on_write)
+                error_on_write = flush_write(sptr, out, buf, temppath);
+            }
+        }
+
+      else      /* its the ircd.conf file, and not a D line or comment */
+        {
+          if(!error_on_write)
+            error_on_write = flush_write(sptr, out, buf, temppath);
+        }
+    }
+
+  fbclose(in);
+
+
+  if(!error_on_write)
+    {
+      fbclose(out);
+      (void)rename(temppath, filename);
+      rehash(cptr,sptr,0);
+    }
+  else
+    {
+      sendto_one(sptr,":%s NOTICE %s :Couldn't write D-line file, aborted",
+        me.name,parv[0]);
+      return -1;
+    }
+
+  if(!pairme)
+    {
+      sendto_one(sptr, ":%s NOTICE %s :No D-Line for %s",
+                 me.name, parv[0],cidr);
+      return 0;
+    }
+
+  sendto_one(sptr, ":%s NOTICE %s :D-Line for [%s] is removed",
+             me.name, parv[0], cidr);
+  sendto_ops("%s has removed the D-Line for: [%s]",
+             parv[0], cidr);
+
+  log(L_NOTICE, "%s removed D-Line for [%s]", parv[0], cidr);
+  return 0;
+}
+
+/*
+** m_ungline
+** added May 29th 2000 by Toby Verrall <toot@melnet.co.uk>
+**
+**      parv[0] = sender nick
+**      parv[1] = gline to remove
+*/
+
+int m_ungline (aClient *cptr,aClient *sptr,int parc,char *parv[])
+{
+#ifdef GLINES
+
+  char  *user,*host;
+
+  if (check_registered(sptr))
+    {
+      return -1;
+    }
+
+  if (!IsOper(sptr))
+    {
+      sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name,
+                 parv[0]);
+      return 0;
+    }
+
+  if (!IsSetOperUnkline(sptr) || !IsSetOperGline(sptr))
+    {
+      sendto_one(sptr,":%s NOTICE %s :You have no U and G flag",
+                 me.name,parv[0]);
+      return 0;
+    }
+
+  if ( parc < 2 )
+    {
+      sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
+                 me.name, parv[0], "UNGLINE");
+      return 0;
+    }
+
+  if ( (host = strchr(parv[1], '@')) || *parv[1] == '*' )
+    {
+      /* Explicit user@host mask given */
+
+      if(host)                  /* Found user@host */
+        {
+          user = parv[1];       /* here is user part */
+          *(host++) = '\0';     /* and now here is host */
+        }
+      else
+        {
+          user = "*";           /* no @ found, assume its *@somehost */
+          host = parv[1];
+        }
+    }
+  else
+    {
+      sendto_one(sptr, ":%s NOTICE %s :Invalid parameters",
+                 me.name, parv[0]);
+      return 0;
+    }
+
+  if(remove_gline_match(user, host))
+    {
+      sendto_one(sptr, ":%s NOTICE %s :Un-glined [%s@%s]",
+                 me.name, parv[0],user, host);
+      sendto_ops("%s has removed the G-Line for: [%s@%s]",
+                 parv[0], user, host );
+      log(L_NOTICE, "%s removed G-Line for [%s@%s]",
+          parv[0], user, host);
+      return 0;
+    }
+  else
+    {
+      sendto_one(sptr, ":%s NOTICE %s :No G-Line for %s@%s",
+                 me.name, parv[0],user,host);
+      return 0;
+    }
+#else
+  sendto_one(sptr,":%s NOTICE %s :UNGLINE disabled",me.name,parv[0]);
+#endif
 }
