]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
063b14fc44936e5d30bdaf9846d0e2d93f45fac9
[user/henk/code/inspircd.git] / src / mode.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $Core: libIRCDmode */
15 /* $ExtraDeps: $(RELCPPFILES) */
16 /* $ExtraObjects: modes/modeclasses.a */
17 /* $ExtraBuild: @${MAKE} -C "modes" DIRNAME="src/modes" CC="$(CC)" $(MAKEARGS) CPPFILES="$(CPPFILES)" */
18
19 #include "inspircd.h"
20 #include "inspstring.h"
21
22 /* +s (secret) */
23 #include "modes/cmode_s.h"
24 /* +p (private) */
25 #include "modes/cmode_p.h"
26 /* +b (bans) */
27 #include "modes/cmode_b.h"
28 /* +m (moderated) */
29 #include "modes/cmode_m.h"
30 /* +t (only (half) ops can change topic) */
31 #include "modes/cmode_t.h"
32 /* +n (no external messages) */
33 #include "modes/cmode_n.h"
34 /* +i (invite only) */
35 #include "modes/cmode_i.h"
36 /* +k (keyed channel) */
37 #include "modes/cmode_k.h"
38 /* +l (channel user limit) */
39 #include "modes/cmode_l.h"
40 /* +o (channel op) */
41 #include "modes/cmode_o.h"
42 /* +h (channel halfop) */
43 #include "modes/cmode_h.h"
44 /* +v (channel voice) */
45 #include "modes/cmode_v.h"
46 /* +s (server notices) */
47 #include "modes/umode_s.h"
48 /* +w (see wallops) */
49 #include "modes/umode_w.h"
50 /* +i (invisible) */
51 #include "modes/umode_i.h"
52 /* +o (operator) */
53 #include "modes/umode_o.h"
54 /* +n (notice mask - our implementation of snomasks) */
55 #include "modes/umode_n.h"
56
57 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired)
58         : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired)
59 {
60 }
61
62 ModeHandler::~ModeHandler()
63 {
64 }
65
66 bool ModeHandler::IsListMode()
67 {
68         return list;
69 }
70
71 char ModeHandler::GetNeededPrefix()
72 {
73         return prefixneeded;
74 }
75
76 void ModeHandler::SetNeededPrefix(char needsprefix)
77 {
78         prefixneeded = needsprefix;
79 }
80
81 unsigned int ModeHandler::GetPrefixRank()
82 {
83         return 0;
84 }
85
86 unsigned int ModeHandler::GetCount()
87 {
88         return 0;
89 }
90
91 void ModeHandler::ChangeCount(int modifier)
92 {
93         count += modifier;
94         ServerInstance->Log(DEBUG,"Change count for mode %c is now %d", mode, count);
95 }
96
97 ModeType ModeHandler::GetModeType()
98 {
99         return m_type;
100 }
101
102 bool ModeHandler::NeedsOper()
103 {
104         return oper;
105 }
106
107 char ModeHandler::GetPrefix()
108 {
109         return prefix;
110 }
111
112 int ModeHandler::GetNumParams(bool adding)
113 {
114         return adding ? n_params_on : n_params_off;
115 }
116
117 char ModeHandler::GetModeChar()
118 {
119         return mode;
120 }
121
122 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool)
123 {
124         return MODEACTION_DENY;
125 }
126
127 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
128 {
129         if (dest)
130         {
131                 return std::make_pair(dest->IsModeSet(this->mode), "");
132         }
133         else
134         {
135                 return std::make_pair(channel->IsModeSet(this->mode), "");
136         }
137 }
138
139 void ModeHandler::DisplayList(User*, Channel*)
140 {
141 }
142
143 void ModeHandler::DisplayEmptyList(User*, Channel*)
144 {
145 }
146
147 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
148 {
149         return (ours < theirs);
150 }
151
152 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
153 {
154 }
155
156 ModeWatcher::~ModeWatcher()
157 {
158 }
159
160 char ModeWatcher::GetModeChar()
161 {
162         return mode;
163 }
164
165 ModeType ModeWatcher::GetModeType()
166 {
167         return m_type;
168 }
169
170 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType)
171 {
172         return true;
173 }
174
175 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
176 {
177 }
178
179 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
180 {
181         User *d;
182         if ((!user) || (!dest) || (!chan) || (!*dest))
183         {
184                 return NULL;
185         }
186         d = ServerInstance->FindNick(dest);
187         if (!d)
188         {
189                 user->WriteServ("401 %s %s :No such nick/channel",user->nick, dest);
190                 return NULL;
191         }
192         return d;
193 }
194
195 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
196 {
197         if (!chan)
198                 return "";
199
200         UCListIter n = d->chans.find(chan);
201         if (n != d->chans.end())
202         {
203                 if (n->second & MASK)
204                 {
205                         return "";
206                 }
207                 n->second = n->second | MASK;
208                 switch (MASK)
209                 {
210                         case UCMODE_OP:
211                                 n->first->AddOppedUser(d);
212                         break;
213                         case UCMODE_HOP:
214                                 n->first->AddHalfoppedUser(d);
215                         break;
216                         case UCMODE_VOICE:
217                                 n->first->AddVoicedUser(d);
218                         break;
219                 }
220                 return d->nick;
221         }
222         return "";
223 }
224
225 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
226 {
227         if (!chan)
228                 return "";
229
230         UCListIter n = d->chans.find(chan);
231         if (n != d->chans.end())
232         {
233                 if ((n->second & MASK) == 0)
234                 {
235                         return "";
236                 }
237                 n->second ^= MASK;
238                 switch (MASK)
239                 {
240                         case UCMODE_OP:
241                                 n->first->DelOppedUser(d);
242                         break;
243                         case UCMODE_HOP:
244                                 n->first->DelHalfoppedUser(d);
245                         break;
246                         case UCMODE_VOICE:
247                                 n->first->DelVoicedUser(d);
248                         break;
249                 }
250                 return d->nick;
251         }
252         return "";
253 }
254
255 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
256 {
257         if (targetchannel)
258         {
259                 /* Display channel's current mode string */
260                 user->WriteServ("324 %s %s +%s",user->nick, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));
261                 user->WriteServ("329 %s %s %lu", user->nick, targetchannel->name, (unsigned long)targetchannel->age);
262                 return;
263         }
264         else if (targetuser)
265         {
266                 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
267                 {
268                         user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
269                         return;
270                 }
271
272                 if ((targetuser == user) || (IS_OPER(user)))
273                 {
274                         /* Display user's current mode string */
275                         user->WriteServ("221 %s :+%s",targetuser->nick,targetuser->FormatModes());
276                         if (IS_OPER(targetuser))
277                                 user->WriteServ("008 %s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());
278                         return;
279                 }
280                 else
281                 {
282                         user->WriteServ("502 %s :Can't change mode for other users", user->nick);
283                         return;
284                 }
285         }
286
287         /* No such nick/channel */
288         user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
289         return;
290 }
291
292 void ModeParser::Process(const char** parameters, int pcnt, User *user, bool servermode)
293 {
294         std::string target = parameters[0];
295         ModeType type = MODETYPE_USER;
296         unsigned char mask = 0;
297         Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
298         User* targetuser  = ServerInstance->FindNick(parameters[0]);
299
300         LastParse.clear();
301
302         /* Special case for displaying the list for listmodes,
303          * e.g. MODE #chan b, or MODE #chan +b without a parameter
304          */
305         if ((targetchannel) && (pcnt == 2))
306         {
307                 const char* mode = parameters[1];
308                 int nonlistmodes_found = 0;
309                 bool sent[256];
310
311                 mask = MASK_CHANNEL;
312
313                 memset(&sent, 0, 256);
314                 
315                 while (mode && *mode)
316                 {
317                         unsigned char mletter = *mode;
318
319                         if (*mode == '+')
320                         {
321                                 mode++;
322                                 continue;
323                         }
324                         
325                         /* Ensure the user doesnt request the same mode twice,
326                          * so they cant flood themselves off out of idiocy.
327                          */
328                         if (!sent[mletter])
329                         {
330                                 sent[mletter] = true;
331                         }
332                         else
333                         {
334                                 mode++;
335                                 continue;
336                         }
337
338                         ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
339                         bool display = true;
340
341                         if ((mh) && (mh->IsListMode()))
342                         {
343                                 int MOD_RESULT = 0;
344                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
345                                 if (MOD_RESULT == ACR_DENY)
346                                 {
347                                         mode++;
348                                         continue;
349                                 }
350
351                                 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
352                                 {
353                                         user->WriteServ("482 %s %s :Only half-operators and above may view the +%c list",user->nick, targetchannel->name, *mode++);
354                                         mh->DisplayEmptyList(user, targetchannel);
355                                         continue;
356                                 }
357
358                                 /** See below for a description of what craq this is :D
359                                  */
360                                 unsigned char handler_id = (*mode - 65) | mask;
361
362                                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
363                                 {
364                                         std::string dummyparam;
365                                         
366                                         if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
367                                                 display = false;
368                                 }
369
370                                 if (display)
371                                         mh->DisplayList(user, targetchannel);
372                         }
373                         else
374                                 nonlistmodes_found++;
375
376                         mode++;
377                 }
378
379                 /* We didnt have any modes that were non-list, we can return here */
380                 if (!nonlistmodes_found)
381                         return;
382         }
383
384         if (pcnt == 1)
385         {
386                 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]);
387         }
388         else if (pcnt > 1)
389         {
390                 if (targetchannel)
391                 {
392                         type = MODETYPE_CHANNEL;
393                         mask = MASK_CHANNEL;
394
395                         /* Extra security checks on channel modes
396                          * (e.g. are they a (half)op?
397                          */
398
399                         if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
400                         {
401                                 /* We don't have halfop */
402                                 int MOD_RESULT = 0;
403                                 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
404                                 if (MOD_RESULT == ACR_DENY)
405                                         return;
406                         }
407                 }
408                 else if (targetuser)
409                 {
410                         type = MODETYPE_USER;
411                         mask = MASK_USER;
412                         if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
413                         {
414                                 user->WriteServ("502 %s :Can't change mode for other users", user->nick);
415                                 return;
416                         }
417                 }
418                 else
419                 {
420                         /* No such nick/channel */
421                         user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
422                         return;
423                 }
424
425                 std::string mode_sequence = parameters[1];
426                 std::string parameter;
427                 std::ostringstream parameter_list;
428                 std::string output_sequence;
429                 bool adding = true, state_change = false;
430                 unsigned char handler_id = 0;
431                 int parameter_counter = 2; /* Index of first parameter */
432                 int parameter_count = 0;
433                 bool last_successful_state_change = false;
434
435                 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
436                 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
437                         mode_sequence.insert(0, "+");
438
439                 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
440                 {
441                         unsigned char modechar = *letter;
442
443                         switch (modechar)
444                         {
445                                 /* NB:
446                                  * For + and - mode characters, we don't just stick the character into the output sequence.
447                                  * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
448                                  * appearing in the output sequence, we store a flag which says there was a state change,
449                                  * which is set on any + or -, however, the + or - that we finish on is only appended to
450                                  * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
451                                  */
452                                 case '+':
453                                         /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
454                                          * however, will allow the + if it is the first item in the sequence, regardless.
455                                          */
456                                         if ((!adding) || (!output_sequence.length()))
457                                                 state_change = true;
458                                         adding = true;
459                                         if (!output_sequence.length())
460                                                 last_successful_state_change = false;
461                                         continue;
462                                 break;
463                                 case '-':
464                                         if ((adding) || (!output_sequence.length()))
465                                                 state_change = true;
466                                         adding = false;
467                                         if (!output_sequence.length())
468                                                 last_successful_state_change = true;
469                                         continue;
470                                 break;
471                                 default:
472
473                                         /**
474                                          * Watch carefully for the sleight of hand trick.
475                                          * 65 is the ascii value of 'A'. We take this from
476                                          * the char we're looking at to get a number between
477                                          * 1 and 127. We then logic-or it to get the hashed
478                                          * position, dependent on wether its a channel or
479                                          * a user mode. This is a little stranger, but a lot
480                                          * faster, than using a map of pairs.
481                                          */
482                                         handler_id = (modechar - 65) | mask;
483
484                                         if (modehandlers[handler_id])
485                                         {
486                                                 bool abort = false;
487
488                                                 if (modehandlers[handler_id]->GetModeType() == type)
489                                                 {
490                                                         int MOD_RESULT = 0;
491
492                                                         if (modehandlers[handler_id]->GetNumParams(adding))
493                                                         {
494                                                                 /* This mode expects a parameter, do we have any parameters left in our list to use? */
495                                                                 if (parameter_counter < pcnt)
496                                                                 {
497                                                                         parameter = parameters[parameter_counter++];
498
499                                                                         /* Yerk, invalid! */
500                                                                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
501                                                                                 parameter.clear();
502                                                                 }
503                                                                 else
504                                                                 {
505                                                                         /* No parameter, continue to the next mode */
506                                                                         continue;
507                                                                 }
508
509                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1));
510                                                         }
511                                                         else
512                                                         {
513                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0));
514                                                         }
515
516                                                         if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
517                                                                 continue;
518
519                                                         if (IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
520                                                         {
521                                                                 ServerInstance->Log(DEBUG,"Enter minimum prefix check");
522                                                                 /* Check access to this mode character */
523                                                                 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
524                                                                 {
525                                                                         char needed = modehandlers[handler_id]->GetNeededPrefix();
526                                                                         ModeHandler* prefixmode = FindPrefix(needed);
527                                                                         ServerInstance->Log(DEBUG,"Needed prefix: %c", needed);
528
529                                                                         /* If the mode defined by the handler is not '\0', but the handler for it
530                                                                          * cannot be found, they probably dont have the right module loaded to implement
531                                                                          * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
532                                                                          * Revert to checking against the minimum core prefix, '%'.
533                                                                          */
534                                                                         if (needed && !prefixmode)
535                                                                                 prefixmode = FindPrefix('%');
536                                                 
537                                                                         unsigned int neededrank = prefixmode->GetPrefixRank();
538                                                                         /* Compare our rank on the channel against the rank of the required prefix,
539                                                                          * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
540                                                                          * in NAMES(X) are not in rank order, we know the most powerful mode is listed
541                                                                          * first, so we don't need to iterate, we just look up the first instead.
542                                                                          */
543                                                                         std::string modestring = targetchannel->GetAllPrefixChars(user);
544                                                                         char ml = (modestring.empty() ? '\0' : modestring[0]);
545                                                                         ModeHandler* ourmode = FindPrefix(ml);
546                                                                         if (!ourmode || ourmode->GetPrefixRank() < neededrank)
547                                                                         {
548                                                                                 /* Bog off */
549                                                                                 user->WriteServ("482 %s %s :You require channel privilege %c or above to %sset channel mode %c",
550                                                                                                 user->nick, targetchannel->name, needed, adding ? "" : "un", modechar);
551                                                                                 continue;
552                                                                         }
553                                                                 }
554                                                         }
555
556                                                         bool had_parameter = !parameter.empty();
557                                                                 
558                                                         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
559                                                         {
560                                                                 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
561                                                                 {
562                                                                         abort = true;
563                                                                         break;
564                                                                 }
565                                                                 /* A module whacked the parameter completely, and there was one. abort. */
566                                                                 if ((had_parameter) && (parameter.empty()))
567                                                                 {
568                                                                         abort = true;
569                                                                         break;
570                                                                 }
571                                                         }
572
573                                                         if (abort)
574                                                                 continue;
575
576                                                         /* It's an oper only mode, check if theyre an oper. If they arent,
577                                                          * eat any parameter that  came with the mode, and continue to next
578                                                          */
579                                                         if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))
580                                                         {
581                                                                 user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,
582                                                                                 adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
583                                                                                 modehandlers[handler_id]->GetModeChar());
584                                                                 continue;
585                                                         }
586
587                                                         /* Call the handler for the mode */
588                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding);
589
590                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
591                                                         {
592                                                                 /* The handler nuked the parameter and they are supposed to have one.
593                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
594                                                                  * so we bail to the next mode character.
595                                                                  */
596                                                                 continue;
597                                                         }
598
599                                                         if (ma == MODEACTION_ALLOW)
600                                                         {
601                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
602                                                                 if (state_change)
603                                                                 {
604                                                                         if (adding != last_successful_state_change)
605                                                                                 output_sequence.append(adding ? "+" : "-");
606                                                                         last_successful_state_change = adding;
607                                                                 }
608                                                                 
609                                                                 /* Add the mode letter */
610                                                                 output_sequence.push_back(modechar);
611
612                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
613
614                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
615                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
616                                                                 {
617                                                                         parameter_list << " " << parameter;
618                                                                         parameter_count++;
619                                                                         /* Does this mode have a prefix? */
620                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
621                                                                         {
622                                                                                 User* user_to_prefix = ServerInstance->FindNick(parameter);
623                                                                                 if (user_to_prefix)
624                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
625                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
626                                                                         }
627                                                                 }
628
629                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
630                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
631                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type);
632
633                                                                 /* Reset the state change flag */
634                                                                 state_change = false;
635
636                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
637                                                                                 || (parameter_count > MAXMODES))
638                                                                 {
639                                                                         /* We cant have a mode sequence this long */
640                                                                         letter = mode_sequence.end() - 1;
641                                                                         continue;
642                                                                 }
643                                                         }
644                                                 }
645                                         }
646                                         else
647                                         {
648                                                 /* No mode handler? Unknown mode character then. */
649                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
650                                         }
651                                 break;
652                         }
653                 }
654
655                 /* Was there at least one valid mode in the sequence? */
656                 if (!output_sequence.empty())
657                 {
658                         if (servermode)
659                         {
660                                 if (type == MODETYPE_CHANNEL)
661                                 {
662                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
663                                         this->LastParse = targetchannel->name;
664                                 }
665                                 else
666                                 {
667                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
668                                         this->LastParse = targetuser->nick;
669                                 }
670                         }
671                         else
672                         {
673                                 if (type == MODETYPE_CHANNEL)
674                                 {
675                                         targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
676                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
677                                         this->LastParse = targetchannel->name;
678                                 }
679                                 else
680                                 {
681                                         user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
682                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
683                                         this->LastParse = targetuser->nick;
684                                 }
685                         }
686
687                         LastParse.append(" ");
688                         LastParse.append(output_sequence);
689                         LastParse.append(parameter_list.str());
690                 }
691         }
692 }
693
694 const std::string& ModeParser::GetLastParse()
695 {
696         return LastParse;
697 }
698
699 void ModeParser::CleanMask(std::string &mask)
700 {
701         std::string::size_type pos_of_pling = mask.find_first_of('!');
702         std::string::size_type pos_of_at = mask.find_first_of('@');
703         std::string::size_type pos_of_dot = mask.find_first_of('.');
704         std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
705
706         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
707         {
708                 /* Just a nick, or just a host */
709                 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
710                 {
711                         /* It has no '.' in it, it must be a nick. */
712                         mask.append("!*@*");
713                 }
714                 else
715                 {
716                         /* Got a dot in it? Has to be a host */
717                         mask = "*!*@" + mask;
718                 }
719         }
720         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
721         {
722                 /* Has an @ but no !, its a user@host */
723                  mask = "*!" + mask;
724         }
725         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
726         {
727                 /* Has a ! but no @, it must be a nick!ident */
728                 mask.append("@*");
729         }
730 }
731
732 bool ModeParser::AddMode(ModeHandler* mh)
733 {
734         unsigned char mask = 0;
735         unsigned char pos = 0;
736
737         /* Yes, i know, this might let people declare modes like '_' or '^'.
738          * If they do that, thats their problem, and if i ever EVER see an
739          * official InspIRCd developer do that, i'll beat them with a paddle!
740          */
741         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
742                 return false;
743
744         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
745          * A mode prefix of ':' will fuck up both server to server, and client to server.
746          * A mode prefix of '#' will mess up /whois and /privmsg
747          */
748         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
749                 return false;
750
751         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
752         pos = (mh->GetModeChar()-65) | mask;
753
754         if (modehandlers[pos])
755                 return false;
756
757         modehandlers[pos] = mh;
758         return true;
759 }
760
761 bool ModeParser::DelMode(ModeHandler* mh)
762 {
763         unsigned char mask = 0;
764         unsigned char pos = 0;
765
766         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
767                 return false;
768
769         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
770         pos = (mh->GetModeChar()-65) | mask;
771
772         if (!modehandlers[pos])
773                 return false;
774
775         switch (mh->GetModeType())
776         {
777                 case MODETYPE_USER:
778                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
779                         {
780                                 mh->RemoveMode(i->second);
781                         }
782                 break;
783                 case MODETYPE_CHANNEL:
784                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
785                         {
786                                 mh->RemoveMode(i->second);
787                         }
788                 break;
789         }
790
791         modehandlers[pos] = NULL;
792
793         return true;
794 }
795
796 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
797 {
798         unsigned char mask = 0;
799         unsigned char pos = 0;
800
801         if ((modeletter < 'A') || (modeletter > 'z'))
802                 return NULL;
803
804         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
805         pos = (modeletter-65) | mask;
806
807         return modehandlers[pos];
808 }
809
810 std::string ModeParser::UserModeList()
811 {
812         char modestr[256];
813         int pointer = 0;
814
815         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
816         {
817                 unsigned char pos = (mode-65) | MASK_USER;
818
819                 if (modehandlers[pos])
820                         modestr[pointer++] = mode;
821         }
822         modestr[pointer++] = 0;
823         return modestr;
824 }
825
826 std::string ModeParser::ChannelModeList()
827 {
828         char modestr[256];
829         int pointer = 0;
830
831         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
832         {
833                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
834                         continue;
835
836                 unsigned char pos = (mode-65) | MASK_CHANNEL;
837
838                 if (modehandlers[pos])
839                         modestr[pointer++] = mode;
840         }
841         modestr[pointer++] = 0;
842         return modestr;
843 }
844
845 std::string ModeParser::ParaModeList()
846 {
847         char modestr[256];
848         int pointer = 0;
849
850         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
851         {
852                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
853                         continue;
854
855                 unsigned char pos = (mode-65) | MASK_CHANNEL;
856
857                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
858                         modestr[pointer++] = mode;
859         }
860         modestr[pointer++] = 0;
861         return modestr;
862 }
863
864 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
865 {
866         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
867         {
868                 unsigned char pos = (mode-65) | MASK_CHANNEL;
869
870                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
871                 {
872                         return modehandlers[pos];
873                 }
874         }
875         return NULL;
876 }
877
878 std::string ModeParser::ModeString(User* user, Channel* channel)
879 {
880         std::string types;
881         std::string pars;
882
883         if (!channel || !user)
884                 return "";
885
886         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
887         {
888                 unsigned char pos = (mode-65) | MASK_CHANNEL;
889                 ModeHandler* mh = modehandlers[pos];
890                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
891                 {
892                         ModePair ret;
893                         ret = mh->ModeSet(NULL, user, channel, user->nick);
894                         if ((ret.first) && (ret.second == user->nick))
895                         {
896                                 pars.append(" ");
897                                 pars.append(user->nick);
898                                 types.push_back(mh->GetModeChar());
899                         }
900                 }
901         }
902
903         return types+pars;
904 }
905
906 std::string ModeParser::ChanModes()
907 {
908         std::string type1;      /* Listmodes EXCEPT those with a prefix */
909         std::string type2;      /* Modes that take a param when adding or removing */
910         std::string type3;      /* Modes that only take a param when adding */
911         std::string type4;      /* Modes that dont take a param */
912
913         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
914         {
915                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
916                         continue;
917
918                 unsigned char pos = (mode-65) | MASK_CHANNEL;
919                  /* One parameter when adding */
920                 if (modehandlers[pos])
921                 {       
922                         if (modehandlers[pos]->GetNumParams(true))
923                         {
924                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
925                                 {
926                                         type1 += modehandlers[pos]->GetModeChar();
927                                 }
928                                 else
929                                 {
930                                         /* ... and one parameter when removing */
931                                         if (modehandlers[pos]->GetNumParams(false))
932                                         {
933                                                 /* But not a list mode */
934                                                 if (!modehandlers[pos]->GetPrefix())
935                                                 {
936                                                         type2 += modehandlers[pos]->GetModeChar();
937                                                 }
938                                         }
939                                         else
940                                         {
941                                                 /* No parameters when removing */
942                                                 type3 += modehandlers[pos]->GetModeChar();
943                                         }
944                                 }
945                         }
946                         else
947                         {
948                                 type4 += modehandlers[pos]->GetModeChar();
949                         }
950                 }
951                          
952         }
953
954         return type1 + "," + type2 + "," + type3 + "," + type4;
955 }
956
957 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
958 {       
959         return one.second > two.second;
960 }
961
962 std::string ModeParser::BuildPrefixes()
963 {
964         std::string mletters;
965         std::string mprefixes;
966         pfxcontainer pfx;
967         std::map<char,char> prefix_to_mode;
968
969         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
970         {
971                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
972                         continue;
973
974                 unsigned char pos = (mode-65) | MASK_CHANNEL;
975
976                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
977                 {
978                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
979                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
980                 }
981         }
982
983         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
984
985         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
986         {
987                 mletters = mletters + n->first;
988                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
989         }
990
991         return "(" + mprefixes + ")" + mletters;
992 }
993
994 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
995 {
996         unsigned char mask = 0;
997         unsigned char pos = 0;
998
999         if (!mw)
1000                 return false;
1001
1002         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1003                 return false;
1004
1005         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1006         pos = (mw->GetModeChar()-65) | mask;
1007
1008         modewatchers[pos].push_back(mw);
1009
1010         return true;
1011 }
1012
1013 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1014 {
1015         unsigned char mask = 0;
1016         unsigned char pos = 0;
1017
1018         if (!mw)
1019                 return false;
1020
1021         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1022                 return false;
1023
1024         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1025         pos = (mw->GetModeChar()-65) | mask;
1026
1027         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1028
1029         if (a == modewatchers[pos].end())
1030         {
1031                 return false;
1032         }
1033
1034         modewatchers[pos].erase(a);
1035
1036         return true;
1037 }
1038
1039 /** This default implementation can remove simple user modes
1040  */
1041 void ModeHandler::RemoveMode(User* user)
1042 {
1043         char moderemove[MAXBUF];
1044         const char* parameters[] = { user->nick, moderemove };
1045
1046         if (user->IsModeSet(this->GetModeChar()))
1047         {
1048                 sprintf(moderemove,"-%c",this->GetModeChar());
1049                 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1050         }
1051 }
1052
1053 /** This default implementation can remove simple channel modes
1054  * (no parameters)
1055  */
1056 void ModeHandler::RemoveMode(Channel* channel)
1057 {
1058         char moderemove[MAXBUF];
1059         const char* parameters[] = { channel->name, moderemove };
1060
1061         if (channel->IsModeSet(this->GetModeChar()))
1062         {
1063                 sprintf(moderemove,"-%c",this->GetModeChar());
1064                 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1065         }
1066 }
1067
1068 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1069 {
1070         ModeHandler* modes[] =
1071         {
1072                 new ModeChannelSecret(Instance),
1073                 new ModeChannelPrivate(Instance),
1074                 new ModeChannelModerated(Instance),
1075                 new ModeChannelTopicOps(Instance),
1076                 new ModeChannelNoExternal(Instance),
1077                 new ModeChannelInviteOnly(Instance),
1078                 new ModeChannelKey(Instance),
1079                 new ModeChannelLimit(Instance),
1080                 new ModeChannelBan(Instance),
1081                 new ModeChannelOp(Instance),
1082                 new ModeChannelHalfOp(Instance),
1083                 new ModeChannelVoice(Instance),
1084                 new ModeUserServerNotice(Instance),
1085                 new ModeUserWallops(Instance),
1086                 new ModeUserInvisible(Instance),
1087                 new ModeUserOperator(Instance),
1088                 new ModeUserServerNoticeMask(Instance),
1089                 NULL
1090         };
1091
1092         /* Clear mode list */
1093         memset(modehandlers, 0, sizeof(modehandlers));
1094         memset(modewatchers, 0, sizeof(modewatchers));
1095
1096         /* Last parse string */
1097         LastParse.clear();
1098
1099         /* Initialise the RFC mode letters */
1100         for (int index = 0; modes[index]; index++)
1101                 this->AddMode(modes[index]);
1102 }