1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
7 * <brain@chatspike.net>
8 * <Craig@chatspike.net>
10 * Written by Craig Edwards, Craig McLure, and others.
11 * This program is free but copyrighted software; see
12 * the file COPYING for details.
14 * ---------------------------------------------------
22 #include "helperfuncs.h"
35 ListData() : list_start(0), list_position(0), list_ended(false) {};
36 ListData(long pos, time_t t) : list_start(t), list_position(pos), list_ended(false) {};
39 /* $ModDesc: A module overriding /list, and making it safe - stop those sendq problems. */
41 typedef std::vector<userrec *> UserList;
43 class ModuleSafeList : public Module
47 UserList listusers; /* vector of people doing a /list */
49 ModuleSafeList(Server* Me) : Module::Module(Me)
54 virtual ~ModuleSafeList()
58 virtual Version GetVersion()
60 return Version(1,0,0,0,VF_VENDOR);
63 void Implements(char* List)
65 List[I_OnPreCommand] = List[I_OnBackgroundTimer] = List[I_OnCleanup] = List[I_OnUserQuit] = List[I_On005Numeric] = 1;
70 * Intercept the LIST command.
72 virtual int OnPreCommand(std::string command, char **parameters, int pcnt, userrec *user, bool validated)
74 /* If the command doesnt appear to be valid, we dont want to mess with it. */
78 if (command == "LIST")
80 return this->HandleList(parameters, pcnt, user);
87 * Spool off safelist information to users currently doing /list.
89 virtual void OnBackgroundTimer(time_t curtime)
98 for (UserList::iterator iter = listusers.begin(); iter != listusers.end(); iter++)
102 * - Get where they are up to
103 * - If it's > GetChannelCount, erase them from the iterator, set go_again to true
104 * - If not, spool the next 20 channels
106 userrec* u = (userrec*)(*iter);
107 ListData* ld = (ListData*)u->GetExt("safelist_cache");
108 if (ld->list_position > Srv->GetChannelCount())
110 u->Shrink("safelist_cache");
112 listusers.erase(iter);
117 log(DEBUG, "m_safelist.so: resuming spool of list to client %s at channel %ld", u->nick, ld->list_position);
119 /* Attempt to fill up to half the user's sendq with /LIST output */
120 long amount_sent = 0;
123 log(DEBUG,"Channel %ld",ld->list_position);
124 chan = Srv->GetChannelIndex(ld->list_position);
128 /* Increment total plus linefeed */
129 int counter = snprintf(buffer,MAXBUF,"322 %s %s %d :[+%s] %s",u->nick,chan->name,usercount_i(chan),chanmodes(chan,has_channel(u,chan)),chan->topic);
130 amount_sent += counter + 4 + Srv->GetServerName().length();
131 log(DEBUG,"m_safelist.so: Sent %ld of safe %ld / 2",amount_sent,u->sendqmax);
132 WriteServ(u->fd,"%s",buffer);
138 ld->list_ended = true;
139 WriteServ(u->fd,"323 %s :End of channel list.",u->nick);
145 while ((chan != NULL) && (amount_sent < (u->sendqmax / 2)));
152 * Handle (override) the LIST command.
154 int HandleList(char** parameters, int pcnt, userrec* user)
156 /* First, let's check if the user is currently /list'ing */
157 ListData *ld = (ListData*)user->GetExt("safelist_cache");
161 /* user is already /list'ing, we don't want to do shit. */
165 time_t* last_list_time = (time_t*)user->GetExt("safelist_last");
168 if (TIME < (*last_list_time)+60)
170 WriteServ(user->fd,"NOTICE %s :*** Woah there, slow down a little, you can't /LIST so often!",user->nick);
174 delete last_list_time;
175 user->Shrink("safelist_last");
179 * start at channel 0! ;)
181 ld = new ListData(0,TIME);
182 user->Extend("safelist_cache", (char*)ld);
183 listusers.push_back(user);
185 time_t* llt = new time_t;
187 user->Extend("safelist_last",(char*)llt);
189 WriteServ(user->fd,"321 %s Channel :Users Name",user->nick);
191 * If we can, we try and fill up the user's sendq right now with the first batch of channels,
192 * which on a small net, may be ALL of them.
194 this->OnBackgroundTimer(TIME);
198 virtual void OnCleanup(int target_type, void* item)
200 if(target_type == TYPE_USER)
202 userrec* u = (userrec*)item;
203 ListData* ld = (ListData*)u->GetExt("safelist_cache");
206 u->Shrink("safelist_cache");
209 for (UserList::iterator iter = listusers.begin(); iter != listusers.end(); iter++)
211 userrec* u2 = (userrec*)(*iter);
214 listusers.erase(iter);
218 time_t* last_list_time = (time_t*)u->GetExt("safelist_last");
221 delete last_list_time;
222 u->Shrink("safelist_last");
227 virtual void On005Numeric(std::string &output)
229 output.append(" SAFELIST");
232 virtual void OnUserQuit(userrec* user, std::string message)
234 this->OnCleanup(TYPE_USER,user);
241 /******************************************************************************************************/
243 class ModuleSafeListFactory : public ModuleFactory
246 ModuleSafeListFactory()
250 ~ModuleSafeListFactory()
254 virtual Module * CreateModule(Server* Me)
256 return new ModuleSafeList(Me);
261 extern "C" void * init_module( void )
263 return new ModuleSafeListFactory;