--- qmail-smtpd.c.bfore-xf	Sat May 26 21:41:37 2007
+++ qmail-smtpd.c	Sat May 26 21:43:36 2007
@@ -39,6 +39,8 @@
 #define FDLOG 2
 
 #define MAXHOPS 100
+#define XFENVLEN 2048
+//#define XF_QUITASAP
 unsigned long databytes = 0;
 int timeout = 1200;
 unsigned int spfbehavior = 0;
@@ -173,6 +175,109 @@
   return;
   }
 
+// QMAIL SMTPEXTFORK patch start block
+void err_smtpxf450() {
+     out("450 ");
+  if (env_get("450SMTPEXTFORK"))
+     out(env_get("450SMTPEXTFORK"));
+  else
+     out("sorry, temporary mailbox failure imposed by local policy");
+  out(" (#4.3.0)\r\n"); flush();
+#ifdef XF_QUITASAP
+  sleep(2); _exit(1);
+#endif
+}
+void err_smtpxf421() {           
+     out("421 ");
+  if (env_get("421SMTPEXTFORK"))
+     out(env_get("421SMTPEXTFORK"));
+  else
+     out("sorry, service not available due to local policy");
+  out(" (#4.3.0)\r\n"); flush();
+#ifdef XF_QUITASAP
+  sleep(2); _exit(1);
+#endif
+}
+void err_smtpxf451() {           
+     out("451 ");
+  if (env_get("451SMTPEXTFORK"))
+     out(env_get("451SMTPEXTFORK"));
+  else
+     out("sorry, service not available due to local policy");
+  out(" (#4.3.0)\r\n"); flush();
+#ifdef XF_QUITASAP
+  sleep(2); _exit(1);
+#endif
+}
+void err_smtpxf454() {
+     out("454 ");
+  if (env_get("454SMTPEXTFORK"))
+     out(env_get("454SMTPEXTFORK"));
+  else
+     out("sorry, temporary envelope failure due to local policy");
+  out(" (#5.7.1)\r\n"); flush();
+#ifdef XF_QUITASAP
+  sleep(2); _exit(1);
+#endif
+
+}
+void err_smtpxf501() {           
+     out("501 ");
+  if (env_get("501SMTPEXTFORK"))
+     out(env_get("501SMTPEXTFORK"));
+  else
+     out("syntax error");
+  out(" (#5.7.1)\r\n"); flush();
+#ifdef XF_QUITASAP
+  sleep(2); _exit(1);
+#endif
+}
+void err_smtpxf503() {
+     out("503 ");
+  if (env_get("503SMTPEXTFORK"))
+     out(env_get("503SMTPEXTFORK"));
+  else
+     out("sorry, wrong usage of SMTP commands");
+  out(" (#5.7.1)\r\n"); flush();
+#ifdef XF_QUITASAP
+  sleep(2); _exit(1);
+#endif
+}
+void err_smtpxf550() {
+     out("550 ");
+  if (env_get("550SMTPEXTFORK"))
+     out(env_get("550SMTPEXTFORK"));
+  else
+     out("sorry, permanent failure imposed by local policy");
+  out(" (#5.7.1)\r\n"); flush();
+#ifdef XF_QUITASAP
+  sleep(2); _exit(1);
+#endif
+}
+void err_smtpxf553() {
+     out("552 ");
+  if (env_get("552SMTPEXTFORK"))
+     out(env_get("553SMTPEXTFORK"));
+  else
+     out("sorry, permanent mailbox failure due to local policy");
+  out(" (#5.7.1)\r\n"); flush();
+#ifdef XF_QUITASAP
+  sleep(2); _exit(1);
+#endif
+}
+void err_smtpxf554() {
+     out("554 ");
+  if (env_get("554SMTPEXTFORK"))
+     out(env_get("554SMTPEXTFORK"));
+  else
+     out("sorry, permanent envelope failure due to local policy"); 
+  out(" (#5.7.1)\r\n"); flush();
+#ifdef XF_QUITASAP
+  sleep(2); _exit(1);
+#endif
+}
+// QMAIL SMTPEXTFORK patch end block
+
 int err_child() { out("454 oops, problem with child and I can't auth (#4.3.0)\r\n"); return -1; }
 int err_fork() { out("454 oops, child won't start and I can't auth (#4.3.0)\r\n"); return -1; }
 int err_pipe() { out("454 oops, unable to open pipe and I can't auth (#4.3.0)\r\n"); return -1; }
@@ -778,6 +883,126 @@
 
 /* this file is too long ----------------------------------------- SMTP DIALOG */
 
+// QMAIL SMTPEXTFORK patch start block
+int xf_extfork()
+{
+  int i, child, wstat;
+  char *sep = ",";
+  char *prog;
+  char *brkt;
+  char var_ambiente[XFENVLEN];
+  char *rop[2];
+
+  if (!env_unset("REMOTEMF")) die_read();
+  if (!env_unset("REMOTERCPT")) die_read();
+  if (!env_unset("REMOTEHELO")) die_read();
+  if (!env_put2("REMOTEMF",mailfrom.s)) die_nomem();
+  if (!env_put2("REMOTERCPT",addr.s)) die_nomem();
+  if (!env_put2("REMOTEHELO",helohost.s)) die_nomem();
+
+  rop[1] = 0;
+
+if ( strlen(env_get("SMTPEXTFORK")) > XFENVLEN -1 ||  strlen(env_get("SMTPEXTFORK")) > XFENVLEN -1 )
+  {
+    logs("XF: SMTPEXTFORK(R) enviroment variable is too long (over 2k):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+    return;
+  }
+
+  // split horizon our own
+  if (!relayclient)
+  {
+    if (!(brkt=env_get("SMTPEXTFORK")))
+    {
+      logs("XF: SMTPEXTFORK enviroment variable is not defined:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+      return 1;
+    }
+    else
+     strncpy(var_ambiente,brkt,XFENVLEN -1);
+  }
+  else
+  {
+    if (!(brkt=env_get("SMTPEXTFORKR")))
+    {
+      //logs("XF: SMTPEXTFORKR env variable not defined in relay mode:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
+      return 1;
+    }
+    else
+     strncpy(var_ambiente,brkt,XFENVLEN -1);
+  }
+  // end split horizon
+
+  for (prog=strtok(var_ambiente, sep); prog ; prog=strtok(0, sep)) {
+
+	switch(child = vfork()) {
+	  case -1:
+	    return 1;
+	  case 0:
+	    rop[0] = prog;
+	    execv(rop[0], rop);
+	    _exit(111); // returns 111 if fork fails
+	}
+
+	wait_pid(&wstat,child);
+	
+	if (wait_crashed(wstat)) {
+	   logd("XF (#5c):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+	   return 1;
+	}
+
+	switch(wait_exitcode(wstat)) {
+	   case 101:
+	     logd("XF (101):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+	     err_smtpxf454(); return;
+	   break;
+	   case 103:
+	     logd("XF (103):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+	     err_smtpxf451(); return;
+	   break;
+           case 105:
+             logd("XF (105):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+             err_smtpxf421(); return;
+           break;
+           case 107:
+             logd("XF (107):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+             err_smtpxf450(); return;
+           break;
+	   case 100:
+	     logd("XF (100):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+	     err_smtpxf554(); return;
+	   break;
+           case 102:
+             logd("XF (102):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+             err_smtpxf550(); return;
+           break;
+           case 104:
+             logd("XF (104):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+             err_smtpxf553(); return;
+           break;
+           case 106:
+             logd("XF (106):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+             err_smtpxf503(); return;
+           break;
+           case 108:
+             logd("XF (108):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+             err_smtpxf501(); return;
+           break;
+	   case 111:
+	     logd("XF warn: cannot fork external program:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+	   break;
+	   case 0:
+	     logd("XF (0):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+	   break;
+	   default:
+	     logd("XF (#5d):",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s,prog);
+	   break;
+	}
+  }
+	return 1; /* if there is no more external program to fork
+			and no err_smtpxfXXX was issued, we should return 1 */
+}
+// QMAIL SMTPEXTFORK patch end block
+
+
 void smtp_helo(arg) char *arg;
 {
   smtp_greet("250 "); out("\r\n");
@@ -1050,6 +1275,10 @@
     err_size(); 
     logs("Reject::DATA::Invalid_Size:",protocol.s,remoteip,remotehost,helohost.s,mailfrom.s,addr.s);
     return;
+  }
+
+  if (env_get("SMTPEXTFORK") || env_get("SMTPEXTFORKR")) {
+	if (!xf_extfork()) return;
   }
 
 /* this file is too long --------------------------------- Checks done; mailfrom/recipient accepted */
