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