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