--- a/innd/perl.c
+++ b/innd/perl.c
@@ -45,6 +45,7 @@ char *artBody;
    int		rc;
    char		*p;
    static char	buf[256];
+   char		*argv[] = { NULL };
 
    if (!PerlFilterActive || perl_filter_cv == NULL)
      return NULL;
@@ -59,7 +60,11 @@ char *artBody;
 
    /* store article body */
    if (artBody != NULL)
+#if (PERL_VERSION < 7) || ((PERL_VERSION == 7) && (PERL_SUBVERSION < 1))
      hv_store(hdr, (char *) "__BODY__", 8, newSVpv(artBody, 0), 0) ;
+#else
+     hv_store(hdr, "__BODY__", 8, newSVpvn_share(artBody, 0, 42), 0);
+#endif /* Perl < 5.7.1 */
 
    if (pathForPerl != NULL)
      {
@@ -73,7 +78,7 @@ char *artBody;
    ENTER ;
    SAVETMPS ;
 
-   rc = perl_call_argv ("filter_art", G_EVAL|G_SCALAR,NULL);
+   rc = perl_call_argv ("filter_art", G_EVAL|G_SCALAR, argv);
 
    SPAGAIN;
 
@@ -168,6 +173,7 @@ char		*reason;
 {
     dSP ;
     HV	*hdr;
+    char *argv[] = { NULL };
 
     ENTER ;
     SAVETMPS ;
@@ -191,7 +197,7 @@ char		*reason;
     hv_store(hdr, "reason", 6, newSVpv(reason, 0), 0);
 
     if (perl_get_cv("filter_mode", FALSE) != NULL) {
-        perl_call_argv("filter_mode", G_EVAL|G_DISCARD|G_NOARGS, NULL);
+        perl_call_argv("filter_mode", G_EVAL|G_DISCARD|G_NOARGS, argv);
         if (SvTRUE(ERRSV)) { /* check $@ */
             syslog (L_ERROR,"Perl function filter_mode died: %s",
                     SvPV(ERRSV, PL_na)) ;
--- a/lib/perl.c
+++ b/lib/perl.c
@@ -33,11 +33,15 @@ static void use_rcsid (const char *rid)
 #include "macros.h"
 
 extern void xs_init    _((pTHX));
-extern void boot_DynaLoader _((CV* cv));
+XS(boot_DynaLoader);
+
+void PerlSilence(void);
+void PerlUnSilence(void);
+
 
 int	PerlFilterActive = FALSE;
 
-PerlInterpreter	*PerlCode;
+PerlInterpreter	*PerlCode = NULL;
 CV *perl_filter_cv ;                 /* filter_art or filter_post holder */
 extern char	LogName[];
 
@@ -52,6 +55,7 @@ PerlFilter(value)
   BOOL value ;
 {
     dSP;
+    char *argv[] = { NULL };
 
     ENTER ;
     SAVETMPS ;
@@ -59,7 +63,7 @@ PerlFilter(value)
     /* Execute an end function */
     if (PerlFilterActive && !value) {
         if (perl_get_cv("filter_end", FALSE) != NULL) {
-            perl_call_argv("filter_end", G_EVAL|G_DISCARD|G_NOARGS, NULL);
+            perl_call_argv("filter_end", G_EVAL|G_DISCARD|G_NOARGS, argv);
             if (SvTRUE(ERRSV))     /* check $@ */ {
                 syslog (L_ERROR,"%s perl function filter_end died: %s",
                         LogName, SvPV(ERRSV, PL_na)) ;
@@ -110,23 +114,36 @@ PERLsetup (startupfile, filterfile, func
     char *startupfile, *filterfile, *function;
 {
     if (PerlCode == NULL) {
+        /* Perl waits on standard input if not called with '-e'. */
+        int argc = 3;
+        const char *argv_innd[] = { "innd", "-e", "0", NULL };
+        char **argv = (char **)argv_innd; /* Cast required by Perl 5.10. */
+        char **env  = { NULL };
+#ifdef PERL_SYS_INIT3
+        PERL_SYS_INIT3(&argc, &argv, &env);
+#endif
         PerlCode = perl_alloc();
         perl_construct(PerlCode);
-        PerlParse () ;
+        PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
+        perl_parse(PerlCode, xs_init, argc, argv, env) ;
     }
     
     if (startupfile != NULL && filterfile != NULL) {
-        char *argv[2] ;
-        int rc ;
+        char *evalfile = NULL;
+        size_t length;
         dSP;
     
         ENTER ;
         SAVETMPS ;
     
-        argv[0] = startupfile ;
-        argv[1] = NULL ;
-        
-        rc = perl_call_argv ("_load_",G_DISCARD, argv) ;
+        /* The Perl expression which will be evaluated. */
+        length = strlen("do '%s'") + strlen(startupfile);
+        evalfile = xmalloc(length);
+        snprintf(evalfile, length, "do '%s'", startupfile);
+
+        PerlSilence();
+        perl_eval_pv(evalfile, TRUE);
+        PerlUnSilence();
         
         SPAGAIN ;
         
@@ -157,16 +174,15 @@ PERLreadfilter(filterfile, function)
   char  *filterfile, *function ;
 {
     dSP ;
-    char *argv [3] ;
+    char *argv[] = { NULL };
+    char *evalfile = NULL;
+    size_t length;
     
     ENTER ;
     SAVETMPS ;
     
-    argv[0] = filterfile ;
-    argv[1] = NULL ;
-    
     if (perl_get_cv("filter_before_reload", FALSE) != NULL)    {
-        perl_call_argv("filter_before_reload",G_EVAL|G_DISCARD|G_NOARGS,NULL);
+        perl_call_argv("filter_before_reload",G_EVAL|G_DISCARD|G_NOARGS,argv);
         if (SvTRUE(ERRSV))     /* check $@ */ {
             syslog (L_ERROR,"%s perl function filter_before_reload died: %s",
                     LogName, SvPV(ERRSV, PL_na)) ;
@@ -175,7 +191,17 @@ PERLreadfilter(filterfile, function)
         }
     }
 
-    perl_call_argv ("_load_", 0, argv) ;
+    /* The Perl expression which will be evaluated. */
+    length = strlen("do '%s'") + strlen(filterfile);
+    evalfile = xmalloc(length);
+    snprintf(evalfile, length, "do '%s'", filterfile);
+
+    PerlSilence();
+    perl_eval_pv(evalfile, TRUE);
+    PerlUnSilence();
+
+    free(evalfile);
+    evalfile = NULL;
 
     if (SvTRUE(ERRSV))     /* check $@ */ {
         syslog (L_ERROR,"%s perl loading %s failed: %s",
@@ -184,21 +210,21 @@ PERLreadfilter(filterfile, function)
         
         /* If the reload failed we don't want the old definition hanging
            around. */
-        argv[0] = NEW (char,strlen (function) + strlen ("undef &%s")) ;
-        sprintf (argv[0],"undef &%s",function) ;
-        perl_call_argv ("_eval_",0,argv) ;
+        length = strlen("undef &%s") + strlen(function);
+        evalfile = xmalloc(length);
+        snprintf(evalfile, length, "undef &%s", function);
+        perl_eval_pv(evalfile, TRUE);
 
         if (SvTRUE(ERRSV))     /* check $@ */ {
             syslog (L_ERROR,"%s perl undef &%s failed: %s",
                     LogName, function, SvPV(ERRSV, PL_na)) ;
         }
-        DISPOSE (argv[0]) ;
     } else if ((perl_filter_cv = perl_get_cv(function, FALSE)) == NULL) {
         PerlFilter (FALSE) ;
     }
     
     if (perl_get_cv("filter_after_reload", FALSE) != NULL) {
-        perl_call_argv("filter_after_reload", G_EVAL|G_DISCARD|G_NOARGS, NULL);
+        perl_call_argv("filter_after_reload", G_EVAL|G_DISCARD|G_NOARGS, argv);
         if (SvTRUE(ERRSV))     /* check $@ */ {
             syslog (L_ERROR,"%s perl function filter_after_reload died: %s",
                     LogName, SvPV(ERRSV, PL_na)) ;
@@ -220,17 +246,126 @@ PERLreadfilter(filterfile, function)
 void
 PerlClose()
 {
-   perl_destruct(PerlCode);
-   perl_free(PerlCode);
+   if (PerlCode !=  NULL) {
+      perl_destruct(PerlCode);
+      perl_free(PerlCode);
+#ifdef PERL_SYS_TERM
+      PERL_SYS_TERM();
+#endif
+   }
    PerlFilterActive = FALSE;
 }
 
+/*
+**  Redirects STDOUT/STDERR briefly (otherwise PERL complains to the net
+**  connection for NNRPD and that just won't do) -- dave@jetcafe.org
+*/
+static int savestdout = 0;
+static int savestderr = 0;
+void PerlSilence(void)
+{
+  int newfd;
+
+  /* Save the descriptors */
+  if ( (savestdout = dup(1)) < 0) {
+    syslog(L_ERROR,"SERVER perl silence cant redirect stdout: %m");
+    savestdout = 0;
+    return;
+  }
+  if ( (savestderr = dup(2)) < 0) {
+    syslog(L_ERROR,"SERVER perl silence cant redirect stderr: %m");
+    savestdout = 0;
+    savestderr = 0;
+    return;
+  }
+
+  /* Open /dev/null */
+  if ((newfd = open("/dev/null",O_WRONLY)) < 0) {
+    syslog(L_ERROR,"SERVER perl silence cant open /dev/null: %m");
+    savestdout = 0;
+    savestderr = 0;
+    return;
+  }
+
+  /* Redirect descriptors */
+  if (dup2(newfd,1) < 0) {
+    syslog(L_ERROR,"SERVER perl silence cant redirect stdout: %m");
+    savestdout = 0;
+    return;
+  }
+
+  if (dup2(newfd,2) < 0) {
+    syslog(L_ERROR,"SERVER perl silence cant redirect stderr: %m");
+    savestderr = 0;
+    return;
+  }
+  close(newfd);
+}
+
+void PerlUnSilence(void) {
+  if (savestdout != 0) {
+    if (dup2(savestdout,1) < 0) {
+      syslog(L_ERROR,"SERVER perl silence cant restore stdout: %m");
+    }
+    close(savestdout);
+    savestdout = 0;
+  }
+
+  if (savestderr != 0) {
+    if (dup2(savestderr,2) < 0) {
+      syslog(L_ERROR,"SERVER perl silence cant restore stderr: %m");
+    }
+    close(savestderr);
+    savestderr = 0;
+  }
+}
+
+/*
+**  The remainder of this file consists of XS callbacks usable by either
+**  innd or nnrpd and initialized automatically when the Perl filter is
+**  initialized, as well as the function that initializes them.
+*/
+
+/*
+**  Log a message via syslog.  Only the first letter of the priority
+**  matters, and this function assumes that the controlling program has
+**  already done an openlog().  The argument must be a complete message, not
+**  a printf-style format.
+*/
+XS(XS_INN_syslog)
+{
+    dXSARGS;
+    const char *loglevel;
+    const char *logmsg;
+    int priority;
+
+    if (items != 2)
+        croak("Usage: INN::syslog(level, message)");
+
+    loglevel = (const char *) SvPV(ST(0), PL_na);
+    logmsg = (const char *) SvPV(ST(1), PL_na);
+
+    switch (*loglevel) {
+        default:                priority = LOG_NOTICE;
+        case 'a': case 'A':     priority = LOG_ALERT;           break;
+        case 'c': case 'C':     priority = LOG_CRIT;            break;
+        case 'e': case 'E':     priority = LOG_ERR;             break;
+        case 'w': case 'W':     priority = LOG_WARNING;         break;
+        case 'n': case 'N':     priority = LOG_NOTICE;          break;
+        case 'i': case 'I':     priority = LOG_INFO;            break;
+        case 'd': case 'D':     priority = LOG_DEBUG;           break;
+    }
+    syslog(priority, "filter: %s", logmsg);
+    XSRETURN_UNDEF;
+}
+
 extern void xs_init(pTHX)
 {
     char * file = __FILE__;
     dXSUB_SYS;
 
     newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
+    newXS("INN::syslog", XS_INN_syslog, file);
 }
 	
 #endif /* defined(DO_PERL) */
--- a/nnrpd/perl.c
+++ b/nnrpd/perl.c
@@ -52,6 +52,7 @@ char *artBody;
    int		rc;
    char		*p;
    static char	buf[256];
+   char		*args[] = { NULL };
    register int   i;
    register char *s,*t;
    HE            *scan;
@@ -96,7 +97,7 @@ char *artBody;
    sv_setpv(body, artBody);
 
    /* Call the filtering function */
-   rc = perl_call_argv("filter_post", G_EVAL|G_SCALAR, NULL);
+   rc = perl_call_argv("filter_post", G_EVAL|G_SCALAR, args);
 
    SPAGAIN;
 
@@ -139,7 +140,7 @@ char *artBody;
    }
 
    hv_undef (hdr);
-   sv_setsv (body, &PL_sv_undef);
+   body = &PL_sv_undef;
 
    buf [0] = '\0' ;
    
--- a/innd/cc.c
+++ b/innd/cc.c
@@ -860,13 +860,15 @@ CCmode(av)
     /* perl filter status */
 
     if (perl_get_cv("filter_stats", FALSE) != NULL) {
+	char *argv[] = { NULL };
+
         *p++ = '\n';
         p += strlen(strcpy(p, "Perl filter stats: "));
  
 	ENTER ;
 	SAVETMPS;
     
-	perl_call_argv("filter_stats", G_EVAL|G_NOARGS, NULL);
+	perl_call_argv("filter_stats", G_EVAL|G_NOARGS, argv);
 
 	SPAGAIN;
 
