Skip to content

Commit

Permalink
mod_slack: Increase usability of in-thread replies.
Browse files Browse the repository at this point in the history
Commit 5a226d4 added
support for in-thread replies from IRC. This increases
the usability with two small modifications:

* Prefix Slack replies towards IRC with a '>', to indicate
  they are in-thread replies, rather than top level messages.
* Allow a user to prefix a message with '>' as shorthand
  to reply to the most recently active thread.
  • Loading branch information
InterLinked1 committed Jan 26, 2024
1 parent efc68ac commit 356e700
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 5 deletions.
5 changes: 4 additions & 1 deletion configs/mod_slack.conf
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ cookie_ds=
; then that message will be replied to "in thread" (without the thread ID prefixed). This allows transparently preserving Slack threading from IRC.
; Default is 'no'.
;prefixthread=no ; Whether to prefix messages sent to IRC with the Slack thread ID. Default is 'no'.
; This is mainly useful if preservethreading=yes, since it allows IRC users to copy and paste the thread ID for a reply.
; If prefixed, messages will be prefixed with the thread ID. Additionally,
; for messages that are replies in a thread, a '>' will be prefixed to the message to distinguish replies from top-level messages.
; This option is mainly useful if preservethreading=yes, since it allows IRC users to copy and paste the thread ID for a reply.
; To reply in thread in the most recently active thread, the message can be prefixed with simply '>' (followed by a space), for convenience.
;mapping=ws1-map ; Name of config section that provides specific channel mappings.

[ws1-map] ; Config section with mappings for the relay. Must be provided, unless prefix= is specified.
Expand Down
46 changes: 42 additions & 4 deletions modules/mod_slack.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ struct chan_pair {

RWLIST_HEAD(chan_pairs, chan_pair);

#define SLACK_TS_LENGTH 17

struct slack_relay {
RWLIST_ENTRY(slack_relay) entry;
struct slack_client *slack;
Expand All @@ -112,6 +114,8 @@ struct slack_relay {
struct chan_pairs mappings;
struct slack_users users;
pthread_t thread;
pthread_mutex_t lock;
char last_ts[SLACK_TS_LENGTH + 1];
char data[];
};

Expand Down Expand Up @@ -144,6 +148,7 @@ static void relay_free(struct slack_relay *relay)
}
RWLIST_WRLOCK_REMOVE_ALL(&relay->mappings, entry, cp_free);
RWLIST_WRLOCK_REMOVE_ALL(&relay->users, entry, slack_user_free);
pthread_mutex_destroy(&relay->lock);
free(relay);
}

Expand Down Expand Up @@ -737,8 +742,21 @@ static int on_message(struct slack_event *event, const char *channel, const char
* In most small workspaces, this should not pose an issue; however, if a collision occurs
* (and we don't check for this), then unexpected behavior may occur. */
if (relay->prefixthread) {
snprintf(prefixed, sizeof(prefixed), "%s: %s", S_OR(thread_ts, ts), text);
text = prefixed;
/* If this is the first message in a thread, just include the ts.
* If it's a reply to a message in a thread, prefix the ts with a '>',
* which allows recipients on IRC to distinguish replies from top-level messages. */
const char *eff_ts = S_OR(thread_ts, ts);
if (!strlen_zero(eff_ts)) {
snprintf(prefixed, sizeof(prefixed), "%s%s: %s", thread_ts ? ">" : "", eff_ts, text);
text = prefixed;
/* Also keep track of the last active ts.
* on_message can only be called once per relay at a time since there's a single thread dispatching events,
* but multiple threads could try sending messages (using this variable) simultaneously,
* so this needs to be atomic with that. */
pthread_mutex_lock(&relay->lock);
safe_strncpy(relay->last_ts, eff_ts, sizeof(relay->last_ts));
pthread_mutex_unlock(&relay->lock);
}
}
irc_relay_send_multiline(destination, CHANNEL_USER_MODE_NONE, "Slack", ircusername, user, text, substitute_mentions, relay->ircuser);
return 0;
Expand Down Expand Up @@ -813,8 +831,6 @@ static void notify_unauthorized(const char *sender, const char *channel, const c
irc_relay_send_notice(sender, CHANNEL_USER_MODE_NONE, "Slack", sender, NULL, notice, NULL);
}

#define SLACK_TS_LENGTH 17

static inline void parse_parent_thread(struct slack_relay *relay, char *restrict ts, const char **restrict thread_ts, char const **restrict msg)
{
const char *word2;
Expand All @@ -825,6 +841,27 @@ static inline void parse_parent_thread(struct slack_relay *relay, char *restrict
return;
}

if (*(*msg) == '>') {
(*msg)++;
if (strlen_zero(*msg)) {
return;
}
/* If it starts with >,
* that's short hand for "reply in thread in the last active thread" */
pthread_mutex_lock(&relay->lock);
if (!strlen_zero(relay->last_ts)) {
safe_strncpy(ts, relay->last_ts, SLACK_TS_LENGTH + 2);
pthread_mutex_unlock(&relay->lock);
*thread_ts = ts;
bbs_debug(5, "Replying to last active thread: %s\n", ts);
} else {
pthread_mutex_unlock(&relay->lock);
bbs_debug(3, "No last ts on file, can't reply in thread\n");
/* Just post a top level message */
}
return;
}

safe_strncpy(ts, *msg, SLACK_TS_LENGTH + 2);
tsl = atol(ts); /* Parse timestamp, at least up until period */
if (tsl <= 0) {
Expand Down Expand Up @@ -1333,6 +1370,7 @@ static int load_config(void)
if (ALLOC_FAILURE(relay)) {
continue;
}
pthread_mutex_init(&relay->lock, NULL);
SET_BITFIELD(relay->relaysystem, relaysystem);
SET_BITFIELD(relay->prefixthread, prefixthread);
SET_BITFIELD(relay->preservethreading, preservethreading);
Expand Down

0 comments on commit 356e700

Please sign in to comment.