]>
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.1 2005/10/06 04:00:26 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
);
193 ircd_strncpy(buf
+ 2, chptr
->chname
, len
+ 1);
196 if (PubChannel(chptr
))
198 else if (SecretChannel(chptr
))
206 send_reply(sptr
, (filter
& NAMES_DEL
) ? RPL_DELNAMREPLY
: RPL_NAMREPLY
, buf
);
207 if (filter
&NAMES_EON
)
208 send_reply(sptr
, RPL_ENDOFNAMES
, chptr
->chname
);
212 * m_names - generic message handler
214 * parv[0] = sender prefix
218 int m_names(struct Client
* cptr
, struct Client
* sptr
, int parc
, char* parv
[])
220 struct Channel
*chptr
;
221 struct Channel
*ch2ptr
;
222 struct Client
*c2ptr
;
223 struct Membership
* member
;
225 char* para
= parc
> 1 ? parv
[1] : 0;
226 int showingdelayed
= 0;
228 if (parc
> 1 && !ircd_strcmp(parv
[1], "-D")) {
229 para
= (parc
> 2) ? parv
[2] : 0;
231 if (parc
> 3 && hunt_server_cmd(sptr
, CMD_NAMES
, cptr
, 1, "%s %s %C", 3, parc
, parv
))
233 } else if (parc
> 2 && hunt_server_cmd(sptr
, CMD_NAMES
, cptr
, 1, "%s %C", 2, parc
, parv
))
236 if (EmptyString(para
)) {
237 send_reply(sptr
, RPL_ENDOFNAMES
, "*");
240 else if (*para
== '0')
243 s
= strchr(para
, ','); /* Recursively call m_names for each comma-separated channel. Eww. */
245 parv
[1+showingdelayed
] = ++s
;
246 m_names(cptr
, sptr
, parc
, parv
);
250 * Special Case 1: "/names 0".
251 * Full list as per RFC.
258 struct Channel
*ch3ptr
;
261 mlen
= strlen(cli_name(&me
)) + 10 + strlen(cli_name(sptr
));
263 /* List all visible channels/visible members */
265 for (ch2ptr
= GlobalChannelList
; ch2ptr
; ch2ptr
= ch2ptr
->next
)
267 if (!ShowChannel(sptr
, ch2ptr
))
268 continue; /* Don't show secret chans. */
270 if (find_channel_member(sptr
, ch2ptr
))
272 do_names(sptr
, ch2ptr
, (showingdelayed
?NAMES_DEL
:0)|NAMES_ALL
); /* Full list if we're in this chan. */
274 do_names(sptr
, ch2ptr
, (showingdelayed
?NAMES_DEL
:0)|NAMES_VIS
);
278 /* List all remaining users on channel '*' */
280 strcpy(buf
, "* * :");
284 for (c2ptr
= GlobalClientList
; c2ptr
; c2ptr
= cli_next(c2ptr
))
288 if (!IsUser(c2ptr
) || (sptr
!= c2ptr
&& IsInvisible(c2ptr
)))
291 member
= cli_user(c2ptr
)->channel
;
295 ch3ptr
= member
->channel
;
297 if (PubChannel(ch3ptr
) || find_channel_member(sptr
, ch3ptr
))
300 member
= member
->next_channel
;
303 if (showflag
) /* Have we already shown them? */
306 strcat(buf
, cli_name(c2ptr
));
308 idx
+= strlen(cli_name(c2ptr
)) + 1;
311 if (mlen
+ idx
+ NICKLEN
+ 3 > BUFSIZE
) /* space, \r\n\0 */
313 send_reply(sptr
, RPL_NAMREPLY
, buf
);
314 strcpy(buf
, "* * :");
320 send_reply(sptr
, RPL_NAMREPLY
, buf
);
321 send_reply(sptr
, RPL_ENDOFNAMES
, "*");
326 * Special Case 2: User is on this channel, requesting full names list.
327 * (As performed with each /join) - ** High frequency usage **
330 chptr
= FindChannel(para
);
333 member
= find_member_link(chptr
, sptr
);
336 do_names(sptr
, chptr
, (showingdelayed
?NAMES_DEL
:0)|NAMES_ALL
);
337 if (!EmptyString(para
))
339 send_reply(sptr
, RPL_ENDOFNAMES
, chptr
? chptr
->chname
: para
);
346 * Special Case 3: User isn't on this channel, show all visible users, in
347 * non secret channels.
349 do_names(sptr
, chptr
, (showingdelayed
?NAMES_DEL
:0)|NAMES_VIS
);
350 send_reply(sptr
, RPL_ENDOFNAMES
, para
);
352 } else { /* Channel doesn't exist. */
353 send_reply(sptr
, RPL_ENDOFNAMES
, para
);
360 * ms_names - server message handler
362 * parv[0] = sender prefix
365 int ms_names(struct Client
* cptr
, struct Client
* sptr
, int parc
, char* parv
[])
367 struct Channel
*chptr
;
368 struct Channel
*ch2ptr
;
369 struct Client
*c2ptr
;
370 struct Membership
* member
;
372 char* para
= parc
> 1 ? parv
[1] : 0;
373 int showingdelayed
= 0;
375 if (parc
> 1 && !ircd_strcmp(parv
[1], "-D")) {
376 para
= (parc
> 2) ? parv
[2] : 0;
377 showingdelayed
= NAMES_DEL
;
378 if (parc
> 3 && hunt_server_cmd(sptr
, CMD_NAMES
, cptr
, 1, "%s %s %C", 3, parc
, parv
))
380 } else if (parc
> 2 && hunt_server_cmd(sptr
, CMD_NAMES
, cptr
, 1, "%s %C", 2, parc
, parv
))
383 if (EmptyString(para
)) {
384 send_reply(sptr
, RPL_ENDOFNAMES
, "*");
387 else if (*para
== '0')
390 s
= strchr(para
, ','); /* Recursively call m_names for each comma-separated channel. */
392 parv
[1+!!showingdelayed
] = ++s
;
393 m_names(cptr
, sptr
, parc
, parv
);
397 * Special Case 1: "/names 0".
398 * Full list as per RFC.
405 struct Channel
*ch3ptr
;
408 mlen
= strlen(cli_name(&me
)) + 10 + strlen(cli_name(sptr
));
410 /* List all visible channels/visible members */
412 for (ch2ptr
= GlobalChannelList
; ch2ptr
; ch2ptr
= ch2ptr
->next
)
414 if (!ShowChannel(sptr
, ch2ptr
))
415 continue; /* Don't show secret chans. */
417 if (find_channel_member(sptr
, ch2ptr
))
419 do_names(sptr
, ch2ptr
, showingdelayed
|NAMES_ALL
); /* Full list if we're in this chan. */
421 do_names(sptr
, ch2ptr
, showingdelayed
|NAMES_VIS
);
425 /* List all remaining users on channel '*' */
427 strcpy(buf
, "* * :");
431 for (c2ptr
= GlobalClientList
; c2ptr
; c2ptr
= cli_next(c2ptr
))
435 if (!IsUser(c2ptr
) || (sptr
!= c2ptr
&& IsInvisible(c2ptr
)))
438 member
= cli_user(c2ptr
)->channel
;
442 ch3ptr
= member
->channel
;
444 if (PubChannel(ch3ptr
) || find_channel_member(sptr
, ch3ptr
))
447 member
= member
->next_channel
;
450 if (showflag
) /* Have we already shown them? */
453 strcat(buf
, cli_name(c2ptr
));
455 idx
+= strlen(cli_name(c2ptr
)) + 1;
458 if (mlen
+ idx
+ NICKLEN
+ 3 > BUFSIZE
) /* space, \r\n\0 */
460 send_reply(sptr
, RPL_NAMREPLY
, buf
);
461 strcpy(buf
, "* * :");
467 send_reply(sptr
, RPL_NAMREPLY
, buf
);
468 send_reply(sptr
, RPL_ENDOFNAMES
, "*");
473 * Special Case 2: User is on this channel, requesting full names list.
474 * (As performed with each /join) - ** High frequency usage **
477 chptr
= FindChannel(para
);
480 member
= find_member_link(chptr
, sptr
);
483 do_names(sptr
, chptr
, showingdelayed
|NAMES_ALL
);
484 if (!EmptyString(para
))
486 send_reply(sptr
, RPL_ENDOFNAMES
, chptr
? chptr
->chname
: para
);
493 * Special Case 3: User isn't on this channel, show all visible users, in
494 * non secret channels.
496 do_names(sptr
, chptr
, showingdelayed
|NAMES_VIS
);
498 } else { /* Channel doesn't exist. */
499 send_reply(sptr
, RPL_ENDOFNAMES
, para
);