Skip to content

Commit

Permalink
Add CHGHOST bind
Browse files Browse the repository at this point in the history
Found by: thommey
Patch by: Geo
Fixes: #1371

Summary of feature:

    Adds CHGHOST bind to respond to CHGHOST message
    Updates internal user records with new hosts after CHGHOST
    Adds hidden-host type to EVNT bind (for a 396)
    Updates internal tracking of own host after a 396
  • Loading branch information
vanosg committed Apr 11, 2023
1 parent 6d705dc commit 540f3bc
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 55 deletions.
8 changes: 8 additions & 0 deletions doc/sphinx_source/using/tcl-commands.rst
Expand Up @@ -3432,6 +3432,7 @@ The following is a list of bind types and how they work. Below each bind type is
init-server - called when we actually get on our IRC server
disconnect-server - called when we disconnect from our IRC server
fail-server - called when an IRC server fails to respond
hidden-host - called after the bot's host is hidden by the server

Note that Tcl scripts can trigger arbitrary events, including ones that are not pre-defined or used by Eggdrop.

Expand Down Expand Up @@ -3563,6 +3564,13 @@ The following is a list of bind types and how they work. Below each bind type is

Module: irc

(56) CHGHOST

bind chghost <flags> <mask> <proc>

procname <nick> <old user@host> <handle> <channel> <new user@host>

Description: triggered when a server sends an IRCv3 spec CHGHOST message to change a user's hostmask. The new host is matched against mask in the form of "#channel nick!user\@host" and can contain wildcards. The specified proc will be called with the nick of the user whose hostmask changed; the hostmask the affected user had before the change, the handle of the affected user (or * if no handle is present), the channel the user was on when the bind triggered, and the new hostmask of the affected user. This bind will trigger once for each channel the user is on.

^^^^^^^^^^^^^
Return Values
Expand Down
58 changes: 58 additions & 0 deletions src/mod/irc.mod/chan.c
Expand Up @@ -1335,6 +1335,62 @@ static int got354(char *from, char *msg)
return 0;
}

/* React to IRCv3 CHGHOST command. CHGHOST changes the hostname and/or
* ident of the user. Format:
* :geo!awesome@eggdrop.com CHGHOST tehgeo foo.io
* changes user hostmask to tehgeo@foo.io
*/
static int gotchghost(char *from, char *msg){
struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
struct userrec *u;
struct chanset_t *chan;
memberlist *m;
char mask[1024], *nick, *ident, buf[MSGMAX], *s1=buf, *chname;

strlcpy(s1, from, sizeof buf);
nick = splitnick(&s1);
ident = newsplit(&msg); /* Get the ident */
/* Update my own internal hostmask */
if (match_my_nick(nick)) {
snprintf(botuserhost, UHOSTMAX, "%s@%s", ident, msg);
}
u = get_user_by_host(from);
/* Run the bind for each channel the user is on */
for (chan = chanset; chan; chan = chan->next) {
chname = chan->dname;
m = ismember(chan, nick);
if (m) {
snprintf(m->userhost, sizeof m->userhost, "%s@%s", ident, msg);
snprintf(mask, sizeof mask, "%s %s!%s@%s", chname, nick, ident, msg);
check_tcl_chghost(nick, from, mask, u, chname, ident, msg);
get_user_flagrec(m->user ? m->user : get_user_by_host(s1), &fr,
chan->dname);
check_this_member(chan, m->nick, &fr);
}
}
return 0;
}

/* React to 396 numeric (HOSTHIDDEN), sent when user mode +x (hostmasking) was
* successfully set. Format:
* :barjavel.freenode.net 396 BeerBot unaffiliated/geo/bot/beerbot :is now your hidden host (set by services.)
*/
static int got396(char *from, char *msg)
{
char *nick, *ident, *uhost, userbuf[UHOSTLEN];

nick = newsplit(&msg);
if (match_my_nick(nick)) { /* Double check this really is for me */
strlcpy(userbuf, botuserhost, sizeof userbuf);
ident = strtok(userbuf, "@");
uhost = newsplit(&msg);
if (ident) {
snprintf(botuserhost, UHOSTMAX, "%s@%s", ident, uhost);
check_tcl_event("hidden-host");
}
}
return 0;
}

/* got 315: end of who
* <server> 315 <to> <chan> :End of /who
Expand Down Expand Up @@ -3031,7 +3087,9 @@ static cmd_t irc_raw[] = {
{"347", "", (IntFunc) got347, "irc:347"},
{"348", "", (IntFunc) got348, "irc:348"},
{"349", "", (IntFunc) got349, "irc:349"},
{"396", "", (IntFunc) got396, "irc:396"},
{"ACCOUNT", "", (IntFunc) gotaccount, "irc:account"},
{"CHGHOST", "", (IntFunc) gotchghost, "irc:chghost"},
{NULL, NULL, NULL, NULL}
};

Expand Down
28 changes: 26 additions & 2 deletions src/mod/irc.mod/irc.c
Expand Up @@ -33,7 +33,7 @@

static p_tcl_bind_list H_topc, H_splt, H_sign, H_rejn, H_part, H_pub, H_pubm;
static p_tcl_bind_list H_nick, H_mode, H_kick, H_join, H_need, H_invt, H_ircaway;
static p_tcl_bind_list H_monitor, H_account;
static p_tcl_bind_list H_monitor, H_account, H_chghost;

static Function *global = NULL, *channels_funcs = NULL, *server_funcs = NULL;

Expand Down Expand Up @@ -776,6 +776,27 @@ static int invite_4char STDVAR
return TCL_OK;
}

static int check_tcl_chghost(char *nick, char *from, char *mask, struct userrec *u,
char *chan, char *ident, char * host)
{
struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 };
char usermask[UHOSTMAX];
int x;

get_user_flagrec(u, &fr, NULL);
snprintf(usermask, sizeof usermask, "%s!%s@%s", nick, ident, host);

Tcl_SetVar(interp, "_chghost1", nick, 0);
Tcl_SetVar(interp, "_chghost2", from, 0);
Tcl_SetVar(interp, "_chghost3", u ? u->handle : "*", 0);
Tcl_SetVar(interp, "_chghost4", chan, 0);
Tcl_SetVar(interp, "_chghost5", usermask, 0);
x = check_tcl_bind(H_chghost, mask, &fr,
" $_chghost1 $_chghost2 $_chghost3 $_chghost4 $_chghost5",
MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE);
return (x == BIND_EXEC_LOG);
}

static int check_tcl_ircaway(char *nick, char *from, char *mask,
struct userrec *u, char *chan, char *msg)
{
Expand Down Expand Up @@ -1340,6 +1361,7 @@ static char *irc_close()
del_bind_table(H_ircaway);
del_bind_table(H_monitor);
del_bind_table(H_account);
del_bind_table(H_chghost);
rem_tcl_strings(mystrings);
rem_tcl_ints(myints);
rem_builtins(H_dcc, irc_dcc);
Expand Down Expand Up @@ -1402,7 +1424,8 @@ static Function irc_table[] = {
(Function) & twitch, /* int */
/* 28 - 31 */
(Function) & H_ircaway, /* p_tcl_bind_list */
(Function) & H_monitor /* p_tcl_bind_list */
(Function) & H_monitor, /* p_tcl_bind_list */
(Function) & H_chghost /* p_tcl_bind_list */
};

char *irc_start(Function *global_funcs)
Expand Down Expand Up @@ -1472,6 +1495,7 @@ char *irc_start(Function *global_funcs)
H_ircaway = add_bind_table("ircaway", HT_STACKABLE, channels_5char);
H_monitor = add_bind_table("monitor", HT_STACKABLE, monitor_2char);
H_account = add_bind_table("account", HT_STACKABLE, channels_5char);
H_chghost = add_bind_table("chghost", HT_STACKABLE, channels_5char);
do_nettype();
return NULL;
}
1 change: 1 addition & 0 deletions src/mod/irc.mod/irc.h
Expand Up @@ -49,6 +49,7 @@ static int check_tcl_ircaway(char *, char *, char *, struct userrec *, char *,
char*);
static int check_tcl_monitor(char *, int);
static void check_tcl_account(char *nick, char *uhost, struct userrec *u, char *chan, char *account);
static int check_tcl_chghost(char *, char *, char *, struct userrec *, char *, char *, char *);
static int me_op(struct chanset_t *);
static int me_halfop(struct chanset_t *);
static int me_voice(struct chanset_t *);
Expand Down
2 changes: 1 addition & 1 deletion src/mod/server.mod/server.c
Expand Up @@ -46,7 +46,7 @@ static int flud_ctcp_thr; /* ctcp flood threshold */
static int flud_ctcp_time; /* ctcp flood time */
static char initserver[121]; /* what, if anything, to send to the
* server on connection */
static char botuserhost[121]; /* bot's user@host (refreshed whenever the
static char botuserhost[UHOSTMAX];/* bot's user@host (refreshed whenever the
* bot joins a channel) */
/* may not be correct user@host BUT it's
* how the server sees it */
Expand Down
52 changes: 0 additions & 52 deletions src/mod/server.mod/servmsg.c
Expand Up @@ -1311,56 +1311,6 @@ static int got311(char *from, char *msg)
return 0;
}

static int got396orchghost(char *nick, char *user, char *uhost)
{
struct chanset_t *chan;
memberlist *m;

for (chan = chanset; chan; chan = chan->next) {
m = ismember(chan, nick);
if (m) {
snprintf(m->userhost, sizeof m->userhost, "%s@%s", user, uhost);
if (!rfc_casecmp(m->nick, botname)) {
strcpy(botuserhost, m->userhost);
}
}
}
return 0;
}


/* React to IRCv3 CHGHOST command. CHGHOST changes the hostname and/or
* ident of the user. Format:
* :geo!awesome@eggdrop.com CHGHOST tehgeo foo.io
* changes user hostmask to tehgeo@foo.io
*/
static int gotchghost(char *from, char *msg){
char *nick, *user;

nick = splitnick(&from); /* Get the nick */
user = newsplit(&msg); /* Get the user */
got396orchghost(nick, user, msg);
return 0;
}

/* React to 396 numeric (HOSTHIDDEN), sent when user mode +x (hostmasking) was
* successfully set. Format:
* :barjavel.freenode.net 396 BeerBot unaffiliated/geo/bot/beerbot :is now your hidden host (set by services.)
*/
static int got396(char *from, char *msg)
{
char *nick, *uhost, *user, userbuf[UHOSTLEN];

nick = newsplit(&msg);
if (match_my_nick(nick)) { /* Double check this really is for me */
uhost = newsplit(&msg);
strlcpy(userbuf, botuserhost, sizeof userbuf);
user = strtok(userbuf, "@");
got396orchghost(nick, user, uhost);
}
return 0;
}

static int gotsetname(char *from, char *msg)
{
fixcolon(msg);
Expand Down Expand Up @@ -2019,7 +1969,6 @@ static cmd_t my_raw_binds[] = {
{"303", "", (IntFunc) got303, NULL},
{"311", "", (IntFunc) got311, NULL},
{"318", "", (IntFunc) whoispenalty, NULL},
{"396", "", (IntFunc) got396, NULL},
{"410", "", (IntFunc) got410, NULL},
{"417", "", (IntFunc) got417, NULL},
{"421", "", (IntFunc) got421, NULL},
Expand All @@ -2046,7 +1995,6 @@ static cmd_t my_raw_binds[] = {
{"KICK", "", (IntFunc) gotkick, NULL},
{"CAP", "", (IntFunc) gotcap, NULL},
{"AUTHENTICATE", "", (IntFunc) gotauthenticate, NULL},
{"CHGHOST", "", (IntFunc) gotchghost, NULL},
{"SETNAME", "", (IntFunc) gotsetname, NULL},
{NULL, NULL, NULL, NULL}
};
Expand Down

0 comments on commit 540f3bc

Please sign in to comment.