ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_join.c
Revision: 4565
Committed: Sun Aug 24 10:27:40 2014 UTC (9 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 11922 byte(s)
Log Message:
- Update GPL 2 license headers

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2014 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 "parse.h"
40 #include "modules.h"
41 #include "resv.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 time_t newts = 0;
95 time_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 == 2 && !strcmp(parv[1], "0"))
107 {
108 channel_do_join_0(source_p);
109 return 0;
110 }
111
112 if (parc < 4)
113 return 0;
114
115 if (!check_channel_name(parv[2], 0))
116 {
117 sendto_realops_flags(UMODE_DEBUG, L_ALL, SEND_NOTICE,
118 "*** Too long or invalid channel name from %s(via %s): %s",
119 source_p->name, source_p->from->name, parv[2]);
120 return 0;
121 }
122
123 mbuf = modebuf;
124 mode.mode = mode.limit = 0;
125 mode.key[0] = '\0';
126
127 if ((chptr = hash_find_channel(parv[2])) == NULL)
128 {
129 isnew = 1;
130 chptr = make_channel(parv[2]);
131 }
132
133 newts = atol(parv[1]);
134 oldts = chptr->channelts;
135 oldmode = &chptr->mode;
136
137 if (ConfigGeneral.ignore_bogus_ts)
138 {
139 if (newts < 800000000)
140 {
141 sendto_realops_flags(UMODE_DEBUG, L_ALL, SEND_NOTICE,
142 "*** Bogus TS %lu on %s ignored from %s(via %s)",
143 (unsigned long)newts, chptr->chname,
144 source_p->name, source_p->from->name);
145
146 newts = (oldts == 0) ? 0 : 800000000;
147 }
148 }
149 else
150 {
151 if (!newts && !isnew && oldts)
152 {
153 sendto_channel_local(ALL_MEMBERS, 0, chptr,
154 ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to 0",
155 me.name, chptr->chname, chptr->chname, (unsigned long)oldts);
156 sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
157 "Server %s changing TS on %s from %lu to 0",
158 source_p->name, chptr->chname, (unsigned long)oldts);
159 }
160 }
161
162 if (isnew)
163 chptr->channelts = newts;
164 else if (newts == 0 || oldts == 0)
165 chptr->channelts = 0;
166 else if (newts == oldts)
167 ;
168 else if (newts < oldts)
169 {
170 keep_our_modes = 0;
171 chptr->channelts = newts;
172 }
173 else
174 keep_new_modes = 0;
175
176 if (!keep_new_modes)
177 mode = *oldmode;
178 else if (keep_our_modes)
179 {
180 mode.mode |= oldmode->mode;
181
182 if (oldmode->limit > mode.limit)
183 mode.limit = oldmode->limit;
184 if (strcmp(mode.key, oldmode->key) < 0)
185 strlcpy(mode.key, oldmode->key, sizeof(mode.key));
186 }
187
188 set_final_mode(&mode, oldmode);
189 chptr->mode = mode;
190
191 /* Lost the TS, other side wins, so remove modes on this side */
192 if (!keep_our_modes)
193 {
194 remove_our_modes(chptr, source_p);
195
196 if (chptr->topic[0])
197 {
198 channel_set_topic(chptr, "", "", 0, 0);
199 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s TOPIC %s :",
200 (IsHidden(source_p) ||
201 ConfigServerHide.hide_servers) ?
202 me.name : source_p->name, chptr->chname);
203 }
204
205 sendto_channel_local(ALL_MEMBERS, 0, chptr,
206 ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to %lu",
207 me.name, chptr->chname, chptr->chname,
208 (unsigned long)oldts, (unsigned long)newts);
209 }
210
211 if (*modebuf)
212 {
213 servername = (ConfigServerHide.hide_servers || IsHidden(source_p)) ?
214 me.name : source_p->name;
215
216 /* This _SHOULD_ be to ALL_MEMBERS
217 * It contains only +imnpstlk, etc */
218 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s %s %s",
219 servername, chptr->chname, modebuf, parabuf);
220 }
221
222 if (!IsMember(source_p, chptr))
223 {
224 add_user_to_channel(chptr, source_p, 0, 1);
225 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
226 source_p->name, source_p->username,
227 source_p->host, chptr->chname);
228
229 if (source_p->away[0])
230 sendto_channel_local_butone(source_p, 0, CAP_AWAY_NOTIFY, chptr,
231 ":%s!%s@%s AWAY :%s",
232 source_p->name, source_p->username,
233 source_p->host, source_p->away);
234 }
235
236 sendto_server(source_p, NOCAPS, NOCAPS, ":%s JOIN %lu %s +",
237 source_p->id, (unsigned long)chptr->channelts, chptr->chname);
238 return 0;
239 }
240
241 /* set_final_mode
242 *
243 * inputs - channel mode
244 * - old channel mode
245 * output - NONE
246 * side effects - walk through all the channel modes turning off modes
247 * that were on in oldmode but aren't on in mode.
248 * Then walk through turning on modes that are on in mode
249 * but were not set in oldmode.
250 */
251 static void
252 set_final_mode(const struct Mode *mode, const struct Mode *oldmode)
253 {
254 char *pbuf = parabuf;
255 int what = 0, len = 0;
256
257 for (const struct mode_letter *tab = chan_modes; tab->letter; ++tab)
258 {
259 if ((tab->mode & mode->mode) &&
260 !(tab->mode & oldmode->mode))
261 {
262 if (what != 1)
263 {
264 *mbuf++ = '+';
265 what = 1;
266 }
267
268 *mbuf++ = tab->letter;
269 }
270 }
271
272 for (const struct mode_letter *tab = chan_modes; tab->letter; ++tab)
273 {
274 if ((tab->mode & oldmode->mode) &&
275 !(tab->mode & mode->mode))
276 {
277 if (what != -1)
278 {
279 *mbuf++ = '-';
280 what = -1;
281 }
282
283 *mbuf++ = tab->letter;
284 }
285 }
286
287 if (oldmode->limit && mode->limit == 0)
288 {
289 if (what != -1)
290 {
291 *mbuf++ = '-';
292 what = -1;
293 }
294
295 *mbuf++ = 'l';
296 }
297
298 if (oldmode->key[0] && !mode->key[0])
299 {
300 if (what != -1)
301 {
302 *mbuf++ = '-';
303 what = -1;
304 }
305
306 *mbuf++ = 'k';
307 len = sprintf(pbuf, "%s ", oldmode->key);
308 pbuf += len;
309 }
310
311 if (mode->limit && oldmode->limit != mode->limit)
312 {
313 if (what != 1)
314 {
315 *mbuf++ = '+';
316 what = 1;
317 }
318
319 *mbuf++ = 'l';
320 len = sprintf(pbuf, "%d ", mode->limit);
321 pbuf += len;
322 }
323
324 if (mode->key[0] && strcmp(oldmode->key, mode->key))
325 {
326 if (what != 1)
327 {
328 *mbuf++ = '+';
329 what = 1;
330 }
331
332 *mbuf++ = 'k';
333 len = sprintf(pbuf, "%s ", mode->key);
334 pbuf += len;
335 }
336
337 *mbuf = '\0';
338 }
339
340 /* remove_our_modes()
341 *
342 * inputs - pointer to channel to remove modes from
343 * - client pointer
344 * output - NONE
345 * side effects - Go through the local members, remove all their
346 * chanop modes etc., this side lost the TS.
347 */
348 static void
349 remove_our_modes(struct Channel *chptr, struct Client *source_p)
350 {
351 remove_a_mode(chptr, source_p, CHFL_CHANOP, 'o');
352 remove_a_mode(chptr, source_p, CHFL_HALFOP, 'h');
353 remove_a_mode(chptr, source_p, CHFL_VOICE, 'v');
354 }
355
356 /* remove_a_mode()
357 *
358 * inputs -
359 * output - NONE
360 * side effects - remove ONE mode from a channel
361 */
362 static void
363 remove_a_mode(struct Channel *chptr, struct Client *source_p, int mask, const char flag)
364 {
365 dlink_node *ptr = NULL;
366 char lmodebuf[MODEBUFLEN];
367 const char *lpara[MAXMODEPARAMS];
368 int count = 0, lcount = 0;
369
370 mbuf = lmodebuf;
371 *mbuf++ = '-';
372
373 for (lcount = 0; lcount < MAXMODEPARAMS; ++lcount)
374 lpara[lcount] = "";
375
376 sendbuf[0] = '\0';
377
378 DLINK_FOREACH(ptr, chptr->members.head)
379 {
380 struct Membership *ms = ptr->data;
381
382 if ((ms->flags & mask) == 0)
383 continue;
384
385 ms->flags &= ~mask;
386
387 lpara[count++] = ms->client_p->name;
388
389 *mbuf++ = flag;
390
391 if (count >= MAXMODEPARAMS)
392 {
393 for (lcount = 0; lcount < MAXMODEPARAMS; ++lcount)
394 {
395 if (*lpara[lcount] == '\0')
396 break;
397
398 strlcat(sendbuf, " ", sizeof(sendbuf));
399 strlcat(sendbuf, lpara[lcount], sizeof(sendbuf));
400 lpara[lcount] = "";
401 }
402
403 *mbuf = '\0';
404 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s %s%s",
405 (IsHidden(source_p) ||
406 ConfigServerHide.hide_servers) ?
407 me.name : source_p->name,
408 chptr->chname, lmodebuf, sendbuf);
409 mbuf = lmodebuf;
410 *mbuf++ = '-';
411 count = 0;
412 sendbuf[0] = '\0';
413 }
414 }
415
416 if (count)
417 {
418 *mbuf = '\0';
419
420 for (lcount = 0; lcount < MAXMODEPARAMS; ++lcount)
421 {
422 if (*lpara[lcount] == '\0')
423 break;
424
425 strlcat(sendbuf, " ", sizeof(sendbuf));
426 strlcat(sendbuf, lpara[lcount], sizeof(sendbuf));
427 }
428
429 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s %s%s",
430 (IsHidden(source_p) || ConfigServerHide.hide_servers) ?
431 me.name : source_p->name, chptr->chname, lmodebuf, sendbuf);
432 }
433 }
434
435 static struct Message join_msgtab =
436 {
437 "JOIN", NULL, 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
438 { m_unregistered, m_join, ms_join, m_ignore, m_join, m_ignore }
439 };
440
441 static void
442 module_init(void)
443 {
444 mod_add_cmd(&join_msgtab);
445 }
446
447 static void
448 module_exit(void)
449 {
450 mod_del_cmd(&join_msgtab);
451 }
452
453 struct module module_entry =
454 {
455 .node = { NULL, NULL, NULL },
456 .name = NULL,
457 .version = "$Revision$",
458 .handle = NULL,
459 .modinit = module_init,
460 .modexit = module_exit,
461 .flags = MODULE_FLAG_CORE
462 };

Properties

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