Index: IrcClient/Delegates.cs
===================================================================
--- IrcClient/Delegates.cs	(revision 291)
+++ IrcClient/Delegates.cs	(working copy)
@@ -7,7 +7,8 @@
  *
  * SmartIrc4net - the IRC library for .NET/C# <http://smartirc4net.sf.net>
  *
- * Copyright (c) 2003-2005 Mirco Bauer <meebey@meebey.net> <http://www.meebey.net>
+ * Copyright (c) 2003-2009 Mirco Bauer <meebey@meebey.net> <http://www.meebey.net>
+ * Copyright (c) 2008-2009 Thomas Bruderer <apophis@apophis.ch>
  *
  * Full LGPL License: <http://www.gnu.org/licenses/lgpl.txt>
  *
@@ -41,8 +42,12 @@
     public delegate void InviteEventHandler(object sender, InviteEventArgs e);
     public delegate void OpEventHandler(object sender, OpEventArgs e);
     public delegate void DeopEventHandler(object sender, DeopEventArgs e);
+    public delegate void AdminEventHandler(object sender, AdminEventArgs e);
+    public delegate void DeadminEventHandler(object sender, DeadminEventArgs e);
     public delegate void HalfopEventHandler(object sender, HalfopEventArgs e);
     public delegate void DehalfopEventHandler(object sender, DehalfopEventArgs e);
+    public delegate void OwnerEventHandler(object sender, OwnerEventArgs e);
+    public delegate void DeownerEventHandler(object sender, DeownerEventArgs e);
     public delegate void VoiceEventHandler(object sender, VoiceEventArgs e);
     public delegate void DevoiceEventHandler(object sender, DevoiceEventArgs e);
     public delegate void BanEventHandler(object sender, BanEventArgs e);
Index: IrcClient/EventArgs.cs
===================================================================
--- IrcClient/EventArgs.cs	(revision 291)
+++ IrcClient/EventArgs.cs	(working copy)
@@ -7,7 +7,8 @@
  *
  * SmartIrc4net - the IRC library for .NET/C# <http://smartirc4net.sf.net>
  *
- * Copyright (c) 2003-2005 Mirco Bauer <meebey@meebey.net> <http://www.meebey.net>
+ * Copyright (c) 2003-2009 Mirco Bauer <meebey@meebey.net> <http://www.meebey.net>
+ * Copyright (c) 2008-2009 Thomas Bruderer <apophis@apophis.ch>
  * 
  * Full LGPL License: <http://www.gnu.org/licenses/lgpl.txt>
  * 
@@ -780,6 +781,134 @@
         }
     }
     
+    public class AdminEventArgs : IrcEventArgs
+    {
+        private string   _Channel;
+        private string   _Who;
+        private string   _Whom;
+        
+        public string Channel {
+            get {
+                return _Channel;
+            }
+        }
+
+        public string Who {
+            get {
+                return _Who;
+            }
+        }
+
+        public string Whom {
+            get {
+                return _Whom;
+            }
+        }
+        
+        internal AdminEventArgs(IrcMessageData data, string channel, string who, string whom) : base(data)
+        {
+            _Channel = channel;
+            _Who = who;
+            _Whom = whom;
+        }
+    }
+        
+    public class DeadminEventArgs : IrcEventArgs
+    {
+        private string   _Channel;
+        private string   _Who;
+        private string   _Whom;
+        
+        public string Channel {
+            get {
+                return _Channel;
+            }
+        }
+
+        public string Who {
+            get {
+                return _Who;
+            }
+        }
+
+        public string Whom {
+            get {
+                return _Whom;
+            }
+        }
+        
+        internal DeadminEventArgs(IrcMessageData data, string channel, string who, string whom) : base(data)
+        {
+            _Channel = channel;
+            _Who = who;
+            _Whom = whom;
+        }
+    }
+            
+    public class OwnerEventArgs : IrcEventArgs
+    {
+        private string   _Channel;
+        private string   _Who;
+        private string   _Whom;
+        
+        public string Channel {
+            get {
+                return _Channel;
+            }
+        }
+
+        public string Who {
+            get {
+                return _Who;
+            }
+        }
+
+        public string Whom {
+            get {
+                return _Whom;
+            }
+        }
+        
+        internal OwnerEventArgs(IrcMessageData data, string channel, string who, string whom) : base(data)
+        {
+            _Channel = channel;
+            _Who = who;
+            _Whom = whom;
+        }
+    }
+                
+    public class DeownerEventArgs : IrcEventArgs
+    {
+        private string   _Channel;
+        private string   _Who;
+        private string   _Whom;
+        
+        public string Channel {
+            get {
+                return _Channel;
+            }
+        }
+
+        public string Who {
+            get {
+                return _Who;
+            }
+        }
+
+        public string Whom {
+            get {
+                return _Whom;
+            }
+        }
+        
+        internal DeownerEventArgs(IrcMessageData data, string channel, string who, string whom) : base(data)
+        {
+            _Channel = channel;
+            _Who = who;
+            _Whom = whom;
+        }
+    }
+    
     /// <summary>
     ///
     /// </summary>
Index: IrcClient/IrcClient.cs
===================================================================
--- IrcClient/IrcClient.cs	(revision 291)
+++ IrcClient/IrcClient.cs	(working copy)
@@ -7,7 +7,8 @@
  *
  * SmartIrc4net - the IRC library for .NET/C# <http://smartirc4net.sf.net>
  *
- * Copyright (c) 2003-2008 Mirco Bauer <meebey@meebey.net>
+ * Copyright (c) 2003-2009 Mirco Bauer <meebey@meebey.net>
+ * Copyright (c) 2008-2009 Thomas Bruderer <apophis@apophis.ch>
  *
  * Full LGPL License: <http://www.gnu.org/licenses/lgpl.txt>
  *
@@ -114,8 +115,12 @@
         public event UnbanEventHandler          OnUnban;
         public event OpEventHandler             OnOp;
         public event DeopEventHandler           OnDeop;
+        public event AdminEventHandler          OnAdmin;
+        public event DeadminEventHandler        OnDeadmin;
         public event HalfopEventHandler         OnHalfop;
         public event DehalfopEventHandler       OnDehalfop;
+        public event OwnerEventHandler          OnOwner;
+        public event DeownerEventHandler        OnDeowner;
         public event VoiceEventHandler          OnVoice;
         public event DevoiceEventHandler        OnDevoice;
         public event WhoEventHandler            OnWho;
@@ -311,8 +316,14 @@
                 }
 #endif
                 _SupportNonRfc = value;
+                
+                if (SupportNonRfcChanged != null) {
+                    SupportNonRfcChanged(this, EventArgs.Empty);
+                }
             }
         }
+        
+        public event EventHandler SupportNonRfcChanged;
 
         /// <summary>
         /// Gets the nickname of us.
@@ -1366,7 +1377,9 @@
             chan.UnsafeVoices.Remove(nickname);
             if (SupportNonRfc) {
                 NonRfcChannel nchan = (NonRfcChannel)chan;
+                nchan.UnsafeAdmins.Remove(nickname);
                 nchan.UnsafeHalfops.Remove(nickname);
+                nchan.UnsafeOwners.Remove(nickname);
             } 
         }
 
@@ -1530,6 +1543,138 @@
                             }
                         }
                     break;
+                    case 'a':
+                        if (SupportNonRfc) {
+                            temp = (string)parametersEnumerator.Current;
+                            parametersEnumerator.MoveNext();
+                            
+                            if (add) {
+                                if (ActiveChannelSyncing) {
+                                    // sanity check
+                                    if (GetChannelUser(ircdata.Channel, temp) != null) {
+                                        // update the halfop list
+                                        try {
+                                            ((NonRfcChannel)channel).UnsafeAdmins.Add(temp, GetIrcUser(temp));
+#if LOG4NET
+                                            Logger.ChannelSyncing.Debug("added admin: "+temp+" to: "+ircdata.Channel);
+#endif
+                                        } catch (ArgumentException) {
+#if LOG4NET
+                                            Logger.ChannelSyncing.Debug("duplicate admin: "+temp+" in: "+ircdata.Channel+" not added");
+#endif
+                                        }
+                                        
+                                        // update the user halfop status
+                                        NonRfcChannelUser cuser = (NonRfcChannelUser)GetChannelUser(ircdata.Channel, temp);
+                                        cuser.IsAdmin = true;
+#if LOG4NET
+                                        Logger.ChannelSyncing.Debug("set admin status: " + temp + " for: "+ircdata.Channel);
+#endif
+                                    } else {
+#if LOG4NET
+                                        Logger.ChannelSyncing.Error("_InterpretChannelMode(): GetChannelUser(" + ircdata.Channel + "," + temp + ") returned null! Ignoring...");
+#endif
+                                    }
+                                }
+                                
+                                if (OnAdmin != null) {
+                                    OnAdmin(this, new AdminEventArgs(ircdata, ircdata.Channel, ircdata.Nick, temp));
+                                }
+                            }
+                            if (remove) {
+                                if (ActiveChannelSyncing) {
+                                    // sanity check
+                                    if (GetChannelUser(ircdata.Channel, temp) != null) {
+                                        // update the halfop list
+                                        ((NonRfcChannel)channel).UnsafeAdmins.Remove(temp);
+#if LOG4NET
+                                        Logger.ChannelSyncing.Debug("removed admin: "+temp+" from: "+ircdata.Channel);
+#endif
+                                        // update the user halfop status
+                                        NonRfcChannelUser cuser = (NonRfcChannelUser)GetChannelUser(ircdata.Channel, temp);
+                                        cuser.IsAdmin = false;
+#if LOG4NET
+                                        Logger.ChannelSyncing.Debug("unset admin status: " + temp + " for: "+ircdata.Channel);
+#endif
+                                    } else {
+#if LOG4NET
+                                        Logger.ChannelSyncing.Error("_InterpretChannelMode(): GetChannelUser(" + ircdata.Channel + "," + temp + ") returned null! Ignoring...");
+#endif
+                                    }
+                                }
+                                
+                                if (OnDeadmin != null) {
+                                    OnDeadmin(this, new DeadminEventArgs(ircdata, ircdata.Channel, ircdata.Nick, temp));
+                                }
+                            }
+                        }
+                    break;
+                    case 'r':
+                        if (SupportNonRfc) {
+                            temp = (string)parametersEnumerator.Current;
+                            parametersEnumerator.MoveNext();
+                            
+                            if (add) {
+                                if (ActiveChannelSyncing) {
+                                    // sanity check
+                                    if (GetChannelUser(ircdata.Channel, temp) != null) {
+                                        // update the halfop list
+                                        try {
+                                            ((NonRfcChannel)channel).UnsafeOwners.Add(temp, GetIrcUser(temp));
+#if LOG4NET
+                                            Logger.ChannelSyncing.Debug("added owner: "+temp+" to: "+ircdata.Channel);
+#endif
+                                        } catch (ArgumentException) {
+#if LOG4NET
+                                            Logger.ChannelSyncing.Debug("duplicate owner: "+temp+" in: "+ircdata.Channel+" not added");
+#endif
+                                        }
+                                        
+                                        // update the user halfop status
+                                        NonRfcChannelUser cuser = (NonRfcChannelUser)GetChannelUser(ircdata.Channel, temp);
+                                        cuser.IsOwner = true;
+#if LOG4NET
+                                        Logger.ChannelSyncing.Debug("set owner status: " + temp + " for: "+ircdata.Channel);
+#endif
+                                    } else {
+#if LOG4NET
+                                        Logger.ChannelSyncing.Error("_InterpretChannelMode(): GetChannelUser(" + ircdata.Channel + "," + temp + ") returned null! Ignoring...");
+#endif
+                                    }
+                                }
+                                
+                                if (OnOwner != null) {
+                                    OnOwner(this, new OwnerEventArgs(ircdata, ircdata.Channel, ircdata.Nick, temp));
+                                }
+                            }
+                            if (remove) {
+                                if (ActiveChannelSyncing) {
+                                    // sanity check
+                                    if (GetChannelUser(ircdata.Channel, temp) != null) {
+                                        // update the halfop list
+                                        ((NonRfcChannel)channel).UnsafeOwners.Remove(temp);
+#if LOG4NET
+                                        Logger.ChannelSyncing.Debug("removed owner: "+temp+" from: "+ircdata.Channel);
+#endif
+                                        // update the user halfop status
+                                        NonRfcChannelUser cuser = (NonRfcChannelUser)GetChannelUser(ircdata.Channel, temp);
+                                        cuser.IsOwner = false;
+#if LOG4NET
+                                        Logger.ChannelSyncing.Debug("unset owner status: " + temp + " for: "+ircdata.Channel);
+#endif
+                                    } else {
+#if LOG4NET
+                                        Logger.ChannelSyncing.Error("_InterpretChannelMode(): GetChannelUser(" + ircdata.Channel + "," + temp + ") returned null! Ignoring...");
+#endif
+                                    }
+                                }
+                                
+                                if (OnDeowner != null) {
+                                    OnDeowner(this, new DeownerEventArgs(ircdata, ircdata.Channel, ircdata.Nick, temp));
+                                }
+                            }
+                        }
+                    break;
                     case 'v':
                         temp = (string)parametersEnumerator.Current;
                         parametersEnumerator.MoveNext();
@@ -2084,15 +2229,26 @@
                             channel.UnsafeOps.Remove(oldnickname);
                             channel.UnsafeOps.Add(newnickname, channeluser);
                         }
-                        if (SupportNonRfc && ((NonRfcChannelUser)channeluser).IsHalfop) {
-                            NonRfcChannel nchannel = (NonRfcChannel)channel;
-                            nchannel.UnsafeHalfops.Remove(oldnickname);
-                            nchannel.UnsafeHalfops.Add(newnickname, channeluser);
-                        }
                         if (channeluser.IsVoice) {
                             channel.UnsafeVoices.Remove(oldnickname);
                             channel.UnsafeVoices.Add(newnickname, channeluser);
                         }
+                        if (SupportNonRfc) {
+                            NonRfcChannel nchannel = (NonRfcChannel)channel;
+                        	if (((NonRfcChannelUser)channeluser).IsAdmin) {
+    	                        nchannel.UnsafeAdmins.Remove(oldnickname);
+        	                    nchannel.UnsafeAdmins.Add(newnickname, channeluser);            		
+                        	}
+                        	if (((NonRfcChannelUser)channeluser).IsHalfop) {
+    	                        nchannel.UnsafeHalfops.Remove(oldnickname);
+        	                    nchannel.UnsafeHalfops.Add(newnickname, channeluser);            		
+                        	}
+                        	if (((NonRfcChannelUser)channeluser).IsOwner) {
+    	                        nchannel.UnsafeOwners.Remove(oldnickname);
+        	                    nchannel.UnsafeOwners.Add(newnickname, channeluser);            		
+                        	}
+                        }
+
                     }
                 }
             }
@@ -2234,17 +2390,18 @@
             if (ActiveChannelSyncing &&
                 IsJoined(channelname)) {
                 string nickname;
-                bool   op;
-                bool   halfop;
-                bool   voice;
+                bool   op, voice;
+                bool   halfop, admin, owner;
                 foreach (string user in userlist) {
                     if (user.Length <= 0) {
                         continue;
                     }
 
                     op = false;
+                    voice = false;
                     halfop = false;
-                    voice = false;
+                    admin = false;
+                    owner = false;
                     switch (user[0]) {
                         case '@':
                             op = true;
@@ -2266,6 +2423,14 @@
                         case '~':
                             nickname = user.Substring(1);
                         break;
+                        case '*':
+                            owner = true;
+                            nickname = user.Substring(1);
+                        break;
+                        case '!':
+                            admin = true;
+                            nickname = user.Substring(1);
+                        break;
                         default:
                             nickname = user;
                         break;
@@ -2297,24 +2462,41 @@
                             Logger.ChannelSyncing.Debug("added op: "+nickname+" to: "+channelname);
 #endif
                         }
-                        if (SupportNonRfc && halfop)  {
-                            ((NonRfcChannel)channel).UnsafeHalfops.Add(nickname, channeluser);
-#if LOG4NET
-                            Logger.ChannelSyncing.Debug("added halfop: "+nickname+" to: "+channelname);
-#endif
-                        }
                         if (voice) {
                             channel.UnsafeVoices.Add(nickname, channeluser);
 #if LOG4NET
                             Logger.ChannelSyncing.Debug("added voice: "+nickname+" to: "+channelname);
 #endif
                         }
+                        if (SupportNonRfc) {
+                        	if (admin)  {
+	                            ((NonRfcChannel)channel).UnsafeAdmins.Add(nickname, channeluser);
+#if LOG4NET
+    	                        Logger.ChannelSyncing.Debug("added admin: "+nickname+" to: "+channelname);
+#endif
+                        	}
+                        	if (halfop)  {
+	                            ((NonRfcChannel)channel).UnsafeHalfops.Add(nickname, channeluser);
+#if LOG4NET
+    	                        Logger.ChannelSyncing.Debug("added halfop: "+nickname+" to: "+channelname);
+#endif
+                        	}
+                        	if (owner)  {
+	                            ((NonRfcChannel)channel).UnsafeOwners.Add(nickname, channeluser);
+#if LOG4NET
+    	                        Logger.ChannelSyncing.Debug("added owner: "+nickname+" to: "+channelname);
+#endif
+                        	}
+
+                        }
                     }
 
                     channeluser.IsOp    = op;
                     channeluser.IsVoice = voice;
                     if (SupportNonRfc) {
+                        ((NonRfcChannelUser)channeluser).IsAdmin = admin;
                         ((NonRfcChannelUser)channeluser).IsHalfop = halfop;
+                        ((NonRfcChannelUser)channeluser).IsOwner = owner;
                     }
                 }
             }
Index: IrcClient/NonRfcChannel.cs
===================================================================
--- IrcClient/NonRfcChannel.cs	(revision 291)
+++ IrcClient/NonRfcChannel.cs	(working copy)
@@ -8,6 +8,7 @@
  * SmartIrc4net - the IRC library for .NET/C# <http://smartirc4net.sf.net>
  *
  * Copyright (c) 2003-2005 Mirco Bauer <meebey@meebey.net> <http://www.meebey.net>
+ * Copyright (c) 2008-2009 Thomas Bruderer <apophis@apophis.ch>
  * 
  * Full LGPL License: <http://www.gnu.org/licenses/lgpl.txt>
  * 
@@ -38,6 +39,8 @@
     public class NonRfcChannel : Channel
     {
         private Hashtable _Halfops = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer()));
+        private Hashtable _Admins = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer()));
+        private Hashtable _Owners = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer()));
         
         /// <summary>
         /// 
@@ -73,5 +76,45 @@
                 return _Halfops;
             }
         }
+        
+                /// <summary>
+        /// 
+        /// </summary>
+        /// <value> </value>
+        public Hashtable Admins {
+            get {
+                return (Hashtable) _Admins.Clone();
+            }
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <value> </value>
+        internal Hashtable UnsafeAdmins {
+            get {
+                return _Admins;
+            }
+        }
+        
+                /// <summary>
+        /// 
+        /// </summary>
+        /// <value> </value>
+        public Hashtable Owners {
+            get {
+                return (Hashtable) _Owners.Clone();
+            }
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <value> </value>
+        internal Hashtable UnsafeOwners {
+            get {
+                return _Owners;
+            }
+        }
     }
 }
Index: IrcClient/NonRfcChannelUser.cs
===================================================================
--- IrcClient/NonRfcChannelUser.cs	(revision 291)
+++ IrcClient/NonRfcChannelUser.cs	(working copy)
@@ -8,6 +8,7 @@
  * SmartIrc4net - the IRC library for .NET/C# <http://smartirc4net.sf.net>
  *
  * Copyright (c) 2003-2005 Mirco Bauer <meebey@meebey.net> <http://www.meebey.net>
+ * Copyright (c) 2008-2009 Thomas Bruderer <apophis@apophis.ch>
  * 
  * Full LGPL License: <http://www.gnu.org/licenses/lgpl.txt>
  * 
@@ -34,9 +35,9 @@
     /// <threadsafety static="true" instance="true" />
     public class NonRfcChannelUser : ChannelUser
     {
-        private bool _IsHalfop;
-        private bool _IsOwner;
-        private bool _IsAdmin;
+        private bool _IsHalfop; //+h - halfop (%)
+        private bool _IsOwner;  //+q - owner (*)
+        private bool _IsAdmin;  //+a - admin/protect (!)
         
         /// <summary>
         /// 
@@ -58,6 +59,19 @@
         /// 
         /// </summary>
         /// <value> </value>
+        public bool IsAdmin {
+            get {
+                return _IsAdmin;
+            }
+            set {
+                _IsAdmin = value;
+            }
+        }
+        
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <value> </value>
         public bool IsHalfop {
             get {
                 return _IsHalfop;
@@ -66,5 +80,19 @@
                 _IsHalfop = value;
             }
         }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <value> </value>
+        public bool IsOwner {
+            get {
+                return _IsOwner;
+            }
+            set {
+                _IsOwner = value;
+            }
+        }
+
     }
 }
