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 send_reply(sptr, RPL_LISTEND);
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 send_reply(sptr, RPL_LISTUSAGE,
265 "Usage: \002/QUOTE LIST\002 \037parameters\037");
266 send_reply(sptr, RPL_LISTUSAGE,
267 "Where \037parameters\037 is a space or comma seperated "
268 "list of one or more of:");
269 send_reply(sptr, RPL_LISTUSAGE,
270 " \002<\002\037max_users\037 ; Show all channels with less "
271 "than \037max_users\037.");
272 send_reply(sptr, RPL_LISTUSAGE,
273 " \002>\002\037min_users\037 ; Show all channels with more "
274 "than \037min_users\037.");
275 send_reply(sptr, RPL_LISTUSAGE,
276 " \002C<\002\037max_minutes\037 ; Channels that exist less "
277 "than \037max_minutes\037.");
278 send_reply(sptr, RPL_LISTUSAGE,
279 " \002C>\002\037min_minutes\037 ; Channels that exist more "
280 "than \037min_minutes\037.");
281 send_reply(sptr, RPL_LISTUSAGE,
282 " \002T<\002\037max_minutes\037 ; Channels with a topic last "
283 "set less than \037max_minutes\037 ago.");
284 send_reply(sptr, RPL_LISTUSAGE,
285 " \002T>\002\037min_minutes\037 ; Channels with a topic last "
286 "set more than \037min_minutes\037 ago.");
287 send_reply(sptr, RPL_LISTUSAGE,
288 "Example: LIST <3,>1,C<10,T>0 ; 2 users, younger than 10 "
293 send_reply(sptr, RPL_LISTSTART);
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 send_reply(sptr, RPL_LISTEND);
316 for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
318 chptr = FindChannel(name);
319 if (chptr && ShowChannel(sptr, chptr) && sptr->user)
320 send_reply(sptr, RPL_LIST, chptr->chname,
321 chptr->users - number_of_zombies(chptr), chptr->topic);
324 send_reply(sptr, RPL_LISTEND);
333 * parv[0] = sender prefix
334 * parv[1] = channel list or user/time limit
335 * parv[2...] = more user/time limits
337 int m_list(struct Client* cptr, struct Client *sptr, int parc, char *parv[])
339 struct Channel *chptr;
341 int show_usage = 0, show_channels = 0, param;
342 struct ListingArgs args = {
343 2147483647, /* max_time */
345 4294967295U, /* max_users */
347 0, /* topic_limits */
348 2147483647, /* max_topic_time */
349 0, /* min_topic_time */
353 if (sptr->listing) /* Already listing ? */
355 sptr->listing->chptr->mode.mode &= ~MODE_LISTED;
356 MyFree(sptr->listing);
358 sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, sptr->name); /* XXX DEAD */
360 return 0; /* Let LIST abort a listing. */
363 if (parc < 2) /* No arguments given to /LIST ? */
365 #ifdef DEFAULT_LIST_PARAM
366 static char *defparv[MAXPARA + 1];
367 static int defparc = 0;
368 static char lp[] = DEFAULT_LIST_PARAM;
376 defparv[defparc++] = t = strtok(s, " ");
377 while (t && defparc < MAXPARA)
379 if ((t = strtok(0, " ")))
380 defparv[defparc++] = t;
383 for (i = 1; i < defparc; i++)
384 parv[i] = defparv[i];
387 #endif /* DEFAULT_LIST_PARAM */
391 for (param = 1; !show_usage && parv[param]; param++)
393 char *p = parv[param];
402 args.topic_limits = 1;
408 if (*p != '<' && *p != '>')
424 time_t val = atoi(p);
427 if (val < 80000000) /* Toggle UTC/offset */
431 * 'TStime() - chptr->creationtime < val * 60'
433 * 'chptr->creationtime > TStime() - val * 60'
436 args.min_time = TStime() - val * 60;
438 args.min_topic_time = TStime() - val * 60;
440 else if (is_time == 1) /* Creation time in UTC was entered */
442 else /* Topic time in UTC was entered */
443 args.max_topic_time = val;
445 else if (val < 80000000)
448 args.max_time = TStime() - val * 60;
450 args.max_topic_time = TStime() - val * 60;
452 else if (is_time == 1)
455 args.min_topic_time = val;
457 else if (p[-1] == '<')
458 args.max_users = atoi(p);
460 args.min_users = atoi(p);
461 if ((p = strchr(p, ',')))
467 if (!IsChannelName(p))
472 if (parc != 2) /* Don't allow a mixture of channels with <,> */
479 while (!show_usage && p); /* p points after comma, or is NULL */
484 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
485 "Usage: \002/QUOTE LIST\002 \037parameters\037");
486 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
487 "Where \037parameters\037 is a space or comma seperated "
488 "list of one or more of:");
489 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
490 " \002<\002\037max_users\037 ; Show all channels with less "
491 "than \037max_users\037.");
492 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
493 " \002>\002\037min_users\037 ; Show all channels with more "
494 "than \037min_users\037.");
495 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
496 " \002C<\002\037max_minutes\037 ; Channels that exist less "
497 "than \037max_minutes\037.");
498 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
499 " \002C>\002\037min_minutes\037 ; Channels that exist more "
500 "than \037min_minutes\037.");
501 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
502 " \002T<\002\037max_minutes\037 ; Channels with a topic last "
503 "set less than \037max_minutes\037 ago.");
504 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
505 " \002T>\002\037min_minutes\037 ; Channels with a topic last "
506 "set more than \037min_minutes\037 ago.");
507 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0], /* XXX DEAD */
508 "Example: LIST <3,>1,C<10,T>0 ; 2 users, younger than 10 min., "
513 sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]); /* XXX DEAD */
517 if (args.max_users > args.min_users + 1 && args.max_time > args.min_time &&
518 args.max_topic_time > args.min_topic_time) /* Sanity check */
520 sptr->listing = (struct ListingArgs*) MyMalloc(sizeof(struct ListingArgs));
521 assert(0 != sptr->listing);
522 memcpy(sptr->listing, &args, sizeof(struct ListingArgs));
523 if ((sptr->listing->chptr = GlobalChannelList)) {
524 int m = GlobalChannelList->mode.mode & MODE_LISTED;
525 list_next_channels(sptr, 64);
526 GlobalChannelList->mode.mode |= m;
529 MyFree(sptr->listing);
532 sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]); /* XXX DEAD */
536 for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
538 chptr = FindChannel(name);
539 if (chptr && ShowChannel(sptr, chptr) && sptr->user)
540 sendto_one(sptr, rpl_str(RPL_LIST), me.name, parv[0], /* XXX DEAD */
541 ShowChannel(sptr, chptr) ? chptr->chname : "*",
542 chptr->users - number_of_zombies(chptr), chptr->topic);
545 sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]); /* XXX DEAD */