From 4d11be0b85b623a06aca0b8e2ed5a97da57a85e0 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Sun, 22 Nov 2015 23:04:51 +0100
Subject: degesch: implement auto-away
---
NEWS | 2 ++
README.adoc | 2 +-
degesch.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 103 insertions(+), 3 deletions(-)
diff --git a/NEWS b/NEWS
index 9b3772b..97de82a 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@
* degesch: added detection of pasting, so that it doesn't trigger other
keyboard shortcuts, such as for autocomplete
+ * degesch: added auto-away capability
+
* degesch: added an /oper command
* degesch: libedit backend works again
diff --git a/README.adoc b/README.adoc
index 03f72c1..98e13f7 100644
--- a/README.adoc
+++ b/README.adoc
@@ -24,7 +24,7 @@ This is the largest application within the project. It has most of the stuff
you'd expect of an IRC client, such as being able to set up multiple servers,
a powerful configuration system, integrated help, text formatting, CTCP queries,
automatic splitting of overlong messages, autocomplete, logging to file,
-command aliases and rudimentary support for Lua scripting.
+auto-away, command aliases and rudimentary support for Lua scripting.
kike
----
diff --git a/degesch.c b/degesch.c
index f4deab3..dc16c93 100644
--- a/degesch.c
+++ b/degesch.c
@@ -1207,6 +1207,7 @@ struct server
int nick_counter; ///< Iterates "nicks" when registering
struct str irc_user_mode; ///< Our current user modes
char *irc_user_host; ///< Our current user@host
+ bool autoaway_active; ///< Autoaway is currently active
bool cap_echo_message; ///< Whether the server echos messages
@@ -1480,6 +1481,7 @@ struct app_context
struct poller_timer flush_timer; ///< Flush all open files (e.g. logs)
struct poller_timer date_chg_tmr; ///< Print a date change
+ struct poller_timer autoaway_tmr; ///< Autoaway timer
struct poller poller; ///< Manages polled descriptors
bool quitting; ///< User requested quitting
@@ -1863,6 +1865,16 @@ static struct config_schema g_config_behaviour[] =
.validate = config_validate_nonnegative,
.default_ = "600" },
+ { .name = "autoaway_message",
+ .comment = "Automated away message",
+ .type = CONFIG_ITEM_STRING,
+ .default_ = "\"I'm not here right now\"" },
+ { .name = "autoaway_delay",
+ .comment = "Delay from the last keypress in seconds",
+ .type = CONFIG_ITEM_INTEGER,
+ .validate = config_validate_nonnegative,
+ .default_ = "1800" },
+
{ .name = "plugin_autoload",
.comment = "Plugins to automatically load on start",
.type = CONFIG_ITEM_STRING_ARRAY,
@@ -6110,6 +6122,7 @@ irc_try_parse_welcome_for_userhost (struct server *s, const char *m)
static bool process_input_utf8
(struct app_context *, struct buffer *, const char *, int);
+static void on_autoaway_timer (struct app_context *ctx);
static void
irc_on_registered (struct server *s, const char *nickname)
@@ -6124,6 +6137,10 @@ irc_on_registered (struct server *s, const char *nickname)
// XXX: we can also use WHOIS if it's not supported (optional by RFC 2812)
irc_send (s, "USERHOST %s", s->irc_user->nickname);
+ // A little hack that reinstates auto-away status when we get disconnected
+ if (s->autoaway_active)
+ on_autoaway_timer (s->ctx);
+
const char *command = get_config_string (s->config, "command");
if (command)
{
@@ -6486,6 +6503,24 @@ irc_handle_rpl_inviting (struct server *s, const struct irc_message *msg)
"You have invited #n to #S", nickname, channel_name);
}
+static void
+irc_handle_rpl_nowaway (struct server *s, const struct irc_message *msg)
+{
+ (void) msg;
+
+ if (s->irc_user)
+ s->irc_user->away = true;
+}
+
+static void
+irc_handle_rpl_unaway (struct server *s, const struct irc_message *msg)
+{
+ (void) msg;
+
+ if (s->irc_user)
+ s->irc_user->away = false;
+}
+
static void
irc_handle_err_nicknameinuse (struct server *s, const struct irc_message *msg)
{
@@ -6707,6 +6742,10 @@ irc_process_numeric (struct server *s,
irc_handle_rpl_topicwhotime (s, msg); buffer = NULL; break;
case IRC_RPL_INVITING:
irc_handle_rpl_inviting (s, msg); buffer = NULL; break;
+ case IRC_RPL_NOWAWAY:
+ irc_handle_rpl_nowaway (s, msg); break;
+ case IRC_RPL_UNAWAY:
+ irc_handle_rpl_unaway (s, msg); break;
case IRC_ERR_NICKNAMEINUSE:
irc_handle_err_nicknameinuse (s, msg); buffer = NULL; break;
@@ -10980,10 +11019,60 @@ done:
}
static void
-on_tty_readable (const struct pollfd *fd, struct app_context *ctx)
+reset_autoaway (struct app_context *ctx)
{
- (void) ctx;
+ // Stop the last one if it's been disabled altogether in the meantime
+ poller_timer_reset (&ctx->autoaway_tmr);
+
+ // Unset any automated statuses that are active right at this moment
+ struct str_map_iter iter;
+ str_map_iter_init (&iter, &ctx->servers);
+ struct server *s;
+ while ((s = str_map_iter_next (&iter)))
+ {
+ if (s->autoaway_active
+ && s->irc_user
+ && s->irc_user->away)
+ irc_send (s, "AWAY");
+ s->autoaway_active = false;
+ }
+
+ // And potentially start a new auto-away timer
+ int64_t delay = get_config_integer
+ (ctx->config.root, "behaviour.autoaway_delay");
+ if (delay)
+ poller_timer_set (&ctx->autoaway_tmr, delay * 1000);
+}
+
+static void
+on_autoaway_timer (struct app_context *ctx)
+{
+ // An empty message would unset any away status, so let's ignore that
+ const char *message = get_config_string
+ (ctx->config.root, "behaviour.autoaway_message");
+ if (!message || !*message)
+ return;
+
+ struct str_map_iter iter;
+ str_map_iter_init (&iter, &ctx->servers);
+ struct server *s;
+ while ((s = str_map_iter_next (&iter)))
+ {
+ // If the user has already been marked as away,
+ // don't override his current away status
+ if (s->irc_user
+ && s->irc_user->away)
+ continue;
+
+ irc_send (s, "AWAY :%s", message);
+ s->autoaway_active = true;
+ }
+}
+
+static void
+on_tty_readable (const struct pollfd *fd, struct app_context *ctx)
+{
if (fd->revents & ~(POLLIN | POLLHUP | POLLERR))
print_debug ("fd %d: unexpected revents: %d", fd->fd, fd->revents);
@@ -10995,6 +11084,10 @@ on_tty_readable (const struct pollfd *fd, struct app_context *ctx)
// XXX: this may loop for a bit: stop the event or eat the input?
// (This prevents a segfault when the input has been stopped.)
input_on_readable (&ctx->input);
+
+ // User activity detected, stop current auto-away and start anew;
+ // since they might have just changed the settings, do this last
+ reset_autoaway (ctx);
}
static void
@@ -11059,6 +11152,10 @@ init_poller_events (struct app_context *ctx)
ctx->date_chg_tmr.dispatcher = (poller_timer_fn) on_date_change_timer;
ctx->date_chg_tmr.user_data = ctx;
rearm_date_change_timer (ctx);
+
+ poller_timer_init (&ctx->autoaway_tmr, &ctx->poller);
+ ctx->autoaway_tmr.dispatcher = (poller_timer_fn) on_autoaway_timer;
+ ctx->autoaway_tmr.user_data = ctx;
}
// --- Main program ------------------------------------------------------------
@@ -11146,6 +11243,7 @@ main (int argc, char *argv[])
refresh_prompt (&ctx);
input_start (&ctx.input, argv[0]);
toggle_bracketed_paste (true);
+ reset_autoaway (&ctx);
// Finally, we juice the configuration for some servers to create
load_plugins (&ctx);
--
cgit v1.2.3-70-g09d2