]>
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 list
12 * CMDHELP: USERS requires you to be known (+k) on the named channel. You must also be on the
13 * CMDHELP: channel yourself.
16 #include "../chanserv.h"
17 #include "../../nick/nick.h"
18 #include "../../lib/flags.h"
19 #include "../../lib/irc_string.h"
20 #include "../../channel/channel.h"
21 #include "../../parser/parser.h"
22 #include "../../irc/irc.h"
23 #include "../../localuser/localuserchannel.h"
27 /* Random flags and structs and sort functions which will come in handly later */
29 #define ISQ 0x40000000
30 #define ISOP 0x20000000
31 #define ISV 0x10000000
40 static int comparetheflags(const void *a
, const void *b
) {
41 const struct chanuserrec
*ra
=a
, *rb
=b
;
43 return rb
->flags
-ra
->flags
;
46 int csc_dousers(void *source
, int cargc
, char **cargv
) {
47 nick
*sender
=source
, *np
;
48 reguser
*rup
=getreguserfromnick(sender
);
51 struct chanuserrec
*theusers
;
55 char *flagbuf
, *unbuf
, modechar
;
56 char uhbuf
[USERLEN
+HOSTLEN
+2];
58 unsigned int ops
,voices
,users
,flags
,qops
,masters
;
59 unsigned int notonchan
=0;
62 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "users");
66 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_KNOWN
,
67 NULL
, "users", QPRIV_VIEWFULLCHANLEV
, 0)))
70 rcp
=cip
->exts
[chanservext
];
72 if (!(cp
=cip
->channel
)) {
73 chanservstdmessage(sender
,QM_EMPTYCHAN
,cip
->name
->content
);
77 /* Two part logic here. Firstly, only staff are allowed to look at
78 * channels they are not on. But later we will prevent them looking at
79 * channels with opers on them, but clearly it's ok to do this on any
80 * channel you are actually on regardless of whether there is an oper or
81 * not. So extract this "notonchan" status here and use it in the later
82 * checks. We set "notonchan" if you are not an oper and not on the
83 * channel. Non-staff with "notonchan" set are then immediately rebuffed.
85 if (!getnumerichandlefromchanhash(cip
->channel
->users
,sender
->numeric
) &&
89 if (!cs_privcheck(QPRIV_VIEWFULLCHANLEV
, sender
) && notonchan
) {
90 chanservstdmessage(sender
,QM_NOTONCHAN
,cip
->name
->content
);
94 /* malloc() time: if we abort after here we should goto out; rather than
96 theusers
=malloc(cp
->users
->totalusers
* sizeof(struct chanuserrec
));
97 memset(theusers
,0,cp
->users
->totalusers
* sizeof(struct chanuserrec
));
99 /* OK, fill in our custom struct with useful info about each actual user */
100 for (i
=0,j
=0;i
<cp
->users
->hashsize
;i
++) {
101 if (cp
->users
->content
[i
]==nouser
)
104 /* shouldn't happen */
105 if (!(np
=getnickbynumeric(cp
->users
->content
[i
])))
108 /* Don't let non-opers look at channels with opers in. How paranoid are we?
109 * Obviously if you are on the channel yourself, no such silliness is necessary.
110 * Making the arbitrary assumption that one letter nicks are OK as per helpmod2.
112 if (notonchan
&& IsOper(np
) && np
->nick
[1] &&
113 (IsSecret(cp
) || IsPrivate(cp
) || IsKey(cp
) || IsInviteOnly(cp
))) {
114 chanservstdmessage(sender
,QM_OPERONCHAN
,"users",cip
->name
->content
);
120 /* Copy op and voice bits from the chanuser */
121 theusers
[j
].flags
=(cp
->users
->content
[i
]>>2) & 0x30000000;
123 /* Make sure we come out at the top of the list */
124 if (np
==chanservnick
) {
125 theusers
[j
].flags
|=0x40000000;
128 theusers
[j
].rup
=getreguserfromnick(np
);
129 if (theusers
[j
].rup
) {
130 theusers
[j
].rcup
=findreguseronchannel(rcp
, theusers
[j
].rup
);
131 /* OR in the chanlev flags at the bottom if they are known */
132 if (theusers
[j
].rcup
)
133 theusers
[j
].flags
|= theusers
[j
].rcup
->flags
;
138 qsort(theusers
, j
, sizeof(struct chanuserrec
), comparetheflags
);
140 chanservstdmessage(sender
, QM_USERSHEADER
, cip
->name
->content
);
142 /* Determine what flags to show. Public flags always OK, punishment flags
143 * for masters only, personal flags for yourself only except staff who can
144 * see all. Obviously we have to do the bit about personal flags later on...
146 flagmask
=QCUFLAGS_PUBLIC
;
147 ops
=voices
=users
=flags
=qops
=masters
=0;
148 if (cs_checkaccess(sender
, NULL
, CA_MASTERPRIV
, cip
, "users", 0, 1))
149 flagmask
|= QCUFLAGS_PUNISH
;
151 if (cs_privcheck(QPRIV_VIEWFULLCHANLEV
, sender
))
152 flagmask
= QCUFLAG_ALL
;
155 if (theusers
[i
].flags
& ISOP
) {
158 } else if (theusers
[i
].flags
& ISV
) {
166 if (theusers
[i
].flags
& ISQ
) {
167 /* OK so in reality we may actually have a username and even some
168 * flags. But those don't really matter so let's sub in a cute message. */
172 if (theusers
[i
].rup
) {
173 unbuf
=theusers
[i
].rup
->username
;
178 rcup
=theusers
[i
].rcup
;
182 if (CUHasOpPriv(rcup
))
185 if (CUIsMaster(rcup
) || CUIsOwner(rcup
))
189 /* Subtlety here: we conditionally OR in the personal flags for
190 * display but not for the check. This is because if you have
191 * personal flags you must have some public flag too by definition.
192 * Compare based on reguser so you can see personal flags for all
193 * clones on your account. */
194 if (theusers
[i
].rcup
&& (theusers
[i
].rcup
->flags
& flagmask
)) {
195 flagbuf
=printflags((flagmask
| (theusers
[i
].rup
==rup
?QCUFLAGS_PERSONAL
:0)) & theusers
[i
].rcup
->flags
, rcuflags
);
201 chanservsendmessage(sender
, "%c%-15s %-15s %-12s (%s)",modechar
,np
->nick
,unbuf
,flagbuf
,visibleuserhost(np
, uhbuf
));
205 chanservstdmessage(sender
, QM_ENDOFLIST
);
206 chanservstdmessage(sender
, QM_USERSSUMMARY
, j
, ops
, voices
, users
, flags
, qops
, masters
);