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