AmendHub

Download:

jcs

/

subtext

/

amendments

/

314

fidopkt: Add FidoNet packet message parser

This only supports type 4d format messages, but that's all I've seen.

jcs made amendment 314 about 1 year ago
--- fidopkt.c Thu Feb 23 09:48:06 2023 +++ fidopkt.c Thu Feb 23 09:48:06 2023 @@ -0,0 +1,341 @@ +/* + * FidoNet echomail packet parser + * http://wiki.synchro.net/ref:fidonet_packets + * + * Copyright (c) 2023 joshua stein <jcs@jcs.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "fidopkt.h" +#include "logger.h" +#include "util.h" +#include "zip.h" /* for GET_U* */ + +/* #define FIDOPKT_DEBUG */ + +#define PKTHEADER_ORIGNODE 0 +#define PKTHEADER_DESTNODE 2 +#define PKTHEADER_YEAR 4 +#define PKTHEADER_MONTH 6 +#define PKTHEADER_DAY 8 +#define PKTHEADER_HOUR 10 +#define PKTHEADER_MINUTE 12 +#define PKTHEADER_SECOND 14 + +#define PKTHEADER_BAUD 16 +#define PKTHEADER_PKTTYPE 18 + +#define PKTHEADER_ORIGNET 20 +#define PKTHEADER_DESTNET 22 +#define PKTHEADER_PRODCODELOW 24 +#define PKTHEADER_REVMAJOR 25 +#define PKTHEADER_PASSWORD 26 + +#define PKTHEADER_QORIGZONE 34 +#define PKTHEADER_QDESTZONE 36 + +#define PKTHEADER_AUXNET 38 +#define PKTHEADER_CWVALIDCOPY 40 +#define PKTHEADER_PRODCODEHIGH 42 +#define PKTHEADER_REVMINOR 43 +#define PKTHEADER_CAPABILWORD 44 + +#define PKTHEADER_ORIGZONE 46 +#define PKTHEADER_DESTZONE 48 +#define PKTHEADER_ORIGPOINT 50 +#define PKTHEADER_DESTPOINT 52 +#define PKTHEADER_PRODDATA 54 + +#define SIZE_PKTHEADER 58 + +/* PktMsgHeader */ +#define PKTMSGHEADER_PKTTYPE 0 +#define PKTMSGHEADER_ORIGNODE 2 +#define PKTMSGHEADER_DESTNODE 4 +#define PKTMSGHEADER_ORIGNET 6 +#define PKTMSGHEADER_DESTNET 8 +#define PKTMSGHEADER_ATTR 10 +#define PKTMSGHEADER_COST 12 + +#define SIZE_PKTMSGHEADER 14 + +static const char *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", + "Nov", "Dec", +}; + +size_t fidopkt_read_until(char **buf, size_t *buf_len, char delim, + size_t max_len, char *ret, bool terminate); + +size_t +fidopkt_read_until(char **buf, size_t *buf_len, char delim, + size_t max_len, char *ret, bool terminate) +{ + char ch; + size_t retpos = 0; + bool found = false; + + if (*buf_len < max_len) + max_len = *buf_len; + + while (max_len != 0) { + ch = *(*buf)++; + ret[retpos++] = (ch == delim ? '\0' : ch); + max_len--; + (*buf_len)--; + if (ch == delim) { + found = true; + break; + } + } + if (terminate || found) + ret[retpos - 1] = '\0'; + + return retpos; +} + +struct fidopkt * +fidopkt_parse(char *packet_filename, char *buf, size_t len) +{ + static char line[100]; +#ifdef FIDOPKT_DEBUG + static char datetime[100], tz[50], ct[50]; + char *lastbreak, was; +#endif + struct fidopkt *ret; + size_t message_len, llen; + long tzoff; + struct tm tm = { 0 }; + char dmon[6]; + short dday, dyear, dhour, dmin, dsec, dutc, n; + bool tear; + +#ifdef FIDOPKT_DEBUG + logger_printf("[fidopkt] Parsing %s ==========", packet_filename); +#endif + + if (len < SIZE_PKTHEADER) { + logger_printf("[fidopkt] packet too small (%ld)", len); + return; + } + + if (GET_U16(buf + PKTHEADER_PKTTYPE) != 2) { + logger_printf("[fidopkt] not a fidonet packet"); + return; + } + + if (GET_U16(buf + PKTHEADER_BAUD) == 2) { + logger_printf("[fidopkt] 5d format not supported"); + return; + } + + if (buf[PKTHEADER_CWVALIDCOPY] != buf[PKTHEADER_CAPABILWORD + 1] || + buf[PKTHEADER_CWVALIDCOPY + 1] != buf[PKTHEADER_CAPABILWORD]) { + logger_printf("[fidopkt] not in 4d format"); + return; + } + + buf += SIZE_PKTHEADER; + len -= SIZE_PKTHEADER; + + if (len < SIZE_PKTMSGHEADER) { + logger_printf("[fidopkt] message header too short"); + return; + } + + if (GET_U16(buf + PKTMSGHEADER_PKTTYPE) != 2) { + logger_printf("[fidopkt] header packet type != 2"); + return; + } + + buf += SIZE_PKTMSGHEADER; + len -= SIZE_PKTMSGHEADER; + + ret = xmalloczero(sizeof(struct fidopkt), "fidopkt"); + + fidopkt_read_until(&buf, &len, '\0', sizeof(line), line, true); + if (len == 0) { + logger_printf("[fidopkt] short read"); + goto parse_fail; + } + if (sscanf(line, "%d %5s %d %d:%d:%d", &dday, (char *)&dmon, &dyear, + &dhour, &dmin, &dsec) != 6) { + logger_printf("[fidopkt] couldn't parse date \"%s\"", line); + goto parse_fail; + } + + tm.tm_sec = dsec; + tm.tm_min = dmin; + tm.tm_hour = dhour; + tm.tm_mday = dday; + tm.tm_year = 100 + dyear; + tm.tm_mon = -1; + for (n = 0; n < nitems(months); n++) { + if (strcmp(months[n], dmon) == 0) { + tm.tm_mon = n; + break; + } + } + if (tm.tm_mon == -1) { + logger_printf("[fidopkt] couldn't parse month \"%s\"", dmon); + goto parse_fail; + } +#ifdef FIDOPKT_DEBUG + strlcpy(datetime, line, sizeof(datetime)); +#endif + + fidopkt_read_until(&buf, &len, '\0', sizeof(ret->to), ret->to, true); + if (len == 0) { + logger_printf("[fidopkt] short read to"); + goto parse_fail; + } + fidopkt_read_until(&buf, &len, '\0', sizeof(ret->from), ret->from, true); + if (len == 0) { + logger_printf("[fidopkt] short read from"); + goto parse_fail; + } + fidopkt_read_until(&buf, &len, '\0', sizeof(ret->subject), ret->subject, + true); + if (len == 0) { + logger_printf("[fidopkt] short read subject"); + goto parse_fail; + } + + fidopkt_read_until(&buf, &len, '\r', sizeof(line), line, true); + if (len == 0) { + logger_printf("[fidopkt] short read area"); + goto parse_fail; + } + if (strncmp(line, "AREA:", 5) != 0) { + logger_printf("[fidopkt] no AREA in first line"); + goto parse_fail; + } + strlcpy(ret->area, line + 5, sizeof(ret->area)); + + ret->message = xmalloc(len, "fidopkt message"); + message_len = 0; + + tear = false; + while (len) { + llen = fidopkt_read_until(&buf, &len, '\r', sizeof(line), line, + false); + /* + * We are not terminating long lines now, so don't use unbounded + * string comparisons. + */ + if (memcmp(line, "--- ", 4) == 0 || memcmp(line, "---\0", 4) == 0) { + /* tear line */ + tear = true; + } else if (line[0] == 0x01) { + /* kludge line */ + line[llen] = '\0'; + if (sscanf(line + 1, "TZUTC: %d", &dutc) == 1) { + tzoff = ((long)dutc * 60 * 60) / 100; +#ifdef FIDOPKT_DEBUG + strlcpy(tz, line + 1 + 7, sizeof(tz)); +#endif + } + else if (strncmp(line + 1, "MSGID: ", 7) == 0) + strlcpy(ret->msgid, line + 1 + 7, sizeof(ret->msgid)); + else if (strncmp(line + 1, "REPLY: ", 7) == 0) + strlcpy(ret->reply, line + 1 + 7, sizeof(ret->reply)); + } else if (tear && strncmp(line, " * Origin: ", 11) == 0) { + line[llen] = '\0'; + strlcpy(ret->origin, line + 11, sizeof(ret->origin)); + } else if (!tear) { + if (line[0] == ' ' && line[1] == ' ') + continue; + if (message_len == 0 && + (line[0] == '\n' || line[0] == '\r' || line[0] == '\0')) + continue; + if (line[llen - 1] == '\0') { + memcpy(ret->message + message_len, line, llen - 1); + message_len += llen - 1; + ret->message[message_len++] = '\r'; + //ret->message[message_len++] = '\n'; + } else { + /* long line */ + memcpy(ret->message + message_len, line, llen); + message_len += llen; + } + } + } + + while (message_len > 1) { + if (ret->message[message_len - 1] == '\n' && + ret->message[message_len - 2] == '\r') + message_len -= 2; + else if (ret->message[message_len - 1] == '\r') + message_len -= 1; + else + break; + } + ret->message[message_len] = '\0'; + ret->message_len = message_len; + + ret->time = mktime(&tm); + if (ret->time == -1) { + logger_printf("[fidopkt] parsed date but mktime failed"); + goto parse_fail; + } + ret->time -= tzoff; + +#ifdef FIDOPKT_DEBUG + logger_printf("[fidopkt] ID: %s", ret->msgid); + logger_printf("[fidopkt] Origin: %s", ret->origin); + logger_printf("[fidopkt] Reply To: %s", ret->reply); + logger_printf("[fidopkt] Area: %s", ret->area); + logger_printf("[fidopkt] From: %s", ret->from); + logger_printf("[fidopkt] To: %s", ret->to); + logger_printf("[fidopkt] Subject: %s", ret->subject); + + llen = strlcpy(ct, ctime(&ret->time), sizeof(ct)); + ct[llen - 1] = '\0'; + logger_printf("[fidopkt] Date: %s UTC (%s %s%s)", ct, datetime, + (tzoff >= 0 ? "+" : ""), tz); + logger_printf("[fidopkt] Message:"); + + lastbreak = ret->message; + for (n = 0; n <= ret->message_len; n++) { + if (ret->message[n] == '\r' || n == ret->message_len) { + was = ret->message[n]; + ret->message[n] = '\0'; + logger_printf("[fidopkt] %s", lastbreak); + ret->message[n] = was; + lastbreak = ret->message + n + 1; + } + } +#endif + + return ret; + +parse_fail: + fidopkt_free(&ret); + return NULL; +} + +void +fidopkt_free(struct fidopkt **pktp) +{ + struct fidopkt *pkt = (struct fidopkt *)*pktp; + + if (pkt->message) + xfree(&pkt->message); + xfree(pktp); +} --- fidopkt.h Wed Feb 22 15:54:38 2023 +++ fidopkt.h Wed Feb 22 15:54:38 2023 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 joshua stein <jcs@jcs.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __FIDOPKT_H__ +#define __FIDOPKT_H__ + +#include "util.h" + +struct fidopkt { + time_t time; + char to[36]; + char from[36]; + char subject[72]; + char area[16]; + char origin[72]; + char msgid[32]; + char reply[32]; + char *message; + size_t message_len; +}; + +struct fidopkt * fidopkt_parse(char *packet_filename, char *buf, + size_t len); +void fidopkt_free(struct fidopkt **pktp); + +#endif