Skip to content

Commit

Permalink
Add Tcl isaway, refreshchan commands
Browse files Browse the repository at this point in the history
* Add Tcl isaway command
Track away status via 352 and ircv3 AWAY messages
Moved AWAY tracking from server.mod to irc.mod

* Add 'away' flag to resetchan

* revise isaway to accept channel argument

* Add refreshchan command
Removes the a flag, b/c of refreshchan we can now just use the w flag- it runs the same command. refreshchan does not remove all channel info first like resetchan does; this allows updating channel status flags without resetting idle times
  • Loading branch information
vanosg committed Jun 11, 2020
1 parent c99a550 commit d5eff2a
Show file tree
Hide file tree
Showing 13 changed files with 260 additions and 126 deletions.
72 changes: 52 additions & 20 deletions doc/sphinx_source/mainDocs/tcl-commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,16 @@ isvoice <nickname> [channel]

Module: irc

^^^^^^^^^^^^^^^^^^^^^^^^^^^
isaway <nickname> [channel]
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Description: determine if a user is marked as 'away' on a server. IMPORTANT: this command is only "mostly" reliable on its own when the IRCv3 away-notify capability is available and negotiated with the IRC server (if you didn't add this to your config file, it likely isn't enabled- you can confirm using the ``cap`` Tcl command). Additionally, there is no way for Eggdrop (or any client) to capture a user's away status when the user first joins a channel (they are assumed present by Eggdrop on join). To use this command without the away-notify capability negotiated, or to get a user's away status on join (via a JOIN bind), use ``refreshchan <channel> w`` on a channel the user is on, which will refresh the current away status stored by Eggdrop for all users on the channel.

Returns: 1 if Eggdrop is currently tracking someone by that nickname marked as 'away' (again, see disclaimer above) by an IRC server; 0 otherwise.

Module: irc

^^^^^^^^^^^^^^^^^^^^^^^^^^^
onchan <nickname> [channel]
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -1200,21 +1210,43 @@ resetchanjoin [nick] <channel>
resetchan <channel> [flags]
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Description: rereads in the channel info from the server. If flags are specified, only the required information will be reset, according to the given flags. Available flags:
Description: clears the channel info Eggdrop is currently storing for a channel, then rereads the channel info from the server. Useful if Eggdrop gets into a bad state on a server with respect to a channel userlist, for example. If flags are specified, only the required information will be reset, according to the given flags. Available flags:

+-----+------------------------------+
| b | channel bans |
+-----+------------------------------+
| e | channel exempts |
+-----+------------------------------+
| I | channel invites |
+-----+------------------------------+
| m | channel modes |
+-----+------------------------------+
| w | memberlist (who & away info) |
+-----+------------------------------+

Returns: nothing

Module: irc

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
refreshchan <channel> [flags]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Description: An alternative to resetchan, refresh rereads the channel info from the server without first clearing out the previously stored information. Useful for updateing a user's away status without resetting their idle time, for example. If flags are specified, only the required information will be refreshed, according to the given flags. Available flags:

+-----+---------------------------+
| b | reset channel bans |
+-----+---------------------------+
| e | reset channel exempts |
+-----+---------------------------+
| I | reset channel invites |
+-----+---------------------------+
| m | refresh channel modes |
+-----+---------------------------+
| t | refresh channel topic |
+-----+---------------------------+
| w | refresh memberlist |
+-----+---------------------------+
+-----+------------------------------+
| b | channel bans |
+-----+------------------------------+
| e | channel exempts |
+-----+------------------------------+
| I | channel invites |
+-----+------------------------------+
| m | channel modes |
+-----+------------------------------+
| t | channel topic |
+-----+------------------------------+
| w | memberlist (who & away info) |
+-----+------------------------------+

Returns: nothing

Expand Down Expand Up @@ -3311,15 +3343,15 @@ The following is a list of bind types and how they work. Below each bind type is

Module: core

(50) AWY3 (stackable)

bind awy3 <flags> <mask> <proc>
(50) IRCAWAY (stackable)

procname <from> <msg>
bind ircaway <flags> <mask> <proc>

Description: triggered when Eggdrop recieves an IRCv3 AWAY message for a user from an IRC server, ONLY if the away-notify IRCv3 capability is enabled via CAP. "Normal" away messages (301 messages) will not trigger this bind, for those you should instead use a RAWT bind. mask is a nickname (* to catch all nicknames) and msg is the reason that has been specified. flags is ignored. This bind will only work with IRC servers that support the IRCv3 away-notify capability, and the away-notify capability must be enabled.
procname <nick> <user> <hand> <channel> <msg>

Description: triggered when Eggdrop recieves an AWAY message for a user from an IRC server, ONLY if the away-notify capability is enabled via CAP (the server must supports this capability, see the 'cap' Tcl command for more info on requesting capabilites). "Normal" away messages (301 messages) will not trigger this bind, for those you should instead use a RAWT bind. The mask for the bind is in the format "#channel nick!user@hostname" (* to catch all nicknames). nick is the nickname of the user that triggered the bind, user is the nick!user@host of the user, handle is the handle of the user on the bot (- if the user is not added to the bot), channel is the channel the user was found on (read on for more info on this) and msg is the contents of the away message, if any. If a "*" is used for the channel in the mask, this bind is triggered once for every channel that the user is in the bot with; in other words if the bot is in two channels with the target user, the bind will be triggered twice. To trigger a proc only once per nick change, regardless of the number of channels the Eggdrop and user share, use the RAWT bind with AWAY as the keyword.

Module: server
Module: irc

(51) INVT (stackable)

Expand Down
2 changes: 1 addition & 1 deletion help/cmds1.help
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ See also: chhandle
channel-specific commands (like 'say' and 'op') take affect on.

Valid flags are:
%bj%b joins, parts, quits, and netsplits on the channel
%bj%b joins, parts, quits, aways, and netsplits on the channel
%bk%b kicks, bans, and mode changes on the channel
%bm%b private msgs, notices and ctcps to the bot
%bp%b public text on the channel
Expand Down
2 changes: 2 additions & 0 deletions src/chan.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ typedef struct memstruct {
#define SENTDEHALFOP 0x08000 /* a mode -h was already sent out for this user */
#define WASHALFOP 0x10000 /* was a halfop before a split */
#define WHO_SYNCED 0x20000 /* who reply received for this member */
#define IRCAWAY 0x40000 /* is marked as away on IRC server */

#define chan_hasvoice(x) (x->flags & CHANVOICE)
#define chan_hasop(x) (x->flags & CHANOP)
Expand All @@ -90,6 +91,7 @@ typedef struct memstruct {
#define chan_washalfop(x) (x->flags & WASHALFOP)
#define chan_stopcheck(x) (x->flags & STOPCHECK)
#define chan_whosynced(x) (x->flags & WHO_SYNCED)
#define chan_ircaway(x) (x->flags & IRCAWAY)

/* Why duplicate this struct for exempts and invites only under another
* name? <cybah>
Expand Down
3 changes: 2 additions & 1 deletion src/mod/channels.mod/channels.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
#define CHAN_RESETBANS 0x08
#define CHAN_RESETEXEMPTS 0x10
#define CHAN_RESETINVITED 0x20
#define CHAN_RESETALL 0x3F
#define CHAN_RESETAWAY 0x40
#define CHAN_RESETALL 0x7F

#ifdef MAKING_CHANNELS

Expand Down
98 changes: 65 additions & 33 deletions src/mod/irc.mod/chan.c
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ static void recheck_channel(struct chanset_t *chan, int dobans)
* In case we got them on join, nothing will be done */
if (chan->ircnet_status & (CHAN_ASKED_EXEMPTS | CHAN_ASKED_INVITED)) {
chan->ircnet_status &= ~(CHAN_ASKED_EXEMPTS | CHAN_ASKED_INVITED);
reset_chan_info(chan, CHAN_RESETEXEMPTS | CHAN_RESETINVITED);
reset_chan_info(chan, CHAN_RESETEXEMPTS | CHAN_RESETINVITED, 1);
}
if (dobans) {
if (channel_nouserbans(chan) && !stop_reset)
Expand Down Expand Up @@ -1067,6 +1067,10 @@ static int got352or4(struct chanset_t *chan, char *user, char *host,
m->flags |= CHANVOICE;
else
m->flags &= ~CHANVOICE;
if (strchr(flags, 'G') != NULL)
m->flags |= IRCAWAY;
else
m->flags &= ~IRCAWAY;
if (!(m->flags & (CHANVOICE | CHANOP | CHANHALFOP)))
m->flags |= STOPWHO;
if (match_my_nick(nick) && any_ops(chan) && !me_op(chan)) {
Expand Down Expand Up @@ -1165,6 +1169,33 @@ static int got315(char *from, char *msg)
return 0; /* Don't check for I-Lines here. */
}

/* Got AWAY message; only valid for IRCv3 away-notify capability */
static int gotaway(char *from, char *msg)
{
struct userrec *u;
struct chanset_t *chan;
char mask[1024], buf[MSGMAX], *nick, *s1 = buf, *chname;

strlcpy(s1, from, sizeof buf);
nick = splitnick(&s1);
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;
if (ismember(chan, nick)) {
snprintf(mask, sizeof mask, "%s %s", chname, from);
check_tcl_ircaway(nick, from, mask, u, chname, msg);
if (strlen(msg)) {
fixcolon(msg);
putlog(LOG_JOIN, chan->dname, "%s is now away: %s", from, msg);
} else {
putlog(LOG_JOIN, chan->dname, "%s has returned from away status", from);
}
}
}
return 0;
}

/* got 367: ban info
* <server> 367 <to> <chan> <ban> [placed-by] [timestamp]
*/
Expand Down Expand Up @@ -1769,7 +1800,7 @@ static int gotjoin(char *from, char *chname)
chan->dname);
chan->status |= CHAN_ACTIVE;
chan->status &= ~CHAN_PEND;
reset_chan_info(chan, CHAN_RESETALL);
reset_chan_info(chan, CHAN_RESETALL, 1);
} else {
m = ismember(chan, nick);
if (m && m->split && !strcasecmp(m->userhost, uhost)) {
Expand Down Expand Up @@ -1849,7 +1880,7 @@ static int gotjoin(char *from, char *chname)
else
putlog(LOG_JOIN | LOG_MISC, chan->dname, "%s joined %s.", nick,
chname);
reset_chan_info(chan, (CHAN_RESETALL & ~CHAN_RESETTOPIC));
reset_chan_info(chan, (CHAN_RESETALL & ~CHAN_RESETTOPIC), 1);
} else {
struct chanuserrec *cr;

Expand Down Expand Up @@ -2001,7 +2032,7 @@ static int gotpart(char *from, char *msg)
chan->dname);
chan->status |= CHAN_ACTIVE;
chan->status &= ~CHAN_PEND;
reset_chan_info(chan, CHAN_RESETALL);
reset_chan_info(chan, CHAN_RESETALL, 1);
}
set_handle_laston(chan->dname, u, now);
/* This must be directly above the killmember, in case we're doing anything
Expand Down Expand Up @@ -2500,35 +2531,36 @@ static int gotnotice(char *from, char *msg)
}

static cmd_t irc_raw[] = {
{"324", "", (IntFunc) got324, "irc:324"},
{"352", "", (IntFunc) got352, "irc:352"},
{"354", "", (IntFunc) got354, "irc:354"},
{"315", "", (IntFunc) got315, "irc:315"},
{"367", "", (IntFunc) got367, "irc:367"},
{"368", "", (IntFunc) got368, "irc:368"},
{"403", "", (IntFunc) got403, "irc:403"},
{"405", "", (IntFunc) got405, "irc:405"},
{"471", "", (IntFunc) got471, "irc:471"},
{"473", "", (IntFunc) got473, "irc:473"},
{"474", "", (IntFunc) got474, "irc:474"},
{"475", "", (IntFunc) got475, "irc:475"},
{"INVITE", "", (IntFunc) gotinvite, "irc:invite"},
{"TOPIC", "", (IntFunc) gottopic, "irc:topic"},
{"331", "", (IntFunc) got331, "irc:331"},
{"332", "", (IntFunc) got332, "irc:332"},
{"JOIN", "", (IntFunc) gotjoin, "irc:join"},
{"PART", "", (IntFunc) gotpart, "irc:part"},
{"KICK", "", (IntFunc) gotkick, "irc:kick"},
{"NICK", "", (IntFunc) gotnick, "irc:nick"},
{"QUIT", "", (IntFunc) gotquit, "irc:quit"},
{"PRIVMSG", "", (IntFunc) gotmsg, "irc:msg"},
{"NOTICE", "", (IntFunc) gotnotice, "irc:notice"},
{"MODE", "", (IntFunc) gotmode, "irc:mode"},
{"346", "", (IntFunc) got346, "irc:346"},
{"347", "", (IntFunc) got347, "irc:347"},
{"348", "", (IntFunc) got348, "irc:348"},
{"349", "", (IntFunc) got349, "irc:349"},
{NULL, NULL, NULL, NULL}
{"324", "", (IntFunc) got324, "irc:324"},
{"352", "", (IntFunc) got352, "irc:352"},
{"354", "", (IntFunc) got354, "irc:354"},
{"315", "", (IntFunc) got315, "irc:315"},
{"367", "", (IntFunc) got367, "irc:367"},
{"368", "", (IntFunc) got368, "irc:368"},
{"403", "", (IntFunc) got403, "irc:403"},
{"405", "", (IntFunc) got405, "irc:405"},
{"471", "", (IntFunc) got471, "irc:471"},
{"473", "", (IntFunc) got473, "irc:473"},
{"474", "", (IntFunc) got474, "irc:474"},
{"475", "", (IntFunc) got475, "irc:475"},
{"INVITE", "", (IntFunc) gotinvite, "irc:invite"},
{"TOPIC", "", (IntFunc) gottopic, "irc:topic"},
{"331", "", (IntFunc) got331, "irc:331"},
{"332", "", (IntFunc) got332, "irc:332"},
{"JOIN", "", (IntFunc) gotjoin, "irc:join"},
{"PART", "", (IntFunc) gotpart, "irc:part"},
{"KICK", "", (IntFunc) gotkick, "irc:kick"},
{"NICK", "", (IntFunc) gotnick, "irc:nick"},
{"QUIT", "", (IntFunc) gotquit, "irc:quit"},
{"PRIVMSG", "", (IntFunc) gotmsg, "irc:msg"},
{"NOTICE", "", (IntFunc) gotnotice, "irc:notice"},
{"MODE", "", (IntFunc) gotmode, "irc:mode"},
{"AWAY", "", (IntFunc) gotaway, "irc:gotaway"},
{"346", "", (IntFunc) got346, "irc:346"},
{"347", "", (IntFunc) got347, "irc:347"},
{"348", "", (IntFunc) got348, "irc:348"},
{"349", "", (IntFunc) got349, "irc:349"},
{NULL, NULL, NULL, NULL}
};

static cmd_t irc_rawt[] = {
Expand Down
15 changes: 10 additions & 5 deletions src/mod/irc.mod/cmdsirc.c
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ static void cmd_channel(struct userrec *u, int idx, char *par)
maxhandlen = 9;

dprintf(idx, "(n = owner, m = master, o = op, d = deop, b = bot)\n");
egg_snprintf(format, sizeof format, " %%-%us %%-%us %%-6s %%-5s %%s\n",
egg_snprintf(format, sizeof format, " %%-%us %%-%us %%-6s %%-12s %%s\n",
maxnicklen, maxhandlen);
dprintf(idx, format, "NICKNAME", "HANDLE", " JOIN", "IDLE", "USER@HOST");
for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
Expand Down Expand Up @@ -855,13 +855,13 @@ static void cmd_channel(struct userrec *u, int idx, char *par)
chanflag = ' ';
if (chan_issplit(m)) {
egg_snprintf(format, sizeof format,
"%%c%%-%us %%-%us %%s %%c <- netsplit, %%lus\n",
"%%c%%-%us %%-%us %%s %%c <- netsplit, %%lus\n",
maxnicklen, maxhandlen);
dprintf(idx, format, chanflag, m->nick, handle, s, atrflag,
now - (m->split));
} else if (!rfc_casecmp(m->nick, botname)) {
egg_snprintf(format, sizeof format,
"%%c%%-%us %%-%us %%s %%c <- it's me!\n",
"%%c%%-%us %%-%us %%s %%c <- it's me!\n",
maxnicklen, maxhandlen);
dprintf(idx, format, chanflag, m->nick, handle, s, atrflag);
} else {
Expand All @@ -874,6 +874,11 @@ static void cmd_channel(struct userrec *u, int idx, char *par)
egg_snprintf(s1, sizeof s1, "%2lum", ((now - (m->last)) / 60));
else
strlcpy(s1, " ", sizeof s1);
if (chan_ircaway(m)) {
egg_snprintf(s1+strlen(s1), ((sizeof s1)-strlen(s1)), " (away)");
} else {
egg_snprintf(s1+strlen(s1), ((sizeof s1)-strlen(s1)), " ");
}
egg_snprintf(format, sizeof format,
"%%c%%-%us %%-%us %%s %%c %%s %%s\n", maxnicklen,
maxhandlen);
Expand Down Expand Up @@ -1136,7 +1141,7 @@ static void cmd_reset(struct userrec *u, int idx, char *par)
else {
putlog(LOG_CMDS, "*", "#%s# reset %s", dcc[idx].nick, par);
dprintf(idx, "Resetting channel info for %s...\n", chan->dname);
reset_chan_info(chan, CHAN_RESETALL);
reset_chan_info(chan, CHAN_RESETALL, 1);
}
}
} else if (!(u->flags & USER_MASTER))
Expand All @@ -1146,7 +1151,7 @@ static void cmd_reset(struct userrec *u, int idx, char *par)
dprintf(idx, "Resetting channel info for all channels...\n");
for (chan = chanset; chan; chan = chan->next) {
if (channel_active(chan))
reset_chan_info(chan, CHAN_RESETALL);
reset_chan_info(chan, CHAN_RESETALL, 1);
}
}
}
Expand Down
Loading

0 comments on commit d5eff2a

Please sign in to comment.