]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_spanningtree/treesocket2.cpp
Fix broken openssl outbound connects.
[user/henk/code/inspircd.git] / src / modules / m_spanningtree / treesocket2.cpp
1 #include "configreader.h"
2 #include "users.h"
3 #include "channels.h"
4 #include "modules.h"
5 #include "commands/cmd_whois.h"
6 #include "commands/cmd_stats.h"
7 #include "socket.h"
8 #include "inspircd.h"
9 #include "wildcard.h"
10 #include "xline.h"
11 #include "transport.h"
12 #include "socketengine.h"
13
14 #include "m_spanningtree/main.h"
15 #include "m_spanningtree/utils.h"
16 #include "m_spanningtree/treeserver.h"
17 #include "m_spanningtree/link.h"
18 #include "m_spanningtree/treesocket.h"
19 #include "m_spanningtree/resolvers.h"
20 #include "m_spanningtree/handshaketimer.h"
21
22 /* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h */
23
24 int TreeSocket::WriteLine(std::string line)
25 {
26         Instance->Log(DEBUG, "-> %s", line.c_str());
27         line.append("\r\n");
28         return this->Write(line);
29 }
30
31 /* Handle ERROR command */
32 bool TreeSocket::Error(std::deque<std::string> &params)
33 {
34         if (params.size() < 1)
35                 return false;
36         this->Instance->SNO->WriteToSnoMask('l',"ERROR from %s: %s",(InboundServerName != "" ? InboundServerName.c_str() : myhost.c_str()),params[0].c_str());
37         /* we will return false to cause the socket to close. */
38         return false;
39 }
40
41 /** remote MOTD. leet, huh? */
42 bool TreeSocket::Motd(const std::string &prefix, std::deque<std::string> &params)
43 {
44         if (params.size() > 0)
45         {
46                 if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
47                 {
48                         /* It's for our server */
49                         string_list results;
50                         userrec* source = this->Instance->FindNick(prefix);
51
52                         if (source)
53                         {
54                                 std::deque<std::string> par;
55                                 par.push_back(prefix);
56                                 par.push_back("");
57
58                                 if (!Instance->Config->MOTD.size())
59                                 {
60                                         par[1] = std::string("::")+Instance->Config->ServerName+" 422 "+source->nick+" :Message of the day file is missing.";
61                                         Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
62                                         return true;
63                                 }
64
65                                 par[1] = std::string("::")+Instance->Config->ServerName+" 375 "+source->nick+" :"+Instance->Config->ServerName+" message of the day";
66                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
67
68                                 for (unsigned int i = 0; i < Instance->Config->MOTD.size(); i++)
69                                 {
70                                         par[1] = std::string("::")+Instance->Config->ServerName+" 372 "+source->nick+" :- "+Instance->Config->MOTD[i];
71                                         Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
72                                 }
73
74                                 par[1] = std::string("::")+Instance->Config->ServerName+" 376 "+source->nick+" End of message of the day.";
75                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
76                         }
77                 }
78                 else
79                 {
80                         /* Pass it on */
81                         userrec* source = this->Instance->FindNick(prefix);
82                         if (source)
83                                 Utils->DoOneToOne(prefix, "MOTD", params, params[0]);
84                 }
85         }
86         return true;
87 }
88
89 /** remote ADMIN. leet, huh? */
90 bool TreeSocket::Admin(const std::string &prefix, std::deque<std::string> &params)
91 {
92         if (params.size() > 0)
93         {
94                 if (this->Instance->MatchText(this->Instance->Config->ServerName, params[0]))
95                 {
96                         /* It's for our server */
97                         string_list results;
98                         userrec* source = this->Instance->FindNick(prefix);
99                         if (source)
100                         {
101                                 std::deque<std::string> par;
102                                 par.push_back(prefix);
103                                 par.push_back("");
104                                 par[1] = std::string("::")+Instance->Config->ServerName+" 256 "+source->nick+" :Administrative info for "+Instance->Config->ServerName;
105                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
106                                 par[1] = std::string("::")+Instance->Config->ServerName+" 257 "+source->nick+" :Name     - "+Instance->Config->AdminName;
107                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
108                                 par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :Nickname - "+Instance->Config->AdminNick;
109                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
110                                 par[1] = std::string("::")+Instance->Config->ServerName+" 258 "+source->nick+" :E-Mail   - "+Instance->Config->AdminEmail;
111                                 Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
112                         }
113                 }
114                 else
115                 {
116                         /* Pass it on */
117                         userrec* source = this->Instance->FindNick(prefix);
118                         if (source)
119                                 Utils->DoOneToOne(prefix, "ADMIN", params, params[0]);
120                 }
121         }
122         return true;
123 }
124
125 bool TreeSocket::Stats(const std::string &prefix, std::deque<std::string> &params)
126 {
127         /* Get the reply to a STATS query if it matches this servername,
128          * and send it back as a load of PUSH queries
129          */
130         if (params.size() > 1)
131         {
132                 if (this->Instance->MatchText(this->Instance->Config->ServerName, params[1]))
133                 {
134                         /* It's for our server */
135                         string_list results;
136                         userrec* source = this->Instance->FindNick(prefix);
137                         if (source)
138                         {
139                                 std::deque<std::string> par;
140                                 par.push_back(prefix);
141                                 par.push_back("");
142                                 DoStats(this->Instance, *(params[0].c_str()), source, results);
143                                 for (size_t i = 0; i < results.size(); i++)
144                                 {
145                                         par[1] = "::" + results[i];
146                                         Utils->DoOneToOne(this->Instance->Config->ServerName, "PUSH",par, source->server);
147                                 }
148                         }
149                 }
150                 else
151                 {
152                         /* Pass it on */
153                         userrec* source = this->Instance->FindNick(prefix);
154                         if (source)
155                                 Utils->DoOneToOne(prefix, "STATS", params, params[1]);
156                 }
157         }
158         return true;
159 }
160
161
162 /** Because the core won't let users or even SERVERS set +o,
163  * we use the OPERTYPE command to do this.
164  */
165 bool TreeSocket::OperType(const std::string &prefix, std::deque<std::string> &params)
166 {
167         if (params.size() != 1)
168                 return true;
169         std::string opertype = params[0];
170         userrec* u = this->Instance->FindNick(prefix);
171         if (u)
172         {
173                 u->modes[UM_OPERATOR] = 1;
174                 this->Instance->all_opers.push_back(u);
175                 strlcpy(u->oper,opertype.c_str(),NICKMAX-1);
176                 Utils->DoOneToAllButSender(u->nick,"OPERTYPE",params,u->server);
177                 this->Instance->SNO->WriteToSnoMask('o',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server, u->nick,u->ident,u->host,irc::Spacify(opertype.c_str()));
178         }
179         return true;
180 }
181
182 /** Because Andy insists that services-compatible servers must
183  * implement SVSNICK and SVSJOIN, that's exactly what we do :p
184  */
185 bool TreeSocket::ForceNick(const std::string &prefix, std::deque<std::string> &params)
186 {
187         if (params.size() < 3)
188                 return true;
189
190         userrec* u = this->Instance->FindNick(params[0]);
191
192         if (u)
193         {
194                 Utils->DoOneToAllButSender(prefix,"SVSNICK",params,prefix);
195                 if (IS_LOCAL(u))
196                 {
197                         std::deque<std::string> par;
198                         par.push_back(params[1]);
199                         if (!u->ForceNickChange(params[1].c_str()))
200                         {
201                                 userrec::QuitUser(this->Instance, u, "Nickname collision");
202                                 return true;
203                         }
204                         u->age = atoi(params[2].c_str());
205                 }
206         }
207         return true;
208 }
209
210 /*
211  * Remote SQUIT (RSQUIT). Routing works similar to SVSNICK: Route it to the server that the target is connected to locally,
212  * then let that server do the dirty work (squit it!). Example:
213  * A -> B -> C -> D: oper on A squits D, A routes to B, B routes to C, C notices D connected locally, kills it. -- w00t
214  */
215 bool TreeSocket::RemoteSquit(const std::string &prefix, std::deque<std::string> &params)
216 {
217         /* ok.. :w00t RSQUIT jupe.barafranca.com :reason here */
218         if (params.size() < 2)
219                 return true;
220
221         TreeServer* s = Utils->FindServerMask(params[0]);
222
223         if (s)
224         {
225                 if (s == Utils->TreeRoot)
226                 {
227                         this->Instance->SNO->WriteToSnoMask('l',"What the fuck, I recieved a remote SQUIT for myself? :< (from %s", prefix.c_str());
228                         return true;
229                 }
230
231                 TreeSocket* sock = s->GetSocket();
232
233                 if (sock)
234                 {
235                         /* it's locally connected, KILL IT! */
236                         Instance->SNO->WriteToSnoMask('l',"RSQUIT: Server \002%s\002 removed from network by %s: %s", params[0].c_str(), prefix.c_str(), params[1].c_str());
237                         sock->Squit(s,"Server quit by " + prefix + ": " + params[1]);
238                         Instance->SE->DelFd(sock);
239                         sock->Close();
240                         delete sock;
241                 }
242                 else
243                 {
244                         /* route the rsquit */
245                         params[1] = ":" + params[1];
246                         Utils->DoOneToOne(prefix, "RSQUIT", params, params[0]);
247                 }
248         }
249         else
250         {
251                 /* mother fucker! it doesn't exist */
252         }
253
254         return true;
255 }
256
257 bool TreeSocket::ServiceJoin(const std::string &prefix, std::deque<std::string> &params)
258 {
259         if (params.size() < 2)
260                 return true;
261
262         userrec* u = this->Instance->FindNick(params[0]);
263
264         if (u)
265         {
266                 /* only join if it's local, otherwise just pass it on! */
267                 if (IS_LOCAL(u))
268                         chanrec::JoinUser(this->Instance, u, params[1].c_str(), false);
269                 Utils->DoOneToAllButSender(prefix,"SVSJOIN",params,prefix);
270         }
271         return true;
272 }
273
274 bool TreeSocket::RemoteRehash(const std::string &prefix, std::deque<std::string> &params)
275 {
276         if (params.size() < 1)
277                 return false;
278
279         std::string servermask = params[0];
280
281         if (this->Instance->MatchText(this->Instance->Config->ServerName,servermask))
282         {
283                 this->Instance->SNO->WriteToSnoMask('l',"Remote rehash initiated by \002"+prefix+"\002.");
284                 this->Instance->RehashServer();
285                 Utils->ReadConfiguration(false);
286                 InitializeDisabledCommands(Instance->Config->DisabledCommands, Instance);
287         }
288         Utils->DoOneToAllButSender(prefix,"REHASH",params,prefix);
289         return true;
290 }
291
292 bool TreeSocket::RemoteKill(const std::string &prefix, std::deque<std::string> &params)
293 {
294         if (params.size() != 2)
295                 return true;
296
297         std::string nick = params[0];
298         userrec* u = this->Instance->FindNick(prefix);
299         userrec* who = this->Instance->FindNick(nick);
300
301         if (who)
302         {
303                 /* Prepend kill source, if we don't have one */
304                 std::string sourceserv = prefix;
305                 if (u)
306                 {
307                         sourceserv = u->server;
308                 }
309                 if (*(params[1].c_str()) != '[')
310                 {
311                         params[1] = "[" + sourceserv + "] Killed (" + params[1] +")";
312                 }
313                 std::string reason = params[1];
314                 params[1] = ":" + params[1];
315                 Utils->DoOneToAllButSender(prefix,"KILL",params,sourceserv);
316                 who->Write(":%s KILL %s :%s (%s)", sourceserv.c_str(), who->nick, sourceserv.c_str(), reason.c_str());
317                 userrec::QuitUser(this->Instance,who,reason);
318         }
319         return true;
320 }
321
322 bool TreeSocket::LocalPong(const std::string &prefix, std::deque<std::string> &params)
323 {
324         if (params.size() < 1)
325                 return true;
326
327         if (params.size() == 1)
328         {
329                 TreeServer* ServerSource = Utils->FindServer(prefix);
330                 if (ServerSource)
331                 {
332                         ServerSource->SetPingFlag();
333                 }
334         }
335         else
336         {
337                 std::string forwardto = params[1];
338                 if (forwardto == this->Instance->Config->ServerName)
339                 {
340                         /*
341                          * this is a PONG for us
342                          * if the prefix is a user, check theyre local, and if they are,
343                          * dump the PONG reply back to their fd. If its a server, do nowt.
344                          * Services might want to send these s->s, but we dont need to yet.
345                          */
346                         userrec* u = this->Instance->FindNick(prefix);
347                         if (u)
348                         {
349                                 u->WriteServ("PONG %s %s",params[0].c_str(),params[1].c_str());
350                         }
351                 }
352                 else
353                 {
354                         // not for us, pass it on :)
355                         Utils->DoOneToOne(prefix,"PONG",params,forwardto);
356                 }
357         }
358
359         return true;
360 }
361
362 bool TreeSocket::MetaData(const std::string &prefix, std::deque<std::string> &params)
363 {
364         if (params.size() < 3)
365                 return true;
366         TreeServer* ServerSource = Utils->FindServer(prefix);
367         if (ServerSource)
368         {
369                 if (params[0] == "*")
370                 {
371                         FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_OTHER,NULL,params[1],params[2]));
372                 }
373                 else if (*(params[0].c_str()) == '#')
374                 {
375                         chanrec* c = this->Instance->FindChan(params[0]);
376                         if (c)
377                         {
378                                 FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_CHANNEL,c,params[1],params[2]));
379                         }
380                 }
381                 else if (*(params[0].c_str()) != '#')
382                 {
383                         userrec* u = this->Instance->FindNick(params[0]);
384                         if (u)
385                         {
386                                 FOREACH_MOD_I(this->Instance,I_OnDecodeMetaData,OnDecodeMetaData(TYPE_USER,u,params[1],params[2]));
387                         }
388                 }
389         }
390
391         params[2] = ":" + params[2];
392         Utils->DoOneToAllButSender(prefix,"METADATA",params,prefix);
393         return true;
394 }
395
396 bool TreeSocket::ServerVersion(const std::string &prefix, std::deque<std::string> &params)
397 {
398         if (params.size() < 1)
399                 return true;
400
401         TreeServer* ServerSource = Utils->FindServer(prefix);
402
403         if (ServerSource)
404         {
405                 ServerSource->SetVersion(params[0]);
406         }
407         params[0] = ":" + params[0];
408         Utils->DoOneToAllButSender(prefix,"VERSION",params,prefix);
409         return true;
410 }
411
412 bool TreeSocket::ChangeHost(const std::string &prefix, std::deque<std::string> &params)
413 {
414         if (params.size() < 1)
415                 return true;
416         userrec* u = this->Instance->FindNick(prefix);
417
418         if (u)
419         {
420                 u->ChangeDisplayedHost(params[0].c_str());
421                 Utils->DoOneToAllButSender(prefix,"FHOST",params,u->server);
422         }
423         return true;
424 }
425
426 bool TreeSocket::AddLine(const std::string &prefix, std::deque<std::string> &params)
427 {
428         if (params.size() < 6)
429                 return true;
430         bool propogate = false;
431         if (!this->bursting)
432                 Utils->lines_to_apply = 0;
433         switch (*(params[0].c_str()))
434         {
435                 case 'Z':
436                         propogate = Instance->XLines->add_zline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
437                         Instance->XLines->zline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
438                         if (propogate)
439                                 Utils->lines_to_apply |= APPLY_ZLINES;
440                 break;
441                 case 'Q':
442                         propogate = Instance->XLines->add_qline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
443                         Instance->XLines->qline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
444                         if (propogate)
445                                 Utils->lines_to_apply |= APPLY_QLINES;
446                 break;
447                 case 'E':
448                         propogate = Instance->XLines->add_eline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
449                         Instance->XLines->eline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
450                 break;
451                 case 'G':
452                         propogate = Instance->XLines->add_gline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
453                         Instance->XLines->gline_set_creation_time(params[1].c_str(), atoi(params[3].c_str()));
454                         if (propogate)
455                                 Utils->lines_to_apply |= APPLY_GLINES;
456                 break;
457                 case 'K':
458                         propogate = Instance->XLines->add_kline(atoi(params[4].c_str()), params[2].c_str(), params[5].c_str(), params[1].c_str());
459                         if (propogate)
460                                 Utils->lines_to_apply |= APPLY_KLINES;
461                 break;
462                 default:
463                         /* Just in case... */
464                         this->Instance->SNO->WriteToSnoMask('x',"\2WARNING\2: Invalid xline type '"+params[0]+"' sent by server "+prefix+", ignored!");
465                         propogate = false;
466                 break;
467         }
468         /* Send it on its way */
469         if (propogate)
470         {
471                 if (atoi(params[4].c_str()))
472                 {
473                         this->Instance->SNO->WriteToSnoMask('x',"%s Added %cLINE on %s to expire in %lu seconds (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),atoi(params[4].c_str()),params[5].c_str());
474                 }
475                 else
476                 {
477                         this->Instance->SNO->WriteToSnoMask('x',"%s Added permenant %cLINE on %s (%s).",prefix.c_str(),*(params[0].c_str()),params[1].c_str(),params[5].c_str());
478                 }
479                 params[5] = ":" + params[5];
480                 Utils->DoOneToAllButSender(prefix,"ADDLINE",params,prefix);
481         }
482         if (!this->bursting)
483         {
484                 Instance->XLines->apply_lines(Utils->lines_to_apply);
485                 Utils->lines_to_apply = 0;
486         }
487         return true;
488 }
489
490 bool TreeSocket::ChangeName(const std::string &prefix, std::deque<std::string> &params)
491 {
492         if (params.size() < 1)
493                 return true;
494         userrec* u = this->Instance->FindNick(prefix);
495         if (u)
496         {
497                 u->ChangeName(params[0].c_str());
498                 params[0] = ":" + params[0];
499                 Utils->DoOneToAllButSender(prefix,"FNAME",params,u->server);
500         }
501         return true;
502 }
503
504 bool TreeSocket::Whois(const std::string &prefix, std::deque<std::string> &params)
505 {
506         if (params.size() < 1)
507                 return true;
508         userrec* u = this->Instance->FindNick(prefix);
509         if (u)
510         {
511                 // an incoming request
512                 if (params.size() == 1)
513                 {
514                         userrec* x = this->Instance->FindNick(params[0]);
515                         if ((x) && (IS_LOCAL(x)))
516                         {
517                                 userrec* x = this->Instance->FindNick(params[0]);
518                                 char signon[MAXBUF];
519                                 char idle[MAXBUF];
520                                 snprintf(signon,MAXBUF,"%lu",(unsigned long)x->signon);
521                                 snprintf(idle,MAXBUF,"%lu",(unsigned long)abs((x->idle_lastmsg)-Instance->Time(true)));
522                                 std::deque<std::string> par;
523                                 par.push_back(prefix);
524                                 par.push_back(signon);
525                                 par.push_back(idle);
526                                 // ours, we're done, pass it BACK
527                                 Utils->DoOneToOne(params[0],"IDLE",par,u->server);
528                         }
529                         else
530                         {
531                                 // not ours pass it on
532                                 Utils->DoOneToOne(prefix,"IDLE",params,x->server);
533                         }
534                 }
535                 else if (params.size() == 3)
536                 {
537                         std::string who_did_the_whois = params[0];
538                         userrec* who_to_send_to = this->Instance->FindNick(who_did_the_whois);
539                         if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))
540                         {
541                                 // an incoming reply to a whois we sent out
542                                 std::string nick_whoised = prefix;
543                                 unsigned long signon = atoi(params[1].c_str());
544                                 unsigned long idle = atoi(params[2].c_str());
545                                 if ((who_to_send_to) && (IS_LOCAL(who_to_send_to)))
546                                         do_whois(this->Instance,who_to_send_to,u,signon,idle,nick_whoised.c_str());
547                         }
548                         else
549                         {
550                                 // not ours, pass it on
551                                 Utils->DoOneToOne(prefix,"IDLE",params,who_to_send_to->server);
552                         }
553                 }
554         }
555         return true;
556 }
557
558 bool TreeSocket::Push(const std::string &prefix, std::deque<std::string> &params)
559 {
560         if (params.size() < 2)
561                 return true;
562         userrec* u = this->Instance->FindNick(params[0]);
563         if (!u)
564                 return true;
565         if (IS_LOCAL(u))
566         {
567                 u->Write(params[1]);
568         }
569         else
570         {
571                 // continue the raw onwards
572                 params[1] = ":" + params[1];
573                 Utils->DoOneToOne(prefix,"PUSH",params,u->server);
574         }
575         return true;
576 }
577
578 bool TreeSocket::HandleSetTime(const std::string &prefix, std::deque<std::string> &params)
579 {
580         if (!params.size() || !Utils->EnableTimeSync)
581                 return true;
582
583         bool force = false;
584
585         if ((params.size() == 2) && (params[1] == "FORCE"))
586                 force = true;
587
588         time_t rts = atoi(params[0].c_str());
589         time_t us = Instance->Time(true);
590
591         if (rts == us)
592         {
593                 Utils->DoOneToAllButSender(prefix, "TIMESET", params, prefix);
594         }
595         else if (force || (rts < us))
596         {
597                 int old = Instance->SetTimeDelta(rts - us);
598                 Instance->Log(DEBUG, "%s TS (diff %d) from %s applied (old delta was %d)", (force) ? "Forced" : "Lower", rts - us, prefix.c_str(), old);
599
600                 Utils->DoOneToAllButSender(prefix, "TIMESET", params, prefix);
601         }
602         else
603         {
604                 Instance->Log(DEBUG, "Higher TS (diff %d) from %s overridden", us - rts, prefix.c_str());
605
606                 std::deque<std::string> oparams;
607                 oparams.push_back(ConvToStr(us));
608
609                 Utils->DoOneToMany(prefix, "TIMESET", oparams);
610         }
611
612         return true;
613 }
614
615 bool TreeSocket::Time(const std::string &prefix, std::deque<std::string> &params)
616 {
617         // :source.server TIME remote.server sendernick
618         // :remote.server TIME source.server sendernick TS
619         if (params.size() == 2)
620         {
621                 // someone querying our time?
622                 if (this->Instance->Config->ServerName == params[0])
623                 {
624                         userrec* u = this->Instance->FindNick(params[1]);
625                         if (u)
626                         {
627                                 params.push_back(ConvToStr(Instance->Time(false)));
628                                 params[0] = prefix;
629                                 Utils->DoOneToOne(this->Instance->Config->ServerName,"TIME",params,params[0]);
630                         }
631                 }
632                 else
633                 {
634                         // not us, pass it on
635                         userrec* u = this->Instance->FindNick(params[1]);
636                         if (u)
637                                 Utils->DoOneToOne(prefix,"TIME",params,params[0]);
638                 }
639         }
640         else if (params.size() == 3)
641         {
642                 // a response to a previous TIME
643                 userrec* u = this->Instance->FindNick(params[1]);
644                 if ((u) && (IS_LOCAL(u)))
645                 {
646                         time_t rawtime = atol(params[2].c_str());
647                         struct tm * timeinfo;
648                         timeinfo = localtime(&rawtime);
649                         char tms[26];
650                         snprintf(tms,26,"%s",asctime(timeinfo));
651                         tms[24] = 0;
652                         u->WriteServ("391 %s %s :%s",u->nick,prefix.c_str(),tms);
653                 }
654                 else
655                 {
656                         if (u)
657                                 Utils->DoOneToOne(prefix,"TIME",params,u->server);
658                 }
659         }
660         return true;
661 }
662
663 bool TreeSocket::LocalPing(const std::string &prefix, std::deque<std::string> &params)
664 {
665         if (params.size() < 1)
666                 return true;
667         if (params.size() == 1)
668         {
669                 std::string stufftobounce = params[0];
670                 this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" PONG "+stufftobounce);
671                 return true;
672         }
673         else
674         {
675                 std::string forwardto = params[1];
676                 if (forwardto == this->Instance->Config->ServerName)
677                 {
678                         // this is a ping for us, send back PONG to the requesting server
679                         params[1] = params[0];
680                         params[0] = forwardto;
681                         Utils->DoOneToOne(forwardto,"PONG",params,params[1]);
682                 }
683                 else
684                 {
685                         // not for us, pass it on :)
686                         Utils->DoOneToOne(prefix,"PING",params,forwardto);
687                 }
688                 return true;
689         }
690 }
691
692 bool TreeSocket::RemoveStatus(const std::string &prefix, std::deque<std::string> &params)
693 {
694         if (params.size() < 1)
695                 return true;
696         chanrec* c = Instance->FindChan(params[0]);
697         if (c)
698         {
699                 irc::modestacker modestack(false);
700                 CUList *ulist = c->GetUsers();
701                 const char* y[127];
702                 std::deque<std::string> stackresult;
703                 std::string x;
704                 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
705                 {
706                         std::string modesequence = Instance->Modes->ModeString(i->second, c);
707                         if (modesequence.length())
708                         {
709                                 irc::spacesepstream sep(modesequence);
710                                 std::string modeletters = sep.GetToken();
711                                 while (!modeletters.empty())
712                                 {
713                                         char mletter = *(modeletters.begin());
714                                         modestack.Push(mletter,sep.GetToken());
715                                         modeletters.erase(modeletters.begin());
716                                 }
717                         }
718                 }
719
720                 while (modestack.GetStackedLine(stackresult))
721                 {
722                         stackresult.push_front(ConvToStr(c->age));
723                         stackresult.push_front(c->name);
724                         Utils->DoOneToMany(Instance->Config->ServerName, "FMODE", stackresult);
725                         stackresult.erase(stackresult.begin() + 1);
726                         for (size_t z = 0; z < stackresult.size(); z++)
727                         {
728                                 y[z] = stackresult[z].c_str();
729                         }
730                         userrec* n = new userrec(Instance);
731                         n->SetFd(FD_MAGIC_NUMBER);
732                         Instance->SendMode(y, stackresult.size(), n);
733                         delete n;
734                 }
735         }
736         return true;
737 }
738
739 bool TreeSocket::RemoteServer(const std::string &prefix, std::deque<std::string> &params)
740 {
741         if (params.size() < 4)
742                 return false;
743         std::string servername = params[0];
744         std::string password = params[1];
745         // hopcount is not used for a remote server, we calculate this ourselves
746         std::string description = params[3];
747         TreeServer* ParentOfThis = Utils->FindServer(prefix);
748         if (!ParentOfThis)
749         {
750                 this->WriteLine("ERROR :Protocol error - Introduced remote server from unknown server "+prefix);
751                 return false;
752         }
753         TreeServer* CheckDupe = Utils->FindServer(servername);
754         if (CheckDupe)
755         {
756                 this->WriteLine("ERROR :Server "+servername+" already exists!");
757                 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+servername+"\2 denied, already exists");
758                 return false;
759         }
760         TreeServer* Node = new TreeServer(this->Utils,this->Instance,servername,description,ParentOfThis,NULL);
761         ParentOfThis->AddChild(Node);
762         params[3] = ":" + params[3];
763         Utils->DoOneToAllButSender(prefix,"SERVER",params,prefix);
764         this->Instance->SNO->WriteToSnoMask('l',"Server \002"+prefix+"\002 introduced server \002"+servername+"\002 ("+description+")");
765         return true;
766 }
767
768 bool TreeSocket::Outbound_Reply_Server(std::deque<std::string> &params)
769 {
770         if (params.size() < 4)
771                 return false;
772
773         irc::string servername = params[0].c_str();
774         std::string sname = params[0];
775         std::string password = params[1];
776         int hops = atoi(params[2].c_str());
777
778         if (hops)
779         {
780                 this->WriteLine("ERROR :Server too far away for authentication");
781                 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");
782                 return false;
783         }
784         std::string description = params[3];
785         for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
786         {
787                 if ((x->Name == servername) && (x->RecvPass == password))
788                 {
789                         TreeServer* CheckDupe = Utils->FindServer(sname);
790                         if (CheckDupe)
791                         {
792                                 this->WriteLine("ERROR :Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");
793                                 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());
794                                 return false;
795                         }
796                         // Begin the sync here. this kickstarts the
797                         // other side, waiting in WAIT_AUTH_2 state,
798                         // into starting their burst, as it shows
799                         // that we're happy.
800                         this->LinkState = CONNECTED;
801                         // we should add the details of this server now
802                         // to the servers tree, as a child of the root
803                         // node.
804                         TreeServer* Node = new TreeServer(this->Utils,this->Instance,sname,description,Utils->TreeRoot,this);
805                         Utils->TreeRoot->AddChild(Node);
806                         params[3] = ":" + params[3];
807                         Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,sname);
808                         this->bursting = true;
809                         this->DoBurst(Node);
810                         return true;
811                 }
812         }
813         this->WriteLine("ERROR :Invalid credentials");
814         this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials");
815         return false;
816 }
817
818 bool TreeSocket::Inbound_Server(std::deque<std::string> &params)
819 {
820         if (params.size() < 4)
821                 return false;
822         irc::string servername = params[0].c_str();
823         std::string sname = params[0];
824         std::string password = params[1];
825         int hops = atoi(params[2].c_str());
826
827         if (hops)
828         {
829                 this->WriteLine("ERROR :Server too far away for authentication");
830                 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server is too far away for authentication");
831                 return false;
832         }
833         std::string description = params[3];
834         for (std::vector<Link>::iterator x = Utils->LinkBlocks.begin(); x < Utils->LinkBlocks.end(); x++)
835         {
836                 if ((x->Name == servername) && (x->RecvPass == password))
837                 {
838                         TreeServer* CheckDupe = Utils->FindServer(sname);
839                         if (CheckDupe)
840                         {
841                                 this->WriteLine("ERROR :Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");
842                                 this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());
843                                 return false;
844                         }
845                         this->Instance->SNO->WriteToSnoMask('l',"Verified incoming server connection from \002"+sname+"\002["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] ("+description+")");
846                         if (this->Hook)
847                         {
848                                 std::string name = InspSocketNameRequest((Module*)Utils->Creator, this->Hook).Send();
849                                 this->Instance->SNO->WriteToSnoMask('l',"Connection from \2"+sname+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+name+"\2");
850                         }
851
852                         this->InboundServerName = sname;
853                         this->InboundDescription = description;
854                         // this is good. Send our details: Our server name and description and hopcount of 0,
855                         // along with the sendpass from this block.
856                         this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+x->SendPass+" 0 :"+this->Instance->Config->ServerDesc);
857                         // move to the next state, we are now waiting for THEM.
858                         this->LinkState = WAIT_AUTH_2;
859                         return true;
860                 }
861         }
862         this->WriteLine("ERROR :Invalid credentials");
863         this->Instance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, invalid link credentials");
864         return false;
865 }
866
867 void TreeSocket::Split(const std::string &line, std::deque<std::string> &n)
868 {
869         n.clear();
870         irc::tokenstream tokens(line);
871         std::string param;
872         while ((param = tokens.GetToken()) != "")
873                 n.push_back(param);
874         return;
875 }
876
877 bool TreeSocket::ProcessLine(std::string &line)
878 {
879         std::deque<std::string> params;
880         irc::string command;
881         std::string prefix;
882
883         line = line.substr(0, line.find_first_of("\r\n"));
884
885         if (line.empty())
886                 return true;
887
888         Instance->Log(DEBUG, "<- %s", line.c_str());
889
890         this->Split(line.c_str(),params);
891
892         if ((params[0][0] == ':') && (params.size() > 1))
893         {
894                 prefix = params[0].substr(1);
895                 params.pop_front();
896         }
897         command = params[0].c_str();
898         params.pop_front();
899         switch (this->LinkState)
900         {
901                 TreeServer* Node;
902
903                 case WAIT_AUTH_1:
904                         // Waiting for SERVER command from remote server. Server initiating
905                         // the connection sends the first SERVER command, listening server
906                         // replies with theirs if its happy, then if the initiator is happy,
907                         // it starts to send its net sync, which starts the merge, otherwise
908                         // it sends an ERROR.
909                         if (command == "PASS")
910                         {
911                                 /* Silently ignored */
912                         }
913                         else if (command == "SERVER")
914                         {
915                                 return this->Inbound_Server(params);
916                         }
917                         else if (command == "ERROR")
918                         {
919                                 return this->Error(params);
920                         }
921                         else if (command == "USER")
922                         {
923                                 this->WriteLine("ERROR :Client connections to this port are prohibited.");
924                                 return false;
925                         }
926                         else if (command == "CAPAB")
927                         {
928                                 return this->Capab(params);
929                         }
930                         else if ((command == "U") || (command == "S"))
931                         {
932                                 this->WriteLine("ERROR :Cannot use the old-style mesh linking protocol with m_spanningtree.so!");
933                                 return false;
934                         }
935                         else
936                         {
937                                 std::string error("ERROR :Invalid command in negotiation phase: ");
938                                 error.append(command.c_str());
939                                 this->WriteLine(error);
940                                 return false;
941                         }
942                 break;
943                 case WAIT_AUTH_2:
944                         // Waiting for start of other side's netmerge to say they liked our
945                         // password.
946                         if (command == "SERVER")
947                         {
948                                 // cant do this, they sent it to us in the WAIT_AUTH_1 state!
949                                 // silently ignore.
950                                 return true;
951                         }
952                         else if ((command == "U") || (command == "S"))
953                         {
954                                 this->WriteLine("ERROR :Cannot use the old-style mesh linking protocol with m_spanningtree.so!");
955                                 return false;
956                         }
957                         else if (command == "BURST")
958                         {
959                                 if (params.size() && Utils->EnableTimeSync)
960                                 {
961                                         /* If a time stamp is provided, apply synchronization */
962                                         bool force = false;
963                                         time_t them = atoi(params[0].c_str());
964                                         time_t us = Instance->Time(true);
965                                         int delta = them - us;
966                                         if ((params.size() == 2) && (params[1] == "FORCE"))
967                                                 force = true;
968                                         if ((delta < -600) || (delta > 600))
969                                         {
970                                                 this->Instance->SNO->WriteToSnoMask('l',"\2ERROR\2: Your clocks are out by %d seconds (this is more than ten minutes). Link aborted, \2PLEASE SYNC YOUR CLOCKS!\2",abs(delta));
971                                                 this->WriteLine("ERROR :Your clocks are out by "+ConvToStr(abs(delta))+" seconds (this is more than ten minutes). Link aborted, PLEASE SYNC YOUR CLOCKS!");
972                                                 return false;
973                                         }
974
975                                         if (force || (us > them))
976                                         {
977                                                 this->Instance->SetTimeDelta(them - us);
978                                                 // Send this new timestamp to any other servers
979                                                 Utils->DoOneToMany(Utils->TreeRoot->GetName(), "TIMESET", params);
980                                         }
981                                         else
982                                         {
983                                                 // Override the timestamp
984                                                 this->WriteLine(":" + Utils->TreeRoot->GetName() + " TIMESET " + ConvToStr(us));
985                                         }
986                                 }
987                                 this->LinkState = CONNECTED;
988                                 Node = new TreeServer(this->Utils,this->Instance,InboundServerName,InboundDescription,Utils->TreeRoot,this);
989                                 Utils->TreeRoot->AddChild(Node);
990                                 params.clear();
991                                 params.push_back(InboundServerName);
992                                 params.push_back("*");
993                                 params.push_back("1");
994                                 params.push_back(":"+InboundDescription);
995                                 Utils->DoOneToAllButSender(Utils->TreeRoot->GetName(),"SERVER",params,InboundServerName);
996                                 this->bursting = true;
997                                 this->DoBurst(Node);
998                         }
999                         else if (command == "ERROR")
1000                         {
1001                                 return this->Error(params);
1002                         }
1003                         else if (command == "CAPAB")
1004                         {
1005                                 return this->Capab(params);
1006                         }
1007
1008                 break;
1009                 case LISTENER:
1010                         this->WriteLine("ERROR :Internal error -- listening socket accepted its own descriptor!!!");
1011                         return false;
1012                 break;
1013                 case CONNECTING:
1014                         if (command == "SERVER")
1015                         {
1016                                 // another server we connected to, which was in WAIT_AUTH_1 state,
1017                                 // has just sent us their credentials. If we get this far, theyre
1018                                 // happy with OUR credentials, and they are now in WAIT_AUTH_2 state.
1019                                 // if we're happy with this, we should send our netburst which
1020                                 // kickstarts the merge.
1021                                 return this->Outbound_Reply_Server(params);
1022                         }
1023                         else if (command == "ERROR")
1024                         {
1025                                 return this->Error(params);
1026                         }
1027                 break;
1028                 case CONNECTED:
1029                         // This is the 'authenticated' state, when all passwords
1030                         // have been exchanged and anything past this point is taken
1031                         // as gospel.
1032
1033                         if (prefix != "")
1034                         {
1035                                 std::string direction = prefix;
1036                                 userrec* t = this->Instance->FindNick(prefix);
1037                                 if (t)
1038                                 {
1039                                         direction = t->server;
1040                                 }
1041                                 TreeServer* route_back_again = Utils->BestRouteTo(direction);
1042                                 if ((!route_back_again) || (route_back_again->GetSocket() != this))
1043                                 {
1044                                         if (route_back_again)
1045                                                 Instance->Log(DEBUG,"Protocol violation: Fake direction in command '%s' from connection '%s'",line.c_str(),this->GetName().c_str());
1046                                         return true;
1047                                 }
1048                                 /* Fix by brain:
1049                                  * When there is activity on the socket, reset the ping counter so
1050                                  * that we're not wasting bandwidth pinging an active server.
1051                                  */
1052                                 route_back_again->SetNextPingTime(time(NULL) + 60);
1053                                 route_back_again->SetPingFlag();
1054                         }
1055
1056                         if (command == "SVSMODE")
1057                         {
1058                                 /* Services expects us to implement
1059                                  * SVSMODE. In inspircd its the same as
1060                                  * MODE anyway.
1061                                  */
1062                                 command = "MODE";
1063                         }
1064                         std::string target = "";
1065                         /* Yes, know, this is a mess. Its reasonably fast though as we're
1066                          * working with std::string here.
1067                          */
1068                         if ((command == "NICK") && (params.size() > 1))
1069                         {
1070                                 return this->IntroduceClient(prefix,params);
1071                         }
1072                         else if (command == "FJOIN")
1073                         {
1074                                 return this->ForceJoin(prefix,params);
1075                         }
1076                         else if (command == "STATS")
1077                         {
1078                                 return this->Stats(prefix, params);
1079                         }
1080                         else if (command == "MOTD")
1081                         {
1082                                 return this->Motd(prefix, params);
1083                         }
1084                         else if (command == "ADMIN")
1085                         {
1086                                 return this->Admin(prefix, params);
1087                         }
1088                         else if (command == "SERVER")
1089                         {
1090                                 return this->RemoteServer(prefix,params);
1091                         }
1092                         else if (command == "ERROR")
1093                         {
1094                                 return this->Error(params);
1095                         }
1096                         else if (command == "OPERTYPE")
1097                         {
1098                                 return this->OperType(prefix,params);
1099                         }
1100                         else if (command == "FMODE")
1101                         {
1102                                 return this->ForceMode(prefix,params);
1103                         }
1104                         else if (command == "KILL")
1105                         {
1106                                 return this->RemoteKill(prefix,params);
1107                         }
1108                         else if (command == "FTOPIC")
1109                         {
1110                                 return this->ForceTopic(prefix,params);
1111                         }
1112                         else if (command == "REHASH")
1113                         {
1114                                 return this->RemoteRehash(prefix,params);
1115                         }
1116                         else if (command == "METADATA")
1117                         {
1118                                 return this->MetaData(prefix,params);
1119                         }
1120                         else if (command == "REMSTATUS")
1121                         {
1122                                 return this->RemoveStatus(prefix,params);
1123                         }
1124                         else if (command == "PING")
1125                         {
1126                                 /*
1127                                  * We just got a ping from a server that's bursting.
1128                                  * This can't be right, so set them to not bursting, and
1129                                  * apply their lines.
1130                                  */
1131                                 if (this->bursting)
1132                                 {
1133                                         this->bursting = false;
1134                                         Instance->XLines->apply_lines(Utils->lines_to_apply);
1135                                         Utils->lines_to_apply = 0;
1136                                 }
1137                                 if (prefix == "")
1138                                 {
1139                                         prefix = this->GetName();
1140                                 }
1141                                 return this->LocalPing(prefix,params);
1142                         }
1143                         else if (command == "PONG")
1144                         {
1145                                 /*
1146                                  * We just got a pong from a server that's bursting.
1147                                  * This can't be right, so set them to not bursting, and
1148                                  * apply their lines.
1149                                  */
1150                                 if (this->bursting)
1151                                 {
1152                                         this->bursting = false;
1153                                         Instance->XLines->apply_lines(Utils->lines_to_apply);
1154                                         Utils->lines_to_apply = 0;
1155                                 }
1156                                 if (prefix == "")
1157                                 {
1158                                         prefix = this->GetName();
1159                                 }
1160                                 return this->LocalPong(prefix,params);
1161                         }
1162                         else if (command == "VERSION")
1163                         {
1164                                 return this->ServerVersion(prefix,params);
1165                         }
1166                         else if (command == "FHOST")
1167                         {
1168                                 return this->ChangeHost(prefix,params);
1169                         }
1170                         else if (command == "FNAME")
1171                         {
1172                                 return this->ChangeName(prefix,params);
1173                         }
1174                         else if (command == "ADDLINE")
1175                         {
1176                                 return this->AddLine(prefix,params);
1177                         }
1178                         else if (command == "SVSNICK")
1179                         {
1180                                 if (prefix == "")
1181                                 {
1182                                         prefix = this->GetName();
1183                                 }
1184                                 return this->ForceNick(prefix,params);
1185                         }
1186                         else if (command == "RSQUIT")
1187                         {
1188                                 return this->RemoteSquit(prefix, params);
1189                         }
1190                         else if (command == "IDLE")
1191                         {
1192                                 return this->Whois(prefix,params);
1193                         }
1194                         else if (command == "PUSH")
1195                         {
1196                                 return this->Push(prefix,params);
1197                         }
1198                         else if (command == "TIMESET")
1199                         {
1200                                 return this->HandleSetTime(prefix, params);
1201                         }
1202                         else if (command == "TIME")
1203                         {
1204                                 return this->Time(prefix,params);
1205                         }
1206                         else if ((command == "KICK") && (Utils->IsServer(prefix)))
1207                         {
1208                                 std::string sourceserv = this->myhost;
1209                                 if (params.size() == 3)
1210                                 {
1211                                         userrec* user = this->Instance->FindNick(params[1]);
1212                                         chanrec* chan = this->Instance->FindChan(params[0]);
1213                                         if (user && chan)
1214                                         {
1215                                                 if (!chan->ServerKickUser(user, params[2].c_str(), false))
1216                                                         /* Yikes, the channels gone! */
1217                                                         delete chan;
1218                                         }
1219                                 }
1220                                 if (this->InboundServerName != "")
1221                                 {
1222                                         sourceserv = this->InboundServerName;
1223                                 }
1224                                 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
1225                         }
1226                         else if (command == "SVSJOIN")
1227                         {
1228                                 if (prefix == "")
1229                                 {
1230                                         prefix = this->GetName();
1231                                 }
1232                                 return this->ServiceJoin(prefix,params);
1233                         }
1234                         else if (command == "SQUIT")
1235                         {
1236                                 if (params.size() == 2)
1237                                 {
1238                                         this->Squit(Utils->FindServer(params[0]),params[1]);
1239                                 }
1240                                 return true;
1241                         }
1242                         else if (command == "OPERNOTICE")
1243                         {
1244                                 std::string sourceserv = this->myhost;
1245                                 if (this->InboundServerName != "")
1246                                         sourceserv = this->InboundServerName;
1247                                 if (params.size() >= 1)
1248                                         Instance->WriteOpers("*** From " + sourceserv + ": " + params[0]);
1249                                 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
1250                         }
1251                         else if (command == "MODENOTICE")
1252                         {
1253                                 std::string sourceserv = this->myhost;
1254                                 if (this->InboundServerName != "")
1255                                         sourceserv = this->InboundServerName;
1256                                 if (params.size() >= 2)
1257                                 {
1258                                         Instance->WriteMode(params[0].c_str(), WM_AND, "*** From %s: %s", sourceserv.c_str(), params[1].c_str());
1259                                 }
1260                                 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
1261                         }
1262                         else if (command == "SNONOTICE")
1263                         {
1264                                 std::string sourceserv = this->myhost;
1265                                 if (this->InboundServerName != "")
1266                                         sourceserv = this->InboundServerName;
1267                                 if (params.size() >= 2)
1268                                 {
1269                                         Instance->SNO->WriteToSnoMask(*(params[0].c_str()), "From " + sourceserv + ": "+ params[1]);
1270                                 }
1271                                 return Utils->DoOneToAllButSenderRaw(line, sourceserv, prefix, command, params);
1272                         }
1273                         else if (command == "ENDBURST")
1274                         {
1275                                 this->bursting = false;
1276                                 Instance->XLines->apply_lines(Utils->lines_to_apply);
1277                                 Utils->lines_to_apply = 0;
1278                                 std::string sourceserv = this->myhost;
1279                                 if (this->InboundServerName != "")
1280                                 {
1281                                         sourceserv = this->InboundServerName;
1282                                 }
1283                                 this->Instance->SNO->WriteToSnoMask('l',"Received end of netburst from \2%s\2",sourceserv.c_str());
1284
1285                                 Event rmode((char*)sourceserv.c_str(), (Module*)Utils->Creator, "new_server");
1286                                 rmode.Send(Instance);
1287
1288                                 return true;
1289                         }
1290                         else
1291                         {
1292                                 // not a special inter-server command.
1293                                 // Emulate the actual user doing the command,
1294                                 // this saves us having a huge ugly parser.
1295                                 userrec* who = this->Instance->FindNick(prefix);
1296                                 std::string sourceserv = this->myhost;
1297                                 if (this->InboundServerName != "")
1298                                 {
1299                                         sourceserv = this->InboundServerName;
1300                                 }
1301                                 if ((!who) && (command == "MODE"))
1302                                 {
1303                                         if (Utils->IsServer(prefix))
1304                                         {
1305                                                 const char* modelist[127];
1306                                                 for (size_t i = 0; i < params.size(); i++)
1307                                                         modelist[i] = params[i].c_str();
1308                                                 userrec* fake = new userrec(Instance);
1309                                                 fake->SetFd(FD_MAGIC_NUMBER);
1310                                                 this->Instance->SendMode(modelist, params.size(), fake);
1311
1312                                                 delete fake;
1313                                                 /* Hot potato! pass it on! */
1314                                                 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
1315                                         }
1316                                 }
1317                                 if (who)
1318                                 {
1319                                         if ((command == "NICK") && (params.size() > 0))
1320                                         {
1321                                                 /* On nick messages, check that the nick doesnt
1322                                                  * already exist here. If it does, kill their copy,
1323                                                  * and our copy.
1324                                                  */
1325                                                 userrec* x = this->Instance->FindNick(params[0]);
1326                                                 if ((x) && (x != who))
1327                                                 {
1328                                                         std::deque<std::string> p;
1329                                                         p.push_back(params[0]);
1330                                                         p.push_back("Nickname collision ("+prefix+" -> "+params[0]+")");
1331                                                         Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p);
1332                                                         p.clear();
1333                                                         p.push_back(prefix);
1334                                                         p.push_back("Nickname collision");
1335                                                         Utils->DoOneToMany(this->Instance->Config->ServerName,"KILL",p);
1336                                                         userrec::QuitUser(this->Instance,x,"Nickname collision ("+prefix+" -> "+params[0]+")");
1337                                                         userrec* y = this->Instance->FindNick(prefix);
1338                                                         if (y)
1339                                                         {
1340                                                                 userrec::QuitUser(this->Instance,y,"Nickname collision");
1341                                                         }
1342                                                         return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
1343                                                 }
1344                                         }
1345                                         // its a user
1346                                         target = who->server;
1347                                         const char* strparams[127];
1348                                         for (unsigned int q = 0; q < params.size(); q++)
1349                                         {
1350                                                 strparams[q] = params[q].c_str();
1351                                         }
1352                                         switch (this->Instance->CallCommandHandler(command.c_str(), strparams, params.size(), who))
1353                                         {
1354                                                 case CMD_INVALID:
1355                                                         this->WriteLine("ERROR :Unrecognised command '"+std::string(command.c_str())+"' -- possibly loaded mismatched modules");
1356                                                         return false;
1357                                                 break;
1358                                                 case CMD_FAILURE:
1359                                                         return true;
1360                                                 break;
1361                                                 default:
1362                                                         /* CMD_SUCCESS and CMD_USER_DELETED fall through here */
1363                                                 break;
1364                                         }
1365                                 }
1366                                 else
1367                                 {
1368                                         // its not a user. Its either a server, or somethings screwed up.
1369                                         if (Utils->IsServer(prefix))
1370                                                 target = this->Instance->Config->ServerName;
1371                                         else
1372                                                 return true;
1373                                 }
1374                                 return Utils->DoOneToAllButSenderRaw(line,sourceserv,prefix,command,params);
1375
1376                         }
1377                         return true;
1378                 break;
1379         }
1380         return true;
1381 }
1382
1383 std::string TreeSocket::GetName()
1384 {
1385         std::string sourceserv = this->myhost;
1386         if (this->InboundServerName != "")
1387         {
1388                 sourceserv = this->InboundServerName;
1389         }
1390         return sourceserv;
1391 }
1392
1393 void TreeSocket::OnTimeout()
1394 {
1395         if (this->LinkState == CONNECTING)
1396         {
1397                 this->Instance->SNO->WriteToSnoMask('l',"CONNECT: Connection to \002"+myhost+"\002 timed out.");
1398                 Link* MyLink = Utils->FindLink(myhost);
1399                 if (MyLink)
1400                         Utils->DoFailOver(MyLink);
1401         }
1402 }
1403
1404 void TreeSocket::OnClose()
1405 {
1406         // Connection closed.
1407         // If the connection is fully up (state CONNECTED)
1408         // then propogate a netsplit to all peers.
1409         std::string quitserver = this->myhost;
1410         if (this->InboundServerName != "")
1411         {
1412                 quitserver = this->InboundServerName;
1413         }
1414         TreeServer* s = Utils->FindServer(quitserver);
1415         if (s)
1416         {
1417                 Squit(s,"Remote host closed the connection");
1418         }
1419
1420         if (quitserver != "")
1421                 this->Instance->SNO->WriteToSnoMask('l',"Connection to '\2%s\2' failed.",quitserver.c_str());
1422 }
1423
1424 int TreeSocket::OnIncomingConnection(int newsock, char* ip)
1425 {
1426         /* To prevent anyone from attempting to flood opers/DDoS by connecting to the server port,
1427          * or discovering if this port is the server port, we don't allow connections from any
1428          * IPs for which we don't have a link block.
1429          */
1430         bool found = false;
1431
1432         found = (std::find(Utils->ValidIPs.begin(), Utils->ValidIPs.end(), ip) != Utils->ValidIPs.end());
1433         if (!found)
1434         {
1435                 for (vector<std::string>::iterator i = Utils->ValidIPs.begin(); i != Utils->ValidIPs.end(); i++)
1436                         if (irc::sockets::MatchCIDR(ip, (*i).c_str()))
1437                                 found = true;
1438
1439                 if (!found)
1440                 {
1441                         this->Instance->SNO->WriteToSnoMask('l',"Server connection from %s denied (no link blocks with that IP address)", ip);
1442                         close(newsock);
1443                         return false;
1444                 }
1445         }
1446
1447         TreeSocket* s = new TreeSocket(this->Utils, this->Instance, newsock, ip, this->Hook);
1448         s = s; /* Whinge whinge whinge, thats all GCC ever does. */
1449         return true;
1450 }