]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
efb1a4cf03192e887ebc5bb50ae51b20b143f76d
[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->Logs->Log("MODE", 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, 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, bool)
171 {
172         return true;
173 }
174
175 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
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* const* 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                 bool SkipAccessChecks = false;
391
392                 if (targetchannel)
393                 {
394                         type = MODETYPE_CHANNEL;
395                         mask = MASK_CHANNEL;
396
397                         /* Extra security checks on channel modes
398                          * (e.g. are they a (half)op?
399                          */
400
401                         if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
402                         {
403                                 /* We don't have halfop */
404                                 int MOD_RESULT = 0;
405                                 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
406                                 if (MOD_RESULT == ACR_DENY)
407                                         return;
408                                 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
409                         }
410                 }
411                 else if (targetuser)
412                 {
413                         type = MODETYPE_USER;
414                         mask = MASK_USER;
415                         if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
416                         {
417                                 user->WriteServ("502 %s :Can't change mode for other users", user->nick);
418                                 return;
419                         }
420                 }
421                 else
422                 {
423                         /* No such nick/channel */
424                         user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
425                         return;
426                 }
427
428                 std::string mode_sequence = parameters[1];
429                 std::string parameter;
430                 std::ostringstream parameter_list;
431                 std::string output_sequence;
432                 bool adding = true, state_change = false;
433                 unsigned char handler_id = 0;
434                 int parameter_counter = 2; /* Index of first parameter */
435                 int parameter_count = 0;
436                 bool last_successful_state_change = false;
437
438                 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
439                 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
440                         mode_sequence.insert(0, "+");
441
442                 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
443                 {
444                         unsigned char modechar = *letter;
445
446                         switch (modechar)
447                         {
448                                 /* NB:
449                                  * For + and - mode characters, we don't just stick the character into the output sequence.
450                                  * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
451                                  * appearing in the output sequence, we store a flag which says there was a state change,
452                                  * which is set on any + or -, however, the + or - that we finish on is only appended to
453                                  * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
454                                  */
455                                 case '+':
456                                         /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
457                                          * however, will allow the + if it is the first item in the sequence, regardless.
458                                          */
459                                         if ((!adding) || (!output_sequence.length()))
460                                                 state_change = true;
461                                         adding = true;
462                                         if (!output_sequence.length())
463                                                 last_successful_state_change = false;
464                                         continue;
465                                 break;
466                                 case '-':
467                                         if ((adding) || (!output_sequence.length()))
468                                                 state_change = true;
469                                         adding = false;
470                                         if (!output_sequence.length())
471                                                 last_successful_state_change = true;
472                                         continue;
473                                 break;
474                                 default:
475
476                                         /**
477                                          * Watch carefully for the sleight of hand trick.
478                                          * 65 is the ascii value of 'A'. We take this from
479                                          * the char we're looking at to get a number between
480                                          * 1 and 127. We then logic-or it to get the hashed
481                                          * position, dependent on wether its a channel or
482                                          * a user mode. This is a little stranger, but a lot
483                                          * faster, than using a map of pairs.
484                                          */
485                                         handler_id = (modechar - 65) | mask;
486
487                                         if (modehandlers[handler_id])
488                                         {
489                                                 bool abort = false;
490
491                                                 if (modehandlers[handler_id]->GetModeType() == type)
492                                                 {
493                                                         int MOD_RESULT = 0;
494
495                                                         if (modehandlers[handler_id]->GetNumParams(adding))
496                                                         {
497                                                                 /* This mode expects a parameter, do we have any parameters left in our list to use? */
498                                                                 if (parameter_counter < pcnt)
499                                                                 {
500                                                                         parameter = parameters[parameter_counter++];
501
502                                                                         /* Yerk, invalid! */
503                                                                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
504                                                                                 parameter.clear();
505                                                                 }
506                                                                 else
507                                                                 {
508                                                                         /* No parameter, continue to the next mode */
509                                                                         continue;
510                                                                 }
511
512                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
513                                                         }
514                                                         else
515                                                         {
516                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
517                                                         }
518
519                                                         if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
520                                                                 continue;
521
522                                                         if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
523                                                         {
524                                                                 /* Check access to this mode character */
525                                                                 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
526                                                                 {
527                                                                         char needed = modehandlers[handler_id]->GetNeededPrefix();
528                                                                         ModeHandler* prefixmode = FindPrefix(needed);
529
530                                                                         /* If the mode defined by the handler is not '\0', but the handler for it
531                                                                          * cannot be found, they probably dont have the right module loaded to implement
532                                                                          * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
533                                                                          * Revert to checking against the minimum core prefix, '%'.
534                                                                          */
535                                                                         if (needed && !prefixmode)
536                                                                                 prefixmode = FindPrefix('%');
537                                                 
538                                                                         unsigned int neededrank = prefixmode->GetPrefixRank();
539                                                                         /* Compare our rank on the channel against the rank of the required prefix,
540                                                                          * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
541                                                                          * in NAMES(X) are not in rank order, we know the most powerful mode is listed
542                                                                          * first, so we don't need to iterate, we just look up the first instead.
543                                                                          */
544                                                                         std::string modestring = targetchannel->GetAllPrefixChars(user);
545                                                                         char ml = (modestring.empty() ? '\0' : modestring[0]);
546                                                                         ModeHandler* ourmode = FindPrefix(ml);
547                                                                         if (!ourmode || ourmode->GetPrefixRank() < neededrank)
548                                                                         {
549                                                                                 /* Bog off */
550                                                                                 user->WriteServ("482 %s %s :You must have channel privilege %c or above to %sset channel mode %c",
551                                                                                                 user->nick, targetchannel->name, needed, adding ? "" : "un", modechar);
552                                                                                 continue;
553                                                                         }
554                                                                 }
555                                                         }
556
557                                                         bool had_parameter = !parameter.empty();
558                                                                 
559                                                         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
560                                                         {
561                                                                 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
562                                                                 {
563                                                                         abort = true;
564                                                                         break;
565                                                                 }
566                                                                 /* A module whacked the parameter completely, and there was one. abort. */
567                                                                 if ((had_parameter) && (parameter.empty()))
568                                                                 {
569                                                                         abort = true;
570                                                                         break;
571                                                                 }
572                                                         }
573
574                                                         if (abort)
575                                                                 continue;
576
577                                                         /* It's an oper only mode, check if theyre an oper. If they arent,
578                                                          * eat any parameter that  came with the mode, and continue to next
579                                                          */
580                                                         if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))
581                                                         {
582                                                                 user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,
583                                                                                 adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
584                                                                                 modehandlers[handler_id]->GetModeChar());
585                                                                 continue;
586                                                         }
587
588                                                         /* Call the handler for the mode */
589                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
590
591                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
592                                                         {
593                                                                 /* The handler nuked the parameter and they are supposed to have one.
594                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
595                                                                  * so we bail to the next mode character.
596                                                                  */
597                                                                 continue;
598                                                         }
599
600                                                         if (ma == MODEACTION_ALLOW)
601                                                         {
602                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
603                                                                 if (state_change)
604                                                                 {
605                                                                         if (adding != last_successful_state_change)
606                                                                                 output_sequence.append(adding ? "+" : "-");
607                                                                         last_successful_state_change = adding;
608                                                                 }
609                                                                 
610                                                                 /* Add the mode letter */
611                                                                 output_sequence.push_back(modechar);
612
613                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
614
615                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
616                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
617                                                                 {
618                                                                         parameter_list << " " << parameter;
619                                                                         parameter_count++;
620                                                                         /* Does this mode have a prefix? */
621                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
622                                                                         {
623                                                                                 User* user_to_prefix = ServerInstance->FindNick(parameter);
624                                                                                 if (user_to_prefix)
625                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
626                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
627                                                                         }
628                                                                 }
629
630                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
631                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
632                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
633
634                                                                 /* Reset the state change flag */
635                                                                 state_change = false;
636
637                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
638                                                                                 || (parameter_count > MAXMODES))
639                                                                 {
640                                                                         /* We cant have a mode sequence this long */
641                                                                         letter = mode_sequence.end() - 1;
642                                                                         continue;
643                                                                 }
644                                                         }
645                                                 }
646                                         }
647                                         else
648                                         {
649                                                 /* No mode handler? Unknown mode character then. */
650                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
651                                         }
652                                 break;
653                         }
654                 }
655
656                 /* Was there at least one valid mode in the sequence? */
657                 if (!output_sequence.empty())
658                 {
659                         if (servermode)
660                         {
661                                 if (type == MODETYPE_CHANNEL)
662                                 {
663                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
664                                         this->LastParse = targetchannel->name;
665                                 }
666                                 else
667                                 {
668                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
669                                         this->LastParse = targetuser->nick;
670                                 }
671                         }
672                         else
673                         {
674                                 if (type == MODETYPE_CHANNEL)
675                                 {
676                                         targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
677                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
678                                         this->LastParse = targetchannel->name;
679                                 }
680                                 else
681                                 {
682                                         user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
683                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
684                                         this->LastParse = targetuser->nick;
685                                 }
686                         }
687
688                         LastParse.append(" ");
689                         LastParse.append(output_sequence);
690                         LastParse.append(parameter_list.str());
691                 }
692         }
693 }
694
695 const std::string& ModeParser::GetLastParse()
696 {
697         return LastParse;
698 }
699
700 void ModeParser::CleanMask(std::string &mask)
701 {
702         std::string::size_type pos_of_pling = mask.find_first_of('!');
703         std::string::size_type pos_of_at = mask.find_first_of('@');
704         std::string::size_type pos_of_dot = mask.find_first_of('.');
705         std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
706
707         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
708         {
709                 /* Just a nick, or just a host */
710                 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
711                 {
712                         /* It has no '.' in it, it must be a nick. */
713                         mask.append("!*@*");
714                 }
715                 else
716                 {
717                         /* Got a dot in it? Has to be a host */
718                         mask = "*!*@" + mask;
719                 }
720         }
721         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
722         {
723                 /* Has an @ but no !, its a user@host */
724                  mask = "*!" + mask;
725         }
726         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
727         {
728                 /* Has a ! but no @, it must be a nick!ident */
729                 mask.append("@*");
730         }
731 }
732
733 bool ModeParser::AddMode(ModeHandler* mh)
734 {
735         unsigned char mask = 0;
736         unsigned char pos = 0;
737
738         /* Yes, i know, this might let people declare modes like '_' or '^'.
739          * If they do that, thats their problem, and if i ever EVER see an
740          * official InspIRCd developer do that, i'll beat them with a paddle!
741          */
742         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
743                 return false;
744
745         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
746          * A mode prefix of ':' will fuck up both server to server, and client to server.
747          * A mode prefix of '#' will mess up /whois and /privmsg
748          */
749         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
750                 return false;
751
752         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
753         pos = (mh->GetModeChar()-65) | mask;
754
755         if (modehandlers[pos])
756                 return false;
757
758         modehandlers[pos] = mh;
759         return true;
760 }
761
762 bool ModeParser::DelMode(ModeHandler* mh)
763 {
764         unsigned char mask = 0;
765         unsigned char pos = 0;
766
767         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
768                 return false;
769
770         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
771         pos = (mh->GetModeChar()-65) | mask;
772
773         if (!modehandlers[pos])
774                 return false;
775
776         switch (mh->GetModeType())
777         {
778                 case MODETYPE_USER:
779                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
780                         {
781                                 mh->RemoveMode(i->second);
782                         }
783                 break;
784                 case MODETYPE_CHANNEL:
785                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
786                         {
787                                 mh->RemoveMode(i->second);
788                         }
789                 break;
790         }
791
792         modehandlers[pos] = NULL;
793
794         return true;
795 }
796
797 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
798 {
799         unsigned char mask = 0;
800         unsigned char pos = 0;
801
802         if ((modeletter < 'A') || (modeletter > 'z'))
803                 return NULL;
804
805         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
806         pos = (modeletter-65) | mask;
807
808         return modehandlers[pos];
809 }
810
811 std::string ModeParser::UserModeList()
812 {
813         char modestr[256];
814         int pointer = 0;
815
816         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
817         {
818                 unsigned char pos = (mode-65) | MASK_USER;
819
820                 if (modehandlers[pos])
821                         modestr[pointer++] = mode;
822         }
823         modestr[pointer++] = 0;
824         return modestr;
825 }
826
827 std::string ModeParser::ChannelModeList()
828 {
829         char modestr[256];
830         int pointer = 0;
831
832         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
833         {
834                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
835                         continue;
836
837                 unsigned char pos = (mode-65) | MASK_CHANNEL;
838
839                 if (modehandlers[pos])
840                         modestr[pointer++] = mode;
841         }
842         modestr[pointer++] = 0;
843         return modestr;
844 }
845
846 std::string ModeParser::ParaModeList()
847 {
848         char modestr[256];
849         int pointer = 0;
850
851         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
852         {
853                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
854                         continue;
855
856                 unsigned char pos = (mode-65) | MASK_CHANNEL;
857
858                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
859                         modestr[pointer++] = mode;
860         }
861         modestr[pointer++] = 0;
862         return modestr;
863 }
864
865 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
866 {
867         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
868         {
869                 unsigned char pos = (mode-65) | MASK_CHANNEL;
870
871                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
872                 {
873                         return modehandlers[pos];
874                 }
875         }
876         return NULL;
877 }
878
879 std::string ModeParser::ModeString(User* user, Channel* channel)
880 {
881         std::string types;
882         std::string pars;
883
884         if (!channel || !user)
885                 return "";
886
887         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
888         {
889                 unsigned char pos = (mode-65) | MASK_CHANNEL;
890                 ModeHandler* mh = modehandlers[pos];
891                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
892                 {
893                         ModePair ret;
894                         ret = mh->ModeSet(NULL, user, channel, user->nick);
895                         if ((ret.first) && (ret.second == user->nick))
896                         {
897                                 pars.append(" ");
898                                 pars.append(user->nick);
899                                 types.push_back(mh->GetModeChar());
900                         }
901                 }
902         }
903
904         return types+pars;
905 }
906
907 std::string ModeParser::ChanModes()
908 {
909         std::string type1;      /* Listmodes EXCEPT those with a prefix */
910         std::string type2;      /* Modes that take a param when adding or removing */
911         std::string type3;      /* Modes that only take a param when adding */
912         std::string type4;      /* Modes that dont take a param */
913
914         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
915         {
916                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
917                         continue;
918
919                 unsigned char pos = (mode-65) | MASK_CHANNEL;
920                  /* One parameter when adding */
921                 if (modehandlers[pos])
922                 {       
923                         if (modehandlers[pos]->GetNumParams(true))
924                         {
925                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
926                                 {
927                                         type1 += modehandlers[pos]->GetModeChar();
928                                 }
929                                 else
930                                 {
931                                         /* ... and one parameter when removing */
932                                         if (modehandlers[pos]->GetNumParams(false))
933                                         {
934                                                 /* But not a list mode */
935                                                 if (!modehandlers[pos]->GetPrefix())
936                                                 {
937                                                         type2 += modehandlers[pos]->GetModeChar();
938                                                 }
939                                         }
940                                         else
941                                         {
942                                                 /* No parameters when removing */
943                                                 type3 += modehandlers[pos]->GetModeChar();
944                                         }
945                                 }
946                         }
947                         else
948                         {
949                                 type4 += modehandlers[pos]->GetModeChar();
950                         }
951                 }
952                          
953         }
954
955         return type1 + "," + type2 + "," + type3 + "," + type4;
956 }
957
958 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
959 {       
960         return one.second > two.second;
961 }
962
963 std::string ModeParser::BuildPrefixes()
964 {
965         std::string mletters;
966         std::string mprefixes;
967         pfxcontainer pfx;
968         std::map<char,char> prefix_to_mode;
969
970         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
971         {
972                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
973                         continue;
974
975                 unsigned char pos = (mode-65) | MASK_CHANNEL;
976
977                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
978                 {
979                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
980                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
981                 }
982         }
983
984         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
985
986         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
987         {
988                 mletters = mletters + n->first;
989                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
990         }
991
992         return "(" + mprefixes + ")" + mletters;
993 }
994
995 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
996 {
997         unsigned char mask = 0;
998         unsigned char pos = 0;
999
1000         if (!mw)
1001                 return false;
1002
1003         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1004                 return false;
1005
1006         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1007         pos = (mw->GetModeChar()-65) | mask;
1008
1009         modewatchers[pos].push_back(mw);
1010
1011         return true;
1012 }
1013
1014 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1015 {
1016         unsigned char mask = 0;
1017         unsigned char pos = 0;
1018
1019         if (!mw)
1020                 return false;
1021
1022         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1023                 return false;
1024
1025         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1026         pos = (mw->GetModeChar()-65) | mask;
1027
1028         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1029
1030         if (a == modewatchers[pos].end())
1031         {
1032                 return false;
1033         }
1034
1035         modewatchers[pos].erase(a);
1036
1037         return true;
1038 }
1039
1040 /** This default implementation can remove simple user modes
1041  */
1042 void ModeHandler::RemoveMode(User* user)
1043 {
1044         char moderemove[MAXBUF];
1045         const char* parameters[] = { user->nick, moderemove };
1046
1047         if (user->IsModeSet(this->GetModeChar()))
1048         {
1049                 sprintf(moderemove,"-%c",this->GetModeChar());
1050                 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1051         }
1052 }
1053
1054 /** This default implementation can remove simple channel modes
1055  * (no parameters)
1056  */
1057 void ModeHandler::RemoveMode(Channel* channel)
1058 {
1059         char moderemove[MAXBUF];
1060         const char* parameters[] = { channel->name, moderemove };
1061
1062         if (channel->IsModeSet(this->GetModeChar()))
1063         {
1064                 sprintf(moderemove,"-%c",this->GetModeChar());
1065                 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1066         }
1067 }
1068
1069 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1070 {
1071         ModeHandler* modes[] =
1072         {
1073                 new ModeChannelSecret(Instance),
1074                 new ModeChannelPrivate(Instance),
1075                 new ModeChannelModerated(Instance),
1076                 new ModeChannelTopicOps(Instance),
1077                 new ModeChannelNoExternal(Instance),
1078                 new ModeChannelInviteOnly(Instance),
1079                 new ModeChannelKey(Instance),
1080                 new ModeChannelLimit(Instance),
1081                 new ModeChannelBan(Instance),
1082                 new ModeChannelOp(Instance),
1083                 new ModeChannelHalfOp(Instance),
1084                 new ModeChannelVoice(Instance),
1085                 new ModeUserServerNotice(Instance),
1086                 new ModeUserWallops(Instance),
1087                 new ModeUserInvisible(Instance),
1088                 new ModeUserOperator(Instance),
1089                 new ModeUserServerNoticeMask(Instance),
1090                 NULL
1091         };
1092
1093         /* Clear mode list */
1094         memset(modehandlers, 0, sizeof(modehandlers));
1095         memset(modewatchers, 0, sizeof(modewatchers));
1096
1097         /* Last parse string */
1098         LastParse.clear();
1099
1100         /* Initialise the RFC mode letters */
1101         for (int index = 0; modes[index]; index++)
1102                 this->AddMode(modes[index]);
1103 }