diff --git a/.gitignore b/.gitignore index af3bac6..e78d0b3 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,4 @@ deps/libuuid/configure deps/libuuid/Makefile.in deps/libuuid/aclocal.m4 deps/libuuid/ltmain.sh +utils/qwknet/qwktoss diff --git a/STRINGS.CHANGES b/STRINGS.CHANGES index 21e0d83..6f11691 100644 --- a/STRINGS.CHANGES +++ b/STRINGS.CHANGES @@ -23,6 +23,10 @@ LINE 289 NEW OLDSTRING: (NONE) NEWSTRING: "\e[2J\e[1;1H\e[1;32mFrom : \e[1;37m%s (@%d)\r\n" +LINE 290 NEW +OLDSTRING: (NONE) +NEWSTRING: "\e[2J\e[1;1H\e[1;32mFrom : \e[1;37m%s (%s)\r\n" + Changes from v0.9-alpha -> v0.10-alpha -------------------------------------------------------------- diff --git a/dist/magicka.strings b/dist/magicka.strings index 6c15e2f..8935029 100644 --- a/dist/magicka.strings +++ b/dist/magicka.strings @@ -287,3 +287,4 @@ Read Now ? (Y / N): \e[1;30m[\e[1;34;44m%5d\e[1;30;40m]\e[1;31m!\e[1;37m%-24.24s \e[1;32m%-15.15s \e[1;33m%-15.15s \e[1;35m%02d:%02d %02d-%02d-%02d\e[K\e[0m\r\n \e[1;30m[\e[1;34m%5d\e[1;30m]\e[1;31m!\e[1;37m%-24.24s \e[1;32m%-15.15s \e[1;33m%-15.15s \e[1;35m%02d:%02d %02d-%02d-%02d\e[K\e[0m\r\n \e[2J\e[1;1H\e[1;32mFrom : \e[1;37m%s (@%d)\r\n +\e[2J\e[1;1H\e[1;32mFrom : \e[1;37m%s (%s)\r\n diff --git a/src/bbs.h b/src/bbs.h index b4218fe..b871178 100644 --- a/src/bbs.h +++ b/src/bbs.h @@ -20,6 +20,7 @@ #define NETWORK_FIDO 1 #define NETWORK_WWIV 2 #define NETWORK_MAGI 3 +#define NETWORK_QWK 4 #define TYPE_LOCAL_AREA 0 #define TYPE_NETMAIL_AREA 1 @@ -82,7 +83,6 @@ struct mail_conference { int mail_area_count; struct mail_area **mail_areas; struct fido_addr *fidoaddr; - int wwivnode; int maginode; }; diff --git a/src/bluewave.c b/src/bluewave.c index e3189b9..cba3b40 100644 --- a/src/bluewave.c +++ b/src/bluewave.c @@ -695,6 +695,12 @@ int bwave_add_message(int confr, int area, unsigned int dwritten, char *to, char jsf.Buffer = (char *)buffer; JAM_PutSubfield(jsp, &jsf); jmh.MsgIdCRC = JAM_Crc32(buffer, strlen(buffer)); + } else if (conf.mail_conferences[confr]->nettype == NETWORK_QWK) { + jsf.LoID = JAMSFLD_OADDRESS; + jsf.HiID = 0; + jsf.DatLen = strlen(conf.bwave_name); + jsf.Buffer = (char *)conf.bwave_name; + JAM_PutSubfield(jsp, &jsf); } } else if (conf.mail_conferences[confr]->mail_areas[area]->type == TYPE_NETMAIL_AREA && conf.mail_conferences[confr]->nettype == NETWORK_FIDO) { jmh.Attribute |= JAM_MSG_TYPENET; @@ -1081,6 +1087,8 @@ void bwave_upload_reply() { } } else if (conf.mail_conferences[confr]->nettype == NETWORK_MAGI) { snprintf(originlinebuffer, 256, "\r--- %s\r * Origin: %s (@%d)\r", upl_hdr.reader_tear, tagline, conf.mail_conferences[confr]->maginode); + } else if (conf.mail_conferences[confr]->nettype == NETWORK_QWK) { + snprintf(originlinebuffer, 256, "\r--- $s\r * Origin: %s (%s)\r", upl_hdr.reader_tear, tagline, conf.bwave_name); } else { snprintf(originlinebuffer, 256, "\r"); } diff --git a/src/mail_menu.c b/src/mail_menu.c index 3c9605b..5c575e3 100644 --- a/src/mail_menu.c +++ b/src/mail_menu.c @@ -555,6 +555,8 @@ char *external_editor(struct user_record *user, char *to, char *from, char *quot } } else if (conf.mail_conferences[user->cur_mail_conf]->nettype == NETWORK_MAGI && !email) { snprintf(buffer, 256, "\r--- MagickaBBS v%d.%d%s (%s/%s)\r * Origin: %s (@%d)\r", VERSION_MAJOR, VERSION_MINOR, VERSION_STR, name.sysname, name.machine, tagline, conf.mail_conferences[user->cur_mail_conf]->maginode); + } else if (conf.mail_conferences[user->cur_mail_conf]->nettype == NETWORK_QWK && !email) { + snprintf(buffer, 256, "\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); } else { snprintf(buffer, 256, "\r"); } @@ -691,6 +693,8 @@ char *editor(struct user_record *user, char *quote, int quotelen, char *from, in } } else if (conf.mail_conferences[user->cur_mail_conf]->nettype == NETWORK_MAGI && !email) { snprintf(buffer, 256, "\r--- MagickaBBS v%d.%d%s (%s/%s)\r * Origin: %s (@%d)\r", VERSION_MAJOR, VERSION_MINOR, VERSION_STR, name.sysname, name.machine, tagline, conf.mail_conferences[user->cur_mail_conf]->maginode); + } else if (conf.mail_conferences[user->cur_mail_conf]->nettype == NETWORK_QWK && !email) { + snprintf(buffer, 256, "\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); } else { snprintf(buffer, 256, "\r"); } @@ -1581,6 +1585,8 @@ int read_message(struct user_record *user, struct msg_headers *msghs, int mailno free(from_addr); } else if (msghs->msgs[mailno]->oaddress != NULL && conf.mail_conferences[user->cur_mail_conf]->nettype == NETWORK_MAGI) { s_printf(get_string(288), msghs->msgs[mailno]->from, atoi(msghs->msgs[mailno]->oaddress)); + } else if (msghs->msgs[mailno]->oaddress != NULL && conf.mail_conferences[user->cur_mail_conf]->nettype == NETWORK_QWK) { + s_printf(get_string(289), msghs->msgs[mailno]->from, msghs->msgs[mailno]->oaddress); } else { s_printf(get_string(106), msghs->msgs[mailno]->from); } @@ -1872,6 +1878,12 @@ int read_message(struct user_record *user, struct msg_headers *msghs, int mailno JAM_PutSubfield(jsp, &jsf); jmh.ReplyCRC = JAM_Crc32(buffer, strlen(buffer)); } + } else if (conf.mail_conferences[user->cur_mail_conf]->nettype == NETWORK_QWK) { + jsf.LoID = JAMSFLD_OADDRESS; + jsf.HiID = 0; + jsf.DatLen = strlen(conf.bwave_name); + jsf.Buffer = (char *)conf.bwave_name; + JAM_PutSubfield(jsp, &jsf); } } else if (conf.mail_conferences[user->cur_mail_conf]->mail_areas[user->cur_mail_area]->type == TYPE_NETMAIL_AREA) { jmh.Attribute |= JAM_MSG_TYPENET; @@ -2327,9 +2339,14 @@ void post_message(struct user_record *user) { JAM_PutSubfield(jsp, &jsf); jmh.MsgIdCRC = JAM_Crc32(buffer, strlen(buffer)); - } - } else - if (conf.mail_conferences[user->cur_mail_conf]->mail_areas[user->cur_mail_area]->type == TYPE_NETMAIL_AREA) { + } else if (conf.mail_conferences[user->cur_mail_conf]->nettype == NETWORK_QWK) { + jsf.LoID = JAMSFLD_OADDRESS; + jsf.HiID = 0; + jsf.DatLen = strlen(conf.bwave_name); + jsf.Buffer = (char *)conf.bwave_name; + JAM_PutSubfield(jsp, &jsf); + } + } else if (conf.mail_conferences[user->cur_mail_conf]->mail_areas[user->cur_mail_area]->type == TYPE_NETMAIL_AREA) { jmh.Attribute |= JAM_MSG_TYPENET; jmh.Attribute |= JAM_MSG_PRIVATE; if (conf.mail_conferences[user->cur_mail_conf]->nettype == NETWORK_FIDO) { diff --git a/src/main.c b/src/main.c index b61212b..68cbd7c 100644 --- a/src/main.c +++ b/src/main.c @@ -337,6 +337,8 @@ static int mail_area_handler(void* user, const char* section, const char* name, mc->nettype = NETWORK_FIDO; } else if (strcasecmp(value, "magi") == 0) { mc->nettype = NETWORK_MAGI; + } else if (strcasecmp(value, "qwk") == 0) { + mc->nettype = NETWORK_QWK; } } else if (strcasecmp(name, "fido node") == 0) { mc->fidoaddr = parse_fido_addr(value); diff --git a/utils/qwknet/Makefile b/utils/qwknet/Makefile new file mode 100644 index 0000000..8eb2f33 --- /dev/null +++ b/utils/qwknet/Makefile @@ -0,0 +1,21 @@ +CC=cc +CFLAGS=-I/usr/local/include -ggdb +DEPS = qwktoss.c +JAMLIB = ../../deps/jamlib/jamlib.a +OBJ = qwktoss.o ../../src/inih/ini.o + +all: qwktoss + +%.o: %.c $(DEPS) + $(CC) -c -o $@ $< $(CFLAGS) + +$(JAMLIB): + cd ../../deps/jamlib && make -f Makefile.linux + +qwktoss: $(OBJ) $(JAMLIB) + $(CC) -o qwktoss $^ $(CFLAGS) -L/usr/local/lib + +.PHONY: clean + +clean: + rm -f $(OBJ) qwktoss \ No newline at end of file diff --git a/utils/qwknet/qwk.h b/utils/qwknet/qwk.h new file mode 100644 index 0000000..a24ffbe --- /dev/null +++ b/utils/qwknet/qwk.h @@ -0,0 +1,16 @@ +struct QwkHeader { + unsigned char Msgstat; /* Message status */ + unsigned char Msgnum[7]; /* Message number */ + unsigned char Msgdate[8]; /* Message date MM-DD-YY*/ + unsigned char Msgtime[5]; /* Message time HH:MM */ + unsigned char MsgTo[25]; /* Message To: */ + unsigned char MsgFrom[25]; /* Message From: */ + unsigned char MsgSubj[25]; /* Message Subject: */ + unsigned char Msgpass[12]; /* Message password */ + unsigned char Msgrply[8]; /* Message reply to */ + unsigned char Msgrecs[6]; /* Length in records */ + 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 */ +} __attribute__((packed)); \ No newline at end of file diff --git a/utils/qwknet/qwk.ini b/utils/qwknet/qwk.ini new file mode 100644 index 0000000..5e2c2ce --- /dev/null +++ b/utils/qwknet/qwk.ini @@ -0,0 +1,6 @@ +[Main] +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 diff --git a/utils/qwknet/qwktoss.c b/utils/qwknet/qwktoss.c new file mode 100644 index 0000000..fd09c4c --- /dev/null +++ b/utils/qwknet/qwktoss.c @@ -0,0 +1,388 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qwk.h" +#include "../../deps/jamlib/jam.h" +#include "../../src/inih/ini.h" + +char *inbound_path; +char *message_base_path; +char *temp_dir; +char *unpack_cmd; + +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, "inbound") == 0) { + inbound_path = strdup(value); + } else if (strcasecmp(name, "temp dir") == 0) { + temp_dir = strdup(value); + } else if (strcasecmp(name, "unpack command") == 0) { + unpack_cmd = strdup(value); + } + } + return 1; +} + +size_t trimwhitespace(char *out, size_t len, const char *str) { + if(len == 0) + return 0; + + const char *end; + size_t out_size; + + // Trim trailing space + end = str + strlen(str) - 1; + while(end > str && isspace((unsigned char)*end)) end--; + end++; + + // Set output size to minimum of trimmed string length and buffer size minus 1 + out_size = (end - str) < len-1 ? (end - str) : len-1; + + // Copy trimmed string and add null terminator + memcpy(out, str, out_size); + out[out_size] = 0; + + return out_size; +} + +int process_msgs_dat(char *msgsdat) { + FILE *fptr; + char buffer[PATH_MAX]; + struct QwkHeader qhdr; + int msgrecs; + unsigned char *msgbody; + char mbuf[129]; + int i; + time_t msgdate; + struct tm thedate; + int year; + char msgto[26]; + char msgfrom[26]; + char msgsubj[26]; + unsigned int msgconf; + s_JamBase *jb; + s_JamMsgHeader jmh; + s_JamSubPacket* jsp; + s_JamSubfield jsf; + int z; + + snprintf(buffer, PATH_MAX, "%s/%s", temp_dir, msgsdat); + + fptr = fopen(buffer, "rb"); + + if (!fptr) { + return -1; + } + + fread(&qhdr, sizeof(struct QwkHeader), 1, fptr); + while (!feof(fptr)) { + if (fread(&qhdr, sizeof(struct QwkHeader), 1, fptr) != 1) { + break; + } + msgrecs = atoi(qhdr.Msgrecs); + msgbody = (char *)malloc((msgrecs * 128) + 1); + memset(msgbody, 0, (msgrecs * 128) + 1); + for (i=1;i> 8 == 127) { + return -1; + } + // process NDXs + tmpb = opendir(temp_dir); + if (!tmpb) { + fprintf(stderr, "Error opening temp directory\n"); + return -1; + } + while ((dent = readdir(tmpb)) != NULL) { + if (strcasecmp(dent->d_name, "messages.dat") == 0) { + // process tic file + ret = process_msgs_dat(dent->d_name); + } + } + closedir(tmpb); + + // delete temp dir + recursive_delete(temp_dir); + snprintf(buffer, PATH_MAX, "%s/%s", inbound_path, qwkfile); + remove(buffer); + return ret; +} + +int main(int argc, char **argv) { + // read ini file + DIR *inb; + struct dirent *dent; + + + message_base_path = NULL; + inbound_path = NULL; + temp_dir = NULL; + if (argc < 2) { + fprintf(stderr, "Usage:\n ./qwktoss config.ini\n"); + return -1; + } + + if (ini_parse(argv[1], handler, NULL) <0) { + fprintf(stderr, "Unable to load configuration ini (%s)!\n", argv[1]); + exit(-1); + } + + if (temp_dir == NULL || message_base_path == NULL || inbound_path == NULL) { + fprintf(stderr, "Message Base Path and Inbound Path must be set\n"); + exit(-1); + } + + // scan for QWK files + inb = opendir(inbound_path); + if (!inb) { + fprintf(stderr, "Error opening inbound directory\n"); + return -1; + } + while ((dent = readdir(inb)) != NULL) { + if (dent->d_name[strlen(dent->d_name) - 4] == '.' && + tolower(dent->d_name[strlen(dent->d_name) - 3]) == 'q' && + tolower(dent->d_name[strlen(dent->d_name) - 2]) == 'w' && + tolower(dent->d_name[strlen(dent->d_name) - 1]) == 'k' + ) { + // process qwk file + fprintf(stderr, "Processing QWK file %s\n", dent->d_name); + if (process_qwk_file(dent->d_name) != -1) { + + rewinddir(inb); + } + } + } + closedir(inb); + + return 0; +} \ No newline at end of file diff --git a/utils/ticproc/ticproc.c b/utils/ticproc/ticproc.c index c7b402d..47704f1 100644 --- a/utils/ticproc/ticproc.c +++ b/utils/ticproc/ticproc.c @@ -490,6 +490,12 @@ int main(int argc, char **argv) { conf.filearea_count = 0; conf.case_insensitve = 0; + + if (argc < 2) { + fprintf(stderr, "Usage: \n ./ticproc config.ini\n"); + return -1; + } + if (ini_parse(argv[1], handler, NULL) <0) { fprintf(stderr, "Unable to load configuration ini (%s)!\n", argv[1]); exit(-1);