From 8a3e8a2f6e82ce5c683475d0c1e63abf09bfed4c Mon Sep 17 00:00:00 2001 From: Andrew Pamment Date: Sat, 27 Oct 2018 22:32:21 +1000 Subject: [PATCH] Initial commit of QWK Scan --- src/bluewave.c | 4 +- src/mail_menu.c | 11 +- src/www_msgs.c | 3 + utils/qwknet/Makefile | 10 +- utils/qwknet/qwk.h | 4 +- utils/qwknet/qwk.ini | 4 +- utils/qwknet/qwkscan.c | 377 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 399 insertions(+), 14 deletions(-) create mode 100644 utils/qwknet/qwkscan.c diff --git a/src/bluewave.c b/src/bluewave.c index a81f500..37f1995 100644 --- a/src/bluewave.c +++ b/src/bluewave.c @@ -1082,8 +1082,8 @@ void bwave_upload_reply() { snprintf(originlinebuffer, sizeof originlinebuffer, "\r--- %s\r * Origin: %s (@%d)\r", upl_hdr.reader_tear, tagline, mc->maginode); } else if (mc->nettype == NETWORK_QWK) { - snprintf(originlinebuffer, sizeof originlinebuffer, "\r--- $s\r * Origin: %s (%s)\r", - upl_hdr.reader_tear, tagline, conf.bwave_name); + snprintf(originlinebuffer, sizeof originlinebuffer, "\r---\r \xFE MagickaBBS \xFE %s\r", + tagline); } else { snprintf(originlinebuffer, sizeof originlinebuffer, "\r"); } diff --git a/src/mail_menu.c b/src/mail_menu.c index ead0702..b640bd2 100644 --- a/src/mail_menu.c +++ b/src/mail_menu.c @@ -469,9 +469,8 @@ char *external_editor(struct user_record *user, char *to, char *from, char *quot VERSION_MAJOR, VERSION_MINOR, VERSION_STR, name.sysname, name.machine, tagline, mc->maginode); } else if (mc->nettype == NETWORK_QWK && !email) { - snprintf(buffer, sizeof buffer, "\r--- MagickaBBS v%d.%d%s (%s/%s)\r * Origin: %s (%s)\r", - VERSION_MAJOR, VERSION_MINOR, VERSION_STR, name.sysname, name.machine, tagline, - conf.bwave_name); + snprintf(buffer, sizeof buffer, "\r---\r \xFE MagickaBBS \xFE %s\r", + tagline); } else { snprintf(buffer, sizeof buffer, "\r"); } @@ -608,10 +607,8 @@ char *editor(struct user_record *user, char *quote, int quotelen, char *from, in VERSION_MAJOR, VERSION_MINOR, VERSION_STR, name.sysname, name.machine, tagline, mc->maginode); } else if (mc->nettype == NETWORK_QWK && !email) { - snprintf(buffer, sizeof buffer, - "\r--- MagickaBBS v%d.%d%s (%s/%s)\r * Origin: %s (%s)\r", - VERSION_MAJOR, VERSION_MINOR, VERSION_STR, name.sysname, name.machine, tagline, - conf.bwave_name); + snprintf(buffer, sizeof buffer, "\r---\r \xFE MagickaBBS \xFE %s\r", + tagline); } else { strlcpy(buffer, "\r", sizeof buffer); } diff --git a/src/www_msgs.c b/src/www_msgs.c index 165eb38..9366597 100644 --- a/src/www_msgs.c +++ b/src/www_msgs.c @@ -1114,6 +1114,9 @@ int www_send_msg(struct user_record *user, char *to, char *subj, int conference, } else if (mc->nettype == NETWORK_MAGI) { snprintf(buffer, sizeof buffer, "\r\r--- MagickaBBS v%d.%d%s (%s/%s)\r * Origin: %s (@%d)\r", VERSION_MAJOR, VERSION_MINOR, VERSION_STR, name.sysname, name.machine, tagline, mc->maginode); + } else if (mc->nettype == NETWORK_QWK) { + snprintf(buffer, sizeof buffer, "\r---\r \xFE MagickaBBS \xFE %s\r", + tagline); } else { snprintf(buffer, sizeof buffer, "\r"); } diff --git a/utils/qwknet/Makefile b/utils/qwknet/Makefile index 8eb2f33..74b2eb9 100644 --- a/utils/qwknet/Makefile +++ b/utils/qwknet/Makefile @@ -1,10 +1,11 @@ CC=cc CFLAGS=-I/usr/local/include -ggdb -DEPS = qwktoss.c +DEPS = qwktoss.c qwkscan.c JAMLIB = ../../deps/jamlib/jamlib.a OBJ = qwktoss.o ../../src/inih/ini.o +SOBJ = qwkscan.o ../../src/inih/ini.o -all: qwktoss +all: qwktoss qwkscan %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) @@ -14,7 +15,10 @@ $(JAMLIB): qwktoss: $(OBJ) $(JAMLIB) $(CC) -o qwktoss $^ $(CFLAGS) -L/usr/local/lib - + +qwkscan: $(SOBJ) $(JAMLIB) + $(CC) -o qwkscan $^ $(CFLAGS) -L/usr/local/lib + .PHONY: clean clean: diff --git a/utils/qwknet/qwk.h b/utils/qwknet/qwk.h index a24ffbe..fb99fa5 100644 --- a/utils/qwknet/qwk.h +++ b/utils/qwknet/qwk.h @@ -12,5 +12,7 @@ struct QwkHeader { unsigned char Msglive; /* Message active status*/ unsigned char Msgarealo; /* Lo-byte message area */ unsigned char Msgareahi; /* Hi-byte message area */ - unsigned char Msgfiller[3]; /* Filler bytes */ + unsigned char Msgofflo; + unsigned char Msgoffhi; + unsigned char Msgtagp; } __attribute__((packed)); \ No newline at end of file diff --git a/utils/qwknet/qwk.ini b/utils/qwknet/qwk.ini index 5e2c2ce..2f22317 100644 --- a/utils/qwknet/qwk.ini +++ b/utils/qwknet/qwk.ini @@ -1,6 +1,8 @@ [Main] +Host = SANDWICH Message Path = /home/andrew/MagickaBBS/msgs/dovenet Inbound = /home/andrew/MagickaBBS/qwk/in Outbound = /home/andrew/MagickaBBS/qwk/out Temp Dir = /home/andrew/MagickaBBS/qwm/Temp -Unpack Command = unzip -j -o *a -d *d \ No newline at end of file +Unpack Command = unzip -j -o *a -d *d +Pack Command = zip -j *a *f diff --git a/utils/qwknet/qwkscan.c b/utils/qwknet/qwkscan.c new file mode 100644 index 0000000..bbc19af --- /dev/null +++ b/utils/qwknet/qwkscan.c @@ -0,0 +1,377 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qwk.h" +#include "../../deps/jamlib/jam.h" +#include "../../src/inih/ini.h" + +char *outbound_path; +char *message_base_path; +char *temp_dir; +char *pack_cmd; +char *config_file; +char *hostid; + +int bases_exists = 0; + +struct msg_bases { + int baseno; + char *path; +}; + +struct msg_bases **msgbases; +int msgbasecount = 0; + +int recursive_delete(const char *dir) { + int ret = 0; + FTS *ftsp = NULL; + FTSENT *curr; + + char *files[] = { (char *) dir, NULL }; + + ftsp = fts_open(files, FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV, NULL); + if (!ftsp) { + fprintf(stderr, "%s: fts_open failed: %s\n", dir, strerror(errno)); + ret = -1; + goto finish; + } + + while ((curr = fts_read(ftsp))) { + switch (curr->fts_info) { + case FTS_NS: + case FTS_DNR: + case FTS_ERR: + fprintf(stderr, "%s: fts_read error: %s\n", curr->fts_accpath, strerror(curr->fts_errno)); + break; + + case FTS_DC: + case FTS_DOT: + case FTS_NSOK: + break; + + case FTS_D: + break; + + case FTS_DP: + case FTS_F: + case FTS_SL: + case FTS_SLNONE: + case FTS_DEFAULT: + if (remove(curr->fts_accpath) < 0) { + fprintf(stderr, "%s: Failed to remove: %s", curr->fts_path, strerror(errno)); + ret = -1; + } + break; + } + } + +finish: + if (ftsp) { + fts_close(ftsp); + } + + return ret; +} + +s_JamBase *open_jam_base(char *path) { + int ret; + s_JamBase *jb; + + ret = JAM_OpenMB((char *)path, &jb); + + if (ret != 0) { + if (ret == JAM_IO_ERROR) { + free(jb); + ret = JAM_CreateMB((char *)path, 1, &jb); + if (ret != 0) { + free(jb); + return NULL; + } + } else { + free(jb); + return NULL; + } + } + return jb; +} + +static int handler(void* user, const char* section, const char* name, + const char* value) +{ + if (strcasecmp(section, "main") == 0) { + if (strcasecmp(name, "message path") == 0) { + message_base_path = strdup(value); + } else if (strcasecmp(name, "outbound") == 0) { + outbound_path = strdup(value); + } else if (strcasecmp(name, "temp dir") == 0) { + temp_dir = strdup(value); + } else if (strcasecmp(name, "pack command") == 0) { + pack_cmd = strdup(value); + } else if (strcasecmp(name, "host") == 0) { + hostid = strdup(value); + } + } else if (strcasecmp(section, "bases") == 0) { + bases_exists = 1; + if (msgbasecount == 0) { + msgbases = (struct msg_bases **)malloc(sizeof(struct msg_bases *)); + } else { + msgbases = (struct msg_bases **)realloc(msgbases, sizeof(struct msg_bases *) * (msgbasecount + 1)); + } + + msgbases[msgbasecount] = (struct msg_bases *)malloc(sizeof(struct msg_bases)); + + msgbases[msgbasecount]->baseno = atoi(name); + msgbases[msgbasecount]->path = strdup(value); + msgbasecount++; + } + return 1; +} + +int export_messages(int baseno, char *basefilename, int qwkidx) { + int msgcount = 0; + s_JamBase *jb; + s_JamBaseHeader jbh; + s_JamMsgHeader jmh; + s_JamSubPacket* jsp; + s_JamSubfield jsf; + int i; + int z; + int len; + int lenbytes; + char buffer[PATH_MAX]; + struct QwkHeader qh; + struct tm msgtm; + FILE *fptr; + char text[128]; + char *msgbuf; + char *msgptr; + + snprintf(buffer, PATH_MAX, "%s/%s", message_base_path, basefilename); + + jb = open_jam_base(buffer); + if (jb) { + JAM_ReadMBHeader(jb, &jbh); + if (jbh.ActiveMsgs > 0) { + for (i=0;iNumFields;z++) { + if (jsp->Fields[z]->LoID == JAMSFLD_SUBJECT) { + if (jsp->Fields[z]->DatLen > 24) { + len = 24; + } else { + len = jsp->Fields[z]->DatLen; + } + memset(qh.MsgSubj, 0, 25); + memcpy(qh.MsgSubj, jsp->Fields[z]->Buffer, len); + } + if (jsp->Fields[z]->LoID == JAMSFLD_SENDERNAME) { + if (jsp->Fields[z]->DatLen > 24) { + len = 24; + } else { + len = jsp->Fields[z]->DatLen; + } + memset(qh.MsgFrom, 0, 25); + memcpy(qh.MsgFrom, jsp->Fields[z]->Buffer, len); + } + if (jsp->Fields[z]->LoID == JAMSFLD_RECVRNAME) { + if (jsp->Fields[z]->DatLen > 24) { + len = 24; + } else { + len = jsp->Fields[z]->DatLen; + } + memset(qh.MsgTo, 0, 25); + memcpy(qh.MsgTo, jsp->Fields[z]->Buffer, len); + } + } + qh.Msgstat = ' '; + snprintf(buffer, 7, "%d", baseno); + memset(qh.Msgnum, ' ', 7); + memcpy(qh.Msgnum, buffer, strlen(buffer)); + + localtime_r(&jmh.DateWritten, &msgtm); + + snprintf(buffer, PATH_MAX, "%02d-%02d-%02d", msgtm.tm_mon + 1, msgtm.tm_mday, msgtm.tm_year - 100); + memcpy(qh.Msgdate, buffer, 8); + + snprintf(buffer, PATH_MAX, "%02d:%02d", msgtm.tm_hour, msgtm.tm_min); + memcpy(qh.Msgtime, buffer, 5); + + memset(qh.Msgpass, ' ', 12); + memset(qh.Msgrply, ' ', 8); + + len = jmh.TxtLen / 128 + 2; + lenbytes = len * 128; + + msgbuf = (char *)malloc(lenbytes); + + memset(msgbuf, '\0', lenbytes); + + JAM_ReadMsgText(jb, jmh.TxtOffset, jmh.TxtLen, msgbuf); + + msgptr = msgbuf; + while (*msgptr != '\0') { + if (*msgptr == '\r') { + *msgptr = '\xe3'; + } + msgptr++; + } + + msgptr = msgbuf + lenbytes; + while (*msgptr == '\0') { + *msgptr = ' '; + msgptr--; + } + + snprintf(buffer, 7, "%d", len); + memset(qh.Msgrecs, ' ', 6); + memcpy(qh.Msgrecs, buffer, strlen(buffer)); + + qh.Msglive = 0xE1; + qh.Msgarealo = baseno & 0xff; + qh.Msgareahi = (baseno >> 8) & 0xff; + + qh.Msgoffhi = ((qwkidx + msgcount + 1) >> 8) & 0xff; + qh.Msgofflo = (qwkidx + msgcount + 1) & 0xff; + + qh.Msgtagp = '*'; + + + snprintf(buffer, PATH_MAX, "%s/%s.MSG", temp_dir, hostid); + fptr = fopen(buffer, "r+"); + if (!fptr) { + fptr = fopen(buffer, "w"); + if (!fptr) { + memset(text, ' ', 128); + memcpy(text, hostid, strlen(hostid)); + fwrite(text, 128, 1, fptr); + } else { + fprintf(stderr, "UNABLE TO OPEN %s!!\n", buffer); + JAM_CloseMB(jb); + free(jb); + exit(-1); + } + } else { + fseek(fptr, 0, SEEK_END); + } + + fwrite(&qh, 128, 1, fptr); + fwrite(msgbuf, lenbytes - 128, 1, fptr); + fclose(fptr); + jmh.Attribute |= JAM_MSG_SENT; + while (1) { + z = JAM_LockMB(jb, 100); + if (z == 0) { + break; + } else if (z == JAM_LOCK_FAILED) { + sleep(1); + } else { + JAM_DelSubPacket(jsp); + JAM_CloseMB(jb); + free(jb); + fprintf(stderr, "Error locking JAM base!\n"); + exit(-1); + } + } + z =JAM_ChangeMsgHeader(jb, i, &jmh); + JAM_UnlockMB(jb); + JAM_DelSubPacket(jsp); + free(msgbuf); + msgcount++; + } + } + } + JAM_CloseMB(jb); + free(jb); + } + + return msgcount; +} + +int main(int argc, char **argv) { + int i; + message_base_path = NULL; + outbound_path = NULL; + temp_dir = NULL; + int qwkidx = 0; + int msgcount = 0; + char buffer[PATH_MAX]; + char archive[PATH_MAX]; + int ret; + if (argc < 2) { + fprintf(stderr, "Usage:\n ./qwkscan config.ini\n"); + return -1; + } + + config_file = argv[1]; + + if (ini_parse(config_file, handler, NULL) <0) { + fprintf(stderr, "Unable to load configuration ini (%s)!\n", config_file); + exit(-1); + } + + if (temp_dir == NULL || message_base_path == NULL || outbound_path == NULL) { + fprintf(stderr, "Outbound Path & Temp dir must both be set\n"); + exit(-1); + } + + for (i=0;ibaseno, msgbases[i]->path, qwkidx); + qwkidx += msgcount; + fprintf(stderr, "Exporting from base %d... %d exported\n", msgbases[i]->baseno, msgcount); + } + + snprintf(archive, PATH_MAX, "%s/%s.REP", outbound_path, hostid); + + char *b = buffer; + size_t blen = sizeof buffer; + for (const char *p = pack_cmd; *p != '\0' && blen >= 1; ++p) { + if (*p != '*') { + *b++ = *p; + --blen; + continue; + } + p++; + size_t alen = 0; + if (*p == 'a') { + strncpy(b, archive, blen); + alen = strlen(archive); + } else if (*p == 'f') { + snprintf(b, blen, "%s/%s.MSG", temp_dir, hostid); + alen = strlen(b); + } else if (*p == '*') { + *b++ = '*'; + alen = 1; + } + b += alen; + blen -= alen; + } + *b = '\0'; + + ret = system(buffer); + if (ret == -1 || ret >> 8 == 127) { + return -1; + } + recursive_delete(temp_dir); +} \ No newline at end of file