mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-06-27 23:36:38 +02:00
b0dba4bede
and 7 for unknown-users (with max-bytes 5250 and 1500 respectively). This
allows pasting a short snippet of code, config file, text from a site, etc.
With multiline you have the guarantee that:
1) You will see the entire text with no delay between lines
2) You won't see another persons chat half-way through such a paste
3) For multiline supporting clients it is now clear that all the text
belongs to each other, which can make selecting/copying it easier.
This basically means short snippets/pastes like that can be completely on
IRC again. No need for a pastebin for it. Though, you may still need such
a service if you are pasting more lines.
Regarding the implementation in UnrealIRCd:
* Clients without multiline get individual fallback lines (concat lines
merged, blank lines skipped, as per spec). And we know that clients like
weechat - which does support multiline - also shows all lines and not
only a few plus snippet style "[.."]. That is another reason for only
allowing 15 lines by default and not something much more. Otherwise all
those clients would get a big wall of text, which just sucks.
* Spamfilter (also) runs on the full text of all lines together, so
splitting a phrase across lines does not evade spamfilter.
* Fakelag: a client can send the BATCH start+PRIVMSG (or NOTICE)+BATCH end
at full speed. We impose no fake lag there. Also, the multiline default
max-lines and max-bytes are lower than the example class::recvq of 8000,
so should be perfectly safe. If the entire BATCH is accepted then we
will impose fake-lag afterwards, with a cap of 15 seconds maximum.
If the BATCH is rejected, we impose half the fakelag plus 2sec.
* If the time between BATCH start and BATCH end is more than 15 seconds
then the BATCH is rejected (set::multiline::batch-timeout).
* The BATCH is atomic (either you see it all, or you see none of it):
* When the client sends it to server, it is buffered first.
* Only after the batch close the server indicates if it is accepted
or rejected. This has various reasons, two of them are: 1) The client
is going to send everything in one go anyway and not wait for a
response between each PRIVMSG, and 2) we can't do many checks in the
buffering stage and skip those after, that would cause a TOCTOU
problem (eg. a banned user still being able to speak).
* If any line gets rejected due to spamfilter or other case
(eg +c, +b ~text with block, etc etc), the entire batch is rejected
* Locally we deliver all or nothing (as said)
* S2S we buffer the batch as well, so if a server splits after having
received 10 lines out of 15, then clients will not see anything.
* We send max-lines and max-bytes, this is the hard upper limit.
* A multiline can still be limited more tight if:
* +f with 't' or 'm' restricts to fewer lines,
eg +f [5t]:15, which means max 5 lines per 15 seconds,
means the max accepted multiline is 5 for that channel.
* +F works the same, except that default +F normal does not
have a 't' at the moment and 'm' is very high (50) so
practically not limited by default.
* There will be a future +f flood subtype for some more control
TODO: we will send CAP NEW on unknown-users <-> known-users to
indicate the new max-lines value if you transition security groups
TODO: chat history does not yet include multiline batches.
117 lines
2.8 KiB
C
117 lines
2.8 KiB
C
/*
|
|
* IRC - Internet Relay Chat, src/modules/reply-tag.c
|
|
* (C) 2021 Syzop & The UnrealIRCd Team
|
|
*
|
|
* See file AUTHORS in IRC package for additional names of
|
|
* the programmers.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 1, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
/* This implements https://ircv3.net/specs/client-tags/reply */
|
|
|
|
#include "unrealircd.h"
|
|
|
|
ModuleHeader MOD_HEADER
|
|
= {
|
|
"reply-tag",
|
|
"5.0",
|
|
"+reply client tag",
|
|
"UnrealIRCd Team",
|
|
"unrealircd-6",
|
|
};
|
|
|
|
int replytag_mtag_is_ok(Client *client, const char *name, const char *value);
|
|
void mtag_add_replytag(Client *client, MessageTag *recv_mtags, MessageTag **mtag_list, const char *signature);
|
|
|
|
MOD_INIT()
|
|
{
|
|
MessageTagHandlerInfo mtag;
|
|
|
|
MARK_AS_OFFICIAL_MODULE(modinfo);
|
|
|
|
#if 0
|
|
memset(&mtag, 0, sizeof(mtag));
|
|
mtag.name = "+reply";
|
|
mtag.is_ok = replytag_mtag_is_ok;
|
|
mtag.flags = MTAG_HANDLER_FLAGS_NO_CAP_NEEDED;
|
|
MessageTagHandlerAdd(modinfo->handle, &mtag);
|
|
#endif
|
|
|
|
memset(&mtag, 0, sizeof(mtag));
|
|
mtag.name = "+draft/reply";
|
|
mtag.is_ok = replytag_mtag_is_ok;
|
|
mtag.flags = MTAG_HANDLER_FLAGS_NO_CAP_NEEDED | MTAG_HANDLER_FLAGS_FIRST_ONLY;
|
|
MessageTagHandlerAdd(modinfo->handle, &mtag);
|
|
|
|
HookAddVoid(modinfo->handle, HOOKTYPE_NEW_MESSAGE, 0, mtag_add_replytag);
|
|
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
MOD_LOAD()
|
|
{
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
MOD_UNLOAD()
|
|
{
|
|
return MOD_SUCCESS;
|
|
}
|
|
|
|
/** This function verifies if the client sending the mtag is permitted to do so.
|
|
*/
|
|
int replytag_mtag_is_ok(Client *client, const char *name, const char *value)
|
|
{
|
|
const char *p;
|
|
|
|
/* Require a non-empty parameter */
|
|
if (BadPtr(value))
|
|
return 0;
|
|
|
|
/* All our PRIVMSG/NOTICE msgid's are of this size: */
|
|
if (strlen(value) != MSGIDLEN)
|
|
return 0;
|
|
|
|
for (p = value; *p; p++)
|
|
if (!isalnum(*p))
|
|
return 0; /* non-alphanumeric */
|
|
|
|
return 1; /* OK */
|
|
}
|
|
|
|
void mtag_add_replytag(Client *client, MessageTag *recv_mtags, MessageTag **mtag_list, const char *signature)
|
|
{
|
|
MessageTag *m;
|
|
|
|
if (IsUser(client))
|
|
{
|
|
#if 0
|
|
m = find_mtag(recv_mtags, "+reply");
|
|
if (m)
|
|
{
|
|
m = duplicate_mtag(m);
|
|
AddListItem(m, *mtag_list);
|
|
}
|
|
#endif
|
|
m = find_mtag(recv_mtags, "+draft/reply");
|
|
if (m)
|
|
{
|
|
m = duplicate_mtag(m);
|
|
AddListItem(m, *mtag_list);
|
|
}
|
|
}
|
|
}
|