From 4238d38f75d45793521a3b49ba421413d2b53a21 Mon Sep 17 00:00:00 2001
From: Sam Varshavchik
Date: Sun, 23 Jul 2017 23:16:48 -0400
Subject: maildrop: add the "system" command.
---
 maildrop/filter.C            | 63 +++++++++++++++++++++++++++++++++++++++++++-
 maildrop/funcs.h             |  1 +
 maildrop/lexer.C             |  3 +++
 maildrop/maildrop.sgml       | 13 +++++++--
 maildrop/maildropfilter.sgml | 26 +++++++++++++++++-
 maildrop/recipenode.C        | 13 ++++++++-
 maildrop/recipenode.h        |  1 +
 maildrop/recipeparse.C       |  8 ++++++
 maildrop/token.C             |  1 +
 maildrop/token.h             |  1 +
 10 files changed, 125 insertions(+), 5 deletions(-)
diff --git a/maildrop/filter.C b/maildrop/filter.C
index d59e2ec..abc3872 100644
--- a/maildrop/filter.C
+++ b/maildrop/filter.C
@@ -100,7 +100,7 @@ pid_t	pid=fork();
 		{
 			if (write(2, p, strlen(p)) < 0 ||
 			    write(2, "\n", 1) < 0)
-				; /* ignore */ 
+				; /* ignore */
 			_exit(100);
 		}
 #if NEED_NONCONST_EXCEPTIONS
@@ -273,3 +273,64 @@ int	wait_stat;
 		return (-1);
 	return (0);
 }
+
+void executesystem(const char *cmd)
+{
+	int devnull=open("/dev/null", O_RDONLY);
+	pid_t	pid;
+
+	if (devnull < 0)
+		throw "Cannot open /dev/null";
+
+	pid=fork();
+	if (pid < 0)
+	{
+		close(devnull);
+		throw "Cannot fork.";
+	}
+
+	if (pid == 0)
+	{
+		try
+		{
+			dup2(devnull, 0);
+			close(devnull);
+			subshell(cmd);
+		}
+		catch (const char *p)
+		{
+			if (write(2, p, strlen(p)) < 0 ||
+			    write(2, "\n", 1) < 0)
+				; /* ignore */
+			_exit(100);
+		}
+#if NEED_NONCONST_EXCEPTIONS
+		catch (char *p)
+		{
+			if (write(2, p, strlen(p)) < 0 ||
+			    write(2, "\n", 1) < 0)
+				; /* ignore */
+			_exit(100);
+		}
+#endif
+		catch (...)
+		{
+			_exit(101);
+		}
+	}
+	close(devnull);
+
+int	wait_stat;
+
+	while (wait(&wait_stat) != pid)
+		;
+	wait_stat= WIFEXITED(wait_stat) ? WEXITSTATUS(wait_stat):-1;
+
+	{
+	Buffer	name, val;
+
+		val.append( (unsigned long)wait_stat);
+		name="RETURNCODE";
+		SetVar(name, val);
+	}
+}
diff --git a/maildrop/funcs.h b/maildrop/funcs.h
index 3ac3a5e..ad17bac 100644
--- a/maildrop/funcs.h
+++ b/maildrop/funcs.h
@@ -20,6 +20,7 @@ extern int verbose_level;
 const char *GetDefaultMailbox(const char *);
 int	delivery(const char *);
 int	filter(const char *);
+void	executesystem(const char *);
 void	subshell(const char *);
 const char *TempName();	// Return temporary filename
 const char *TempName(const char *, unsigned=0);	// ... with this prefix.
diff --git a/maildrop/lexer.C b/maildrop/lexer.C
index 99732dd..65e019a 100644
--- a/maildrop/lexer.C
+++ b/maildrop/lexer.C
@@ -41,6 +41,7 @@ void	Lexer::token(Token &t)
 		case Token::tokencc:
 		case Token::btstring:
 		case Token::tokenxfilter:
+		case Token::tokensystem:
 		case Token::dotlock:
 		case Token::flock:
 		case Token::logfile:
@@ -346,6 +347,8 @@ missquote:
 			t.Type(Token::echo);
 		else if (pattern == "xfilter")
 			t.Type(Token::tokenxfilter);
+		else if (pattern == "system")
+			t.Type(Token::tokensystem);
 		else if (pattern == "dotlock")
 			t.Type(Token::dotlock);
 		else if (pattern == "flock")
diff --git a/maildrop/maildrop.sgml b/maildrop/maildrop.sgml
index b476d71..ca5beba 100644
--- a/maildrop/maildrop.sgml
+++ b/maildrop/maildrop.sgml
@@ -619,6 +619,13 @@ The log command is not allowed in embedded mode.
 The logfile command is not allowed in embedded mode.
 	  
 	
+	
+	  system
+	  
+
+The system command is not allowed in embedded mode.
+	  
+	
 	
 	  to
 	  
@@ -663,8 +670,10 @@ suspended for any additional filter files that are included from
 
       
 This allows the system administrator to have a controlled environment for
-running external commands (via the backticks, or the
-xfilter command).
+running external commands (via the backticks, the
+system
+or the
+xfilter commands).
 
       
 The name of the file may not contain any periods (so that a creative
diff --git a/maildrop/maildropfilter.sgml b/maildrop/maildropfilter.sgml
index 4d91abc..c97aeec 100644
--- a/maildrop/maildropfilter.sgml
+++ b/maildrop/maildropfilter.sgml
@@ -511,7 +511,9 @@ MAILBOX="${HOME-WORD}/Mailbox"
 
 	
 	RETURNCODEThis variable is set when maildrop
-	      runs the xfilter command, or a command that's
+	      runs the
+	      system command,
+	      xfilter command, or a command that's
 	      specified within a pair of backtick characters ( command substitution ).
 	      The RETURNCODE variable will be set to the exit code of the
 	      command, after it completes.
@@ -1484,6 +1486,28 @@ log expression
 	  standard output.
       
 
+      
+	system - execute a system command
+	
+
+	
+	  
+	    
+system expression
+	    
+	  
+	
+
+	
+	  expression specifies an external program
+	  that
+	  maildrop runs as a subprocess.
+	  The subprocess's standard input gets connected to
+	  /dev/null, and the subprocess inherits
+	  the standard output and error from
+	   maildrop.
+      
+
       
 	to - deliver message to a mailbox
 	
diff --git a/maildrop/recipenode.C b/maildrop/recipenode.C
index c69c017..031eec0 100644
--- a/maildrop/recipenode.C
+++ b/maildrop/recipenode.C
@@ -496,7 +496,7 @@ RecipeNode	*c;
 				debug += '\0';
 				r.errmsg(*this, debug);
 			}
-	
+
 		long l=bb.Length();
 
 			if (n < 0 || n > l)	n=l;
@@ -622,6 +622,17 @@ RecipeNode	*c;
 			throw "Unable to filter message.";
 		b = "0";
 		break;
+	case system:
+		if (!firstChild)
+			throw "Internal error in system statement.";
+		firstChild->Evaluate(r,b);
+		b += '\0';
+		if (VerboseLevel() > 0)
+			merr << "maildrop: Executing system command " <<
+				(const char *)b << "\n";
+		executesystem(b);
+		b = "0";
+		break;
 	case exception:
 		if (!firstChild)
 			throw "Internal error in delivery statement.";
diff --git a/maildrop/recipenode.h b/maildrop/recipenode.h
index cff0a7a..4a76a42 100644
--- a/maildrop/recipenode.h
+++ b/maildrop/recipenode.h
@@ -97,6 +97,7 @@ public:
 		exception,
 		echo,
 		xfilter,
+		system,
 		dotlock,
 		flock,
 		logfile,
diff --git a/maildrop/recipeparse.C b/maildrop/recipeparse.C
index f43cc1b..6a83042 100644
--- a/maildrop/recipeparse.C
+++ b/maildrop/recipeparse.C
@@ -173,6 +173,14 @@ RecipeNode *n, *o;
 			throw "Syntax error.";
 		lex->token(cur_tok);
 		return (n);
+	case Token::tokensystem:
+		lex->token(cur_tok);
+		n=alloc(RecipeNode::system);
+		n->AppendSibling( ParseExpr());
+		if (cur_tok.Type() != Token::semicolon)
+			throw "Syntax error.";
+		lex->token(cur_tok);
+		return (n);
 	case Token::dotlock:
 		lex->token(cur_tok);
 		n=alloc(RecipeNode::dotlock);
diff --git a/maildrop/token.C b/maildrop/token.C
index c6ab42d..59ca3e0 100644
--- a/maildrop/token.C
+++ b/maildrop/token.C
@@ -50,6 +50,7 @@ static const char *names[]={
 		"exception",
 		"echo",
 		"xfilter",
+		"system",
 		"dotlock",
 		"flock",
 		"logfile",
diff --git a/maildrop/token.h b/maildrop/token.h
index 0a97471..f2829b1 100644
--- a/maildrop/token.h
+++ b/maildrop/token.h
@@ -65,6 +65,7 @@ public:
 		exception,
 		echo,
 		tokenxfilter,
+		tokensystem,
 		dotlock,
 		flock,
 		logfile,
-- 
cgit v1.2.3