]>
jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chancmds/users.c
3 * CMDLEVEL: QCMD_AUTHED
5 * CMDDESC: Displays a list of users on the channel.
7 * CMDPROTO: int csc_dousers(void *source, int cargc, char **cargv);
8 * CMDHELP: Usage: USERS <channel>
9 * CMDHELP: Displays a list of users on the named channel along with their usernames and flags
10 * CMDHELP: on the channel, where:
11 * CMDHELP: channel - channel to use
12 * CMDHELP: USERS requires operator (+o) access on the named channel.
15 #include "../chanserv.h"
16 #include "../../nick/nick.h"
17 #include "../../lib/flags.h"
18 #include "../../lib/irc_string.h"
19 #include "../../channel/channel.h"
20 #include "../../parser/parser.h"
21 #include "../../irc/irc.h"
22 #include "../../localuser/localuserchannel.h"
26 /* Random flags and structs and sort functions which will come in handly later */
28 #define ISQ 0x40000000
29 #define ISOP 0x20000000
30 #define ISV 0x10000000
39 static int comparetheflags(const void *a
, const void *b
) {
40 const struct chanuserrec
*ra
=a
, *rb
=b
;
42 return rb
->flags
-ra
->flags
;
45 int csc_dousers(void *source
, int cargc
, char **cargv
) {
46 nick
*sender
=source
, *np
;
47 reguser
*rup
=getreguserfromnick(sender
);
50 struct chanuserrec
*theusers
;
54 char *flagbuf
, *unbuf
, modechar
;
55 char uhbuf
[USERLEN
+HOSTLEN
+2];
57 unsigned int ops
,voices
,users
,flags
,qops
,masters
;
58 unsigned int notonchan
=0;
61 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "users");
65 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_KNOWN
,
66 NULL
, "users", QPRIV_VIEWFULLCHANLEV
, 0)))
69 rcp
=cip
->exts
[chanservext
];
71 if (!(cp
=cip
->channel
)) {
72 chanservstdmessage(sender
,QM_EMPTYCHAN
,cip
->name
->content
);
76 /* Two part logic here. Firstly, only staff are allowed to look at
77 * channels they are not on. But later we will prevent them looking at
78 * channels with opers on them, but clearly it's ok to do this on any
79 * channel you are actually on regardless of whether there is an oper or
80 * not. So extract this "notonchan" status here and use it in the later
81 * checks. We set "notonchan" if you are not an oper and not on the
82 * channel. Non-staff with "notonchan" set are then immediately rebuffed.
84 if (!getnumerichandlefromchanhash(cip
->channel
->users
,sender
->numeric
) &&
88 if (!cs_privcheck(QPRIV_VIEWFULLCHANLEV
, sender
) && notonchan
) {
89 chanservstdmessage(sender
,QM_NOTONCHAN
,cip
->name
->content
);
93 /* malloc() time: if we abort after here we should goto out; rather than
95 theusers
=malloc(cp
->users
->totalusers
* sizeof(struct chanuserrec
));
96 memset(theusers
,0,cp
->users
->totalusers
* sizeof(struct chanuserrec
));
98 /* OK, fill in our custom struct with useful info about each actual user */
99 for (i
=0,j
=0;i
<cp
->users
->hashsize
;i
++) {
100 if (cp
->users
->content
[i
]==nouser
)
103 /* shouldn't happen */
104 if (!(np
=getnickbynumeric(cp
->users
->content
[i
])))
107 /* Don't let non-opers look at channels with opers in. How paranoid are we?
108 * Obviously if you are on the channel yourself, no such silliness is necessary.
109 * Making the arbitrary assumption that one letter nicks are OK as per helpmod2.
111 if (notonchan
&& IsOper(np
) && np
->nick
[1] &&
112 (IsSecret(cp
) || IsPrivate(cp
) || IsKey(cp
) || IsInviteOnly(cp
))) {
113 chanservstdmessage(sender
,QM_OPERONCHAN
,"users",cip
->name
->content
);
119 /* Copy op and voice bits from the chanuser */
120 theusers
[j
].flags
=(cp
->users
->content
[i
]>>2) & 0x30000000;
122 /* Make sure we come out at the top of the list */
123 if (np
==chanservnick
) {
124 theusers
[j
].flags
|=0x40000000;
127 theusers
[j
].rup
=getreguserfromnick(np
);
128 if (theusers
[j
].rup
) {
129 theusers
[j
].rcup
=findreguseronchannel(rcp
, theusers
[j
].rup
);
130 /* OR in the chanlev flags at the bottom if they are known */
131 if (theusers
[j
].rcup
)
132 theusers
[j
].flags
|= theusers
[j
].rcup
->flags
;
137 qsort(theusers
, j
, sizeof(struct chanuserrec
), comparetheflags
);
139 chanservstdmessage(sender
, QM_USERSHEADER
, cip
->name
->content
);
141 /* Determine what flags to show. Public flags always OK, punishment flags
142 * for masters only, personal flags for yourself only except staff who can
143 * see all. Obviously we have to do the bit about personal flags later on...
145 flagmask
=QCUFLAGS_PUBLIC
;
146 ops
=voices
=users
=flags
=qops
=masters
=0;
147 if (cs_checkaccess(sender
, NULL
, CA_MASTERPRIV
, cip
, "users", 0, 1))
148 flagmask
|= QCUFLAGS_PUNISH
;
150 if (cs_privcheck(QPRIV_VIEWFULLCHANLEV
, sender
))
151 flagmask
= QCUFLAG_ALL
;
154 if (theusers
[i
].flags
& ISOP
) {
157 } else if (theusers
[i
].flags
& ISV
) {
165 if (theusers
[i
].flags
& ISQ
) {
166 /* OK so in reality we may actually have a username and even some
167 * flags. But those don't really matter so let's sub in a cute message. */
171 if (theusers
[i
].rup
) {
172 unbuf
=theusers
[i
].rup
->username
;
177 rcup
=theusers
[i
].rcup
;
181 if (CUHasOpPriv(rcup
))
184 if (CUIsMaster(rcup
) || CUIsOwner(rcup
))
188 /* Subtlety here: we conditionally OR in the personal flags for
189 * display but not for the check. This is because if you have
190 * personal flags you must have some public flag too by definition.
191 * Compare based on reguser so you can see personal flags for all
192 * clones on your account. */
193 if (theusers
[i
].rcup
&& (theusers
[i
].rcup
->flags
& flagmask
)) {
194 flagbuf
=printflags((flagmask
| (theusers
[i
].rup
==rup
?QCUFLAGS_PERSONAL
:0)) & theusers
[i
].rcup
->flags
, rcuflags
);
200 chanservsendmessage(sender
, "%c%-15s %-15s %-12s (%s)",modechar
,np
->nick
,unbuf
,flagbuf
,visibleuserhost(np
, uhbuf
));
204 chanservstdmessage(sender
, QM_ENDOFLIST
);
205 chanservstdmessage(sender
, QM_USERSSUMMARY
, j
, ops
, voices
, users
, flags
, qops
, masters
);