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