]>
jfr.im git - irc/quakenet/snircd.git/blob - ircd/m_names.c
2 * IRC - Internet Relay Chat, ircd/m_names.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.
23 * $Id: m_names.c,v 1.22.2.2 2005/11/17 00:05:00 entrope Exp $
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
89 #include "ircd_reply.h"
90 #include "ircd_string.h"
97 /* #include <assert.h> -- Now using assert in ircd_log.h */
101 * Sends a suitably formatted 'names' reply to 'sptr' consisting of nicks within
102 * 'chptr', depending on 'filter'.
104 * NAMES_ALL - Lists all users on channel.
105 * NAMES_VIS - Only list visible (-i) users. --Gte (04/06/2000).
106 * NAMES_EON - When OR'd with the other two, adds an 'End of Names' numeric
111 void do_names(struct Client
* sptr
, struct Channel
* chptr
, int filter
)
119 struct Client
*c2ptr
;
120 struct Membership
* member
;
124 assert((filter
&NAMES_ALL
) != (filter
&NAMES_VIS
));
126 /* Tag Pub/Secret channels accordingly. */
129 if (PubChannel(chptr
))
131 else if (SecretChannel(chptr
))
134 len
= strlen(chptr
->chname
);
135 strcpy(buf
+ 2, chptr
->chname
);
136 strcpy(buf
+ 2 + len
, " :");
142 if (!ShowChannel(sptr
, chptr
)) /* Don't list private channels unless we are on them. */
145 /* Iterate over all channel members, and build up the list. */
147 mlen
= strlen(cli_name(&me
)) + 10 + strlen(cli_name(sptr
));
149 for (member
= chptr
->members
; member
; member
= member
->next_member
)
151 c2ptr
= member
->user
;
153 if (((filter
&NAMES_VIS
)!=0) && IsInvisible(c2ptr
))
156 if (IsZombie(member
) && member
->user
!= sptr
)
159 if (IsDelayedJoin(member
) && (member
->user
!= sptr
) && !(filter
& NAMES_DEL
))
162 if ((!IsDelayedJoin(member
) || (member
->user
== sptr
)) && (filter
& NAMES_DEL
))
170 if (IsZombie(member
))
175 else if (IsChanOp(member
))
180 else if (HasVoice(member
))
185 strcat(buf
, cli_name(c2ptr
));
186 idx
+= strlen(cli_name(c2ptr
));
188 if (mlen
+ idx
+ NICKLEN
+ 5 > BUFSIZE
)
189 /* space, modifier, nick, \r \n \0 */
191 send_reply(sptr
, (filter
& NAMES_DEL
) ? RPL_DELNAMREPLY
: RPL_NAMREPLY
, buf
);
198 send_reply(sptr
, (filter
& NAMES_DEL
) ? RPL_DELNAMREPLY
: RPL_NAMREPLY
, buf
);
199 if (filter
&NAMES_EON
)
200 send_reply(sptr
, RPL_ENDOFNAMES
, chptr
->chname
);
204 * m_names - generic message handler
206 * parv[0] = sender prefix
210 int m_names(struct Client
* cptr
, struct Client
* sptr
, int parc
, char* parv
[])
212 struct Channel
*chptr
;
213 struct Channel
*ch2ptr
;
214 struct Client
*c2ptr
;
215 struct Membership
* member
;
217 char* para
= parc
> 1 ? parv
[1] : 0;
218 int showingdelayed
= 0;
220 if (parc
> 1 && !ircd_strcmp(parv
[1], "-D")) {
221 para
= (parc
> 2) ? parv
[2] : 0;
223 if (parc
> 3 && hunt_server_cmd(sptr
, CMD_NAMES
, cptr
, 1, "%s %s %C", 3, parc
, parv
))
225 } else if (parc
> 2 && hunt_server_cmd(sptr
, CMD_NAMES
, cptr
, 1, "%s %C", 2, parc
, parv
))
228 if (EmptyString(para
)) {
229 send_reply(sptr
, RPL_ENDOFNAMES
, "*");
232 else if (*para
== '0')
235 s
= strchr(para
, ','); /* Recursively call m_names for each comma-separated channel. Eww. */
238 parv
[1+showingdelayed
] = s
;
239 m_names(cptr
, sptr
, parc
, parv
);
243 * Special Case 1: "/names 0".
244 * Full list as per RFC.
251 struct Channel
*ch3ptr
;
254 mlen
= strlen(cli_name(&me
)) + 10 + strlen(cli_name(sptr
));
256 /* List all visible channels/visible members */
258 for (ch2ptr
= GlobalChannelList
; ch2ptr
; ch2ptr
= ch2ptr
->next
)
260 if (!ShowChannel(sptr
, ch2ptr
))
261 continue; /* Don't show secret chans. */
263 if (find_channel_member(sptr
, ch2ptr
))
265 do_names(sptr
, ch2ptr
, (showingdelayed
?NAMES_DEL
:0)|NAMES_ALL
); /* Full list if we're in this chan. */
267 do_names(sptr
, ch2ptr
, (showingdelayed
?NAMES_DEL
:0)|NAMES_VIS
);
271 /* List all remaining users on channel '*' */
273 strcpy(buf
, "* * :");
277 for (c2ptr
= GlobalClientList
; c2ptr
; c2ptr
= cli_next(c2ptr
))
281 if (!IsUser(c2ptr
) || (sptr
!= c2ptr
&& IsInvisible(c2ptr
)))
284 member
= cli_user(c2ptr
)->channel
;
288 ch3ptr
= member
->channel
;
290 if (PubChannel(ch3ptr
) || find_channel_member(sptr
, ch3ptr
))
293 member
= member
->next_channel
;
296 if (showflag
) /* Have we already shown them? */
299 strcat(buf
, cli_name(c2ptr
));
301 idx
+= strlen(cli_name(c2ptr
)) + 1;
304 if (mlen
+ idx
+ NICKLEN
+ 3 > BUFSIZE
) /* space, \r\n\0 */
306 send_reply(sptr
, RPL_NAMREPLY
, buf
);
307 strcpy(buf
, "* * :");
313 send_reply(sptr
, RPL_NAMREPLY
, buf
);
314 send_reply(sptr
, RPL_ENDOFNAMES
, "*");
319 * Special Case 2: User is on this channel, requesting full names list.
320 * (As performed with each /join) - ** High frequency usage **
323 chptr
= FindChannel(para
);
326 member
= find_member_link(chptr
, sptr
);
329 do_names(sptr
, chptr
, (showingdelayed
?NAMES_DEL
:0)|NAMES_ALL
);
330 if (!EmptyString(para
))
332 send_reply(sptr
, RPL_ENDOFNAMES
, chptr
? chptr
->chname
: para
);
339 * Special Case 3: User isn't on this channel, show all visible users, in
340 * non secret channels.
342 do_names(sptr
, chptr
, (showingdelayed
?NAMES_DEL
:0)|NAMES_VIS
);
343 send_reply(sptr
, RPL_ENDOFNAMES
, para
);
345 } else { /* Channel doesn't exist. */
346 send_reply(sptr
, RPL_ENDOFNAMES
, para
);
353 * ms_names - server message handler
355 * parv[0] = sender prefix
358 int ms_names(struct Client
* cptr
, struct Client
* sptr
, int parc
, char* parv
[])
360 struct Channel
*chptr
;
361 struct Channel
*ch2ptr
;
362 struct Client
*c2ptr
;
363 struct Membership
* member
;
365 char* para
= parc
> 1 ? parv
[1] : 0;
366 int showingdelayed
= 0;
368 if (parc
> 1 && !ircd_strcmp(parv
[1], "-D")) {
369 para
= (parc
> 2) ? parv
[2] : 0;
370 showingdelayed
= NAMES_DEL
;
371 if (parc
> 3 && hunt_server_cmd(sptr
, CMD_NAMES
, cptr
, 1, "%s %s %C", 3, parc
, parv
))
373 } else if (parc
> 2 && hunt_server_cmd(sptr
, CMD_NAMES
, cptr
, 1, "%s %C", 2, parc
, parv
))
376 if (EmptyString(para
)) {
377 send_reply(sptr
, RPL_ENDOFNAMES
, "*");
380 else if (*para
== '0')
383 s
= strchr(para
, ','); /* Recursively call m_names for each comma-separated channel. */
386 parv
[1+!!showingdelayed
] = s
;
387 m_names(cptr
, sptr
, parc
, parv
);
391 * Special Case 1: "/names 0".
392 * Full list as per RFC.
399 struct Channel
*ch3ptr
;
402 mlen
= strlen(cli_name(&me
)) + 10 + strlen(cli_name(sptr
));
404 /* List all visible channels/visible members */
406 for (ch2ptr
= GlobalChannelList
; ch2ptr
; ch2ptr
= ch2ptr
->next
)
408 if (!ShowChannel(sptr
, ch2ptr
))
409 continue; /* Don't show secret chans. */
411 if (find_channel_member(sptr
, ch2ptr
))
413 do_names(sptr
, ch2ptr
, showingdelayed
|NAMES_ALL
); /* Full list if we're in this chan. */
415 do_names(sptr
, ch2ptr
, showingdelayed
|NAMES_VIS
);
419 /* List all remaining users on channel '*' */
421 strcpy(buf
, "* * :");
425 for (c2ptr
= GlobalClientList
; c2ptr
; c2ptr
= cli_next(c2ptr
))
429 if (!IsUser(c2ptr
) || (sptr
!= c2ptr
&& IsInvisible(c2ptr
)))
432 member
= cli_user(c2ptr
)->channel
;
436 ch3ptr
= member
->channel
;
438 if (PubChannel(ch3ptr
) || find_channel_member(sptr
, ch3ptr
))
441 member
= member
->next_channel
;
444 if (showflag
) /* Have we already shown them? */
447 strcat(buf
, cli_name(c2ptr
));
449 idx
+= strlen(cli_name(c2ptr
)) + 1;
452 if (mlen
+ idx
+ NICKLEN
+ 3 > BUFSIZE
) /* space, \r\n\0 */
454 send_reply(sptr
, RPL_NAMREPLY
, buf
);
455 strcpy(buf
, "* * :");
461 send_reply(sptr
, RPL_NAMREPLY
, buf
);
462 send_reply(sptr
, RPL_ENDOFNAMES
, "*");
467 * Special Case 2: User is on this channel, requesting full names list.
468 * (As performed with each /join) - ** High frequency usage **
471 chptr
= FindChannel(para
);
474 member
= find_member_link(chptr
, sptr
);
477 do_names(sptr
, chptr
, showingdelayed
|NAMES_ALL
);
478 if (!EmptyString(para
))
480 send_reply(sptr
, RPL_ENDOFNAMES
, chptr
? chptr
->chname
: para
);
487 * Special Case 3: User isn't on this channel, show all visible users, in
488 * non secret channels.
490 do_names(sptr
, chptr
, showingdelayed
|NAMES_VIS
);
492 } else { /* Channel doesn't exist. */
493 send_reply(sptr
, RPL_ENDOFNAMES
, para
);