]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/inspircd.cpp
Fixed invite bugs
[user/henk/code/inspircd.git] / src / inspircd.cpp
index 11a91ca48e96b7da9a97ea17a8f35e4d138c235c..c1eac632fa38b555ab6378080febabf97092c385 100644 (file)
@@ -1601,11 +1601,8 @@ chanrec* add_channel(userrec *user, const char* cn, const char* key, bool overri
                                {
                                        if (servers[j] != NULL)
                                        {
-                                               if (ChanAnyOnThisServer(Ptr,servers[j]->name))
-                                               {
-                                                       me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
-                                                       log(DEBUG,"Sent J token");
-                                               }
+                                               me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
+                                               log(DEBUG,"Sent J token");
                                        }
                                }
                        }
@@ -1676,11 +1673,8 @@ chanrec* del_channel(userrec *user, const char* cname, const char* reason, bool
                                        {
                                                if (servers[j] != NULL)
                                                {
-                                                       if (ChanAnyOnThisServer(Ptr,servers[j]->name))
-                                                       {
-                                                               me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
-                                                               log(DEBUG,"Sent L token (with reason)");
-                                                       }
+                                                       me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
+                                                       log(DEBUG,"Sent L token (with reason)");
                                                }
                                        }
                                }
@@ -1697,11 +1691,8 @@ chanrec* del_channel(userrec *user, const char* cname, const char* reason, bool
                                        {
                                                if (servers[j] != NULL)
                                                {
-                                               if (ChanAnyOnThisServer(Ptr,servers[j]->name))
-                                                       {
-                                                               me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
-                                                               log(DEBUG,"Sent L token (no reason)");
-                                                       }
+                                                       me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
+                                                       log(DEBUG,"Sent L token (no reason)");
                                                }
                                        }
                                }
@@ -1773,7 +1764,8 @@ void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason)
        for (int i =0; i != MAXCHANS; i++)
        {
                /* zap it from the channel list of the user */
-               if (user->chans[i].channel == Ptr)
+               if (user->chans[i].channel)
+               if (!strcasecmp(user->chans[i].channel->name,Ptr->name))
                {
                        WriteChannel(Ptr,src,"KICK %s %s :%s",Ptr->name, user->nick, reason);
                        user->chans[i].uc_modes = 0;
@@ -1830,8 +1822,9 @@ int give_ops(userrec *user,char *dest,chanrec *chan,int status)
                log(DEFAULT,"*** BUG *** give_ops was given an invalid parameter");
                return 0;
        }
-       if (status != STATUS_OP)
+       if (status < STATUS_OP)
        {
+               log(DEBUG,"%s cant give ops to %s because they nave status %d and needs %d",user->nick,dest,status,STATUS_OP);
                WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
                return 0;
        }
@@ -1839,12 +1832,14 @@ int give_ops(userrec *user,char *dest,chanrec *chan,int status)
        {
                if (!isnick(dest))
                {
+                       log(DEFAULT,"the target nickname given to give_ops was invalid");
                        WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
                        return 0;
                }
                d = Find(dest);
                if (!d)
                {
+                       log(DEFAULT,"the target nickname given to give_ops couldnt be found");
                        WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
                        return 0;
                }
@@ -1852,17 +1847,21 @@ int give_ops(userrec *user,char *dest,chanrec *chan,int status)
                {
                        for (int i = 0; i != MAXCHANS; i++)
                        {
-                               if ((d->chans[i].channel == chan) && (chan != NULL))
+                               if ((d->chans[i].channel != NULL) && (chan != NULL))
+                               if (!strcasecmp(d->chans[i].channel->name,chan->name))
                                {
                                        if (d->chans[i].uc_modes & UCMODE_OP)
                                        {
                                                /* mode already set on user, dont allow multiple */
+                                               log(DEFAULT,"The target user given to give_ops was already opped on the channel");
                                                return 0;
                                        }
                                        d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_OP;
                                        log(DEBUG,"gave ops: %s %s",d->chans[i].channel->name,d->nick);
+                                       return 1;
                                }
                        }
+                       log(DEFAULT,"The target channel given to give_ops was not in the users mode list");
                }
        }
        return 1;
@@ -1900,7 +1899,8 @@ int give_hops(userrec *user,char *dest,chanrec *chan,int status)
                {
                        for (int i = 0; i != MAXCHANS; i++)
                        {
-                               if ((d->chans[i].channel == chan) && (chan != NULL))
+                               if ((d->chans[i].channel != NULL) && (chan != NULL))
+                               if (!strcasecmp(d->chans[i].channel->name,chan->name))
                                {
                                        if (d->chans[i].uc_modes & UCMODE_HOP)
                                        {
@@ -1909,6 +1909,7 @@ int give_hops(userrec *user,char *dest,chanrec *chan,int status)
                                        }
                                        d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_HOP;
                                        log(DEBUG,"gave h-ops: %s %s",d->chans[i].channel->name,d->nick);
+                                       return 1;
                                }
                        }
                }
@@ -1948,7 +1949,8 @@ int give_voice(userrec *user,char *dest,chanrec *chan,int status)
                {
                        for (int i = 0; i != MAXCHANS; i++)
                        {
-                               if ((d->chans[i].channel == chan) && (chan != NULL))
+                               if ((d->chans[i].channel != NULL) && (chan != NULL))
+                               if (!strcasecmp(d->chans[i].channel->name,chan->name))
                                {
                                        if (d->chans[i].uc_modes & UCMODE_VOICE)
                                        {
@@ -1957,6 +1959,7 @@ int give_voice(userrec *user,char *dest,chanrec *chan,int status)
                                        }
                                        d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_VOICE;
                                        log(DEBUG,"gave voice: %s %s",d->chans[i].channel->name,d->nick);
+                                       return 1;
                                }
                        }
                }
@@ -1974,8 +1977,9 @@ int take_ops(userrec *user,char *dest,chanrec *chan,int status)
                log(DEFAULT,"*** BUG *** take_ops was given an invalid parameter");
                return 0;
        }
-       if (status != STATUS_OP)
+       if (status < STATUS_OP)
        {
+               log(DEBUG,"%s cant give ops to %s because they have status %d and needs %d",user->nick,dest,status,STATUS_OP);
                WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
                return 0;
        }
@@ -1984,11 +1988,13 @@ int take_ops(userrec *user,char *dest,chanrec *chan,int status)
                d = Find(dest);
                if (!isnick(dest))
                {
+                       log(DEBUG,"take_ops was given an invalid target nickname of %s",dest);
                        WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
                        return 0;
                }
                if (!d)
                {
+                       log(DEBUG,"take_ops couldnt resolve the target nickname: %s",dest);
                        WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
                        return 0;
                }
@@ -1996,7 +2002,8 @@ int take_ops(userrec *user,char *dest,chanrec *chan,int status)
                {
                        for (int i = 0; i != MAXCHANS; i++)
                        {
-                               if ((d->chans[i].channel == chan) && (chan != NULL))
+                               if ((d->chans[i].channel != NULL) && (chan != NULL))
+                               if (!strcasecmp(d->chans[i].channel->name,chan->name))
                                {
                                        if ((d->chans[i].uc_modes & UCMODE_OP) == 0)
                                        {
@@ -2005,8 +2012,10 @@ int take_ops(userrec *user,char *dest,chanrec *chan,int status)
                                        }
                                        d->chans[i].uc_modes ^= UCMODE_OP;
                                        log(DEBUG,"took ops: %s %s",d->chans[i].channel->name,d->nick);
+                                       return 1;
                                }
                        }
+                       log(DEBUG,"take_ops couldnt locate the target channel in the target users list");
                }
        }
        return 1;
@@ -2044,7 +2053,8 @@ int take_hops(userrec *user,char *dest,chanrec *chan,int status)
                {
                        for (int i = 0; i != MAXCHANS; i++)
                        {
-                               if ((d->chans[i].channel == chan) && (chan != NULL))
+                               if ((d->chans[i].channel != NULL) && (chan != NULL))
+                               if (!strcasecmp(d->chans[i].channel->name,chan->name))
                                {
                                        if ((d->chans[i].uc_modes & UCMODE_HOP) == 0)
                                        {
@@ -2053,6 +2063,7 @@ int take_hops(userrec *user,char *dest,chanrec *chan,int status)
                                        }
                                        d->chans[i].uc_modes ^= UCMODE_HOP;
                                        log(DEBUG,"took h-ops: %s %s",d->chans[i].channel->name,d->nick);
+                                       return 1;
                                }
                        }
                }
@@ -2092,7 +2103,8 @@ int take_voice(userrec *user,char *dest,chanrec *chan,int status)
                {
                        for (int i = 0; i != MAXCHANS; i++)
                        {
-                               if ((d->chans[i].channel == chan) && (chan != NULL))
+                               if ((d->chans[i].channel != NULL) && (chan != NULL))
+                               if (!strcasecmp(d->chans[i].channel->name,chan->name))
                                {
                                        if ((d->chans[i].uc_modes & UCMODE_VOICE) == 0)
                                        {
@@ -2101,6 +2113,7 @@ int take_voice(userrec *user,char *dest,chanrec *chan,int status)
                                        }
                                        d->chans[i].uc_modes ^= UCMODE_VOICE;
                                        log(DEBUG,"took voice: %s %s",d->chans[i].channel->name,d->nick);
+                                       return 1;
                                }
                        }
                }
@@ -2204,7 +2217,7 @@ int take_ban(userrec *user,char *dest,chanrec *chan,int status)
        return 0;
 }
 
-void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int pcnt, bool servermode, bool silent)
+void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int pcnt, bool servermode, bool silent, bool local)
 {
        if (!parameters) {
                log(DEFAULT,"*** BUG *** process_modes was given an invalid parameter");
@@ -2227,7 +2240,7 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                return;
        }
 
-       log(DEBUG,"process_modes: start");
+       log(DEBUG,"process_modes: start: parameters=%d",pcnt);
 
        strcpy(modelist,parameters[1]); /* mode list, e.g. +oo-o */
                                        /* parameters[2] onwards are parameters for
@@ -2278,13 +2291,17 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                                break;
 
                                case 'o':
+                                       log(DEBUG,"Ops");
                                        if ((param >= pcnt)) break;
+                                       log(DEBUG,"Enough parameters left");
                                        if (mdir == 1)
                                        {
+                                               log(DEBUG,"calling give_ops");
                                                r = give_ops(user,parameters[param++],chan,status);
                                        }
                                        else
                                        {
+                                               log(DEBUG,"calling take_ops");
                                                r = take_ops(user,parameters[param++],chan,status);
                                        }
                                        if (r)
@@ -2587,21 +2604,26 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                        strcat(outstr," ");
                        strcat(outstr,outpars[ptr]);
                }
-               if (servermode)
+               if (local)
                {
-                       if (!silent)
+                       log(DEBUG,"Local mode change");
+                       WriteChannelLocal(chan, user, "MODE %s %s",chan->name,outstr);
+               }
+               else
+               {
+                       if (servermode)
                        {
-                               WriteChannelWithServ(ServerName,chan,user,"MODE %s %s",chan->name,outstr);
-                               // M token for a usermode must go to all servers
-                               char buffer[MAXBUF];
-                               snprintf(buffer,MAXBUF,"M %s %s",ServerName,chan->name, outstr);
-                               for (int j = 0; j < 255; j++)
+                               if (!silent)
                                {
-                                       if (servers[j] != NULL)
+                                       WriteChannelWithServ(ServerName,chan,user,"MODE %s %s",chan->name,outstr);
+                                       // M token for a usermode must go to all servers
+                                       char buffer[MAXBUF];
+                                       snprintf(buffer,MAXBUF,"M %s %s",chan->name, outstr);
+                                       for (int j = 0; j < 255; j++)
                                        {
-                                               if (strcmp(servers[j]->name,ServerName))
+                                               if (servers[j] != NULL)
                                                {
-                                                       if (ChanAnyOnThisServer(chan,servers[j]->name))
+                                                       if (strcmp(servers[j]->name,ServerName))
                                                        {
                                                                me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
                                                                log(DEBUG,"Sent M token");
@@ -2609,24 +2631,21 @@ void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int
                                                }
                                        }
                                }
+                                       
                        }
-                               
-               }
-               else
-               {
-                       if (!silent)
+                       else
                        {
-                               WriteChannel(chan,user,"MODE %s %s",chan->name,outstr);
-                               // M token for a usermode must go to all servers
-                               char buffer[MAXBUF];
-                               snprintf(buffer,MAXBUF,"m %s %s %s",user->nick,chan->name, outstr);
-                               for (int j = 0; j < 255; j++)
+                               if (!silent)
                                {
-                                       if (servers[j] != NULL)
+                                       WriteChannel(chan,user,"MODE %s %s",chan->name,outstr);
+                                       // M token for a usermode must go to all servers
+                                       char buffer[MAXBUF];
+                                       snprintf(buffer,MAXBUF,"m %s %s %s",user->nick,chan->name, outstr);
+                                       for (int j = 0; j < 255; j++)
                                        {
-                                               if (strcmp(servers[j]->name,ServerName))
+                                               if (servers[j] != NULL)
                                                {
-                                                       if (ChanAnyOnThisServer(chan,servers[j]->name))
+                                                       if (strcmp(servers[j]->name,ServerName))
                                                        {
                                                                me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
                                                                log(DEBUG,"Sent m token");
@@ -2963,6 +2982,7 @@ void handle_mode(char **parameters, int pcnt, userrec *user)
                                        WriteServ(user->fd,"367 %s %s %s %s %d",user->nick, Ptr->name, i->data, i->set_by, i->set_time);
                                }
                                WriteServ(user->fd,"368 %s %s :End of channel ban list",user->nick, Ptr->name);
+                               return;
                        }
                }
 
@@ -2972,7 +2992,7 @@ void handle_mode(char **parameters, int pcnt, userrec *user)
                        return;
                }
 
-               process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt,false,false);
+               process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt,false,false,false);
        }
        else
        {
@@ -3169,7 +3189,7 @@ void server_mode(char **parameters, int pcnt, userrec *user)
        Ptr = FindChan(parameters[0]);
        if (Ptr)
        {
-               process_modes(parameters,user,Ptr,STATUS_OP,pcnt,true,false);
+               process_modes(parameters,user,Ptr,STATUS_OP,pcnt,true,false,false);
        }
        else
        {
@@ -3352,7 +3372,7 @@ void merge_mode(char **parameters, int pcnt)
                strncpy(s2.nick,ServerName,NICKMAX);
                strcpy(s2.modes,"o");
                s2.fd = -1;
-               process_modes(parameters,&s2,Ptr,STATUS_OP,pcnt,true,true);
+               process_modes(parameters,&s2,Ptr,STATUS_OP,pcnt,true,true,false);
        }
 }
 
@@ -3510,6 +3530,8 @@ void merge_mode2(char **parameters, int pcnt, userrec* user)
                        if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
                                return;
 
+                       WriteTo(user,dest,"MODE :%s",b);
+
                        if (strlen(dmodes)>MAXMODES)
                        {
                                dmodes[MAXMODES-1] = '\0';
@@ -3526,7 +3548,12 @@ void merge_mode2(char **parameters, int pcnt, userrec* user)
        Ptr = FindChan(parameters[0]);
        if (Ptr)
        {
-               process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt,false,true);
+               if ((cstatus(user,Ptr) < STATUS_HOP) && (Ptr))
+               {
+                       return;
+               }
+
+               process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt,false,false,true);
        }
 }
 
@@ -3743,10 +3770,11 @@ void handle_kick(char **parameters, int pcnt, userrec *user)
                WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, parameters[0]);
                return;
        }
+
+       char reason[MAXBUF];
        
        if (pcnt > 2)
        {
-               char reason[MAXBUF];
                strncpy(reason,parameters[2],MAXBUF);
                if (strlen(reason)>MAXKICK)
                {
@@ -3757,8 +3785,23 @@ void handle_kick(char **parameters, int pcnt, userrec *user)
        }
        else
        {
-               kick_channel(user,u,Ptr,user->nick);
+               strcpy(reason,user->nick);
+               kick_channel(user,u,Ptr,reason);
+       }
+       
+       // this must be propogated so that channel membership is kept in step network-wide
+       
+       char buffer[MAXBUF];
+       snprintf(buffer,MAXBUF,"k %s %s %s :%s",user->nick,u->nick,Ptr->name,reason);
+       for (int j = 0; j < 255; j++)
+       {
+               if (servers[j] != NULL)
+               {
+                       me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
+                       log(DEBUG,"Sent k token");
+               }
        }
+       
 }
 
 
@@ -3976,6 +4019,21 @@ void handle_invite(char **parameters, int pcnt, userrec *user)
        u->InviteTo(c->name);
        WriteFrom(u->fd,user,"INVITE %s :%s",u->nick,c->name);
        WriteServ(user->fd,"341 %s %s %s",user->nick,u->nick,c->name);
+       
+       // i token must go to ALL servers!!!
+       char buffer[MAXBUF];
+       snprintf(buffer,MAXBUF,"i %s %s %s",u->nick,user->nick,c->name);
+       for (int j = 0; j < 255; j++)
+       {
+               if (servers[j] != NULL)
+               {
+                       if (strcmp(servers[j]->name,ServerName))
+                       {
+                               me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
+                               log(DEBUG,"Sent i token");
+                       }
+               }
+       }
 }
 
 void handle_topic(char **parameters, int pcnt, userrec *user)
@@ -4030,6 +4088,21 @@ void handle_topic(char **parameters, int pcnt, userrec *user)
                                strcpy(Ptr->setby,user->nick);
                                Ptr->topicset = time(NULL);
                                WriteChannel(Ptr,user,"TOPIC %s :%s",Ptr->name, Ptr->topic);
+
+                               // t token must go to ALL servers!!!
+                               char buffer[MAXBUF];
+                               snprintf(buffer,MAXBUF,"t %s %s :%s",user->nick,Ptr->name,topic);
+                               for (int j = 0; j < 255; j++)
+                               {
+                                       if (servers[j] != NULL)
+                                       {
+                                               if (strcmp(servers[j]->name,ServerName))
+                                               {
+                                                       me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
+                                                       log(DEBUG,"Sent t token");
+                                               }
+                                       }
+                               }
                        }
                        else
                        {
@@ -4596,6 +4669,20 @@ void handle_whois(char **parameters, int pcnt, userrec *user)
        }
 }
 
+void send_network_quit(const char* nick, const char* reason)
+{
+               char buffer[MAXBUF];
+               snprintf(buffer,MAXBUF,"Q %s :%s",nick,reason);
+               for (int j = 0; j < 255; j++)
+               {
+                       if (servers[j] != NULL)
+                       {
+                               me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
+                               log(DEBUG,"Sent Q token");
+                       }
+               }
+}
+
 void handle_quit(char **parameters, int pcnt, userrec *user)
 {
        user_hash::iterator iter = clientlist.find(user->nick);
@@ -4627,12 +4714,9 @@ void handle_quit(char **parameters, int pcnt, userrec *user)
                        {
                                if (servers[j] != NULL)
                                {
-                                       if (CommonOnThisServer(user,servers[j]->name))
-                                       {
-                                               me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
-                                               log(DEBUG,"Sent Q token");
-                                       }
-                                       }
+                                       me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
+                                       log(DEBUG,"Sent Q token");
+                               }
                        }
                }
                else
@@ -4647,12 +4731,9 @@ void handle_quit(char **parameters, int pcnt, userrec *user)
                        {
                                if (servers[j] != NULL)
                                {
-                                       if (CommonOnThisServer(user,servers[j]->name))
-                                       {
-                                               me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
-                                               log(DEBUG,"Sent Q token");
-                                       }
-                                       }
+                                       me[defaultRoute]->SendPacket(buffer,servers[j]->internal_addr,servers[j]->internal_port,MyKey);
+                                       log(DEBUG,"Sent Q token");
+                               }
                        }
                }
                FOREACH_MOD OnUserQuit(user);
@@ -5098,6 +5179,28 @@ void handle_modules(char **parameters, int pcnt, userrec *user)
        }
 }
 
+// calls a handler function for a command
+
+void call_handler(const char* commandname,char **parameters, int pcnt, userrec *user)
+{
+               for (int i = 0; i < cmdlist.size(); i++)
+               {
+                       if (!strcasecmp(cmdlist[i].command,commandname))
+                       {
+                               if (cmdlist[i].handler_function)
+                               {
+                                       if (pcnt>=cmdlist[i].min_params)
+                                       {
+                                               if (strchr(user->modes,cmdlist[i].flags_needed))
+                                               {
+                                                       cmdlist[i].handler_function(parameters,pcnt,user);
+                                               }
+                                       }
+                               }
+                       }
+               }
+}
+
 void handle_stats(char **parameters, int pcnt, userrec *user)
 {
        if (pcnt != 1)
@@ -5953,6 +6056,37 @@ void handle_P(char token,char* params,serverrec* source,serverrec* reply, char*
        
 }
 
+void handle_i(char token,char* params,serverrec* source,serverrec* reply, char* udp_host,int udp_port)
+{
+       char* nick = strtok(params," ");
+       char* from = strtok(NULL," ");
+       char* channel = strtok(NULL," ");
+       userrec* u = Find(nick);
+       userrec* user = Find(from);
+       chanrec* c = FindChan(channel);
+       if ((c) && (u) && (user))
+       {
+               u->InviteTo(c->name);
+               WriteFrom(u->fd,user,"INVITE %s :%s",u->nick,c->name);
+       }
+}
+
+void handle_t(char token,char* params,serverrec* source,serverrec* reply, char* udp_host,int udp_port)
+{
+       char* setby = strtok(params," ");
+       char* channel = strtok(NULL," :");
+       char* topic = strtok(NULL,"\r\n");
+       topic++;
+       userrec* u = Find(setby);
+       chanrec* c = FindChan(channel);
+       if ((c) && (u))
+       {
+               WriteChannelLocal(c,u,"TOPIC %s :%s",c->name,topic);
+               strncpy(c->topic,topic,MAXTOPIC);
+               strncpy(c->setby,u->nick,NICKMAX);
+       }       
+}
+       
 
 void handle_T(char token,char* params,serverrec* source,serverrec* reply, char* udp_host,int udp_port)
 {
@@ -5988,7 +6122,7 @@ void handle_M(char token,char* params,serverrec* source,serverrec* reply, char*
                pars[index++] = parameter;
                parameter = strtok(NULL," ");
        }
-       merge_mode(pars,--index);
+       merge_mode(pars,index);
        if (FindChan(target))
        {
                WriteChannelLocal(FindChan(target), NULL, "MODE %s",original);
@@ -6014,11 +6148,6 @@ void handle_m(char token,char* params,serverrec* source,serverrec* reply, char*
                return;
        }
        
-       char* o = original;
-       while (o[0] != ' ')
-               o++;
-       o++;
-       
        int index = 0;
        
        char* src = strtok(params," ");
@@ -6035,17 +6164,7 @@ void handle_m(char token,char* params,serverrec* source,serverrec* reply, char*
                }
                
                log(DEBUG,"Calling merge_mode2");
-               merge_mode2(pars,--index,user);
-               if (FindChan(pars[0]))
-               {
-                       log(DEBUG,"Target is channel");
-                       WriteChannelLocal(FindChan(pars[0]), user, "MODE %s",o);
-               }
-               if (Find(pars[0]))
-               {
-                       log(DEBUG,"Target is nick");
-                       WriteTo(user,Find(pars[0]),"MODE %s",o);
-               }
+               merge_mode2(pars,index,user);
        }
 }
 
@@ -6121,6 +6240,23 @@ void handle_n(char token,char* params,serverrec* source,serverrec* reply, char*
        }
 }
 
+// k <SOURCE> <DEST> <CHANNEL> :<REASON>
+void handle_k(char token,char* params,serverrec* source,serverrec* reply, char* udp_host,int udp_port)
+{
+       char* src = strtok(params," ");
+       char* dest = strtok(NULL," ");
+       char* channel = strtok(NULL," :");
+       char* reason = strtok(NULL,"\r\n");
+       reason++;
+       userrec* s = Find(src);
+       userrec* d = Find(dest);
+       chanrec* c = FindChan(channel);
+       if ((s) && (d) && (c))
+       {
+               kick_channel(s,d,c,reason);
+       }
+}
+
 void handle_N(char token,char* params,serverrec* source,serverrec* reply, char* udp_host,int udp_port)
 {
        char* tm = strtok(params," ");
@@ -6220,7 +6356,7 @@ void handle_J(char token,char* params,serverrec* source,serverrec* reply, char*
                                                if (privilage == '+')
                                                {
                                                        user->chans[i].uc_modes = user->chans[i].uc_modes | UCMODE_VOICE;
-                                                       WriteChannelLocal(user->chans[i].channel, NULL, "MODE %s +o %s",channel,user->nick);
+                                                       WriteChannelLocal(user->chans[i].channel, NULL, "MODE %s +v %s",channel,user->nick);
                                                }
                                        }
                                }
@@ -6246,6 +6382,21 @@ void process_restricted_commands(char token,char* params,serverrec* source,serve
                case 'N':
                        handle_N(token,params,source,reply,udp_host,udp_port);
                break;
+               // t <NICK> <CHANNEL> :<TOPIC>
+               // change a channel topic
+               case 't':
+                       handle_t(token,params,source,reply,udp_host,udp_port);
+               break;
+               // i <NICK> <CHANNEL>
+               // invite a user to a channel
+               case 'i':
+                       handle_i(token,params,source,reply,udp_host,udp_port);
+               break;
+               // k <SOURCE> <DEST> <CHANNEL> :<REASON>
+               // kick a user from a channel
+               case 'k':
+                       handle_k(token,params,source,reply,udp_host,udp_port);
+               break;
                // n <NICK> <NEWNICK>
                // change nickname of client -- a server should only be able to
                // change the nicknames of clients that reside on it unless