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

#include "gen_defs.h"
#include "fidodefs.h"
#include "dirwrap.h"	/* _PATH_DEVNULL */
#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)
			break;
	}

	str[maxlen-1]=0;

	return(str);
}

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

rswindell's avatar
rswindell committed
#define FIDO_ATTR_CHECK(a, f) if(a&FIDO_##f)	sprintf(str + strlen(str), "%s%s", str[0] == 0 ? "" : ", ", #f);
	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);
	if(str[0] == 0)
		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);
	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);
//		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);
rswindell's avatar
rswindell committed
	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
rswindell's avatar
rswindell committed
		,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
rswindell's avatar
rswindell committed
		,hdr.origzone, hdr.orignet, hdr.orignode, hdr.origpoint);
	TERMINATE(hdr.time);
rswindell's avatar
rswindell committed
	printf("Time: %.*s\n", (int)sizeof(hdr.time)-1, hdr.time);

	if(end <= sizeof(hdr)+1) {
		fprintf(stderr, "!No body text\n");
		return(__COUNTER__);
	}

	long len = end - sizeof(hdr);
	char* body = calloc(len + 1, 1);
rswindell's avatar
rswindell committed
	if(body == NULL) {
		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");
		return __COUNTER__;
	}
rswindell's avatar
rswindell committed
	fprintf(bodyfp, "\n-start of message text-\n");
	char* p = body;
	while(*p && p < body + len) {
rswindell's avatar
rswindell committed
		if((p == body || *(p - 1) == '\r') && *p == 1) {
			fputc('@', ctrlfp);
			p++;
			while(*p && *p != '\r')
				fputc(*(p++), ctrlfp);
			if(*p)
				p++;
			fputc('\n', ctrlfp);
			continue;
		}
		for(; *p && *p != '\r'; p++) {
			if(*p != '\n')
				fputc(*p, bodyfp);
		}
		if(*p) {
			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");
	return(0);
}

char* usage = "usage: fmsgdump [-body | -ctrl] <file1.msg> [file2.msg] [...]\n";
rswindell's avatar
rswindell committed

int main(int argc, char** argv)
{
	FILE*	fp;
	int		i;

	fprintf(stderr,"fmsgdump rev 3.7 - Dump FidoNet Stored Messages\n\n");
rswindell's avatar
rswindell committed

	if(argc<2) {
		fprintf(stderr,"%s",usage);
		return -1;
	}

	if((nulfp=fopen(_PATH_DEVNULL,"w+"))==NULL) {
		perror(_PATH_DEVNULL);
		return -1;
	}
	bodyfp=nulfp;
rswindell's avatar
rswindell committed
	ctrlfp=nulfp;
rswindell's avatar
rswindell committed

	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);
		return(-1);
	}

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

	return(0);
}