]>
Commit | Line | Data |
---|---|---|
189935b1 | 1 | /* |
2 | * IRC - Internet Relay Chat, ircd/m_clearmode.c | |
3 | * Copyright (C) 1990 Jarkko Oikarinen and | |
4 | * University of Oulu, Computing Center | |
5 | * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu> | |
6 | * | |
7 | * See file AUTHORS in IRC package for additional names of | |
8 | * the programmers. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 1, or (at your option) | |
13 | * any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
23 | * | |
24 | * $Id: m_clearmode.c,v 1.31 2005/09/27 02:41:57 entrope Exp $ | |
25 | */ | |
26 | ||
27 | /* | |
28 | * m_functions execute protocol messages on this server: | |
29 | * | |
30 | * cptr is always NON-NULL, pointing to a *LOCAL* client | |
31 | * structure (with an open socket connected!). This | |
32 | * identifies the physical socket where the message | |
33 | * originated (or which caused the m_function to be | |
34 | * executed--some m_functions may call others...). | |
35 | * | |
36 | * sptr is the source of the message, defined by the | |
37 | * prefix part of the message if present. If not | |
38 | * or prefix not found, then sptr==cptr. | |
39 | * | |
40 | * (!IsServer(cptr)) => (cptr == sptr), because | |
41 | * prefixes are taken *only* from servers... | |
42 | * | |
43 | * (IsServer(cptr)) | |
44 | * (sptr == cptr) => the message didn't | |
45 | * have the prefix. | |
46 | * | |
47 | * (sptr != cptr && IsServer(sptr) means | |
48 | * the prefix specified servername. (?) | |
49 | * | |
50 | * (sptr != cptr && !IsServer(sptr) means | |
51 | * that message originated from a remote | |
52 | * user (not local). | |
53 | * | |
54 | * combining | |
55 | * | |
56 | * (!IsServer(sptr)) means that, sptr can safely | |
57 | * taken as defining the target structure of the | |
58 | * message in this server. | |
59 | * | |
60 | * *Always* true (if 'parse' and others are working correct): | |
61 | * | |
62 | * 1) sptr->from == cptr (note: cptr->from == cptr) | |
63 | * | |
64 | * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr | |
65 | * *cannot* be a local connection, unless it's | |
66 | * actually cptr!). [MyConnect(x) should probably | |
67 | * be defined as (x == x->from) --msa ] | |
68 | * | |
69 | * parc number of variable parameter strings (if zero, | |
70 | * parv is allowed to be NULL) | |
71 | * | |
72 | * parv a NULL terminated list of parameter pointers, | |
73 | * | |
74 | * parv[0], sender (prefix string), if not present | |
75 | * this points to an empty string. | |
76 | * parv[1]...parv[parc-1] | |
77 | * pointers to additional parameters | |
78 | * parv[parc] == NULL, *always* | |
79 | * | |
80 | * note: it is guaranteed that parv[0]..parv[parc-1] are all | |
81 | * non-NULL pointers. | |
82 | */ | |
83 | #include "config.h" | |
84 | ||
85 | #include "client.h" | |
86 | #include "channel.h" | |
87 | #include "hash.h" | |
88 | #include "ircd.h" | |
89 | #include "ircd_alloc.h" | |
90 | #include "ircd_features.h" | |
91 | #include "ircd_log.h" | |
92 | #include "ircd_reply.h" | |
93 | #include "ircd_string.h" | |
94 | #include "list.h" | |
95 | #include "msg.h" | |
96 | #include "numeric.h" | |
97 | #include "numnicks.h" | |
98 | #include "s_conf.h" | |
99 | #include "send.h" | |
100 | ||
101 | /* #include <assert.h> -- Now using assert in ircd_log.h */ | |
102 | ||
103 | /* | |
104 | * do_clearmode(struct Client *cptr, struct Client *sptr, | |
105 | * struct Channel *chptr, char *control) | |
106 | * | |
107 | * This is the function that actually clears the channel modes. | |
108 | */ | |
109 | static int | |
110 | do_clearmode(struct Client *cptr, struct Client *sptr, struct Channel *chptr, | |
111 | char *control) | |
112 | { | |
113 | static int flags[] = { | |
114 | MODE_CHANOP, 'o', | |
115 | MODE_VOICE, 'v', | |
116 | MODE_PRIVATE, 'p', | |
117 | MODE_SECRET, 's', | |
118 | MODE_MODERATED, 'm', | |
119 | MODE_TOPICLIMIT, 't', | |
120 | MODE_INVITEONLY, 'i', | |
121 | MODE_NOPRIVMSGS, 'n', | |
122 | MODE_KEY, 'k', | |
123 | MODE_BAN, 'b', | |
124 | MODE_LIMIT, 'l', | |
125 | MODE_REGONLY, 'r', | |
126 | MODE_DELJOINS, 'D', | |
149c0c9f | 127 | MODE_NOQUITPARTS, 'u', |
a378e1b2 | 128 | MODE_NOCOLOUR, 'c', |
129 | MODE_NOCTCP, 'C', | |
130 | MODE_NONOTICE, 'N', | |
189935b1 | 131 | 0x0, 0x0 |
132 | }; | |
133 | int *flag_p; | |
134 | unsigned int del_mode = 0; | |
135 | char control_buf[20]; | |
136 | int control_buf_i = 0; | |
137 | struct ModeBuf mbuf; | |
138 | struct Ban *link, *next; | |
139 | struct Membership *member; | |
140 | ||
141 | /* Ok, so what are we supposed to get rid of? */ | |
142 | for (; *control; control++) { | |
143 | for (flag_p = flags; flag_p[0]; flag_p += 2) | |
144 | if (*control == flag_p[1]) { | |
145 | del_mode |= flag_p[0]; | |
146 | break; | |
147 | } | |
148 | } | |
149 | ||
150 | if (!del_mode) | |
151 | return 0; /* nothing to remove; ho hum. */ | |
152 | ||
153 | modebuf_init(&mbuf, sptr, cptr, chptr, | |
154 | (MODEBUF_DEST_CHANNEL | /* Send MODE to channel */ | |
155 | MODEBUF_DEST_OPMODE | /* Treat it like an OPMODE */ | |
156 | MODEBUF_DEST_HACK4)); /* Generate a HACK(4) notice */ | |
157 | ||
158 | modebuf_mode(&mbuf, MODE_DEL | (del_mode & chptr->mode.mode)); | |
159 | chptr->mode.mode &= ~del_mode; /* and of course actually delete them */ | |
160 | ||
161 | /* If we're removing invite, remove all the invites */ | |
162 | if (del_mode & MODE_INVITEONLY) | |
163 | mode_invite_clear(chptr); | |
164 | ||
165 | /* | |
166 | * If we're removing the key, note that; note that we can't clear | |
167 | * the key until after modebuf_* are done with it | |
168 | */ | |
169 | if (del_mode & MODE_KEY && *chptr->mode.key) | |
170 | modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0); | |
171 | ||
172 | /* If we're removing the limit, note that and clear the limit */ | |
173 | if (del_mode & MODE_LIMIT && chptr->mode.limit) { | |
174 | modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit); | |
175 | chptr->mode.limit = 0; /* not referenced, so safe */ | |
176 | } | |
177 | ||
178 | /* | |
179 | * Go through and mark the bans for deletion; note that we can't | |
180 | * free them until after modebuf_* are done with them | |
181 | */ | |
182 | if (del_mode & MODE_BAN) { | |
183 | for (link = chptr->banlist; link; link = next) { | |
184 | char *bandup; | |
185 | next = link->next; | |
186 | ||
187 | DupString(bandup, link->banstr); | |
188 | modebuf_mode_string(&mbuf, MODE_DEL | MODE_BAN, /* delete ban */ | |
189 | bandup, 1); | |
190 | free_ban(link); | |
191 | } | |
192 | ||
193 | chptr->banlist = 0; | |
194 | } | |
195 | ||
196 | /* Deal with users on the channel */ | |
197 | if (del_mode & (MODE_BAN | MODE_CHANOP | MODE_VOICE)) | |
198 | for (member = chptr->members; member; member = member->next_member) { | |
199 | if (IsZombie(member)) /* we ignore zombies */ | |
200 | continue; | |
201 | ||
202 | if (del_mode & MODE_BAN) /* If we cleared bans, clear the valid flags */ | |
203 | ClearBanValid(member); | |
204 | ||
205 | /* Drop channel operator status */ | |
206 | if (IsChanOp(member) && del_mode & MODE_CHANOP) { | |
207 | modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, MAXOPLEVEL + 1); | |
208 | member->status &= ~CHFL_CHANOP; | |
209 | } | |
210 | ||
211 | /* Drop voice */ | |
212 | if (HasVoice(member) && del_mode & MODE_VOICE) { | |
213 | modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, MAXOPLEVEL + 1); | |
214 | member->status &= ~CHFL_VOICE; | |
215 | } | |
216 | } | |
217 | ||
218 | /* And flush the modes to the channel */ | |
219 | modebuf_flush(&mbuf); | |
220 | ||
221 | /* Finally, we can clear the key... */ | |
222 | if (del_mode & MODE_KEY) | |
223 | chptr->mode.key[0] = '\0'; | |
224 | ||
225 | /* Ok, build control string again */ | |
226 | for (flag_p = flags; flag_p[0]; flag_p += 2) | |
227 | if (del_mode & flag_p[0]) | |
228 | control_buf[control_buf_i++] = flag_p[1]; | |
229 | ||
230 | control_buf[control_buf_i] = '\0'; | |
231 | ||
232 | /* Log it... */ | |
233 | log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE, "%#C CLEARMODE %H %s", sptr, | |
234 | chptr, control_buf); | |
235 | ||
236 | /* Then send it */ | |
237 | if (!IsLocalChannel(chptr->chname)) | |
238 | sendcmdto_serv_butone(sptr, CMD_CLEARMODE, cptr, "%H %s", chptr, | |
239 | control_buf); | |
240 | ||
241 | return 0; | |
242 | } | |
243 | ||
244 | /* | |
245 | * ms_clearmode - server message handler | |
246 | * | |
247 | * parv[0] = Send prefix | |
248 | * parv[1] = Channel name | |
249 | * parv[2] = Control string | |
250 | */ | |
251 | int | |
252 | ms_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) | |
253 | { | |
254 | struct Channel *chptr; | |
255 | ||
256 | if (parc < 3) | |
257 | return need_more_params(sptr, "CLEARMODE"); | |
258 | ||
259 | if (!IsPrivileged(sptr)) { | |
260 | protocol_violation(sptr,"No privileges on source for CLEARMODE, desync?"); | |
261 | return send_reply(sptr, ERR_NOPRIVILEGES); | |
262 | } | |
263 | ||
264 | if (!IsChannelName(parv[1]) || IsLocalChannel(parv[1]) || | |
265 | !(chptr = FindChannel(parv[1]))) | |
266 | return send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]); | |
267 | ||
268 | return do_clearmode(cptr, sptr, chptr, parv[2]); | |
269 | } | |
270 | ||
271 | /* | |
272 | * mo_clearmode - oper message handler | |
273 | * | |
274 | * parv[0] = Send prefix | |
275 | * parv[1] = Channel name | |
276 | * parv[2] = Control string | |
277 | */ | |
278 | int | |
279 | mo_clearmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) | |
280 | { | |
281 | struct Channel *chptr; | |
282 | char *control = "ovpsmikbl"; /* default control string */ | |
283 | const char *chname, *qreason; | |
284 | int force = 0; | |
285 | ||
286 | if (!feature_bool(FEAT_CONFIG_OPERCMDS)) | |
287 | return send_reply(sptr, ERR_DISABLED, "CLEARMODE"); | |
288 | ||
289 | if (parc < 2) | |
290 | return need_more_params(sptr, "CLEARMODE"); | |
291 | ||
292 | if (parc > 2) | |
293 | control = parv[2]; | |
294 | ||
295 | chname = parv[1]; | |
296 | if (*chname == '!') | |
297 | { | |
298 | chname++; | |
299 | if (!HasPriv(sptr, IsLocalChannel(chname) ? | |
300 | PRIV_FORCE_LOCAL_OPMODE : | |
301 | PRIV_FORCE_OPMODE)) | |
302 | return send_reply(sptr, ERR_NOPRIVILEGES); | |
303 | force = 1; | |
304 | } | |
305 | ||
306 | if (!HasPriv(sptr, | |
307 | IsLocalChannel(chname) ? PRIV_LOCAL_OPMODE : PRIV_OPMODE)) | |
308 | return send_reply(sptr, ERR_NOPRIVILEGES); | |
309 | ||
310 | if (('#' != *chname && '&' != *chname) || !(chptr = FindChannel(chname))) | |
311 | return send_reply(sptr, ERR_NOSUCHCHANNEL, chname); | |
312 | ||
313 | if (!force && (qreason = find_quarantine(chptr->chname))) | |
314 | return send_reply(sptr, ERR_QUARANTINED, chptr->chname, qreason); | |
315 | ||
316 | return do_clearmode(cptr, sptr, chptr, control); | |
317 | } |