From 00664cc3ece7c29843771561fe2890b635f2b74e Mon Sep 17 00:00:00 2001
From: Sam Varshavchik <mrsam@courier-mta.com>
Date: Fri, 26 Nov 2021 13:06:23 -0500
Subject: [PATCH] Convert to pcre2.

---
 maildrop/Makefile.am  |   6 +-
 maildrop/configure.ac |   9 ++-
 maildrop/search.C     | 139 +++++++++++++++++++++---------------------
 maildrop/search.h     |  24 ++++----
 configure.ac          |  12 +++---
 5 files changed, 92 insertions(+), 98 deletions(-)

diff --git a/maildrop/Makefile.am b/maildrop/Makefile.am
index 5f94c37..154cebe 100644
--- a/libs/maildrop/Makefile.am
+++ b/libs/maildrop/Makefile.am
@@ -3,7 +3,7 @@
 # distribution information.
 
 
-AM_CPPFLAGS=@AUTHINCLUDE@
+AM_CPPFLAGS := @AUTHINCLUDE@ `pcre2-config --cflags`
 
 DISTCLEANFILES=uidgid testmailbot.*
 CLEANFILES=maildrop.html maildrop.1 maildropfilter.7 maildropfilter.html
@@ -46,8 +46,8 @@ maildrop_SOURCES=deliver.C deliverdotlock.C deliverdotlock.h \
 
 maildrop_DEPENDENCIES = libmdcommon.la
 
-maildrop_LDADD = libmdcommon.la @AUTHLDADD@ -lpcre
-maildrop_LDFLAGS=
+maildrop_LDADD = libmdcommon.la @AUTHLDADD@
+maildrop_LDFLAGS= `pcre2-config --libs8`
 
 reformail_SOURCES=reformail.C
 reformail_LDADD = libmdcommon.la
diff --git a/maildrop/configure.ac b/maildrop/configure.ac
index fca57fe..63acdfb 100644
--- a/libs/maildrop/configure.ac
+++ b/libs/maildrop/configure.ac
@@ -159,7 +159,7 @@ AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
 AC_HEADER_TIME
 AC_HEADER_DIRENT
-AC_CHECK_HEADERS(fcntl.h memory.h sys/file.h sys/time.h sys/stat.h unistd.h strings.h locale.h pcre.h pcre/pcre.h)
+AC_CHECK_HEADERS(fcntl.h memory.h sys/file.h sys/time.h sys/stat.h unistd.h strings.h locale.h)
 
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_TYPE_MODE_T
@@ -301,6 +301,13 @@ else
 	AC_CHECK_PROG(QMAIL,qmail-inject,qmail-inject,)
 fi
 
+AC_CHECK_PROG(PCRE2, pcre2-config, yes, no)
+
+if test "$PCRE2" = "no"
+then
+	AC_MSG_ERROR([pcre2 library not found])
+fi
+
 dnl Try to find sendmail.
 
 test "x$prefix" = xNONE && prefix=$ac_default_prefix
diff --git a/maildrop/search.C b/maildrop/search.C
index 9add6ee..32d4ce6 100644
--- a/libs/maildrop/search.C
+++ b/libs/maildrop/search.C
@@ -12,22 +12,17 @@
 
 void Search::cleanup()
 {
-	if (pcre_regexp_extra)
+	if (match_data)
 	{
-		pcre_free(pcre_regexp_extra);
-		pcre_regexp_extra=NULL;
+		pcre2_match_data_free(match_data);
+		match_data=NULL;
 	}
+
 	if (pcre_regexp)
 	{
-		pcre_free(pcre_regexp);
+		pcre2_code_free(pcre_regexp);
 		pcre_regexp=NULL;
 	}
-
-	if (pcre_vectors)
-	{
-		free(pcre_vectors);
-		pcre_vectors=NULL;
-	}
 }
 
 int	Search::init(const char *expr, const char *opts)
@@ -51,69 +46,55 @@ int	Search::init(const char *expr, const char *opts)
 		if (strchr(opts, 'w'))	match_body=1;
 	}
 
-	const char *errptr;
+	int errcode;
 
 	cleanup();
 
-	int errindex;
+	PCRE2_SIZE errindex;
 
-	pcre_regexp=pcre_compile(expr,
-				 PCRE_UTF8 | (strchr(opts, 'D') ? 0:PCRE_CASELESS),
-				 &errptr,
-				 &errindex, 0);
+	pcre_regexp=pcre2_compile((PCRE2_SPTR8)expr,
+				  PCRE2_ZERO_TERMINATED,
+				  PCRE2_UTF | (strchr(opts, 'D') ? 0:PCRE2_CASELESS),
+				  &errcode,
+				  &errindex,
+				  NULL);
 
 	if (!pcre_regexp)
 	{
 		Buffer b;
 
+		PCRE2_UCHAR buffer[256];
+		pcre2_get_error_message(errcode, buffer, sizeof(buffer));
+
 		b="Invalid regular expression, offset ";
 		b.append((unsigned long)errindex);
 		b += " of: ";
 		b += expr;
 		b += ": ";
-		b += errptr;
+		b += (char *)buffer;
 		b += "\n";
 		b += '\0';
 		merr.write(b);
 		return -1;
 	}
 
-	pcre_regexp_extra=pcre_study(pcre_regexp, 0, &errptr);
+	match_data= pcre2_match_data_create_from_pattern(
+		pcre_regexp, NULL
+	);
 
-	if (errptr)
+	if (!match_data)
 	{
 		Buffer b;
 
-		b="Error parsing regular expression: ";
+		b="Failed to create match data for: ";
 		b += expr;
-		b += ": ";
-		b += errptr;
 		b += "\n";
 		b += '\0';
 		merr.write(b);
+		cleanup();
 		return -1;
 	}
-
 	search_expr=expr;
-	int cnt=0;
-
-	pcre_fullinfo(pcre_regexp, pcre_regexp_extra,
-		      PCRE_INFO_CAPTURECOUNT, &cnt);
-
-	pcre_vector_count=(cnt+1)*3;
-
-	pcre_vectors=(int *)malloc(pcre_vector_count*sizeof(int));
-
-	if (!pcre_vectors)
-	{
-		Buffer b;
-
-		b=strerror(errno);
-		b += "\n";
-		b += '\0';
-		merr.write(b);
-		return -1;
-	}
 
 	while (*opts)
 	{
@@ -166,30 +147,40 @@ int Search::find(const char *str, const char *expr, const char *opts,
 
 	int startoffset=0;
 	const char *orig_str=str;
-	int match_count=0;
 
 	for (;;)
 	{
-		match_count=pcre_exec(pcre_regexp, pcre_regexp_extra,
-				      orig_str, strlen(orig_str),
-				      startoffset,
-				      0,
-				      pcre_vectors,
-				      pcre_vector_count);
-		if (match_count <= 0)
+		int rc=pcre2_match(pcre_regexp,
+				   (PCRE2_SPTR8)orig_str,
+				   strlen(orig_str),
+				   startoffset,
+				   0,
+				   match_data,
+				   NULL);
+
+		if (rc < 0 )
 			break;
-		startoffset=pcre_vectors[1];
+
+
+		PCRE2_SIZE *ovector=pcre2_get_ovector_pointer(match_data);
+		uint32_t ovector_count=pcre2_get_ovector_count(match_data);
 
 		score += weight1;
 		weight1 *= weight2;
 
 		if (!scoring_match || foreachp)
 		{
-			init_match_vars(orig_str, match_count,
-					pcre_vectors, foreachp);
+			init_match_vars(orig_str, ovector, ovector_count,
+					foreachp);
 			if (!foreachp)
 				break;
 		}
+
+		if (!ovector || ovector_count <= 0)
+			break;
+
+		startoffset=ovector[1];
+
 	}
 	return (0);
 }
@@ -263,27 +254,32 @@ int Search::search_cb(const char *ptr, size_t cnt)
 			}
 
 			const char *orig_str=current_line;
-			int match_count;
-
-			match_count=pcre_exec(pcre_regexp,
-					      pcre_regexp_extra,
-					      orig_str,
-					      strlen(orig_str),
-					      0,
-					      0,
-					      pcre_vectors,
-					      pcre_vector_count);
-
-			if (match_count > 0)
+
+			int rc=pcre2_match(pcre_regexp,
+					   (PCRE2_SPTR8)orig_str,
+					   strlen(orig_str),
+					   0,
+					   0,
+					   match_data,
+					   NULL);
+
+			if (rc >= 0)
 			{
 				score += weight1;
 				weight1 *= weight2;
 
 				if (!scoring_match || foreachp_arg)
 				{
+					PCRE2_SIZE *ovector=
+						pcre2_get_ovector_pointer(
+							match_data);
+					uint32_t ovector_count=
+						pcre2_get_ovector_count(
+							match_data);
+
 					init_match_vars(orig_str,
-							match_count,
-							pcre_vectors,
+							ovector,
+							ovector_count,
 							foreachp_arg);
 					if (!foreachp_arg)
 						// Stop searching now
@@ -311,11 +307,16 @@ int Search::search_cb(const char *ptr, size_t cnt)
 	return (0);
 }
 
-void Search::init_match_vars(const char *str, int nranges, int *offsets,
+void Search::init_match_vars(const char *str,
+			     PCRE2_SIZE *offsets,
+			     uint32_t nranges,
 			     Buffer *foreachp)
 {
 	Buffer varname;
-	int cnt;
+	uint32_t cnt;
+
+	if (!offsets)
+		return;
 
 	for (cnt=0; cnt<nranges; cnt++)
 	{
diff --git a/maildrop/search.h b/maildrop/search.h
index 681c082..963ea8c 100644
--- a/libs/maildrop/search.h
+++ b/libs/maildrop/search.h
@@ -4,11 +4,9 @@
 
 #include	"buffer.h"
 
-#if	HAVE_PCRE_H
-#include	<pcre.h>
-#else
-#include	<pcre/pcre.h>
-#endif
+#define PCRE2_CODE_UNIT_WIDTH 8
+
+#include <pcre2.h>
 
 ////////////////////////////////////////////////////////////////////////////
 //
@@ -42,10 +40,8 @@ class Message;
 
 class Search {
 
-	pcre	*pcre_regexp;
-	pcre_extra *pcre_regexp_extra;
-	int	*pcre_vectors;
-	size_t	pcre_vector_count;
+	pcre2_code *pcre_regexp;
+	pcre2_match_data *match_data;
 
 	Buffer	current_line;
 	Buffer	next_line;
@@ -62,8 +58,8 @@ public:
 	double	score;	// For weighted scoring.  Without scoring, this is
 			// either 0, or 1.
 
-	Search() : pcre_regexp(NULL), pcre_regexp_extra(NULL),
-		pcre_vectors(NULL)	{}
+	Search() : pcre_regexp(NULL),
+		   match_data(NULL) {}
 	~Search()	{ cleanup(); }
 	int find(Message &, MessageInfo &, const char *, const char *,
 		Buffer *);
@@ -71,8 +67,10 @@ public:
 private:
 	int findinline(Message &, const char *, Buffer *);
 	int findinsection(Message &, const char *, Buffer *);
-	void init_match_vars(const char *, int, int *, Buffer *);
-
+	void init_match_vars(const char *,
+			     PCRE2_SIZE *,
+			     uint32_t,
+			     Buffer *);
 	Buffer search_expr;
 	Buffer *foreachp_arg;
 	static int search_cb(const char *ptr, size_t cnt, void *arg);
diff --git a/configure.ac b/configure.ac
index d118fec..e311082 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,18 +17,6 @@ AC_PROG_LN_S
 AC_PROG_MAKE_SET
 AM_PROG_LIBTOOL
 
-AC_CHECK_HEADER([pcre.h],
-		[ : ],
-		[
-
-		AC_CHECK_HEADER([pcre/pcre.h],
-				[ : ],
-				[
-						AC_MSG_ERROR(pcre.h not found - install PCRE from www.pcre.org)
-				])
-		]
-)
-
 test "x$prefix" = xNONE && prefix=$ac_default_prefix
 test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
 
--
2.27.0
