diff --git a/lib/modules/Protocols.pmod/IRC.pmod/Client.pike b/lib/modules/Protocols.pmod/IRC.pmod/Client.pike
index 933667744e75c8fcdfb5883ca22709ab7516f07b..635e26efd6489bde5947c5842ce23331874cfef9 100644
--- a/lib/modules/Protocols.pmod/IRC.pmod/Client.pike
+++ b/lib/modules/Protocols.pmod/IRC.pmod/Client.pike
@@ -2,7 +2,7 @@
 
 import ".";
 
-object raw;
+Raw raw;
 string pass=MIME.encode_base64(Crypto.randomness.reasonably_random()->read(6));
 
 mapping options;
@@ -52,12 +52,19 @@ void create(string _server,void|mapping _options)
    call_out(da_ping,options->ping_interval || 60);
 }
 
+void close()
+{
+   if (raw->con) raw->con->close();
+   destruct(raw);
+   raw=0;
+}
+
 string expecting_pong;
 
 void da_ping()
 {
-   call_out(da_ping,options->ping_interval || 60);
-   call_out(no_ping_reply,options->ping_timeout || 60); // timeout
+   call_out(da_ping,options->ping_interval || 120);
+   call_out(no_ping_reply,options->ping_timeout || 120); // timeout
    cmd->ping(expecting_pong=
 	     options->host+" "+Array.shuffle("pike""IRC""client"/"")*"");
 }
@@ -97,12 +104,12 @@ void got_command(string what,string ... args)
 	    options->error_notify(@args);
 	 return;
    }
-   werror("got command: %O, %O\n",what,args);
+//     werror("got command: %O, %O\n",what,args);
 }
 
 void got_notify(string from,string type,
 		void|string to,void|string message,
-		void|string extra,void|string extra2)
+		string ...extra)
 {
    object c;
    if (options->system_notify && glob("2??",type))
@@ -138,19 +145,61 @@ void got_notify(string from,string type,
 	 break;
 
       case "353": // names list
-	 if (extra && (c=channels[lower_case(extra||"")]))
+	 if (sizeof(extra) && (c=channels[lower_case(extra[0]||"")]) &&
+	     c->not_names)
 	 {
-	    c->not_names(map(extra2/" "-({""}),
+	    c->not_names(map(extra[1]/" "-({""}),
 			     lambda(string name)
 			     {
 				string a,b,c;
-				sscanf(name,"%[@]%s%[+]",
+				sscanf(name,"%[+@%]%s%[+@%]",
 				       a,b,c);
-				return ({person(b),a+c});
+				Person p=person(b);
+				p->channels[lower_case(extra[0])]=1;
+				return ({p,a+c});
 			     }));
 	    return;
 	 }
 	 break;
+      case "366": // "end of names list"
+	 break;
+
+      case "352": // who list
+	 if (sizeof(extra)>2 && 
+	     message && (c=channels[lower_case(message||"")]))
+	 {
+	    Person p=person(extra[3],extra[0]+"@"+extra[1]);
+	    p->server=extra[2];
+	    p->realname=extra[6..]*" ";
+	    p->channels[lower_case(message)]=1;
+	    if (c->not_who) c->not_who(p,extra[4]);
+	    return;
+	 }
+	 break;
+      case "315": // "end of who list"
+	 break;
+
+      case "482": // "you're not channel operator"
+	 if ((c=channels[lower_case(message||"")]))
+	 {
+	    if (c->not_not_oper) c->not_not_oper();
+	    return;
+	 }
+	 break;
+	 
+
+      case "401": // no such nick
+	 werror("%O\n",({from,type,to,message,extra}));
+	 break;
+
+      case "367": // mode b line
+	 if ((c=channels[lower_case(message||"")]))
+	 {
+	    if (c->not_mode_b) c->not_mode_b(to,extra*" ");
+	    return;
+	 }
+	 break;
+	 
 
 	 /* --- */
 
@@ -166,12 +215,13 @@ void got_notify(string from,string type,
 	 if ((c=channels[lower_case(to||"")]))
 	 {
 	    // who, mode, by
-	    c->not_mode(extra?person(extra):originator,message,originator);
+	    c->not_mode(extra[0]?person(extra[0]):originator,message+( ({""})+extra)*" ",originator);
 	    return;
 	 }
 	 break;
 
       case "JOIN":
+//  	 werror("me=%O\n",me);
 	 if ((c=channels[lower_case(to||"")]))
 	 {
 	    c->not_join(originator);
@@ -180,6 +230,7 @@ void got_notify(string from,string type,
 	 break;
 
       case "PART":
+	 originator->channels[lower_case(to)]=0;
 	 if ((c=channels[lower_case(to||"")]))
 	 {
 	    // who, why, by
@@ -189,10 +240,11 @@ void got_notify(string from,string type,
 	 break;
 
       case "KICK":
+	 person(message)->channels[lower_case(extra[0])]=0;
 	 if ((c=channels[lower_case(to||"")]))
 	 {
 	    // who, why, by
-	    c->not_part(person(message),extra,originator);
+	    c->not_part(person(message),extra[0],originator);
 	    return;
 	 }
 	 break;
@@ -219,16 +271,27 @@ void got_notify(string from,string type,
 	 options->privmsg_notify(originator,message,to);
 	 return;
 
+      case "NOTICE":
+	 if ((c=channels[lower_case(to||"")]))
+	 {
+	    c->not_message(originator,message);
+	    return;
+	 }
+	 if (!options->notice_notify) break;
+	 options->notice_notify(originator,message,to);
+	 return;
+
       case "NICK":
-//  	 werror("%s is known as %s (aka %s)\n",
-//  		originator->nick,
-//  		to,
-//  		((array)originator->aka)*",");
+	 werror("%s is known as %s (aka %s)\n",
+		originator->nick,
+		to,
+		((array)originator->aka)*",");
 	 mixed err=0;
 	 originator->aka[originator->nick]=1;
 	 originator->aka[to]=1;
 	 if (options->nick_notify)
 	    err=catch { options->nick_notify(originator,to); };
+	 m_delete(nick2person,originator->nick);
 	 originator->nick=to;
 	 nick2person[to]=originator;
 	 if (err) throw(err);
@@ -236,7 +299,7 @@ void got_notify(string from,string type,
    }
 //    werror("got notify: %O, %O, %O, %O\n",from,type,to,message);
    if (options->generic_notify)
-      options->generic_notify(from,type,to,message,extra);
+      options->generic_notify(from,type,to,message,extra[0]);
 }
 
 object cmd=class
@@ -334,58 +397,63 @@ void send_message(string|array to,string msg)
    cmd->privmsg( (arrayp(to)?to*",":to), msg);
 }
 
-// ----- channel
-
-class Channel
-{
-   string name;
-
-   void	not_message(string who,string message);
-   void	not_join(string who);
-   void	not_part(string who,string message,string executor);
-   void	not_mode(string who,string mode);
-   void	not_failed_to_join();
-}
-
 // ----- persons
 
 class Person
 {
-   string nick; // Mirar
-   string user; // mirar
-   string ip;   // mistel.idonex.se
-   int last_action; // time_t
-   multiset aka=(<>);
+   inherit .Person;
 
    void say(string message)
    {
       cmd->privmsg(nick,message);
    }
 
-   void me(string what)
+   void notice(string message)
+   {
+      cmd->notice(nick,message);
+   }
+
+   void action(string what)
    {
       say("\1ACTION "+what+"\1");
    }
+
+   string _sprintf(int t)
+   {
+      switch (t)
+      {
+	 case 'O':
+	    return sprintf("Person(%s!%s@%s%s)",
+			   nick,user||"?",ip||"?",
+			   (realname!="?")?"("+realname+")":"");
+	 default:
+	    return 0;
+      }
+   }
 }
 
 mapping nick2person=([]);
-object me;
+Person me;
 
 Person person(string who,void|string ip)
 {
    Person p;
 
-   if ( ! (p=nick2person[who]) )
+   if ( ! (p=nick2person[lower_case(who)]) )
    {
       p=Person();
       p->nick=who;
-      nick2person[who]=p;
+      nick2person[lower_case(who)]=p;
+//        werror("new person: %O\n",p);
+   }
+   else if (lower_case(p->nick)!=lower_case(who))
+   {
+      werror("nick mismatch: %O was %O\n",who,p->nick);
+      p->nick=who;
    }
    if (ip && !p->ip)
       sscanf(ip,"%*[~]%s@%s",p->user,p->ip);
 
-//    werror("%O is %O %O %O\n",who,p->nick,p->user,p->ip);
-
    return p;
 }
 
diff --git a/lib/modules/Protocols.pmod/IRC.pmod/Raw.pike b/lib/modules/Protocols.pmod/IRC.pmod/Raw.pike
index 53e2245df96b4dabc411d3bccf9e9e43cd2d3e1e..e8df9820ebd39fffb5d67777b241bad2c4a90e45 100644
--- a/lib/modules/Protocols.pmod/IRC.pmod/Raw.pike
+++ b/lib/modules/Protocols.pmod/IRC.pmod/Raw.pike
@@ -4,7 +4,7 @@ import ".";
 
 object con;
 
-// #define IRC_DEBUG
+//  #define IRC_DEBUG
 
 function(string,string ...:void) command_callback;
 function(string,string ...:void) notify_callback;
@@ -101,6 +101,13 @@ void con_write(string s)
       write_buf+=({s});
       return;
    }
+   if (!con)
+   {
+#ifdef IRC_DEBUG
+	 werror("<- (write error; con lost)\n");
+#endif
+      return;
+   }
    int j=con->write(s);
    if (j!=sizeof(s))
    {
diff --git a/lib/modules/Protocols.pmod/IRC.pmod/Requests.pmod b/lib/modules/Protocols.pmod/IRC.pmod/Requests.pmod
index d4b08b5945abf04d286dfee06fce38a5135b1808..7ffddd7c8d9586fa5c88d94d05179f96b9f6e927 100644
--- a/lib/modules/Protocols.pmod/IRC.pmod/Requests.pmod
+++ b/lib/modules/Protocols.pmod/IRC.pmod/Requests.pmod
@@ -6,7 +6,7 @@ NICK Mirar^
 USER mirar mistel.idonex.se irc.starchat.net :Mirar is testing
 */
 
-string __cvs_id="$Id: Requests.pmod,v 1.3 2000/09/28 03:39:01 hubbe Exp $";
+string __cvs_id="$Id: Requests.pmod,v 1.4 2000/11/12 23:41:50 mirar Exp $";
 
 import ".";
 
@@ -17,12 +17,14 @@ class Request
    
    void async(object con,mixed ...args)
    {
-      con->transmit_async(cmd,encode(args),got_answer);
+      con->transmit_noreply(cmd,encode(args));
+      if (callback) call_out(callback,0,1);
    }
 
-   mixed sync(object con,mixed ...args)
-   {
-      return decode_answer(con->transmit(cmd,encode(args)));
+   int(1..1) sync(object con,mixed ...args)
+   { 
+      con->transmit_noreply(cmd,encode(args));
+      return 1;
    }
 
    void got_answer(mixed s)
@@ -47,18 +49,6 @@ inherit Protocols.IRC.Requests.Request;
 
 string cmd=\"%cmd%\";
 
-void async(object con,mixed ...args)
-{
-    con->transmit_noreply(cmd,encode(args));
-    if (callback) call_out(callback,0,1);
-}
-
-int(1..1) sync(object con,mixed ...args)
-{ 
-   con->transmit_noreply(cmd,encode(args));
-   return 1;
-}
-
 string encode(array args)
 {
     %encode%
@@ -110,6 +100,34 @@ object user=NoReply("USER","string","string","string","text");
 object pong=NoReply("PONG","text");
 object ping=NoReply("PING","text");
 object privmsg=NoReply("PRIVMSG","string","text");
+object notice=NoReply("NOTICE","string","text");
 object join=NoReply("JOIN","string");
 object names=NoReply("NAMES","string");
+object who=NoReply("WHO","string");
+object kick=NoReply("KICK","string","string","text");
+
+class mode
+{
+   inherit Request;
+
+   string cmd="MODE";
+
+   string encode(array args)
+   {
+      switch (sizeof(args))
+      {
+         case 2:  
+            return sprintf("%s %s",@args);
+         case 3:  
+            return sprintf("%s %s :%s",@args);
+         default:
+            error("illegal number of args to MODE");
+      }
+   }
+
+   mixed decode_answer(string s)
+   {
+      return 1;
+   }
+};