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