jcs
/subtext
/amendments
/250
*: Add Message of the Day support
Track the highest MOTD id each user has seen and only show it on
login if the current one is higher than the user's highest seen.
Also, in migrations, we can't iterate through users while modifying
each one, because the order will change as we save and write a new
user in the map.
jcs made amendment 250 over 2 years ago
--- db.c Mon Aug 1 13:02:28 2022
+++ db.c Tue Sep 13 23:49:37 2022
@@ -283,7 +283,7 @@ db_migrate(struct db *tdb, short is_new)
} else {
if (bile_read(tdb->bile, DB_VERS_RTYPE, 1, &ver, 1) != 1)
ver = 1;
-
+
if (ver == DB_CUR_VERS)
return 0;
@@ -298,20 +298,21 @@ db_migrate(struct db *tdb, short is_new)
case 1: {
/* 1->2, added user is_enabled field */
struct user user;
- struct bile_object *o;
- size_t nuser;
-
- nuser = 0;
- while ((o = bile_get_nth_of_type(tdb->bile, nuser, DB_USER_RTYPE))) {
+ size_t nusers, n;
+ unsigned long *ids = NULL;
+
+ nusers = bile_sorted_ids_by_type(tdb->bile, DB_USER_RTYPE,
+ &ids);
+ for (n = 0; n < nusers; n++) {
memset(&user, 0, sizeof(user));
- bile_read(tdb->bile, DB_USER_RTYPE, o->id, (char *)&user,
+ bile_read(tdb->bile, DB_USER_RTYPE, ids[n], (char *)&user,
sizeof(user));
user.is_enabled = DB_TRUE;
- bile_write(tdb->bile, DB_USER_RTYPE, o->id, (char *)&user,
+ bile_write(tdb->bile, DB_USER_RTYPE, ids[n], (char *)&user,
sizeof(user));
- xfree(&o);
- nuser++;
}
+ if (ids)
+ xfree(&ids);
break;
}
case 2: {
@@ -385,6 +386,26 @@ db_migrate(struct db *tdb, short is_new)
bile_write(tdb->bile, DB_CONFIG_RTYPE, 1, &new_config,
sizeof(new_config));
+ break;
+ }
+ case 8: {
+ /* 8->9, added user.last_motd_seen */
+ struct user user;
+ size_t nusers, n;
+ unsigned long *ids = NULL;
+
+ nusers = bile_sorted_ids_by_type(tdb->bile, DB_USER_RTYPE,
+ &ids);
+ for (n = 0; n < nusers; n++) {
+ memset(&user, 0, sizeof(user));
+ bile_read(tdb->bile, DB_USER_RTYPE, ids[n], (char *)&user,
+ sizeof(user));
+ user.last_motd_seen = 0;
+ bile_write(tdb->bile, DB_USER_RTYPE, ids[n], (char *)&user,
+ sizeof(user));
+ }
+ if (ids)
+ xfree(&ids);
break;
}
}
--- db.h Tue Jul 19 15:20:39 2022
+++ db.h Tue Sep 13 20:59:29 2022
@@ -23,7 +23,7 @@
#define DB_TYPE 'STDB'
-#define DB_CUR_VERS 8
+#define DB_CUR_VERS 9
#define DB_TRUE 0x100
#define DB_FALSE 0x000
@@ -34,6 +34,7 @@
#define DB_FOLDER_RTYPE 'FOLD'
#define DB_VERS_RTYPE 'VERS'
#define DB_MESSAGE_RTYPE 'PMSG'
+#define DB_MOTD_RTYPE 'MOTD'
#define DB_TEXT_TYPE 'TEXT'
#define DB_TEXT_MENU_ID 1
--- session.c Fri Jan 1 12:47:29 1904
+++ session.c Wed Sep 14 16:26:26 2022
@@ -199,6 +199,8 @@ session_run(struct uthread *uthread, void *arg)
session_flush(s);
uthread_yield();
+ session_print_motd(s, false);
+
main_menu:
session_output_view_or_printf(s, DB_TEXT_MENU_ID,
"\r\n[ Menu missing! ]\r\n\r\n");
@@ -251,6 +253,10 @@ get_another_char:
case 'M':
mail_menu(s);
break;
+ case 'o':
+ case 'O':
+ session_print_motd(s, true);
+ break;
case 'p':
case 'P':
if (s->user && s->user->is_sysop)
@@ -1285,6 +1291,48 @@ void
session_answer_page(struct session *s)
{
/* TODO */
+}
+
+void
+session_print_motd(struct session *s, bool force)
+{
+ struct bile_object *o;
+ unsigned long last_seen_motd = 0, motd_id = 0;
+ size_t size;
+ char *view = NULL, *output = NULL;
+
+ if (s->user)
+ last_seen_motd = s->user->last_motd_seen;
+
+ o = bile_get_nth_of_type(db->bile, 0, DB_MOTD_RTYPE);
+ motd_id = o->id;
+ if (o == NULL || (!force && motd_id <= last_seen_motd)) {
+ if (o)
+ xfree(&o);
+ return;
+ }
+
+ view = xmalloc(o->size + 1, "motd view");
+ size = bile_read_object(db->bile, o, view, o->size);
+ view[size] = '\0';
+ xfree(&o);
+
+ size = session_expand_template(s, view, &output);
+ xfree(&view);
+ if (!size)
+ return;
+
+ session_output(s, "\r\n", 2);
+ session_output(s, output, size);
+ session_output(s, "\r\n\r\n", 4);
+ xfree(&output);
+
+ session_pause_return(s, 0, "to continue...");
+
+ if (s->user && !force) {
+ s->user->last_motd_seen = motd_id;
+ user_save(s->user);
+ }
}
void
--- session.h Fri Jan 1 12:52:42 1904
+++ session.h Wed Sep 14 11:08:03 2022
@@ -141,6 +141,7 @@ size_t session_expand_template(struct session *session
char * session_field_input(struct session *session, unsigned short size,
unsigned short width, char *initial_input, bool multiline, char mask);
void session_pause_return(struct session *s, char enforce, char *msg);
+void session_print_motd(struct session *s, bool force);
void session_recents(struct session *s);
void session_who(struct session *s);
char session_menu(struct session *s, char *title, char *prompt,
--- sysop.c Fri Jan 1 02:06:04 1904
+++ sysop.c Wed Sep 14 11:09:13 2022
@@ -26,6 +26,7 @@
void sysop_edit_boards(struct session *s);
void sysop_edit_folders(struct session *s);
+void sysop_edit_motd(struct session *s);
void sysop_edit_users(struct session *s);
size_t sysop_find_user_ids(size_t nall_user_ids,
unsigned long *all_user_ids, unsigned long **user_ids, size_t offset,
@@ -36,6 +37,7 @@ void
sysop_menu(struct session *s)
{
static const struct session_menu_option opts[] = {
+ { 'm', "Mm", "Edit Message of the Day" },
{ 'b', "Bb", "Manage Boards" },
{ 'f', "Ff", "Manage File Folders" },
{ 'u', "Uu", "Manage Users" },
@@ -64,6 +66,9 @@ sysop_menu(struct session *s)
case 'f':
sysop_edit_folders(s);
break;
+ case 'm':
+ sysop_edit_motd(s);
+ break;
case 's':
sysop_edit_settings(s);
break;
@@ -345,6 +350,114 @@ sysop_edit_folders(struct session *s)
session_flush(s);
}
break;
+ case '?':
+ show_help = true;
+ break;
+ default:
+ done = true;
+ break;
+ }
+ }
+}
+
+void
+sysop_edit_motd(struct session *s)
+{
+ static const struct session_menu_option opts[] = {
+ { 'n', "Nn", "Create new MOTD" },
+ { 's', "Ss", "Show latest MOTD" },
+ { 'q', "QqXx", "Return to sysop menu" },
+ { '?', "?", "List menu options" },
+ };
+ char prompt[30];
+ struct session_menu_option *opt;
+ size_t n, size;
+ short ret;
+ char c, *data = NULL;
+ bool show_help = true;
+ bool done = false;
+ bool found = false;
+
+ while (!done && !s->ending) {
+ c = session_menu(s, "MOTD Editor", "Sysop:MOTD", opts,
+ nitems(opts), show_help);
+ show_help = false;
+
+ switch (c) {
+ case 's': {
+ session_print_motd(s, true);
+ break;
+ }
+ case 'n': {
+ char *motd = NULL, *tmp = NULL, c;
+ struct bile_object *old_motd;
+ unsigned long new_id;
+
+motd_write:
+ session_printf(s, "MOTD Text:\r\n");
+ session_flush(s);
+
+ tmp = session_field_input(s, 2048, s->terminal_columns - 1,
+ motd, true, 0);
+ session_output(s, "\r\n", 2);
+ session_flush(s);
+
+ rtrim(tmp, "\r\n\t ");
+
+ if (motd)
+ xfree(&motd);
+ motd = tmp;
+
+ session_printf(s, "\r\n{{B}}(S){{/B}}ave MOTD, "
+ "{{B}}(E){{/B}}dit again, or {{B}}(C){{/B}}ancel? ");
+ session_flush(s);
+
+ c = session_input_char(s);
+ if (c == 0 && s->obuflen > 0) {
+ s->node_funcs->output(s);
+ uthread_yield();
+ xfree(&motd);
+ break;
+ }
+
+ session_printf(s, "%c\r\n", c);
+ session_flush(s);
+
+ switch (c) {
+ case 's':
+ case 'S':
+ case 'y':
+ case '\n':
+ case '\r':
+ /* save */
+ session_printf(s, "Saving MOTD...");
+ session_flush(s);
+
+ new_id = bile_next_id(db->bile, DB_MOTD_RTYPE);
+ old_motd = bile_get_nth_of_type(db->bile, 0,
+ DB_MOTD_RTYPE);
+ if (old_motd) {
+ bile_delete(db->bile, DB_MOTD_RTYPE, old_motd->id);
+ xfree(&old_motd);
+ }
+ bile_write(db->bile, DB_MOTD_RTYPE, new_id, motd,
+ strlen(motd) + 1);
+
+ session_printf(s, " saved!\r\n");
+ session_flush(s);
+ break;
+ case 'e':
+ case 'E':
+ goto motd_write;
+ break;
+ case 'c':
+ case 'C':
+ case CONTROL_C:
+ xfree(&motd);
+ break;
+ }
+ break;
+ }
case '?':
show_help = true;
break;
--- user.h Mon Aug 1 09:59:33 2022
+++ user.h Tue Sep 13 20:57:14 2022
@@ -35,6 +35,7 @@ struct user {
unsigned long last_seen_at;
short is_sysop;
short is_enabled;
+ unsigned long last_motd_seen;
};
struct username_cache {