// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2019 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. namespace ircd::m::users { static bool for_each_host(const opts &, const user::closure_bool &); static bool for_each_in_host(const opts &, const user::closure_bool &); } decltype(ircd::m::users::opts_default) ircd::m::users::opts_default; bool ircd::m::users::exists(const opts &opts) { return !for_each(opts, [] (const auto &) noexcept { // return false to break and have for_each() returns false return false; }); } size_t ircd::m::users::count(const opts &opts) { size_t ret(0); for_each(opts, [&ret] (const auto &) noexcept { ++ret; return true; }); return ret; } bool ircd::m::users::for_each(const user::closure_bool &closure) { return for_each(opts_default, closure); } bool ircd::m::users::for_each(const opts &opts, const user::closure_bool &closure) { // Branch to a better query for hosts when there's no localpart given. if(opts.hostpart && (!opts.localpart || opts.localpart == "@")) return for_each_host(opts, closure); bool ret{true}; events::sender::for_each(opts.localpart, [&opts, &ret, &closure] (const id::user &sender) { if(opts.localpart && !opts.localpart_prefix) if(sender.local() != opts.localpart) return false; if(opts.localpart && opts.localpart_prefix) if(!startswith(sender.local(), opts.localpart)) return false; if(opts.hostpart && !opts.hostpart_prefix) if(sender.host() != opts.hostpart) return true; if(opts.hostpart && opts.hostpart_prefix) if(!startswith(sender.host(), opts.hostpart)) return true; // Call the user with match.a ret = closure(sender); return ret; }); return ret; } bool ircd::m::users::for_each_host(const opts &opts, const user::closure_bool &closure) { bool ret{true}; events::origin::for_each(opts.hostpart, [&ret, &opts, &closure] (const string_view &origin) { if(opts.hostpart && !opts.hostpart_prefix) if(origin != opts.hostpart) return false; if(opts.hostpart && opts.hostpart_prefix) if(!startswith(origin, opts.hostpart)) return false; auto _opts(opts); _opts.hostpart = origin; _opts.hostpart_prefix = false; ret = for_each_in_host(_opts, closure); return ret; }); return ret; } bool ircd::m::users::for_each_in_host(const opts &opts, const user::closure_bool &closure) { bool ret{true}; m::user::id::buf last; events::origin::for_each_in(opts.hostpart, [&opts, &ret, &closure, &last] (const id::user &sender, const auto &event_idx) { if(sender == last) return true; if(opts.hostpart && !opts.hostpart_prefix) if(sender.host() != opts.hostpart) return false; if(opts.hostpart && opts.hostpart_prefix) if(!startswith(sender.host(), opts.hostpart)) return false; if(opts.localpart && opts.localpart_prefix) if(!startswith(sender.local(), opts.localpart)) return true; if(opts.localpart && !opts.localpart_prefix) if(sender.local() != opts.localpart) return true; // Call the user with match. ret = closure(sender); last = sender; return ret; }); return ret; } ircd::m::users::opts::opts(const string_view &query) { if(startswith(query, '@') && has(query, ':')) { localpart = split(query, ':').first; hostpart = split(query, ':').second; hostpart_prefix = !has(hostpart, '.'); return; } if(startswith(query, '@')) { localpart = query; localpart_prefix = true; return; } if(startswith(query, ':')) { hostpart = lstrip(query, ':'); hostpart_prefix = !has(hostpart, '.'); return; } localpart = query; localpart_prefix = true; }