AmendHub

Download:

jcs

/

subtext

/

amendments

/

383

binkp: Rearrange the deck chairs again, use outbound folder

Instead of asking mail for pending deliveries, mail will just make
a fidopkt and hand it to binkp, which will then encode it and write
it to its outbox folder. At the next connection, scan the outbox
and send any files in it.
 
Also switch to a single binkp_connection instead of passing one
around. We're only going to do one connection at a time anyway.

jcs made amendment 383 about 1 year ago
--- binkp.c Wed Mar 8 10:10:54 2023 +++ binkp.c Thu Mar 9 10:15:04 2023 @@ -29,174 +29,134 @@ /* #define BINKP_DEBUG */ +static struct fidopkt_address *binkp_our_address; static struct binkp_connection *binkpc = NULL; -static Str255 binkp_dir, binkp_done_dir; +static Str255 binkp_inbox_dir, binkp_done_dir, binkp_outbox_dir; static short binkp_fidopkt_skipped, binkp_fidopkt_imported; static bool binkp_temp_fail = false; struct uthread *binkp_thread = NULL; -size_t binkp_send_frame(struct binkp_connection *conn, short command, - char *data, size_t data_size); -bool binkp_read_frame(struct binkp_connection *conn); -bool binkp_login(struct binkp_connection *conn); -void binkp_fetch(void); +void binkp_mkdir(Str255 *dir_str, char *suffix); +void binkp_sync_with_hub(void); +bool binkp_connect(void); +void binkp_free(void); +size_t binkp_send_frame(short command, char *data, size_t data_size); +bool binkp_read_frame(void); +bool binkp_login(void); void binkp_ingest(void); bool binkp_zip_decider(char *filename, size_t size); void binkp_fidopkt_processor(char *filename, unsigned char *data, size_t size); -bool binkp_ingest_post(struct fidopkt *fidopkt, struct board *board); -bool binkp_ingest_mail(struct fidopkt *fidopkt); size_t binkp_buffer_file(Str255 path, char **data); -bool binkp_send_buf_as_file(struct binkp_connection *conn, char *filename, - char *pkt_buf, size_t pkt_buf_size); +void binkp_deliver_inbox(void); +void binkp_deliver_outbox(void); void binkp_process(struct uthread *uthread, void *arg) { short newdirid, error; - binkp_thread = uthread; + if (!fidopkt_parse_address(db->config.fidonet_node_addr, + &binkp_our_address)) { + logger_printf("[binkp] failed parsing local FidoNet node address " + "\"%s\", fix in settings", db->config.fidonet_node_addr); + return; + } - /* make sure working dir is there */ - if (getpath(db->bile->vrefnum, db->bile->filename, &binkp_dir, - false) != 0) - panic("getpath failed on %s", PtoCstr(db->bile->filename)); - PtoCstr(binkp_dir); - strlcat((char *)binkp_dir, ":binkp", sizeof(binkp_dir)); - CtoPstr(binkp_dir); + binkp_thread = uthread; - if (!FIsDir(binkp_dir)) { - error = DirCreate(db->bile->vrefnum, 0, binkp_dir, &newdirid); - if (error) - panic("Failed creating %s: %d", PtoCstr(binkp_dir), error); - } - - if (!db->config.binkp_delete_done) { - /* and processed dir */ - if (getpath(db->bile->vrefnum, db->bile->filename, &binkp_done_dir, - false) != 0) - panic("getpath failed on %s", PtoCstr(db->bile->filename)); - PtoCstr(binkp_done_dir); - strlcat((char *)binkp_done_dir, ":binkp-processed", - sizeof(binkp_done_dir)); - CtoPstr(binkp_done_dir); + uthread_msleep(1000UL * 2); - if (!FIsDir(binkp_done_dir)) { - error = DirCreate(db->bile->vrefnum, 0, binkp_done_dir, - &newdirid); - if (error) - panic("Failed creating %s: %d", PtoCstr(binkp_dir), error); - } - } + binkp_mkdir(&binkp_inbox_dir, "inbox"); + if (!db->config.binkp_delete_done) + binkp_mkdir(&binkp_done_dir, "processed"); + binkp_mkdir(&binkp_outbox_dir, "outbox"); for (;;) { if (db->config.binkp_hostname[0] != '\0' && db->config.binkp_port != 0) - binkp_fetch(); - - binkp_ingest(); + binkp_sync_with_hub(); + + binkp_deliver_inbox(); - if (db->config.binkp_hostname[0] == '\0' || - db->config.binkp_port == 0) - /* no new ones are likely to show up, then */ + if (db->config.binkp_hostname[0] != '\0' && + db->config.binkp_port != 0 && + db->config.binkp_interval_seconds) + uthread_msleep(1000UL * db->config.binkp_interval_seconds); + else break; - - if (!db->config.binkp_interval_seconds) - break; - uthread_msleep(1000UL * db->config.binkp_interval_seconds); } binkp_thread = NULL; } void +binkp_mkdir(Str255 *dir_str, char *suffix) +{ + short error, id; + + if (getpath(db->bile->vrefnum, db->bile->filename, dir_str, false) != 0) + panic("getpath failed on %s", PtoCstr(db->bile->filename)); + PtoCstr(*dir_str); + snprintf((char *)*dir_str, sizeof(Str255), "%s:binkp-%s", *dir_str, + suffix); + CtoPstr(*dir_str); + + if (!FIsDir(*dir_str)) { + error = DirCreate(db->bile->vrefnum, 0, *dir_str, &id); + if (error) + panic("Failed creating %s: %d", PtoCstr(*dir_str), error); + } +} + +void binkp_atexit(void) { if (binkpc != NULL) - binkp_connection_free(&binkpc); + binkp_free(); } void -binkp_fetch(void) +binkp_sync_with_hub(void) { char filename[16]; - struct fidopkt_address *our_address = NULL; - size_t nmail_ids, n, pkt_buf_size; + size_t n, pkt_buf_size; char *pkt_buf; - unsigned long *mail_ids = NULL; unsigned long started = Time, elapsed; - - if (!fidopkt_parse_address(db->config.fidonet_node_addr, - &our_address)) { - logger_printf("[binkp] failed parsing local FidoNet node address " - "\"%s\", fix in settings", db->config.fidonet_node_addr); - return; - } - nmail_ids = mail_ids_needing_fidonet_dispatch(&mail_ids); - - binkpc = binkp_connect(db->config.binkp_hostname, - db->config.binkp_port); - if (!binkpc) { - xfree(&our_address); + binkp_connect(); + if (!binkpc) return; - } - if (!binkp_login(binkpc)) + if (!binkp_login()) goto done; while (binkpc != NULL && !binkpc->done_receiving) { - binkp_read_frame(binkpc); - if (binkpc == NULL) - break; + binkp_read_frame(); uthread_yield(); } - for (n = 0; n < nmail_ids; n++) { - pkt_buf_size = mail_encode_as_fidopkt(mail_ids[n], our_address, - &pkt_buf); - if (pkt_buf == NULL) { - logger_printf("[binkp] failed encoding mail %ld as FidoNet " - "packet", mail_ids[n]); - continue; - } - - snprintf(filename, sizeof(filename), "f%07lu.pkt", mail_ids[n]); - if (!binkp_send_buf_as_file(binkpc, filename, pkt_buf, - pkt_buf_size)) { - xfree(&pkt_buf); - binkpc->done_sending = true; - break; - } - - xfree(&pkt_buf); - - mail_mark_fidonet_dispatched(mail_ids[n]); - } + if (binkpc) + binkp_deliver_outbox(); - if (!binkp_send_frame(binkpc, BINKP_COMMAND_M_EOB, "", 0)) - logger_printf("[binkp] failed sending M_EOB"); - - binkpc->done_sending = true; - - _TCPClose(&binkpc->tcp_send_iopb, binkpc->tcp_stream, nil, nil, false); + if (binkpc) + _TCPClose(&binkpc->tcp_send_iopb, binkpc->tcp_stream, nil, nil, + false); elapsed = Time - started; logger_printf("[binkp] done transferring in %ld sec%s", elapsed, elapsed == 1 ? "" : "s"); done: - xfree(&our_address); - if (binkpc != NULL) - binkp_connection_free(&binkpc); + binkp_free(); } -struct binkp_connection * -binkp_connect(char *hostname, unsigned short port) +bool +binkp_connect(void) { - struct binkp_connection *conn; char ip_s[16]; + char *hostname; ip_addr local_ip, host_ip; tcp_port local_port; short error; @@ -204,36 +164,41 @@ binkp_connect(char *hostname, unsigned short port) if (_TCPInit() != noErr) panic("Failed initializing MacTCP"); - conn = xcalloc(sizeof(struct binkp_connection), 1); - if (conn == NULL) { + if (binkpc != NULL) + binkp_free(); + + binkpc = xmalloczero(sizeof(struct binkp_connection)); + if (binkpc == NULL) { logger_printf("[binkp] failed allocating connection of size %ld", sizeof(struct binkp_connection)); goto error; } - conn->buf_size = 1024; - conn->buf = xmalloc(conn->buf_size); - if (conn->buf == NULL) { + binkpc->buf_size = 1024; + binkpc->buf = xmalloc(binkpc->buf_size); + if (binkpc->buf == NULL) { logger_printf("[binkp] failed allocating connection buffer of " - "size %ld", conn->buf_size); + "size %ld", binkpc->buf_size); goto error; } - conn->tcp_buf_size = (4 * 1500) + conn->buf_size; - conn->tcp_buf = xmalloc(conn->tcp_buf_size); - if (conn->tcp_buf == NULL) { + binkpc->tcp_buf_size = (4 * 1500) + binkpc->buf_size; + binkpc->tcp_buf = xmalloc(binkpc->tcp_buf_size); + if (binkpc->tcp_buf == NULL) { logger_printf("[binkp] failed allocating TCP buffer of " - "size %ld", conn->tcp_buf_size); + "size %ld", binkpc->tcp_buf_size); goto error; } - - error = DNSResolveName(&hostname, &host_ip, uthread_yield); + + hostname = db->config.binkp_hostname; + error = DNSResolveName(&hostname, &host_ip, + uthread_yield); if (error) { logger_printf("[binkp] failed resolving binkp host %s: %d", - hostname, error); + db->config.binkp_hostname, error); goto error; } - error = _TCPCreate(&conn->tcp_send_iopb, &conn->tcp_stream, - (Ptr)conn->tcp_buf, conn->tcp_buf_size, nil, nil, nil, false); + error = _TCPCreate(&binkpc->tcp_send_iopb, &binkpc->tcp_stream, + (Ptr)binkpc->tcp_buf, binkpc->tcp_buf_size, nil, nil, nil, false); if (error) { logger_printf("[binkp] failed creating TCP stream: %d", error); goto error; @@ -242,81 +207,85 @@ binkp_connect(char *hostname, unsigned short port) long2ip(host_ip, (char *)&ip_s); logger_printf("[binkp] connecting to %s (%s) port %d", - hostname, ip_s, port); + db->config.binkp_hostname, ip_s, db->config.binkp_port); - error = _TCPActiveOpen(&conn->tcp_send_iopb, conn->tcp_stream, - host_ip, port, &local_ip, &local_port, nil, nil, false); - if (error) { + error = _TCPActiveOpen(&binkpc->tcp_send_iopb, binkpc->tcp_stream, + host_ip, db->config.binkp_port, &local_ip, &local_port, nil, nil, + true); + while (!error && binkpc->tcp_send_iopb.ioResult > 0) + uthread_yield(); + if (error || binkpc->tcp_send_iopb.ioResult != 0) { logger_printf("[binkp] failed connecting to %s (%s) port %d: %d", - hostname, ip_s, port, error); + db->config.binkp_hostname, ip_s, db->config.binkp_port, + binkpc->tcp_send_iopb.ioResult); goto error; } - return conn; + return true; error: - binkp_connection_free(&conn); - return NULL; + binkp_free(); + return false; } void -binkp_connection_free(struct binkp_connection **ptr) +binkp_free(void) { - struct binkp_connection *conn = *ptr; - - if (conn == NULL) + if (binkpc == NULL) return; - if (conn->tcp_stream) - _TCPRelease(&conn->tcp_send_iopb, conn->tcp_stream, nil, nil, + if (binkpc->tcp_stream) + _TCPRelease(&binkpc->tcp_send_iopb, binkpc->tcp_stream, nil, nil, false); - if (conn->tcp_buf != NULL) - xfree(&conn->tcp_buf); - if (conn->buf != NULL) - xfree(&conn->buf); + if (binkpc->tcp_buf != NULL) + xfree(&binkpc->tcp_buf); + if (binkpc->buf != NULL) + xfree(&binkpc->buf); - xfree(ptr); + xfree(&binkpc); } size_t -binkp_send_frame(struct binkp_connection *conn, short command, char *data, - size_t data_size) +binkp_send_frame(short command, char *data, size_t data_size) { u_int16_t flen; short error; - if (conn == NULL) + if (binkpc == NULL) return 0; - if (data_size + 2 + 1 > conn->buf_size) { - logger_printf("[binkp] binkp_send_frame: frame too large (%ld)", - data_size + 2 + 1); + flen = data_size + 2; + if (command != BINKP_DATA) + flen++; + if (flen > binkpc->buf_size) { + logger_printf("[binkp] binkp_send_frame: frame too large (%u)", + flen); return 0; } - while (conn->tcp_send_iopb.ioResult > 0) + while (binkpc->tcp_send_iopb.ioResult > 0) /* previous _TCPSend has not completed yet */ uthread_yield(); if (command == BINKP_DATA) { - conn->buf[0] = (data_size >> 8) & 0xff; - conn->buf[1] = data_size & 0xff; + binkpc->buf[0] = (data_size >> 8) & 0xff; + binkpc->buf[1] = data_size & 0xff; flen = data_size + 2; - memcpy(conn->buf + 2, data, data_size); + memcpy(binkpc->buf + 2, data, data_size); } else { - conn->buf[0] = (((data_size + 1) | 0x8000) >> 8) & 0xff; - conn->buf[1] = (data_size + 1) & 0xff; - conn->buf[2] = command; + binkpc->buf[0] = (((data_size + 1) | 0x8000) >> 8) & 0xff; + binkpc->buf[1] = (data_size + 1) & 0xff; + binkpc->buf[2] = command; flen = data_size + 3; - memcpy(conn->buf + 3, data, data_size); + memcpy(binkpc->buf + 3, data, data_size); /* not sent, just for debugging */ - conn->buf[3 + data_size] = '\0'; + binkpc->buf[3 + data_size] = '\0'; } - memset(&conn->tcp_wds, 0, sizeof(conn->tcp_wds)); - conn->tcp_wds[0].ptr = (Ptr)conn->buf; - conn->tcp_wds[0].length = flen; + memset(&binkpc->tcp_wds, 0, sizeof(binkpc->tcp_wds)); + binkpc->tcp_wds[0].ptr = (Ptr)binkpc->buf; + binkpc->tcp_wds[0].length = flen; #ifdef BINKP_DEBUG switch (command) { @@ -325,38 +294,39 @@ binkp_send_frame(struct binkp_connection *conn, short data_size); break; case BINKP_COMMAND_M_FILE: - logger_printf("[binkp] sending new file: %s", conn->buf + 3); + logger_printf("[binkp] sending new file: %s", binkpc->buf + 3); break; case BINKP_COMMAND_M_EOB: logger_printf("[binkp] sending EOB"); break; case BINKP_COMMAND_M_GOT: - logger_printf("[binkp] sending GOT for %s", conn->cur_file.filename); + logger_printf("[binkp] sending GOT for %s", + binkpc->cur_incoming_file.filename); break; case BINKP_DATA: logger_printf("[binkp] sending data of size %ld", data_size); break; default: logger_printf("[binkp] sending command %d of size %ld: %s", - command, data_size, conn->buf + 3); + command, data_size, binkpc->buf + 3); } #endif - error = _TCPSend(&conn->tcp_send_iopb, conn->tcp_stream, conn->tcp_wds, - nil, nil, false); + error = _TCPSend(&binkpc->tcp_send_iopb, binkpc->tcp_stream, + binkpc->tcp_wds, nil, nil, false); if (error) { logger_printf("[binkp] TCPSend of %d failed: %d", - conn->tcp_wds[0].length, error); + binkpc->tcp_wds[0].length, error); return 0; } uthread_yield(); - return conn->tcp_wds[0].length; + return binkpc->tcp_wds[0].length; } bool -binkp_read_frame(struct binkp_connection *conn) +binkp_read_frame(void) { char tmp[128]; size_t len, off, frame_data_read; @@ -364,345 +334,316 @@ binkp_read_frame(struct binkp_connection *conn) short error; Ptr read_dest; - if (conn == NULL) + if (binkpc == NULL) return false; - error = _TCPStatus(&conn->tcp_read_iopb, conn->tcp_stream, - &conn->tcp_status_pb, nil, nil, false); + error = _TCPStatus(&binkpc->tcp_read_iopb, binkpc->tcp_stream, + &binkpc->tcp_status_pb, nil, nil, false); if (error) return false; - if (conn->tcp_status_pb.amtUnreadData < 2) + if (binkpc->tcp_status_pb.amtUnreadData < 2) return false; rlen = 2; - error = _TCPRcv(&conn->tcp_read_iopb, conn->tcp_stream, - (Ptr)&conn->cur_frame, &rlen, nil, nil, false); + error = _TCPRcv(&binkpc->tcp_read_iopb, binkpc->tcp_stream, + (Ptr)&binkpc->cur_frame, &rlen, nil, nil, false); if (error) return false; - if (conn->cur_frame.data_size == 0) { + if (binkpc->cur_frame.data_size == 0) { logger_printf("[binkp] binkp_read_frame: bogus frame, " "no data_size"); return false; } - conn->cur_frame.type = (conn->cur_frame.data_size & (1 << 15)) == 0 ? - BINKP_TYPE_DATA : BINKP_TYPE_COMMAND; - conn->cur_frame.data_size &= 0x7fff; + binkpc->cur_frame.type = + (binkpc->cur_frame.data_size & (1 << 15)) == 0 ? BINKP_TYPE_DATA : + BINKP_TYPE_COMMAND; + binkpc->cur_frame.data_size &= 0x7fff; frame_data_read = 0; - while (frame_data_read < conn->cur_frame.data_size) { - error = _TCPStatus(&conn->tcp_read_iopb, conn->tcp_stream, - &conn->tcp_status_pb, nil, nil, false); + while (frame_data_read < binkpc->cur_frame.data_size) { + error = _TCPStatus(&binkpc->tcp_read_iopb, binkpc->tcp_stream, + &binkpc->tcp_status_pb, nil, nil, false); if (error) goto failed_read; - if (conn->tcp_status_pb.amtUnreadData == 0) { + if (binkpc->tcp_status_pb.amtUnreadData == 0) { uthread_yield(); continue; } - if (conn->cur_frame.type == BINKP_TYPE_COMMAND) { - if (frame_data_read >= conn->buf_size) { + if (binkpc->cur_frame.type == BINKP_TYPE_COMMAND) { + if (frame_data_read >= binkpc->buf_size) { /* * Frame is too big but we can't overwrite buf since we * need the start of the frame, so just read into a junk * buffer and discard it */ read_dest = tmp; - rlen = MIN(conn->cur_frame.data_size - frame_data_read, + rlen = MIN(binkpc->cur_frame.data_size - frame_data_read, sizeof(tmp)); } else { - read_dest = conn->buf + frame_data_read; - rlen = MIN(conn->buf_size - frame_data_read, - conn->cur_frame.data_size - frame_data_read); + read_dest = binkpc->buf + frame_data_read; + rlen = MIN(binkpc->buf_size - frame_data_read, + binkpc->cur_frame.data_size - frame_data_read); } } else { - read_dest = conn->buf; - rlen = MIN(conn->cur_frame.data_size - frame_data_read, - conn->buf_size); + read_dest = binkpc->buf; + rlen = MIN(binkpc->cur_frame.data_size - frame_data_read, + binkpc->buf_size); } - rlen = MIN(rlen, conn->tcp_status_pb.amtUnreadData); + rlen = MIN(rlen, binkpc->tcp_status_pb.amtUnreadData); - error = _TCPRcv(&conn->tcp_read_iopb, conn->tcp_stream, + error = _TCPRcv(&binkpc->tcp_read_iopb, binkpc->tcp_stream, read_dest, &rlen, nil, nil, false); if (error) goto failed_read; frame_data_read += rlen; - if (conn->cur_frame.type == BINKP_TYPE_DATA) { - conn->cur_file.data_read += rlen; + if (binkpc->cur_frame.type == BINKP_TYPE_DATA) { + binkpc->cur_incoming_file.data_read += rlen; #ifdef BINKP_DEBUG logger_printf("[binkp] read %d TCP chunk (%ld / %d)", - rlen, frame_data_read, conn->cur_frame.data_size); + rlen, frame_data_read, binkpc->cur_frame.data_size); #endif - if (conn->cur_file.frefnum == 0) - panic("no frefnum for data, bogus state"); + if (binkpc->cur_incoming_file.frefnum == 0) + panic("binkpc: no frefnum for data, bogus state"); len = rlen; - error = FSWrite(conn->cur_file.frefnum, &len, conn->buf); + error = FSWrite(binkpc->cur_incoming_file.frefnum, &len, + binkpc->buf); if (error) { - logger_printf("[binkp] error writing %d to %s: %d", - rlen, PtoCstr(conn->cur_file.pfilename), error); - CtoPstr(conn->cur_file.pfilename); - conn->done_receiving = conn->done_sending = true; + logger_printf("[binkp] error writing %u to %s: %d", + rlen, PtoCstr(binkpc->cur_incoming_file.pfilename), + error); + CtoPstr(binkpc->cur_incoming_file.pfilename); + binkpc->done_receiving = binkpc->done_sending = true; goto failed_read; } } } - if (frame_data_read > conn->cur_frame.data_size) + if (frame_data_read > binkpc->cur_frame.data_size) panic("binkp data overread"); - if (conn->cur_frame.type == BINKP_TYPE_COMMAND) { - conn->cur_frame.command_id = conn->buf[0]; - if (frame_data_read < conn->buf_size) - conn->buf[frame_data_read] = '\0'; + if (binkpc->cur_frame.type == BINKP_TYPE_COMMAND) { + binkpc->cur_frame.command_id = binkpc->buf[0]; + if (frame_data_read < binkpc->buf_size) + binkpc->buf[frame_data_read] = '\0'; else - conn->buf[conn->buf_size - 1] = '\0'; + binkpc->buf[binkpc->buf_size - 1] = '\0'; #ifdef BINKP_DEBUG logger_printf("[binkp] read command 0x%x frame [%ld]: %s", - conn->cur_frame.command_id, - frame_data_read, conn->buf + (frame_data_read > 0 ? 1 : 0)); + binkpc->cur_frame.command_id, + frame_data_read, binkpc->buf + (frame_data_read > 0 ? 1 : 0)); #endif - switch (conn->cur_frame.command_id) { + switch (binkpc->cur_frame.command_id) { case BINKP_COMMAND_M_NUL: - if (strncmp(conn->buf + 1, "SYS ", 4) == 0) + if (strncmp(binkpc->buf + 1, "SYS ", 4) == 0) logger_printf("[binkp] connected to %s", - conn->buf + 1 + 4); + binkpc->buf + 1 + 4); break; case BINKP_COMMAND_M_FILE: - if (conn->cur_file.filename[0]) { + if (binkpc->cur_incoming_file.filename[0]) { logger_printf("[binkp] received M_FILE but not done " - "with file %s!", conn->cur_file.filename); - conn->cur_file.filename[0] = '\0'; - if (conn->cur_file.frefnum > 0) { - FSClose(conn->cur_file.frefnum); - conn->cur_file.frefnum = 0; + "with file %s!", binkpc->cur_incoming_file.filename); + binkpc->cur_incoming_file.filename[0] = '\0'; + if (binkpc->cur_incoming_file.frefnum > 0) { + FSClose(binkpc->cur_incoming_file.frefnum); + binkpc->cur_incoming_file.frefnum = 0; } } - if (sscanf(conn->buf + 1, "%128s %lu %lu %lu", - &conn->cur_file.filename, &conn->cur_file.size, - &conn->cur_file.mtime, &off) == 4) { - logger_printf("[binkp] new file \"%s\" size %ld", - conn->cur_file.filename, conn->cur_file.size); + if (sscanf(binkpc->buf + 1, "%128s %lu %lu %lu", + &binkpc->cur_incoming_file.filename, + &binkpc->cur_incoming_file.size, + &binkpc->cur_incoming_file.mtime, &off) == 4) { + logger_printf("[binkp] receiving file \"%s\" size %ld", + binkpc->cur_incoming_file.filename, + binkpc->cur_incoming_file.size); if (off != 0) logger_printf("[binkp] non-zero file fetch not " "supported"); - conn->cur_file.data_read = 0; + binkpc->cur_incoming_file.data_read = 0; - PtoCstr(binkp_dir); - snprintf((char *)conn->cur_file.pfilename, - sizeof(conn->cur_file.pfilename), - "%s:%s", binkp_dir, conn->cur_file.filename); - CtoPstr(binkp_dir); - CtoPstr(conn->cur_file.pfilename); + PtoCstr(binkp_inbox_dir); + snprintf((char *)binkpc->cur_incoming_file.pfilename, + sizeof(binkpc->cur_incoming_file.pfilename), + "%s:%s", binkp_inbox_dir, + binkpc->cur_incoming_file.filename); + CtoPstr(binkp_inbox_dir); + CtoPstr(binkpc->cur_incoming_file.pfilename); - error = Create(conn->cur_file.pfilename, 0, + error = Create(binkpc->cur_incoming_file.pfilename, 0, SUBTEXT_CREATOR, 'BINK'); if (error == dupFNErr) { - FSDelete(conn->cur_file.pfilename, 0); - error = Create(conn->cur_file.pfilename, 0, + FSDelete(binkpc->cur_incoming_file.pfilename, 0); + error = Create(binkpc->cur_incoming_file.pfilename, 0, SUBTEXT_CREATOR, 'BINK'); } if (error) { warn("failed creating %s: %d", - PtoCstr(conn->cur_file.pfilename), error); - CtoPstr(conn->cur_file.pfilename); + PtoCstr(binkpc->cur_incoming_file.pfilename), error); + CtoPstr(binkpc->cur_incoming_file.pfilename); goto failed_read; } - error = FSOpen(conn->cur_file.pfilename, 0, - &conn->cur_file.frefnum); + error = FSOpen(binkpc->cur_incoming_file.pfilename, 0, + &binkpc->cur_incoming_file.frefnum); if (error) { warn("failed opening %s: %d", - PtoCstr(conn->cur_file.pfilename), error); - CtoPstr(conn->cur_file.pfilename); + PtoCstr(binkpc->cur_incoming_file.pfilename), error); + CtoPstr(binkpc->cur_incoming_file.pfilename); goto failed_read; } - len = conn->cur_file.size; - error = Allocate(conn->cur_file.frefnum, &len); + len = binkpc->cur_incoming_file.size; + error = Allocate(binkpc->cur_incoming_file.frefnum, &len); if (error) { warn("failed setting %s to size %ld: %d", - PtoCstr(conn->cur_file.pfilename), - conn->cur_file.size, error); - CtoPstr(conn->cur_file.pfilename); + PtoCstr(binkpc->cur_incoming_file.pfilename), + binkpc->cur_incoming_file.size, error); + CtoPstr(binkpc->cur_incoming_file.pfilename); } } else { logger_printf("[binkp] failed parsing M_FILE: %s", - conn->buf + 1); + binkpc->buf + 1); } break; case BINKP_COMMAND_M_EOB: - conn->done_receiving = true; + binkpc->done_receiving = true; break; case BINKP_COMMAND_M_ERR: - logger_printf("[binkp] error from remote: %s", conn->buf + 1); - conn->done_receiving = conn->done_sending = true; + logger_printf("[binkp] error from remote: %s", + binkpc->buf + 1); + binkpc->done_receiving = binkpc->done_sending = true; break; case BINKP_COMMAND_M_BSY: - logger_printf("[binkp] remote is busy: %s", conn->buf + 1); - conn->done_receiving = conn->done_sending = true; + logger_printf("[binkp] remote is busy: %s", binkpc->buf + 1); + binkpc->done_receiving = binkpc->done_sending = true; break; } } else { #ifdef BINKP_DEBUG logger_printf("[binkp] read %d data frame of file (%ld / %ld)", - conn->cur_frame.data_size, - conn->cur_file.data_read, conn->cur_file.size); + binkpc->cur_frame.data_size, + binkpc->cur_incoming_file.data_read, + binkpc->cur_incoming_file.size); #endif - if (conn->cur_file.data_read == conn->cur_file.size) { + if (binkpc->cur_incoming_file.data_read == + binkpc->cur_incoming_file.size) { #ifdef BINKP_DEBUG logger_printf("[binkp] done reading file %s (%ld)", - conn->cur_file.filename, conn->cur_file.size); + binkpc->cur_incoming_file.filename, + binkpc->cur_incoming_file.size); #endif - FSClose(conn->cur_file.frefnum); - conn->cur_file.frefnum = 0; + FSClose(binkpc->cur_incoming_file.frefnum); + binkpc->cur_incoming_file.frefnum = 0; len = snprintf(tmp, sizeof(tmp), "%s %lu %lu", - conn->cur_file.filename, conn->cur_file.size, - conn->cur_file.mtime); - if (!binkp_send_frame(conn, BINKP_COMMAND_M_GOT, tmp, len)) + binkpc->cur_incoming_file.filename, + binkpc->cur_incoming_file.size, + binkpc->cur_incoming_file.mtime); + if (!binkp_send_frame(BINKP_COMMAND_M_GOT, tmp, len)) logger_printf("[binkp] failed sending M_GOT %s", - conn->cur_file.filename); + binkpc->cur_incoming_file.filename); - conn->cur_file.filename[0] = '\0'; + binkpc->cur_incoming_file.filename[0] = '\0'; } } return true; failed_read: - if (conn->cur_file.frefnum > 0) { - FSClose(conn->cur_file.frefnum); - conn->cur_file.frefnum = 0; + if (binkpc->cur_incoming_file.frefnum > 0) { + FSClose(binkpc->cur_incoming_file.frefnum); + binkpc->cur_incoming_file.frefnum = 0; } - conn->done_receiving = conn->done_sending = true; + binkpc->done_receiving = binkpc->done_sending = true; return false; } bool -binkp_login(struct binkp_connection *conn) +binkp_login(void) { char command[50]; size_t len; - while (binkp_read_frame(conn)) + while (binkpc != NULL && binkp_read_frame()) ; len = snprintf(command, sizeof(command), "SYS %s", db->config.name); - if (!binkp_send_frame(conn, BINKP_COMMAND_M_NUL, command, len)) + if (!binkp_send_frame(BINKP_COMMAND_M_NUL, command, len)) return false; len = snprintf(command, sizeof(command), "LOC %s", db->config.location); - if (!binkp_send_frame(conn, BINKP_COMMAND_M_NUL, command, len)) + if (!binkp_send_frame(BINKP_COMMAND_M_NUL, command, len)) return false; len = snprintf(command, sizeof(command), "NDL 14400,TCP,BINKP"); - if (!binkp_send_frame(conn, BINKP_COMMAND_M_NUL, command, len)) + if (!binkp_send_frame(BINKP_COMMAND_M_NUL, command, len)) return false; len = snprintf(command, sizeof(command), "VER Subtext/%s binkp/1.1", get_version(false)); - if (!binkp_send_frame(conn, BINKP_COMMAND_M_NUL, command, len)) + if (!binkp_send_frame(BINKP_COMMAND_M_NUL, command, len)) return false; - if (!binkp_send_frame(conn, BINKP_COMMAND_M_ADR, + if (!binkp_send_frame(BINKP_COMMAND_M_ADR, db->config.fidonet_node_addr, strlen(db->config.fidonet_node_addr))) return false; - if (!binkp_send_frame(conn, BINKP_COMMAND_M_PWD, - db->config.binkp_password, strlen(db->config.binkp_password))) + if (!binkp_send_frame(BINKP_COMMAND_M_PWD, db->config.binkp_password, + strlen(db->config.binkp_password))) return false; - for (;;) { - if (!conn) - return false; - - if (!binkp_read_frame(conn)) { + while (binkpc) { + if (!binkp_read_frame()) { uthread_yield(); continue; } - if (conn->cur_frame.type != BINKP_TYPE_COMMAND) + if (binkpc->cur_frame.type != BINKP_TYPE_COMMAND) continue; - if (conn->cur_frame.command_id == BINKP_COMMAND_M_OK) { - logger_printf("[binkp] logged in successfully as %s", + if (binkpc->cur_frame.command_id == BINKP_COMMAND_M_ERR) { + logger_printf("[binkp] login as %s failed, disconnecting", db->config.fidonet_node_addr); - return true; + binkp_free(); + return false; } - if (conn->cur_frame.command_id == BINKP_COMMAND_M_ERR) { - logger_printf("[binkp] login as %s failed, disconnecting", + if (binkpc->cur_frame.command_id == BINKP_COMMAND_M_OK) { + logger_printf("[binkp] logged in successfully as %s", db->config.fidonet_node_addr); - binkp_connection_free(&conn); - return false; + return true; } } return false; } -bool -binkp_send_buf_as_file(struct binkp_connection *conn, char *filename, - char *pkt_buf, size_t pkt_buf_size) -{ - char command[50]; - size_t len; - - len = snprintf(command, sizeof(command), "%s %lu 1 0", filename, - pkt_buf_size); - if (!binkp_send_frame(conn, BINKP_COMMAND_M_FILE, command, len)) - return false; - - if (!binkp_send_frame(conn, BINKP_DATA, pkt_buf, pkt_buf_size)) - return false; - - for (;;) { - if (!binkp_read_frame(conn)) { - uthread_yield(); - continue; - } - - if (conn->cur_frame.type != BINKP_TYPE_COMMAND) - continue; - - if (conn->cur_frame.command_id == BINKP_COMMAND_M_GOT) { - logger_printf("[binkp] successfully sent file"); - return true; - } - - logger_printf("[binkp] unrecognized command in response to M_FILE"); - binkp_connection_free(&conn); - return false; - } - - return true; -} - void -binkp_ingest(void) +binkp_deliver_inbox(void) { CInfoPBRec cipbr = { 0 }; HFileInfo *fpb = (HFileInfo *)&cipbr; DirInfo *dpb = (DirInfo *)&cipbr; CMovePBRec cmpbr = { 0 }; - Str255 file_name_c, abs_path, done_abs_path; + Str255 file_name_c, path, done_path; short dir_id, error; unsigned long started = Time, elapsed; size_t data_size; char *data; fpb->ioVRefNum = 0; - fpb->ioNamePtr = (StringPtr)&binkp_dir; + fpb->ioNamePtr = (StringPtr)&binkp_inbox_dir; error = PBGetCatInfo(&cipbr, false); if (error) { logger_printf("[binkp] PBGetCatInfo on binkp dir failed: %d", @@ -727,21 +668,21 @@ binkp_ingest(void) PtoCstr(file_name_c); - PtoCstr(binkp_dir); - snprintf((char *)abs_path, sizeof(abs_path), "%s:%s", - binkp_dir, file_name_c); - logger_printf("[binkp] processing file %s", (char *)abs_path); - CtoPstr(abs_path); - CtoPstr(binkp_dir); + PtoCstr(binkp_inbox_dir); + snprintf((char *)path, sizeof(path), "%s:%s", + binkp_inbox_dir, file_name_c); + logger_printf("[binkp] processing file %s", (char *)path); + CtoPstr(path); + CtoPstr(binkp_inbox_dir); binkp_fidopkt_skipped = 0; binkp_fidopkt_imported = 0; - if (zip_is_zip_file(abs_path)) - zip_read_file(abs_path, binkp_zip_decider, + if (zip_is_zip_file(path)) + zip_read_file(path, binkp_zip_decider, binkp_fidopkt_processor); else if (strstr((char *)file_name_c, ".pkt")) { - data_size = binkp_buffer_file(abs_path, &data); + data_size = binkp_buffer_file(path, &data); if (data_size == 0) binkp_temp_fail = true; else { @@ -762,35 +703,35 @@ binkp_ingest(void) binkp_fidopkt_skipped); PtoCstr(binkp_done_dir); - snprintf((char *)done_abs_path, sizeof(done_abs_path), + snprintf((char *)done_path, sizeof(done_path), "%s:%s", binkp_done_dir, file_name_c); - CtoPstr(done_abs_path); + CtoPstr(done_path); CtoPstr(binkp_done_dir); if (db->config.binkp_delete_done) { - if ((error = FSDelete(done_abs_path, 0)) != 0) { + if ((error = FSDelete(done_path, 0)) != 0) { logger_printf("[binkp] failed deleting %s: %d", - PtoCstr(done_abs_path), error); + PtoCstr(done_path), error); break; } } else { try_rename: - cmpbr.ioNamePtr = abs_path; + cmpbr.ioNamePtr = path; cmpbr.ioNewName = binkp_done_dir; cmpbr.ioDirID = 0; cmpbr.ioNewDirID = 0; cmpbr.ioVRefNum = 0; error = PBCatMove(&cmpbr, false); if (error == dupFNErr) { - if ((error = FSDelete(done_abs_path, 0)) != 0) { + if ((error = FSDelete(done_path, 0)) != 0) { logger_printf("[binkp] failed deleting %s: %d", - PtoCstr(done_abs_path), error); + PtoCstr(done_path), error); break; } goto try_rename; } else if (error) { logger_printf("[binkp] failed moving %s to %s: %d", - PtoCstr(abs_path), PtoCstr(binkp_done_dir), error); + PtoCstr(path), PtoCstr(binkp_done_dir), error); CtoPstr(binkp_done_dir); break; } @@ -891,4 +832,203 @@ binkp_buffer_file(Str255 path, char **data) } return count; -} +} + +void +binkp_deliver_outbox(void) +{ + char command[50]; + CInfoPBRec cipbr = { 0 }; + HFileInfo *fpb = (HFileInfo *)&cipbr; + DirInfo *dpb = (DirInfo *)&cipbr; + CMovePBRec cmpbr = { 0 }; + Str255 file_name_c, path; + struct stat sb; + unsigned long started = Time, elapsed; + size_t len, data_size, fsize_left; + short dir_id, error, frefnum; + char *data = NULL; + + fpb->ioVRefNum = 0; + fpb->ioNamePtr = (StringPtr)&binkp_outbox_dir; + error = PBGetCatInfo(&cipbr, false); + if (error) { + logger_printf("[binkp] PBGetCatInfo on binkp outbox failed: %d", + error); + return; + } + dir_id = dpb->ioDrDirID; + + fpb->ioNamePtr = (StringPtr)&file_name_c; + for (;;) { + file_name_c[0] = 0; + fpb->ioDirID = dir_id; + /* + * Keep requesting the first item in the directory since we're + * deleting each file as we process it + */ + fpb->ioFDirIndex = 1; + + error = PBGetCatInfo(&cipbr, false); + if (error) + break; + + if (data == NULL) { + data = xmalloc(binkpc->buf_size); + if (data == NULL) { + logger_printf("[binkp] failed allocating outbound buffer " + "%lu", binkpc->buf_size); + return; + } + } + + PtoCstr(file_name_c); + + PtoCstr(binkp_outbox_dir); + snprintf((char *)path, sizeof(path), "%s:%s", + binkp_outbox_dir, file_name_c); + CtoPstr(path); + CtoPstr(binkp_outbox_dir); + + FStat(path, &sb); + + logger_printf("[binkp] sending file %s size %lu", file_name_c, + sb.st_size); + + /* just send 1 as unix mtime */ + len = snprintf(command, sizeof(command), "%s %lu 1 0", file_name_c, + sb.st_size); + if (!binkp_send_frame(BINKP_COMMAND_M_FILE, command, len)) + goto done; + + error = FSOpen(path, 0, &frefnum); + if (error) { + warn("binkp: failed opening %s: %d", PtoCstr(path), error); + goto done; + } + + for (fsize_left = sb.st_size; fsize_left != 0; ) { + /* leave 2 bytes for size */ + len = MIN(fsize_left, binkpc->buf_size - 2); + + error = FSRead(frefnum, &len, data); + if (error && error != eofErr) { + warn("binkp: error reading from %s: %d", PtoCstr(path), + error); + goto done; + } + + if (!binkp_send_frame(BINKP_DATA, data, len)) + goto done; + + fsize_left -= len; + } + + FSClose(frefnum); + frefnum = 0; + + /* wait for frame */ + while (binkpc != NULL && !binkp_read_frame()) { + uthread_yield(); + continue; + } + + if (!binkpc) { + logger_printf("[binkp] connection lost waiting for M_GOT"); + goto done; + } + + if (binkpc->cur_frame.type != BINKP_TYPE_COMMAND || + binkpc->cur_frame.command_id != BINKP_COMMAND_M_GOT) { + logger_printf("[binkp] got unexpected response to sending " + "file"); + goto done; + } + + logger_printf("[binkp] successfully sent file %s", file_name_c); + + error = FSDelete(path, 0); + if (error) { + logger_printf("[binkp] failed deleting file %s: %d", + PtoCstr(path), error); + goto done; + } + } + + if (!binkp_send_frame(BINKP_COMMAND_M_EOB, "", 0)) + logger_printf("[binkp] failed sending M_EOB"); + + if (binkpc) + binkpc->done_sending = true; + +done: + if (data) + xfree(&data); + if (frefnum) + FSClose(frefnum); +} + +bool +binkp_store_outbound_fidopkt(struct fidopkt *pkt) +{ + Str255 path; + char filename[32]; + char *buf = NULL; + short error, frefnum; + size_t size, asize; + bool ret = false; + + size = fidopkt_encode(pkt, &buf, db->config.fidonet_pkt_password, + db->config.timezone_utcoff); + if (size == 0) + return false; + + snprintf(filename, sizeof(filename), "%c%07lx.pkt", + pkt->area[0] ? 'b' : 'm', pkt->msgid.id & 0x0fffffff); + + PtoCstr(binkp_outbox_dir); + snprintf((char *)path, sizeof(path), "%s:%s", binkp_outbox_dir, + filename); + CtoPstr(binkp_outbox_dir); + CtoPstr(path); + + error = Create(path, 0, SUBTEXT_CREATOR, FIDONET_SPOOL_PACKET_TYPE); + if (error == dupFNErr) { + warn("binkp: collision saving packet to %s", PtoCstr(path)); + goto done; + } + if (error) { + warn("binkp: failed creating %s: %d", PtoCstr(path), error); + goto done; + } + + error = FSOpen(path, 0, &frefnum); + if (error) { + warn("binkp: failed opening newly created %s: %d", PtoCstr(path), + error); + goto done; + } + + asize = size; + error = Allocate(frefnum, &asize); + if (error) { + warn("binkp: failed setting %s to size %ld: %d", PtoCstr(path), + size, error); + goto done; + } + + error = FSWrite(frefnum, &size, buf); + if (error) { + logger_printf("[binkp] error writing %lu to %s: %d", + size, PtoCstr(path), error); + goto done; + } + + ret = true; + +done: + if (frefnum) + FSClose(frefnum); + xfree(&buf); + return ret; +} --- binkp.h Mon Mar 6 21:09:38 2023 +++ binkp.h Wed Mar 8 16:22:05 2023 @@ -63,16 +63,14 @@ struct binkp_connection { char *buf; size_t buf_size; struct binkp_frame cur_frame; - struct binkp_file cur_file; + struct binkp_file cur_incoming_file; bool done_receiving; bool done_sending; }; extern struct uthread *binkp_thread; void binkp_process(struct uthread *uthread, void *arg); - -struct binkp_connection * binkp_connect(char *, unsigned short); -void binkp_connection_free(struct binkp_connection **); void binkp_atexit(void); +bool binkp_store_outbound_fidopkt(struct fidopkt *pkt); #endif