2 * ircd-ratbox: A slightly useful ircd.
3 * m_sjoin.c: Joins a user to a channel.
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 * $Id: m_sjoin.c 3434 2007-04-28 23:47:25Z jilles $
32 #include "irc_string.h"
33 #include "sprintf_irc.h"
44 static int ms_sjoin(struct Client
*, struct Client
*, int, const char **);
46 struct Message sjoin_msgtab
= {
47 "SJOIN", 0, 0, 0, MFLG_SLOW
,
48 {mg_unreg
, mg_ignore
, mg_ignore
, {ms_sjoin
, 0}, mg_ignore
, mg_ignore
}
51 mapi_clist_av1 sjoin_clist
[] = { &sjoin_msgtab
, NULL
};
53 DECLARE_MODULE_AV1(sjoin
, NULL
, NULL
, sjoin_clist
, NULL
, NULL
, "$Revision: 3434 $");
60 * parv[3] - modes + n arguments (key and/or limit)
61 * parv[4+n] - flags+nick list (all in one parameter)
63 * process a SJOIN, taking the TS's into account to either ignore the
64 * incoming modes or undo the existing ones or merge them, and JOIN
65 * all the specified users while sending JOIN/MODEs to local clients
69 static char modebuf
[MODEBUFLEN
];
70 static char parabuf
[MODEBUFLEN
];
71 static const char *para
[MAXMODEPARAMS
];
75 static void set_final_mode(struct Mode
*mode
, struct Mode
*oldmode
);
76 static void remove_our_modes(struct Channel
*chptr
, struct Client
*source_p
);
77 static void remove_ban_list(struct Channel
*chptr
, struct Client
*source_p
,
78 dlink_list
* list
, char c
, int cap
, int mems
);
81 ms_sjoin(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
83 static char buf_nick
[BUFSIZE
];
84 static char buf_uid
[BUFSIZE
];
85 static const char empty_modes
[] = "0";
86 struct Channel
*chptr
;
87 struct Client
*target_p
, *fakesource_p
;
90 static struct Mode mode
, *oldmode
;
93 int keep_our_modes
= 1;
94 int keep_new_modes
= 1;
97 int mlen_nick
, mlen_uid
;
106 int i
, joinc
= 0, timeslice
= 0;
107 static char empty
[] = "";
108 dlink_node
*ptr
, *next_ptr
;
110 if(!IsChannelName(parv
[2]) || !check_channel_name(parv
[2]))
113 /* SJOIN's for local channels can't happen. */
117 modebuf
[0] = parabuf
[0] = mode
.key
[0] = mode
.forward
[0] = '\0';
118 pargs
= mode
.mode
= mode
.limit
= mode
.join_num
= mode
.join_time
= 0;
120 /* Hide connecting server on netburst -- jilles */
121 if (ConfigServerHide
.flatten_links
&& !HasSentEob(source_p
))
124 fakesource_p
= source_p
;
127 newts
= atol(parv
[1]);
135 mode
.mode
|= MODE_INVITEONLY
;
138 mode
.mode
|= MODE_NOPRIVMSGS
;
141 mode
.mode
|= MODE_PRIVATE
;
144 mode
.mode
|= MODE_SECRET
;
147 mode
.mode
|= MODE_MODERATED
;
150 mode
.mode
|= MODE_TOPICLIMIT
;
153 mode
.mode
|= MODE_REGONLY
;
156 mode
.mode
|= MODE_EXLIMIT
;
159 mode
.mode
|= MODE_PERMANENT
;
162 mode
.mode
|= MODE_NOCOLOR
;
165 mode
.mode
|= MODE_FREEINVITE
;
168 mode
.mode
|= MODE_OPMODERATE
;
171 mode
.mode
|= MODE_FREETARGET
;
174 mode
.mode
|= MODE_DISFORWARD
;
177 strlcpy(mode
.forward
, parv
[4 + args
], sizeof(mode
.forward
));
183 sscanf(parv
[4 + args
], "%d:%d", &joinc
, ×lice
);
185 mode
.join_num
= joinc
;
186 mode
.join_time
= timeslice
;
191 strlcpy(mode
.key
, parv
[4 + args
], sizeof(mode
.key
));
197 mode
.limit
= atoi(parv
[4 + args
]);
209 /* remove any leading spaces */
216 if((chptr
= get_or_create_channel(source_p
, parv
[2], &isnew
)) == NULL
)
217 return 0; /* channel name too long? */
220 oldts
= chptr
->channelts
;
221 oldmode
= &chptr
->mode
;
223 #ifdef IGNORE_BOGUS_TS
224 if(newts
< 800000000)
226 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
227 "*** Bogus TS %ld on %s ignored from %s",
228 (long) newts
, chptr
->chname
, client_p
->name
);
230 newts
= (oldts
== 0) ? oldts
: 800000000;
233 if(!isnew
&& !newts
&& oldts
)
235 sendto_channel_local(ALL_MEMBERS
, chptr
,
236 ":%s NOTICE %s :*** Notice -- TS for %s "
237 "changed from %ld to 0",
238 me
.name
, chptr
->chname
, chptr
->chname
, (long) oldts
);
239 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
240 "Server %s changing TS on %s from %ld to 0",
241 source_p
->name
, chptr
->chname
, (long) oldts
);
246 chptr
->channelts
= newts
;
248 else if(newts
== 0 || oldts
== 0)
249 chptr
->channelts
= 0;
250 else if(newts
== oldts
)
252 else if(newts
< oldts
)
254 /* If configured, kick people trying to join +i/+k
255 * channels by recreating them on split servers.
256 * Don't kick if the source has sent EOB (services
257 * deopping everyone by TS-1 SJOIN).
259 if (ConfigChannel
.kick_on_split_riding
&&
260 !HasSentEob(source_p
) &&
261 ((mode
.mode
& MODE_INVITEONLY
) ||
262 (mode
.key
[0] != 0 && irccmp(mode
.key
, oldmode
->key
) != 0)))
264 struct membership
*msptr
;
266 int l
= dlink_list_length(&chptr
->members
);
267 int b
= dlink_list_length(&chptr
->banlist
) +
268 dlink_list_length(&chptr
->exceptlist
) +
269 dlink_list_length(&chptr
->invexlist
) +
270 dlink_list_length(&chptr
->quietlist
);
272 DLINK_FOREACH_SAFE(ptr
, next_ptr
, chptr
->locmembers
.head
)
275 who
= msptr
->client_p
;
276 sendto_one(who
, ":%s KICK %s %s :Net Rider",
277 me
.name
, chptr
->chname
, who
->name
);
279 sendto_server(NULL
, chptr
, CAP_TS6
, NOCAPS
,
280 ":%s KICK %s %s :Net Rider",
281 me
.id
, chptr
->chname
,
283 sendto_server(NULL
, chptr
, NOCAPS
, CAP_TS6
,
284 ":%s KICK %s %s :Net Rider",
285 me
.name
, chptr
->chname
, who
->name
);
286 remove_user_from_channel(msptr
);
292 /* Channel was emptied, create a new one */
293 if((chptr
= get_or_create_channel(source_p
, parv
[2], &isnew
)) == NULL
)
294 return 0; /* oops! */
296 /* If the source does not do TS6,
297 * nontimestamped bans have been sent to it,
298 * but we have just lost those here. Let's
299 * warn the channel about this. Because
300 * of the kicks, any users on the channel
301 * will be at client_p. -- jilles */
302 if (!has_id(source_p
) && b
> 0)
303 sendto_one(client_p
, ":%s NOTICE %s :*** Notice -- possible ban desync on %s, please remove any bans just added by servers", get_id(&me
, client_p
), parv
[2], parv
[2]);
304 oldmode
= &chptr
->mode
;
308 chptr
->channelts
= newts
;
315 else if(keep_our_modes
)
317 mode
.mode
|= oldmode
->mode
;
318 if(oldmode
->limit
> mode
.limit
)
319 mode
.limit
= oldmode
->limit
;
320 if(strcmp(mode
.key
, oldmode
->key
) < 0)
321 strcpy(mode
.key
, oldmode
->key
);
322 if(oldmode
->join_num
> mode
.join_num
||
323 (oldmode
->join_num
== mode
.join_num
&&
324 oldmode
->join_time
> mode
.join_time
))
326 mode
.join_num
= oldmode
->join_num
;
327 mode
.join_time
= oldmode
->join_time
;
329 if(irccmp(mode
.forward
, oldmode
->forward
) < 0)
330 strcpy(mode
.forward
, oldmode
->forward
);
334 /* If setting -j, clear join throttle state -- jilles */
336 chptr
->join_count
= chptr
->join_delta
= 0;
339 set_final_mode(&mode
, oldmode
);
342 /* Lost the TS, other side wins, so remove modes on this side */
345 remove_our_modes(chptr
, fakesource_p
);
346 DLINK_FOREACH_SAFE(ptr
, next_ptr
, chptr
->invites
.head
)
348 del_invite(chptr
, ptr
->data
);
350 sendto_channel_local(ALL_MEMBERS
, chptr
,
351 ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to %ld",
352 me
.name
, chptr
->chname
, chptr
->chname
,
353 (long) oldts
, (long) newts
);
354 /* Update capitalization in channel name, this makes the
355 * capitalization timestamped like modes are -- jilles */
356 strcpy(chptr
->chname
, parv
[2]);
360 sendto_channel_local(ALL_MEMBERS
, chptr
, ":%s MODE %s %s %s",
361 fakesource_p
->name
, chptr
->chname
, modebuf
, parabuf
);
363 *modebuf
= *parabuf
= '\0';
365 if(parv
[3][0] != '0' && keep_new_modes
)
366 modes
= channel_modes(chptr
, source_p
);
370 mlen_nick
= ircsprintf(buf_nick
, ":%s SJOIN %ld %s %s :",
371 source_p
->name
, (long) chptr
->channelts
, parv
[2], modes
);
372 ptr_nick
= buf_nick
+ mlen_nick
;
374 /* working on the presumption eventually itll be more efficient to
375 * build a TS6 buffer without checking its needed..
377 mlen_uid
= ircsprintf(buf_uid
, ":%s SJOIN %ld %s %s :",
378 use_id(source_p
), (long) chptr
->channelts
, parv
[2], modes
);
379 ptr_uid
= buf_uid
+ mlen_uid
;
382 para
[0] = para
[1] = para
[2] = para
[3] = empty
;
384 len_nick
= len_uid
= 0;
386 /* if theres a space, theres going to be more than one nick, change the
387 * first space to \0, so s is just the first nick, and point p to the
390 if((p
= strchr(s
, ' ')) != NULL
)
401 for (i
= 0; i
< 2; i
++)
415 /* if the client doesnt exist or is fake direction, skip. */
416 if(!(target_p
= find_client(s
)) ||
417 (target_p
->from
!= client_p
) || !IsPerson(target_p
))
420 /* we assume for these we can fit at least one nick/uid in.. */
422 /* check we can fit another status+nick+space into a buffer */
423 if((mlen_nick
+ len_nick
+ NICKLEN
+ 3) > (BUFSIZE
- 3))
425 *(ptr_nick
- 1) = '\0';
426 sendto_server(client_p
->from
, NULL
, NOCAPS
, CAP_TS6
, "%s", buf_nick
);
427 ptr_nick
= buf_nick
+ mlen_nick
;
431 if((mlen_uid
+ len_uid
+ IDLEN
+ 3) > (BUFSIZE
- 3))
433 *(ptr_uid
- 1) = '\0';
434 sendto_server(client_p
->from
, NULL
, CAP_TS6
, NOCAPS
, "%s", buf_uid
);
435 ptr_uid
= buf_uid
+ mlen_uid
;
457 /* copy the nick to the two buffers */
458 len
= ircsprintf(ptr_nick
, "%s ", target_p
->name
);
461 len
= ircsprintf(ptr_uid
, "%s ", use_id(target_p
));
473 if(!IsMember(target_p
, chptr
))
475 add_user_to_channel(chptr
, target_p
, fl
);
476 sendto_channel_local(ALL_MEMBERS
, chptr
, ":%s!%s@%s JOIN :%s",
478 target_p
->username
, target_p
->host
, parv
[2]);
485 para
[pargs
++] = target_p
->name
;
487 /* a +ov user.. bleh */
490 /* its possible the +o has filled up MAXMODEPARAMS, if so, start
493 if(pargs
>= MAXMODEPARAMS
)
496 sendto_channel_local(ALL_MEMBERS
, chptr
,
497 ":%s MODE %s %s %s %s %s %s",
498 fakesource_p
->name
, chptr
->chname
,
500 para
[0], para
[1], para
[2], para
[3]);
503 para
[0] = para
[1] = para
[2] = para
[3] = NULL
;
508 para
[pargs
++] = target_p
->name
;
511 else if(fl
& CHFL_VOICE
)
514 para
[pargs
++] = target_p
->name
;
517 if(pargs
>= MAXMODEPARAMS
)
520 sendto_channel_local(ALL_MEMBERS
, chptr
,
521 ":%s MODE %s %s %s %s %s %s",
524 modebuf
, para
[0], para
[1], para
[2], para
[3]);
527 para
[0] = para
[1] = para
[2] = para
[3] = NULL
;
532 /* p points to the next nick */
535 /* if there was a trailing space and p was pointing to it, then we
536 * need to exit.. this has the side effect of breaking double spaces
537 * in an sjoin.. but that shouldnt happen anyway
539 if(s
&& (*s
== '\0'))
542 /* if p was NULL due to no spaces, s wont exist due to the above, so
543 * we cant check it for spaces.. if there are no spaces, then when
544 * we next get here, s will be NULL
546 if(s
&& ((p
= strchr(s
, ' ')) != NULL
))
555 sendto_channel_local(ALL_MEMBERS
, chptr
,
556 ":%s MODE %s %s %s %s %s %s",
557 fakesource_p
->name
, chptr
->chname
, modebuf
,
558 para
[0], CheckEmpty(para
[1]),
559 CheckEmpty(para
[2]), CheckEmpty(para
[3]));
562 if(!joins
&& !(chptr
->mode
.mode
& MODE_PERMANENT
) && isnew
)
564 destroy_channel(chptr
);
569 /* Keep the colon if we're sending an SJOIN without nicks -- jilles */
572 *(ptr_nick
- 1) = '\0';
573 *(ptr_uid
- 1) = '\0';
576 sendto_server(client_p
->from
, NULL
, CAP_TS6
, NOCAPS
, "%s", buf_uid
);
577 sendto_server(client_p
->from
, NULL
, NOCAPS
, CAP_TS6
, "%s", buf_nick
);
579 /* if the source does TS6 we have to remove our bans. Its now safe
580 * to issue -b's to the non-ts6 servers, as the sjoin we've just
581 * sent will kill any ops they have.
583 if(!keep_our_modes
&& source_p
->id
[0] != '\0')
585 if(dlink_list_length(&chptr
->banlist
) > 0)
586 remove_ban_list(chptr
, fakesource_p
, &chptr
->banlist
, 'b', NOCAPS
, ALL_MEMBERS
);
588 if(dlink_list_length(&chptr
->exceptlist
) > 0)
589 remove_ban_list(chptr
, fakesource_p
, &chptr
->exceptlist
,
590 'e', CAP_EX
, ONLY_CHANOPS
);
592 if(dlink_list_length(&chptr
->invexlist
) > 0)
593 remove_ban_list(chptr
, fakesource_p
, &chptr
->invexlist
,
594 'I', CAP_IE
, ONLY_CHANOPS
);
596 if(dlink_list_length(&chptr
->quietlist
) > 0)
597 remove_ban_list(chptr
, fakesource_p
, &chptr
->quietlist
,
598 'q', NOCAPS
, ALL_MEMBERS
);
612 static struct mode_letter flags
[] = {
613 {MODE_NOPRIVMSGS
, 'n'},
614 {MODE_TOPICLIMIT
, 't'},
616 {MODE_MODERATED
, 'm'},
617 {MODE_INVITEONLY
, 'i'},
621 {MODE_PERMANENT
, 'P'},
623 {MODE_FREEINVITE
, 'g'},
624 {MODE_OPMODERATE
, 'z'},
625 {MODE_FREETARGET
, 'F'},
626 {MODE_DISFORWARD
, 'Q'},
631 set_final_mode(struct Mode
*mode
, struct Mode
*oldmode
)
633 int dir
= MODE_QUERY
;
634 char *pbuf
= parabuf
;
638 /* ok, first get a list of modes we need to add */
639 for (i
= 0; flags
[i
].letter
; i
++)
641 if((mode
->mode
& flags
[i
].mode
) && !(oldmode
->mode
& flags
[i
].mode
))
648 *mbuf
++ = flags
[i
].letter
;
652 /* now the ones we need to remove. */
653 for (i
= 0; flags
[i
].letter
; i
++)
655 if((oldmode
->mode
& flags
[i
].mode
) && !(mode
->mode
& flags
[i
].mode
))
662 *mbuf
++ = flags
[i
].letter
;
666 if(oldmode
->limit
&& !mode
->limit
)
675 if(oldmode
->key
[0] && !mode
->key
[0])
683 len
= ircsprintf(pbuf
, "%s ", oldmode
->key
);
687 if(oldmode
->join_num
&& !mode
->join_num
)
696 if(oldmode
->forward
[0] && !mode
->forward
[0])
705 if(mode
->limit
&& oldmode
->limit
!= mode
->limit
)
713 len
= ircsprintf(pbuf
, "%d ", mode
->limit
);
717 if(mode
->key
[0] && strcmp(oldmode
->key
, mode
->key
))
725 len
= ircsprintf(pbuf
, "%s ", mode
->key
);
729 if(mode
->join_num
&& (oldmode
->join_num
!= mode
->join_num
|| oldmode
->join_time
!= mode
->join_time
))
737 len
= ircsprintf(pbuf
, "%d:%d ", mode
->join_num
, mode
->join_time
);
741 if(mode
->forward
[0] && strcmp(oldmode
->forward
, mode
->forward
) && ConfigChannel
.use_forward
)
749 len
= ircsprintf(pbuf
, "%s ", mode
->forward
);
764 remove_our_modes(struct Channel
*chptr
, struct Client
*source_p
)
766 struct membership
*msptr
;
768 char lmodebuf
[MODEBUFLEN
];
769 char *lpara
[MAXMODEPARAMS
];
776 for (i
= 0; i
< MAXMODEPARAMS
; i
++)
779 DLINK_FOREACH(ptr
, chptr
->members
.head
)
785 msptr
->flags
&= ~CHFL_CHANOP
;
786 lpara
[count
++] = msptr
->client_p
->name
;
789 /* +ov, might not fit so check. */
792 if(count
>= MAXMODEPARAMS
)
795 sendto_channel_local(ALL_MEMBERS
, chptr
,
796 ":%s MODE %s %s %s %s %s %s",
797 me
.name
, chptr
->chname
,
798 lmodebuf
, lpara
[0], lpara
[1],
801 /* preserve the initial '-' */
806 for (i
= 0; i
< MAXMODEPARAMS
; i
++)
810 msptr
->flags
&= ~CHFL_VOICE
;
811 lpara
[count
++] = msptr
->client_p
->name
;
815 else if(is_voiced(msptr
))
817 msptr
->flags
&= ~CHFL_VOICE
;
818 lpara
[count
++] = msptr
->client_p
->name
;
824 if(count
>= MAXMODEPARAMS
)
827 sendto_channel_local(ALL_MEMBERS
, chptr
,
828 ":%s MODE %s %s %s %s %s %s",
829 me
.name
, chptr
->chname
, lmodebuf
,
830 lpara
[0], lpara
[1], lpara
[2], lpara
[3]);
835 for (i
= 0; i
< MAXMODEPARAMS
; i
++)
843 sendto_channel_local(ALL_MEMBERS
, chptr
,
844 ":%s MODE %s %s %s %s %s %s",
845 me
.name
, chptr
->chname
, lmodebuf
,
846 EmptyString(lpara
[0]) ? "" : lpara
[0],
847 EmptyString(lpara
[1]) ? "" : lpara
[1],
848 EmptyString(lpara
[2]) ? "" : lpara
[2],
849 EmptyString(lpara
[3]) ? "" : lpara
[3]);
856 * inputs - channel, source, list to remove, char of mode, caps needed
858 * side effects - given list is removed, with modes issued to local clients
859 * and non-TS6 servers.
862 remove_ban_list(struct Channel
*chptr
, struct Client
*source_p
,
863 dlink_list
* list
, char c
, int cap
, int mems
)
865 static char lmodebuf
[BUFSIZE
];
866 static char lparabuf
[BUFSIZE
];
869 dlink_node
*next_ptr
;
872 int cur_len
, mlen
, plen
;
876 cur_len
= mlen
= ircsprintf(lmodebuf
, ":%s MODE %s -", source_p
->name
, chptr
->chname
);
877 mbuf
= lmodebuf
+ mlen
;
879 DLINK_FOREACH_SAFE(ptr
, next_ptr
, list
->head
)
883 /* trailing space, and the mode letter itself */
884 plen
= strlen(banptr
->banstr
) + 2;
886 if(count
>= MAXMODEPARAMS
|| (cur_len
+ plen
) > BUFSIZE
- 4)
888 /* remove trailing space */
892 sendto_channel_local(mems
, chptr
, "%s %s", lmodebuf
, lparabuf
);
893 /* Tricky tricky. If we changed source_p to &me
894 * in ms_sjoin(), this still won't send stuff
895 * where it should not be sent, because the
896 * real source_p does TS6 -- jilles */
897 sendto_server(source_p
, chptr
, cap
, CAP_TS6
, "%s %s", lmodebuf
, lparabuf
);
900 mbuf
= lmodebuf
+ mlen
;
907 pbuf
+= ircsprintf(pbuf
, "%s ", banptr
->banstr
);
915 sendto_channel_local(mems
, chptr
, "%s %s", lmodebuf
, lparabuf
);
916 sendto_server(source_p
, chptr
, cap
, CAP_TS6
, "%s %s", lmodebuf
, lparabuf
);
918 list
->head
= list
->tail
= NULL
;