+2004-10-13 Michael Poole <mdpoole@troilus.org>
+
+ * include/channel.h: Delete MODE_LISTED and is_listed(). Replace
+ ListingArgs.chptr with ListingArgs.bucket. Move declaration of
+ list_next_channels() to..
+
+ * include/hash.h: here, and drop the "nr" argument.
+
+ * ircd/channel.c: Remove redundant scan of local clients for
+ channels being listed. Delete list_next_channels() function.
+
+ * ircd/hash.c: Add list_next_channels() here, revising to not use
+ MODE_LISTED and to use ListingArgs.bucket instead of chptr. Also
+ decide when to stop sending RPL_LISTs based on a half-full sendq.
+
+ * ircd/m_burst.c, ircd/s_misc.c: Delete mention of MODE_LISTED.
+
+ * ircd/m_list.c: Delete mention of MODE_LISTED. Unconditionally
+ call list_next_channels(sptr).
+
+ * ircd/s_bsd.c: Remove the "nr" argument to list_next_channels().
+
+ * ircd/Makefile.in: Update dependencies (for hash.c).
+
2004-10-13 Michael Poole <mdpoole@troilus.org>
* ircd/ircd_parser.y: Consistently zero out global variables after
#define MODE_LIMIT 0x0400 /**< +l Limit */
#define MODE_REGONLY 0x0800 /**< Only +r users may join */
#define MODE_DELJOINS 0x1000 /**< New join messages are delayed */
-#define MODE_LISTED 0x10000
#define MODE_SAVE 0x20000 /**< save this mode-with-arg 'til
* later */
#define MODE_FREE 0x40000 /**< string needs to be passed to
(IsAnOper(v) && HasPriv(v, PRIV_LIST_CHAN)))
#define PubChannel(x) ((!x) || ((x)->mode.mode & \
(MODE_PRIVATE | MODE_SECRET)) == 0)
-#define is_listed(x) ((x)->mode.mode & MODE_LISTED)
#define IsGlobalChannel(name) (*(name) == '#')
#define IsLocalChannel(name) (*(name) == '&')
unsigned int flags;
time_t max_topic_time;
time_t min_topic_time;
- struct Channel *chptr;
+ unsigned int bucket;
};
struct ModeBuf {
extern void send_channel_modes(struct Client *cptr, struct Channel *chptr);
extern char *pretty_mask(char *mask);
extern void del_invite(struct Client *cptr, struct Channel *chptr);
-extern void list_next_channels(struct Client *cptr, int nr);
extern void list_set_default(void); /* this belongs elsewhere! */
extern void RevealDelayedJoin(struct Membership *member);
extern int isNickJuped(const char *nick);
extern int addNickJupes(const char *nicks);
extern void clearNickJupes(void);
+extern void list_next_channels(struct Client *cptr);
#endif /* INCLUDED_hash_h */
IPcheck.o: IPcheck.c ../config.h ../include/IPcheck.h ../include/client.h \
../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
../include/ircd_events.h ../include/ircd_handler.h ../include/res.h \
- ../include/ircd.h ../include/struct.h ../include/msg.h \
- ../include/numnicks.h ../include/ircd_alloc.h \
+ ../include/ircd.h ../include/struct.h ../include/match.h \
+ ../include/msg.h ../include/numnicks.h ../include/ircd_alloc.h \
../include/ircd_features.h ../include/s_debug.h ../include/s_user.h \
- ../include/send.h ../include/match.h
+ ../include/send.h
channel.o: channel.c ../config.h ../include/channel.h \
../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
hash.o: hash.c ../config.h ../include/hash.h ../include/client.h \
../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
../include/ircd_events.h ../include/ircd_handler.h ../include/res.h \
- ../include/channel.h ../include/ircd_chattr.h ../include/ircd_string.h \
- ../include/ircd.h ../include/struct.h ../include/msg.h \
- ../include/send.h ../include/sys.h
+ ../include/channel.h ../include/ircd_alloc.h ../include/ircd_chattr.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/ircd.h \
+ ../include/struct.h ../include/msg.h ../include/numeric.h \
+ ../include/random.h ../include/send.h ../include/sys.h
ircd.o: ircd.c ../config.h ../include/ircd.h ../include/struct.h \
../include/ircd_defs.h ../include/IPcheck.h ../include/class.h \
../include/client.h ../include/dbuf.h ../include/msgq.h \
random.o: random.c ../config.h ../include/random.h ../include/client.h \
../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
../include/ircd_events.h ../include/ircd_handler.h ../include/res.h \
- ../include/ircd_log.h ../include/ircd_reply.h ../include/send.h
+ ../include/ircd_log.h ../include/ircd_md5.h ../include/ircd_reply.h \
+ ../include/send.h
s_auth.o: s_auth.c ../config.h ../include/s_auth.h \
../include/ircd_events.h ../include/client.h ../include/ircd_defs.h \
../include/dbuf.h ../include/msgq.h ../include/ircd_handler.h \
assert(0 == chptr->members);
- /* Channel became (or was) empty: Remove channel */
- if (is_listed(chptr))
- {
- int i;
- for (i = 0; i <= HighestFd; i++)
- {
- struct Client *acptr = 0;
- if ((acptr = LocalClientArray[i]) && cli_listing(acptr) &&
- (cli_listing(acptr))->chptr == chptr)
- {
- list_next_channels(acptr, 1);
- break; /* Only one client can list a channel */
- }
- }
- }
/*
* Now, find all invite links from channel structure
*/
}
}
-/** List a set of channels
- * Lists a series of channels that match a filter, skipping channels that
- * have been listed before.
- *
- * @param cptr Client to send the list to.
- * @param nr Number of channels to send this update.
- */
-void list_next_channels(struct Client *cptr, int nr)
-{
- struct ListingArgs *args = cli_listing(cptr);
- struct Channel *chptr = args->chptr;
- chptr->mode.mode &= ~MODE_LISTED;
- while (is_listed(chptr) || --nr >= 0)
- {
- for (; chptr; chptr = chptr->next)
- {
- if (!cli_user(cptr))
- continue;
- if (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) &&
- SecretChannel(chptr) && !find_channel_member(cptr, chptr))
- continue;
- if (chptr->users > args->min_users && chptr->users < args->max_users &&
- chptr->creationtime > args->min_time &&
- chptr->creationtime < args->max_time &&
- (!(args->flags & LISTARG_TOPICLIMITS) || (*chptr->topic &&
- chptr->topic_time > args->min_topic_time &&
- chptr->topic_time < args->max_topic_time)))
- {
- if ((args->flags & LISTARG_SHOWSECRET) || ShowChannel(cptr,chptr))
- send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
- chptr->topic);
- chptr = chptr->next;
- break;
- }
- }
- if (!chptr)
- {
- MyFree(cli_listing(cptr));
- cli_listing(cptr) = NULL;
- send_reply(cptr, RPL_LISTEND);
- break;
- }
- }
- if (chptr)
- {
- (cli_listing(cptr))->chptr = chptr;
- chptr->mode.mode |= MODE_LISTED;
- }
-
- update_write(cptr);
-}
-
/** @page zombie Explaination of Zombies
*
* Consider:
#include "hash.h"
#include "client.h"
#include "channel.h"
+#include "ircd_alloc.h"
#include "ircd_chattr.h"
+#include "ircd_reply.h"
#include "ircd_string.h"
#include "ircd.h"
#include "msg.h"
+#include "numeric.h"
#include "random.h"
#include "send.h"
#include "struct.h"
for (i = 0; i < JUPEHASHSIZE; i++)
jupeTable[i][0] = '\000';
}
+
+/** Send more channels to a client in mid-LIST.
+ * @param[in] cptr Client to send the list to.
+ */
+void list_next_channels(struct Client *cptr)
+{
+ struct ListingArgs *args;
+ struct Channel *chptr;
+
+ /* Walk consecutive buckets until we hit the end. */
+ for (args = cli_listing(cptr); args->bucket < HASHSIZE; args->bucket++)
+ {
+ /* Send all the matching channels in the bucket. */
+ for (chptr = channelTable[args->bucket]; chptr; chptr = chptr->hnext)
+ {
+ if (chptr->users > args->min_users
+ && chptr->users < args->max_users
+ && chptr->creationtime > args->min_time
+ && chptr->creationtime < args->max_time
+ && (!(args->flags & LISTARG_TOPICLIMITS)
+ || (chptr->topic[0]
+ && chptr->topic_time > args->min_topic_time
+ && chptr->topic_time < args->max_topic_time))
+ && ((args->flags & LISTARG_SHOWSECRET)
+ || ShowChannel(cptr, chptr)))
+ {
+ send_reply(cptr, RPL_LIST, chptr->chname, chptr->users, chptr->topic);
+ }
+ }
+ /* If, at the end of the bucket, client sendq is more than half
+ * full, stop. */
+ if (MsgQLength(&cli_sendQ(cptr)) > cli_max_sendq(cptr) / 2)
+ break;
+ }
+
+ /* If we did all buckets, clean the client and send RPL_LISTEND. */
+ if (args->bucket >= HASHSIZE)
+ {
+ MyFree(cli_listing(cptr));
+ cli_listing(cptr) = NULL;
+ send_reply(cptr, RPL_LISTEND);
+ }
+}
modebuf_init(mbuf = &modebuf, &me, cptr, chptr,
MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY);
modebuf_mode(mbuf, MODE_DEL | chptr->mode.mode); /* wipeout modes */
- chptr->mode.mode &= MODE_LISTED | MODE_BURSTADDED | MODE_WASDELJOINS;
+ chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
parse_flags |= (MODE_PARSE_SET | MODE_PARSE_WIPEOUT); /* wipeout keys */
if (cli_listing(sptr)) /* Already listing ? */
{
- cli_listing(sptr)->chptr->mode.mode &= ~MODE_LISTED;
MyFree(cli_listing(sptr));
cli_listing(sptr) = 0;
send_reply(sptr, RPL_LISTEND);
cli_listing(sptr) = (struct ListingArgs*) MyMalloc(sizeof(struct ListingArgs));
assert(0 != cli_listing(sptr));
memcpy(cli_listing(sptr), &args, sizeof(struct ListingArgs));
- if ((cli_listing(sptr)->chptr = GlobalChannelList)) {
- int m = GlobalChannelList->mode.mode & MODE_LISTED;
- list_next_channels(sptr, 64);
- GlobalChannelList->mode.mode |= m;
- return 0;
- }
- MyFree(cli_listing(sptr));
- cli_listing(sptr) = 0;
+ list_next_channels(sptr);
+ return 0;
}
send_reply(sptr, RPL_LISTEND);
return 0;
case ET_WRITE: /* socket is writable */
ClrFlag(cptr, FLAG_BLOCKED);
if (cli_listing(cptr) && MsgQLength(&(cli_sendQ(cptr))) < 2048)
- list_next_channels(cptr, 64);
+ list_next_channels(cptr);
Debug((DEBUG_SEND, "Sending queued data to %C", cptr));
send_queued(cptr);
break;
* Stop a running /LIST clean
*/
if (MyUser(bcptr) && cli_listing(bcptr)) {
- cli_listing(bcptr)->chptr->mode.mode &= ~MODE_LISTED;
MyFree(cli_listing(bcptr));
cli_listing(bcptr) = NULL;
}