00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "inspircd.h"
00015 #include <stdarg.h>
00016
00017
00018
00019 static ConfigReader* conf;
00020
00021 class QuietOper : public VisData
00022 {
00023 public:
00024 QuietOper()
00025 {
00026 }
00027
00028 virtual ~QuietOper()
00029 {
00030 }
00031
00032 virtual bool VisibleTo(User* user)
00033 {
00034 return IS_OPER(user);
00035 }
00036 };
00037
00038
00039 class InvisibleMode : public ModeHandler
00040 {
00041 QuietOper* qo;
00042 public:
00043 InvisibleMode(InspIRCd* Instance) : ModeHandler(Instance, 'Q', 0, 0, false, MODETYPE_USER, true)
00044 {
00045 qo = new QuietOper();
00046 }
00047
00048 ~InvisibleMode()
00049 {
00050 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
00051 if (i->second->Visibility == qo)
00052 i->second->Visibility = NULL;
00053 delete qo;
00054 }
00055
00056 ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool)
00057 {
00058 if (source != dest)
00059 return MODEACTION_DENY;
00060
00061 if (dest->IsModeSet('Q') != adding)
00062 {
00063 bool ok = false;
00064
00065 for (int j = 0; j < conf->Enumerate("type"); j++)
00066 {
00067 std::string opertype = conf->ReadValue("type","name",j);
00068 if (opertype == source->oper)
00069 {
00070 ok = conf->ReadFlag("type", "canquiet", j);
00071 break;
00072 }
00073 }
00074
00075 if (!ok)
00076 {
00077 source->WriteNumeric(481, "%s :Permission Denied - You do not have access to become invisible via user mode +Q", source->nick.c_str());
00078 return MODEACTION_DENY;
00079 }
00080
00081 dest->SetMode('Q', adding);
00082
00083
00084 Module* m = ServerInstance->Modules->Find("m_watch.so");
00085
00086
00087 if (m && adding)
00088 m->OnUserQuit(dest, "Connection closed", "Connection closed");
00089
00090
00091 dest->Visibility = adding ? qo : NULL;
00092
00093
00094 if (m && !adding)
00095 m->OnPostConnect(dest);
00096
00097
00098 for (UCListIter f = dest->chans.begin(); f != dest->chans.end(); f++)
00099 {
00100 CUList *ulist = f->first->GetUsers();
00101 char tb[MAXBUF];
00102
00103 snprintf(tb,MAXBUF,":%s %s %s", dest->GetFullHost().c_str(), adding ? "PART" : "JOIN", f->first->name.c_str());
00104 std::string out = tb;
00105 std::string n = this->ServerInstance->Modes->ModeString(dest, f->first);
00106
00107 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
00108 {
00109
00110 if (IS_LOCAL(i->first) && !IS_OPER(i->first))
00111 {
00112 i->first->Write(out);
00113 if (!n.empty() && !adding)
00114 i->first->WriteServ("MODE %s +%s", f->first->name.c_str(), n.c_str());
00115 }
00116 }
00117 }
00118
00119 ServerInstance->SNO->WriteToSnoMask('A', "\2NOTICE\2: Oper %s has become %svisible (%sQ)", dest->GetFullHost().c_str(), adding ? "in" : "", adding ? "+" : "-");
00120 return MODEACTION_ALLOW;
00121 }
00122 else
00123 {
00124 return MODEACTION_DENY;
00125 }
00126 }
00127 };
00128
00129 class InvisibleDeOper : public ModeWatcher
00130 {
00131 private:
00132 InspIRCd* Srv;
00133 public:
00134 InvisibleDeOper(InspIRCd* Instance) : ModeWatcher(Instance, 'o', MODETYPE_USER), Srv(Instance)
00135 {
00136 }
00137
00138 bool BeforeMode(User* source, User* dest, Channel* channel, std::string ¶m, bool adding, ModeType type, bool)
00139 {
00140
00141 if ((!adding) && (dest->IsModeSet('Q')))
00142 {
00143 std::vector<std::string> newmodes;
00144 newmodes.push_back(dest->nick);
00145 newmodes.push_back("-Q");
00146 ServerInstance->Modes->Process(newmodes, source, true);
00147 }
00148 return true;
00149 }
00150 };
00151
00152
00153 class ModuleInvisible : public Module
00154 {
00155 private:
00156 InvisibleMode* qm;
00157 InvisibleDeOper* ido;
00158 public:
00159 ModuleInvisible(InspIRCd* Me)
00160 : Module(Me)
00161 {
00162 conf = new ConfigReader(ServerInstance);
00163 qm = new InvisibleMode(ServerInstance);
00164 if (!ServerInstance->Modes->AddMode(qm))
00165 throw ModuleException("Could not add new modes!");
00166 ido = new InvisibleDeOper(ServerInstance);
00167 if (!ServerInstance->Modes->AddModeWatcher(ido))
00168 throw ModuleException("Could not add new mode watcher on usermode +o!");
00169
00170
00171 ServerInstance->Users->ServerNoticeAll("*** m_invisible.so has just been loaded on this network. For more information, please visit http://inspircd.org/wiki/Modules/invisible");
00172 Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserJoin, I_OnUserPart, I_OnUserQuit, I_OnRehash };
00173 ServerInstance->Modules->Attach(eventlist, this, 6);
00174 };
00175
00176 virtual ~ModuleInvisible()
00177 {
00178 ServerInstance->Modes->DelMode(qm);
00179 ServerInstance->Modes->DelModeWatcher(ido);
00180 delete qm;
00181 delete ido;
00182 delete conf;
00183 };
00184
00185 virtual Version GetVersion();
00186 virtual void OnUserJoin(User* user, Channel* channel, bool sync, bool &silent);
00187 virtual void OnRehash(User* user, const std::string ¶meter);
00188 void OnUserPart(User* user, Channel* channel, std::string &partmessage, bool &silent);
00189 void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message);
00190
00191 virtual int OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
00192 virtual int OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
00193
00194 void WriteCommonFrom(User *user, Channel* channel, const char* text, ...) CUSTOM_PRINTF(4, 5);
00195 };
00196
00197 Version ModuleInvisible::GetVersion()
00198 {
00199 return Version("$Id: m_invisible.cpp 10336 2008-08-28 19:12:49Z w00t $", VF_COMMON | VF_VENDOR, API_VERSION);
00200 }
00201
00202 void ModuleInvisible::OnUserJoin(User* user, Channel* channel, bool sync, bool &silent)
00203 {
00204 if (user->IsModeSet('Q'))
00205 {
00206 silent = true;
00207
00208 this->WriteCommonFrom(user, channel, "JOIN %s", channel->name.c_str());
00209 ServerInstance->SNO->WriteToSnoMask('A', "\2NOTICE\2: Oper %s has joined %s invisibly (+Q)", user->GetFullHost().c_str(), channel->name.c_str());
00210 }
00211 }
00212
00213 void ModuleInvisible::OnRehash(User* user, const std::string ¶meter)
00214 {
00215 delete conf;
00216 conf = new ConfigReader(ServerInstance);
00217 }
00218
00219 void ModuleInvisible::OnUserPart(User* user, Channel* channel, std::string &partmessage, bool &silent)
00220 {
00221 if (user->IsModeSet('Q'))
00222 {
00223 silent = true;
00224
00225 this->WriteCommonFrom(user, channel, "PART %s%s%s", channel->name.c_str(),
00226 partmessage.empty() ? "" : " :",
00227 partmessage.empty() ? "" : partmessage.c_str());
00228 }
00229 }
00230
00231 void ModuleInvisible::OnUserQuit(User* user, const std::string &reason, const std::string &oper_message)
00232 {
00233 if (user->IsModeSet('Q'))
00234 {
00235 Command* parthandler = ServerInstance->Parser->GetHandler("PART");
00236 std::vector<std::string> to_leave;
00237 if (parthandler)
00238 {
00239 for (UCListIter f = user->chans.begin(); f != user->chans.end(); f++)
00240 to_leave.push_back(f->first->name);
00241
00242 for (std::vector<std::string>::iterator n = to_leave.begin(); n != to_leave.end(); n++)
00243 {
00244 std::vector<std::string> parameters;
00245 parameters.push_back(*n);
00246
00247 parthandler->Handle(parameters, user);
00248 }
00249 }
00250 }
00251 }
00252
00253
00254 int ModuleInvisible::OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
00255 {
00256 if ((target_type == TYPE_USER) && (IS_LOCAL(user)))
00257 {
00258 User* target = (User*)dest;
00259 if(target->IsModeSet('Q') && !IS_OPER(user))
00260 {
00261 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), target->nick.c_str());
00262 return 1;
00263 }
00264 }
00265 return 0;
00266 }
00267
00268 int ModuleInvisible::OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
00269 {
00270 return OnUserPreNotice(user, dest, target_type, text, status, exempt_list);
00271 }
00272
00273
00274 void ModuleInvisible::WriteCommonFrom(User *user, Channel* channel, const char* text, ...)
00275 {
00276 va_list argsPtr;
00277 char textbuffer[MAXBUF];
00278 char tb[MAXBUF];
00279
00280 va_start(argsPtr, text);
00281 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
00282 va_end(argsPtr);
00283 snprintf(tb,MAXBUF,":%s %s",user->GetFullHost().c_str(), textbuffer);
00284
00285 CUList *ulist = channel->GetUsers();
00286
00287 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
00288 {
00289
00290 if (IS_LOCAL(i->first) && IS_OPER(i->first))
00291 {
00292 i->first->Write(std::string(tb));
00293 }
00294 }
00295 }
00296
00297 MODULE_INIT(ModuleInvisible)