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