Skip to content

Commit

Permalink
mod_webmail: Add CLI command for sessions.
Browse files Browse the repository at this point in the history
This adds a CLI command to view active webmail
sessions. This requires adding a wrapped linked
list structure around the WebSocket sessions, since
these are only allocated and freed by mod_webmail,
but not kept track of here, since they are callback
data to net_ws. This allows more easily seeing
what webmail sessions are doing at the moment,
aside from simply parsing the webmail log, if enabled.
  • Loading branch information
InterLinked1 committed Nov 26, 2023
1 parent dbb37a2 commit 3425fb8
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 1 deletion.
2 changes: 2 additions & 0 deletions modules/mod_smtp_delivery_external.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ static void process_capabilities(int *restrict caps, int *restrict maxsendsize,
* https://www.exim.org/exim-html-current/doc/html/spec_html/ch-main_configuration.html */
} else if (!strcmp(capname, "AUTH=LOGIN PLAIN")) {
/* Ignore: this SMTP server advertises this capability (even though it's malformed) to support some broken clients */
} else if (!strcmp(capname, "OK")) {
/* This is not a real capability, just ignore it. Yahoo seems to do this. */
} else {
bbs_warning("Unknown capability advertised: %s\n", capname);
}
Expand Down
69 changes: 68 additions & 1 deletion modules/mod_webmail.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "include/utils.h"
#include "include/json.h"
#include "include/base64.h"
#include "include/cli.h"

#include "include/net_ws.h"

Expand Down Expand Up @@ -70,6 +71,17 @@ struct imap_client {
char *filter;
};

/* Additional data structure to keep track of
* webmail clients in a linked list, since
* these are really opaque data structures
* that technically belong to net_ws. */
struct webmail_session {
struct imap_client *client;
RWLIST_ENTRY(webmail_session) entry;
};

static RWLIST_HEAD_STATIC(sessions, webmail_session);

static unsigned int webmail_log_level = 0;
static FILE *webmail_log_fp = NULL;
static pthread_mutex_t loglock = PTHREAD_MUTEX_INITIALIZER;
Expand Down Expand Up @@ -3504,10 +3516,17 @@ static int on_text_message(struct ws_session *ws, void *data, const char *buf, s

static int on_open(struct ws_session *ws)
{
struct webmail_session *s;
struct imap_client *client;

s = calloc(1, sizeof(*client));
if (ALLOC_FAILURE(s)) {
return -1;
}

client = calloc(1, sizeof(*client)); /* Unfortunately, we can't stack allocate this */
if (ALLOC_FAILURE(client)) {
free(s);
return -1;
}

Expand All @@ -3519,28 +3538,67 @@ static int on_open(struct ws_session *ws)
}

websocket_set_custom_poll_fd(ws, client->imapfd, SEC_MS(60)); /* Give the user a minute to authenticate */
s->client = client;
RWLIST_WRLOCK(&sessions);
RWLIST_INSERT_HEAD(&sessions, s, entry);
RWLIST_UNLOCK(&sessions);
webmail_log(2, client, "New session established\n");
return 0;

done:
free(s);
FREE(client);
return -1;
}

static int on_close(struct ws_session *ws, void *data)
{
struct webmail_session *s;
struct imap_client *client = data;

idle_stop(ws, client);
mailimap_logout(client->imap);
mailimap_free(client->imap); /* Must exist, or we would have rejected in on_open */

RWLIST_WRLOCK(&sessions);
RWLIST_TRAVERSE_SAFE_BEGIN(&sessions, s, entry) {
if (s->client == client) {
RWLIST_REMOVE_CURRENT(entry);
free(s);
break;
}
}
RWLIST_TRAVERSE_SAFE_END;
RWLIST_UNLOCK(&sessions);

free_if(client->mailbox);
free_if(client->sort);
free_if(client->filter);
free(client);
return 0;
}

static int cli_webmail_sessions(struct bbs_cli_args *a)
{
struct webmail_session *s;
time_t now = time(NULL);

bbs_dprintf(a->fdout, "%7s %4s %4s %4s %s\n", "IMAP FD", "Auth", "Idle", "Page", "Mailbox");
RWLIST_RDLOCK(&sessions);
RWLIST_TRAVERSE(&sessions, s, entry) {
struct imap_client *c = s->client;
/* net_ws doesn't expose the node associated with the ws_session, which is fine,
* but that means we can't display the node ID. */
bbs_dprintf(a->fdout, "%7d %4s %4d %4d %s\n", c->imapfd, BBS_YN(c->authenticated), c->idling ? (int) (now - c->idlestart) : -1, c->page, S_IF(c->mailbox));
}
RWLIST_UNLOCK(&sessions);
return 0;
}

static struct bbs_cli_entry cli_commands_webmail[] = {
BBS_CLI_COMMAND(cli_webmail_sessions, "webmail sessions", 2, "Show connected webmail clients", NULL),
};

struct ws_callbacks callbacks = {
.on_open = on_open,
.on_close = on_close,
Expand Down Expand Up @@ -3575,11 +3633,20 @@ static int load_module(void)
if (load_config()) {
return -1;
}
return websocket_route_register("/webmail", &callbacks);
return websocket_route_register("/webmail", &callbacks) || bbs_cli_register_multiple(cli_commands_webmail);
}

static int unload_module(void)
{
bbs_cli_unregister_multiple(cli_commands_webmail);

RWLIST_WRLOCK(&sessions);
if (!RWLIST_EMPTY(&sessions)) {
bbs_error("Webmail sessions still present at module unload?\n");
RWLIST_REMOVE_ALL(&sessions, entry, free);
}
RWLIST_UNLOCK(&sessions);

if (webmail_log_fp) {
fclose(webmail_log_fp);
}
Expand Down

0 comments on commit 3425fb8

Please sign in to comment.