/[svn]/ircd-hybrid/branches/8.2.x/modules/core/m_join.c
ViewVC logotype

Contents of /ircd-hybrid/branches/8.2.x/modules/core/m_join.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8366 - (show annotations)
Mon Mar 5 19:51:02 2018 UTC (5 years, 2 months ago) by michael
File MIME type: text/x-chdr
File size: 12078 byte(s)
- "JOIN 0" is now no longer supported

1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2018 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file m_join.c
23 * \brief Includes required functions for processing the JOIN command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "channel.h"
30 #include "channel_mode.h"
31 #include "client.h"
32 #include "hash.h"
33 #include "irc_string.h"
34 #include "ircd.h"
35 #include "numeric.h"
36 #include "send.h"
37 #include "server.h"
38 #include "conf.h"
39 #include "conf_resv.h"
40 #include "parse.h"
41 #include "modules.h"
42
43
44 static void set_final_mode(const struct Mode *, const struct Mode *);
45 static void remove_our_modes(struct Channel *, struct Client *);
46 static void remove_a_mode(struct Channel *, struct Client *, int, const char);
47
48 static char modebuf[MODEBUFLEN];
49 static char parabuf[MODEBUFLEN];
50 static char sendbuf[MODEBUFLEN];
51 static char *mbuf;
52
53 /*! \brief JOIN command handler
54 *
55 * \param source_p Pointer to allocated Client struct from which the message
56 * originally comes from. This can be a local or remote client.
57 * \param parc Integer holding the number of supplied arguments.
58 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
59 * pointers.
60 * \note Valid arguments for this command are:
61 * - parv[0] = command
62 * - parv[1] = channel
63 * - parv[2] = channel password (key)
64 */
65 static int
66 m_join(struct Client *source_p, int parc, char *parv[])
67 {
68 if (EmptyString(parv[1]))
69 {
70 sendto_one_numeric(source_p, &me, ERR_NEEDMOREPARAMS, "JOIN");
71 return 0;
72 }
73
74 channel_do_join(source_p, parv[1], parv[2]);
75 return 0;
76 }
77
78 /* ms_join()
79 *
80 * inputs - parv[0] = command
81 * parv[1] = ts
82 * parv[2] = channel name
83 * parv[3] = modes (Deprecated)
84 * output - none
85 * side effects - handles remote JOIN's sent by servers. In TSora
86 * remote clients are joined using SJOIN, hence a
87 * JOIN sent by a server on behalf of a client is an error.
88 * here, the initial code is in to take an extra parameter
89 * and use it for the TimeStamp on a new channel.
90 */
91 static int
92 ms_join(struct Client *source_p, int parc, char *parv[])
93 {
94 uintmax_t newts = 0;
95 uintmax_t oldts = 0;
96 int keep_our_modes = 1;
97 int keep_new_modes = 1;
98 int isnew = 0;
99 const char *servername = NULL;
100 struct Channel *chptr = NULL;
101 struct Mode mode, *oldmode;
102
103 if (!IsClient(source_p))
104 return 0;
105
106 if (parc < 4)
107 return 0;
108
109 if (!channel_check_name(parv[2], 0))
110 {
111 sendto_realops_flags(UMODE_DEBUG, L_ALL, SEND_NOTICE,
112 "*** Too long or invalid channel name from %s(via %s): %s",
113 source_p->name, source_p->from->name, parv[2]);
114 return 0;
115 }
116
117 mbuf = modebuf;
118 mode.mode = mode.limit = 0;
119 mode.key[0] = '\0';
120
121 if ((chptr = hash_find_channel(parv[2])) == NULL)
122 {
123 isnew = 1;
124 chptr = channel_make(parv[2]);
125 }
126
127 newts = strtoumax(parv[1], NULL, 10);
128 oldts = chptr->creationtime;
129 oldmode = &chptr->mode;
130
131 if (ConfigGeneral.ignore_bogus_ts)
132 {
133 if (newts < 800000000)
134 {
135 sendto_realops_flags(UMODE_DEBUG, L_ALL, SEND_NOTICE,
136 "*** Bogus TS %ju on %s ignored from %s(via %s)",
137 newts, chptr->name,
138 source_p->name, source_p->from->name);
139
140 newts = (oldts == 0) ? 0 : 800000000;
141 }
142 }
143 else
144 {
145 if (!newts && !isnew && oldts)
146 {
147 sendto_channel_local(NULL, chptr, 0, 0, 0,
148 ":%s NOTICE %s :*** Notice -- TS for %s changed from %ju to 0",
149 me.name, chptr->name, chptr->name, oldts);
150 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
151 "Server %s changing TS on %s from %ju to 0",
152 source_p->name, chptr->name, oldts);
153 }
154 }
155
156 if (isnew)
157 chptr->creationtime = newts;
158 else if (newts == 0 || oldts == 0)
159 chptr->creationtime = 0;
160 else if (newts == oldts)
161 ;
162 else if (newts < oldts)
163 {
164 keep_our_modes = 0;
165 chptr->creationtime = newts;
166 }
167 else
168 keep_new_modes = 0;
169
170 if (!keep_new_modes)
171 mode = *oldmode;
172 else if (keep_our_modes)
173 {
174 mode.mode |= oldmode->mode;
175
176 if (oldmode->limit > mode.limit)
177 mode.limit = oldmode->limit;
178 if (strcmp(mode.key, oldmode->key) < 0)
179 strlcpy(mode.key, oldmode->key, sizeof(mode.key));
180 }
181
182 set_final_mode(&mode, oldmode);
183 chptr->mode = mode;
184
185 /* Lost the TS, other side wins, so remove modes on this side */
186 if (!keep_our_modes)
187 {
188 remove_our_modes(chptr, source_p);
189
190 if (chptr->topic[0])
191 {
192 channel_set_topic(chptr, "", "", 0, 0);
193 sendto_channel_local(NULL, chptr, 0, 0, 0, ":%s TOPIC %s :",
194 (IsHidden(source_p) ||
195 ConfigServerHide.hide_servers) ?
196 me.name : source_p->name, chptr->name);
197 }
198
199 sendto_channel_local(NULL, chptr, 0, 0, 0,
200 ":%s NOTICE %s :*** Notice -- TS for %s changed from %ju to %ju",
201 me.name, chptr->name, chptr->name,
202 oldts, newts);
203 }
204
205 if (*modebuf)
206 {
207 servername = (ConfigServerHide.hide_servers || IsHidden(source_p)) ?
208 me.name : source_p->name;
209
210 /* This _SHOULD_ be to ALL_MEMBERS
211 * It contains only +imnpstlk, etc */
212 sendto_channel_local(NULL, chptr, 0, 0, 0, ":%s MODE %s %s %s",
213 servername, chptr->name, modebuf, parabuf);
214 }
215
216 if (!IsMember(source_p, chptr))
217 {
218 add_user_to_channel(chptr, source_p, 0, 1);
219
220 sendto_channel_local(NULL, chptr, 0, CAP_EXTENDED_JOIN, 0, ":%s!%s@%s JOIN %s %s :%s",
221 source_p->name, source_p->username,
222 source_p->host, chptr->name, source_p->account, source_p->info);
223 sendto_channel_local(NULL, chptr, 0, 0, CAP_EXTENDED_JOIN, ":%s!%s@%s JOIN :%s",
224 source_p->name, source_p->username,
225 source_p->host, chptr->name);
226
227 if (source_p->away[0])
228 sendto_channel_local(source_p, chptr, 0, CAP_AWAY_NOTIFY, 0,
229 ":%s!%s@%s AWAY :%s",
230 source_p->name, source_p->username,
231 source_p->host, source_p->away);
232 }
233
234 sendto_server(source_p, 0, 0, ":%s JOIN %ju %s +",
235 source_p->id, chptr->creationtime, chptr->name);
236 return 0;
237 }
238
239 /* set_final_mode
240 *
241 * inputs - channel mode
242 * - old channel mode
243 * output - NONE
244 * side effects - walk through all the channel modes turning off modes
245 * that were on in oldmode but aren't on in mode.
246 * Then walk through turning on modes that are on in mode
247 * but were not set in oldmode.
248 */
249 static void
250 set_final_mode(const struct Mode *mode, const struct Mode *oldmode)
251 {
252 char *pbuf = parabuf;
253 int what = 0, len = 0;
254
255 for (const struct chan_mode *tab = cmode_tab; tab->letter; ++tab)
256 {
257 if (tab->mode && (tab->mode & mode->mode) && !(tab->mode & oldmode->mode))
258 {
259 if (what != 1)
260 {
261 *mbuf++ = '+';
262 what = 1;
263 }
264
265 *mbuf++ = tab->letter;
266 }
267 }
268
269 for (const struct chan_mode *tab = cmode_tab; tab->letter; ++tab)
270 {
271 if (tab->mode && (tab->mode & oldmode->mode) && !(tab->mode & mode->mode))
272 {
273 if (what != -1)
274 {
275 *mbuf++ = '-';
276 what = -1;
277 }
278
279 *mbuf++ = tab->letter;
280 }
281 }
282
283 if (oldmode->limit && mode->limit == 0)
284 {
285 if (what != -1)
286 {
287 *mbuf++ = '-';
288 what = -1;
289 }
290
291 *mbuf++ = 'l';
292 }
293
294 if (oldmode->key[0] && mode->key[0] == '\0')
295 {
296 if (what != -1)
297 {
298 *mbuf++ = '-';
299 what = -1;
300 }
301
302 *mbuf++ = 'k';
303 len = sprintf(pbuf, "%s ", oldmode->key);
304 pbuf += len;
305 }
306
307 if (mode->limit && oldmode->limit != mode->limit)
308 {
309 if (what != 1)
310 {
311 *mbuf++ = '+';
312 what = 1;
313 }
314
315 *mbuf++ = 'l';
316 len = sprintf(pbuf, "%u ", mode->limit);
317 pbuf += len;
318 }
319
320 if (mode->key[0] && strcmp(oldmode->key, mode->key))
321 {
322 if (what != 1)
323 {
324 *mbuf++ = '+';
325 what = 1;
326 }
327
328 *mbuf++ = 'k';
329 len = sprintf(pbuf, "%s ", mode->key);
330 pbuf += len;
331 }
332
333 *mbuf = '\0';
334 }
335
336 /* remove_our_modes()
337 *
338 * inputs - pointer to channel to remove modes from
339 * - client pointer
340 * output - NONE
341 * side effects - Go through the local members, remove all their
342 * chanop modes etc., this side lost the TS.
343 */
344 static void
345 remove_our_modes(struct Channel *chptr, struct Client *source_p)
346 {
347 remove_a_mode(chptr, source_p, CHFL_CHANOP, 'o');
348 remove_a_mode(chptr, source_p, CHFL_HALFOP, 'h');
349 remove_a_mode(chptr, source_p, CHFL_VOICE, 'v');
350 }
351
352 /* remove_a_mode()
353 *
354 * inputs -
355 * output - NONE
356 * side effects - remove ONE mode from a channel
357 */
358 static void
359 remove_a_mode(struct Channel *chptr, struct Client *source_p, int mask, const char flag)
360 {
361 dlink_node *node = NULL;
362 char lmodebuf[MODEBUFLEN];
363 const char *lpara[MAXMODEPARAMS];
364 int count = 0, lcount = 0;
365
366 mbuf = lmodebuf;
367 *mbuf++ = '-';
368
369 for (lcount = 0; lcount < MAXMODEPARAMS; ++lcount)
370 lpara[lcount] = "";
371
372 sendbuf[0] = '\0';
373
374 DLINK_FOREACH(node, chptr->members.head)
375 {
376 struct Membership *member = node->data;
377
378 if ((member->flags & mask) == 0)
379 continue;
380
381 member->flags &= ~mask;
382
383 lpara[count++] = member->client_p->name;
384
385 *mbuf++ = flag;
386
387 if (count >= MAXMODEPARAMS)
388 {
389 for (lcount = 0; lcount < MAXMODEPARAMS; ++lcount)
390 {
391 if (*lpara[lcount] == '\0')
392 break;
393
394 strlcat(sendbuf, " ", sizeof(sendbuf));
395 strlcat(sendbuf, lpara[lcount], sizeof(sendbuf));
396 lpara[lcount] = "";
397 }
398
399 *mbuf = '\0';
400 sendto_channel_local(NULL, chptr, 0, 0, 0, ":%s MODE %s %s%s",
401 (IsHidden(source_p) ||
402 ConfigServerHide.hide_servers) ?
403 me.name : source_p->name,
404 chptr->name, lmodebuf, sendbuf);
405 mbuf = lmodebuf;
406 *mbuf++ = '-';
407 count = 0;
408 sendbuf[0] = '\0';
409 }
410 }
411
412 if (count)
413 {
414 *mbuf = '\0';
415
416 for (lcount = 0; lcount < MAXMODEPARAMS; ++lcount)
417 {
418 if (*lpara[lcount] == '\0')
419 break;
420
421 strlcat(sendbuf, " ", sizeof(sendbuf));
422 strlcat(sendbuf, lpara[lcount], sizeof(sendbuf));
423 }
424
425 sendto_channel_local(NULL, chptr, 0, 0, 0, ":%s MODE %s %s%s",
426 (IsHidden(source_p) || ConfigServerHide.hide_servers) ?
427 me.name : source_p->name, chptr->name, lmodebuf, sendbuf);
428 }
429 }
430
431 static struct Message join_msgtab =
432 {
433 .cmd = "JOIN",
434 .args_min = 2,
435 .args_max = MAXPARA,
436 .handlers[UNREGISTERED_HANDLER] = m_unregistered,
437 .handlers[CLIENT_HANDLER] = m_join,
438 .handlers[SERVER_HANDLER] = ms_join,
439 .handlers[ENCAP_HANDLER] = m_ignore,
440 .handlers[OPER_HANDLER] = m_join
441 };
442
443 static void
444 module_init(void)
445 {
446 mod_add_cmd(&join_msgtab);
447 }
448
449 static void
450 module_exit(void)
451 {
452 mod_del_cmd(&join_msgtab);
453 }
454
455 struct module module_entry =
456 {
457 .version = "$Revision$",
458 .modinit = module_init,
459 .modexit = module_exit,
460 .flags = MODULE_FLAG_CORE
461 };

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.30