]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Add an optional bool to ModeParser::ModeString() to not give the nickname n times...
[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->WriteNumeric(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->WriteNumeric(324, "%s %s +%s",user->nick, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));
261                 user->WriteNumeric(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->WriteNumeric(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->WriteNumeric(221, "%s :+%s",targetuser->nick,targetuser->FormatModes());
276                         if (IS_OPER(targetuser))
277                                 user->WriteNumeric(8, "%s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());
278                         return;
279                 }
280                 else
281                 {
282                         user->WriteNumeric(502, "%s :Can't change mode for other users", user->nick);
283                         return;
284                 }
285         }
286
287         /* No such nick/channel */
288         user->WriteNumeric(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->WriteNumeric(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->WriteNumeric(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->WriteNumeric(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->WriteNumeric(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()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
581                                                         {
582                                                                 user->WriteNumeric(481, "%s :Permission Denied - Oper type %s does not have access to %sset %s mode %c",
583                                                                                 user->nick,
584                                                                                 user->oper,
585                                                                                 adding ? "" : "un",
586                                                                                 type == MODETYPE_CHANNEL ? "channel" : "user",
587                                                                                 modehandlers[handler_id]->GetModeChar());
588                                                                 continue;
589                                                         }
590
591                                                         /* Call the handler for the mode */
592                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
593
594                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
595                                                         {
596                                                                 /* The handler nuked the parameter and they are supposed to have one.
597                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
598                                                                  * so we bail to the next mode character.
599                                                                  */
600                                                                 continue;
601                                                         }
602
603                                                         if (ma == MODEACTION_ALLOW)
604                                                         {
605                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
606                                                                 if (state_change)
607                                                                 {
608                                                                         if (adding != last_successful_state_change)
609                                                                                 output_sequence.append(adding ? "+" : "-");
610                                                                         last_successful_state_change = adding;
611                                                                 }
612                                                                 
613                                                                 /* Add the mode letter */
614                                                                 output_sequence.push_back(modechar);
615
616                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
617
618                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
619                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
620                                                                 {
621                                                                         parameter_list << " " << parameter;
622                                                                         parameter_count++;
623                                                                         /* Does this mode have a prefix? */
624                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
625                                                                         {
626                                                                                 User* user_to_prefix = ServerInstance->FindNick(parameter);
627                                                                                 if (user_to_prefix)
628                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
629                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
630                                                                         }
631                                                                 }
632
633                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
634                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
635                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
636
637                                                                 /* Reset the state change flag */
638                                                                 state_change = false;
639
640                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
641                                                                                 || (parameter_count > MAXMODES))
642                                                                 {
643                                                                         /* We cant have a mode sequence this long */
644                                                                         letter = mode_sequence.end() - 1;
645                                                                         continue;
646                                                                 }
647                                                         }
648                                                 }
649                                         }
650                                         else
651                                         {
652                                                 /* No mode handler? Unknown mode character then. */
653                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
654                                         }
655                                 break;
656                         }
657                 }
658
659                 /* Was there at least one valid mode in the sequence? */
660                 if (!output_sequence.empty())
661                 {
662                         if (servermode)
663                         {
664                                 if (type == MODETYPE_CHANNEL)
665                                 {
666                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
667                                         this->LastParse = targetchannel->name;
668                                 }
669                                 else
670                                 {
671                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
672                                         this->LastParse = targetuser->nick;
673                                 }
674                         }
675                         else
676                         {
677                                 if (type == MODETYPE_CHANNEL)
678                                 {
679                                         targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
680                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
681                                         this->LastParse = targetchannel->name;
682                                 }
683                                 else
684                                 {
685                                         user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
686                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
687                                         this->LastParse = targetuser->nick;
688                                 }
689                         }
690
691                         LastParse.append(" ");
692                         LastParse.append(output_sequence);
693                         LastParse.append(parameter_list.str());
694                 }
695         }
696 }
697
698 const std::string& ModeParser::GetLastParse()
699 {
700         return LastParse;
701 }
702
703 void ModeParser::CleanMask(std::string &mask)
704 {
705         std::string::size_type pos_of_pling = mask.find_first_of('!');
706         std::string::size_type pos_of_at = mask.find_first_of('@');
707         std::string::size_type pos_of_dot = mask.find_first_of('.');
708         std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
709
710         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
711         {
712                 /* Just a nick, or just a host */
713                 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
714                 {
715                         /* It has no '.' in it, it must be a nick. */
716                         mask.append("!*@*");
717                 }
718                 else
719                 {
720                         /* Got a dot in it? Has to be a host */
721                         mask = "*!*@" + mask;
722                 }
723         }
724         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
725         {
726                 /* Has an @ but no !, its a user@host */
727                  mask = "*!" + mask;
728         }
729         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
730         {
731                 /* Has a ! but no @, it must be a nick!ident */
732                 mask.append("@*");
733         }
734 }
735
736 bool ModeParser::AddMode(ModeHandler* mh)
737 {
738         unsigned char mask = 0;
739         unsigned char pos = 0;
740
741         /* Yes, i know, this might let people declare modes like '_' or '^'.
742          * If they do that, thats their problem, and if i ever EVER see an
743          * official InspIRCd developer do that, i'll beat them with a paddle!
744          */
745         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
746                 return false;
747
748         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
749          * A mode prefix of ':' will fuck up both server to server, and client to server.
750          * A mode prefix of '#' will mess up /whois and /privmsg
751          */
752         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
753                 return false;
754
755         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
756         pos = (mh->GetModeChar()-65) | mask;
757
758         if (modehandlers[pos])
759                 return false;
760
761         modehandlers[pos] = mh;
762         return true;
763 }
764
765 bool ModeParser::DelMode(ModeHandler* mh)
766 {
767         unsigned char mask = 0;
768         unsigned char pos = 0;
769
770         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
771                 return false;
772
773         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
774         pos = (mh->GetModeChar()-65) | mask;
775
776         if (!modehandlers[pos])
777                 return false;
778
779         switch (mh->GetModeType())
780         {
781                 case MODETYPE_USER:
782                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
783                         {
784                                 mh->RemoveMode(i->second);
785                         }
786                 break;
787                 case MODETYPE_CHANNEL:
788                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
789                         {
790                                 mh->RemoveMode(i->second);
791                         }
792                 break;
793         }
794
795         modehandlers[pos] = NULL;
796
797         return true;
798 }
799
800 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
801 {
802         unsigned char mask = 0;
803         unsigned char pos = 0;
804
805         if ((modeletter < 'A') || (modeletter > 'z'))
806                 return NULL;
807
808         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
809         pos = (modeletter-65) | mask;
810
811         return modehandlers[pos];
812 }
813
814 std::string ModeParser::UserModeList()
815 {
816         char modestr[256];
817         int pointer = 0;
818
819         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
820         {
821                 unsigned char pos = (mode-65) | MASK_USER;
822
823                 if (modehandlers[pos])
824                         modestr[pointer++] = mode;
825         }
826         modestr[pointer++] = 0;
827         return modestr;
828 }
829
830 std::string ModeParser::ChannelModeList()
831 {
832         char modestr[256];
833         int pointer = 0;
834
835         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
836         {
837                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
838                         continue;
839
840                 unsigned char pos = (mode-65) | MASK_CHANNEL;
841
842                 if (modehandlers[pos])
843                         modestr[pointer++] = mode;
844         }
845         modestr[pointer++] = 0;
846         return modestr;
847 }
848
849 std::string ModeParser::ParaModeList()
850 {
851         char modestr[256];
852         int pointer = 0;
853
854         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
855         {
856                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
857                         continue;
858
859                 unsigned char pos = (mode-65) | MASK_CHANNEL;
860
861                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
862                         modestr[pointer++] = mode;
863         }
864         modestr[pointer++] = 0;
865         return modestr;
866 }
867
868 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
869 {
870         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
871         {
872                 unsigned char pos = (mode-65) | MASK_CHANNEL;
873
874                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
875                 {
876                         return modehandlers[pos];
877                 }
878         }
879         return NULL;
880 }
881
882 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
883 {
884         std::string types;
885         std::string pars;
886
887         if (!channel || !user)
888                 return "";
889
890         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
891         {
892                 unsigned char pos = (mode-65) | MASK_CHANNEL;
893                 ModeHandler* mh = modehandlers[pos];
894                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
895                 {
896                         ModePair ret;
897                         ret = mh->ModeSet(NULL, user, channel, user->nick);
898                         if ((ret.first) && (ret.second == user->nick))
899                         {
900                                 if (nick_suffix)
901                                 {
902                                         pars.append(" ");
903                                         pars.append(user->nick);
904                                 }
905                                 types.push_back(mh->GetModeChar());
906                         }
907                 }
908         }
909
910         if (nick_suffix)
911                 return types+pars;
912         else
913                 return types;
914 }
915
916 std::string ModeParser::ChanModes()
917 {
918         std::string type1;      /* Listmodes EXCEPT those with a prefix */
919         std::string type2;      /* Modes that take a param when adding or removing */
920         std::string type3;      /* Modes that only take a param when adding */
921         std::string type4;      /* Modes that dont take a param */
922
923         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
924         {
925                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
926                         continue;
927
928                 unsigned char pos = (mode-65) | MASK_CHANNEL;
929                  /* One parameter when adding */
930                 if (modehandlers[pos])
931                 {       
932                         if (modehandlers[pos]->GetNumParams(true))
933                         {
934                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
935                                 {
936                                         type1 += modehandlers[pos]->GetModeChar();
937                                 }
938                                 else
939                                 {
940                                         /* ... and one parameter when removing */
941                                         if (modehandlers[pos]->GetNumParams(false))
942                                         {
943                                                 /* But not a list mode */
944                                                 if (!modehandlers[pos]->GetPrefix())
945                                                 {
946                                                         type2 += modehandlers[pos]->GetModeChar();
947                                                 }
948                                         }
949                                         else
950                                         {
951                                                 /* No parameters when removing */
952                                                 type3 += modehandlers[pos]->GetModeChar();
953                                         }
954                                 }
955                         }
956                         else
957                         {
958                                 type4 += modehandlers[pos]->GetModeChar();
959                         }
960                 }
961                          
962         }
963
964         return type1 + "," + type2 + "," + type3 + "," + type4;
965 }
966
967 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
968 {       
969         return one.second > two.second;
970 }
971
972 std::string ModeParser::BuildPrefixes()
973 {
974         std::string mletters;
975         std::string mprefixes;
976         pfxcontainer pfx;
977         std::map<char,char> prefix_to_mode;
978
979         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
980         {
981                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
982                         continue;
983
984                 unsigned char pos = (mode-65) | MASK_CHANNEL;
985
986                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
987                 {
988                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
989                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
990                 }
991         }
992
993         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
994
995         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
996         {
997                 mletters = mletters + n->first;
998                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
999         }
1000
1001         return "(" + mprefixes + ")" + mletters;
1002 }
1003
1004 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1005 {
1006         unsigned char mask = 0;
1007         unsigned char pos = 0;
1008
1009         if (!mw)
1010                 return false;
1011
1012         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1013                 return false;
1014
1015         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1016         pos = (mw->GetModeChar()-65) | mask;
1017
1018         modewatchers[pos].push_back(mw);
1019
1020         return true;
1021 }
1022
1023 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1024 {
1025         unsigned char mask = 0;
1026         unsigned char pos = 0;
1027
1028         if (!mw)
1029                 return false;
1030
1031         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1032                 return false;
1033
1034         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1035         pos = (mw->GetModeChar()-65) | mask;
1036
1037         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1038
1039         if (a == modewatchers[pos].end())
1040         {
1041                 return false;
1042         }
1043
1044         modewatchers[pos].erase(a);
1045
1046         return true;
1047 }
1048
1049 /** This default implementation can remove simple user modes
1050  */
1051 void ModeHandler::RemoveMode(User* user)
1052 {
1053         char moderemove[MAXBUF];
1054         const char* parameters[] = { user->nick, moderemove };
1055
1056         if (user->IsModeSet(this->GetModeChar()))
1057         {
1058                 sprintf(moderemove,"-%c",this->GetModeChar());
1059                 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1060         }
1061 }
1062
1063 /** This default implementation can remove simple channel modes
1064  * (no parameters)
1065  */
1066 void ModeHandler::RemoveMode(Channel* channel)
1067 {
1068         char moderemove[MAXBUF];
1069         const char* parameters[] = { channel->name, moderemove };
1070
1071         if (channel->IsModeSet(this->GetModeChar()))
1072         {
1073                 sprintf(moderemove,"-%c",this->GetModeChar());
1074                 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1075         }
1076 }
1077
1078 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1079 {
1080         ModeHandler* modes[] =
1081         {
1082                 new ModeChannelSecret(Instance),
1083                 new ModeChannelPrivate(Instance),
1084                 new ModeChannelModerated(Instance),
1085                 new ModeChannelTopicOps(Instance),
1086                 new ModeChannelNoExternal(Instance),
1087                 new ModeChannelInviteOnly(Instance),
1088                 new ModeChannelKey(Instance),
1089                 new ModeChannelLimit(Instance),
1090                 new ModeChannelBan(Instance),
1091                 new ModeChannelOp(Instance),
1092                 new ModeChannelHalfOp(Instance),
1093                 new ModeChannelVoice(Instance),
1094                 new ModeUserServerNotice(Instance),
1095                 new ModeUserWallops(Instance),
1096                 new ModeUserInvisible(Instance),
1097                 new ModeUserOperator(Instance),
1098                 new ModeUserServerNoticeMask(Instance),
1099                 NULL
1100         };
1101
1102         /* Clear mode list */
1103         memset(modehandlers, 0, sizeof(modehandlers));
1104         memset(modewatchers, 0, sizeof(modewatchers));
1105
1106         /* Last parse string */
1107         LastParse.clear();
1108
1109         /* Initialise the RFC mode letters */
1110         for (int index = 0; modes[index]; index++)
1111                 this->AddMode(modes[index]);
1112 }