]> jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chancmds/users.c
Added new USERS command - shows channel users with account names and Q flags.
[irc/quakenet/newserv.git] / chanserv / chancmds / users.c
1 /*
2 * CMDNAME: users
3 * CMDLEVEL: QCMD_AUTHED
4 * CMDARGS: 1
5 * CMDDESC: Displays a list of users on the channel.
6 * CMDFUNC: csc_dousers
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.
13 */
14
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"
23 #include <string.h>
24 #include <stdio.h>
25
26 #define ISQ 0x40000000
27 #define ISOP 0x20000000
28 #define ISV 0x10000000
29
30 struct chanuserrec {
31 unsigned int flags; /* Something that sorts nicely */
32 regchanuser *rcup;
33 reguser *rup;
34 nick *np;
35 };
36
37 static int comparetheflags(const void *a, const void *b) {
38 const struct chanuserrec *ra=a, *rb=b;
39
40 return rb->flags-ra->flags;
41 }
42
43 int csc_dousers(void *source, int cargc, char **cargv) {
44 nick *sender=source, *np;
45 chanindex *cip;
46 regchan *rcp;
47 struct chanuserrec *theusers;
48 regchanuser *rcup;
49 channel *cp;
50 unsigned int i,j;
51 char *flagbuf, *unbuf, modechar;
52 char uhbuf[USERLEN+HOSTLEN+2];
53 flag_t flagmask;
54 unsigned int ops,voices,users,flags,qops,masters;
55
56 if (cargc<1) {
57 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "users");
58 return CMD_ERROR;
59 }
60
61 if (!(cip=cs_checkaccess(sender, cargv[0], CA_OPPRIV,
62 NULL, "users", QPRIV_VIEWFULLCHANLEV, 0)))
63 return CMD_ERROR;
64
65 rcp=cip->exts[chanservext];
66
67 if (!(cp=cip->channel)) {
68 chanservstdmessage(sender,QM_EMPTYCHAN,cip->name->content);
69 return CMD_ERROR;
70 }
71
72 if (!cs_privcheck(QPRIV_VIEWFULLCHANLEV, sender) && !getnumerichandlefromchanhash(cip->channel->users,sender->numeric)) {
73 chanservstdmessage(sender,QM_NOTONCHAN,cip->name->content);
74 return CMD_ERROR;
75 }
76
77 theusers=malloc(cp->users->totalusers * sizeof(struct chanuserrec));
78 memset(theusers,0,cp->users->totalusers * sizeof(struct chanuserrec));
79
80 for (i=0,j=0;i<cp->users->hashsize;i++) {
81 if (cp->users->content[i]==nouser)
82 continue;
83
84 if (!(np=getnickbynumeric(cp->users->content[i])))
85 goto out;
86
87 theusers[j].np=np;
88
89 theusers[j].flags=(cp->users->content[i]>>2) & 0x30000000;
90
91 if (np==chanservnick) {
92 theusers[j].flags|=0x40000000;
93 }
94
95 theusers[j].rup=getreguserfromnick(np);
96 if (theusers[j].rup) {
97 theusers[j].rcup=findreguseronchannel(rcp, theusers[j].rup);
98 if (theusers[j].rcup)
99 theusers[j].flags |= theusers[j].rcup->flags;
100 }
101 j++;
102 }
103
104 qsort(theusers, j, sizeof(struct chanuserrec), comparetheflags);
105
106 chanservstdmessage(sender,QM_USERSHEADER, cip->name->content);
107
108 flagmask=QCUFLAGS_PUBLIC;
109 ops=voices=users=flags=qops=masters=0;
110 if (cs_checkaccess(sender, NULL, CA_MASTERPRIV, cip, "users", 0, 1))
111 flagmask |= QCUFLAGS_PUNISH;
112
113 if (cs_privcheck(QPRIV_VIEWFULLCHANLEV, sender))
114 flagmask = QCUFLAG_ALL;
115
116 for (i=0;i<j;i++) {
117 if (theusers[i].flags & ISOP) {
118 ops++;
119 modechar='@';
120 } else if (theusers[i].flags & ISV) {
121 voices++;
122 modechar='+';
123 } else {
124 users++;
125 modechar=' ';
126 }
127
128 if (theusers[i].flags & ISQ) {
129 modechar='@';
130 unbuf="It's me!";
131 flagbuf="";
132 } else {
133 if (theusers[i].rup) {
134 unbuf=theusers[i].rup->username;
135 } else {
136 unbuf="";
137 }
138
139 rcup=theusers[i].rcup;
140
141 if (rcup) {
142 flags++;
143 if (CUHasOpPriv(rcup))
144 qops++;
145
146 if (CUIsMaster(rcup) || CUIsOwner(rcup))
147 masters++;
148 }
149
150 if (theusers[i].rcup && (theusers[i].rcup->flags & flagmask)) {
151 flagbuf=printflags((flagmask | (theusers[i].np==sender?QCUFLAGS_PERSONAL:0)) & theusers[i].rcup->flags, rcuflags);
152 } else {
153 flagbuf="";
154 }
155 }
156 np=theusers[i].np;
157 chanservsendmessage(sender, "%c%-15s %-15s %-12s (%s)",modechar,np->nick,unbuf,flagbuf,visibleuserhost(np, uhbuf));
158 }
159 free(theusers);
160
161 chanservstdmessage(sender, QM_ENDOFLIST);
162 chanservstdmessage(sender, QM_USERSSUMMARY, j, ops, voices, users, flags, qops, masters);
163 return CMD_OK;
164
165 out:
166 free(theusers);
167 return CMD_ERROR;
168 }