jcs
/subtext
/amendments
/390
board: Add FidoNet replying/posting
jcs made amendment 390 about 1 year ago
--- board.c Tue Mar 7 22:34:45 2023
+++ board.c Fri Mar 10 14:03:28 2023
@@ -21,6 +21,7 @@
#include "subtext.h"
#include "ansi.h"
+#include "binkp.h"
#include "board.h"
#include "logger.h"
#include "user.h"
@@ -105,8 +106,6 @@ const struct bile_object_field board_fidonet_post_obje
member_size(struct board_fidonet_post, id), -1 },
{ offsetof(struct board_fidonet_post, msgid),
member_size(struct board_fidonet_post, msgid), -1 },
- { offsetof(struct board_fidonet_post, need_dispatch),
- member_size(struct board_fidonet_post, need_dispatch), -1 },
{ offsetof(struct board_fidonet_post, time),
member_size(struct board_fidonet_post, time), -1 },
{ offsetof(struct board_fidonet_post, from),
@@ -149,7 +148,10 @@ const size_t nboard_thread_object_fields = nitems(boar
unsigned long board_compose(struct session *s, struct board *board,
struct board_thread *thread, struct board_post *parent_post,
- char *initial_subject, char *initial_body);
+ struct board_fidonet_post *fidonet_parent_post, char *initial_subject,
+ char *initial_body);
+short board_post_create(struct board *board, struct board_thread *thread,
+ struct board_fidonet_post *fidonet_parent_post, struct board_post *post);
void board_list_posts(struct session *s, struct board *board,
size_t npost_Ids, unsigned long *post_ids, size_t page, size_t pages);
short board_post_read(struct session *s, struct board *board,
@@ -169,6 +171,7 @@ board_list_fidonet_boards(struct session *s)
};
struct board *fboards = NULL, tboard;
size_t nfboards;
+ char prompt[] = "FidoNet";
char c;
short bn, n, i, j;
bool done, show_list, show_help;
@@ -220,7 +223,7 @@ board_list_fidonet_boards(struct session *s)
show_list = false;
}
- c = session_menu(s, "FidoNet Boards", "FidoNet", opts,
+ c = session_menu(s, "FidoNet Boards", prompt, opts,
nitems(opts), show_help, "Board #", &bn);
show_help = false;
@@ -234,7 +237,7 @@ board_list_fidonet_boards(struct session *s)
session_flush(s);
break;
}
- board_show(s, fboards[bn - 1].id, "FidoNet");
+ board_show(s, fboards[bn - 1].id, prompt);
break;
case '?':
show_help = true;
@@ -329,7 +332,7 @@ handle_opt:
show_list = true;
break;
case 'p':
- if (board_compose(s, board, NULL, NULL, NULL, NULL)) {
+ if (board_compose(s, board, NULL, NULL, NULL, NULL, NULL)) {
find_post_ids = true;
show_list = true;
}
@@ -532,7 +535,8 @@ board_list_posts(struct session *s, struct board *boar
unsigned long
board_compose(struct session *s, struct board *board,
struct board_thread *thread, struct board_post *parent_post,
- char *initial_subject, char *initial_body)
+ struct board_fidonet_post *fidonet_parent_post, char *initial_subject,
+ char *initial_body)
{
struct board_post post = { 0 };
char *tmp = NULL;
@@ -546,7 +550,7 @@ board_compose(struct session *s, struct board *board,
}
if (board->restricted_posting && !s->user->is_sysop) {
- session_printf(s, "Posting is not available on this board.\r\n");
+ session_printf(s, "Posting to this board is not permitted.\r\n");
session_flush(s);
return 0;
}
@@ -579,6 +583,11 @@ post_compose_start:
session_printf(s, "{{B}}Subject:{{/B}}{{#}} Re: %s\r\n",
thread->subject);
session_flush(s);
+ } else if (fidonet_parent_post) {
+ session_printf(s, "{{B}}Subject:{{/B}}{{#}} %s%s\r\n",
+ strncmp("Re:", fidonet_parent_post->subject, 3) == 1 ?
+ "" : "Re: ", fidonet_parent_post->subject);
+ session_flush(s);
} else {
if (initial_subject && !thread->subject) {
thread->subject = xstrdup(initial_subject);
@@ -662,7 +671,8 @@ post_compose_start:
session_printf(s, "Posting message... ");
session_flush(s);
- if (board_post_create(board, thread, &post) == 0) {
+ if (board_post_create(board, thread, fidonet_parent_post,
+ &post) == 0) {
session_logf(s, "Posted message %ld to %s", post.id,
board->name);
session_printf(s, "done\r\n");
@@ -725,7 +735,7 @@ board_post_read(struct session *s, struct board *board
short ret = POST_READ_RETURN_DONE;
char c;
char *data, *subject;
- short cc;
+ short cc, bcret;
bool done = false, show_help = false;
dopts = xmalloc(sizeof(opts));
@@ -866,7 +876,14 @@ board_post_read(struct session *s, struct board *board
}
break;
case 'r':
- if (board_compose(s, board, &thread, &post, NULL, NULL)) {
+ if (board->fidonet_area[0])
+ bcret = board_compose(s, board, NULL, NULL, &fpost, NULL,
+ NULL);
+ else
+ bcret = board_compose(s, board, &thread, &post, NULL, NULL,
+ NULL);
+
+ if (bcret) {
ret = POST_READ_RETURN_FIND;
done = true;
}
@@ -956,91 +973,215 @@ board_find_post_ids(struct session *s, struct board *b
short
board_post_create(struct board *board, struct board_thread *thread,
- struct board_post *post)
+ struct board_fidonet_post *fidonet_parent_post, struct board_post *post)
{
+ struct board_fidonet_post fidonet_post = { 0 };
+ struct fidopkt pkt = { 0 };
+ struct username_cache *user;
+ struct fidopkt_address our_address, hub_address;
+ struct bile_object *o;
short ret;
char *data;
- size_t size, insert;
+ size_t size, insert, npost_ids;
ssize_t n, j;
unsigned long *post_ids, *parent_post_ids;
-
- if (post->parent_post_id == 0) {
- thread->thread_id = bile_next_id(board->bile, BOARD_THREAD_RTYPE);
- post->thread_id = thread->thread_id;
- }
-
- post->id = bile_next_id(board->bile, BOARD_POST_RTYPE);
- if (!post->time)
- post->time = Time;
- ret = bile_marshall_object(board->bile, board_post_object_fields,
- nboard_post_object_fields, post, &data, &size);
- if (ret != 0 || size == 0) {
- warn("failed to marshall new post object");
- post->id = 0;
- goto done;
- }
- if (bile_write(board->bile, BOARD_POST_RTYPE, post->id, data,
- size) != size) {
- warn("bile_write of new post failed! %d", bile_error(board->bile));
- post->id = 0;
- xfree(&data);
- goto done;
- }
- xfree(&data);
-
- if (post->time > thread->last_post_at)
- thread->last_post_at = post->time;
- thread->nposts++;
- post_ids = xreallocarray(thread->post_ids, thread->nposts,
- sizeof(long));
- if (post_ids == NULL)
- return 0;
- thread->post_ids == post_ids;
- parent_post_ids = xreallocarray(thread->parent_post_ids,
- thread->nposts, sizeof(long));
- if (parent_post_ids == NULL)
- return 0;
- thread->parent_post_ids = parent_post_ids;
-
- /*
- * Add new post id to thread post_ids, but put it in the right
- * place so that reading post_ids will present the tree in order.
- * Walk parent_post_ids and find the first match of our parent,
- * then insert our new post there. This puts newest replies at
- * the top.
- */
+ if (board->fidonet_area[0]) {
+ post->id = bile_next_id(board->bile, BOARD_FIDONET_POST_RTYPE);
+
+ if (!post->time)
+ post->time = Time;
- insert = thread->nposts - 1;
- for (n = 0; n < thread->nposts - 1; n++) {
- if (thread->post_ids[n] != post->parent_post_id)
- continue;
+ if (!fidopkt_parse_address(db->config.fidonet_node_addr,
+ &our_address)) {
+ logger_printf("[board] invalid fidonet address, can't "
+ "create board post");
+ post->id = 0;
+ goto done;
+ }
+ if (!fidopkt_parse_address(db->config.fidonet_hub_addr,
+ &hub_address)) {
+ logger_printf("[board] invalid fidonet hub address, can't "
+ "create board post");
+ post->id = 0;
+ goto done;
+ }
- for (j = thread->nposts - 2; j > n; j--) {
- thread->post_ids[j + 1] = thread->post_ids[j];
- thread->parent_post_ids[j + 1] = thread->parent_post_ids[j];
+ fidonet_post.id = post->id;
+ fidonet_post.time = post->time;
+
+ if (fidonet_parent_post) {
+ snprintf(fidonet_post.subject, sizeof(fidonet_post.subject),
+ "%s%s",
+ strncmp("Re:", fidonet_parent_post->subject, 3) == 1 ?
+ "" : "Re: ",
+ fidonet_parent_post->subject);
+ strlcpy(fidonet_post.reply, fidonet_parent_post->msgid_orig,
+ sizeof(fidonet_post.reply));
+ strlcpy(fidonet_post.to, fidonet_parent_post->from,
+ sizeof(fidonet_post.to));
+ } else {
+ strlcpy(fidonet_post.subject, thread->subject,
+ sizeof(fidonet_post.subject));
+ strlcpy(fidonet_post.to, "All", sizeof(fidonet_post.to));
}
- insert = n + 1;
- break;
- }
- thread->post_ids[insert] = post->id;
- thread->parent_post_ids[insert] = post->parent_post_id;
+
+ user = user_username(post->sender_user_id);
+ if (user == NULL) {
+ warn("can't find username of user posting new message?");
+ post->id = 0;
+ goto done;
+ }
+ strlcpy(fidonet_post.from, user->username,
+ sizeof(fidonet_post.from));
+
+ fidonet_post.body = post->body;
+ fidonet_post.body_size = post->body_size;
+
+ /* make each board's posts have ids unique to our zone/net/node */
+ fidonet_post.msgid.id = (board->id << 16) | post->id;
+ fidonet_post.msgid.zone = our_address.zone;
+ fidonet_post.msgid.net = our_address.net;
+ fidonet_post.msgid.node = our_address.node;
+ fidonet_post.msgid.point = our_address.point;
+
+ snprintf(fidonet_post.origin, sizeof(fidonet_post.origin),
+ "%s | %s (%s)",
+ db->config.name, db->config.hostname,
+ db->config.fidonet_node_addr);
+
+ pkt.time = fidonet_post.time;
+ memcpy(&pkt.orig, &our_address, sizeof(pkt.orig));
+ memcpy(&pkt.dest, &hub_address, sizeof(pkt.dest));
+ strlcpy(pkt.area, board->fidonet_area, sizeof(pkt.area));
+ strlcpy(pkt.to, fidonet_post.to, sizeof(pkt.to));
+ strlcpy(pkt.from, fidonet_post.from, sizeof(pkt.from));
+ strlcpy(pkt.subject, fidonet_post.subject, sizeof(pkt.subject));
+ pkt.body = fidonet_post.body;
+ pkt.body_len = fidonet_post.body_size - 1;
+ strlcpy(pkt.reply, fidonet_post.reply, sizeof(pkt.reply));
+ memcpy(&pkt.msgid, &fidonet_post.msgid, sizeof(pkt.msgid));
+ strlcpy(pkt.origin, fidonet_post.origin, sizeof(pkt.origin));
+
+ if (!binkp_store_outbound_fidopkt(&pkt)) {
+ warn("failed storing outbound fidopkt");
+ post->id = 0;
+ goto done;
+ }
+
+ ret = bile_marshall_object(board->bile,
+ board_fidonet_post_object_fields,
+ nboard_fidonet_post_object_fields, &fidonet_post, &data, &size);
+ if (ret != 0 || size == 0) {
+ warn("failed to marshall new fidonet post object");
+ post->id = 0;
+ goto done;
+ }
+ if (bile_write(board->bile, BOARD_FIDONET_POST_RTYPE,
+ fidonet_post.id, data, size) != size) {
+ warn("bile_write of new post failed! %d",
+ bile_error(board->bile));
+ post->id = 0;
+ xfree(&data);
+ goto done;
+ }
+ xfree(&data);
+
+ /* assume our post is now the newest, prepend its id */
+ o = bile_find(board->bile, BOARD_SORTED_IDS_RTYPE, 1);
+ size = (o ? o->size : 0) + sizeof(unsigned long);
+ npost_ids = (o ? (o->size / sizeof(unsigned long)) : 0) + 1;
+ post_ids = xmalloc(size);
+ if (post_ids == NULL)
+ goto done;
+ if (o)
+ bile_read(board->bile, BOARD_SORTED_IDS_RTYPE, 1,
+ post_ids + sizeof(unsigned long), o->size);
+ post_ids[0] = post->id;
+ bile_write(board->bile, BOARD_SORTED_IDS_RTYPE, 1, post_ids,
+ size);
+ } else {
+ if (!post->time)
+ post->time = Time;
+
+ if (post->parent_post_id == 0) {
+ thread->thread_id = bile_next_id(board->bile,
+ BOARD_THREAD_RTYPE);
+ post->thread_id = thread->thread_id;
+ }
+
+ ret = bile_marshall_object(board->bile, board_post_object_fields,
+ nboard_post_object_fields, post, &data, &size);
+ if (ret != 0 || size == 0) {
+ warn("failed to marshall new post object");
+ post->id = 0;
+ goto done;
+ }
+ if (bile_write(board->bile, BOARD_POST_RTYPE, post->id, data,
+ size) != size) {
+ warn("bile_write of new post failed! %d",
+ bile_error(board->bile));
+ post->id = 0;
+ xfree(&data);
+ goto done;
+ }
+ xfree(&data);
+
+ if (post->time > thread->last_post_at)
+ thread->last_post_at = post->time;
+ thread->nposts++;
+ post_ids = xreallocarray(thread->post_ids, thread->nposts,
+ sizeof(long));
+ if (post_ids == NULL)
+ return 0;
+ thread->post_ids == post_ids;
+ parent_post_ids = xreallocarray(thread->parent_post_ids,
+ thread->nposts, sizeof(long));
+ if (parent_post_ids == NULL)
+ return 0;
+ thread->parent_post_ids = parent_post_ids;
+
+ /*
+ * Add new post id to thread post_ids, but put it in the right
+ * place so that reading post_ids will present the tree in order.
+ * Walk parent_post_ids and find the first match of our parent,
+ * then insert our new post there. This puts newest replies at
+ * the top.
+ */
- ret = bile_marshall_object(board->bile, board_thread_object_fields,
- nboard_thread_object_fields, thread, &data, &size);
- if (ret != 0 || size == 0) {
- warn("failed to marshall thread object");
- post->id = 0;
- goto done;
- }
- if (bile_write(board->bile, BOARD_THREAD_RTYPE, thread->thread_id,
- data, size) != size) {
- warn("bile_write of thread failed! %d", bile_error(board->bile));
- post->id = 0;
+ insert = thread->nposts - 1;
+ for (n = 0; n < thread->nposts - 1; n++) {
+ if (thread->post_ids[n] != post->parent_post_id)
+ continue;
+
+ for (j = thread->nposts - 2; j > n; j--) {
+ thread->post_ids[j + 1] = thread->post_ids[j];
+ thread->parent_post_ids[j + 1] =
+ thread->parent_post_ids[j];
+ }
+ insert = n + 1;
+ break;
+ }
+ thread->post_ids[insert] = post->id;
+ thread->parent_post_ids[insert] = post->parent_post_id;
+
+ ret = bile_marshall_object(board->bile, board_thread_object_fields,
+ nboard_thread_object_fields, thread, &data, &size);
+ if (ret != 0 || size == 0) {
+ warn("failed to marshall thread object");
+ post->id = 0;
+ goto done;
+ }
+ if (bile_write(board->bile, BOARD_THREAD_RTYPE, thread->thread_id,
+ data, size) != size) {
+ warn("bile_write of thread failed! %d",
+ bile_error(board->bile));
+ post->id = 0;
+ xfree(&data);
+ goto done;
+ }
xfree(&data);
- goto done;
}
- xfree(&data);
bile_flush(board->bile, true);
@@ -1399,10 +1540,9 @@ board_ingest_fidopkt(struct board *board, struct fidop
}
memset(&post, 0, sizeof(post));
- post.time = fidopkt->time -
- ((db->config.timezone_utcoff * 60 * 60) / 100);
- post.body_size = fidopkt->message_len + 1;
- post.body = fidopkt->message;
+ post.time = fidopkt->time;
+ post.body_size = fidopkt->body_len + 1;
+ post.body = fidopkt->body;
strlcpy(post.reply, fidopkt->reply, sizeof(post.reply));
strlcpy(post.from, fidopkt->from, sizeof(post.from));
strlcpy(post.subject, fidopkt->subject, sizeof(post.subject));
--- board.h Tue Mar 7 20:44:42 2023
+++ board.h Thu Mar 9 15:27:08 2023
@@ -57,7 +57,6 @@ extern const size_t nboard_post_object_fields;
struct board_fidonet_post {
unsigned long id;
struct fidopkt_msgid msgid;
- short need_dispatch;
time_t time;
char from[32];
char subject[80];
@@ -85,8 +84,6 @@ extern const size_t nboard_thread_object_fields;
void board_list_fidonet_boards(struct session *s);
void board_show(struct session *s, short id, char *prompt_prefix);
-short board_post_create(struct board *board, struct board_thread *thread,
- struct board_post *post);
void board_delete_post(struct session *s, struct board *board,
struct board_post *post, struct board_thread *thread);
void board_delete_fidonet_post(struct session *s, struct board *board,