Skip to content
Snippets Groups Projects
fmsgdump.c 4.58 KiB
Newer Older
rswindell's avatar
rswindell committed
// vi: tabstop=4

#include "gen_defs.h"
#include "fidodefs.h"
#include "dirwrap.h"    /* _PATH_DEVNULL */
rswindell's avatar
rswindell committed
#include <stdio.h>
#include <string.h>

FILE* nulfp;
FILE* bodyfp;
rswindell's avatar
rswindell committed
FILE* ctrlfp;
rswindell's avatar
rswindell committed

char* freadstr(FILE* fp, char* str, size_t maxlen)
{
	int    ch;
	size_t len = 0;
	while ((ch = fgetc(fp)) != EOF && len < maxlen) {
		str[len++] = ch;
		if (ch == 0)
rswindell's avatar
rswindell committed
			break;
	}

	str[maxlen - 1] = 0;
rswindell's avatar
rswindell committed
const char* fmsgattr_str(uint16_t attr)
{
	char str[64] = "";

#define FIDO_ATTR_CHECK(a, f) if (a & FIDO_ ## f)    sprintf(str + strlen(str), "%s%s", str[0] == 0 ? "" : ", ", #f);
rswindell's avatar
rswindell committed
	FIDO_ATTR_CHECK(attr, PRIVATE);
	FIDO_ATTR_CHECK(attr, CRASH);
	FIDO_ATTR_CHECK(attr, RECV);
	FIDO_ATTR_CHECK(attr, SENT);
	FIDO_ATTR_CHECK(attr, FILE);
	FIDO_ATTR_CHECK(attr, INTRANS);
	FIDO_ATTR_CHECK(attr, ORPHAN);
	FIDO_ATTR_CHECK(attr, KILLSENT);
	FIDO_ATTR_CHECK(attr, LOCAL);
	FIDO_ATTR_CHECK(attr, HOLD);
	FIDO_ATTR_CHECK(attr, FREQ);
	FIDO_ATTR_CHECK(attr, RRREQ);
	FIDO_ATTR_CHECK(attr, RR);
	FIDO_ATTR_CHECK(attr, AUDIT);
	FIDO_ATTR_CHECK(attr, FUPREQ);
rswindell's avatar
rswindell committed
		return "";

rswindell's avatar
rswindell committed
	sprintf(buf, "(%s)", str);
	return buf;
}

rswindell's avatar
rswindell committed
int msgdump(FILE* fp, const char* fname)
{
	int       ch;
	long      end;
	fmsghdr_t hdr;
	if (fread(&hdr, sizeof(hdr), 1, fp) != 1) {
		fprintf(stderr, "%s !Error reading msg hdr (%" XP_PRIsize_t "u bytes)\n"
		        , fname, sizeof(hdr));
		return __COUNTER__;
	fseek(fp, -1L, SEEK_END);
rswindell's avatar
rswindell committed
	ch = fgetc(fp);
	end = ftell(fp);
	if (ch != FIDO_STORED_MSG_TERMINATOR) {
		fprintf(stderr, "%s !Message missing terminator (%02X instead of %02X)\n"
		        , fname, (uchar)ch, FIDO_STORED_MSG_TERMINATOR);
rswindell's avatar
rswindell committed
//		return(-2);
	}

	if (hdr.from[sizeof(hdr.from) - 1] != 0)
		fprintf(stderr, "%s Unterminated 'from' field\n", fname);
	if (hdr.to[sizeof(hdr.to) - 1] != 0)
		fprintf(stderr, "%s Unterminated 'to' field\n", fname);
	if (hdr.subj[sizeof(hdr.subj) - 1] != 0)
		fprintf(stderr, "%s Unterminated 'subj' field\n", fname);
	if (hdr.time[sizeof(hdr.time) - 1] != 0)
		fprintf(stderr, "%s Unterminated 'time' field\n", fname);
	TERMINATE(hdr.subj);
	printf("Subj: %.*s\n", (int)sizeof(hdr.subj) - 1, hdr.subj);
rswindell's avatar
rswindell committed
	printf("Attr: 0x%04hX %s\n", hdr.attr, fmsgattr_str(hdr.attr));
	TERMINATE(hdr.to);
	printf("To  : %.*s (%u:%u/%u.%u)\n", (int)sizeof(hdr.to) - 1, hdr.to
	       , hdr.destzone, hdr.destnet, hdr.destnode, hdr.destpoint);
	TERMINATE(hdr.from);
	printf("From: %.*s (%u:%u/%u.%u)\n", (int)sizeof(hdr.from) - 1, hdr.from
	       , hdr.origzone, hdr.orignet, hdr.orignode, hdr.origpoint);
	TERMINATE(hdr.time);
	printf("Time: %.*s\n", (int)sizeof(hdr.time) - 1, hdr.time);
	if (end <= sizeof(hdr) + 1) {
rswindell's avatar
rswindell committed
		fprintf(stderr, "!No body text\n");
	long  len = end - sizeof(hdr);
	char* body = calloc(len + 1, 1);
	if (body == NULL) {
rswindell's avatar
rswindell committed
		fprintf(stderr, "!MALLOC failure\n");
		return __COUNTER__;
	}
rswindell's avatar
rswindell committed
	fseek(fp, sizeof(hdr), SEEK_SET);
	if (fread(body, len, 1, fp) != 1) {
		perror("reading body text");
		free(body);
rswindell's avatar
rswindell committed
	fprintf(bodyfp, "\n-start of message text-\n");
	char* p = body;
	while (*p && p < body + len) {
		if ((p == body || *(p - 1) == '\r') && *p == 1) {
rswindell's avatar
rswindell committed
			fputc('@', ctrlfp);
			p++;
			while (*p && *p != '\r')
rswindell's avatar
rswindell committed
				fputc(*(p++), ctrlfp);
rswindell's avatar
rswindell committed
				p++;
			fputc('\n', ctrlfp);
			continue;
		}
		for (; *p && *p != '\r'; p++) {
			if (*p != '\n')
rswindell's avatar
rswindell committed
				fputc(*p, bodyfp);
		}
rswindell's avatar
rswindell committed
			p++;
			fputc('\n', bodyfp);
		}
	}
	if (p == (body + len) - 1)
		fprintf(bodyfp, "-end of message text-\n");
	else
		fprintf(bodyfp, "-PREMATURE end of message text-\n");
rswindell's avatar
rswindell committed
	free(body);
rswindell's avatar
rswindell committed
	printf("\n");
char* usage = "usage: fmsgdump [-body | -ctrl] <file1.msg> [file2.msg] [...]\n";
rswindell's avatar
rswindell committed

int main(int argc, char** argv)
{
	fprintf(stderr, "fmsgdump rev 3.7 - Dump FidoNet Stored Messages\n\n");
	if (argc < 2) {
		fprintf(stderr, "%s", usage);
rswindell's avatar
rswindell committed
		return -1;
	}

	if ((nulfp = fopen(_PATH_DEVNULL, "w+")) == NULL) {
rswindell's avatar
rswindell committed
		perror(_PATH_DEVNULL);
		return -1;
	}
	bodyfp = nulfp;
	ctrlfp = nulfp;
	if (sizeof(fmsghdr_t) != FIDO_STORED_MSG_HDR_LEN) {
		printf("sizeof(fmsghdr_t)=%" XP_PRIsize_t "u, expected: %d\n", sizeof(fmsghdr_t), FIDO_STORED_MSG_HDR_LEN);
	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch (tolower(argv[i][1])) {
rswindell's avatar
rswindell committed
				case 'b':
					bodyfp = stdout;
				// fall-through
rswindell's avatar
rswindell committed
				case 'c':
rswindell's avatar
rswindell committed
					break;
				default:
					printf("%s", usage);
rswindell's avatar
rswindell committed
			}
			continue;
		}
		fprintf(stdout, "Opening %s\n", argv[i]);
		if ((fp = fopen(argv[i], "rb")) == NULL) {
rswindell's avatar
rswindell committed
			perror(argv[i]);
			continue;
		}
		msgdump(fp, argv[i]);
		fclose(fp);
	}

rswindell's avatar
rswindell committed
}