Skip to content

Commit

Permalink
node.c: Move welcome banners to mod_events.
Browse files Browse the repository at this point in the history
To promote modularity, move the welcome banners to
mod_events as an event callback, so they're not
hardcoded in node.c. This allows them to be more
easily changed, without having to restart the BBS.

Also print a special message if it's a user's birthday!
  • Loading branch information
InterLinked1 committed Feb 1, 2024
1 parent 3df5ecc commit 8ab0f7a
Show file tree
Hide file tree
Showing 6 changed files with 297 additions and 136 deletions.
14 changes: 14 additions & 0 deletions bbs/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ const char *bbs_event_name(enum bbs_event_type type)
return "NODE_BAD_REQUEST";
case EVENT_USER_REGISTRATION:
return "USER_REGISTRATION";
case EVENT_NODE_INTERACTIVE_START:
return "NODE_INTERACTIVE_START";
case EVENT_NODE_INTERACTIVE_LOGIN:
return "NODE_INTERACTIVE_LOGIN";
case EVENT_USER_LOGIN:
return "USER_LOGIN";
case EVENT_USER_LOGOFF:
Expand Down Expand Up @@ -175,6 +179,16 @@ int bbs_event_dispatch_custom(struct bbs_node *node, enum bbs_event_type type, c
safe_strncpy(event.ipaddr, node->ip, sizeof(event.ipaddr));
}
break;
case EVENT_NODE_INTERACTIVE_START:
case EVENT_NODE_INTERACTIVE_LOGIN:
if (!node) {
bbs_error("Can't create an event without a node\n");
return -1;
}
/* Allow direct access to node for these callbacks,
* to promote modularity */
event.node = node;
break;
/* No default, so we'll have to explicitly handle any newly added events. */
}

Expand Down
159 changes: 32 additions & 127 deletions bbs/node.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
#include "include/variables.h"
#include "include/term.h"
#include "include/pty.h"
#include "include/os.h"
#include "include/menu.h"
#include "include/auth.h"
#include "include/config.h"
Expand Down Expand Up @@ -66,9 +65,9 @@ static unsigned int defaultbps = 0;
static unsigned int idlemins = 0;

static char bbs_name_buf[32] = "BBS"; /* A simple default so this is never empty. */
static char bbs_tagline[84] = "";
static char bbs_tagline_buf[84] = "";
static char bbs_hostname_buf[92] = "";
static char bbs_sysop[16] = "";
static char bbs_sysop_buf[16] = "";
static char bbs_exitmsg[484] = "";

static int load_config(void)
Expand Down Expand Up @@ -96,9 +95,9 @@ static int load_config(void)
if (bbs_config_val_set_str(cfg, "bbs", "name", bbs_name_buf, sizeof(bbs_name_buf))) {
bbs_warning("No name is configured for this BBS in nodes.conf - BBS will be impersonal!\n");
}
bbs_config_val_set_str(cfg, "bbs", "tagline", bbs_tagline, sizeof(bbs_tagline));
bbs_config_val_set_str(cfg, "bbs", "tagline", bbs_tagline_buf, sizeof(bbs_tagline_buf));
bbs_config_val_set_str(cfg, "bbs", "hostname", bbs_hostname_buf, sizeof(bbs_hostname_buf));
bbs_config_val_set_str(cfg, "bbs", "sysop", bbs_sysop, sizeof(bbs_sysop));
bbs_config_val_set_str(cfg, "bbs", "sysop", bbs_sysop_buf, sizeof(bbs_sysop_buf));
bbs_config_val_set_uint(cfg, "bbs", "minuptimedisplayed", &minuptimedisplayed);
bbs_config_val_set_str(cfg, "bbs", "exitmsg", bbs_exitmsg, sizeof(bbs_exitmsg));
bbs_config_val_set_uint(cfg, "nodes", "maxnodes", &maxnodes);
Expand Down Expand Up @@ -173,6 +172,11 @@ unsigned int bbs_max_nodenum(void)
return maxnodenum;
}

unsigned int bbs_min_uptime_threshold(void)
{
return minuptimedisplayed;
}

unsigned int bbs_idle_ms(void)
{
return idlemins;
Expand All @@ -193,6 +197,16 @@ const char *bbs_name(void)
return bbs_name_buf;
}

const char *bbs_tagline(void)
{
return bbs_tagline_buf;
}

const char *bbs_sysop(void)
{
return bbs_sysop_buf;
}

static unsigned int lifetime_nodes = 0;

struct bbs_node *__bbs_node_request(int fd, const char *protname, void *mod)
Expand Down Expand Up @@ -1182,54 +1196,11 @@ static int _bbs_intro(struct bbs_node *node)

static int node_intro(struct bbs_node *node)
{
char timebuf[29];

if (!NODE_IS_TDD(node)) {
NEG_RETURN(bbs_node_clear_screen(node));
NEG_RETURN(bbs_node_writef(node, "%s %d.%d.%d %s\n\n", BBS_TAGLINE, BBS_MAJOR_VERSION, BBS_MINOR_VERSION, BBS_PATCH_VERSION, BBS_COPYRIGHT));
usleep(150000);
NEG_RETURN(bbs_node_writef(node, COLOR(COLOR_PRIMARY)));
} else {
/* Print some spaces as TDD carrier starts up, so we don't clip the beginning of output,
* and because the TDD could be in FIGS mode and this gives it a chance to get into LTRS mode. */
NEG_RETURN(bbs_node_writef(node, "%10s", ""));
/* Since the server will keep going until we block (hit a key),
* sleep explicitly as it will take some for the TDD to print the output anyways.
* This will allow the sysop to begin spying on the node here and catch the next output.
* Really, mainly to help with testing and debugging. */
usleep(2500000);
NEG_RETURN(bbs_node_writef(node, "%s %d.%d.%d %s\n\n", BBS_SHORTNAME, BBS_MAJOR_VERSION, BBS_MINOR_VERSION, BBS_PATCH_VERSION, BBS_COPYRIGHT_SHORT));
}

NEG_RETURN(bbs_node_writef(node, "%s\n", bbs_name_buf)); /* Print BBS name */

if (!NODE_IS_TDD(node)) {
if (!s_strlen_zero(bbs_tagline)) {
NEG_RETURN(bbs_node_writef(node, "%s\n\n", bbs_tagline)); /* Print BBS tagline */
}
bbs_time_friendly_now(timebuf, sizeof(timebuf));
NEG_RETURN(bbs_node_writef(node, "%s%6s %s%s: %s%s\n", COLOR(COLOR_WHITE), "CLIENT", COLOR(COLOR_SECONDARY), "CONN", COLOR(COLOR_PRIMARY), node->protname));
NEG_RETURN(bbs_node_writef(node, "%s%6s %s%s: %s%s\n", "", "", COLOR(COLOR_SECONDARY), "ADDR", COLOR(COLOR_PRIMARY), node->ip));
NEG_RETURN(bbs_node_writef(node, "%s%6s %s%s: %s%dx%d\n", "", "", COLOR(COLOR_SECONDARY), "TERM", COLOR(COLOR_PRIMARY), node->cols, node->rows));
NEG_RETURN(bbs_node_writef(node, "%s%6s %s%s: %s%s\n", COLOR(COLOR_WHITE), "SERVER", COLOR(COLOR_SECONDARY), "NAME", COLOR(COLOR_WHITE), bbs_name_buf));
if (!s_strlen_zero(bbs_hostname_buf)) {
NEG_RETURN(bbs_node_writef(node, "%s%6s %s%s: %s%s\n", "", "", COLOR(COLOR_SECONDARY), "ADDR", COLOR(COLOR_PRIMARY), bbs_hostname_buf));
}
NEG_RETURN(bbs_node_writef(node, "%s%6s %s%s: %s%d %s(of %s%d%s) - %s%s\n", "", "", COLOR(COLOR_SECONDARY), "NODE", COLOR(COLOR_PRIMARY),
node->id, COLOR(COLOR_SECONDARY), COLOR(COLOR_PRIMARY), bbs_maxnodes(), COLOR(COLOR_SECONDARY), COLOR(COLOR_PRIMARY), bbs_get_osver()));
NEG_RETURN(bbs_node_writef(node, "%s%6s %s%s: %s%s\n", "", "", COLOR(COLOR_SECONDARY), "TIME", COLOR(COLOR_PRIMARY), timebuf));
if (!s_strlen_zero(bbs_hostname_buf)) {
NEG_RETURN(bbs_node_writef(node, "%s%6s %s%s: %s%s\n", "", "", COLOR(COLOR_SECONDARY), "ADMN", COLOR(COLOR_PRIMARY), bbs_sysop));
}
} else {
bbs_time_friendly_short_now(timebuf, sizeof(timebuf)); /* Use condensed date for TDDs */
NEG_RETURN(bbs_node_writef(node, "Node %d - %s\n", node->id, timebuf));
/* Display any pre-auth banners */
if (bbs_event_dispatch(node, EVENT_NODE_INTERACTIVE_START)) {
return -1;
}

usleep(300000);

NEG_RETURN(bbs_node_wait_key(node, SEC_MS(75)));

/* Some protocols like SSH may support direct login of users. Otherwise, do a normal login. */
if (!bbs_node_logged_in(node)) {
NEG_RETURN(bbs_node_clear_line(node));
Expand All @@ -1243,20 +1214,9 @@ static int node_intro(struct bbs_node *node)
* We do it here rather than in bbs_authenticate, because the SSH module can do native login
* where bbs_node_logged_in will be true right above here.
* So doing it here ensures that, no matter how authentication happened, we run the code. */

/* Make some basic variables available that can be used in menus.conf scripting
* For example, something in the menu could say Welcome ${BBS_USERNAME}!
*/
bbs_node_var_set_fmt(node, "BBS_NODENUM", "%d", node->id);
bbs_node_var_set_fmt(node, "BBS_USERID", "%d", node->user->id);
bbs_node_var_set_fmt(node, "BBS_USERPRIV", "%d", node->user->priv);
bbs_node_var_set(node, "BBS_USERNAME", bbs_username(node->user));
bbs_user_init_vars(node); /* Set any custom variables for this user */

/*! \todo Notify user's friends that s/he's logged on now */
/*! \todo Notify the sysop (sysop console), via BELL, that a new user has logged in, if and only if the sysop console is idle */

NEG_RETURN(bbs_node_writef(node, COLOR_RESET "\r\n"));
if (bbs_event_dispatch(node, EVENT_NODE_INTERACTIVE_LOGIN)) {
return -1;
}
return 0;
}

Expand Down Expand Up @@ -1288,66 +1248,15 @@ int bbs_node_statuses(struct bbs_node *node, const char *username)
return 0;
}

static int bbs_node_splash(struct bbs_node *node)
{
node->menu = "welcome"; /* Not really a menu, but it's a page and we should give it a name */
NEG_RETURN(bbs_node_clear_screen(node));

#if 0
NEG_RETURN(bbs_node_writef(node, "%sLast few callers:\n\n", COLOR(COLOR_PRIMARY)));
/*! \todo Finish this: need to be able to retrieve past authentication info, e.g. from DB */
#endif

/* System stats */
if (!NODE_IS_TDD(node)) {
NEG_RETURN(bbs_node_writef(node, "%s%-20s: %s%s\n", COLOR(COLOR_SECONDARY), "System", COLOR(COLOR_PRIMARY), bbs_name_buf));
NEG_RETURN(bbs_node_writef(node, "%s%6s%s %4u%9s%s: %s%s\n", COLOR(COLOR_SECONDARY), "User #", COLOR(COLOR_PRIMARY), node->user->id, "", COLOR(COLOR_SECONDARY), COLOR(COLOR_PRIMARY), bbs_username(node->user)));
} else {
/* Omit the # sign since TDDs display # as $ */
NEG_RETURN(bbs_node_writef(node, "User %d - %s\n", node->user->id, bbs_username(node->user)));
}

/*! \todo Add more stats here, e.g. num logins today, since started, lifetime, etc. */

if (bbs_starttime() > (int) minuptimedisplayed) {
char timebuf[24];
time_t now = time(NULL);
print_time_elapsed(bbs_starttime(), now, timebuf, sizeof(timebuf)); /* Formatting for timebuf (11 chars) should be enough for 11 years uptime, I think that's good enough */
if (!NODE_IS_TDD(node)) {
char daysbuf[36];
print_days_elapsed(bbs_starttime(), now, daysbuf, sizeof(daysbuf));
NEG_RETURN(bbs_node_writef(node, "%s%6s%s %2s%-11s%s: %s%s\n", COLOR(COLOR_SECONDARY), "Uptime", COLOR(COLOR_PRIMARY), "", timebuf, COLOR(COLOR_SECONDARY), COLOR(COLOR_PRIMARY), daysbuf));
} else {
NEG_RETURN(bbs_node_writef(node, "Uptime %s\n", timebuf)); /* Only print the condensed uptime */
}
}

#if 0
/*! \todo Finish these and make them work */
NEG_RETURN(bbs_node_writef(node, "%s%-20s: %s%5d %s%-9s%s%6d%s%s\n", COLOR(COLOR_SECONDARY), "Logons Today", COLOR(COLOR_PRIMARY), 1, COLOR(COLOR_SECONDARY), "(Max ", COLOR(COLOR_PRIMARY), 22, COLOR(COLOR_SECONDARY), ")"));
NEG_RETURN(bbs_node_writef(node, "%s%-20s: %s%5d %s%-9s%s%6d%s%s\n", COLOR(COLOR_SECONDARY), "Time on Today", COLOR(COLOR_PRIMARY), 26, COLOR(COLOR_SECONDARY), "(Max ", COLOR(COLOR_PRIMARY), 86, COLOR(COLOR_SECONDARY), ")"));
NEG_RETURN(bbs_node_writef(node, "%s%-20s: %s%5d %s%-9s%s%6d%s%s\n", COLOR(COLOR_SECONDARY), "Mail Waiting", COLOR(COLOR_PRIMARY), 0, COLOR(COLOR_SECONDARY), "(Unread ", COLOR(COLOR_PRIMARY), 0, COLOR(COLOR_SECONDARY), ")"));
#endif
if (!s_strlen_zero(bbs_sysop) && !NODE_IS_TDD(node)) {
NEG_RETURN(bbs_node_writef(node, "%s%-20s: %s%s\n", COLOR(COLOR_SECONDARY), "Sysop is", COLOR(COLOR_PRIMARY), bbs_sysop));
}

NEG_RETURN(bbs_node_writef(node, "\n")); /* Separation before next section */
if (!NODE_IS_TDD(node)) {
NEG_RETURN(bbs_node_statuses(node, NULL));
}
NEG_RETURN(bbs_node_wait_key(node, MIN_MS(2)));
return 0;
}

static int bbs_goodbye(struct bbs_node *node)
{
char sub[512];

NEG_RETURN(bbs_node_clear_screen(node));
bbs_node_substitute_vars(node, bbs_exitmsg, sub, sizeof(sub));
NEG_RETURN(bbs_node_writef(node, "%s", sub));
NEG_RETURN(bbs_node_wait_key(node, SEC_MS(12)));
if (!s_strlen_zero(bbs_exitmsg)) {
char sub[512];
bbs_node_substitute_vars(node, bbs_exitmsg, sub, sizeof(sub));
NEG_RETURN(bbs_node_writef(node, "%s", sub));
NEG_RETURN(bbs_node_wait_key(node, SEC_MS(12))); /* Give time to display message before session closes */
}
return 0;
}

Expand Down Expand Up @@ -1389,11 +1298,7 @@ static int node_handler_term(struct bbs_node *node)
/* Should be authenticated by now (either as a user or continuing as guest) */
bbs_assert(bbs_node_logged_in(node));

/* Display welcome updates and alerts */
if (bbs_node_splash(node)) {
bbs_debug(5, "Exiting\n");
return -1;
} else if (bbs_node_menuexec(node)) { /* Run the BBS on this node. */
if (bbs_node_menuexec(node)) { /* Run the BBS on this node. */
return -1;
}

Expand Down
19 changes: 11 additions & 8 deletions include/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,23 @@
enum bbs_event_type {
EVENT_STARTUP = 0,
EVENT_SHUTDOWN,
EVENT_NODE_SHORT_SESSION,
EVENT_NODE_ENCRYPTION_FAILED,
EVENT_NODE_LOGIN_FAILED,
EVENT_NODE_BAD_REQUEST,
EVENT_USER_REGISTRATION,
EVENT_USER_LOGIN,
EVENT_USER_LOGOFF,
EVENT_USER_PASSWORD_CHANGE,
EVENT_NODE_SHORT_SESSION, /*!< Extremely short node session (where abnormal) */
EVENT_NODE_ENCRYPTION_FAILED, /*!< TLS setup failed */
EVENT_NODE_LOGIN_FAILED, /*!< Authentication failed */
EVENT_NODE_BAD_REQUEST, /*!< Bad request received */
EVENT_NODE_INTERACTIVE_START, /*!< Interactive terminal session started */
EVENT_NODE_INTERACTIVE_LOGIN, /*!< Interactive terminal login */
EVENT_USER_REGISTRATION, /*!< New user registration */
EVENT_USER_LOGIN, /*!< Successful authentication (any protocol) */
EVENT_USER_LOGOFF, /*!< User logout (any protocol) */
EVENT_USER_PASSWORD_CHANGE, /*!< User password change */
};

struct bbs_event {
enum bbs_event_type type;
unsigned int nodenum;
unsigned int userid;
struct bbs_node *node; /*!< Only set for EVENT_NODE_INTERACTIVE_START and EVENT_NODE_INTERACTIVE_LOGIN */
char protname[10];
char username[64];
char ipaddr[64];
Expand Down
9 changes: 9 additions & 0 deletions include/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ unsigned int bbs_node_mod_count(void *mod);
*/
unsigned int bbs_max_nodenum(void);

/*! \brief Get the configured minimum uptime to display */
unsigned int bbs_min_uptime_threshold(void);

/*!
* \brief Get the configured idle timeout in ms
* \note Certain scenarios warrant using a custom or specified value,
Expand All @@ -139,6 +142,12 @@ const char *bbs_hostname(void);
/*! \brief Get configured BBS name */
const char *bbs_name(void);

/*! \brief Get configured BBS tagline */
const char *bbs_tagline(void);

/*! \brief Get configured BBS sysop */
const char *bbs_sysop(void);

/*!
* \brief Used by network comm drivers to request a BBS node
* \param fd Socket file descriptor
Expand Down
Loading

0 comments on commit 8ab0f7a

Please sign in to comment.