]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_delayjoin.cpp
Membership* changes
[user/henk/code/inspircd.git] / src / modules / m_delayjoin.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *          the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include <stdarg.h>
16
17 class DelayJoinMode : public ModeHandler
18 {
19  private:
20         CUList empty;
21  public:
22         DelayJoinMode(InspIRCd* Instance, Module* Parent) : ModeHandler(Instance, Parent, 'D', 0, 0, false, MODETYPE_CHANNEL, false, 0, '@') {};
23
24         ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding);
25 };
26
27 class ModuleDelayJoin : public Module
28 {
29         DelayJoinMode djm;
30  public:
31         LocalIntExt unjoined;
32         ModuleDelayJoin(InspIRCd* Me) : Module(Me), djm(Me, this), unjoined("delayjoin", this)
33         {
34                 if (!ServerInstance->Modes->AddMode(&djm))
35                         throw ModuleException("Could not add new modes!");
36                 Implementation eventlist[] = { I_OnUserJoin, I_OnUserPart, I_OnUserKick, I_OnUserQuit, I_OnNamesListItem, I_OnText, I_OnHostCycle };
37                 ServerInstance->Modules->Attach(eventlist, this, 7);
38         }
39         ~ModuleDelayJoin();
40         Version GetVersion();
41         void OnNamesListItem(User* issuer, User* user, Channel* channel, std::string &prefixes, std::string &nick);
42         void OnUserJoin(User* user, Channel* channel, bool sync, bool &silent, bool created);
43         void CleanUser(User* user);
44         ModResult OnHostCycle(User* user);
45         void OnUserPart(User* user, Channel* channel, std::string &partmessage, bool &silent);
46         void OnUserKick(User* source, User* user, Channel* chan, const std::string &reason, bool &silent);
47         void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message);
48         void OnText(User* user, void* dest, int target_type, const std::string &text, char status, CUList &exempt_list);
49         void WriteCommonFrom(User *user, Channel* channel, const char* text, ...) CUSTOM_PRINTF(4, 5);
50 };
51
52 /* $ModDesc: Allows for delay-join channels (+D) where users dont appear to join until they speak */
53
54 ModeAction DelayJoinMode::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
55 {
56         /* no change */
57         if (channel->IsModeSet('D') == adding)
58                 return MODEACTION_DENY;
59
60         if (!adding)
61         {
62                 /*
63                  * Make all users visible, as +D is being removed. If we don't do this,
64                  * they remain permanently invisible on this channel!
65                  */
66                 const UserMembList* names = channel->GetUsers();
67                 for (UserMembCIter n = names->begin(); n != names->end(); ++n)
68                         creator->OnText(n->first, channel, TYPE_CHANNEL, "", 0, empty);
69         }
70         channel->SetMode('D', adding);
71         return MODEACTION_ALLOW;
72 }
73
74 ModuleDelayJoin::~ModuleDelayJoin()
75 {
76         ServerInstance->Modes->DelMode(&djm);
77 }
78
79 Version ModuleDelayJoin::GetVersion()
80 {
81         return Version("$Id$", VF_COMMON | VF_VENDOR);
82 }
83
84 void ModuleDelayJoin::OnNamesListItem(User* issuer, User* user, Channel* channel, std::string &prefixes, std::string &nick)
85 {
86         if (!channel->IsModeSet('D'))
87                 return;
88
89         if (nick.empty())
90                 return;
91
92         /* don't prevent the user from seeing themself */
93         if (issuer == user)
94                 return;
95
96         Membership* memb = channel->GetUser(user);
97         /* If the user is hidden by delayed join, hide them from the NAMES list */
98         if (memb && unjoined.get(memb))
99                 nick.clear();
100 }
101
102 void ModuleDelayJoin::OnUserJoin(User* user, Channel* channel, bool sync, bool &silent, bool created)
103 {
104         if (channel->IsModeSet('D'))
105         {
106                 silent = true;
107                 /* Because we silenced the event, make sure it reaches the user whos joining (but only them of course) */
108                 user->WriteFrom(user, "JOIN %s", channel->name.c_str());
109
110                 Membership* memb = channel->GetUser(user);
111
112                 unjoined.set(memb, 1);
113         }
114 }
115
116 void ModuleDelayJoin::OnUserPart(User* user, Channel* channel, std::string &partmessage, bool &silent)
117 {
118         Membership* memb = channel->GetUser(user);
119         if (unjoined.set(memb, 0))
120         {
121                 silent = true;
122                 /* Because we silenced the event, make sure it reaches the user whos leaving (but only them of course) */
123                 user->WriteFrom(user, "PART %s%s%s", channel->name.c_str(), partmessage.empty() ? "" : " :", partmessage.empty() ? "" : partmessage.c_str());
124         }
125 }
126
127 void ModuleDelayJoin::OnUserKick(User* source, User* user, Channel* chan, const std::string &reason, bool &silent)
128 {
129         Membership* memb = chan->GetUser(user);
130         if (unjoined.set(memb, 0))
131         {
132                 silent = true;
133                 user->WriteFrom(source, "KICK %s %s %s", chan->name.c_str(), user->nick.c_str(), reason.c_str());
134         }
135 }
136
137 ModResult ModuleDelayJoin::OnHostCycle(User* user)
138 {
139         // TODO
140         return MOD_RES_DENY;
141 }
142
143 void ModuleDelayJoin::OnUserQuit(User* user, const std::string &reason, const std::string &oper_message)
144 {
145         Command* parthandler = ServerInstance->Parser->GetHandler("PART");
146         if (!parthandler)
147                 return;
148         for (UCListIter f = user->chans.begin(); f != user->chans.end(); f++)
149         {
150                 Channel* chan = *f;
151                 Membership* memb = chan->GetUser(user);
152                 if (memb && unjoined.get(memb))
153                 {
154                         std::vector<std::string> parameters;
155                         parameters.push_back(chan->name);
156                         /* Send a fake PART from the channel, which will be silent */
157                         parthandler->Handle(parameters, user);
158                 }
159         }
160 }
161
162 void ModuleDelayJoin::OnText(User* user, void* dest, int target_type, const std::string &text, char status, CUList &exempt_list)
163 {
164         /* Server origin */
165         if (!user)
166                 return;
167
168         if (target_type != TYPE_CHANNEL)
169                 return;
170
171         Channel* channel = (Channel*) dest;
172
173         Membership* memb = channel->GetUser(user);
174         if (!memb || !unjoined.set(memb, 0))
175                 return;
176
177         /* Display the join to everyone else (the user who joined got it earlier) */
178         channel->WriteAllExceptSender(user, false, 0, "JOIN %s", channel->name.c_str());
179
180         std::string n = this->ServerInstance->Modes->ModeString(user, channel);
181         if (n.length() > 0)
182                 this->WriteCommonFrom(user, channel, "MODE %s +%s", channel->name.c_str(), n.c_str());
183 }
184
185 MODULE_INIT(ModuleDelayJoin)
186