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