/*
 * SPDX-License-Identifier: ISC
 * SPDX-URL: https://spdx.org/licenses/ISC.html
 *
 * Copyright (C) 2005 William Pitcock, et al.
 *
 * Protocol handlers, both generic and the actual declarations themselves.
 */

#ifndef ATHEME_INC_PHANDLER_H
#define ATHEME_INC_PHANDLER_H 1

#include <atheme/attributes.h>
#include <atheme/stdheaders.h>
#include <atheme/structures.h>

struct ircd
{
	const char *    ircdname;
	const char *    tldprefix;
	bool            uses_uid;
	bool            uses_rcommand;
	bool            uses_owner;
	bool            uses_protect;
	bool            uses_halfops;
	bool            uses_p10;       // Parser hackhack
	bool            uses_vhost;     // Do we use vHosts?
	unsigned int    oper_only_modes;
	unsigned int    owner_mode;
	unsigned int    protect_mode;
	unsigned int    halfops_mode;
	const char *    owner_mchar;
	const char *    protect_mchar;
	const char *    halfops_mchar;
	unsigned int    type;
	unsigned int    perm_mode;      // Modes to not disappear when empty
	unsigned int    oimmune_mode;   // Mode to disallow kicking ircops
	const char *    ban_like_modes; // e.g. "beI"
	char            except_mchar;
	char            invex_mchar;
	int             flags;
};

/* values for type */
/*  -- what the HELL are these used for? A grep reveals nothing.. --w00t
 *  -- they are used to provide a hint to third-party module coders about what
 *     ircd they are working with. --nenolod
 */
#define PROTOCOL_ASUKA			1
#define PROTOCOL_BAHAMUT		2
#define PROTOCOL_CHARYBDIS		3
#define PROTOCOL_DREAMFORGE		4
#define PROTOCOL_HYPERION		5 /* obsolete */
#define PROTOCOL_INSPIRCD		6
#define PROTOCOL_IRCNET			7
#define PROTOCOL_MONKEY			8 /* obsolete */
#define PROTOCOL_PLEXUS			9
#define PROTOCOL_PTLINK			10
#define PROTOCOL_RATBOX			11
#define PROTOCOL_SCYLLA			12
#define PROTOCOL_ELEMENTAL_IRCD		13
#define PROTOCOL_SORCERY		14 /* obsolete */
#define PROTOCOL_ULTIMATE3		15
#define PROTOCOL_UNREAL			17
#define PROTOCOL_SOLIDIRCD		18
#define PROTOCOL_NEFARIOUS		19
#define PROTOCOL_OFFICEIRC		20
#define PROTOCOL_SPORKSIRCD		21
#define PROTOCOL_NGIRCD			22

#define PROTOCOL_OTHER			255

/* values for flags */
#define IRCD_CIDR_BANS			1
#define IRCD_HOLDNICK			2 /* supports holdnick_sts() */
#define IRCD_TOPIC_NOCOLOUR		4
#define IRCD_SASL_USE_PUID		8

/* forced nick change types */
#define FNC_REGAIN 0 /* give a registered user their nick back */
#define FNC_FORCE  1 /* force a user off their nick (kill if unsupported) */

/* server login, usually sends PASS, CAPAB, SERVER and SVINFO
 * you can still change ircd->uses_uid at this point
 * set me.bursting = true
 * return 1 if sts() failed (by returning 1), otherwise 0 */
extern unsigned int (*server_login)(void);
/* introduce a client on the services server */
extern void (*introduce_nick)(struct user *u);
/* send an invite for a given user to a channel
 * the source may not be on the channel */
extern void (*invite_sts)(struct user *source, struct user *target, struct channel *channel);
/* quit a client on the services server with the given message */
extern void (*quit_sts)(struct user *u, const char *reason);
/* send wallops
 * use something that only opers can see if easily possible */
extern void (*wallops_sts)(const char *text);
/* join a channel with a client on the services server
 * the client should be introduced opped
 * isnew indicates the channel modes (and bans XXX) should be bursted
 * note that the channelts can still be old in this case (e.g. kills)
 * modes is a convenience argument giving the simple modes with parameters
 * do not rely upon chanuser_find(c,u) */
extern void (*join_sts)(struct channel *c, struct user *u, bool isnew, char *modes);
/* lower the TS of a channel, joining it with the given client on the
 * services server (opped), replacing the current simple modes with the
 * ones stored in the struct channel and clearing all other statuses
 * if bans are timestamped on this ircd, call chanban_clear()
 * if the topic is timestamped on this ircd, clear it */
extern void (*chan_lowerts)(struct channel *c, struct user *u);
/* kick a user from a channel
 * source is a client on the services server which may or may not be
 * on the channel */
extern void (*kick)(struct user *source, struct channel *c, struct user *u, const char *reason);
/* send a privmsg
 * here it's ok to assume the source is able to send */
extern void (*msg)(const char *from, const char *target, const char *fmt, ...) ATHEME_FATTR_PRINTF(3, 4);
/* send a global privmsg to all users on servers matching the mask
 * from is a client on the services server
 * mask is either "*" or it has a non-wildcard TLD */
extern void (*msg_global_sts)(struct user *from, const char *mask, const char *text);
/* send a notice to a user
 * from can be a client on the services server or the services server
 * itself (NULL) */
extern void (*notice_user_sts)(struct user *from, struct user *target, const char *text);
/* send a global notice to all users on servers matching the mask
 * from is a client on the services server
 * mask is either "*" or it has a non-wildcard TLD */
extern void (*notice_global_sts)(struct user *from, const char *mask, const char *text);
/* send a notice to a channel
 * from can be a client on the services server or the services server
 * itself (NULL)
 * if the source cannot send because it is not on the channel, send the
 * notice from the server or join for a moment */
extern void (*notice_channel_sts)(struct user *from, struct channel *target, const char *text);
/* send a notice to ops in a channel
 * source may or may not be on channel
 * generic_wallchops() sends an individual notice to each channel operator */
extern void (*wallchops)(struct user *source, struct channel *target, const char *message);
/* send a numeric from must currently be me.me */
extern void (*numeric_sts)(struct server *from, int numeric, struct user *target, const char *fmt, ...) ATHEME_FATTR_PRINTF(4, 5);
/* kill a user
 * killer can be a client on the services server or NULL for the
 * services server itself
 * unlike other functions, the target is specified by a UID or nick;
 * do not call user_find(), user_find_named() or similar on it */
extern void (*kill_id_sts)(struct user *killer, const char *id, const char *reason);
/* part a channel with a client on the services server */
extern void (*part_sts)(struct channel *c, struct user *u);
/* add a kline on the servers matching the given mask
 * duration is in seconds, 0 for a permanent kline
 * if the ircd requires klines to be sent from users, use opersvs */
extern void (*kline_sts)(const char *server, const char *user, const char *host, long duration, const char *reason);
/* remove a kline on the servers matching the given mask
 * if the ircd requires unklines to be sent from users, use opersvs */
extern void (*unkline_sts)(const char *server, const char *user, const char *host);
/* add a xline on the servers matching the given mask
 * duration is in seconds, 0 for a permanent xline
 * if the ircd requires xlines to be sent from users, use opersvs */
extern void (*xline_sts)(const char *server, const char *realname, long duration, const char *reason);
/* remove a xline on the servers matching the given mask
 * if the ircd requires unxlines to be sent from users, use opersvs */
extern void (*unxline_sts)(const char *server, const char *realname);
/* add a qline on the servers matching the given mask
 * duration is in seconds, 0 for a permanent qline
 * if the ircd requires qlines to be sent from users, use opersvs */
extern void (*qline_sts)(const char *server, const char *mask, long duration, const char *reason);
/* remove a qline on the servers matching the given mask
 * if the ircd requires unqlines to be sent from users, use opersvs */
extern void (*unqline_sts)(const char *server, const char *mask);
/* add a dline (sometimes called zline) on the servers matching mask
 * if the ircd requires dlines to be sent from users, use opersvs */
extern void (*dline_sts)(const char *server, const char *host, long duration, const char *reason);
/* remove a dline (sometimes called zline) on the servers matching the given mask
 * if the ircd requires undlines to be sent from users, use opersvs */
extern void (*undline_sts)(const char *server, const char *host);
/* make the given service set a topic on a channel
 * setter and ts should be used if the ircd supports topics to be set
 * with a given topicsetter and topicts; ts is not a channelts
 * prevts is the topicts of the old topic or 0 if there was no topic,
 * useful in optimizing which form of topic change to use
 * if the given topicts was not set and topicts is used on the ircd,
 * set c->topicts to the value used */
extern void (*topic_sts)(struct channel *c, struct user *source, const char *setter, time_t ts, time_t prevts, const char *topic);
/* set modes on a channel by the given sender; sender must be a client
 * on the services server; sender may or may not be on channel */
extern void (*mode_sts)(char *sender, struct channel *target, char *modes);
/* ping the uplink
 * first check if me.connected is true and bail if not */
extern void (*ping_sts)(void);
/* mark user 'u' as logged in as 'account'
 * wantedhost is currently not used
 * first check if me.connected is true and bail if not */
extern void (*ircd_on_login)(struct user *u, struct myuser *account, const char *wantedhost);
/* mark user 'u' as logged out
 * first check if me.connected is true and bail if not
 * return false if successful or logins are not supported
 * return true if the user was killed to force logout (P10) */
extern bool (*ircd_on_logout)(struct user *u, const char *account);
/* introduce a fake server
 * it is ok to use opersvs to squit the old server
 * if SQUIT uses kill semantics (e.g. charybdis), server_delete() the server
 * and continue
 * if SQUIT uses unconnect semantics (e.g. bahamut), set SF_JUPE_PENDING on
 * the server and return; you will be called again when the server is really
 * deleted */
extern void (*jupe)(const char *server, const char *reason);
/* set a dynamic spoof on a user
 * if the ircd does not notify the user of this, do
 * notice(source->nick, target->nick, "Setting your host to \2%s\2.", host); */
extern void (*sethost_sts)(struct user *source, struct user *target, const char *host);
/* force a nickchange for a user
 * possible values for type:
 * FNC_REGAIN: give a registered user their nick back
 * FNC_FORCE:  force a user off their nick (kill if unsupported)
 */
extern void (*fnc_sts)(struct user *source, struct user *u, const char *newnick, int type);
/* temporarily make a nick unavailable to users
 * source is the responsible service
 * duration is in seconds, 0 to remove the effect of a previous call
 * account is an account that may still use the nick, or NULL */
extern void (*holdnick_sts)(struct user *source, int duration, const char *nick, struct myuser *account);
/* change nick, user, host and/or services login name for a user
 * target may also be a not yet fully introduced UID (for SASL) */
extern void (*svslogin_sts)(const char *target, const char *nick, const char *user, const char *host, struct myuser *account);
/* send sasl message */
extern void (*sasl_sts) (const char *target, char mode, const char *data);
/* send sasl mech list */
extern void (*sasl_mechlist_sts)(const char *mechlist);
/* check whether a mask matches a user */
extern bool (*mask_matches_user)(const char *mask, struct user *u);
/* find next channel ban (or other ban-like mode) matching user */
extern mowgli_node_t *(*next_matching_ban)(struct channel *c, struct user *u, int type, mowgli_node_t *first);
/* find next host channel access matching user */
extern mowgli_node_t *(*next_matching_host_chanacs)(struct mychan *mc, struct user *u, mowgli_node_t *first);
/* check a nickname for validity; normally you don't need to override this */
extern bool (*is_valid_nick)(const char *nick);
/* check a username for validity; normally you don't need to override this */
extern bool (*is_valid_username)(const char *username);
/* check a vhost for validity; the core will already have checked for
 * @!?*, space, empty, : at start, length and cidr masks */
extern bool (*is_valid_host)(const char *host);
/* burst a channel mlock. */
extern void (*mlock_sts)(struct channel *c);
/* burst a channel topiclock */
extern void (*topiclock_sts)(struct channel *c);
/* attempt to quarantine a user.
 * in Unreal-esque terms, this means SHUN.
 * in Hybrid, this means CAPTURE.
 * pretty much the same thing either way.
 */
extern void (*quarantine_sts)(struct user *source, struct user *victim, long duration, const char *reason);
/* Ask the proto module if this is valid as an extban */
extern bool (*is_extban)(const char *mask);
/* previously located in libathemecore/function.c; used for various
 * things that need to know whether a given user has ircd privs */
extern bool (*is_ircop)(struct user *u);
/* as above; not used for much */
extern bool (*is_admin)(struct user *u);
/* as above; used to respect external services clients */
extern bool (*is_service)(struct user *u);

unsigned int generic_server_login(void);
void generic_introduce_nick(struct user *u);
void generic_invite_sts(struct user *source, struct user *target, struct channel *channel);
void generic_quit_sts(struct user *u, const char *reason);
void generic_wallops_sts(const char *text);
void generic_join_sts(struct channel *c, struct user *u, bool isnew, char *modes);
void generic_chan_lowerts(struct channel *c, struct user *u);
void generic_kick(struct user *source, struct channel *c, struct user *u, const char *reason);
void generic_msg(const char *from, const char *target, const char *fmt, ...) ATHEME_FATTR_PRINTF(3, 4);
void generic_msg_global_sts(struct user *from, const char *mask, const char *text);
void generic_notice_user_sts(struct user *from, struct user *target, const char *text);
void generic_notice_global_sts(struct user *from, const char *mask, const char *text);
void generic_notice_channel_sts(struct user *from, struct channel *target, const char *text);
void generic_wallchops(struct user *source, struct channel *target, const char *message);
void generic_numeric_sts(struct server *from, int numeric, struct user *target, const char *fmt, ...) ATHEME_FATTR_PRINTF(4, 5);
void generic_kill_id_sts(struct user *killer, const char *id, const char *reason);
void generic_part_sts(struct channel *c, struct user *u);
void generic_kline_sts(const char *server, const char *user, const char *host, long duration, const char *reason);
void generic_unkline_sts(const char *server, const char *user, const char *host);
void generic_xline_sts(const char *server, const char *realname, long duration, const char *reason);
void generic_unxline_sts(const char *server, const char *realname);
void generic_qline_sts(const char *server, const char *mask, long duration, const char *reason);
void generic_unqline_sts(const char *server, const char *mask);
void generic_topic_sts(struct channel *c, struct user *source, const char *setter, time_t ts, time_t prevts, const char *topic);
void generic_mode_sts(char *sender, struct channel *target, char *modes);
void generic_ping_sts(void);
void generic_on_login(struct user *u, struct myuser *account, const char *wantedhost);
bool generic_on_logout(struct user *u, const char *account);
void generic_jupe(const char *server, const char *reason);
void generic_sethost_sts(struct user *source, struct user *target, const char *host);
void generic_fnc_sts(struct user *source, struct user *u, const char *newnick, int type);
void generic_holdnick_sts(struct user *source, int duration, const char *nick, struct myuser *account);
void generic_svslogin_sts(const char *target, const char *nick, const char *user, const char *host, struct myuser *account);
void generic_sasl_sts(const char *target, char mode, const char *data);
void generic_sasl_mechlist_sts(const char *mechlist);
bool generic_mask_matches_user(const char *mask, struct user *u);
mowgli_node_t *generic_next_matching_ban(struct channel *c, struct user *u, int type, mowgli_node_t *first);
mowgli_node_t *generic_next_matching_host_chanacs(struct mychan *mc, struct user *u, mowgli_node_t *first);
bool generic_is_valid_host(const char *host);
bool generic_is_valid_nick(const char *nick);
bool generic_is_valid_username(const char *username);
void generic_mlock_sts(struct channel *c);
void generic_topiclock_sts(struct channel *c);
void generic_quarantine_sts(struct user *source, struct user *victim, long duration, const char *reason);
bool generic_is_extban(const char *mask);
void generic_dline_sts(const char *server, const char *host, long duration, const char *reason);
void generic_undline_sts(const char *server, const char *host);
bool generic_is_ircop(struct user *u);
bool generic_is_admin(struct user *u);
bool generic_is_service(struct user *u);

extern const struct cmode *mode_list;
extern struct extmode *ignore_mode_list;
extern size_t ignore_mode_list_size;
extern const struct cmode *status_mode_list;
extern const struct cmode *prefix_mode_list;
extern const struct cmode *user_mode_list;

extern struct ircd *ircd;

#endif /* !ATHEME_INC_PHANDLER_H */
