Hi

[2019-08-31 12:16] Philipp Takacs <phil...@bureaucracy.de>
> As Markus mentioned in the other mail we plan to implement a wrapper
> around m_getfld2(). I have started with one called getfields() and
> following interface:
>
> [...]
>
> So next step is clean up the error messages a bit. I have only copied
> them so they maybe not that good. Test the filter system. then implement
> getflieds on all tools.

I have now tested my filter implementation with whom. Today I will
work on replacing m_getfld() calls with getfields(). New version is
attached. Still based on my pick patch.

Philipp
From 710511ce7310e2b850f64243cd8c2c9c0cc41d59 Mon Sep 17 00:00:00 2001
From: Philipp Takacs <phil...@bureaucracy.de>
Date: Wed, 28 Aug 2019 16:50:37 +0200
Subject: [PATCH 1/4] add EOH2 to m_getfld2 return

if you only intrested in the header you don't need to read the first
body line. This is also required for getfields.
---
 h/mh.h           | 1 +
 sbr/m_getfld2.c  | 5 ++++-
 sbr/readconfig.c | 1 +
 sbr/seq_read.c   | 1 +
 uip/distsbr.c    | 4 ++++
 uip/mhbuild.c    | 2 ++
 uip/mhl.c        | 2 ++
 uip/mhparse.c    | 2 ++
 uip/new.c        | 1 +
 uip/pick.c       | 4 +++-
 uip/prompter.c   | 2 ++
 uip/rcvdist.c    | 1 +
 uip/repl.c       | 1 +
 uip/scansbr.c    | 3 ++-
 uip/slocal.c     | 1 +
 uip/spost.c      | 2 ++
 uip/whom.c       | 1 +
 17 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/h/mh.h b/h/mh.h
index 6337a0ca..1aa58655 100644
--- a/h/mh.h
+++ b/h/mh.h
@@ -219,6 +219,7 @@ enum state {
 	FMTERR2 = -3,      /* Format error in message */
 	IOERR2 = -1,       /* Read error */
 	FLD2 = 0,          /* Header field returned */
+	EOH2,              /* End of Header */
 	BODY2,             /* Body line returned */
 	FILEEOF2           /* Reached end of input file */
 };
diff --git a/sbr/m_getfld2.c b/sbr/m_getfld2.c
index b9a618d1..7cc8689c 100644
--- a/sbr/m_getfld2.c
+++ b/sbr/m_getfld2.c
@@ -74,7 +74,7 @@ m_getfld2(enum state s, struct field *f, FILE *msg)
 		if (ret == FLD2 && is_separator(tmpline)) {
 			/* header/body separator found */
 			free(tmpline);
-			return m_getfld2(BODY2, f, msg);
+			return EOH2;
 		}
 
 		f->namelen = copyname(f->name, tmpline);
@@ -129,6 +129,9 @@ m_getfld2(enum state s, struct field *f, FILE *msg)
 		free(tmpline);
 		return ret;
 
+	case EOH2:
+		ret = BODY2;
+		/* FALL */
 	case BODY2:
 		*f->name = '\0';
 		f->namelen = 0;
diff --git a/sbr/readconfig.c b/sbr/readconfig.c
index 91d2b4ed..431530ef 100644
--- a/sbr/readconfig.c
+++ b/sbr/readconfig.c
@@ -75,6 +75,7 @@ readconfig(struct node **npp, FILE *ib, char *file, int ctx)
 			advise(NULL, "%s is poorly formatted", file);
 			state = FLD2;
 			continue;
+		case EOH2:
 		case BODY2:
 			adios(EX_CONFIG, NULL, "no blank lines are permitted in %s",
 					file);
diff --git a/sbr/seq_read.c b/sbr/seq_read.c
index 041f6327..ce56ebca 100644
--- a/sbr/seq_read.c
+++ b/sbr/seq_read.c
@@ -83,6 +83,7 @@ seq_public(struct msgs *mp)
 			seq_init(mp, mh_xstrdup(f.name), trimcpy(f.value));
 			continue;
 
+		case EOH2:
 		case BODY2:
 			adios(EX_CONFIG, NULL, "no blank lines are permitted in %s",
 					seqfile);
diff --git a/uip/distsbr.c b/uip/distsbr.c
index 2662c02d..913ade01 100644
--- a/uip/distsbr.c
+++ b/uip/distsbr.c
@@ -67,6 +67,8 @@ distout(char *drft, char *msgnam, char *backup)
 			fprintf(ofp, "%s: %s", f.name, f.value);
 			break;
 
+		case EOH2:
+			continue;
 		case BODY2:
 			for (dp = f.value; *dp; dp++) {
 				if (!isspace(*dp)) {
@@ -171,6 +173,8 @@ ready_msg(char *msgnam)
 			fprintf(ofp, "%s: %s", f.name, f.value);
 			break;
 
+		case EOH2:
+			continue;
 		case BODY2:
 			fclose(ofp);
 
diff --git a/uip/mhbuild.c b/uip/mhbuild.c
index a233c685..13dc8510 100644
--- a/uip/mhbuild.c
+++ b/uip/mhbuild.c
@@ -376,6 +376,8 @@ build_mime(char *infile)
 
 			continue;
 
+		case EOH2:
+			continue;
 		case BODY2:
 			fseek(in, (long) (-strlen(f.value)), SEEK_CUR);
 			break;
diff --git a/uip/mhl.c b/uip/mhl.c
index fa83602d..a09cd28b 100644
--- a/uip/mhl.c
+++ b/uip/mhl.c
@@ -683,6 +683,8 @@ mhlfile(FILE *fp, char *mname, int ofilen, int ofilec)
 			}
 			continue;
 
+		case EOH2:
+			continue;
 		case BODY2:
 		case FILEEOF2:
 			column = 0;
diff --git a/uip/mhparse.c b/uip/mhparse.c
index 2b72e7bc..2d8e8ead 100644
--- a/uip/mhparse.c
+++ b/uip/mhparse.c
@@ -275,6 +275,8 @@ get_content(FILE *in, char *file, int toplevel)
 			ct->c_begin = ftell(in) + 1;
 			continue;
 
+		case EOH2:
+			continue;
 		case BODY2:
 			ct->c_begin = ftell(in) - strlen(f.value);
 			break;
diff --git a/uip/new.c b/uip/new.c
index 21435b34..cd206e18 100644
--- a/uip/new.c
+++ b/uip/new.c
@@ -137,6 +137,7 @@ get_msgnums(char *folder, char *sequences[])
 			}
 			continue;
 
+		case EOH2:
 		case BODY2:
 			adios(EX_DATAERR, NULL, "no blank lines are permitted in %s", seqfile);
 			/* FALL */
diff --git a/uip/pick.c b/uip/pick.c
index 8f28f354..a2a03cfb 100644
--- a/uip/pick.c
+++ b/uip/pick.c
@@ -865,7 +865,7 @@ pmatches(FILE *fp, int msgnum)
 		nexus_debug(head, 0);
 	}
 
-	while (s == FLD2 || s == BODY2) {
+	while (s == FLD2 || s == BODY2 || s == EOH2) {
 		switch (s = m_getfld2(s, &f, fp)) {
 		case LENERR2:
 			s = FLD2;
@@ -873,6 +873,8 @@ pmatches(FILE *fp, int msgnum)
 		case FLD2:
 			nexus_match(&f, msgnum, head);
 			break;
+		case EOH2:
+			continue;
 		case BODY2:
 			if (!body) {
 				return head->match;
diff --git a/uip/prompter.c b/uip/prompter.c
index 7f71e028..c565b2a5 100644
--- a/uip/prompter.c
+++ b/uip/prompter.c
@@ -185,6 +185,8 @@ abort:
 			}
 			continue;
 
+		case EOH2:
+			continue;
 		case BODY2:
 		case FILEEOF2:
 			fprintf(out, "--------\n");
diff --git a/uip/rcvdist.c b/uip/rcvdist.c
index af3fc10d..b89c1906 100644
--- a/uip/rcvdist.c
+++ b/uip/rcvdist.c
@@ -216,6 +216,7 @@ rcvdistout(FILE *inb, char *form, char *addrs)
 		case LENERR2:
 		case FMTERR2:
 		case IOERR2:
+		case EOH2:
 		case BODY2:
 		case FILEEOF2:
 			goto finished;
diff --git a/uip/repl.c b/uip/repl.c
index b2adebfe..d982a8f3 100644
--- a/uip/repl.c
+++ b/uip/repl.c
@@ -476,6 +476,7 @@ replout(FILE *inb, char *drft, struct msgs *mp,
 		case LENERR2:
 		case FMTERR2:
 		case IOERR2:
+		case EOH2:
 		case BODY2:
 		case FILEEOF2:
 			goto finished;
diff --git a/uip/scansbr.c b/uip/scansbr.c
index 48837d76..739bf375 100644
--- a/uip/scansbr.c
+++ b/uip/scansbr.c
@@ -144,7 +144,8 @@ scan(FILE *inb, int innum, int outnum, char *fmtstr, int width, int curflg,
 				} while ((cptr = cptr->c_next));
 			}
 			break;
-
+		case EOH2:
+			continue;
 		case BODY2:
 			compnum = -1;
 			if (scanfolder) {
diff --git a/uip/slocal.c b/uip/slocal.c
index df0dc7f6..69c7c773 100644
--- a/uip/slocal.c
+++ b/uip/slocal.c
@@ -794,6 +794,7 @@ parse(int fd)
 			}
 			continue;
 
+		case EOH2:
 		case BODY2:
 		case FILEEOF2:
 			break;
diff --git a/uip/spost.c b/uip/spost.c
index fd0cbcc9..b98687d5 100644
--- a/uip/spost.c
+++ b/uip/spost.c
@@ -241,6 +241,8 @@ main(int argc, char **argv)
 			putfmt(f.name, f.value, out);
 			continue;
 
+		case EOH2:
+			continue;
 		case BODY2:
 			finish_headers(out);
 			fprintf(out, "\n%s", f.value);
diff --git a/uip/whom.c b/uip/whom.c
index ef0b684d..5222fc68 100644
--- a/uip/whom.c
+++ b/uip/whom.c
@@ -232,6 +232,7 @@ process(char *file)
 			proc_hdr(f.name, f.value);
 			continue;
 
+		case EOH2:
 		case BODY2:
 		case FILEEOF2:
 			break;
-- 
2.20.1

From 09dfda7195fa22687ed95ae31d25bce41727997c Mon Sep 17 00:00:00 2001
From: Philipp Takacs <phil...@bureaucracy.de>
Date: Wed, 28 Aug 2019 16:53:12 +0200
Subject: [PATCH 2/4] add getfliedlds

not finished
---
 h/prototypes.h  |  1 +
 sbr/Makefile.in |  2 +-
 sbr/getfields.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++
 sbr/utils.c     | 13 +++++++++
 4 files changed, 85 insertions(+), 1 deletion(-)
 create mode 100644 sbr/getfields.c

diff --git a/h/prototypes.h b/h/prototypes.h
index fad1af4f..63c03459 100644
--- a/h/prototypes.h
+++ b/h/prototypes.h
@@ -54,6 +54,7 @@ int gans(char *, struct swit *);
 char **getans(char *, struct swit *);
 int getanswer(char *);
 char **getarguments(char *, int, char **, int);
+ssize_t getfields(FILE **, struct field **, size_t *, const char *, const char * const *);
 char *get_charset();
 char *getcurfol(void);
 char *getdeffol(void);
diff --git a/sbr/Makefile.in b/sbr/Makefile.in
index f2310fb8..7e772332 100644
--- a/sbr/Makefile.in
+++ b/sbr/Makefile.in
@@ -56,7 +56,7 @@ SRCS = addrsbr.c ambigsw.c brkstring.c  \
 	error.c execprog.c ext_hook.c folder_addmsg.c folder_delmsgs.c  \
 	folder_free.c folder_read.c  \
 	folder_realloc.c gans.c getans.c getanswer.c  \
-	getarguments.c \
+	getarguments.c getfields.c \
 	fmt_addr.c fmt_compile.c fmt_new.c fmt_rfc2047.c  \
 	fmt_scan.c lock_file.c m_atoi.c \
 	m_convert.c m_draft.c m_getfld2.c m_gmprot.c  \
diff --git a/sbr/getfields.c b/sbr/getfields.c
new file mode 100644
index 00000000..43f1ebd0
--- /dev/null
+++ b/sbr/getfields.c
@@ -0,0 +1,70 @@
+#include <h/mh.h>
+#include <h/utils.h>
+#include <stdio.h>
+#include <sysexits.h>
+
+static boolean use_name(const char * const *filter, const char *name)
+{
+	size_t i;
+
+	if (!filter) {
+		return TRUE;
+	}
+	for (i = 0; filter[i]; i++) {
+		if (strcasecmp(filter[i], name)==0) {
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+ssize_t getfields(FILE **file, struct field **fields, size_t *n, const char *filename, const char * const * filter)
+{
+	enum state s = FLD2;
+	size_t i = 0;
+
+	if (!*file) {
+		*file = fopen(filename, "r");
+	}
+	if (!*file) {
+		return -1;
+	}
+	if (!(*fields && *n > 0)) {
+		*fields = mh_xcalloc(32, sizeof(**fields));
+		*n = 32;
+	}
+
+	while (s == FLD2) {
+		if (i >= *n) {
+			*fields = mh_xrealloc(*fields, 2*(*n)*sizeof(**fields));
+			*n = 2*(*n);
+		}
+		(*fields)[i].value = NULL;
+		(*fields)[i].alloclen = 0;
+		switch (s = m_getfld2(s, (*fields)+i, *file)) {
+		case LENERR2:
+			s = FLD2;
+			/* FALL */
+		case FLD2:
+			if (!use_name(filter, (*fields)[i].name)) {
+				mh_free0(&(*fields)[i].value);
+				(*fields)[i].alloclen = 0;
+				break;
+			}
+			i++;
+			break;
+		case FILEEOF2:
+		case EOH2:
+			return i;
+		case FMTERR2:
+			advise(NULL, "Format error in message");
+			return -1;
+		case IOERR2:
+			advise(NULL, "IOERROR");
+			return -1;
+		default:
+			adios(EX_SOFTWARE, "m_getfld2", "returned unknown state %d at message %d", s, filename);
+		}
+	}
+	return i;
+}
diff --git a/sbr/utils.c b/sbr/utils.c
index 50060ae7..4e8dce7f 100644
--- a/sbr/utils.c
+++ b/sbr/utils.c
@@ -76,6 +76,19 @@ mh_free0(void * ptr)
 	*p = NULL;
 }
 
+/*
+** Free a array of Fields and set it to NULL
+*/
+void
+fieldsfree(struct fields **f, size_t n)
+{
+	size_t i;
+	for (i = 0; i < n; i++) {
+		free((*f)[i].value);
+	}
+	mh_free0(f);
+}
+
 /*
 ** Return the present working directory, if the current directory does not
 ** exist, or is too long, make / the pwd.
-- 
2.20.1

From e11224e4b2eec3b3f7480675eceb4c371dbbf762 Mon Sep 17 00:00:00 2001
From: Philipp Takacs <phil...@bureaucracy.de>
Date: Sat, 31 Aug 2019 10:59:00 +0200
Subject: [PATCH 3/4] use getfields in uip/pick.c

---
 uip/pick.c | 52 +++++++++++++++++++++++++---------------------------
 1 file changed, 25 insertions(+), 27 deletions(-)

diff --git a/uip/pick.c b/uip/pick.c
index a2a03cfb..af893bd0 100644
--- a/uip/pick.c
+++ b/uip/pick.c
@@ -853,9 +853,13 @@ static void nexus_clear(struct nexus *n)
 static int
 pmatches(FILE *fp, int msgnum)
 {
-	struct field f = {{0}};
-	enum state s = FLD2;
-
+	static struct field *fields = NULL;
+	static size_t alloc = 0;
+	ssize_t field_n;
+	size_t i;
+	enum state s;
+	char tmp[BUFSIZ];
+	snprintf(tmp, BUFSIZ-1, "%d", msgnum);
 
 	if (!head)
 		return 1;
@@ -865,31 +869,25 @@ pmatches(FILE *fp, int msgnum)
 		nexus_debug(head, 0);
 	}
 
-	while (s == FLD2 || s == BODY2 || s == EOH2) {
-		switch (s = m_getfld2(s, &f, fp)) {
-		case LENERR2:
-			s = FLD2;
-			/* FALL */
-		case FLD2:
-			nexus_match(&f, msgnum, head);
-			break;
-		case EOH2:
-			continue;
-		case BODY2:
-			if (!body) {
-				return head->match;
-			}
-			nexus_match(&f, msgnum, head);
-			break;
-		case IOERR2:
-			advise(NULL, "IOERR in message %d\n", msgnum);
-			return FALSE;
-		case FILEEOF2:
-			break;
-		default:
-			adios(EX_SOFTWARE, "m_getfld2", "returned unknown state %d at message %d", s, msgnum);
-		}
+	field_n = getfields(&fp, &fields, &alloc, tmp, NULL);
+
+	if (field_n < 0) {
+		advise("getfields", "returned -1 at message %d", s, msgnum);
+		return FALSE;
+	}
+
+	for (i = 0; i < field_n; i++) {
+		nexus_match(fields+i, msgnum, head);
+	}
+	s = feof(fp) ? FILEEOF2 : BODY2;
+	if (!body) {
+		mh_free0(&fields);
+		return head->match;
+	}
+	while (m_getfld2(s, fields, fp) == BODY2) {
+		nexus_match(fields, msgnum, head);
 	}
+	mh_free0(&fields);
 	return head->match;
 }
 
-- 
2.20.1

From 0387baa6c524002a252beae8304589bf19c876d6 Mon Sep 17 00:00:00 2001
From: Philipp Takacs <phil...@bureaucracy.de>
Date: Sun, 8 Sep 2019 01:23:34 +0200
Subject: [PATCH 4/4] use getfields in whom

---
 test/tests/whom/multible-files | 16 +++++++++
 uip/whom.c                     | 64 +++++++++++++---------------------
 2 files changed, 41 insertions(+), 39 deletions(-)
 create mode 100644 test/tests/whom/multible-files

diff --git a/test/tests/whom/multible-files b/test/tests/whom/multible-files
new file mode 100644
index 00000000..079f37be
--- /dev/null
+++ b/test/tests/whom/multible-files
@@ -0,0 +1,16 @@
+# test whom
+
+. "$MH_TEST_COMMON"
+
+runandcheck 'whom a' <<!
+u...@example.com
+u...@example.com
+u...@example.com
+u...@example.com
+u...@example.com
+u...@example.com
+u...@example.com
+u...@example.com
+u...@example.com
+u...@example.com
+!
diff --git a/uip/whom.c b/uip/whom.c
index 5222fc68..f8cd4028 100644
--- a/uip/whom.c
+++ b/uip/whom.c
@@ -60,12 +60,22 @@ static int alisw = 1;  /* expand aliases on rcpt addrs */
 
 static char *dccsep = "\t==DCC==";
 static char *bccsep = "\t==BCC==";
-
+static const char * const fields[] = {
+	"to",
+	"cc",
+	"bcc",
+	"dcc",
+	"resent-to",
+	"resent-cc",
+	"resent-bcc",
+	"resent-dcc",
+	NULL,
+};
 
 /*
 ** static prototypes
 */
-static int process(char *);
+static void process(char *);
 static void proc_hdr(char *, char *);
 static int print(void);
 static int printdcc(void);
@@ -210,48 +220,24 @@ main(int argc, char **argv)
 }
 
 
-static int
+static void
 process(char *file)
 {
-	enum state state;
-	struct field f = {{0}};
-	int compnum;
-	FILE *in;
+	FILE *in = NULL;
+	static struct field *f = NULL;
+	static size_t alloc = 0;
+	ssize_t num;
+	size_t i;
 
-
-	if ((in = fopen(file, "r")) == NULL) {
-		adios(EX_IOERR, file, "unable to open");
+	num = getfields(&in, &f, &alloc, file, fields);
+	fclose(in);
+	if (num < 0) {
+		advise("getflieds", "Can not process mail %s", file);
+		return;
 	}
-
-	for (compnum=1, state=FLD2;; compnum++) {
-		switch (state = m_getfld2(state, &f, in)) {
-		case LENERR2:
-			state = FLD2;
-			/* FALL */
-		case FLD2:
-			proc_hdr(f.name, f.value);
-			continue;
-
-		case EOH2:
-		case BODY2:
-		case FILEEOF2:
-			break;
-
-		case FMTERR2:
-			advise(NULL, "message format error in component #%d", compnum);
-			continue;
-
-		case IOERR2:
-			adios(EX_DATAERR, NULL, "message format error in component #%d",
-					compnum);
-
-		default:
-			adios(EX_SOFTWARE, NULL, "getfld() returned %d", state);
-		}
-		break;
+	for (i = 0; i < num; i++) {
+		proc_hdr(f[i].name, f[i].value);
 	}
-	fclose(in);
-	return 0;
 }
 
 
-- 
2.20.1

Reply via email to