00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "inspircd.h"
00015 #include "users.h"
00016 #include "channels.h"
00017 #include "modules.h"
00018 #include "hashcomp.h"
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 #ifdef WINDOWS
00069 typedef nspace::hash_map<irc::string, std::deque<userrec*>, nspace::hash_compare<irc::string, less<irc::string> > > watchentries;
00070 #else
00071 typedef nspace::hash_map<irc::string, std::deque<userrec*>, nspace::hash<irc::string> > watchentries;
00072 #endif
00073 typedef std::map<irc::string, std::string> watchlist;
00074
00075
00076
00077
00078
00079 watchentries* whos_watching_me;
00080
00083 class cmd_watch : public command_t
00084 {
00085 unsigned int& MAX_WATCH;
00086 public:
00087 CmdResult remove_watch(userrec* user, const char* nick)
00088 {
00089
00090 if (!ServerInstance->IsNick(nick))
00091 {
00092 user->WriteServ("942 %s %s :Invalid nickname", user->nick, nick);
00093 return CMD_FAILURE;
00094 }
00095
00096 watchlist* wl;
00097 if (user->GetExt("watchlist", wl))
00098 {
00099
00100 watchlist::iterator n = wl->find(nick);
00101
00102 if (!wl)
00103 return CMD_FAILURE;
00104
00105 if (n != wl->end())
00106 {
00107 if (!n->second.empty())
00108 user->WriteServ("602 %s %s %s :stopped watching", user->nick, n->first.c_str(), n->second.c_str());
00109 else
00110 user->WriteServ("602 %s %s * * 0 :stopped watching", user->nick, nick);
00111
00112 wl->erase(n);
00113 }
00114
00115 if (!wl->size())
00116 {
00117 user->Shrink("watchlist");
00118 delete wl;
00119 }
00120
00121 watchentries::iterator x = whos_watching_me->find(nick);
00122 if (x != whos_watching_me->end())
00123 {
00124
00125 std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user);
00126 if (n != x->second.end())
00127
00128 x->second.erase(n);
00129
00130 if (!x->second.size())
00131 whos_watching_me->erase(nick);
00132 }
00133 }
00134
00135
00136
00137
00138
00139 return CMD_FAILURE;
00140 }
00141
00142 CmdResult add_watch(userrec* user, const char* nick)
00143 {
00144 if (!ServerInstance->IsNick(nick))
00145 {
00146 user->WriteServ("942 %s %s :Invalid nickname",user->nick,nick);
00147 return CMD_FAILURE;
00148 }
00149
00150 watchlist* wl;
00151 if (!user->GetExt("watchlist", wl))
00152 {
00153 wl = new watchlist();
00154 user->Extend("watchlist", wl);
00155 }
00156
00157 if (wl->size() == MAX_WATCH)
00158 {
00159 user->WriteServ("512 %s %s :Too many WATCH entries", user->nick, nick);
00160 return CMD_FAILURE;
00161 }
00162
00163 watchlist::iterator n = wl->find(nick);
00164 if (n == wl->end())
00165 {
00166
00167 watchentries::iterator x = whos_watching_me->find(nick);
00168 if (x != whos_watching_me->end())
00169 {
00170
00171 x->second.push_back(user);
00172 }
00173 else
00174 {
00175 std::deque<userrec*> newlist;
00176 newlist.push_back(user);
00177 (*(whos_watching_me))[nick] = newlist;
00178 }
00179
00180 userrec* target = ServerInstance->FindNick(nick);
00181 if (target)
00182 {
00183 if (target->Visibility && !target->Visibility->VisibleTo(user))
00184 {
00185 (*wl)[nick] = "";
00186 user->WriteServ("605 %s %s * * 0 :is offline",user->nick, nick);
00187 return CMD_FAILURE;
00188 }
00189
00190 (*wl)[nick] = std::string(target->ident).append(" ").append(target->dhost).append(" ").append(ConvToStr(target->age));
00191 user->WriteServ("604 %s %s %s :is online",user->nick, nick, (*wl)[nick].c_str());
00192 }
00193 else
00194 {
00195 (*wl)[nick] = "";
00196 user->WriteServ("605 %s %s * * 0 :is offline",user->nick, nick);
00197 }
00198 }
00199
00200 return CMD_FAILURE;
00201 }
00202
00203 cmd_watch (InspIRCd* Instance, unsigned int &maxwatch) : command_t(Instance,"WATCH",0,0), MAX_WATCH(maxwatch)
00204 {
00205 this->source = "m_watch.so";
00206 syntax = "[C|L|S]|[+|-<nick>]";
00207 }
00208
00209 CmdResult Handle (const char** parameters, int pcnt, userrec *user)
00210 {
00211 if (!pcnt)
00212 {
00213 watchlist* wl;
00214 if (user->GetExt("watchlist", wl))
00215 {
00216 for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
00217 {
00218 if (!q->second.empty())
00219 user->WriteServ("604 %s %s %s :is online", user->nick, q->first.c_str(), q->second.c_str());
00220 }
00221 }
00222 user->WriteServ("607 %s :End of WATCH list",user->nick);
00223 }
00224 else if (pcnt > 0)
00225 {
00226 for (int x = 0; x < pcnt; x++)
00227 {
00228 const char *nick = parameters[x];
00229 if (!strcasecmp(nick,"C"))
00230 {
00231
00232 watchlist* wl;
00233 if (user->GetExt("watchlist", wl))
00234 {
00235 for (watchlist::iterator i = wl->begin(); i != wl->end(); i++)
00236 {
00237 watchentries::iterator x = whos_watching_me->find(i->first);
00238 if (x != whos_watching_me->end())
00239 {
00240
00241 std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user);
00242 if (n != x->second.end())
00243
00244 x->second.erase(n);
00245
00246 if (!x->second.size())
00247 whos_watching_me->erase(x);
00248 }
00249 }
00250
00251 delete wl;
00252 user->Shrink("watchlist");
00253 }
00254 }
00255 else if (!strcasecmp(nick,"L"))
00256 {
00257 watchlist* wl;
00258 if (user->GetExt("watchlist", wl))
00259 {
00260 for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
00261 {
00262 if (!q->second.empty())
00263 user->WriteServ("604 %s %s %s :is online", user->nick, q->first.c_str(), q->second.c_str());
00264 else
00265 user->WriteServ("605 %s %s * * 0 :is offline", user->nick, q->first.c_str());
00266 }
00267 }
00268 user->WriteServ("607 %s :End of WATCH list",user->nick);
00269 }
00270 else if (!strcasecmp(nick,"S"))
00271 {
00272 watchlist* wl;
00273 int you_have = 0;
00274 int youre_on = 0;
00275 std::string list;
00276
00277 if (user->GetExt("watchlist", wl))
00278 {
00279 for (watchlist::iterator q = wl->begin(); q != wl->end(); q++)
00280 list.append(q->first.c_str()).append(" ");
00281 you_have = wl->size();
00282 }
00283
00284 watchentries::iterator x = whos_watching_me->find(user->nick);
00285 if (x != whos_watching_me->end())
00286 youre_on = x->second.size();
00287
00288 user->WriteServ("603 %s :You have %d and are on %d WATCH entries", user->nick, you_have, youre_on);
00289 user->WriteServ("606 %s :%s",user->nick, list.c_str());
00290 user->WriteServ("607 %s :End of WATCH S",user->nick);
00291 }
00292 else if (nick[0] == '-')
00293 {
00294 nick++;
00295 remove_watch(user, nick);
00296 }
00297 else if (nick[0] == '+')
00298 {
00299 nick++;
00300 add_watch(user, nick);
00301 }
00302 }
00303 }
00304
00305 return CMD_FAILURE;
00306 }
00307 };
00308
00309 class Modulewatch : public Module
00310 {
00311 cmd_watch* mycommand;
00312 unsigned int maxwatch;
00313 public:
00314
00315 Modulewatch(InspIRCd* Me)
00316 : Module(Me), maxwatch(32)
00317 {
00318 OnRehash(NULL, "");
00319 whos_watching_me = new watchentries();
00320 mycommand = new cmd_watch(ServerInstance, maxwatch);
00321 ServerInstance->AddCommand(mycommand);
00322 }
00323
00324 virtual void OnRehash(userrec* user, const std::string ¶meter)
00325 {
00326 ConfigReader Conf(ServerInstance);
00327 maxwatch = Conf.ReadInteger("watch", "maxentries", 0, true);
00328 if (!maxwatch)
00329 maxwatch = 32;
00330 }
00331
00332 void Implements(char* List)
00333 {
00334 List[I_OnRehash] = List[I_OnGarbageCollect] = List[I_OnCleanup] = List[I_OnUserQuit] = List[I_OnPostConnect] = List[I_OnUserPostNick] = List[I_On005Numeric] = 1;
00335 }
00336
00337 virtual void OnUserQuit(userrec* user, const std::string &reason, const std::string &oper_message)
00338 {
00339 watchentries::iterator x = whos_watching_me->find(user->nick);
00340 if (x != whos_watching_me->end())
00341 {
00342 for (std::deque<userrec*>::iterator n = x->second.begin(); n != x->second.end(); n++)
00343 {
00344 if (!user->Visibility || user->Visibility->VisibleTo(*n))
00345 (*n)->WriteServ("601 %s %s %s %s %lu :went offline", (*n)->nick ,user->nick, user->ident, user->dhost, ServerInstance->Time());
00346
00347 watchlist* wl;
00348 if ((*n)->GetExt("watchlist", wl))
00349
00350 (*wl)[user->nick] = "";
00351 }
00352 }
00353
00354
00355 watchlist* wl;
00356 if (user->GetExt("watchlist", wl))
00357 {
00358
00359 for (watchlist::iterator i = wl->begin(); i != wl->end(); i++)
00360 {
00361 watchentries::iterator x = whos_watching_me->find(i->first);
00362 if (x != whos_watching_me->end())
00363 {
00364
00365 std::deque<userrec*>::iterator n = std::find(x->second.begin(), x->second.end(), user);
00366 if (n != x->second.end())
00367
00368 x->second.erase(n);
00369
00370 if (!x->second.size())
00371 whos_watching_me->erase(x);
00372 }
00373 }
00374
00375
00376 delete wl;
00377 user->Shrink("watchlist");
00378 }
00379 }
00380
00381 virtual void OnGarbageCollect()
00382 {
00383 watchentries* old_watch = whos_watching_me;
00384 whos_watching_me = new watchentries();
00385
00386 for (watchentries::const_iterator n = old_watch->begin(); n != old_watch->end(); n++)
00387 whos_watching_me->insert(*n);
00388
00389 delete old_watch;
00390 }
00391
00392 virtual void OnCleanup(int target_type, void* item)
00393 {
00394 if (target_type == TYPE_USER)
00395 {
00396 watchlist* wl;
00397 userrec* user = (userrec*)item;
00398
00399 if (user->GetExt("watchlist", wl))
00400 {
00401 user->Shrink("watchlist");
00402 delete wl;
00403 }
00404 }
00405 }
00406
00407 virtual void OnPostConnect(userrec* user)
00408 {
00409 watchentries::iterator x = whos_watching_me->find(user->nick);
00410 if (x != whos_watching_me->end())
00411 {
00412 for (std::deque<userrec*>::iterator n = x->second.begin(); n != x->second.end(); n++)
00413 {
00414 if (!user->Visibility || user->Visibility->VisibleTo(*n))
00415 (*n)->WriteServ("600 %s %s %s %s %lu :arrived online", (*n)->nick, user->nick, user->ident, user->dhost, user->age);
00416
00417 watchlist* wl;
00418 if ((*n)->GetExt("watchlist", wl))
00419
00420 (*wl)[user->nick] = std::string(user->ident).append(" ").append(user->dhost).append(" ").append(ConvToStr(user->age));
00421 }
00422 }
00423 }
00424
00425 virtual void OnUserPostNick(userrec* user, const std::string &oldnick)
00426 {
00427 watchentries::iterator new_offline = whos_watching_me->find(assign(oldnick));
00428 watchentries::iterator new_online = whos_watching_me->find(user->nick);
00429
00430 if (new_offline != whos_watching_me->end())
00431 {
00432 for (std::deque<userrec*>::iterator n = new_offline->second.begin(); n != new_offline->second.end(); n++)
00433 {
00434 watchlist* wl;
00435 if ((*n)->GetExt("watchlist", wl))
00436 {
00437 if (!user->Visibility || user->Visibility->VisibleTo(*n))
00438 (*n)->WriteServ("601 %s %s %s %s %lu :went offline", (*n)->nick, oldnick.c_str(), user->ident, user->dhost, user->age);
00439 (*wl)[oldnick.c_str()] = "";
00440 }
00441 }
00442 }
00443
00444 if (new_online != whos_watching_me->end())
00445 {
00446 for (std::deque<userrec*>::iterator n = new_online->second.begin(); n != new_online->second.end(); n++)
00447 {
00448 watchlist* wl;
00449 if ((*n)->GetExt("watchlist", wl))
00450 {
00451 (*wl)[user->nick] = std::string(user->ident).append(" ").append(user->dhost).append(" ").append(ConvToStr(user->age));
00452 if (!user->Visibility || user->Visibility->VisibleTo(*n))
00453 (*n)->WriteServ("600 %s %s %s :arrived online", (*n)->nick, user->nick, (*wl)[user->nick].c_str());
00454 }
00455 }
00456 }
00457 }
00458
00459 virtual void On005Numeric(std::string &output)
00460 {
00461
00462 output = output + " WATCH=" + ConvToStr(maxwatch);
00463 }
00464
00465 virtual ~Modulewatch()
00466 {
00467 delete whos_watching_me;
00468 }
00469
00470 virtual Version GetVersion()
00471 {
00472 return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION);
00473 }
00474 };
00475
00476 MODULE_INIT(Modulewatch)
00477