0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-26 15:33:54 +01:00

Refactor isupport.

This commit is contained in:
Jason Volk 2016-08-25 00:59:58 -07:00
parent 9c16de2d41
commit 5f79420c29
14 changed files with 302 additions and 252 deletions

View file

@ -60,6 +60,8 @@ namespace ircd
struct ev_ctl;
struct ws_ctl;
struct server_conf;
using ostream = std::ostream;
}
#include "util.h"

View file

@ -4,6 +4,8 @@
*
* Entirely rewritten, August 2006 by Jilles Tjoelker
* Copyright (C) 2006 Jilles Tjoelker
* Copyright (C) 2016 Charybdis Development Team
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -35,17 +37,72 @@
#ifdef __cplusplus
namespace ircd {
namespace supported {
extern void add_isupport(const char *, const char *(*)(const void *), const void *);
extern const void *change_isupport(const char *, const char *(*)(const void *), const void *);
extern void delete_isupport(const char *);
extern void show_isupport(client::client *);
extern void init_isupport(void);
using client::client;
extern const char *isupport_intptr(const void *);
extern const char *isupport_boolean(const void *);
extern const char *isupport_string(const void *);
extern const char *isupport_stringptr(const void *);
// Additional types can be supported here eventually
enum class type
{
BOOLEAN, // boolean value (always true if key exists in map)
INTEGER, // integer is copied here as the value
STRING, // string is copied here as the value
FUNC_BOOLEAN, // function returns a boolean value
FUNC_STREAM, // function argument is an output stream
};
struct value
{
enum type type; union
{
int64_t integer;
std::string string;
std::function<bool ()> func_boolean;
std::function<void (ostream &)> func_stream;
};
ostream &operator()(const std::string &key, ostream &buf) const;
value();
value(const int64_t &);
value(const std::string &);
value(const std::function<bool ()> &);
value(const std::function<void (ostream &)> &);
~value() noexcept;
};
extern std::map<std::string, value> map;
template<class value_t> void add(const std::string &key, value_t&& v);
void add(const std::string &key);
bool del(const std::string &key);
void show(client &);
void init();
} // namespace supported
} // namespace ircd
inline
void ircd::supported::add(const std::string &key)
{
//TODO: XXX
//value can't be reassigned unless there's an explicit move constructor
//elaborating the entire unrestricted union etc etc for another time.
map.erase(key);
map.emplace(std::piecewise_construct,
std::make_tuple(key),
std::make_tuple());
}
template<class value_t>
void ircd::supported::add(const std::string &key,
value_t&& v)
{
map.erase(key);
map.emplace(std::piecewise_construct,
std::make_tuple(key),
std::make_tuple(std::forward<value_t>(v)));
}
#endif // __cplusplus

View file

@ -194,6 +194,18 @@ operator^=(Enum &a, const Enum &b)
return (a = (a ^ b));
}
inline size_t
size(std::ostream &s)
{
const auto cur(s.tellp());
s.seekp(0, std::ios::end);
const auto ret(s.tellp());
s.seekp(cur, std::ios::beg);
return ret;
}
} // namespace util
} // namespace ircd
#endif // __cplusplus

View file

@ -77,7 +77,7 @@ extern "C" {
#include <RB_INC_SSTREAM
#include <RB_INC_FSTREAM
#include <RB_INC_IOSTREAM
//#include <RB_INC_IOMANIP
#include <RB_INC_IOMANIP
#include <RB_INC_CSTDIO
//#include <RB_INC_CHRONO
#include <RB_INC_CTIME

View file

@ -649,7 +649,7 @@ charybdis_main(int argc, char * const argv[])
load_all_modules(1);
load_core_modules(1);
init_isupport();
supported::init();
init_bandb();
init_ssld();

View file

@ -1315,7 +1315,7 @@ user_welcome(client::client *source_p)
sendto_one_numeric(source_p, RPL_CREATED, form_str(RPL_CREATED), info::compiled.c_str());
sendto_one_numeric(source_p, RPL_MYINFO, form_str(RPL_MYINFO), me.name, info::version.c_str(), umodebuf, chan::mode::arity[0], chan::mode::arity[1]);
show_isupport(source_p);
supported::show(*source_p);
show_lusers(source_p);

View file

@ -3,6 +3,8 @@
* supported.c: isupport (005) numeric
*
* Copyright (C) 2006 Jilles Tjoelker
* Copyright (C) 2016 Charybdis Development Team
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -70,265 +72,234 @@
* All unknown/unlisted modes are treated as type D.
*/
namespace ircd {
using namespace ircd;
rb_dlink_list isupportlist;
struct isupportitem
{
const char *name;
const char *(*func)(const void *);
const void *param;
rb_dlink_node node;
};
std::map<std::string, supported::value> supported::map;
void
add_isupport(const char *name, const char *(*func)(const void *), const void *param)
supported::init()
{
struct isupportitem *item;
// These should all eventually get filed away into their own
// subsystem's namespace
item = (isupportitem *)rb_malloc(sizeof(struct isupportitem));
item->name = name;
item->func = func;
item->param = param;
rb_dlinkAddTail(item, &item->node, &isupportlist);
}
const void *
change_isupport(const char *name, const char *(*func)(const void *), const void *param)
add("CHANTYPES", [](ostream &s)
{
rb_dlink_node *ptr;
struct isupportitem *item;
const void *oldvalue = NULL;
s << ConfigChannel.disable_local_channels? "#" : "&#";
});
RB_DLINK_FOREACH(ptr, isupportlist.head)
add("EXCEPTS", []
{
item = (isupportitem *)ptr->data;
return ConfigChannel.use_except;
});
if (!strcmp(item->name, name))
add("INVEX", []
{
oldvalue = item->param;
return ConfigChannel.use_invex;
});
// item->name = name;
item->func = func;
item->param = param;
break;
}
}
return oldvalue;
}
void
delete_isupport(const char *name)
{
rb_dlink_node *ptr, *next_ptr;
struct isupportitem *item;
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, isupportlist.head)
{
item = (isupportitem *)ptr->data;
if (!strcmp(item->name, name))
{
rb_dlinkDelete(ptr, &isupportlist);
rb_free(item);
}
}
}
/* XXX caching? */
void
show_isupport(client::client *client_p)
{
rb_dlink_node *ptr;
struct isupportitem *item;
const char *value;
char buf[512];
int extra_space;
unsigned int nchars, nparams;
int l;
extra_space = strlen(client_p->name);
/* UID */
if (!my(*client_p) && extra_space < 9)
extra_space = 9;
/* :<me.name> 005 <nick> <params> :are supported by this server */
/* form_str(RPL_ISUPPORT) is %s :are supported by this server */
extra_space += strlen(me.name) + 1 + strlen(form_str(RPL_ISUPPORT));
nchars = extra_space, nparams = 0, buf[0] = '\0';
RB_DLINK_FOREACH(ptr, isupportlist.head)
{
item = (isupportitem *)ptr->data;
value = (*item->func)(item->param);
if (value == NULL)
continue;
l = strlen(item->name) + (EmptyString(value) ? 0 : 1 + strlen(value));
if (nchars + l + (nparams > 0) >= sizeof buf || nparams + 1 > 12)
{
sendto_one_numeric(client_p, RPL_ISUPPORT, form_str(RPL_ISUPPORT), buf);
nchars = extra_space, nparams = 0, buf[0] = '\0';
}
if (nparams > 0)
rb_strlcat(buf, " ", sizeof buf), nchars++;
rb_strlcat(buf, item->name, sizeof buf);
if (!EmptyString(value))
{
rb_strlcat(buf, "=", sizeof buf);
rb_strlcat(buf, value, sizeof buf);
}
nchars += l;
nparams++;
}
if (nparams > 0)
sendto_one_numeric(client_p, RPL_ISUPPORT, form_str(RPL_ISUPPORT), buf);
}
const char *
isupport_intptr(const void *ptr)
{
static char buf[15];
snprintf(buf, sizeof buf, "%d", *(const int *)ptr);
return buf;
}
const char *
isupport_boolean(const void *ptr)
{
return *(const int *)ptr ? "" : NULL;
}
const char *
isupport_string(const void *ptr)
{
return (const char *)ptr;
}
const char *
isupport_stringptr(const void *ptr)
{
return *(char * const *)ptr;
}
static const char *
isupport_umode(const void *ptr)
{
const char *str;
str = (const char *)ptr;
return ConfigFileEntry.oper_only_umodes &
user_modes[(unsigned char)*str] ? NULL : str;
}
static const char *
isupport_chanmodes(const void *ptr)
add("CHANMODES", [](ostream &s)
{
using namespace chan::mode;
static char result[80];
s << categories[uint(category::A)] << ',';
s << categories[uint(category::B)] << ',';
s << categories[uint(category::C)] << ',';
s << categories[uint(category::D)];
});
snprintf(result, sizeof result, "%s,%s,%s,%s",
categories[uint(category::A)],
categories[uint(category::B)],
categories[uint(category::C)],
categories[uint(category::D)]);
return result;
}
static const char *
isupport_chantypes(const void *ptr)
add("CHANLIMIT", [](ostream &s)
{
return ConfigChannel.disable_local_channels ? "#" : "&#";
}
char result[30];
snprintf(result, sizeof(result), "%s:%i",
ConfigChannel.disable_local_channels? "#" : "&#",
ConfigChannel.max_chans_per_user);
static const char *
isupport_chanlimit(const void *ptr)
s << result;
});
add("PREFIX", "(ov)@+");
add("MAXLIST", [](ostream &s)
{
static char result[30];
snprintf(result, sizeof result, "%s:%i",
ConfigChannel.disable_local_channels ? "#" : "&#", ConfigChannel.max_chans_per_user);
return result;
}
static const char *
isupport_maxlist(const void *ptr)
{
static char result[30];
char result[30];
snprintf(result, sizeof result, "bq%s%s:%i",
ConfigChannel.use_except ? "e" : "",
ConfigChannel.use_invex ? "I" : "",
ConfigChannel.max_bans);
return result;
}
static const char *
isupport_targmax(const void *ptr)
s << result;
});
add("MODES", chan::mode::MAXPARAMS);
add("NETWORK", [](ostream &s)
{
static char result[200];
s << ServerInfo.network_name;
});
add("STATUSMSG", "@+");
add("CALLERID", [](ostream &s)
{
if(ConfigFileEntry.oper_only_umodes & user_modes['g'])
return;
s << 'g';
});
add("CASEMAPPING", "rfc1459");
add("NICKLEN", [](ostream &s)
{
char result[200];
snprintf(result, sizeof(result), "%u", ConfigFileEntry.nicklen - 1);
s << result;
});
add("MAXNICKLEN", NICKLEN - 1);
add("CHANNELLEN", LOC_CHANNELLEN);
add("TOPICLEN", TOPICLEN);
add("DEAF", [](ostream &s)
{
if(ConfigFileEntry.oper_only_umodes & user_modes['D'])
return;
s << 'D';
});
add("TARGMAX", [](ostream &s)
{
char result[200];
snprintf(result, sizeof result, "NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:%d,NOTICE:%d,ACCEPT:,MONITOR:",
ConfigFileEntry.max_targets,
ConfigFileEntry.max_targets);
return result;
s << result;
});
add("EXTBAN", [](ostream &s)
{
const char *const p(chan::get_extban_string());
if(!EmptyString(p))
s << "$," << p;
});
add("CLIENTVER", "3.0");
}
static const char *
isupport_extban(const void *ptr)
bool
supported::del(const std::string &key)
{
const char *p;
static char result[200];
p = chan::get_extban_string();
if (EmptyString(p))
return NULL;
snprintf(result, sizeof result, "$,%s", p);
return result;
}
static const char *
isupport_nicklen(const void *ptr)
{
static char result[200];
snprintf(result, sizeof result, "%u", ConfigFileEntry.nicklen - 1);
return result;
return map.erase(key);
}
void
init_isupport(void)
supported::show(client &client)
{
static int maxmodes = chan::mode::MAXPARAMS;
static int channellen = LOC_CHANNELLEN;
static int topiclen = TOPICLEN;
static int maxnicklen = NICKLEN - 1;
uint leading(strlen(client.name));
add_isupport("CHANTYPES", isupport_chantypes, NULL);
add_isupport("EXCEPTS", isupport_boolean, &ConfigChannel.use_except);
add_isupport("INVEX", isupport_boolean, &ConfigChannel.use_invex);
add_isupport("CHANMODES", isupport_chanmodes, NULL);
add_isupport("CHANLIMIT", isupport_chanlimit, NULL);
add_isupport("PREFIX", isupport_string, "(ov)@+");
add_isupport("MAXLIST", isupport_maxlist, NULL);
add_isupport("MODES", isupport_intptr, &maxmodes);
add_isupport("NETWORK", isupport_stringptr, &ServerInfo.network_name);
add_isupport("STATUSMSG", isupport_string, "@+");
add_isupport("CALLERID", isupport_umode, "g");
add_isupport("CASEMAPPING", isupport_string, "rfc1459");
add_isupport("NICKLEN", isupport_nicklen, NULL);
add_isupport("MAXNICKLEN", isupport_intptr, &maxnicklen);
add_isupport("CHANNELLEN", isupport_intptr, &channellen);
add_isupport("TOPICLEN", isupport_intptr, &topiclen);
add_isupport("DEAF", isupport_umode, "D");
add_isupport("TARGMAX", isupport_targmax, NULL);
add_isupport("EXTBAN", isupport_extban, NULL);
add_isupport("CLIENTVER", isupport_string, "3.0");
// UID
if(!my(client) && leading < 9)
leading = 9;
/* :<me.name> 005 <nick> <params> :are supported by this server */
/* form_str(RPL_ISUPPORT) is %s :are supported by this server */
leading += strlen(me.name) + 1 + strlen(form_str(RPL_ISUPPORT));
//TODO: XXX: It's almost time for the ircstream
uint nparams(3);
std::ostringstream buf;
for(const auto &pit : map)
{
const auto &key(pit.first);
const auto &val(pit.second);
const auto len(size(buf));
val(key, buf);
buf << ' ';
++nparams;
if(size(buf) + leading >= 510 || nparams > 14)
{
buf.seekp(len, std::ios::beg);
sendto_one_numeric(&client, RPL_ISUPPORT, form_str(RPL_ISUPPORT), buf.str().c_str());
buf.str(std::string{});
nparams = 3;
}
else continue;
val(key, buf);
buf << ' ';
++nparams;
}
if(nparams > 3)
sendto_one_numeric(&client, RPL_ISUPPORT, form_str(RPL_ISUPPORT), buf.str().c_str());
}
ostream &
supported::value::operator()(const std::string &key, ostream &s)
const
{
using type = supported::type;
switch(this->type)
{
case type::FUNC_STREAM:
s << key << '=';
func_stream(s);
break;
case type::FUNC_BOOLEAN:
if(func_boolean())
s << key;
break;
case type::STRING:
s << key << '=' << string;
break;
case type::INTEGER:
s << key << '=' << integer;
break;
case type::BOOLEAN:
s << key;
break;
};
return s;
}
supported::value::value(const std::function<void (ostream &)> &val)
:type{supported::type::FUNC_STREAM}
,func_stream{val}
{
}
supported::value::value(const std::function<bool ()> &val)
:type{supported::type::FUNC_BOOLEAN}
,func_boolean{val}
{
}
supported::value::value(const std::string &val)
:type{supported::type::STRING}
,string{val}
{
}
supported::value::value(const int64_t &val)
:type{supported::type::INTEGER}
,integer{val}
{
}
supported::value::value()
:type{supported::type::BOOLEAN}
{
}
supported::value::~value()
noexcept
{
}

View file

@ -56,15 +56,14 @@ struct Message masktrace_msgtab = {
static int
_modinit(void)
{
add_isupport("ETRACE", isupport_string, "");
supported::add("ETRACE");
return 0;
}
static void
_moddeinit(void)
{
delete_isupport("ETRACE");
supported::del("ETRACE");
}
mapi_clist_av1 etrace_clist[] = { &etrace_msgtab, &chantrace_msgtab, &masktrace_msgtab, NULL };

View file

@ -35,14 +35,18 @@ struct Message knock_msgtab = {
static int
_modinit(void)
{
add_isupport("KNOCK", isupport_boolean, &ConfigChannel.use_knock);
supported::add("KNOCK", []
{
return ConfigChannel.use_knock;
});
return 0;
}
static void
_moddeinit(void)
{
delete_isupport("KNOCK");
supported::del("KNOCK");
}
mapi_clist_av1 knock_clist[] = { &knock_msgtab, NULL };

View file

@ -81,8 +81,8 @@ static int _modinit(void)
* C = creation time search (C> C<)
* T = topic search (T> T<)
*/
add_isupport("SAFELIST", isupport_string, "");
add_isupport("ELIST", isupport_string, "CTU");
supported::add("SAFELIST");
supported::add("ELIST", "CTU");
return 0;
}
@ -91,8 +91,8 @@ static void _moddeinit(void)
{
rb_event_delete(iterate_clients_ev);
delete_isupport("SAFELIST");
delete_isupport("ELIST");
supported::del("SAFELIST");
supported::del("ELIST");
}
static void safelist_check_cliexit(hook_data_client_exit * hdata)

View file

@ -47,13 +47,17 @@ DECLARE_MODULE_AV2(monitor, monitor_init, monitor_deinit, monitor_clist, NULL, N
static int monitor_init(void)
{
add_isupport("MONITOR", isupport_intptr, &ConfigFileEntry.max_monitor);
supported::add("MONITOR", [](ostream &s)
{
s << ConfigFileEntry.max_monitor;
});
return 0;
}
static void monitor_deinit(void)
{
delete_isupport("MONITOR");
supported::del("MONITOR");
}
static void

View file

@ -84,14 +84,14 @@ static int
_modinit(void)
{
mark_services();
add_isupport("FNC", isupport_string, "");
supported::add("FNC");
return 0;
}
static void
_moddeinit(void)
{
delete_isupport("FNC");
supported::del("FNC");
unmark_services();
}

View file

@ -74,7 +74,7 @@ m_version(struct MsgBuf *msgbuf_p, client::client &client, client::client &sourc
me.name, confopts(), TS_CURRENT,
ServerInfo.sid);
show_isupport(&source);
supported::show(source);
}
/*
@ -93,7 +93,8 @@ mo_version(struct MsgBuf *msgbuf_p, client::client &client, client::client &sour
#endif
me.name, confopts(), TS_CURRENT,
ServerInfo.sid);
show_isupport(&source);
supported::show(source);
}
}

View file

@ -65,14 +65,14 @@ struct Message who_msgtab = {
static int
_modinit(void)
{
add_isupport("WHOX", isupport_string, "");
supported::add("WHOX");
return 0;
}
static void
_moddeinit(void)
{
delete_isupport("WHOX");
supported::del("WHOX");
}
mapi_clist_av1 who_clist[] = { &who_msgtab, NULL };