]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/commands.cpp
c142e58b2f4f047ad12d4a00a9ec26a9320d9d13
[user/henk/code/inspircd.git] / src / commands.cpp
1 #include "inspircd.h"
2 #include "inspircd_io.h"
3 #include "inspircd_util.h"
4 #include "inspircd_config.h"
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/errno.h>
8 #include <sys/ioctl.h>
9 #include <sys/utsname.h>
10 #include <cstdio>
11 #include <time.h>
12 #include <string>
13 #ifdef GCC3
14 #include <ext/hash_map>
15 #else
16 #include <hash_map>
17 #endif
18 #include <map>
19 #include <sstream>
20 #include <vector>
21 #include <errno.h>
22 #include <deque>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <sched.h>
26 #include "connection.h"
27 #include "users.h"
28 #include "servers.h"
29 #include "ctables.h"
30 #include "globals.h"
31 #include "modules.h"
32 #include "dynamic.h"
33 #include "wildcard.h"
34 #include "message.h"
35 #include "mode.h"
36
37 #ifdef GCC3
38 #define nspace __gnu_cxx
39 #else
40 #define nspace std
41 #endif
42
43 using namespace std;
44
45 extern int MODCOUNT;
46 extern vector<Module*> modules;
47 extern vector<ircd_module*> factory;
48
49 extern int LogLevel;
50 extern char ServerName[MAXBUF];
51 extern char Network[MAXBUF];
52 extern char ServerDesc[MAXBUF];
53 extern char AdminName[MAXBUF];
54 extern char AdminEmail[MAXBUF];
55 extern char AdminNick[MAXBUF];
56 extern char diepass[MAXBUF];
57 extern char restartpass[MAXBUF];
58 extern char motd[MAXBUF];
59 extern char rules[MAXBUF];
60 extern char list[MAXBUF];
61 extern char PrefixQuit[MAXBUF];
62 extern char DieValue[MAXBUF];
63
64 extern int debugging;
65 extern int WHOWAS_STALE;
66 extern int WHOWAS_MAX;
67 extern int DieDelay;
68 extern time_t startup_time;
69 extern int NetBufferSize;
70 extern time_t nb_start;
71
72 extern std::vector<int> fd_reap;
73 extern std::vector<std::string> module_names;
74
75 extern char bannerBuffer[MAXBUF];
76 extern int boundPortCount;
77 extern int portCount;
78 extern int UDPportCount;
79 extern int ports[MAXSOCKS];
80 extern int defaultRoute;
81
82 extern std::vector<long> auth_cookies;
83 extern std::stringstream config_f;
84
85 extern serverrec* me[32];
86
87 extern FILE *log_file;
88
89 namespace nspace
90 {
91         template<> struct nspace::hash<in_addr>
92         {
93                 size_t operator()(const struct in_addr &a) const
94                 {
95                         size_t q;
96                         memcpy(&q,&a,sizeof(size_t));
97                         return q;
98                 }
99         };
100
101         template<> struct nspace::hash<string>
102         {
103                 size_t operator()(const string &s) const
104                 {
105                         char a[MAXBUF];
106                         static struct hash<const char *> strhash;
107                         strcpy(a,s.c_str());
108                         strlower(a);
109                         return strhash(a);
110                 }
111         };
112 }       
113
114
115 struct StrHashComp
116 {
117
118         bool operator()(const string& s1, const string& s2) const
119         {
120                 char a[MAXBUF],b[MAXBUF];
121                 strcpy(a,s1.c_str());
122                 strcpy(b,s2.c_str());
123                 return (strcasecmp(a,b) == 0);
124         }
125
126 };
127
128 struct InAddr_HashComp
129 {
130
131         bool operator()(const in_addr &s1, const in_addr &s2) const
132         {
133                 size_t q;
134                 size_t p;
135                 
136                 memcpy(&q,&s1,sizeof(size_t));
137                 memcpy(&p,&s2,sizeof(size_t));
138                 
139                 return (q == p);
140         }
141
142 };
143
144
145 typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, StrHashComp> user_hash;
146 typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, StrHashComp> chan_hash;
147 typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, InAddr_HashComp> address_cache;
148 typedef std::deque<command_t> command_table;
149
150
151 extern user_hash clientlist;
152 extern chan_hash chanlist;
153 extern user_hash whowas;
154 extern command_table cmdlist;
155 extern file_cache MOTD;
156 extern file_cache RULES;
157 extern address_cache IP;
158
159
160 void handle_join(char **parameters, int pcnt, userrec *user)
161 {
162         chanrec* Ptr;
163         int i = 0;
164         
165         if (loop_call(handle_join,parameters,pcnt,user,0,0,1))
166                 return;
167         if (parameters[0][0] == '#')
168         {
169                 Ptr = add_channel(user,parameters[0],parameters[1],false);
170         }
171 }
172
173
174 void handle_part(char **parameters, int pcnt, userrec *user)
175 {
176         chanrec* Ptr;
177
178         if (pcnt > 1)
179         {
180                 if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-2,0))
181                         return;
182                 del_channel(user,parameters[0],parameters[1],false);
183         }
184         else
185         {
186                 if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-1,0))
187                         return;
188                 del_channel(user,parameters[0],NULL,false);
189         }
190 }
191
192 void handle_kick(char **parameters, int pcnt, userrec *user)
193 {
194         chanrec* Ptr = FindChan(parameters[0]);
195         userrec* u   = Find(parameters[1]);
196
197         if ((!u) || (!Ptr))
198         {
199                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
200                 return;
201         }
202         
203         if (!has_channel(u,Ptr))
204         {
205                 WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, parameters[0]);
206                 return;
207         }
208
209         char reason[MAXBUF];
210         
211         if (pcnt > 2)
212         {
213                 strncpy(reason,parameters[2],MAXBUF);
214                 if (strlen(reason)>MAXKICK)
215                 {
216                         reason[MAXKICK-1] = '\0';
217                 }
218
219                 kick_channel(user,u,Ptr,reason);
220         }
221         else
222         {
223                 strcpy(reason,user->nick);
224                 kick_channel(user,u,Ptr,reason);
225         }
226         
227         // this must be propogated so that channel membership is kept in step network-wide
228         
229         char buffer[MAXBUF];
230         snprintf(buffer,MAXBUF,"k %s %s %s :%s",user->nick,u->nick,Ptr->name,reason);
231         NetSendToAll(buffer);
232 }
233
234
235 void handle_die(char **parameters, int pcnt, userrec *user)
236 {
237         log(DEBUG,"die: %s",user->nick);
238         if (!strcmp(parameters[0],diepass))
239         {
240                 WriteOpers("*** DIE command from %s!%s@%s, terminating...",user->nick,user->ident,user->host);
241                 sleep(DieDelay);
242                 Exit(ERROR);
243         }
244         else
245         {
246                 WriteOpers("*** Failed DIE Command from %s!%s@%s.",user->nick,user->ident,user->host);
247         }
248 }
249
250 void handle_restart(char **parameters, int pcnt, userrec *user)
251 {
252         log(DEBUG,"restart: %s",user->nick);
253         if (!strcmp(parameters[0],restartpass))
254         {
255                 WriteOpers("*** RESTART command from %s!%s@%s, Pretending to restart till this is finished :D",user->nick,user->ident,user->host);
256                 sleep(DieDelay);
257                 Exit(ERROR);
258                 /* Will finish this later when i can be arsed :) */
259         }
260         else
261         {
262                 WriteOpers("*** Failed RESTART Command from %s!%s@%s.",user->nick,user->ident,user->host);
263         }
264 }
265
266 void handle_kill(char **parameters, int pcnt, userrec *user)
267 {
268         userrec *u = Find(parameters[0]);
269         char killreason[MAXBUF];
270         
271         log(DEBUG,"kill: %s %s",parameters[0],parameters[1]);
272         if (u)
273         {
274                 if (strcmp(ServerName,u->server))
275                 {
276                         // remote kill
277                         WriteOpers("*** Remote kill by %s: %s!%s@%s (%s)",user->nick,u->nick,u->ident,u->host,parameters[1]);
278                         sprintf(killreason,"[%s] Killed (%s (%s))",ServerName,user->nick,parameters[1]);
279                         WriteCommonExcept(u,"QUIT :%s",killreason);
280                         // K token must go to ALL servers!!!
281                         char buffer[MAXBUF];
282                         snprintf(buffer,MAXBUF,"K %s %s :%s",user->nick,u->nick,killreason);
283                         NetSendToAll(buffer);
284                         
285                         user_hash::iterator iter = clientlist.find(u->nick);
286                         if (iter != clientlist.end())
287                         {
288                                 log(DEBUG,"deleting user hash value %d",iter->second);
289                                 if ((iter->second) && (user->registered == 7)) {
290                                         delete iter->second;
291                                         }
292                         clientlist.erase(iter);
293                         }
294                         purge_empty_chans();
295                 }
296                 else
297                 {
298                         // local kill
299                         WriteTo(user, u, "KILL %s :%s!%s!%s (%s)", u->nick, ServerName,user->dhost,user->nick,parameters[1]);
300                         WriteOpers("*** Local Kill by %s: %s!%s@%s (%s)",user->nick,u->nick,u->ident,u->host,parameters[1]);
301                         sprintf(killreason,"Killed (%s (%s))",user->nick,parameters[1]);
302                         kill_link(u,killreason);
303                 }
304         }
305         else
306         {
307                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
308         }
309 }
310
311 void handle_summon(char **parameters, int pcnt, userrec *user)
312 {
313         WriteServ(user->fd,"445 %s :SUMMON has been disabled (depreciated command)",user->nick);
314 }
315
316 void handle_users(char **parameters, int pcnt, userrec *user)
317 {
318         WriteServ(user->fd,"445 %s :USERS has been disabled (depreciated command)",user->nick);
319 }
320
321 void handle_pass(char **parameters, int pcnt, userrec *user)
322 {
323         // Check to make sure they havnt registered -- Fix by FCS
324         if (user->registered == 7)
325         {
326                 WriteServ(user->fd,"462 %s :You may not reregister",user->nick);
327                 return;
328         }
329         if (!strcasecmp(parameters[0],Passwd(user)))
330         {
331                 user->haspassed = true;
332         }
333 }
334
335 void handle_invite(char **parameters, int pcnt, userrec *user)
336 {
337         userrec* u = Find(parameters[0]);
338         chanrec* c = FindChan(parameters[1]);
339
340         if ((!c) || (!u))
341         {
342                 if (!c)
343                 {
344                         WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[1]);
345                 }
346                 else
347                 {
348                         if (c->inviteonly)
349                         {
350                                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
351                         }
352                 }
353
354                 return;
355         }
356
357         if (c->inviteonly)
358         {
359                 if (cstatus(user,c) < STATUS_HOP)
360                 {
361                         WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, c->name);
362                         return;
363                 }
364         }
365         if (has_channel(u,c))
366         {
367                 WriteServ(user->fd,"443 %s %s %s :Is already on channel %s",user->nick,u->nick,c->name,c->name);
368                 return;
369         }
370         if (!has_channel(user,c))
371         {
372                 WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, c->name);
373                 return;
374         }
375         u->InviteTo(c->name);
376         WriteFrom(u->fd,user,"INVITE %s :%s",u->nick,c->name);
377         WriteServ(user->fd,"341 %s %s %s",user->nick,u->nick,c->name);
378         
379         // i token must go to ALL servers!!!
380         char buffer[MAXBUF];
381         snprintf(buffer,MAXBUF,"i %s %s %s",u->nick,user->nick,c->name);
382         NetSendToAll(buffer);
383 }
384
385 void handle_topic(char **parameters, int pcnt, userrec *user)
386 {
387         chanrec* Ptr;
388
389         if (pcnt == 1)
390         {
391                 if (strlen(parameters[0]) <= CHANMAX)
392                 {
393                         Ptr = FindChan(parameters[0]);
394                         if (Ptr)
395                         {
396                                 if (Ptr->topicset)
397                                 {
398                                         WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
399                                         WriteServ(user->fd,"333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset);
400                                 }
401                                 else
402                                 {
403                                         WriteServ(user->fd,"331 %s %s :No topic is set.", user->nick, Ptr->name);
404                                 }
405                         }
406                         else
407                         {
408                                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
409                         }
410                 }
411                 return;
412         }
413         else if (pcnt>1)
414         {
415                 if (strlen(parameters[0]) <= CHANMAX)
416                 {
417                         Ptr = FindChan(parameters[0]);
418                         if (Ptr)
419                         {
420                                 if ((Ptr->topiclock) && (cstatus(user,Ptr)<STATUS_HOP))
421                                 {
422                                         WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel", user->nick, Ptr->name);
423                                         return;
424                                 }
425                                 
426                                 char topic[MAXBUF];
427                                 strncpy(topic,parameters[1],MAXBUF);
428                                 if (strlen(topic)>MAXTOPIC)
429                                 {
430                                         topic[MAXTOPIC-1] = '\0';
431                                 }
432                                         
433                                 strcpy(Ptr->topic,topic);
434                                 strcpy(Ptr->setby,user->nick);
435                                 Ptr->topicset = time(NULL);
436                                 WriteChannel(Ptr,user,"TOPIC %s :%s",Ptr->name, Ptr->topic);
437
438                                 // t token must go to ALL servers!!!
439                                 char buffer[MAXBUF];
440                                 snprintf(buffer,MAXBUF,"t %s %s :%s",user->nick,Ptr->name,topic);
441                                 NetSendToAll(buffer);
442                         }
443                         else
444                         {
445                                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
446                         }
447                 }
448         }
449 }
450
451 void handle_names(char **parameters, int pcnt, userrec *user)
452 {
453         chanrec* c;
454
455         if (loop_call(handle_names,parameters,pcnt,user,0,pcnt-1,0))
456                 return;
457         c = FindChan(parameters[0]);
458         if (c)
459         {
460                 /*WriteServ(user->fd,"353 %s = %s :%s", user->nick, c->name,*/
461                 userlist(user,c);
462                 WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, c->name);
463         }
464         else
465         {
466                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
467         }
468 }
469
470 void handle_privmsg(char **parameters, int pcnt, userrec *user)
471 {
472         userrec *dest;
473         chanrec *chan;
474
475         user->idle_lastmsg = time(NULL);
476         
477         if (loop_call(handle_privmsg,parameters,pcnt,user,0,pcnt-2,0))
478                 return;
479         if (parameters[0][0] == '#')
480         {
481                 chan = FindChan(parameters[0]);
482                 if (chan)
483                 {
484                         if ((chan->noexternal) && (!has_channel(user,chan)))
485                         {
486                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
487                                 return;
488                         }
489                         if ((chan->moderated) && (cstatus(user,chan)<STATUS_VOICE))
490                         {
491                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
492                                 return;
493                         }
494                         
495                         int MOD_RESULT = 0;
496
497                         FOREACH_RESULT(OnUserPreMessage(user,chan,TYPE_CHANNEL,std::string(parameters[1])));
498                         if (MOD_RESULT) {
499                                 return;
500                         }
501                         
502                         ChanExceptSender(chan, user, "PRIVMSG %s :%s", chan->name, parameters[1]);
503                         
504                         // if any users of this channel are on remote servers, broadcast the packet
505                         char buffer[MAXBUF];
506                         snprintf(buffer,MAXBUF,"P %s %s :%s",user->nick,chan->name,parameters[1]);
507                         NetSendToCommon(user,buffer);
508                 }
509                 else
510                 {
511                         /* no such nick/channel */
512                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
513                 }
514                 return;
515         }
516         
517         dest = Find(parameters[0]);
518         if (dest)
519         {
520                 if (strcmp(dest->awaymsg,""))
521                 {
522                         /* auto respond with aweh msg */
523                         WriteServ(user->fd,"301 %s %s :%s",user->nick,dest->nick,dest->awaymsg);
524                 }
525
526                 int MOD_RESULT = 0;
527                 
528                 FOREACH_RESULT(OnUserPreMessage(user,dest,TYPE_USER,std::string(parameters[1])));
529                 if (MOD_RESULT) {
530                         return;
531                 }
532
533
534
535                 if (!strcmp(dest->server,user->server))
536                 {
537                         // direct write, same server
538                         WriteTo(user, dest, "PRIVMSG %s :%s", dest->nick, parameters[1]);
539                 }
540                 else
541                 {
542                         char buffer[MAXBUF];
543                         snprintf(buffer,MAXBUF,"P %s %s :%s",user->nick,dest->nick,parameters[1]);
544                         NetSendToOne(dest->server,buffer);
545                 }
546         }
547         else
548         {
549                 /* no such nick/channel */
550                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
551         }
552 }
553
554 void handle_notice(char **parameters, int pcnt, userrec *user)
555 {
556         userrec *dest;
557         chanrec *chan;
558
559         user->idle_lastmsg = time(NULL);
560         
561         if (loop_call(handle_notice,parameters,pcnt,user,0,pcnt-2,0))
562                 return;
563         if (parameters[0][0] == '#')
564         {
565                 chan = FindChan(parameters[0]);
566                 if (chan)
567                 {
568                         if ((chan->noexternal) && (!has_channel(user,chan)))
569                         {
570                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
571                                 return;
572                         }
573                         if ((chan->moderated) && (cstatus(user,chan)<STATUS_VOICE))
574                         {
575                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
576                                 return;
577                         }
578
579                         int MOD_RESULT = 0;
580                 
581                         FOREACH_RESULT(OnUserPreNotice(user,chan,TYPE_CHANNEL,std::string(parameters[1])));
582                         if (MOD_RESULT) {
583                                 return;
584                         }
585
586                         ChanExceptSender(chan, user, "NOTICE %s :%s", chan->name, parameters[1]);
587
588                         // if any users of this channel are on remote servers, broadcast the packet
589                         char buffer[MAXBUF];
590                         snprintf(buffer,MAXBUF,"V %s %s :%s",user->nick,chan->name,parameters[1]);
591                         NetSendToCommon(user,buffer);
592                 }
593                 else
594                 {
595                         /* no such nick/channel */
596                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
597                 }
598                 return;
599         }
600         
601         dest = Find(parameters[0]);
602         if (dest)
603         {
604                 int MOD_RESULT = 0;
605                 
606                 FOREACH_RESULT(OnUserPreNotice(user,dest,TYPE_USER,std::string(parameters[1])));
607                 if (MOD_RESULT) {
608                         return;
609                 }
610
611                 if (!strcmp(dest->server,user->server))
612                 {
613                         // direct write, same server
614                         WriteTo(user, dest, "NOTICE %s :%s", dest->nick, parameters[1]);
615                 }
616                 else
617                 {
618                         char buffer[MAXBUF];
619                         snprintf(buffer,MAXBUF,"V %s %s :%s",user->nick,dest->nick,parameters[1]);
620                         NetSendToOne(dest->server,buffer);
621                 }
622         }
623         else
624         {
625                 /* no such nick/channel */
626                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
627         }
628 }
629
630
631 void handle_info(char **parameters, int pcnt, userrec *user)
632 {
633         WriteServ(user->fd,"371 %s :The Inspire IRCd Project Has been brought to you by the following people..",user->nick);
634         WriteServ(user->fd,"371 %s :Craig Edwards, Craig McLure, and Others..",user->nick);
635         WriteServ(user->fd,"371 %s :Will finish this later when i can be arsed :p",user->nick);
636         FOREACH_MOD OnInfo(user);
637         WriteServ(user->fd,"374 %s :End of /INFO list",user->nick);
638 }
639
640 void handle_time(char **parameters, int pcnt, userrec *user)
641 {
642         time_t rawtime;
643         struct tm * timeinfo;
644
645         time ( &rawtime );
646         timeinfo = localtime ( &rawtime );
647         WriteServ(user->fd,"391 %s %s :%s",user->nick,ServerName, asctime (timeinfo) );
648   
649 }
650
651 void handle_whois(char **parameters, int pcnt, userrec *user)
652 {
653         userrec *dest;
654         char *t;
655
656         if (loop_call(handle_whois,parameters,pcnt,user,0,pcnt-1,0))
657                 return;
658         dest = Find(parameters[0]);
659         if (dest)
660         {
661                 // bug found by phidjit - were able to whois an incomplete connection if it had sent a NICK or USER
662                 if (dest->registered == 7)
663                 {
664                         WriteServ(user->fd,"311 %s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname);
665                         if ((user == dest) || (strchr(user->modes,'o')))
666                         {
667                                 WriteServ(user->fd,"378 %s %s :is connecting from *@%s",user->nick, dest->nick, dest->host);
668                         }
669                         if (strcmp(chlist(dest),""))
670                         {
671                                 WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, chlist(dest));
672                         }
673                         WriteServ(user->fd,"312 %s %s %s :%s",user->nick, dest->nick, dest->server, GetServerDescription(dest->server).c_str());
674                         if (strcmp(dest->awaymsg,""))
675                         {
676                                 WriteServ(user->fd,"301 %s %s :%s",user->nick, dest->nick, dest->awaymsg);
677                         }
678                         if (strchr(dest->modes,'o'))
679                         {
680                                 WriteServ(user->fd,"313 %s %s :is an IRC operator",user->nick, dest->nick);
681                         }
682                         FOREACH_MOD OnWhois(user,dest);
683                         if (!strcasecmp(user->server,dest->server))
684                         {
685                                 // idle time and signon line can only be sent if youre on the same server (according to RFC)
686                                 WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, abs((dest->idle_lastmsg)-time(NULL)), dest->signon);
687                         }
688                         
689                         WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, dest->nick);
690                 }
691                 else
692                 {
693                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
694                 }
695         }
696         else
697         {
698                 /* no such nick/channel */
699                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
700         }
701 }
702
703 void handle_quit(char **parameters, int pcnt, userrec *user)
704 {
705         user_hash::iterator iter = clientlist.find(user->nick);
706         char* reason;
707
708         if (user->registered == 7)
709         {
710                 /* theres more to do here, but for now just close the socket */
711                 if (pcnt == 1)
712                 {
713                         if (parameters[0][0] == ':')
714                         {
715                                 *parameters[0]++;
716                         }
717                         reason = parameters[0];
718
719                         if (strlen(reason)>MAXQUIT)
720                         {
721                                 reason[MAXQUIT-1] = '\0';
722                         }
723
724                         Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,parameters[0]);
725                         WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,parameters[0]);
726                         WriteCommonExcept(user,"QUIT :%s%s",PrefixQuit,parameters[0]);
727
728                         char buffer[MAXBUF];
729                         snprintf(buffer,MAXBUF,"Q %s :%s%s",user->nick,PrefixQuit,parameters[0]);
730                         NetSendToAll(buffer);
731                 }
732                 else
733                 {
734                         Write(user->fd,"ERROR :Closing link (%s@%s) [QUIT]",user->ident,user->host);
735                         WriteOpers("*** Client exiting: %s!%s@%s [Client exited]",user->nick,user->ident,user->host);
736                         WriteCommonExcept(user,"QUIT :Client exited");
737
738                         char buffer[MAXBUF];
739                         snprintf(buffer,MAXBUF,"Q %s :Client exited",user->nick);
740                         NetSendToAll(buffer);
741                 }
742                 FOREACH_MOD OnUserQuit(user);
743                 AddWhoWas(user);
744         }
745
746         /* push the socket on a stack of sockets due to be closed at the next opportunity */
747         fd_reap.push_back(user->fd);
748         
749         if (iter != clientlist.end())
750         {
751                 clientlist.erase(iter);
752                 log(DEBUG,"deleting user hash value %d",iter->second);
753                 //if ((user) && (user->registered == 7)) {
754                         //delete user;
755                 //}
756         }
757
758         if (user->registered == 7) {
759                 purge_empty_chans();
760         }
761 }
762
763 void handle_who(char **parameters, int pcnt, userrec *user)
764 {
765         chanrec* Ptr = NULL;
766         
767         /* theres more to do here, but for now just close the socket */
768         if (pcnt == 1)
769         {
770                 if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")))
771                 {
772                         if (user->chans[0].channel)
773                         {
774                                 Ptr = user->chans[0].channel;
775                                 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
776                                 {
777                                         if ((common_channels(user,i->second)) && (isnick(i->second->nick)))
778                                         {
779                                                 WriteServ(user->fd,"352 %s %s %s %s %s %s Hr@ :0 %s",user->nick, Ptr->name, i->second->ident, i->second->dhost, i->second->server, i->second->nick, i->second->fullname);
780                                         }
781                                 }
782                         }
783                         if (Ptr)
784                         {
785                                 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
786                         }
787                         else
788                         {
789                                 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, user->nick);
790                         }
791                         return;
792                 }
793                 if (parameters[0][0] == '#')
794                 {
795                         Ptr = FindChan(parameters[0]);
796                         if (Ptr)
797                         {
798                                 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
799                                 {
800                                         if ((has_channel(i->second,Ptr)) && (isnick(i->second->nick)))
801                                         {
802                                                 WriteServ(user->fd,"352 %s %s %s %s %s %s Hr@ :0 %s",user->nick, Ptr->name, i->second->ident, i->second->dhost, i->second->server, i->second->nick, i->second->fullname);
803                                         }
804                                 }
805                                 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
806                         }
807                         else
808                         {
809                                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
810                         }
811                 }
812                 else
813                 {
814                         userrec* u = Find(parameters[0]);
815                         if (u)
816                         {
817                                 WriteServ(user->fd,"352 %s %s %s %s %s %s Hr@ :0 %s",user->nick, u->nick, u->ident, u->dhost, u->server, u->nick, u->fullname);
818                         }
819                         WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, parameters[0]);
820                 }
821         }
822         if (pcnt == 2)
823         {
824                 if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")) && (!strcmp(parameters[1],"o")))
825                 {
826                         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
827                         {
828                                 if ((common_channels(user,i->second)) && (isnick(i->second->nick)))
829                                 {
830                                         if (strchr(i->second->modes,'o'))
831                                         {
832                                                 WriteServ(user->fd,"352 %s %s %s %s %s %s Hr@ :0 %s",user->nick, user->nick, i->second->ident, i->second->dhost, i->second->server, i->second->nick, i->second->fullname);
833                                         }
834                                 }
835                         }
836                         WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, user->nick);
837                         return;
838                 }
839         }
840 }
841
842 void handle_wallops(char **parameters, int pcnt, userrec *user)
843 {
844         WriteWallOps(user,false,"%s",parameters[0]);
845 }
846
847 void handle_list(char **parameters, int pcnt, userrec *user)
848 {
849         chanrec* Ptr;
850         
851         WriteServ(user->fd,"321 %s Channel :Users Name",user->nick);
852         for (chan_hash::const_iterator i = chanlist.begin(); i != chanlist.end(); i++)
853         {
854                 if ((!i->second->c_private) && (!i->second->secret))
855                 {
856                         WriteServ(user->fd,"322 %s %s %d :[+%s] %s",user->nick,i->second->name,usercount_i(i->second),chanmodes(i->second),i->second->topic);
857                 }
858         }
859         WriteServ(user->fd,"323 %s :End of channel list.",user->nick);
860 }
861
862
863 void handle_rehash(char **parameters, int pcnt, userrec *user)
864 {
865         WriteServ(user->fd,"382 %s %s :Rehashing",user->nick,CleanFilename(CONFIG_FILE));
866         ReadConfig();
867         FOREACH_MOD OnRehash();
868         WriteOpers("%s is rehashing config file %s",user->nick,CleanFilename(CONFIG_FILE));
869 }
870
871 void handle_lusers(char **parameters, int pcnt, userrec *user)
872 {
873         WriteServ(user->fd,"251 %s :There are %d users and %d invisible on %d servers",user->nick,usercnt()-usercount_invisible(),usercount_invisible(),servercount());
874         WriteServ(user->fd,"252 %s %d :operator(s) online",user->nick,usercount_opers());
875         WriteServ(user->fd,"253 %s %d :unknown connections",user->nick,usercount_unknown());
876         WriteServ(user->fd,"254 %s %d :channels formed",user->nick,chancount());
877         WriteServ(user->fd,"254 %s :I have %d clients and %d servers",user->nick,local_count(),count_servs());
878 }
879
880 void handle_admin(char **parameters, int pcnt, userrec *user)
881 {
882         WriteServ(user->fd,"256 %s :Administrative info for %s",user->nick,ServerName);
883         WriteServ(user->fd,"257 %s :Name     - %s",user->nick,AdminName);
884         WriteServ(user->fd,"258 %s :Nickname - %s",user->nick,AdminNick);
885         WriteServ(user->fd,"258 %s :E-Mail   - %s",user->nick,AdminEmail);
886 }
887
888 void handle_ping(char **parameters, int pcnt, userrec *user)
889 {
890         WriteServ(user->fd,"PONG %s :%s",ServerName,parameters[0]);
891 }
892
893 void handle_pong(char **parameters, int pcnt, userrec *user)
894 {
895         // set the user as alive so they survive to next ping
896         user->lastping = 1;
897 }
898
899 void handle_motd(char **parameters, int pcnt, userrec *user)
900 {
901         ShowMOTD(user);
902 }
903
904 void handle_rules(char **parameters, int pcnt, userrec *user)
905 {
906         ShowRULES(user);
907 }
908
909 void handle_user(char **parameters, int pcnt, userrec *user)
910 {
911         if (user->registered < 3)
912         {
913                 if (isident(parameters[0]) == 0) {
914                         // This kinda Sucks, According to the RFC thou, its either this,
915                         // or "You have already registered" :p -- Craig
916                         WriteServ(user->fd,"461 %s USER :Not enough parameters",user->nick);
917                 }
918                 else {
919                         WriteServ(user->fd,"NOTICE Auth :No ident response, ident prefixed with ~");
920                         strcpy(user->ident,"~"); /* we arent checking ident... but these days why bother anyway? */
921                         strncat(user->ident,parameters[0],IDENTMAX);
922                         strncpy(user->fullname,parameters[3],128);
923                         user->registered = (user->registered | 1);
924                 }
925         }
926         else
927         {
928                 WriteServ(user->fd,"462 %s :You may not reregister",user->nick);
929                 return;
930         }
931         /* parameters 2 and 3 are local and remote hosts, ignored when sent by client connection */
932         if (user->registered == 3)
933         {
934                 /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
935                 ConnectUser(user);
936         }
937 }
938
939 void handle_userhost(char **parameters, int pcnt, userrec *user)
940 {
941         char Return[MAXBUF],junk[MAXBUF];
942         sprintf(Return,"302 %s :",user->nick);
943         for (int i = 0; i < pcnt; i++)
944         {
945                 userrec *u = Find(parameters[i]);
946                 if (u)
947                 {
948                         if (strchr(u->modes,'o'))
949                         {
950                                 sprintf(junk,"%s*=+%s@%s ",u->nick,u->ident,u->host);
951                                 strcat(Return,junk);
952                         }
953                         else
954                         {
955                                 sprintf(junk,"%s=+%s@%s ",u->nick,u->ident,u->host);
956                                 strcat(Return,junk);
957                         }
958                 }
959         }
960         WriteServ(user->fd,Return);
961 }
962
963
964 void handle_ison(char **parameters, int pcnt, userrec *user)
965 {
966         char Return[MAXBUF];
967         sprintf(Return,"303 %s :",user->nick);
968         for (int i = 0; i < pcnt; i++)
969         {
970                 userrec *u = Find(parameters[i]);
971                 if (u)
972                 {
973                         strcat(Return,u->nick);
974                         strcat(Return," ");
975                 }
976         }
977         WriteServ(user->fd,Return);
978 }
979
980
981 void handle_away(char **parameters, int pcnt, userrec *user)
982 {
983         if (pcnt)
984         {
985                 strcpy(user->awaymsg,parameters[0]);
986                 WriteServ(user->fd,"306 %s :You have been marked as being away",user->nick);
987         }
988         else
989         {
990                 strcpy(user->awaymsg,"");
991                 WriteServ(user->fd,"305 %s :You are no longer marked as being away",user->nick);
992         }
993 }
994
995 void handle_whowas(char **parameters, int pcnt, userrec* user)
996 {
997         user_hash::iterator i = whowas.find(parameters[0]);
998
999         if (i == whowas.end())
1000         {
1001                 WriteServ(user->fd,"406 %s %s :There was no such nickname",user->nick,parameters[0]);
1002                 WriteServ(user->fd,"369 %s %s :End of WHOWAS",user->nick,parameters[0]);
1003         }
1004         else
1005         {
1006                 time_t rawtime = i->second->signon;
1007                 tm *timeinfo;
1008                 char b[MAXBUF];
1009                 
1010                 timeinfo = localtime(&rawtime);
1011                 strcpy(b,asctime(timeinfo));
1012                 b[strlen(b)-1] = '\0';
1013                 
1014                 WriteServ(user->fd,"314 %s %s %s %s * :%s",user->nick,i->second->nick,i->second->ident,i->second->dhost,i->second->fullname);
1015                 WriteServ(user->fd,"312 %s %s %s :%s",user->nick,i->second->nick,i->second->server,b);
1016                 WriteServ(user->fd,"369 %s %s :End of WHOWAS",user->nick,parameters[0]);
1017         }
1018
1019 }
1020
1021 void handle_trace(char **parameters, int pcnt, userrec *user)
1022 {
1023         for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
1024         {
1025                 if (i->second)
1026                 {
1027                         if (isnick(i->second->nick))
1028                         {
1029                                 if (strchr(i->second->modes,'o'))
1030                                 {
1031                                         WriteServ(user->fd,"205 %s :Oper 0 %s",user->nick,i->second->nick);
1032                                 }
1033                                 else
1034                                 {
1035                                         WriteServ(user->fd,"204 %s :User 0 %s",user->nick,i->second->nick);
1036                                 }
1037                         }
1038                         else
1039                         {
1040                                 WriteServ(user->fd,"203 %s :???? 0 [%s]",user->nick,i->second->host);
1041                         }
1042                 }
1043         }
1044 }
1045
1046 void handle_modules(char **parameters, int pcnt, userrec *user)
1047 {
1048         for (int i = 0; i < module_names.size(); i++)
1049         {
1050                         Version V = modules[i]->GetVersion();
1051                         char modulename[MAXBUF];
1052                         strncpy(modulename,module_names[i].c_str(),256);
1053                         WriteServ(user->fd,"900 %s :0x%08lx %d.%d.%d.%d %s",user->nick,modules[i],V.Major,V.Minor,V.Revision,V.Build,CleanFilename(modulename));
1054         }
1055 }
1056
1057 void handle_stats(char **parameters, int pcnt, userrec *user)
1058 {
1059         if (pcnt != 1)
1060         {
1061                 return;
1062         }
1063         if (strlen(parameters[0])>1)
1064         {
1065                 /* make the stats query 1 character long */
1066                 parameters[0][1] = '\0';
1067         }
1068
1069         /* stats m (list number of times each command has been used, plus bytecount) */
1070         if (!strcasecmp(parameters[0],"m"))
1071         {
1072                 for (int i = 0; i < cmdlist.size(); i++)
1073                 {
1074                         if (cmdlist[i].handler_function)
1075                         {
1076                                 if (cmdlist[i].use_count)
1077                                 {
1078                                         /* RPL_STATSCOMMANDS */
1079                                         WriteServ(user->fd,"212 %s %s %d %d",user->nick,cmdlist[i].command,cmdlist[i].use_count,cmdlist[i].total_bytes);
1080                                 }
1081                         }
1082                 }
1083                         
1084         }
1085
1086         /* stats z (debug and memory info) */
1087         if (!strcasecmp(parameters[0],"z"))
1088         {
1089                 WriteServ(user->fd,"249 %s :Users(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,clientlist.size(),clientlist.size()*sizeof(userrec),clientlist.bucket_count());
1090                 WriteServ(user->fd,"249 %s :Channels(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,chanlist.size(),chanlist.size()*sizeof(chanrec),chanlist.bucket_count());
1091                 WriteServ(user->fd,"249 %s :Commands(VECTOR) %d (%d bytes)",user->nick,cmdlist.size(),cmdlist.size()*sizeof(command_t));
1092                 WriteServ(user->fd,"249 %s :MOTD(VECTOR) %d, RULES(VECTOR) %d",user->nick,MOTD.size(),RULES.size());
1093                 WriteServ(user->fd,"249 %s :address_cache(HASH_MAP) %d (%d buckets)",user->nick,IP.size(),IP.bucket_count());
1094                 WriteServ(user->fd,"249 %s :Modules(VECTOR) %d (%d)",user->nick,modules.size(),modules.size()*sizeof(Module));
1095                 WriteServ(user->fd,"249 %s :ClassFactories(VECTOR) %d (%d)",user->nick,factory.size(),factory.size()*sizeof(ircd_module));
1096                 WriteServ(user->fd,"249 %s :Ports(STATIC_ARRAY) %d",user->nick,boundPortCount);
1097         }
1098         
1099         /* stats o */
1100         if (!strcasecmp(parameters[0],"o"))
1101         {
1102                 for (int i = 0; i < ConfValueEnum("oper",&config_f); i++)
1103                 {
1104                         char LoginName[MAXBUF];
1105                         char HostName[MAXBUF];
1106                         char OperType[MAXBUF];
1107                         ConfValue("oper","name",i,LoginName,&config_f);
1108                         ConfValue("oper","host",i,HostName,&config_f);
1109                         ConfValue("oper","type",i,OperType,&config_f);
1110                         WriteServ(user->fd,"243 %s O %s * %s %s 0",user->nick,HostName,LoginName,OperType);
1111                 }
1112         }
1113         
1114         /* stats l (show user I/O stats) */
1115         if (!strcasecmp(parameters[0],"l"))
1116         {
1117                 WriteServ(user->fd,"211 %s :server:port nick bytes_in cmds_in bytes_out cmds_out",user->nick);
1118                 for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
1119                 {
1120                         if (isnick(i->second->nick))
1121                         {
1122                                 WriteServ(user->fd,"211 %s :%s:%d %s %d %d %d %d",user->nick,ServerName,i->second->port,i->second->nick,i->second->bytes_in,i->second->cmds_in,i->second->bytes_out,i->second->cmds_out);
1123                         }
1124                         else
1125                         {
1126                                 WriteServ(user->fd,"211 %s :%s:%d (unknown@%d) %d %d %d %d",user->nick,ServerName,i->second->port,i->second->fd,i->second->bytes_in,i->second->cmds_in,i->second->bytes_out,i->second->cmds_out);
1127                         }
1128                         
1129                 }
1130         }
1131         
1132         /* stats u (show server uptime) */
1133         if (!strcasecmp(parameters[0],"u"))
1134         {
1135                 time_t current_time = 0;
1136                 current_time = time(NULL);
1137                 time_t server_uptime = current_time - startup_time;
1138                 struct tm* stime;
1139                 stime = gmtime(&server_uptime);
1140                 /* i dont know who the hell would have an ircd running for over a year nonstop, but
1141                  * Craig suggested this, and it seemed a good idea so in it went */
1142                 if (stime->tm_year > 70)
1143                 {
1144                         WriteServ(user->fd,"242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d",user->nick,(stime->tm_year-70),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);
1145                 }
1146                 else
1147                 {
1148                         WriteServ(user->fd,"242 %s :Server up %d days, %.2d:%.2d:%.2d",user->nick,stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec);
1149                 }
1150         }
1151
1152         WriteServ(user->fd,"219 %s %s :End of /STATS report",user->nick,parameters[0]);
1153         WriteOpers("*** Notice: Stats '%s' requested by %s (%s@%s)",parameters[0],user->nick,user->ident,user->host);
1154         
1155 }
1156
1157 void handle_connect(char **parameters, int pcnt, userrec *user)
1158 {
1159         char Link_ServerName[1024];
1160         char Link_IPAddr[1024];
1161         char Link_Port[1024];
1162         char Link_Pass[1024];
1163         int LinkPort;
1164         bool found = false;
1165         
1166         for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
1167         {
1168                 if (!found)
1169                 {
1170                         ConfValue("link","name",i,Link_ServerName,&config_f);
1171                         ConfValue("link","ipaddr",i,Link_IPAddr,&config_f);
1172                         ConfValue("link","port",i,Link_Port,&config_f);
1173                         ConfValue("link","sendpass",i,Link_Pass,&config_f);
1174                         log(DEBUG,"(%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s'",i,Link_ServerName,Link_IPAddr,Link_Port,Link_Pass);
1175                         LinkPort = atoi(Link_Port);
1176                         if (match(Link_ServerName,parameters[0])) {
1177                                 found = true;
1178                                 break;
1179                         }
1180                 }
1181         }
1182         
1183         if (!found) {
1184                 WriteServ(user->fd,"NOTICE %s :*** Failed to connect to %s: No servers matching this pattern are configured for linking.",user->nick,parameters[0]);
1185                 return;
1186         }
1187         
1188         // TODO: Perform a check here to stop a server being linked twice!
1189
1190         WriteServ(user->fd,"NOTICE %s :*** Connecting to %s (%s) port %s...",user->nick,Link_ServerName,Link_IPAddr,Link_Port);
1191
1192         if (me[defaultRoute])
1193         {
1194                 me[defaultRoute]->BeginLink(Link_IPAddr,LinkPort,Link_Pass,Link_ServerName,me[defaultRoute]->port);
1195                 return;
1196         }
1197         else
1198         {
1199                 WriteServ(user->fd,"NOTICE %s :No default route is defined for server connections on this server. You must define a server connection to be default route so that sockets can be bound to it.",user->nick);
1200         }
1201 }
1202
1203 void handle_squit(char **parameters, int pcnt, userrec *user)
1204 {
1205         // send out an squit across the mesh and then clear the server list (for local squit)
1206         if (!pcnt)
1207         {
1208                 WriteOpers("SQUIT command issued by %s",user->nick);
1209                 char buffer[MAXBUF];
1210                 snprintf(buffer,MAXBUF,"& %s",ServerName);
1211                 NetSendToAll(buffer);
1212                 DoSplitEveryone();
1213         }
1214         else
1215         {
1216                 WriteServ(user->fd,"NOTICE :*** Remote SQUIT not supported yet.");
1217         }
1218 }
1219
1220 void handle_links(char **parameters, int pcnt, userrec *user)
1221 {
1222         WriteServ(user->fd,"364 %s %s %s :0 %s",user->nick,ServerName,ServerName,ServerDesc);
1223         for (int j = 0; j < 32; j++)
1224         {
1225                 if (me[j] != NULL)
1226                 {
1227                         for (int k = 0; k < me[j]->connectors.size(); k++)
1228                         {
1229                                 WriteServ(user->fd,"364 %s %s %s :1 %s",user->nick,me[j]->connectors[k].GetServerName().c_str(),ServerName,me[j]->connectors[k].GetDescription().c_str());
1230                         }
1231                 }
1232         }
1233         WriteServ(user->fd,"365 %s * :End of /LINKS list.",user->nick);
1234 }
1235
1236 void handle_map(char **parameters, int pcnt, userrec *user)
1237 {
1238         char line[MAXBUF];
1239         snprintf(line,MAXBUF,"006 %s :%s",user->nick,ServerName);
1240         while (strlen(line) < 50)
1241                 strcat(line," ");
1242         WriteServ(user->fd,"%s%d (%.2f%%)",line,local_count(),(float)(((float)local_count()/(float)usercnt())*100));
1243         for (int j = 0; j < 32; j++)
1244         {
1245                 if (me[j] != NULL)
1246                 {
1247                         for (int k = 0; k < me[j]->connectors.size(); k++)
1248                         {
1249                                 snprintf(line,MAXBUF,"006 %s :%c-%s",user->nick,islast(me[j]->connectors[k].GetServerName().c_str()),me[j]->connectors[k].GetServerName().c_str());
1250                                 while (strlen(line) < 50)
1251                                         strcat(line," ");
1252                                 WriteServ(user->fd,"%s%d (%.2f%%)",line,map_count(me[j]->connectors[k].GetServerName().c_str()),(float)(((float)map_count(me[j]->connectors[k].GetServerName().c_str())/(float)usercnt())*100));
1253                         }
1254                 }
1255         }
1256         WriteServ(user->fd,"007 %s :End of /MAP",user->nick);
1257 }
1258
1259 bool is_uline(const char* server)
1260 {
1261         char ServName[MAXBUF];
1262         int i,j;
1263
1264         for (int i = 0; i < ConfValueEnum("uline",&config_f); i++)
1265         {
1266                 ConfValue("uline","server",i,ServName,&config_f);
1267                 if (!strcasecmp(server,ServName))
1268                 {
1269                         return true;
1270                 }
1271         }
1272         return false;
1273 }
1274
1275
1276 void handle_oper(char **parameters, int pcnt, userrec *user)
1277 {
1278         char LoginName[MAXBUF];
1279         char Password[MAXBUF];
1280         char OperType[MAXBUF];
1281         char TypeName[MAXBUF];
1282         char Hostname[MAXBUF];
1283         int i,j;
1284
1285         for (int i = 0; i < ConfValueEnum("oper",&config_f); i++)
1286         {
1287                 ConfValue("oper","name",i,LoginName,&config_f);
1288                 ConfValue("oper","password",i,Password,&config_f);
1289                 if ((!strcmp(LoginName,parameters[0])) && (!strcmp(Password,parameters[1])))
1290                 {
1291                         /* correct oper credentials */
1292                         ConfValue("oper","type",i,OperType,&config_f);
1293                         WriteOpers("*** %s (%s@%s) is now an IRC operator of type %s",user->nick,user->ident,user->host,OperType);
1294                         WriteServ(user->fd,"381 %s :You are now an IRC operator of type %s",user->nick,OperType);
1295                         WriteServ(user->fd,"MODE %s :+o",user->nick);
1296                         char global[MAXBUF];
1297                         snprintf(global,MAXBUF,"M %s +o",user->nick);
1298                         NetSendToAll(global);
1299                         for (j =0; j < ConfValueEnum("type",&config_f); j++)
1300                         {
1301                                 ConfValue("type","name",j,TypeName,&config_f);
1302                                 if (!strcmp(TypeName,OperType))
1303                                 {
1304                                         /* found this oper's opertype */
1305                                         ConfValue("type","host",j,Hostname,&config_f);
1306                                         ChangeDisplayedHost(user,Hostname);
1307                                 }
1308                         }
1309                         if (!strchr(user->modes,'o'))
1310                         {
1311                                 strcat(user->modes,"o");
1312                         }
1313                         FOREACH_MOD OnOper(user);
1314                         return;
1315                 }
1316         }
1317         /* no such oper */
1318         WriteServ(user->fd,"491 %s :Invalid oper credentials",user->nick);
1319         WriteOpers("*** WARNING! Failed oper attempt by %s!%s@%s!",user->nick,user->ident,user->host);
1320 }
1321
1322 void handle_nick(char **parameters, int pcnt, userrec *user)
1323 {
1324         if (pcnt < 1) 
1325         {
1326                 log(DEBUG,"not enough params for handle_nick");
1327                 return;
1328         }
1329         if (!parameters[0])
1330         {
1331                 log(DEBUG,"invalid parameter passed to handle_nick");
1332                 return;
1333         }
1334         if (!strlen(parameters[0]))
1335         {
1336                 log(DEBUG,"zero length new nick passed to handle_nick");
1337                 return;
1338         }
1339         if (!user)
1340         {
1341                 log(DEBUG,"invalid user passed to handle_nick");
1342                 return;
1343         }
1344         if (!user->nick)
1345         {
1346                 log(DEBUG,"invalid old nick passed to handle_nick");
1347                 return;
1348         }
1349         if (!strcasecmp(user->nick,parameters[0]))
1350         {
1351                 log(DEBUG,"old nick is new nick, skipping");
1352                 return;
1353         }
1354         else
1355         {
1356                 if (strlen(parameters[0]) > 1)
1357                 {
1358                         if (parameters[0][0] == ':')
1359                         {
1360                                 *parameters[0]++;
1361                         }
1362                 }
1363                 if ((Find(parameters[0])) && (Find(parameters[0]) != user))
1364                 {
1365                         WriteServ(user->fd,"433 %s %s :Nickname is already in use.",user->nick,parameters[0]);
1366                         return;
1367                 }
1368         }
1369         if (isnick(parameters[0]) == 0)
1370         {
1371                 WriteServ(user->fd,"432 %s %s :Erroneous Nickname",user->nick,parameters[0]);
1372                 return;
1373         }
1374
1375         if (user->registered == 7)
1376         {
1377                 int MOD_RESULT = 0;
1378                 FOREACH_RESULT(OnUserPreNick(user,parameters[0]));
1379                 if (MOD_RESULT) {
1380                         // if a module returns true, the nick change is silently forbidden.
1381                         return;
1382                 }
1383
1384                 WriteCommon(user,"NICK %s",parameters[0]);
1385                 
1386                 // Q token must go to ALL servers!!!
1387                 char buffer[MAXBUF];
1388                 snprintf(buffer,MAXBUF,"n %s %s",user->nick,parameters[0]);
1389                 NetSendToAll(buffer);
1390                 
1391         }
1392         
1393         /* change the nick of the user in the users_hash */
1394         user = ReHashNick(user->nick, parameters[0]);
1395         /* actually change the nick within the record */
1396         if (!user) return;
1397         if (!user->nick) return;
1398
1399         strncpy(user->nick, parameters[0],NICKMAX);
1400
1401         log(DEBUG,"new nick set: %s",user->nick);
1402         
1403         if (user->registered < 3)
1404                 user->registered = (user->registered | 2);
1405         if (user->registered == 3)
1406         {
1407                 /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
1408                 ConnectUser(user);
1409         }
1410         log(DEBUG,"exit nickchange: %s",user->nick);
1411 }
1412
1413
1414
1415 void handle_V(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1416 {
1417         char* src = strtok(params," ");
1418         char* dest = strtok(NULL," :");
1419         char* text = strtok(NULL,"\r\n");
1420         text++;
1421         
1422         userrec* user = Find(src);
1423         if (user)
1424         {
1425                 userrec* dst = Find(dest);
1426                 
1427                 if (dst)
1428                 {
1429                         WriteTo(user, dst, "NOTICE %s :%s", dst->nick, text);
1430                 }
1431                 else
1432                 {
1433                         chanrec* d = FindChan(dest);
1434                         if (d)
1435                         {
1436                                 ChanExceptSender(d, user, "NOTICE %s :%s", d->name, text);
1437                         }
1438                 }
1439         }
1440         
1441 }
1442
1443
1444 void handle_P(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1445 {
1446         char* src = strtok(params," ");
1447         char* dest = strtok(NULL," :");
1448         char* text = strtok(NULL,"\r\n");
1449         text++;
1450         
1451         userrec* user = Find(src);
1452         if (user)
1453         {
1454                 userrec* dst = Find(dest);
1455                 
1456                 if (dst)
1457                 {
1458                         WriteTo(user, dst, "PRIVMSG %s :%s", dst->nick, text);
1459                 }
1460                 else
1461                 {
1462                         chanrec* d = FindChan(dest);
1463                         if (d)
1464                         {
1465                                 ChanExceptSender(d, user, "PRIVMSG %s :%s", d->name, text);
1466                         }
1467                 }
1468         }
1469         
1470 }
1471
1472 void handle_i(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1473 {
1474         char* nick = strtok(params," ");
1475         char* from = strtok(NULL," ");
1476         char* channel = strtok(NULL," ");
1477         userrec* u = Find(nick);
1478         userrec* user = Find(from);
1479         chanrec* c = FindChan(channel);
1480         if ((c) && (u) && (user))
1481         {
1482                 u->InviteTo(c->name);
1483                 WriteFrom(u->fd,user,"INVITE %s :%s",u->nick,c->name);
1484         }
1485 }
1486
1487 void handle_t(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1488 {
1489         char* setby = strtok(params," ");
1490         char* channel = strtok(NULL," :");
1491         char* topic = strtok(NULL,"\r\n");
1492         topic++;
1493         userrec* u = Find(setby);
1494         chanrec* c = FindChan(channel);
1495         if ((c) && (u))
1496         {
1497                 WriteChannelLocal(c,u,"TOPIC %s :%s",c->name,topic);
1498                 strncpy(c->topic,topic,MAXTOPIC);
1499                 strncpy(c->setby,u->nick,NICKMAX);
1500                 c->topicset = time(NULL);
1501         }       
1502 }
1503         
1504
1505 void handle_T(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1506 {
1507         char* tm = strtok(params," ");
1508         char* setby = strtok(NULL," ");
1509         char* channel = strtok(NULL," :");
1510         char* topic = strtok(NULL,"\r\n");
1511         topic++;
1512         time_t TS = atoi(tm);
1513         chanrec* c = FindChan(channel);
1514         if (c)
1515         {
1516                 // in the case of topics and TS, the *NEWER* 
1517                 if (TS <= c->topicset)
1518                 {
1519                         WriteChannelLocal(c,NULL,"TOPIC %s :%s",c->name,topic);
1520                         strncpy(c->topic,topic,MAXTOPIC);
1521                         strncpy(c->setby,setby,NICKMAX);
1522                 }
1523         }       
1524 }
1525         
1526 void handle_M(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1527 {
1528         char* pars[128];
1529         char original[MAXBUF],target[MAXBUF];
1530         strncpy(original,params,MAXBUF);
1531         int index = 0;
1532         char* parameter = strtok(params," ");
1533         strncpy(target,parameter,MAXBUF);
1534         while (parameter)
1535         {
1536                 if (parameter[0] == ':')
1537                         parameter++;
1538                 pars[index++] = parameter;
1539                 parameter = strtok(NULL," ");
1540         }
1541         log(DEBUG,"*** MODE: %s %s",pars[0],pars[1]);
1542         merge_mode(pars,index);
1543         if (FindChan(target))
1544         {
1545                 WriteChannelLocal(FindChan(target), NULL, "MODE %s",original);
1546         }
1547         if (Find(target))
1548         {
1549                 Write(Find(target)->fd,":%s MODE %s",ServerName,original);
1550         }
1551 }
1552
1553 // m is modes set by users only (not servers) valid targets are channels or users.
1554
1555 void handle_m(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1556 {
1557         // m blah #chatspike +b *!test@*4
1558         char* pars[128];
1559         char original[MAXBUF];
1560         strncpy(original,params,MAXBUF);
1561         
1562         if (!strchr(params,' '))
1563         {
1564                 WriteOpers("WARNING! 'm' token in data stream without any parameters! Something fishy is going on!");
1565                 return;
1566         }
1567         
1568         int index = 0;
1569         
1570         char* src = strtok(params," ");
1571         userrec* user = Find(src);
1572         
1573         if (user)
1574         {
1575                 log(DEBUG,"Found user: %s",user->nick);
1576                 char* parameter = strtok(NULL," ");
1577                 while (parameter)
1578                 {
1579                         pars[index++] = parameter;
1580                         parameter = strtok(NULL," ");
1581                 }
1582                 
1583                 log(DEBUG,"Calling merge_mode2");
1584                 merge_mode2(pars,index,user);
1585         }
1586 }
1587
1588
1589 void handle_L(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1590 {
1591         char* nick = strtok(params," ");
1592         char* channel = strtok(NULL," :");
1593         char* reason = strtok(NULL,"\r\n");
1594         userrec* user = Find(nick);
1595         reason++;
1596         if (user)
1597         {
1598                 if (strcmp(reason,""))
1599                 {
1600                         del_channel(user,channel,reason,true);
1601                 }
1602                 else
1603                 {
1604                         del_channel(user,channel,NULL,true);
1605                 }
1606         }
1607 }
1608
1609 void handle_K(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1610 {
1611         char* src = strtok(params," ");
1612         char* nick = strtok(NULL," :");
1613         char* reason = strtok(NULL,"\r\n");
1614         char kreason[MAXBUF];
1615         reason++;
1616
1617         userrec* u = Find(nick);
1618         userrec* user = Find(src);
1619         
1620         if ((user) && (u))
1621         {
1622                 WriteTo(user, u, "KILL %s :%s!%s!%s!%s (%s)", u->nick, source->name, ServerName, user->dhost,user->nick,reason);
1623                 WriteOpers("*** Remote kill from %s by %s: %s!%s@%s (%s)",source->name,user->nick,u->nick,u->ident,u->host,reason);
1624                 snprintf(kreason,MAXBUF,"[%s] Killed (%s (%s))",source->name,user->nick,reason);
1625                 kill_link(u,kreason);
1626         }
1627 }
1628
1629 void handle_Q(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1630 {
1631         char* nick = strtok(params," :");
1632         char* reason = strtok(NULL,"\r\n");
1633         reason++;
1634
1635         userrec* user = Find(nick);
1636         
1637         if (user)
1638         {
1639                 if (strlen(reason)>MAXQUIT)
1640                 {
1641                         reason[MAXQUIT-1] = '\0';
1642                 }
1643
1644
1645                 WriteCommonExcept(user,"QUIT :%s",reason);
1646
1647                 user_hash::iterator iter = clientlist.find(user->nick);
1648         
1649                 if (iter != clientlist.end())
1650                 {
1651                         log(DEBUG,"deleting user hash value %d",iter->second);
1652                         if ((iter->second) && (user->registered == 7)) {
1653                                 delete iter->second;
1654                         }
1655                         clientlist.erase(iter);
1656                 }
1657
1658                 purge_empty_chans();
1659         }
1660 }
1661
1662 void handle_n(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1663 {
1664         char* oldnick = strtok(params," ");
1665         char* newnick = strtok(NULL," ");
1666         
1667         userrec* user = Find(oldnick);
1668         
1669         if (user)
1670         {
1671                 WriteCommon(user,"NICK %s",newnick);
1672                 if (is_uline(tcp_host))
1673                 {
1674                         int MOD_RESULT = 0;
1675                         FOREACH_RESULT(OnUserPreNick(user,newnick));
1676                         if (MOD_RESULT) {
1677                                 // if a module returns true, the nick change couldnt be allowed
1678                                 kill_link(user,"Nickname collision");
1679                                 return;
1680                         }
1681         
1682                         // broadcast this because its a services thingy
1683                         char buffer[MAXBUF];
1684                         snprintf(buffer,MAXBUF,"n %s %s",user->nick,newnick);
1685                         NetSendToAll(buffer);
1686                 }
1687                 user = ReHashNick(user->nick, newnick);
1688                 if (!user) return;
1689                 if (!user->nick) return;
1690                 strncpy(user->nick, newnick,NICKMAX);
1691                 log(DEBUG,"new nick set: %s",user->nick);
1692         }
1693 }
1694
1695 // k <SOURCE> <DEST> <CHANNEL> :<REASON>
1696 void handle_k(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1697 {
1698         char* src = strtok(params," ");
1699         char* dest = strtok(NULL," ");
1700         char* channel = strtok(NULL," :");
1701         char* reason = strtok(NULL,"\r\n");
1702         reason++;
1703         userrec* s = Find(src);
1704         userrec* d = Find(dest);
1705         chanrec* c = FindChan(channel);
1706         if ((s) && (d) && (c))
1707         {
1708                 kick_channel(s,d,c,reason);
1709                 return;
1710         }
1711         d = Find(channel);
1712         c = FindChan(dest);
1713         if ((s) && (d) && (c))
1714         {
1715                 kick_channel(s,d,c,reason);
1716                 return;
1717         }
1718 }
1719
1720 void handle_AT(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1721 {
1722         char* who = strtok(params," :");
1723         char* text = strtok(NULL,"\r\n");
1724         text++;
1725         userrec* s = Find(who);
1726         if (s)
1727         {
1728                 WriteWallOps(s,true,text);
1729         }
1730 }
1731
1732 void handle_H(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1733 {
1734         log(DEBUG,"Adding ULined server %s to my map",params);
1735         ircd_connector s;
1736         s.SetState(STATE_DISCONNECTED);
1737         s.SetServerName(params);
1738         source->connectors.push_back(s);
1739 }
1740
1741 void handle_N(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1742 {
1743         char* tm = strtok(params," ");
1744         char* nick = strtok(NULL," ");
1745         char* host = strtok(NULL," ");
1746         char* dhost = strtok(NULL," ");
1747         char* ident = strtok(NULL," ");
1748         char* modes = strtok(NULL," ");
1749         char* server = strtok(NULL," :");
1750         char* gecos = strtok(NULL,"\r\n");
1751         gecos++;
1752         modes++;
1753         time_t TS = atoi(tm);
1754         user_hash::iterator iter = clientlist.find(nick);
1755         if (iter != clientlist.end())
1756         {
1757                 // nick collision
1758                 WriteOpers("Nickname collision: %s@%s != %s@%s",nick,server,iter->second->nick,iter->second->server);
1759                 char str[MAXBUF];
1760                 snprintf(str,MAXBUF,"Killed (Nick Collision (%s@%s < %s@%s))",nick,server,iter->second->nick,iter->second->server);
1761                 WriteServ(iter->second->fd, "KILL %s :%s",iter->second->nick,str);
1762                 kill_link(iter->second,str);
1763         }
1764         clientlist[nick] = new userrec();
1765         // remote users have an fd of -1. This is so that our Write abstraction
1766         // routines know to route any messages to this record away to whatever server
1767         // theyre on.
1768         clientlist[nick]->fd = -1;
1769         strncpy(clientlist[nick]->nick, nick,NICKMAX);
1770         strncpy(clientlist[nick]->host, host,160);
1771         strncpy(clientlist[nick]->dhost, dhost,160);
1772         strncpy(clientlist[nick]->server, server,256);
1773         strncpy(clientlist[nick]->ident, ident,10); // +1 char to compensate for tilde
1774         strncpy(clientlist[nick]->fullname, gecos,128);
1775         clientlist[nick]->signon = TS;
1776         clientlist[nick]->nping = 0; // this is ignored for a remote user anyway.
1777         clientlist[nick]->lastping = 1;
1778         clientlist[nick]->port = 0; // so is this...
1779         clientlist[nick]->registered = 7; // this however we need to set for them to receive messages and appear online
1780         clientlist[nick]->idle_lastmsg = time(NULL); // this is unrealiable and wont actually be used locally
1781         for (int i = 0; i < MAXCHANS; i++)
1782         {
1783                 clientlist[nick]->chans[i].channel = NULL;
1784                 clientlist[nick]->chans[i].uc_modes = 0;
1785         }
1786 }
1787
1788 void handle_F(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1789 {
1790         long tdiff = time(NULL) - atoi(params);
1791         if (tdiff)
1792                 WriteOpers("TS split for %s -> %s: %d",source->name,reply->name,tdiff);
1793 }
1794
1795 void handle_a(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1796 {
1797         char* nick = strtok(params," :");
1798         char* gecos = strtok(NULL,"\r\n");
1799         
1800         userrec* user = Find(nick);
1801
1802         if (user)
1803                 strncpy(user->fullname,gecos,MAXBUF);
1804 }
1805
1806 void handle_b(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1807 {
1808         char* nick = strtok(params," ");
1809         char* host = strtok(NULL," ");
1810         
1811         userrec* user = Find(nick);
1812
1813         if (user)
1814                 strncpy(user->dhost,host,160);
1815 }
1816
1817 void handle_plus(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1818 {
1819         // %s %s %d %d
1820         // + test3.chatspike.net 7010 -2016508415
1821         char* servername = strtok(params," ");
1822         char* ipaddr = strtok(NULL," ");
1823         char* ipport = strtok(NULL," ");
1824         char* cookie = strtok(NULL," ");
1825         log(DEBUG,"*** Connecting back to %s:%d",ipaddr,atoi(ipport));
1826
1827
1828         bool conn_already = false;
1829         for (int i = 0; i < 32; i++)
1830         {
1831                 if (me[i] != NULL)
1832                 {
1833                         for (int j = 0; j < me[i]->connectors.size(); j++)
1834                         {
1835                                 if (!strcasecmp(me[i]->connectors[j].GetServerName().c_str(),servername))
1836                                 {
1837                                         if (me[i]->connectors[j].GetServerPort() == atoi(ipport))
1838                                         {
1839                                                 log(DEBUG,"Already got a connection to %s:%d, ignoring +",ipaddr,atoi(ipport));
1840                                                 conn_already = true;
1841                                         }
1842                                 }
1843                         }
1844                 }
1845         }
1846         if (!conn_already)
1847                 me[defaultRoute]->MeshCookie(ipaddr,atoi(ipport),atoi(cookie),servername);
1848 }
1849
1850 void handle_R(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1851 {
1852         char* server = strtok(params," ");
1853         char* data = strtok(NULL,"\r\n");
1854         log(DEBUG,"Forwarded packet '%s' to '%s'",data,server);
1855         NetSendToOne(server,data);
1856 }
1857
1858 void handle_J(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1859 {
1860         // IMPORTANT NOTE
1861         // The J token currently has no timestamp - this needs looking at
1862         // because it will allow splitriding.
1863         char* nick = strtok(params," ");
1864         char* channel = strtok(NULL," ");
1865         userrec* user = Find(nick);
1866         while (channel)
1867         {
1868                 if ((user != NULL) && (strcmp(channel,"")))
1869                 {
1870                         char privilage = '\0';
1871                         if (channel[0] != '#')
1872                         {
1873                                 privilage = channel[0];
1874                                 channel++;
1875                         }
1876                         add_channel(user,channel,"",true);
1877
1878                         // now work out the privilages they should have on each channel
1879                         // and send the appropriate servermodes.
1880                         for (int i = 0; i != MAXCHANS; i++)
1881                         {
1882                                 if (user->chans[i].channel)
1883                                 {
1884                                         if (!strcasecmp(user->chans[i].channel->name,channel))
1885                                         {
1886                                                 if (privilage == '@')
1887                                                 {
1888                                                         user->chans[i].uc_modes = user->chans[i].uc_modes | UCMODE_OP;
1889                                                         WriteChannelLocal(user->chans[i].channel, NULL, "MODE %s +o %s",channel,user->nick);
1890                                                 }
1891                                                 if (privilage == '%')
1892                                                 {
1893                                                         user->chans[i].uc_modes = user->chans[i].uc_modes | UCMODE_HOP;
1894                                                         WriteChannelLocal(user->chans[i].channel, NULL, "MODE %s +h %s",channel,user->nick);
1895                                                 }
1896                                                 if (privilage == '+')
1897                                                 {
1898                                                         user->chans[i].uc_modes = user->chans[i].uc_modes | UCMODE_VOICE;
1899                                                         WriteChannelLocal(user->chans[i].channel, NULL, "MODE %s +v %s",channel,user->nick);
1900                                                 }
1901                                         }
1902                                 }
1903                         }
1904
1905                 }
1906                 channel = strtok(NULL," ");
1907         }
1908 }
1909
1910 void handle_dollar(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1911 {
1912         log(DEBUG,"Storing routing table...");
1913         char* sourceserver = strtok(params," ");
1914         char* server = strtok(NULL," ");
1915         for (int i = 0; i < 32; i++)
1916         {
1917                 if (me[i] != NULL)
1918                 {
1919                         for (int j = 0; j < me[i]->connectors.size(); j++)
1920                         {
1921                                 if (!strcasecmp(me[i]->connectors[j].GetServerName().c_str(),sourceserver))
1922                                 {
1923                                         me[i]->connectors[j].routes.clear();
1924                                         log(DEBUG,"Found entry for source server.");
1925                                         while (server)
1926                                         {
1927                                                 // store each route
1928                                                 me[i]->connectors[j].routes.push_back(server);
1929                                                 log(DEBUG,"*** Stored route: %s -> %s -> %s",ServerName,sourceserver,server);
1930                                                 server = strtok(NULL," ");
1931                                         }
1932                                         return;
1933                                 }
1934                         }
1935                 }
1936         }
1937         log(DEBUG,"Warning! routing table received from nonexistent server!");
1938 }
1939
1940 void handle_amp(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host)
1941 {
1942         log(DEBUG,"Netsplit! %s split from mesh, removing!",params);
1943         WriteOpers("*** NOTICE - Controlled netsplit: %s split from %s",params,ServerName);
1944         bool go_again = true;
1945         while (go_again)
1946         {
1947                 go_again = false;
1948                 for (int i = 0; i < 32; i++)
1949                 {
1950                         if (me[i] != NULL)
1951                         {
1952                                 for (vector<ircd_connector>::iterator j = me[i]->connectors.begin(); j != me[i]->connectors.end(); j++)
1953                                 {
1954                                         if (!strcasecmp(j->GetServerName().c_str(),params))
1955                                         {
1956                                                 j->routes.clear();
1957                                                 j->CloseConnection();
1958                                                 me[i]->connectors.erase(j);
1959                                                 go_again = true;
1960                                                 break;
1961                                         }
1962                                 }
1963                         }
1964                 }
1965         }
1966         log(DEBUG,"Removed server. Will remove clients...");
1967         // iterate through the userlist and remove all users on this server.
1968         // because we're dealing with a mesh, we dont have to deal with anything
1969         // "down-route" from this server (nice huh)
1970         go_again = true;
1971         char reason[MAXBUF];
1972         snprintf(reason,MAXBUF,"%s %s",ServerName,params);
1973         while (go_again)
1974         {
1975                 go_again = false;
1976                 for (user_hash::const_iterator u = clientlist.begin(); u != clientlist.end(); u++)
1977                 {
1978                         if (!strcasecmp(u->second->server,params))
1979                         {
1980                                 kill_link(u->second,reason);
1981                                 go_again = true;
1982                                 break;
1983                         }
1984                 }
1985         }
1986 }
1987
1988 long authcookie;
1989
1990
1991 void process_restricted_commands(char token,char* params,serverrec* source,serverrec* reply, char* tcp_host,char* ipaddr,int port)
1992 {
1993         char buffer[MAXBUF];
1994
1995         switch(token)
1996         {
1997                 // Y <TS>
1998                 // start netburst
1999                 case 'Y':
2000                         nb_start = time(NULL);
2001                         WriteOpers("Server %s is starting netburst.",tcp_host);
2002                         // now broadcast this new servers address out to all servers that are linked to us,
2003                         // except the newcomer. They'll all attempt to connect back to it.
2004                         authcookie = rand()*rand();
2005                         snprintf(buffer,MAXBUF,"~ %d",authcookie);
2006                         NetSendToAll(buffer);
2007                 break;
2008                 // ~
2009                 // Store authcookie
2010                 // once stored, this authcookie permits other servers to log in
2011                 // without user or password, using it.
2012                 case '~':
2013                         auth_cookies.push_back(atoi(params));
2014                         log(DEBUG,"*** Stored auth cookie, will permit servers with auth-cookie %d",atoi(params));
2015                 break;
2016                 // connect back to a server using an authcookie
2017                 case '+':
2018                         handle_plus(token,params,source,reply,tcp_host);
2019                 break;
2020                 // routing table
2021                 case '$':
2022                         handle_dollar(token,params,source,reply,tcp_host);
2023                 break;
2024                 // node unreachable - we cant route to a server, sooooo we slit it off.
2025                 // servers can generate these for themselves for an squit.
2026                 case '&':
2027                         handle_amp(token,params,source,reply,tcp_host);
2028                 break;
2029                 // R <server> <data>
2030                 // redirect token, send all of <data> along to the given 
2031                 // server as this server has been found to still have a route to it
2032                 case 'R':
2033                         handle_R(token,params,source,reply,tcp_host);
2034                 break;
2035                 // ?
2036                 // ping
2037                 case '?':
2038                         reply->SendPacket("!",tcp_host);
2039                 break;
2040                 // ?
2041                 // pong
2042                 case '!':
2043                 break;
2044                 // *
2045                 // no operation
2046                 case '*':
2047                 break;
2048                 // N <TS> <NICK> <HOST> <DHOST> <IDENT> <MODES> <SERVER> :<GECOS>
2049                 // introduce remote client
2050                 case 'N':
2051                         handle_N(token,params,source,reply,tcp_host);
2052                 break;
2053                 // a <NICK> :<GECOS>
2054                 // change GECOS (SETNAME)
2055                 case 'a':
2056                         handle_a(token,params,source,reply,tcp_host);
2057                 break;
2058                 // b <NICK> :<HOST>
2059                 // change displayed host (SETHOST)
2060                 case 'b':
2061                         handle_b(token,params,source,reply,tcp_host);
2062                 break;
2063                 // t <NICK> <CHANNEL> :<TOPIC>
2064                 // change a channel topic
2065                 case 't':
2066                         handle_t(token,params,source,reply,tcp_host);
2067                 break;
2068                 // i <NICK> <CHANNEL>
2069                 // invite a user to a channel
2070                 case 'i':
2071                         handle_i(token,params,source,reply,tcp_host);
2072                 break;
2073                 // k <SOURCE> <DEST> <CHANNEL> :<REASON>
2074                 // kick a user from a channel
2075                 case 'k':
2076                         handle_k(token,params,source,reply,tcp_host);
2077                 break;
2078                 // n <NICK> <NEWNICK>
2079                 // change nickname of client -- a server should only be able to
2080                 // change the nicknames of clients that reside on it unless
2081                 // they are ulined.
2082                 case 'n':
2083                         handle_n(token,params,source,reply,tcp_host);
2084                 break;
2085                 // J <NICK> <CHANLIST>
2086                 // Join user to channel list, merge channel permissions
2087                 case 'J':
2088                         handle_J(token,params,source,reply,tcp_host);
2089                 break;
2090                 // T <TS> <CHANNEL> <TOPICSETTER> :<TOPIC>
2091                 // change channel topic (netburst only)
2092                 case 'T':
2093                         handle_T(token,params,source,reply,tcp_host);
2094                 break;
2095                 // M <TARGET> <MODES> [MODE-PARAMETERS]
2096                 // Server setting modes on an object
2097                 case 'M':
2098                         handle_M(token,params,source,reply,tcp_host);
2099                 break;
2100                 // m <SOURCE> <TARGET> <MODES> [MODE-PARAMETERS]
2101                 // User setting modes on an object
2102                 case 'm':
2103                         handle_m(token,params,source,reply,tcp_host);
2104                 break;
2105                 // P <SOURCE> <TARGET> :<TEXT>
2106                 // Send a private/channel message
2107                 case 'P':
2108                         handle_P(token,params,source,reply,tcp_host);
2109                 break;
2110                 // V <SOURCE> <TARGET> :<TEXT>
2111                 // Send a private/channel notice
2112                 case 'V':
2113                         handle_V(token,params,source,reply,tcp_host);
2114                 break;
2115                 // L <SOURCE> <CHANNEL> :<REASON>
2116                 // User parting a channel
2117                 case 'L':
2118                         handle_L(token,params,source,reply,tcp_host);
2119                 break;
2120                 // Q <SOURCE> :<REASON>
2121                 // user quitting
2122                 case 'Q':
2123                         handle_Q(token,params,source,reply,tcp_host);
2124                 break;
2125                 // H <SERVER>
2126                 // introduce non-meshable server (such as a services server)
2127                 case 'H':
2128                         handle_H(token,params,source,reply,tcp_host);
2129                 break;
2130                 // K <SOURCE> <DEST> :<REASON>
2131                 // remote kill
2132                 case 'K':
2133                         handle_K(token,params,source,reply,tcp_host);
2134                 break;
2135                 // @ <SOURCE> :<TEXT>
2136                 // wallops
2137                 case '@':
2138                         handle_AT(token,params,source,reply,tcp_host);
2139                 break;
2140                 // F <TS>
2141                 // end netburst
2142                 case 'F':
2143                         WriteOpers("Server %s has completed netburst. (%d secs)",tcp_host,time(NULL)-nb_start);
2144                         handle_F(token,params,source,reply,tcp_host);
2145                         nb_start = 0;
2146                         // tell all the other servers to use this authcookie to connect back again
2147                         // got '+ test3.chatspike.net 7010 -2016508415' from test.chatspike.net
2148                         snprintf(buffer,MAXBUF,"+ %s %s %d %d",tcp_host,ipaddr,port,authcookie);
2149                         NetSendToAllExcept(tcp_host,buffer);
2150                 break;
2151                 // F <TS>
2152                 // end netburst with no mesh creation
2153                 case 'f':
2154                         WriteOpers("Server %s has completed netburst. (%d secs)",tcp_host,time(NULL)-nb_start);
2155                         handle_F(token,params,source,reply,tcp_host);
2156                         nb_start = 0;
2157                         // tell everyone else about the new server name so they just add it in the disconnected
2158                         // state
2159                         snprintf(buffer,MAXBUF,"u %s :%s",tcp_host,GetServerDescription(tcp_host).c_str());
2160                         NetSendToAllExcept(tcp_host,buffer);
2161                 break;
2162                 // X <reserved>
2163                 // Send netburst now
2164                 case 'X':
2165                         WriteOpers("Sending my netburst to %s",tcp_host);
2166                         DoSync(source,tcp_host);
2167                         WriteOpers("Send of netburst to %s completed",tcp_host);
2168                         NetSendMyRoutingTable();
2169                 break;
2170                 // anything else
2171                 default:
2172                         WriteOpers("WARNING! Unknown datagram type '%c'",token);
2173                 break;
2174         }
2175 }
2176
2177
2178 void handle_link_packet(char* udp_msg, char* tcp_host, serverrec *serv)
2179 {
2180         if ((!strncmp(udp_msg,"USER ",5)) || (!strncmp(udp_msg,"NICK ",5)))
2181         {
2182                 // a user on a server port, just close their connection.
2183                 RemoveServer(tcp_host);
2184                 return;
2185         }
2186
2187         char response[10240];
2188         char token = udp_msg[0];
2189         char* old = udp_msg;
2190
2191         if (token == ':') // leading :servername or details - strip them off (services does this, sucky)
2192         {
2193                 char* src = udp_msg+1;
2194                 while (udp_msg[0] != ' ')
2195                         udp_msg++;
2196                 udp_msg[0] = 0;
2197                 udp_msg++;
2198                 char* comd = udp_msg;
2199                 while (udp_msg[0] != ' ')
2200                         udp_msg++;
2201                 udp_msg[0] = 0;
2202                 udp_msg++;
2203                 char data[MAXBUF];
2204                 char source[MAXBUF];
2205                 char command[MAXBUF];
2206                 strcpy(data,udp_msg);
2207                 strcpy(source,src);
2208                 strcpy(command,comd);
2209                 udp_msg = old;
2210                 
2211                 // unused numeric:
2212                 // :services-dev.chatspike.net 433 Craig Craig :Nickname is registered to someone else
2213                 if (!strcmp(command,"433"))
2214                 {
2215                         token = '*';
2216                 }
2217                 if (!strcmp(command,"NOTICE"))
2218                 {
2219                         snprintf(udp_msg,MAXBUF,"V %s %s",source,data);
2220                         log(DEBUG,"Rewrote NOTICE from services to: '%s'",udp_msg);
2221                         token = udp_msg[0];
2222                 }
2223                 if (!strcmp(command,"QUIT"))
2224                 {
2225                         if ((!udp_msg) || (!strcmp(data,"")) || (strcmp(data,":")))
2226                         {
2227                                 strcpy(data,":No reason");
2228                         }
2229                         if (!strcmp(data,":"))
2230                         {
2231                                 strcpy(data,":No reason");
2232                         }
2233                         snprintf(udp_msg,MAXBUF,"Q %s %s",source,data);
2234                         log(DEBUG,"Rewrote QUIT from services to: '%s'",udp_msg);
2235                         token = udp_msg[0];
2236                 }
2237                 if (!strcmp(command,"SQUIT"))
2238                 {
2239                         snprintf(udp_msg,MAXBUF,"& %s",source);
2240                         log(DEBUG,"Rewrote SQUIT from services to: '%s'",udp_msg);
2241                         token = udp_msg[0];
2242                 }
2243                 if (!strcmp(command,"SVSMODE"))
2244                 {
2245                         snprintf(udp_msg,MAXBUF,"M %s",data);
2246                         log(DEBUG,"Rewrote SVSMODE from services to: '%s'",udp_msg);
2247                         token = udp_msg[0];
2248                 }
2249                 if (!strcmp(command,"SVS2MODE"))
2250                 {
2251                         snprintf(udp_msg,MAXBUF,"M %s",data);
2252                         log(DEBUG,"Rewrote SVSMODE from services to: '%s'",udp_msg);
2253                         token = udp_msg[0];
2254                 }
2255                 // todo: this wont work without u:lines
2256                 // in give_ops etc allow nick on a u:lined serv to do just about anything
2257                 if (!strcmp(command,"MODE"))
2258                 {
2259                         snprintf(udp_msg,MAXBUF,"m %s %s",source,data);
2260                         log(DEBUG,"Rewrote MODE from services to: '%s'",udp_msg);
2261                         token = udp_msg[0];
2262                 }
2263                 if (!strcmp(command,"KICK"))
2264                 {
2265                         snprintf(udp_msg,MAXBUF,"k %s %s",source,data);
2266                         log(DEBUG,"Rewrote KICK from services to: '%s'",udp_msg);
2267                         token = udp_msg[0];
2268                 }
2269                 
2270         }
2271
2272
2273         char* params = udp_msg + 2;
2274         char finalparam[1024];
2275         strcpy(finalparam," :xxxx");
2276         if (strstr(udp_msg," :")) {
2277                 strncpy(finalparam,strstr(udp_msg," :"),1024);
2278         }
2279         
2280         
2281         if (token == '-') {
2282                 char* cookie = strtok(params," ");
2283                 char* servername = strtok(NULL," ");
2284                 char* serverdesc = finalparam+2;
2285
2286                 WriteOpers("AuthCookie CONNECT from %s (%s)",servername,tcp_host);
2287
2288                 for (int u = 0; u < auth_cookies.size(); u++)
2289                 {
2290                         if (auth_cookies[u] == atoi(cookie))
2291                         {
2292                                 WriteOpers("Allowed cookie from %s, is now part of the mesh",servername);
2293
2294
2295                                 for (int j = 0; j < 32; j++)
2296                                 {
2297                                         if (me[j] != NULL)
2298                                         {
2299                                                 for (int k = 0; k < me[j]->connectors.size(); k++)
2300                                                 {
2301                                                         if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),tcp_host))
2302                                                         {
2303                                                                 me[j]->connectors[k].SetServerName(servername);
2304                                                                 me[j]->connectors[k].SetDescription(serverdesc);
2305                                                                 me[j]->connectors[k].SetState(STATE_CONNECTED);
2306                                                                 NetSendMyRoutingTable();
2307                                                                 return;
2308                                                         }
2309                                                 }
2310                                         }
2311                                         WriteOpers("\2WARNING!\2 %s sent us an authentication packet but we are not authenticating with this server right now! Possible intrusion attempt!",tcp_host);
2312                                         return;
2313                                 }
2314
2315
2316                                 return;
2317                         }
2318                 }
2319                 // bad cookie, bad bad! go sit in the corner!
2320                 WriteOpers("Bad cookie from %s!",servername);
2321                 return;
2322         }
2323         else
2324         if (token == 'S') {
2325                 // S test.chatspike.net password portn :ChatSpike InspIRCd test server
2326                 char* servername = strtok(params," ");
2327                 char* password = strtok(NULL," ");
2328                 char* myport = strtok(NULL," ");
2329                 char* revision = strtok(NULL," ");
2330                 char* serverdesc = finalparam+2;
2331
2332                 WriteOpers("CONNECT from %s (%s) (their port: %d)",servername,tcp_host,atoi(myport));
2333                 
2334                 ircd_connector* cn = serv->FindHost(servername);
2335                 
2336                 if (cn)
2337                 {
2338                         WriteOpers("CONNECT aborted: Server %s already exists from %s",servername,ServerName);
2339                         char buffer[MAXBUF];
2340                         sprintf(buffer,"E :Server %s already exists!",servername);
2341                         serv->SendPacket(buffer,tcp_host);
2342                         RemoveServer(tcp_host);
2343                         return;
2344                 }
2345
2346                 if (atoi(revision) != GetRevision())
2347                 {
2348                         WriteOpers("CONNECT aborted: Could not link to %s, is an incompatible version %s, our version is %d",servername,revision,GetRevision());
2349                         char buffer[MAXBUF];
2350                         sprintf(buffer,"E :Version number mismatch");
2351                         serv->SendPacket(buffer,tcp_host);
2352                         RemoveServer(tcp_host);
2353                         RemoveServer(servername);
2354                         return;
2355                 }
2356
2357                 for (int j = 0; j < serv->connectors.size(); j++)
2358                 {
2359                         if (!strcasecmp(serv->connectors[j].GetServerName().c_str(),tcp_host))
2360                         {
2361                                 serv->connectors[j].SetServerName(servername);
2362                                 serv->connectors[j].SetDescription(serverdesc);
2363                                 serv->connectors[j].SetServerPort(atoi(myport));
2364                         }
2365                 }
2366                 
2367                 
2368                 char Link_ServerName[1024];
2369                 char Link_IPAddr[1024];
2370                 char Link_Port[1024];
2371                 char Link_Pass[1024];
2372                 char Link_SendPass[1024];
2373                 int LinkPort = 0;
2374                 
2375                 // search for a corresponding <link> block in the config files
2376                 for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
2377                 {
2378                         ConfValue("link","name",i,Link_ServerName,&config_f);
2379                         ConfValue("link","ipaddr",i,Link_IPAddr,&config_f);
2380                         ConfValue("link","port",i,Link_Port,&config_f);
2381                         ConfValue("link","recvpass",i,Link_Pass,&config_f);
2382                         ConfValue("link","sendpass",i,Link_SendPass,&config_f);
2383                         log(DEBUG,"(%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s'",i,Link_ServerName,Link_IPAddr,Link_Port,Link_Pass);
2384                         LinkPort = atoi(Link_Port);
2385                         if (!strcasecmp(Link_ServerName,servername))
2386                         {
2387                                 // we have a matching link line -
2388                                 // send a 'diminutive' server message back...
2389                                 snprintf(response,10240,"s %s %s :%s",ServerName,Link_SendPass,ServerDesc);
2390                                 serv->SendPacket(response,servername);
2391
2392                                 for (int t = 0; t < serv->connectors.size(); t++)
2393                                 {
2394                                         if (!strcasecmp(serv->connectors[t].GetServerName().c_str(),servername))
2395                                         {
2396                                                 serv->connectors[t].SetState(STATE_CONNECTED);
2397                                         }
2398                                 }
2399                 
2400                                 return;
2401                         }
2402                 }
2403                 char buffer[MAXBUF];
2404                 sprintf(buffer,"E :Access is denied (no matching link block)");
2405                 serv->SendPacket(buffer,tcp_host);
2406                 WriteOpers("CONNECT from %s denied, no matching link block",servername);
2407                 RemoveServer(tcp_host);
2408                 RemoveServer(servername);
2409                 return;
2410         }
2411         else
2412         if (token == 's') {
2413                 // S test.chatspike.net password :ChatSpike InspIRCd test server
2414                 char* servername = strtok(params," ");
2415                 char* password = strtok(NULL," ");
2416                 char* serverdesc = finalparam+2;
2417                 
2418                 // TODO: we should do a check here to ensure that this server is one we recently initiated a
2419                 // link with, and didnt hear an 's' or 'E' back from yet (these are the only two valid responses
2420                 // to an 'S' command. If we didn't recently send an 'S' to this server, theyre trying to spoof
2421                 // a connect, so put out an oper alert!
2422                 
2423                 // for now, just accept all, we'll fix that later.
2424                 WriteOpers("%s accepted our link credentials ",servername);
2425                 
2426                 char Link_ServerName[1024];
2427                 char Link_IPAddr[1024];
2428                 char Link_Port[1024];
2429                 char Link_Pass[1024];
2430                 char Link_SendPass[1024];
2431                 int LinkPort = 0;
2432                 
2433                 // search for a corresponding <link> block in the config files
2434                 for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
2435                 {
2436                         ConfValue("link","name",i,Link_ServerName,&config_f);
2437                         ConfValue("link","ipaddr",i,Link_IPAddr,&config_f);
2438                         ConfValue("link","port",i,Link_Port,&config_f);
2439                         ConfValue("link","recvpass",i,Link_Pass,&config_f);
2440                         ConfValue("link","sendpass",i,Link_SendPass,&config_f);
2441                         log(DEBUG,"(%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s'",i,Link_ServerName,Link_IPAddr,Link_Port,Link_Pass);
2442                         LinkPort = atoi(Link_Port);
2443                         if (!strcasecmp(Link_ServerName,servername))
2444                         {
2445                                 // matching link at this end too, we're all done!
2446                                 // at this point we must begin key exchange and insert this
2447                                 // server into our 'active' table.
2448                                 for (int j = 0; j < 32; j++)
2449                                 {
2450                                         if (me[j] != NULL)
2451                                         {
2452                                                 for (int k = 0; k < me[j]->connectors.size(); k++)
2453                                                 {
2454                                                         if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),tcp_host))
2455                                                         {
2456                                                                 char buffer[MAXBUF];
2457                                                                 me[j]->connectors[k].SetDescription(serverdesc);
2458                                                                 me[j]->connectors[k].SetState(STATE_CONNECTED);
2459                                                                 sprintf(buffer,"X 0");
2460                                                                 serv->SendPacket(buffer,tcp_host);
2461                                                                 DoSync(me[j],tcp_host);
2462                                                                 NetSendMyRoutingTable();
2463                                                                 return;
2464                                                         }
2465                                                 }
2466                                         }
2467                                         WriteOpers("\2WARNING!\2 %s sent us an authentication packet but we are not authenticating with this server right noe! Possible intrusion attempt!",tcp_host);
2468                                         return;
2469                                 }
2470                         }
2471                         else {
2472                                 log(DEBUG,"Server names '%s' and '%s' don't match",Link_ServerName,servername);
2473                         }
2474                 }
2475                 char buffer[MAXBUF];
2476                 sprintf(buffer,"E :Access is denied (no matching link block)");
2477                 serv->SendPacket(buffer,tcp_host);
2478                 WriteOpers("CONNECT from %s denied, no matching link block",servername);
2479                 RemoveServer(tcp_host);
2480                 RemoveServer(servername);
2481                 return;
2482         }
2483         else
2484         if (token == 'U') {
2485                 // U services.chatspike.net password :ChatSpike Services
2486                 //
2487                 // non-meshed link, used by services. Everything coming from a non-meshed link is auto broadcasted.
2488                 char* servername = strtok(params," ");
2489                 char* password = strtok(NULL," ");
2490                 char* serverdesc = finalparam+2;
2491                 
2492                 char Link_ServerName[1024];
2493                 char Link_IPAddr[1024];
2494                 char Link_Port[1024];
2495                 char Link_Pass[1024];
2496                 char Link_SendPass[1024];
2497                 int LinkPort = 0;
2498                 
2499                 // search for a corresponding <link> block in the config files
2500                 for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
2501                 {
2502                         ConfValue("link","name",i,Link_ServerName,&config_f);
2503                         ConfValue("link","ipaddr",i,Link_IPAddr,&config_f);
2504                         ConfValue("link","port",i,Link_Port,&config_f);
2505                         ConfValue("link","recvpass",i,Link_Pass,&config_f);
2506                         ConfValue("link","sendpass",i,Link_SendPass,&config_f);
2507                         log(DEBUG,"(%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s'",i,Link_ServerName,Link_IPAddr,Link_Port,Link_Pass);
2508                         LinkPort = atoi(Link_Port);
2509                         if (!strcasecmp(Link_ServerName,servername))
2510                         {
2511                                 // matching link at this end too, we're all done!
2512                                 // at this point we must begin key exchange and insert this
2513                                 // server into our 'active' table.
2514                                 for (int j = 0; j < 32; j++)
2515                                 {
2516                                         if (me[j] != NULL)
2517                                         {
2518                                                 for (int k = 0; k < me[j]->connectors.size(); k++)
2519                                                 {
2520                                                         if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),tcp_host))
2521                                                         {
2522                                                                 char buffer[MAXBUF];
2523                                                                 me[j]->connectors[k].SetDescription(serverdesc);
2524                                                                 me[j]->connectors[k].SetServerName(servername);
2525                                                                 me[j]->connectors[k].SetState(STATE_SERVICES);
2526                                                                 sprintf(buffer,"X 0");
2527                                                                 serv->SendPacket(buffer,servername);
2528                                                                 DoSync(me[j],servername);
2529                                                                 NetSendMyRoutingTable();
2530                                                                 sprintf(buffer,"H %s",servername);
2531                                                                 NetSendToAllExcept(servername,buffer);
2532                                                                 return;
2533                                                         }
2534                                                 }
2535                                         }
2536                                         WriteOpers("\2WARNING!\2 %s sent us an authentication packet but we are not authenticating with this server right noe! Possible intrusion attempt!",tcp_host);
2537                                         return;
2538                                 }
2539                         }
2540                         else {
2541                                 log(DEBUG,"Server names '%s' and '%s' don't match",Link_ServerName,servername);
2542                         }
2543                 }
2544                 char buffer[MAXBUF];
2545                 sprintf(buffer,"E :Access is denied (no matching link block)");
2546                 serv->SendPacket(buffer,tcp_host);
2547                 WriteOpers("CONNECT from %s denied, no matching link block",servername);
2548                 RemoveServer(tcp_host);
2549                 RemoveServer(servername);
2550                 return;
2551         }
2552         else
2553         if (token == 'E') {
2554                 char* error_message = finalparam+2;
2555                 WriteOpers("ERROR from %s: %s",tcp_host,error_message);
2556                 return;
2557         }
2558         else {
2559
2560                 serverrec* source_server = NULL;
2561
2562                 for (int j = 0; j < 32; j++)
2563                 {
2564                         if (me[j] != NULL)
2565                         {
2566                                 for (int x = 0; x < me[j]->connectors.size(); x++)
2567                                 {
2568                                         log(DEBUG,"Servers are: '%s' '%s'",tcp_host,me[j]->connectors[x].GetServerName().c_str());
2569                                         if (!strcasecmp(me[j]->connectors[x].GetServerName().c_str(),tcp_host))
2570                                         {
2571                                                 if ((me[j]->connectors[x].GetState() == STATE_CONNECTED) || (me[j]->connectors[x].GetState() == STATE_SERVICES))
2572                                                 {
2573                                                         // found a valid ircd_connector.
2574                                                         process_restricted_commands(token,params,me[j],serv,tcp_host,me[j]->connectors[x].GetServerIP(),me[j]->connectors[x].GetServerPort());
2575                                                         return;
2576                                                 }
2577                                         }
2578                                 }
2579                         }
2580                 }
2581
2582                 log(DEBUG,"Unrecognised token or unauthenticated host in datagram from %s: %c",tcp_host,token);
2583         }
2584 }
2585