mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-06-23 20:06:38 +02:00
Communicate server featureset (and changes) across server links.
Previously various information was only available for directly attached servers, since it is communicated via PROTOCTL. Now, we will also communicate information about leafs behind us. IRCOps can use the /SINFO command to see these server features. Services codes don't need to do anything, or at least are not expected to do anything. They can still receive the information and do something with it, of course... Read the following technical documentation for full information, as it will outline very specific rules for using the command S2S: https://www.unrealircd.org/docs/Server_protocol:SINFO_command
This commit is contained in:
@@ -118,6 +118,7 @@ loadmodule "m_sjoin";
|
||||
loadmodule "m_sqline";
|
||||
loadmodule "m_swhois";
|
||||
loadmodule "m_umode2";
|
||||
loadmodule "m_sinfo";
|
||||
|
||||
// Services commands
|
||||
// You could disable these if you don't use Services
|
||||
|
||||
@@ -43,6 +43,8 @@ extern MODVAR struct stats *ircstp;
|
||||
extern MODVAR int bootopt;
|
||||
extern MODVAR time_t TSoffset;
|
||||
extern MODVAR time_t timeofday;
|
||||
extern MODVAR char cmodestring[512];
|
||||
extern MODVAR char umodestring[UMODETABLESZ+1];
|
||||
/* newconf */
|
||||
#define get_sendq(x) ((x)->local->class ? (x)->local->class->sendq : MAXSENDQLENGTH)
|
||||
/* get_recvq is only called in send.c for local connections */
|
||||
@@ -491,6 +493,7 @@ extern void flag_add(char ch);
|
||||
extern void flag_del(char ch);
|
||||
extern void init_dynconf(void);
|
||||
extern char *pretty_time_val(long);
|
||||
extern char *pretty_date(TS t);
|
||||
extern int init_conf(char *filename, int rehash);
|
||||
extern void validate_configuration(void);
|
||||
extern void run_configuration(void);
|
||||
@@ -669,6 +672,7 @@ extern MODVAR void (*send_join_to_local_users)(aClient *sptr, aChannel *chptr);
|
||||
extern MODVAR int (*do_nick_name)(char *nick);
|
||||
extern MODVAR int (*do_remote_nick_name)(char *nick);
|
||||
extern MODVAR char *(*charsys_get_current_languages)(void);
|
||||
extern MODVAR void *(*broadcast_sinfo)(aClient *acptr, aClient *to, aClient *except);
|
||||
/* /Efuncs */
|
||||
|
||||
extern MODVAR aMotdFile opermotd, svsmotd, motd, botmotd, smotd, rules;
|
||||
@@ -741,6 +745,7 @@ extern MODVAR BOOL IsService;
|
||||
#endif
|
||||
extern int match_ip46(char *a, char *b);
|
||||
extern void extcmodes_check_for_changes(void);
|
||||
extern void umodes_check_for_changes(void);
|
||||
extern int config_parse_flood(char *orig, int *times, int *period);
|
||||
extern int swhois_add(aClient *acptr, char *tag, int priority, char *swhois, aClient *from, aClient *skip);
|
||||
extern int swhois_delete(aClient *acptr, char *tag, char *swhois, aClient *from, aClient *skip);
|
||||
@@ -809,3 +814,6 @@ extern void setmaxtargets(char *cmd, int limit);
|
||||
extern void freemaxtargets(void);
|
||||
extern int max_targets_for_command(char *cmd);
|
||||
extern void set_targmax_defaults(void);
|
||||
extern void parse_chanmodes_protoctl(aClient *sptr, char *str);
|
||||
extern void concat_params(char *buf, int len, int parc, char *parv[]);
|
||||
extern void charsys_check_for_changes(void);
|
||||
|
||||
@@ -1101,6 +1101,7 @@ _UNREAL_ERROR(_hook_error_incompatible, "Incompatible hook function. Check argum
|
||||
#define EFUNC_DO_NICK_NAME 57
|
||||
#define EFUNC_DO_REMOTE_NICK_NAME 58
|
||||
#define EFUNC_CHARSYS_GET_CURRENT_LANGUAGES 59
|
||||
#define EFUNC_BROADCAST_SINFO 60
|
||||
|
||||
/* Module flags */
|
||||
#define MODFLAG_NONE 0x0000
|
||||
|
||||
+5
-2
@@ -696,8 +696,9 @@ struct Server {
|
||||
char *up; /* uplink for this server */
|
||||
char by[NICKLEN + 1];
|
||||
ConfigItem_link *conf;
|
||||
TS timestamp; /* Remotely determined connect try time */
|
||||
long users;
|
||||
TS timestamp; /* Remotely determined connect try time */
|
||||
long users;
|
||||
TS boottime; /* Startup time of server */
|
||||
#ifdef LIST_DEBUG
|
||||
aClient *bcptr;
|
||||
#endif
|
||||
@@ -706,9 +707,11 @@ struct Server {
|
||||
unsigned server_sent:1; /* SERVER message sent to this link? (for outgoing links) */
|
||||
} flags;
|
||||
struct {
|
||||
char *usermodes;
|
||||
char *chanmodes[4];
|
||||
int protocol;
|
||||
char *software;
|
||||
char *nickchars;
|
||||
} features;
|
||||
};
|
||||
|
||||
|
||||
@@ -232,6 +232,7 @@ DLL_FILES=SRC/MODULES/M_CHGHOST.DLL SRC/MODULES/M_SDESC.DLL SRC/MODULES/M_SETIDE
|
||||
SRC/MODULES/CHARSYS.DLL \
|
||||
SRC/MODULES/ANTIMIXEDUTF8.DLL \
|
||||
SRC/MODULES/AUTHPROMPT.DLL \
|
||||
SRC/MODULES/M_SINFO.DLL \
|
||||
SRC/MODULES/CHANMODES/CENSOR.DLL \
|
||||
SRC/MODULES/CHANMODES/DELAYJOIN.DLL \
|
||||
SRC/MODULES/CHANMODES/FLOODPROT.DLL \
|
||||
@@ -867,6 +868,9 @@ src/modules/antimixedutf8.dll: src/modules/antimixedutf8.c $(INCLUDES)
|
||||
src/modules/authprompt.dll: src/modules/authprompt.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/authprompt.c $(MODLFLAGS)
|
||||
|
||||
src/modules/m_sinfo.dll: src/modules/m_sinfo.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) src/modules/m_sinfo.c $(MODLFLAGS)
|
||||
|
||||
src/modules/chanmodes/censor.dll: src/modules/chanmodes/censor.c $(INCLUDES)
|
||||
$(CC) $(MODCFLAGS) /Fosrc/modules/chanmodes/ /Fesrc/modules/chanmodes/ src/modules/chanmodes/censor.c $(MODLFLAGS)
|
||||
|
||||
|
||||
+17
-6
@@ -39,8 +39,6 @@
|
||||
#include <fcntl.h>
|
||||
#include "h.h"
|
||||
|
||||
extern char cmodestring[512];
|
||||
|
||||
/* Channel parameter to slot# mapping */
|
||||
MODVAR unsigned char param_to_slot_mapping[256];
|
||||
|
||||
@@ -93,12 +91,25 @@ void extcmodes_check_for_changes(void)
|
||||
{
|
||||
char chanmodes[256];
|
||||
Isupport *isup;
|
||||
|
||||
|
||||
make_cmodestr();
|
||||
make_extcmodestr();
|
||||
ircsnprintf(chanmodes, sizeof(chanmodes), CHPAR1 "%s," CHPAR2 "%s," CHPAR3 "%s," CHPAR4 "%s",
|
||||
EXPAR1, EXPAR2, EXPAR3, EXPAR4);
|
||||
|
||||
|
||||
snprintf(chanmodes, sizeof(chanmodes), "%s%s", CHPAR1, EXPAR1);
|
||||
safestrdup(me.serv->features.chanmodes[0], chanmodes);
|
||||
snprintf(chanmodes, sizeof(chanmodes), "%s%s", CHPAR2, EXPAR2);
|
||||
safestrdup(me.serv->features.chanmodes[1], chanmodes);
|
||||
snprintf(chanmodes, sizeof(chanmodes), "%s%s", CHPAR3, EXPAR3);
|
||||
safestrdup(me.serv->features.chanmodes[2], chanmodes);
|
||||
snprintf(chanmodes, sizeof(chanmodes), "%s%s", CHPAR4, EXPAR4);
|
||||
safestrdup(me.serv->features.chanmodes[3], chanmodes);
|
||||
|
||||
ircsnprintf(chanmodes, sizeof(chanmodes), "%s,%s,%s,%s",
|
||||
me.serv->features.chanmodes[0],
|
||||
me.serv->features.chanmodes[1],
|
||||
me.serv->features.chanmodes[2],
|
||||
me.serv->features.chanmodes[3]);
|
||||
|
||||
isup = IsupportFind("CHANMODES");
|
||||
if (!isup)
|
||||
{
|
||||
|
||||
+9
-5
@@ -1347,7 +1347,13 @@ int InitUnrealIRCd(int argc, char *argv[])
|
||||
booted = TRUE;
|
||||
load_tunefile();
|
||||
make_umodestr();
|
||||
me.flags = FLAGS_LISTEN;
|
||||
me.fd = -1;
|
||||
SetMe(&me);
|
||||
make_server(&me);
|
||||
extcmodes_check_for_changes();
|
||||
umodes_check_for_changes();
|
||||
charsys_check_for_changes();
|
||||
clicap_init();
|
||||
if (!find_Command_simple("AWAY") /*|| !find_Command_simple("KILL") ||
|
||||
!find_Command_simple("OPER") || !find_Command_simple("PING")*/)
|
||||
@@ -1379,10 +1385,6 @@ int InitUnrealIRCd(int argc, char *argv[])
|
||||
portnum = PORTNUM;
|
||||
me.local->port = portnum;
|
||||
(void)init_sys();
|
||||
me.flags = FLAGS_LISTEN;
|
||||
me.fd = -1;
|
||||
SetMe(&me);
|
||||
make_server(&me);
|
||||
applymeblock();
|
||||
#ifdef HAVE_SYSLOG
|
||||
openlog("ircd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
|
||||
@@ -1409,7 +1411,9 @@ int InitUnrealIRCd(int argc, char *argv[])
|
||||
me_hash = find_or_add(me.name);
|
||||
me.serv->up = me_hash;
|
||||
timeofday = time(NULL);
|
||||
me.local->lasttime = me.local->since = me.local->firsttime = TStime();
|
||||
me.local->lasttime = me.local->since = me.local->firsttime = me.serv->boottime = TStime();
|
||||
me.serv->features.protocol = UnrealProtocol;
|
||||
me.serv->features.software = strdup(version);
|
||||
(void)add_to_client_hash_table(me.name, &me);
|
||||
(void)add_to_id_hash_table(me.id, &me);
|
||||
list_add(&me.client_node, &global_server_list);
|
||||
|
||||
+3
-1
@@ -137,6 +137,7 @@ void (*send_join_to_local_users)(aClient *sptr, aChannel *chptr);
|
||||
int (*do_nick_name)(char *nick);
|
||||
int (*do_remote_nick_name)(char *nick);
|
||||
char *(*charsys_get_current_languages)(void);
|
||||
void *(*broadcast_sinfo)(aClient *acptr, aClient *to, aClient *except);
|
||||
|
||||
static const EfunctionsList efunction_table[MAXEFUNCTIONS] = {
|
||||
/* 00 */ {NULL, NULL},
|
||||
@@ -199,7 +200,8 @@ static const EfunctionsList efunction_table[MAXEFUNCTIONS] = {
|
||||
/* 57 */ {"do_nick_name", (void *)&do_nick_name},
|
||||
/* 58 */ {"do_remote_nick_name", (void *)&do_remote_nick_name},
|
||||
/* 59 */ {"charsys_get_current_languages", (void *)&charsys_get_current_languages},
|
||||
/* 60 */ {NULL, NULL}
|
||||
/* 60 */ {"broadcast_sinfo", (void *)&broadcast_sinfo},
|
||||
/* 61 */ {NULL, NULL}
|
||||
};
|
||||
|
||||
#ifdef UNDERSCORE
|
||||
|
||||
@@ -62,7 +62,7 @@ R_MODULES= \
|
||||
blacklist.so jointhrottle.so \
|
||||
antirandom.so hideserver.so jumpserver.so \
|
||||
m_ircops.so m_staff.so nocodes.so \
|
||||
charsys.so antimixedutf8.so authprompt.so
|
||||
charsys.so antimixedutf8.so authprompt.so m_sinfo.so
|
||||
|
||||
MODULES=cloak.so $(R_MODULES)
|
||||
MODULEFLAGS=@MODULEFLAGS@
|
||||
@@ -526,6 +526,10 @@ authprompt.so: authprompt.c $(INCLUDES)
|
||||
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
|
||||
-o authprompt.so authprompt.c
|
||||
|
||||
m_sinfo.so: m_sinfo.c $(INCLUDES)
|
||||
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
|
||||
-o m_sinfo.so m_sinfo.c
|
||||
|
||||
#############################################################################
|
||||
# capabilities
|
||||
#############################################################################
|
||||
|
||||
@@ -420,6 +420,7 @@ ILangList *e, *e_next;
|
||||
if (strlen(langsinuse) > 490)
|
||||
abort();
|
||||
#endif
|
||||
charsys_check_for_changes();
|
||||
}
|
||||
|
||||
/** Add a character range to the multibyte list.
|
||||
|
||||
@@ -1173,8 +1173,6 @@ CMD_FUNC(m_nick)
|
||||
** this is not fair. It should actually request another
|
||||
** nick from local user or kill him/her...
|
||||
*/
|
||||
extern MODVAR char cmodestring[512];
|
||||
extern MODVAR char umodestring[UMODETABLESZ+1];
|
||||
|
||||
extern int short_motd(aClient *sptr);
|
||||
|
||||
|
||||
+21
-26
@@ -276,6 +276,12 @@ CMD_FUNC(m_protoctl)
|
||||
get_client_name(cptr, FALSE), charsys_get_current_languages(), s+10);
|
||||
/* return exit_client(cptr, cptr, &me, "Nick charset mismatch"); */
|
||||
}
|
||||
if (cptr->serv)
|
||||
safestrdup(cptr->serv->features.nickchars, s+10);
|
||||
|
||||
/* If this is a runtime change (so post-handshake): */
|
||||
if (IsServer(sptr))
|
||||
broadcast_sinfo(sptr, NULL, cptr);
|
||||
}
|
||||
else if (strncmp(s, "SID=", 4) == 0)
|
||||
{
|
||||
@@ -455,32 +461,21 @@ CMD_FUNC(m_protoctl)
|
||||
}
|
||||
else if ((strncmp(s, "CHANMODES=", 10) == 0) && sptr->serv)
|
||||
{
|
||||
char *ch = s + 4;
|
||||
char *modes, *p;
|
||||
char copy[256];
|
||||
|
||||
strlcpy(copy, s+10, sizeof(copy));
|
||||
|
||||
modes = strtoken(&p, copy, ",");
|
||||
if (modes)
|
||||
{
|
||||
safestrdup(sptr->serv->features.chanmodes[0], modes);
|
||||
modes = strtoken(&p, NULL, ",");
|
||||
if (modes)
|
||||
{
|
||||
safestrdup(sptr->serv->features.chanmodes[1], modes);
|
||||
modes = strtoken(&p, NULL, ",");
|
||||
if (modes)
|
||||
{
|
||||
safestrdup(sptr->serv->features.chanmodes[2], modes);
|
||||
modes = strtoken(&p, NULL, ",");
|
||||
if (modes)
|
||||
{
|
||||
safestrdup(sptr->serv->features.chanmodes[3], modes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parse_chanmodes_protoctl(sptr, s+10);
|
||||
/* If this is a runtime change (so post-handshake): */
|
||||
if (IsServer(sptr))
|
||||
broadcast_sinfo(sptr, NULL, cptr);
|
||||
}
|
||||
else if ((strncmp(s, "USERMODES=", 10) == 0) && sptr->serv)
|
||||
{
|
||||
safestrdup(sptr->serv->features.usermodes, s+10);
|
||||
/* If this is a runtime change (so post-handshake): */
|
||||
if (IsServer(sptr))
|
||||
broadcast_sinfo(sptr, NULL, cptr);
|
||||
}
|
||||
else if ((strncmp(s, "BOOTED=", 7) == 0) && sptr->serv)
|
||||
{
|
||||
sptr->serv->boottime = atol(s+7);
|
||||
}
|
||||
else if (!strcmp(s, "EXTSWHOIS"))
|
||||
{
|
||||
|
||||
+56
-2
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
/* Forward declarations */
|
||||
void send_channel_modes(aClient *cptr, aChannel *chptr);
|
||||
void send_channel_modes_sjoin(aClient *cptr, aChannel *chptr);
|
||||
void send_channel_modes_sjoin3(aClient *cptr, aChannel *chptr);
|
||||
@@ -32,10 +33,11 @@ void _send_protoctl_servers(aClient *sptr, int response);
|
||||
void _send_server_message(aClient *sptr);
|
||||
void _introduce_user(aClient *to, aClient *acptr);
|
||||
int _check_deny_version(aClient *cptr, char *software, int protocol, char *flags);
|
||||
void _broadcast_sinfo(aClient *acptr, aClient *to, aClient *except);
|
||||
|
||||
/* Global variables */
|
||||
static char buf[BUFSIZE];
|
||||
|
||||
|
||||
#define MSG_SERVER "SERVER"
|
||||
|
||||
ModuleHeader MOD_HEADER(m_server)
|
||||
@@ -55,6 +57,7 @@ MOD_TEST(m_server)
|
||||
EfunctionAdd(modinfo->handle, EFUNC_VERIFY_LINK, _verify_link);
|
||||
EfunctionAddVoid(modinfo->handle, EFUNC_INTRODUCE_USER, _introduce_user);
|
||||
EfunctionAdd(modinfo->handle, EFUNC_CHECK_DENY_VERSION, _check_deny_version);
|
||||
EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_SINFO, _broadcast_sinfo);
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -815,6 +818,49 @@ void tls_link_notification_verify(aClient *acptr, ConfigItem_link *aconf)
|
||||
}
|
||||
}
|
||||
|
||||
#define SafeStr(x) ((x && *(x)) ? (x) : "*")
|
||||
|
||||
/** Broadcast SINFO.
|
||||
* @param cptr The server to send the information about.
|
||||
* @param to The server to send the information TO (NULL for broadcast).
|
||||
* @param except The direction NOT to send to.
|
||||
* This function takes into account that the server may not
|
||||
* provide all of the detailed info. If any information is
|
||||
* absent we will send 0 for numbers and * for NULL strings.
|
||||
*/
|
||||
void _broadcast_sinfo(aClient *acptr, aClient *to, aClient *except)
|
||||
{
|
||||
char chanmodes[128], buf[512];
|
||||
|
||||
if (acptr->serv->features.chanmodes[0])
|
||||
{
|
||||
snprintf(chanmodes, sizeof(chanmodes), "%s,%s,%s,%s",
|
||||
acptr->serv->features.chanmodes[0],
|
||||
acptr->serv->features.chanmodes[1],
|
||||
acptr->serv->features.chanmodes[2],
|
||||
acptr->serv->features.chanmodes[3]);
|
||||
} else {
|
||||
strlcpy(chanmodes, "*", sizeof(chanmodes));
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%ld %d %s %s %s :%s",
|
||||
acptr->serv->boottime,
|
||||
acptr->serv->features.protocol,
|
||||
SafeStr(acptr->serv->features.usermodes),
|
||||
chanmodes,
|
||||
SafeStr(acptr->serv->features.nickchars),
|
||||
SafeStr(acptr->serv->features.software));
|
||||
|
||||
if (to)
|
||||
{
|
||||
/* Targetted to one server */
|
||||
sendto_one(to, ":%s SINFO %s", acptr->name, buf);
|
||||
} else {
|
||||
/* Broadcast (except one side...) */
|
||||
sendto_server(except, 0, 0, ":%s SINFO %s", acptr->name, buf);
|
||||
}
|
||||
}
|
||||
|
||||
int m_server_synch(aClient *cptr, ConfigItem_link *aconf)
|
||||
{
|
||||
char *inpath = get_client_name(cptr, TRUE);
|
||||
@@ -912,6 +958,7 @@ int m_server_synch(aClient *cptr, ConfigItem_link *aconf)
|
||||
cptr->local->class = cptr->serv->conf->class;
|
||||
RunHook(HOOKTYPE_SERVER_CONNECT, cptr);
|
||||
|
||||
/* Broadcast new server to the rest of the network */
|
||||
if (*cptr->id)
|
||||
{
|
||||
sendto_server(cptr, PROTO_SID, 0, ":%s SID %s 2 %s :%s",
|
||||
@@ -922,7 +969,12 @@ int m_server_synch(aClient *cptr, ConfigItem_link *aconf)
|
||||
cptr->serv->up,
|
||||
cptr->name, cptr->info);
|
||||
|
||||
send_moddata_client(cptr, &me); /* send moddata of &me (if any, likely minimal) */
|
||||
/* Broadcast the just-linked-in featureset to other servers on our side */
|
||||
broadcast_sinfo(cptr, NULL, cptr);
|
||||
|
||||
/* Send moddata of &me (if any, likely minimal) */
|
||||
send_moddata_client(cptr, &me);
|
||||
|
||||
list_for_each_entry_reverse(acptr, &global_server_list, client_node)
|
||||
{
|
||||
/* acptr->from == acptr for acptr == cptr */
|
||||
@@ -961,6 +1013,8 @@ int m_server_synch(aClient *cptr, ConfigItem_link *aconf)
|
||||
cptr->name, acptr->name);
|
||||
#endif
|
||||
}
|
||||
/* Send SINFO of our servers to their side */
|
||||
broadcast_sinfo(acptr, cptr, NULL);
|
||||
send_moddata_client(cptr, acptr); /* send moddata of server 'acptr' (if any, likely minimal) */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* m_sinfo - Server information
|
||||
* (C) Copyright 2019 Bram Matthys (Syzop) and the UnrealIRCd team.
|
||||
* License: GPLv2
|
||||
*/
|
||||
|
||||
#include "unrealircd.h"
|
||||
|
||||
ModuleHeader MOD_HEADER(sinfo)
|
||||
= {
|
||||
"sinfo",
|
||||
"4.2",
|
||||
"Server information",
|
||||
"3.2-b8-1",
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
CMD_FUNC(m_sinfo);
|
||||
|
||||
MOD_INIT(sinfo)
|
||||
{
|
||||
CommandAdd(modinfo->handle, "SINFO", m_sinfo, MAXPARA, M_USER|M_SERVER);
|
||||
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_LOAD(sinfo)
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
MOD_UNLOAD(sinfo)
|
||||
{
|
||||
return MOD_SUCCESS;
|
||||
}
|
||||
|
||||
int sinfo_server(aClient *cptr, aClient *sptr, int parc, char *parv[])
|
||||
{
|
||||
char buf[512];
|
||||
|
||||
if (cptr == sptr)
|
||||
{
|
||||
/* It is a protocol violation to send an SINFO for yourself,
|
||||
* eg if you are server 001, then you cannot send :001 SINFO ....
|
||||
* Exiting the client may seem harsh, but this way we force users
|
||||
* to use the correct protocol. If we would not do this then some
|
||||
* services coders may think they should use only SINFO while in
|
||||
* fact for directly connected servers they should use things like
|
||||
* PROTOCTL CHANMODES=... USERMODES=... NICKCHARS=.... etc, and
|
||||
* failure to do so will lead to potential desyncs or other major
|
||||
* issues.
|
||||
*/
|
||||
return exit_client(cptr, sptr, &me, "Protocol error: you cannot send SINFO about yourself");
|
||||
}
|
||||
|
||||
/* :SID SINFO up_since protocol umodes chanmodes nickchars :software name
|
||||
* 1 2 3 4 5 6 (last one)
|
||||
* If we extend it then 'software name' will still be the last one, so
|
||||
* it may become 7, 8 or 9. New elements are inserted right before it.
|
||||
*/
|
||||
|
||||
if ((parc < 6) || BadPtr(parv[6]))
|
||||
{
|
||||
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, sptr->name, "SINFO");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sptr->serv->boottime = atol(parv[1]);
|
||||
sptr->serv->features.protocol = atoi(parv[2]);
|
||||
|
||||
if (!strcmp(parv[3], "*"))
|
||||
safefree(parv[3]);
|
||||
else
|
||||
safestrdup(sptr->serv->features.usermodes, parv[3]);
|
||||
|
||||
if (!strcmp(parv[4], "*"))
|
||||
{
|
||||
safefree(sptr->serv->features.chanmodes[0]);
|
||||
safefree(sptr->serv->features.chanmodes[1]);
|
||||
safefree(sptr->serv->features.chanmodes[2]);
|
||||
safefree(sptr->serv->features.chanmodes[3]);
|
||||
} else {
|
||||
parse_chanmodes_protoctl(sptr, parv[4]);
|
||||
}
|
||||
|
||||
if (!strcmp(parv[5], "*"))
|
||||
safefree(sptr->serv->features.nickchars);
|
||||
else
|
||||
safestrdup(sptr->serv->features.nickchars, parv[5]);
|
||||
|
||||
/* Software is always the last parameter. It is currently parv[6]
|
||||
* but may change later. So always use parv[parc-1].
|
||||
*/
|
||||
if (!strcmp(parv[parc-1], "*"))
|
||||
safefree(sptr->serv->features.software);
|
||||
else
|
||||
safestrdup(sptr->serv->features.software, parv[parc-1]);
|
||||
|
||||
/* Broadcast to 'the other side' of the net */
|
||||
concat_params(buf, sizeof(buf), parc, parv);
|
||||
sendto_server(cptr, 0, 0, ":%s SINFO %s", sptr->name, buf);
|
||||
}
|
||||
|
||||
#define SafeDisplayStr(x) ((x && *(x)) ? (x) : "-")
|
||||
int sinfo_user(aClient *cptr, aClient *sptr, int parc, char *parv[])
|
||||
{
|
||||
aClient *acptr;
|
||||
|
||||
if (!IsOper(sptr))
|
||||
{
|
||||
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, sptr->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_for_each_entry(acptr, &global_server_list, client_node)
|
||||
{
|
||||
sendtxtnumeric(sptr, "*** Server %s:", acptr->name);
|
||||
sendtxtnumeric(sptr, "Protocol: %d",
|
||||
acptr->serv->features.protocol);
|
||||
sendtxtnumeric(sptr, "Software: %s",
|
||||
SafeDisplayStr(acptr->serv->features.software));
|
||||
if (!acptr->serv->boottime)
|
||||
{
|
||||
sendtxtnumeric(sptr, "Up since: -");
|
||||
sendtxtnumeric(sptr, "Uptime: -");
|
||||
} else {
|
||||
sendtxtnumeric(sptr, "Up since: %s",
|
||||
pretty_date(acptr->serv->boottime));
|
||||
sendtxtnumeric(sptr, "Uptime: %s",
|
||||
pretty_time_val(TStime() - acptr->serv->boottime));
|
||||
}
|
||||
sendtxtnumeric(sptr, "User modes: %s",
|
||||
SafeDisplayStr(acptr->serv->features.usermodes));
|
||||
if (!acptr->serv->features.chanmodes[0])
|
||||
{
|
||||
sendtxtnumeric(sptr, "Channel modes: -");
|
||||
} else {
|
||||
sendtxtnumeric(sptr, "Channel modes: %s,%s,%s,%s",
|
||||
SafeDisplayStr(acptr->serv->features.chanmodes[0]),
|
||||
SafeDisplayStr(acptr->serv->features.chanmodes[1]),
|
||||
SafeDisplayStr(acptr->serv->features.chanmodes[2]),
|
||||
SafeDisplayStr(acptr->serv->features.chanmodes[3]));
|
||||
}
|
||||
sendtxtnumeric(sptr, "Allowed nick characters: %s",
|
||||
SafeDisplayStr(acptr->serv->features.nickchars));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CMD_FUNC(m_sinfo)
|
||||
{
|
||||
if (IsServer(sptr))
|
||||
return sinfo_server(cptr, sptr, parc, parv);
|
||||
else if (MyClient(sptr))
|
||||
return sinfo_user(cptr, sptr, parc, parv);
|
||||
return 0;
|
||||
}
|
||||
+8
-3
@@ -3020,11 +3020,14 @@ char *pretty_time_val(long timeval)
|
||||
if (timeval/86400)
|
||||
snprintf(buf, sizeof(buf), "%ld day%s ", timeval/86400, timeval/86400 != 1 ? "s" : "");
|
||||
if ((timeval/3600) % 24)
|
||||
snprintf(buf, sizeof(buf), "%s%ld hour%s ", buf, (timeval/3600)%24, (timeval/3600)%24 != 1 ? "s" : "");
|
||||
snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%ld hour%s ", (timeval/3600)%24, (timeval/3600)%24 != 1 ? "s" : "");
|
||||
if ((timeval/60)%60)
|
||||
snprintf(buf, sizeof(buf), "%s%ld minute%s ", buf, (timeval/60)%60, (timeval/60)%60 != 1 ? "s" : "");
|
||||
snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%ld minute%s ", (timeval/60)%60, (timeval/60)%60 != 1 ? "s" : "");
|
||||
if ((timeval%60))
|
||||
snprintf(buf, sizeof(buf), "%s%ld second%s", buf, timeval%60, timeval%60 != 1 ? "s" : "");
|
||||
snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%ld second%s", timeval%60, timeval%60 != 1 ? "s" : "");
|
||||
/* Strip space at the end (if any) */
|
||||
if (*buf && (buf[strlen(buf)-1] == ' '))
|
||||
buf[strlen(buf)-1] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -10598,6 +10601,8 @@ int rehash_internal(aClient *cptr, aClient *sptr, int sig)
|
||||
unload_all_unused_extcmodes();
|
||||
// unload_all_unused_moddata(); -- this will crash
|
||||
extcmodes_check_for_changes();
|
||||
umodes_check_for_changes();
|
||||
charsys_check_for_changes();
|
||||
loop.ircd_rehashing = 0;
|
||||
remote_rehash_client = NULL;
|
||||
return 1;
|
||||
|
||||
@@ -1323,3 +1323,56 @@ size_t add_sjsby(char *buf, char *setby, TS seton)
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
/** Concatenate the entire parameter string.
|
||||
* The function will take care of spaces in the final parameter (if any).
|
||||
* @param buf The buffer to output in.
|
||||
* @param len Length of the buffer.
|
||||
* @param parc Parameter count, ircd style.
|
||||
* @param parv Parameters, ircd style, so we will start at parv[1].
|
||||
* @example
|
||||
* char buf[512];
|
||||
* concat_params(buf, sizeof(buf), parc, parv);
|
||||
* sendto_server(cptr, 0, 0, ":%s SOMECOMMAND %s", sptr->name, buf);
|
||||
*/
|
||||
void concat_params(char *buf, int len, int parc, char *parv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
*buf = '\0';
|
||||
for (i = 1; i < parc; i++)
|
||||
{
|
||||
char *param = parv[i];
|
||||
|
||||
if (param && !*buf)
|
||||
strlcat(buf, " ", sizeof(buf));
|
||||
|
||||
if (strchr(param, ' '))
|
||||
{
|
||||
/* Last parameter, with : */
|
||||
strlcat(buf, ":", sizeof(buf));
|
||||
strlcat(buf, parv[i], sizeof(buf));
|
||||
break;
|
||||
}
|
||||
strlcat(buf, parv[i], sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
||||
char *pretty_date(TS t)
|
||||
{
|
||||
static char buf[128];
|
||||
struct tm *tm;
|
||||
|
||||
if (!t)
|
||||
time(&t);
|
||||
tm = gmtime(&t);
|
||||
snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d GMT",
|
||||
1900 + tm->tm_year,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour,
|
||||
tm->tm_min,
|
||||
tm->tm_sec);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
+60
-5
@@ -216,7 +216,6 @@ char *num = NULL;
|
||||
*/
|
||||
void send_proto(aClient *cptr, ConfigItem_link *aconf)
|
||||
{
|
||||
char buf[1024];
|
||||
Isupport *prefix = IsupportFind("PREFIX");
|
||||
|
||||
/* CAUTION: If adding a token to an existing PROTOCTL line below,
|
||||
@@ -228,10 +227,8 @@ void send_proto(aClient *cptr, ConfigItem_link *aconf)
|
||||
iConf.ban_setter_sync ? "SJSBY" : "");
|
||||
|
||||
/* Second line */
|
||||
snprintf(buf, sizeof(buf), "CHANMODES=%s%s,%s%s,%s%s,%s%s PREFIX=%s NICKCHARS=%s SID=%s MLOCK TS=%ld EXTSWHOIS",
|
||||
CHPAR1, EXPAR1, CHPAR2, EXPAR2, CHPAR3, EXPAR3, CHPAR4, EXPAR4, prefix->value, charsys_get_current_languages(), me.id, (long)TStime());
|
||||
|
||||
sendto_one(cptr, "PROTOCTL %s", buf);
|
||||
sendto_one(cptr, "PROTOCTL CHANMODES=%s%s,%s%s,%s%s,%s%s USERMODES=%s BOOTED=%ld PREFIX=%s NICKCHARS=%s SID=%s MLOCK TS=%ld EXTSWHOIS",
|
||||
CHPAR1, EXPAR1, CHPAR2, EXPAR2, CHPAR3, EXPAR3, CHPAR4, EXPAR4, umodestring, me.local->since, prefix->value, charsys_get_current_languages(), me.id, (long)TStime());
|
||||
}
|
||||
|
||||
#ifndef IRCDTOTALVERSION
|
||||
@@ -1386,3 +1383,61 @@ aClient *find_non_pending_net_duplicates(aClient *cptr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void parse_chanmodes_protoctl(aClient *sptr, char *str)
|
||||
{
|
||||
char *modes, *p;
|
||||
char copy[256];
|
||||
|
||||
strlcpy(copy, str, sizeof(copy));
|
||||
|
||||
modes = strtoken(&p, copy, ",");
|
||||
if (modes)
|
||||
{
|
||||
safestrdup(sptr->serv->features.chanmodes[0], modes);
|
||||
modes = strtoken(&p, NULL, ",");
|
||||
if (modes)
|
||||
{
|
||||
safestrdup(sptr->serv->features.chanmodes[1], modes);
|
||||
modes = strtoken(&p, NULL, ",");
|
||||
if (modes)
|
||||
{
|
||||
safestrdup(sptr->serv->features.chanmodes[2], modes);
|
||||
modes = strtoken(&p, NULL, ",");
|
||||
if (modes)
|
||||
{
|
||||
safestrdup(sptr->serv->features.chanmodes[3], modes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char previous_langsinuse[512];
|
||||
static int previous_langsinuse_ready = 0;
|
||||
|
||||
void charsys_check_for_changes(void)
|
||||
{
|
||||
char *langsinuse = charsys_get_current_languages();
|
||||
/* already called by charsys_finish() */
|
||||
safestrdup(me.serv->features.nickchars, langsinuse);
|
||||
|
||||
if (!previous_langsinuse_ready)
|
||||
{
|
||||
previous_langsinuse_ready = 1;
|
||||
strlcpy(previous_langsinuse, langsinuse, sizeof(previous_langsinuse));
|
||||
return; /* not booted yet. then we are done here. */
|
||||
}
|
||||
|
||||
if (strcmp(langsinuse, previous_langsinuse))
|
||||
{
|
||||
ircd_log(LOG_ERROR, "Permitted nick characters changed at runtime: %s -> %s",
|
||||
previous_langsinuse, langsinuse);
|
||||
sendto_realops("Permitted nick characters changed at runtime: %s -> %s",
|
||||
previous_langsinuse, langsinuse);
|
||||
/* Broadcast change to all (locally connected) servers */
|
||||
sendto_server(&me, 0, 0, "PROTOCTL NICKCHARS=%s", langsinuse);
|
||||
}
|
||||
|
||||
strlcpy(previous_langsinuse, langsinuse, sizeof(previous_langsinuse));
|
||||
}
|
||||
|
||||
|
||||
@@ -141,6 +141,32 @@ void make_umodestr(void)
|
||||
*m = '\0';
|
||||
}
|
||||
|
||||
static char previous_umodestring[256];
|
||||
|
||||
void umodes_check_for_changes(void)
|
||||
{
|
||||
make_umodestr();
|
||||
safestrdup(me.serv->features.usermodes, umodestring);
|
||||
|
||||
if (!*previous_umodestring)
|
||||
{
|
||||
strlcpy(previous_umodestring, umodestring, sizeof(previous_umodestring));
|
||||
return; /* not booted yet. then we are done here. */
|
||||
}
|
||||
|
||||
if (*previous_umodestring && strcmp(umodestring, previous_umodestring))
|
||||
{
|
||||
ircd_log(LOG_ERROR, "User modes changed at runtime: %s -> %s",
|
||||
previous_umodestring, umodestring);
|
||||
sendto_realops("User modes changed at runtime: %s -> %s",
|
||||
previous_umodestring, umodestring);
|
||||
/* Broadcast change to all (locally connected) servers */
|
||||
sendto_server(&me, 0, 0, "PROTOCTL USERMODES=%s", umodestring);
|
||||
}
|
||||
|
||||
strlcpy(previous_umodestring, umodestring, sizeof(previous_umodestring));
|
||||
}
|
||||
|
||||
/* UmodeAdd:
|
||||
* Add a usermode with character 'ch', if global is set to 1 the usermode is global
|
||||
* (sent to other servers) otherwise it's a local usermode
|
||||
|
||||
Reference in New Issue
Block a user