2 * IRC - Internet Relay Chat, ircd/m_list.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * See file AUTHORS in IRC package for additional names of
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 1, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 * m_functions execute protocol messages on this server:
29 * cptr is always NON-NULL, pointing to a *LOCAL* client
30 * structure (with an open socket connected!). This
31 * identifies the physical socket where the message
32 * originated (or which caused the m_function to be
33 * executed--some m_functions may call others...).
35 * sptr is the source of the message, defined by the
36 * prefix part of the message if present. If not
37 * or prefix not found, then sptr==cptr.
39 * (!IsServer(cptr)) => (cptr == sptr), because
40 * prefixes are taken *only* from servers...
43 * (sptr == cptr) => the message didn't
46 * (sptr != cptr && IsServer(sptr) means
47 * the prefix specified servername. (?)
49 * (sptr != cptr && !IsServer(sptr) means
50 * that message originated from a remote
55 * (!IsServer(sptr)) means that, sptr can safely
56 * taken as defining the target structure of the
57 * message in this server.
59 * *Always* true (if 'parse' and others are working correct):
61 * 1) sptr->from == cptr (note: cptr->from == cptr)
63 * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64 * *cannot* be a local connection, unless it's
65 * actually cptr!). [MyConnect(x) should probably
66 * be defined as (x == x->from) --msa ]
68 * parc number of variable parameter strings (if zero,
69 * parv is allowed to be NULL)
71 * parv a NULL terminated list of parameter pointers,
73 * parv[0], sender (prefix string), if not present
74 * this points to an empty string.
75 * parv[1]...parv[parc-1]
76 * pointers to additional parameters
77 * parv[parc] == NULL, *always*
79 * note: it is guaranteed that parv[0]..parv[parc-1] are all
84 * No need to include handlers.h here the signatures must match
85 * and we don't need to force a rebuild of all the handlers everytime
86 * we add a new one to the list. --Bleep
94 #include "ircd_alloc.h"
95 #include "ircd_chattr.h"
96 #include "ircd_reply.h"
97 #include "ircd_string.h"
100 #include "numnicks.h"
108 * m_list - generic message handler
110 * parv[0] = sender prefix
111 * parv[1] = channel list or user/time limit
112 * parv[2...] = more user/time limits
114 int m_list(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
116 struct Channel *chptr;
118 int show_usage = 0, show_channels = 0, param;
119 struct ListingArgs args = {
120 2147483647, /* max_time */
122 4294967295U, /* max_users */
124 0, /* topic_limits */
125 2147483647, /* max_topic_time */
126 0, /* min_topic_time */
130 if (sptr->listing) /* Already listing ? */
132 sptr->listing->chptr->mode.mode &= ~MODE_LISTED;
133 MyFree(sptr->listing);
135 sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, sptr->name);
137 return 0; /* Let LIST abort a listing. */
140 if (parc < 2) /* No arguments given to /LIST ? */
142 #ifdef DEFAULT_LIST_PARAM
143 static char *defparv[MAXPARA + 1];
144 static int defparc = 0;
145 static char lp[] = DEFAULT_LIST_PARAM;
156 defparv[defparc++] = t = strtok(s, " ");
157 while (t && defparc < MAXPARA)
159 if ((t = strtok(0, " ")))
160 defparv[defparc++] = t;
163 for (i = 1; i < defparc; i++)
164 parv[i] = defparv[i];
167 #endif /* DEFAULT_LIST_PARAM */
171 for (param = 1; !show_usage && parv[param]; param++)
173 char *p = parv[param];
182 args.topic_limits = 1;
188 if (*p != '<' && *p != '>')
204 time_t val = atoi(p);
207 if (val < 80000000) /* Toggle UTC/offset */
211 * 'TStime() - chptr->creationtime < val * 60'
213 * 'chptr->creationtime > TStime() - val * 60'
216 args.min_time = TStime() - val * 60;
218 args.min_topic_time = TStime() - val * 60;
220 else if (is_time == 1) /* Creation time in UTC was entered */
222 else /* Topic time in UTC was entered */
223 args.max_topic_time = val;
225 else if (val < 80000000)
228 args.max_time = TStime() - val * 60;
230 args.max_topic_time = TStime() - val * 60;
232 else if (is_time == 1)
235 args.min_topic_time = val;
237 else if (p[-1] == '<')
238 args.max_users = atoi(p);
240 args.min_users = atoi(p);
241 if ((p = strchr(p, ',')))
247 if (!IsChannelName(p))
252 if (parc != 2) /* Don't allow a mixture of channels with <,> */
259 while (!show_usage && p); /* p points after comma, or is NULL */
264 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
265 "Usage: \002/QUOTE LIST\002 \037parameters\037");
266 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
267 "Where \037parameters\037 is a space or comma seperated "
268 "list of one or more of:");
269 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
270 " \002<\002\037max_users\037 ; Show all channels with less "
271 "than \037max_users\037.");
272 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
273 " \002>\002\037min_users\037 ; Show all channels with more "
274 "than \037min_users\037.");
275 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
276 " \002C<\002\037max_minutes\037 ; Channels that exist less "
277 "than \037max_minutes\037.");
278 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
279 " \002C>\002\037min_minutes\037 ; Channels that exist more "
280 "than \037min_minutes\037.");
281 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
282 " \002T<\002\037max_minutes\037 ; Channels with a topic last "
283 "set less than \037max_minutes\037 ago.");
284 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
285 " \002T>\002\037min_minutes\037 ; Channels with a topic last "
286 "set more than \037min_minutes\037 ago.");
287 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
288 "Example: LIST <3,>1,C<10,T>0 ; 2 users, younger than 10 min., "
293 sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]);
297 if (args.max_users > args.min_users + 1 && args.max_time > args.min_time &&
298 args.max_topic_time > args.min_topic_time) /* Sanity check */
300 sptr->listing = (struct ListingArgs*) MyMalloc(sizeof(struct ListingArgs));
301 assert(0 != sptr->listing);
302 memcpy(sptr->listing, &args, sizeof(struct ListingArgs));
303 if ((sptr->listing->chptr = GlobalChannelList)) {
304 int m = GlobalChannelList->mode.mode & MODE_LISTED;
305 list_next_channels(sptr, 64);
306 GlobalChannelList->mode.mode |= m;
309 MyFree(sptr->listing);
312 sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
316 for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
318 chptr = FindChannel(name);
319 if (chptr && ShowChannel(sptr, chptr) && sptr->user)
320 sendto_one(sptr, rpl_str(RPL_LIST), me.name, parv[0],
322 chptr->users - number_of_zombies(chptr), chptr->topic);
325 sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
334 * parv[0] = sender prefix
335 * parv[1] = channel list or user/time limit
336 * parv[2...] = more user/time limits
338 int m_list(struct Client* cptr, struct Client *sptr, int parc, char *parv[])
340 struct Channel *chptr;
342 int show_usage = 0, show_channels = 0, param;
343 struct ListingArgs args = {
344 2147483647, /* max_time */
346 4294967295U, /* max_users */
348 0, /* topic_limits */
349 2147483647, /* max_topic_time */
350 0, /* min_topic_time */
354 if (sptr->listing) /* Already listing ? */
356 sptr->listing->chptr->mode.mode &= ~MODE_LISTED;
357 MyFree(sptr->listing);
359 sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, sptr->name);
361 return 0; /* Let LIST abort a listing. */
364 if (parc < 2) /* No arguments given to /LIST ? */
366 #ifdef DEFAULT_LIST_PARAM
367 static char *defparv[MAXPARA + 1];
368 static int defparc = 0;
369 static char lp[] = DEFAULT_LIST_PARAM;
377 defparv[defparc++] = t = strtok(s, " ");
378 while (t && defparc < MAXPARA)
380 if ((t = strtok(0, " ")))
381 defparv[defparc++] = t;
384 for (i = 1; i < defparc; i++)
385 parv[i] = defparv[i];
388 #endif /* DEFAULT_LIST_PARAM */
392 for (param = 1; !show_usage && parv[param]; param++)
394 char *p = parv[param];
403 args.topic_limits = 1;
409 if (*p != '<' && *p != '>')
425 time_t val = atoi(p);
428 if (val < 80000000) /* Toggle UTC/offset */
432 * 'TStime() - chptr->creationtime < val * 60'
434 * 'chptr->creationtime > TStime() - val * 60'
437 args.min_time = TStime() - val * 60;
439 args.min_topic_time = TStime() - val * 60;
441 else if (is_time == 1) /* Creation time in UTC was entered */
443 else /* Topic time in UTC was entered */
444 args.max_topic_time = val;
446 else if (val < 80000000)
449 args.max_time = TStime() - val * 60;
451 args.max_topic_time = TStime() - val * 60;
453 else if (is_time == 1)
456 args.min_topic_time = val;
458 else if (p[-1] == '<')
459 args.max_users = atoi(p);
461 args.min_users = atoi(p);
462 if ((p = strchr(p, ',')))
468 if (!IsChannelName(p))
473 if (parc != 2) /* Don't allow a mixture of channels with <,> */
480 while (!show_usage && p); /* p points after comma, or is NULL */
485 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
486 "Usage: \002/QUOTE LIST\002 \037parameters\037");
487 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
488 "Where \037parameters\037 is a space or comma seperated "
489 "list of one or more of:");
490 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
491 " \002<\002\037max_users\037 ; Show all channels with less "
492 "than \037max_users\037.");
493 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
494 " \002>\002\037min_users\037 ; Show all channels with more "
495 "than \037min_users\037.");
496 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
497 " \002C<\002\037max_minutes\037 ; Channels that exist less "
498 "than \037max_minutes\037.");
499 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
500 " \002C>\002\037min_minutes\037 ; Channels that exist more "
501 "than \037min_minutes\037.");
502 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
503 " \002T<\002\037max_minutes\037 ; Channels with a topic last "
504 "set less than \037max_minutes\037 ago.");
505 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
506 " \002T>\002\037min_minutes\037 ; Channels with a topic last "
507 "set more than \037min_minutes\037 ago.");
508 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
509 "Example: LIST <3,>1,C<10,T>0 ; 2 users, younger than 10 min., "
514 sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]);
518 if (args.max_users > args.min_users + 1 && args.max_time > args.min_time &&
519 args.max_topic_time > args.min_topic_time) /* Sanity check */
521 sptr->listing = (struct ListingArgs*) MyMalloc(sizeof(struct ListingArgs));
522 assert(0 != sptr->listing);
523 memcpy(sptr->listing, &args, sizeof(struct ListingArgs));
524 if ((sptr->listing->chptr = GlobalChannelList)) {
525 int m = GlobalChannelList->mode.mode & MODE_LISTED;
526 list_next_channels(sptr, 64);
527 GlobalChannelList->mode.mode |= m;
530 MyFree(sptr->listing);
533 sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
537 for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
539 chptr = FindChannel(name);
540 if (chptr && ShowChannel(sptr, chptr) && sptr->user)
541 sendto_one(sptr, rpl_str(RPL_LIST), me.name, parv[0],
542 ShowChannel(sptr, chptr) ? chptr->chname : "*",
543 chptr->users - number_of_zombies(chptr), chptr->topic);
546 sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);