]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/commands.cpp
b7baa9b9f3639dca7f780d3c276867aa3cc4f5f2
[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
36 #ifdef GCC3
37 #define nspace __gnu_cxx
38 #else
39 #define nspace std
40 #endif
41
42 using namespace std;
43
44 extern int MODCOUNT;
45 extern vector<Module*> modules;
46 extern vector<ircd_module*> factory;
47
48 extern int LogLevel;
49 extern char ServerName[MAXBUF];
50 extern char Network[MAXBUF];
51 extern char ServerDesc[MAXBUF];
52 extern char AdminName[MAXBUF];
53 extern char AdminEmail[MAXBUF];
54 extern char AdminNick[MAXBUF];
55 extern char diepass[MAXBUF];
56 extern char restartpass[MAXBUF];
57 extern char motd[MAXBUF];
58 extern char rules[MAXBUF];
59 extern char list[MAXBUF];
60 extern char PrefixQuit[MAXBUF];
61 extern char DieValue[MAXBUF];
62
63 extern int debugging;
64 extern int WHOWAS_STALE;
65 extern int WHOWAS_MAX;
66 extern int DieDelay;
67 extern time_t startup_time;
68 extern int NetBufferSize;
69 extern time_t nb_start;
70
71 extern std::vector<int> fd_reap;
72 extern std::vector<std::string> module_names;
73
74 extern char bannerBuffer[MAXBUF];
75 extern int boundPortCount;
76 extern int portCount;
77 extern int UDPportCount;
78 extern int ports[MAXSOCKS];
79 extern int defaultRoute;
80
81 extern std::vector<long> auth_cookies;
82 extern std::stringstream config_f;
83
84 extern serverrec* me[32];
85
86 extern FILE *log_file;
87
88 namespace nspace
89 {
90         template<> struct nspace::hash<in_addr>
91         {
92                 size_t operator()(const struct in_addr &a) const
93                 {
94                         size_t q;
95                         memcpy(&q,&a,sizeof(size_t));
96                         return q;
97                 }
98         };
99
100         template<> struct nspace::hash<string>
101         {
102                 size_t operator()(const string &s) const
103                 {
104                         char a[MAXBUF];
105                         static struct hash<const char *> strhash;
106                         strcpy(a,s.c_str());
107                         strlower(a);
108                         return strhash(a);
109                 }
110         };
111 }       
112
113
114 struct StrHashComp
115 {
116
117         bool operator()(const string& s1, const string& s2) const
118         {
119                 char a[MAXBUF],b[MAXBUF];
120                 strcpy(a,s1.c_str());
121                 strcpy(b,s2.c_str());
122                 return (strcasecmp(a,b) == 0);
123         }
124
125 };
126
127 struct InAddr_HashComp
128 {
129
130         bool operator()(const in_addr &s1, const in_addr &s2) const
131         {
132                 size_t q;
133                 size_t p;
134                 
135                 memcpy(&q,&s1,sizeof(size_t));
136                 memcpy(&p,&s2,sizeof(size_t));
137                 
138                 return (q == p);
139         }
140
141 };
142
143
144 typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, StrHashComp> user_hash;
145 typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, StrHashComp> chan_hash;
146 typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, InAddr_HashComp> address_cache;
147 typedef std::deque<command_t> command_table;
148
149
150 extern user_hash clientlist;
151 extern chan_hash chanlist;
152 extern user_hash whowas;
153 extern command_table cmdlist;
154 extern file_cache MOTD;
155 extern file_cache RULES;
156 extern address_cache IP;
157
158
159 void handle_join(char **parameters, int pcnt, userrec *user)
160 {
161         chanrec* Ptr;
162         int i = 0;
163         
164         if (loop_call(handle_join,parameters,pcnt,user,0,0,1))
165                 return;
166         if (parameters[0][0] == '#')
167         {
168                 Ptr = add_channel(user,parameters[0],parameters[1],false);
169         }
170 }
171
172
173 void handle_part(char **parameters, int pcnt, userrec *user)
174 {
175         chanrec* Ptr;
176
177         if (pcnt > 1)
178         {
179                 if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-2,0))
180                         return;
181                 del_channel(user,parameters[0],parameters[1],false);
182         }
183         else
184         {
185                 if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-1,0))
186                         return;
187                 del_channel(user,parameters[0],NULL,false);
188         }
189 }
190
191 void handle_kick(char **parameters, int pcnt, userrec *user)
192 {
193         chanrec* Ptr = FindChan(parameters[0]);
194         userrec* u   = Find(parameters[1]);
195
196         if ((!u) || (!Ptr))
197         {
198                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
199                 return;
200         }
201         
202         if (!has_channel(u,Ptr))
203         {
204                 WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, parameters[0]);
205                 return;
206         }
207
208         char reason[MAXBUF];
209         
210         if (pcnt > 2)
211         {
212                 strncpy(reason,parameters[2],MAXBUF);
213                 if (strlen(reason)>MAXKICK)
214                 {
215                         reason[MAXKICK-1] = '\0';
216                 }
217
218                 kick_channel(user,u,Ptr,reason);
219         }
220         else
221         {
222                 strcpy(reason,user->nick);
223                 kick_channel(user,u,Ptr,reason);
224         }
225         
226         // this must be propogated so that channel membership is kept in step network-wide
227         
228         char buffer[MAXBUF];
229         snprintf(buffer,MAXBUF,"k %s %s %s :%s",user->nick,u->nick,Ptr->name,reason);
230         NetSendToAll(buffer);
231 }
232
233
234 void handle_die(char **parameters, int pcnt, userrec *user)
235 {
236         log(DEBUG,"die: %s",user->nick);
237         if (!strcmp(parameters[0],diepass))
238         {
239                 WriteOpers("*** DIE command from %s!%s@%s, terminating...",user->nick,user->ident,user->host);
240                 sleep(DieDelay);
241                 Exit(ERROR);
242         }
243         else
244         {
245                 WriteOpers("*** Failed DIE Command from %s!%s@%s.",user->nick,user->ident,user->host);
246         }
247 }
248
249 void handle_restart(char **parameters, int pcnt, userrec *user)
250 {
251         log(DEBUG,"restart: %s",user->nick);
252         if (!strcmp(parameters[0],restartpass))
253         {
254                 WriteOpers("*** RESTART command from %s!%s@%s, Pretending to restart till this is finished :D",user->nick,user->ident,user->host);
255                 sleep(DieDelay);
256                 Exit(ERROR);
257                 /* Will finish this later when i can be arsed :) */
258         }
259         else
260         {
261                 WriteOpers("*** Failed RESTART Command from %s!%s@%s.",user->nick,user->ident,user->host);
262         }
263 }
264
265 void handle_kill(char **parameters, int pcnt, userrec *user)
266 {
267         userrec *u = Find(parameters[0]);
268         char killreason[MAXBUF];
269         
270         log(DEBUG,"kill: %s %s",parameters[0],parameters[1]);
271         if (u)
272         {
273                 if (strcmp(ServerName,u->server))
274                 {
275                         // remote kill
276                         WriteOpers("*** Remote kill by %s: %s!%s@%s (%s)",user->nick,u->nick,u->ident,u->host,parameters[1]);
277                         sprintf(killreason,"[%s] Killed (%s (%s))",ServerName,user->nick,parameters[1]);
278                         WriteCommonExcept(u,"QUIT :%s",killreason);
279                         // K token must go to ALL servers!!!
280                         char buffer[MAXBUF];
281                         snprintf(buffer,MAXBUF,"K %s %s :%s",user->nick,u->nick,killreason);
282                         NetSendToAll(buffer);
283                         
284                         user_hash::iterator iter = clientlist.find(u->nick);
285                         if (iter != clientlist.end())
286                         {
287                                 log(DEBUG,"deleting user hash value %d",iter->second);
288                                 if ((iter->second) && (user->registered == 7)) {
289                                         delete iter->second;
290                                         }
291                         clientlist.erase(iter);
292                         }
293                         purge_empty_chans();
294                 }
295                 else
296                 {
297                         // local kill
298                         WriteTo(user, u, "KILL %s :%s!%s!%s (%s)", u->nick, ServerName,user->dhost,user->nick,parameters[1]);
299                         WriteOpers("*** Local Kill by %s: %s!%s@%s (%s)",user->nick,u->nick,u->ident,u->host,parameters[1]);
300                         sprintf(killreason,"Killed (%s (%s))",user->nick,parameters[1]);
301                         kill_link(u,killreason);
302                 }
303         }
304         else
305         {
306                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
307         }
308 }
309
310 void handle_summon(char **parameters, int pcnt, userrec *user)
311 {
312         WriteServ(user->fd,"445 %s :SUMMON has been disabled (depreciated command)",user->nick);
313 }
314
315 void handle_users(char **parameters, int pcnt, userrec *user)
316 {
317         WriteServ(user->fd,"445 %s :USERS has been disabled (depreciated command)",user->nick);
318 }
319
320 void handle_pass(char **parameters, int pcnt, userrec *user)
321 {
322         // Check to make sure they havnt registered -- Fix by FCS
323         if (user->registered == 7)
324         {
325                 WriteServ(user->fd,"462 %s :You may not reregister",user->nick);
326                 return;
327         }
328         if (!strcasecmp(parameters[0],Passwd(user)))
329         {
330                 user->haspassed = true;
331         }
332 }
333
334 void handle_invite(char **parameters, int pcnt, userrec *user)
335 {
336         userrec* u = Find(parameters[0]);
337         chanrec* c = FindChan(parameters[1]);
338
339         if ((!c) || (!u))
340         {
341                 if (!c)
342                 {
343                         WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[1]);
344                 }
345                 else
346                 {
347                         if (c->inviteonly)
348                         {
349                                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
350                         }
351                 }
352
353                 return;
354         }
355
356         if (c->inviteonly)
357         {
358                 if (cstatus(user,c) < STATUS_HOP)
359                 {
360                         WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, c->name);
361                         return;
362                 }
363         }
364         if (has_channel(u,c))
365         {
366                 WriteServ(user->fd,"443 %s %s %s :Is already on channel %s",user->nick,u->nick,c->name,c->name);
367                 return;
368         }
369         if (!has_channel(user,c))
370         {
371                 WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, c->name);
372                 return;
373         }
374         u->InviteTo(c->name);
375         WriteFrom(u->fd,user,"INVITE %s :%s",u->nick,c->name);
376         WriteServ(user->fd,"341 %s %s %s",user->nick,u->nick,c->name);
377         
378         // i token must go to ALL servers!!!
379         char buffer[MAXBUF];
380         snprintf(buffer,MAXBUF,"i %s %s %s",u->nick,user->nick,c->name);
381         NetSendToAll(buffer);
382 }
383
384 void handle_topic(char **parameters, int pcnt, userrec *user)
385 {
386         chanrec* Ptr;
387
388         if (pcnt == 1)
389         {
390                 if (strlen(parameters[0]) <= CHANMAX)
391                 {
392                         Ptr = FindChan(parameters[0]);
393                         if (Ptr)
394                         {
395                                 if (Ptr->topicset)
396                                 {
397                                         WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
398                                         WriteServ(user->fd,"333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset);
399                                 }
400                                 else
401                                 {
402                                         WriteServ(user->fd,"331 %s %s :No topic is set.", user->nick, Ptr->name);
403                                 }
404                         }
405                         else
406                         {
407                                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
408                         }
409                 }
410                 return;
411         }
412         else if (pcnt>1)
413         {
414                 if (strlen(parameters[0]) <= CHANMAX)
415                 {
416                         Ptr = FindChan(parameters[0]);
417                         if (Ptr)
418                         {
419                                 if ((Ptr->topiclock) && (cstatus(user,Ptr)<STATUS_HOP))
420                                 {
421                                         WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel", user->nick, Ptr->name);
422                                         return;
423                                 }
424                                 
425                                 char topic[MAXBUF];
426                                 strncpy(topic,parameters[1],MAXBUF);
427                                 if (strlen(topic)>MAXTOPIC)
428                                 {
429                                         topic[MAXTOPIC-1] = '\0';
430                                 }
431                                         
432                                 strcpy(Ptr->topic,topic);
433                                 strcpy(Ptr->setby,user->nick);
434                                 Ptr->topicset = time(NULL);
435                                 WriteChannel(Ptr,user,"TOPIC %s :%s",Ptr->name, Ptr->topic);
436
437                                 // t token must go to ALL servers!!!
438                                 char buffer[MAXBUF];
439                                 snprintf(buffer,MAXBUF,"t %s %s :%s",user->nick,Ptr->name,topic);
440                                 NetSendToAll(buffer);
441                         }
442                         else
443                         {
444                                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
445                         }
446                 }
447         }
448 }
449
450 void handle_names(char **parameters, int pcnt, userrec *user)
451 {
452         chanrec* c;
453
454         if (loop_call(handle_names,parameters,pcnt,user,0,pcnt-1,0))
455                 return;
456         c = FindChan(parameters[0]);
457         if (c)
458         {
459                 /*WriteServ(user->fd,"353 %s = %s :%s", user->nick, c->name,*/
460                 userlist(user,c);
461                 WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, c->name);
462         }
463         else
464         {
465                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
466         }
467 }
468
469 void handle_privmsg(char **parameters, int pcnt, userrec *user)
470 {
471         userrec *dest;
472         chanrec *chan;
473
474         user->idle_lastmsg = time(NULL);
475         
476         if (loop_call(handle_privmsg,parameters,pcnt,user,0,pcnt-2,0))
477                 return;
478         if (parameters[0][0] == '#')
479         {
480                 chan = FindChan(parameters[0]);
481                 if (chan)
482                 {
483                         if ((chan->noexternal) && (!has_channel(user,chan)))
484                         {
485                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
486                                 return;
487                         }
488                         if ((chan->moderated) && (cstatus(user,chan)<STATUS_VOICE))
489                         {
490                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
491                                 return;
492                         }
493                         
494                         int MOD_RESULT = 0;
495
496                         FOREACH_RESULT(OnUserPreMessage(user,chan,TYPE_CHANNEL,std::string(parameters[1])));
497                         if (MOD_RESULT) {
498                                 return;
499                         }
500                         
501                         ChanExceptSender(chan, user, "PRIVMSG %s :%s", chan->name, parameters[1]);
502                         
503                         // if any users of this channel are on remote servers, broadcast the packet
504                         char buffer[MAXBUF];
505                         snprintf(buffer,MAXBUF,"P %s %s :%s",user->nick,chan->name,parameters[1]);
506                         NetSendToCommon(user,buffer);
507                 }
508                 else
509                 {
510                         /* no such nick/channel */
511                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
512                 }
513                 return;
514         }
515         
516         dest = Find(parameters[0]);
517         if (dest)
518         {
519                 if (strcmp(dest->awaymsg,""))
520                 {
521                         /* auto respond with aweh msg */
522                         WriteServ(user->fd,"301 %s %s :%s",user->nick,dest->nick,dest->awaymsg);
523                 }
524
525                 int MOD_RESULT = 0;
526                 
527                 FOREACH_RESULT(OnUserPreMessage(user,dest,TYPE_USER,std::string(parameters[1])));
528                 if (MOD_RESULT) {
529                         return;
530                 }
531
532
533
534                 if (!strcmp(dest->server,user->server))
535                 {
536                         // direct write, same server
537                         WriteTo(user, dest, "PRIVMSG %s :%s", dest->nick, parameters[1]);
538                 }
539                 else
540                 {
541                         char buffer[MAXBUF];
542                         snprintf(buffer,MAXBUF,"P %s %s :%s",user->nick,dest->nick,parameters[1]);
543                         NetSendToOne(dest->server,buffer);
544                 }
545         }
546         else
547         {
548                 /* no such nick/channel */
549                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
550         }
551 }
552
553 void handle_notice(char **parameters, int pcnt, userrec *user)
554 {
555         userrec *dest;
556         chanrec *chan;
557
558         user->idle_lastmsg = time(NULL);
559         
560         if (loop_call(handle_notice,parameters,pcnt,user,0,pcnt-2,0))
561                 return;
562         if (parameters[0][0] == '#')
563         {
564                 chan = FindChan(parameters[0]);
565                 if (chan)
566                 {
567                         if ((chan->noexternal) && (!has_channel(user,chan)))
568                         {
569                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name);
570                                 return;
571                         }
572                         if ((chan->moderated) && (cstatus(user,chan)<STATUS_VOICE))
573                         {
574                                 WriteServ(user->fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name);
575                                 return;
576                         }
577
578                         int MOD_RESULT = 0;
579                 
580                         FOREACH_RESULT(OnUserPreNotice(user,chan,TYPE_CHANNEL,std::string(parameters[1])));
581                         if (MOD_RESULT) {
582                                 return;
583                         }
584
585                         ChanExceptSender(chan, user, "NOTICE %s :%s", chan->name, parameters[1]);
586
587                         // if any users of this channel are on remote servers, broadcast the packet
588                         char buffer[MAXBUF];
589                         snprintf(buffer,MAXBUF,"V %s %s :%s",user->nick,chan->name,parameters[1]);
590                         NetSendToCommon(user,buffer);
591                 }
592                 else
593                 {
594                         /* no such nick/channel */
595                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
596                 }
597                 return;
598         }
599         
600         dest = Find(parameters[0]);
601         if (dest)
602         {
603                 int MOD_RESULT = 0;
604                 
605                 FOREACH_RESULT(OnUserPreNotice(user,dest,TYPE_USER,std::string(parameters[1])));
606                 if (MOD_RESULT) {
607                         return;
608                 }
609
610                 if (!strcmp(dest->server,user->server))
611                 {
612                         // direct write, same server
613                         WriteTo(user, dest, "NOTICE %s :%s", dest->nick, parameters[1]);
614                 }
615                 else
616                 {
617                         char buffer[MAXBUF];
618                         snprintf(buffer,MAXBUF,"V %s %s :%s",user->nick,dest->nick,parameters[1]);
619                         NetSendToOne(dest->server,buffer);
620                 }
621         }
622         else
623         {
624                 /* no such nick/channel */
625                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
626         }
627 }
628
629
630 void handle_info(char **parameters, int pcnt, userrec *user)
631 {
632         WriteServ(user->fd,"371 %s :The Inspire IRCd Project Has been brought to you by the following people..",user->nick);
633         WriteServ(user->fd,"371 %s :Craig Edwards, Craig McLure, and Others..",user->nick);
634         WriteServ(user->fd,"371 %s :Will finish this later when i can be arsed :p",user->nick);
635         FOREACH_MOD OnInfo(user);
636         WriteServ(user->fd,"374 %s :End of /INFO list",user->nick);
637 }
638
639 void handle_time(char **parameters, int pcnt, userrec *user)
640 {
641         time_t rawtime;
642         struct tm * timeinfo;
643
644         time ( &rawtime );
645         timeinfo = localtime ( &rawtime );
646         WriteServ(user->fd,"391 %s %s :%s",user->nick,ServerName, asctime (timeinfo) );
647   
648 }
649
650 void handle_whois(char **parameters, int pcnt, userrec *user)
651 {
652         userrec *dest;
653         char *t;
654
655         if (loop_call(handle_whois,parameters,pcnt,user,0,pcnt-1,0))
656                 return;
657         dest = Find(parameters[0]);
658         if (dest)
659         {
660                 // bug found by phidjit - were able to whois an incomplete connection if it had sent a NICK or USER
661                 if (dest->registered == 7)
662                 {
663                         WriteServ(user->fd,"311 %s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname);
664                         if ((user == dest) || (strchr(user->modes,'o')))
665                         {
666                                 WriteServ(user->fd,"378 %s %s :is connecting from *@%s",user->nick, dest->nick, dest->host);
667                         }
668                         if (strcmp(chlist(dest),""))
669                         {
670                                 WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, chlist(dest));
671                         }
672                         WriteServ(user->fd,"312 %s %s %s :%s",user->nick, dest->nick, dest->server, GetServerDescription(dest->server).c_str());
673                         if (strcmp(dest->awaymsg,""))
674                         {
675                                 WriteServ(user->fd,"301 %s %s :%s",user->nick, dest->nick, dest->awaymsg);
676                         }
677                         if (strchr(dest->modes,'o'))
678                         {
679                                 WriteServ(user->fd,"313 %s %s :is an IRC operator",user->nick, dest->nick);
680                         }
681                         FOREACH_MOD OnWhois(user,dest);
682                         if (!strcasecmp(user->server,dest->server))
683                         {
684                                 // idle time and signon line can only be sent if youre on the same server (according to RFC)
685                                 WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, abs((dest->idle_lastmsg)-time(NULL)), dest->signon);
686                         }
687                         
688                         WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, dest->nick);
689                 }
690                 else
691                 {
692                         WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
693                 }
694         }
695         else
696         {
697                 /* no such nick/channel */
698                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
699         }
700 }
701
702 void handle_quit(char **parameters, int pcnt, userrec *user)
703 {
704         user_hash::iterator iter = clientlist.find(user->nick);
705         char* reason;
706
707         if (user->registered == 7)
708         {
709                 /* theres more to do here, but for now just close the socket */
710                 if (pcnt == 1)
711                 {
712                         if (parameters[0][0] == ':')
713                         {
714                                 *parameters[0]++;
715                         }
716                         reason = parameters[0];
717
718                         if (strlen(reason)>MAXQUIT)
719                         {
720                                 reason[MAXQUIT-1] = '\0';
721                         }
722
723                         Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,parameters[0]);
724                         WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,parameters[0]);
725                         WriteCommonExcept(user,"QUIT :%s%s",PrefixQuit,parameters[0]);
726
727                         char buffer[MAXBUF];
728                         snprintf(buffer,MAXBUF,"Q %s :%s%s",user->nick,PrefixQuit,parameters[0]);
729                         NetSendToAll(buffer);
730                 }
731                 else
732                 {
733                         Write(user->fd,"ERROR :Closing link (%s@%s) [QUIT]",user->ident,user->host);
734                         WriteOpers("*** Client exiting: %s!%s@%s [Client exited]",user->nick,user->ident,user->host);
735                         WriteCommonExcept(user,"QUIT :Client exited");
736
737                         char buffer[MAXBUF];
738                         snprintf(buffer,MAXBUF,"Q %s :Client exited",user->nick);
739                         NetSendToAll(buffer);
740                 }
741                 FOREACH_MOD OnUserQuit(user);
742                 AddWhoWas(user);
743         }
744
745         /* push the socket on a stack of sockets due to be closed at the next opportunity */
746         fd_reap.push_back(user->fd);
747         
748         if (iter != clientlist.end())
749         {
750                 clientlist.erase(iter);
751                 log(DEBUG,"deleting user hash value %d",iter->second);
752                 //if ((user) && (user->registered == 7)) {
753                         //delete user;
754                 //}
755         }
756
757         if (user->registered == 7) {
758                 purge_empty_chans();
759         }
760 }
761
762 void handle_who(char **parameters, int pcnt, userrec *user)
763 {
764         chanrec* Ptr = NULL;
765         
766         /* theres more to do here, but for now just close the socket */
767         if (pcnt == 1)
768         {
769                 if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")))
770                 {
771                         if (user->chans[0].channel)
772                         {
773                                 Ptr = user->chans[0].channel;
774                                 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
775                                 {
776                                         if ((common_channels(user,i->second)) && (isnick(i->second->nick)))
777                                         {
778                                                 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);
779                                         }
780                                 }
781                         }
782                         if (Ptr)
783                         {
784                                 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
785                         }
786                         else
787                         {
788                                 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, user->nick);
789                         }
790                         return;
791                 }
792                 if (parameters[0][0] == '#')
793                 {
794                         Ptr = FindChan(parameters[0]);
795                         if (Ptr)
796                         {
797                                 for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
798                                 {
799                                         if ((has_channel(i->second,Ptr)) && (isnick(i->second->nick)))
800                                         {
801                                                 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);
802                                         }
803                                 }
804                                 WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name);
805                         }
806                         else
807                         {
808                                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
809                         }
810                 }
811                 else
812                 {
813                         userrec* u = Find(parameters[0]);
814                         if (u)
815                         {
816                                 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);
817                         }
818                         WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, parameters[0]);
819                 }
820         }
821         if (pcnt == 2)
822         {
823                 if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")) && (!strcmp(parameters[1],"o")))
824                 {
825                         for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
826                         {
827                                 if ((common_channels(user,i->second)) && (isnick(i->second->nick)))
828                                 {
829                                         if (strchr(i->second->modes,'o'))
830                                         {
831                                                 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);
832                                         }
833                                 }
834                         }
835                         WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, user->nick);
836                         return;
837                 }
838         }
839 }
840
841 void handle_wallops(char **parameters, int pcnt, userrec *user)
842 {
843         WriteWallOps(user,false,"%s",parameters[0]);
844 }
845
846 void handle_list(char **parameters, int pcnt, userrec *user)
847 {
848         chanrec* Ptr;
849         
850         WriteServ(user->fd,"321 %s Channel :Users Name",user->nick);
851         for (chan_hash::const_iterator i = chanlist.begin(); i != chanlist.end(); i++)
852         {
853                 if ((!i->second->c_private) && (!i->second->secret))
854                 {
855                         WriteServ(user->fd,"322 %s %s %d :[+%s] %s",user->nick,i->second->name,usercount_i(i->second),chanmodes(i->second),i->second->topic);
856                 }
857         }
858         WriteServ(user->fd,"323 %s :End of channel list.",user->nick);
859 }
860
861
862 void handle_rehash(char **parameters, int pcnt, userrec *user)
863 {
864         WriteServ(user->fd,"382 %s %s :Rehashing",user->nick,CleanFilename(CONFIG_FILE));
865         ReadConfig();
866         FOREACH_MOD OnRehash();
867         WriteOpers("%s is rehashing config file %s",user->nick,CleanFilename(CONFIG_FILE));
868 }
869
870 void handle_lusers(char **parameters, int pcnt, userrec *user)
871 {
872         WriteServ(user->fd,"251 %s :There are %d users and %d invisible on %d servers",user->nick,usercnt()-usercount_invisible(),usercount_invisible(),servercount());
873         WriteServ(user->fd,"252 %s %d :operator(s) online",user->nick,usercount_opers());
874         WriteServ(user->fd,"253 %s %d :unknown connections",user->nick,usercount_unknown());
875         WriteServ(user->fd,"254 %s %d :channels formed",user->nick,chancount());
876         WriteServ(user->fd,"254 %s :I have %d clients and %d servers",user->nick,local_count(),count_servs());
877 }
878
879 void handle_admin(char **parameters, int pcnt, userrec *user)
880 {
881         WriteServ(user->fd,"256 %s :Administrative info for %s",user->nick,ServerName);
882         WriteServ(user->fd,"257 %s :Name     - %s",user->nick,AdminName);
883         WriteServ(user->fd,"258 %s :Nickname - %s",user->nick,AdminNick);
884         WriteServ(user->fd,"258 %s :E-Mail   - %s",user->nick,AdminEmail);
885 }
886
887 void handle_ping(char **parameters, int pcnt, userrec *user)
888 {
889         WriteServ(user->fd,"PONG %s :%s",ServerName,parameters[0]);
890 }
891
892 void handle_pong(char **parameters, int pcnt, userrec *user)
893 {
894         // set the user as alive so they survive to next ping
895         user->lastping = 1;
896 }
897
898 void handle_motd(char **parameters, int pcnt, userrec *user)
899 {
900         ShowMOTD(user);
901 }
902
903 void handle_rules(char **parameters, int pcnt, userrec *user)
904 {
905         ShowRULES(user);
906 }
907
908 void handle_user(char **parameters, int pcnt, userrec *user)
909 {
910         if (user->registered < 3)
911         {
912                 if (isident(parameters[0]) == 0) {
913                         // This kinda Sucks, According to the RFC thou, its either this,
914                         // or "You have already registered" :p -- Craig
915                         WriteServ(user->fd,"461 %s USER :Not enough parameters",user->nick);
916                 }
917                 else {
918                         WriteServ(user->fd,"NOTICE Auth :No ident response, ident prefixed with ~");
919                         strcpy(user->ident,"~"); /* we arent checking ident... but these days why bother anyway? */
920                         strncat(user->ident,parameters[0],IDENTMAX);
921                         strncpy(user->fullname,parameters[3],128);
922                         user->registered = (user->registered | 1);
923                 }
924         }
925         else
926         {
927                 WriteServ(user->fd,"462 %s :You may not reregister",user->nick);
928                 return;
929         }
930         /* parameters 2 and 3 are local and remote hosts, ignored when sent by client connection */
931         if (user->registered == 3)
932         {
933                 /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
934                 ConnectUser(user);
935         }
936 }
937
938 void handle_userhost(char **parameters, int pcnt, userrec *user)
939 {
940         char Return[MAXBUF],junk[MAXBUF];
941         sprintf(Return,"302 %s :",user->nick);
942         for (int i = 0; i < pcnt; i++)
943         {
944                 userrec *u = Find(parameters[i]);
945                 if (u)
946                 {
947                         if (strchr(u->modes,'o'))
948                         {
949                                 sprintf(junk,"%s*=+%s@%s ",u->nick,u->ident,u->host);
950                                 strcat(Return,junk);
951                         }
952                         else
953                         {
954                                 sprintf(junk,"%s=+%s@%s ",u->nick,u->ident,u->host);
955                                 strcat(Return,junk);
956                         }
957                 }
958         }
959         WriteServ(user->fd,Return);
960 }
961
962
963 void handle_ison(char **parameters, int pcnt, userrec *user)
964 {
965         char Return[MAXBUF];
966         sprintf(Return,"303 %s :",user->nick);
967         for (int i = 0; i < pcnt; i++)
968         {
969                 userrec *u = Find(parameters[i]);
970                 if (u)
971                 {
972                         strcat(Return,u->nick);
973                         strcat(Return," ");
974                 }
975         }
976         WriteServ(user->fd,Return);
977 }
978
979
980 void handle_away(char **parameters, int pcnt, userrec *user)
981 {
982         if (pcnt)
983         {
984                 strcpy(user->awaymsg,parameters[0]);
985                 WriteServ(user->fd,"306 %s :You have been marked as being away",user->nick);
986         }
987         else
988         {
989                 strcpy(user->awaymsg,"");
990                 WriteServ(user->fd,"305 %s :You are no longer marked as being away",user->nick);
991         }
992 }
993
994 void handle_whowas(char **parameters, int pcnt, userrec* user)
995 {
996         user_hash::iterator i = whowas.find(parameters[0]);
997
998         if (i == whowas.end())
999         {
1000                 WriteServ(user->fd,"406 %s %s :There was no such nickname",user->nick,parameters[0]);
1001                 WriteServ(user->fd,"369 %s %s :End of WHOWAS",user->nick,parameters[0]);
1002         }
1003         else
1004         {
1005                 time_t rawtime = i->second->signon;
1006                 tm *timeinfo;
1007                 char b[MAXBUF];
1008                 
1009                 timeinfo = localtime(&rawtime);
1010                 strcpy(b,asctime(timeinfo));
1011                 b[strlen(b)-1] = '\0';
1012                 
1013                 WriteServ(user->fd,"314 %s %s %s %s * :%s",user->nick,i->second->nick,i->second->ident,i->second->dhost,i->second->fullname);
1014                 WriteServ(user->fd,"312 %s %s %s :%s",user->nick,i->second->nick,i->second->server,b);
1015                 WriteServ(user->fd,"369 %s %s :End of WHOWAS",user->nick,parameters[0]);
1016         }
1017
1018 }
1019
1020 void handle_trace(char **parameters, int pcnt, userrec *user)
1021 {
1022         for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
1023         {
1024                 if (i->second)
1025                 {
1026                         if (isnick(i->second->nick))
1027                         {
1028                                 if (strchr(i->second->modes,'o'))
1029                                 {
1030                                         WriteServ(user->fd,"205 %s :Oper 0 %s",user->nick,i->second->nick);
1031                                 }
1032                                 else
1033                                 {
1034                                         WriteServ(user->fd,"204 %s :User 0 %s",user->nick,i->second->nick);
1035                                 }
1036                         }
1037                         else
1038                         {
1039                                 WriteServ(user->fd,"203 %s :???? 0 [%s]",user->nick,i->second->host);
1040                         }
1041                 }
1042         }
1043 }
1044
1045 void handle_modules(char **parameters, int pcnt, userrec *user)
1046 {
1047         for (int i = 0; i < module_names.size(); i++)
1048         {
1049                         Version V = modules[i]->GetVersion();
1050                         char modulename[MAXBUF];
1051                         strncpy(modulename,module_names[i].c_str(),256);
1052                         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));
1053         }
1054 }
1055
1056 void handle_stats(char **parameters, int pcnt, userrec *user)
1057 {
1058         if (pcnt != 1)
1059         {
1060                 return;
1061         }
1062         if (strlen(parameters[0])>1)
1063         {
1064                 /* make the stats query 1 character long */
1065                 parameters[0][1] = '\0';
1066         }
1067
1068         /* stats m (list number of times each command has been used, plus bytecount) */
1069         if (!strcasecmp(parameters[0],"m"))
1070         {
1071                 for (int i = 0; i < cmdlist.size(); i++)
1072                 {
1073                         if (cmdlist[i].handler_function)
1074                         {
1075                                 if (cmdlist[i].use_count)
1076                                 {
1077                                         /* RPL_STATSCOMMANDS */
1078                                         WriteServ(user->fd,"212 %s %s %d %d",user->nick,cmdlist[i].command,cmdlist[i].use_count,cmdlist[i].total_bytes);
1079                                 }
1080                         }
1081                 }
1082                         
1083         }
1084
1085         /* stats z (debug and memory info) */
1086         if (!strcasecmp(parameters[0],"z"))
1087         {
1088                 WriteServ(user->fd,"249 %s :Users(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,clientlist.size(),clientlist.size()*sizeof(userrec),clientlist.bucket_count());
1089                 WriteServ(user->fd,"249 %s :Channels(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,chanlist.size(),chanlist.size()*sizeof(chanrec),chanlist.bucket_count());
1090                 WriteServ(user->fd,"249 %s :Commands(VECTOR) %d (%d bytes)",user->nick,cmdlist.size(),cmdlist.size()*sizeof(command_t));
1091                 WriteServ(user->fd,"249 %s :MOTD(VECTOR) %d, RULES(VECTOR) %d",user->nick,MOTD.size(),RULES.size());
1092                 WriteServ(user->fd,"249 %s :address_cache(HASH_MAP) %d (%d buckets)",user->nick,IP.size(),IP.bucket_count());
1093                 WriteServ(user->fd,"249 %s :Modules(VECTOR) %d (%d)",user->nick,modules.size(),modules.size()*sizeof(Module));
1094                 WriteServ(user->fd,"249 %s :ClassFactories(VECTOR) %d (%d)",user->nick,factory.size(),factory.size()*sizeof(ircd_module));
1095                 WriteServ(user->fd,"249 %s :Ports(STATIC_ARRAY) %d",user->nick,boundPortCount);
1096         }
1097         
1098         /* stats o */
1099         if (!strcasecmp(parameters[0],"o"))
1100         {
1101                 for (int i = 0; i < ConfValueEnum("oper",&config_f); i++)
1102                 {
1103                         char LoginName[MAXBUF];
1104                         char HostName[MAXBUF];
1105                         char OperType[MAXBUF];
1106                         ConfValue("oper","name",i,LoginName,&config_f);
1107                         ConfValue("oper","host",i,HostName,&config_f);
1108                         ConfValue("oper","type",i,OperType,&config_f);
1109                         WriteServ(user->fd,"243 %s O %s * %s %s 0",user->nick,HostName,LoginName,OperType);
1110                 }
1111         }
1112         
1113         /* stats l (show user I/O stats) */
1114         if (!strcasecmp(parameters[0],"l"))
1115         {
1116                 WriteServ(user->fd,"211 %s :server:port nick bytes_in cmds_in bytes_out cmds_out",user->nick);
1117                 for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++)
1118                 {
1119                         if (isnick(i->second->nick))
1120                         {
1121                                 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);
1122                         }
1123                         else
1124                         {
1125                                 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);
1126                         }
1127                         
1128                 }
1129         }
1130         
1131         /* stats u (show server uptime) */
1132         if (!strcasecmp(parameters[0],"u"))
1133         {
1134                 time_t current_time = 0;
1135                 current_time = time(NULL);
1136                 time_t server_uptime = current_time - startup_time;
1137                 struct tm* stime;
1138                 stime = gmtime(&server_uptime);
1139                 /* i dont know who the hell would have an ircd running for over a year nonstop, but
1140                  * Craig suggested this, and it seemed a good idea so in it went */
1141                 if (stime->tm_year > 70)
1142                 {
1143                         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);
1144                 }
1145                 else
1146                 {
1147                         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);
1148                 }
1149         }
1150
1151         WriteServ(user->fd,"219 %s %s :End of /STATS report",user->nick,parameters[0]);
1152         WriteOpers("*** Notice: Stats '%s' requested by %s (%s@%s)",parameters[0],user->nick,user->ident,user->host);
1153         
1154 }
1155
1156 void handle_connect(char **parameters, int pcnt, userrec *user)
1157 {
1158         char Link_ServerName[1024];
1159         char Link_IPAddr[1024];
1160         char Link_Port[1024];
1161         char Link_Pass[1024];
1162         int LinkPort;
1163         bool found = false;
1164         
1165         for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
1166         {
1167                 if (!found)
1168                 {
1169                         ConfValue("link","name",i,Link_ServerName,&config_f);
1170                         ConfValue("link","ipaddr",i,Link_IPAddr,&config_f);
1171                         ConfValue("link","port",i,Link_Port,&config_f);
1172                         ConfValue("link","sendpass",i,Link_Pass,&config_f);
1173                         log(DEBUG,"(%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s'",i,Link_ServerName,Link_IPAddr,Link_Port,Link_Pass);
1174                         LinkPort = atoi(Link_Port);
1175                         if (match(Link_ServerName,parameters[0])) {
1176                                 found = true;
1177                                 break;
1178                         }
1179                 }
1180         }
1181         
1182         if (!found) {
1183                 WriteServ(user->fd,"NOTICE %s :*** Failed to connect to %s: No servers matching this pattern are configured for linking.",user->nick,parameters[0]);
1184                 return;
1185         }
1186         
1187         // TODO: Perform a check here to stop a server being linked twice!
1188
1189         WriteServ(user->fd,"NOTICE %s :*** Connecting to %s (%s) port %s...",user->nick,Link_ServerName,Link_IPAddr,Link_Port);
1190
1191         if (me[defaultRoute])
1192         {
1193                 me[defaultRoute]->BeginLink(Link_IPAddr,LinkPort,Link_Pass,Link_ServerName,me[defaultRoute]->port);
1194                 return;
1195         }
1196         else
1197         {
1198                 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);
1199         }
1200 }
1201
1202 void handle_squit(char **parameters, int pcnt, userrec *user)
1203 {
1204         // send out an squit across the mesh and then clear the server list (for local squit)
1205         if (!pcnt)
1206         {
1207                 WriteOpers("SQUIT command issued by %s",user->nick);
1208                 char buffer[MAXBUF];
1209                 snprintf(buffer,MAXBUF,"& %s",ServerName);
1210                 NetSendToAll(buffer);
1211                 DoSplitEveryone();
1212         }
1213         else
1214         {
1215                 WriteServ(user->fd,"NOTICE :*** Remote SQUIT not supported yet.");
1216         }
1217 }
1218
1219 void handle_links(char **parameters, int pcnt, userrec *user)
1220 {
1221         WriteServ(user->fd,"364 %s %s %s :0 %s",user->nick,ServerName,ServerName,ServerDesc);
1222         for (int j = 0; j < 32; j++)
1223         {
1224                 if (me[j] != NULL)
1225                 {
1226                         for (int k = 0; k < me[j]->connectors.size(); k++)
1227                         {
1228                                 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());
1229                         }
1230                 }
1231         }
1232         WriteServ(user->fd,"365 %s * :End of /LINKS list.",user->nick);
1233 }
1234
1235 void handle_map(char **parameters, int pcnt, userrec *user)
1236 {
1237         char line[MAXBUF];
1238         snprintf(line,MAXBUF,"006 %s :%s",user->nick,ServerName);
1239         while (strlen(line) < 50)
1240                 strcat(line," ");
1241         WriteServ(user->fd,"%s%d (%.2f%%)",line,local_count(),(float)(((float)local_count()/(float)usercnt())*100));
1242         for (int j = 0; j < 32; j++)
1243         {
1244                 if (me[j] != NULL)
1245                 {
1246                         for (int k = 0; k < me[j]->connectors.size(); k++)
1247                         {
1248                                 snprintf(line,MAXBUF,"006 %s :%c-%s",user->nick,islast(me[j]->connectors[k].GetServerName().c_str()),me[j]->connectors[k].GetServerName().c_str());
1249                                 while (strlen(line) < 50)
1250                                         strcat(line," ");
1251                                 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));
1252                         }
1253                 }
1254         }
1255         WriteServ(user->fd,"007 %s :End of /MAP",user->nick);
1256 }
1257
1258
1259 void handle_oper(char **parameters, int pcnt, userrec *user)
1260 {
1261         char LoginName[MAXBUF];
1262         char Password[MAXBUF];
1263         char OperType[MAXBUF];
1264         char TypeName[MAXBUF];
1265         char Hostname[MAXBUF];
1266         int i,j;
1267
1268         for (int i = 0; i < ConfValueEnum("oper",&config_f); i++)
1269         {
1270                 ConfValue("oper","name",i,LoginName,&config_f);
1271                 ConfValue("oper","password",i,Password,&config_f);
1272                 if ((!strcmp(LoginName,parameters[0])) && (!strcmp(Password,parameters[1])))
1273                 {
1274                         /* correct oper credentials */
1275                         ConfValue("oper","type",i,OperType,&config_f);
1276                         WriteOpers("*** %s (%s@%s) is now an IRC operator of type %s",user->nick,user->ident,user->host,OperType);
1277                         WriteServ(user->fd,"381 %s :You are now an IRC operator of type %s",user->nick,OperType);
1278                         WriteServ(user->fd,"MODE %s :+o",user->nick);
1279                         for (j =0; j < ConfValueEnum("type",&config_f); j++)
1280                         {
1281                                 ConfValue("type","name",j,TypeName,&config_f);
1282                                 if (!strcmp(TypeName,OperType))
1283                                 {
1284                                         /* found this oper's opertype */
1285                                         ConfValue("type","host",j,Hostname,&config_f);
1286                                         ChangeDisplayedHost(user,Hostname);
1287                                 }
1288                         }
1289                         if (!strchr(user->modes,'o'))
1290                         {
1291                                 strcat(user->modes,"o");
1292                         }
1293                         FOREACH_MOD OnOper(user);
1294                         return;
1295                 }
1296         }
1297         /* no such oper */
1298         WriteServ(user->fd,"491 %s :Invalid oper credentials",user->nick);
1299         WriteOpers("*** WARNING! Failed oper attempt by %s!%s@%s!",user->nick,user->ident,user->host);
1300 }
1301
1302 void handle_nick(char **parameters, int pcnt, userrec *user)
1303 {
1304         if (pcnt < 1) 
1305         {
1306                 log(DEBUG,"not enough params for handle_nick");
1307                 return;
1308         }
1309         if (!parameters[0])
1310         {
1311                 log(DEBUG,"invalid parameter passed to handle_nick");
1312                 return;
1313         }
1314         if (!strlen(parameters[0]))
1315         {
1316                 log(DEBUG,"zero length new nick passed to handle_nick");
1317                 return;
1318         }
1319         if (!user)
1320         {
1321                 log(DEBUG,"invalid user passed to handle_nick");
1322                 return;
1323         }
1324         if (!user->nick)
1325         {
1326                 log(DEBUG,"invalid old nick passed to handle_nick");
1327                 return;
1328         }
1329         if (!strcasecmp(user->nick,parameters[0]))
1330         {
1331                 log(DEBUG,"old nick is new nick, skipping");
1332                 return;
1333         }
1334         else
1335         {
1336                 if (strlen(parameters[0]) > 1)
1337                 {
1338                         if (parameters[0][0] == ':')
1339                         {
1340                                 *parameters[0]++;
1341                         }
1342                 }
1343                 if ((Find(parameters[0])) && (Find(parameters[0]) != user))
1344                 {
1345                         WriteServ(user->fd,"433 %s %s :Nickname is already in use.",user->nick,parameters[0]);
1346                         return;
1347                 }
1348         }
1349         if (isnick(parameters[0]) == 0)
1350         {
1351                 WriteServ(user->fd,"432 %s %s :Erroneous Nickname",user->nick,parameters[0]);
1352                 return;
1353         }
1354
1355         if (user->registered == 7)
1356         {
1357                 WriteCommon(user,"NICK %s",parameters[0]);
1358                 
1359                 // Q token must go to ALL servers!!!
1360                 char buffer[MAXBUF];
1361                 snprintf(buffer,MAXBUF,"n %s %s",user->nick,parameters[0]);
1362                 NetSendToAll(buffer);
1363                 
1364         }
1365         
1366         /* change the nick of the user in the users_hash */
1367         user = ReHashNick(user->nick, parameters[0]);
1368         /* actually change the nick within the record */
1369         if (!user) return;
1370         if (!user->nick) return;
1371
1372         strncpy(user->nick, parameters[0],NICKMAX);
1373
1374         log(DEBUG,"new nick set: %s",user->nick);
1375         
1376         if (user->registered < 3)
1377                 user->registered = (user->registered | 2);
1378         if (user->registered == 3)
1379         {
1380                 /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */
1381                 ConnectUser(user);
1382         }
1383         log(DEBUG,"exit nickchange: %s",user->nick);
1384 }
1385
1386
1387
1388