--- /home/.cpan/build/Mail-SpamAssassin-3.2.4-GVUlHj/blib/lib/Mail/SpamAssassin/Plugin/Check.pm	2008-01-05 15:10:50.000000000 -0600
+++ Check.pm	2008-04-07 10:34:21.000000000 -0500
@@ -18,6 +18,7 @@
 use Mail::SpamAssassin::Logger;
 use Mail::SpamAssassin::Util;
 use Mail::SpamAssassin::Constants qw(:sa);
+use IO::File ();
 
 use strict;
 use warnings;
@@ -47,6 +48,8 @@
 
   my $pms = $args->{permsgstatus};
 
+
+  $self->setup_eval_cache_dirs($pms);
   # bug 4353:
   # Do this before the RBL tests are kicked off.  The metadata parsing
   # will figure out the (un)trusted relays and such, which are used in the
@@ -242,8 +245,9 @@
   }
 
   # build up the eval string...
-  $self->{evalstr} = $self->start_rules_plugin_code($ruletype, $priority);
-  $self->{evalstr2} = '';
+  $self->init_evalstr(1);
+  $self->init_evalstr(2);
+  $self->add_evalstr($self->start_rules_plugin_code($ruletype, $priority));
 
   # use %nopts for named parameter-passing; it's more friendly to future-proof
   # subclassing, since new parameters can be added without breaking third-party
@@ -269,29 +273,36 @@
   undef &{$methodname};
   $self->free_ruleset_source($pms, $ruletype, $priority);
 
+  my $code_file = $self->{evalpath} . '/' . $ruletype . '_' . $priority . '.pm'; #should use file::spec ?
+  my $eval_fh = new IO::File $code_file, 'w';
+  
   my $evalstr = $self->{evalstr};
 
   # generate the loop that goes through each line...
-  $evalstr = <<"EOT";
+  print {$eval_fh} "
   {
     package $package_name;
 
-    $self->{evalstr2}
-
+    ";
+  $self->write_eval_code_to_fh(2,$eval_fh);
+  print {$eval_fh} "
     sub $methodname {
       my \$self = shift;
-      $evalstr;
+      ";
+  $self->write_eval_code_to_fh(1,$eval_fh);
+  print {$eval_fh} '
     }
-
     1;
   }
-EOT
+  ';
 
-  delete $self->{evalstr};
-  delete $self->{evalstr2}; # free up some RAM before we eval()
+  $self->stop_evalstr(1); #close file
+  $self->stop_evalstr(2); #close file
+  $eval_fh->close();
 
   ## dbg ("rules: eval code to compile: $evalstr");
-  eval $evalstr;
+  dbg("brining in: " . $code_file );
+  eval { do $code_file; };
   if ($@) {
     warn("rules: failed to compile $ruletype tests, skipping:\n\t($@)\n");
     $pms->{rule_errors}++;
@@ -302,16 +313,64 @@
   }
 }
 
+sub setup_eval_cache_dirs {
+	my ($self,$pms) = @_;
+	$self->{'evalpath'} = $pms->{main}->sed_path('__local_state_dir__/evalcache/__version__');
+	dbg('check: eval path is ' . $self->{'evalpath'});
+	if (! -e $self->{'evalpath'}) {
+		my $evalbase = $pms->{main}->sed_path('__local_state_dir__/evalcache');
+		dbg("check: eval base is $evalbase");
+		if (! -e $evalbase) {
+			mkdir($evalbase,0755);
+		}
+
+		mkdir($self->{evalpath},0755);
+	}
+}
+
+sub init_evalstr {
+	my($self,$strnum) = @_;
+	$self->stop_evalstr($strnum);
+	$self->{eval_files}->{$strnum} = IO::File->new_tmpfile();
+}
+
+sub stop_evalstr {
+	my($self,$strnum) = @_;
+	if (exists $self->{eval_files}->{$strnum} && ref $self->{eval_files}->{$strnum} =~ /IO::File/) { $self->{eval_files}->{$strnum}->close(); }
+}
+
+sub write_eval_code_to_fh {
+	my ($self,$strnum,$fh) = @_;
+
+	if ( $_[0]->{eval_files}->{$strnum}) {
+		seek($_[0]->{eval_files}->{$strnum}, 0 , 0); #beginning of fh
+		while(readline($_[0]->{eval_files}->{$strnum})) {
+			print {$fh} $_;
+		}
+	}
+}
+
 sub add_evalstr {
-  my ($self, $str) = @_;
-  $self->{evalstr} .= $str;
+	#avoid allocating new memory for variables
+	#$_[0] is self
+	#$_[1] is the code
+	if (!defined $_[0]->{eval_files}->{1}) {
+		warn("rules: failed to open temporary perl file");
+	}
+	#write the eval code to the temp file
+	print {$_[0]->{eval_files}->{1}} $_[1];
 }
 
 sub add_evalstr2 {
-  my ($self, $str) = @_;
-  $self->{evalstr2} .= $str;
+	#avoid allocating new memory for variables
+	#$_[0] is self
+	#$_[1] is the code
+	if (!defined $_[0]->{eval_files}->{2}) {
+		warn("rules: failed to open temporary perl file");
+	}
+	#write the eval code to the temp file
+	print {$_[0]->{eval_files}->{2}} $_[1];
 }
-
 sub add_temporary_method {
   my ($self, $methodname, $methodbody) = @_;
   $self->add_evalstr2 (' sub '.$methodname.' { '.$methodbody.' } ');
@@ -881,9 +940,26 @@
   my $have_start_rules = $self->{main}->have_plugin("start_rules");
   my $have_ran_rule = $self->{main}->have_plugin("ran_rule");
 
-  # the buffer for the evaluated code 
-  my $evalstr = q{ };
-  $evalstr .= q{ my $function; };
+  # the fh for the evaluated code 
+  my $code_file = $self->{evalpath} . '/' . 'eval' . '_' . $priority . '.pm'; #should use file::spec ?
+  my $eval_fh = new IO::File $code_file, 'w';
+  print {$eval_fh}
+"
+{
+  package $package_name;
+
+    sub ${methodname} {
+      my (\$self, \@extraevalargs) = \@_;
+
+      my \$scoresptr = \$self->{conf}->{scores};
+      my \$prepend2desc = q#$prepend2desc#;
+      my \$rulename;
+      my \$result;
+
+      ";
+
+
+  print {$eval_fh} q{ my $function; };
  
   # conditionally include the dbg in the eval str
   my $dbgstr = q{ };
@@ -915,7 +991,7 @@
       next;
     }
  
-    $evalstr .= '
+     print {$eval_fh} '
     if ($scoresptr->{q#'.$rulename.'#}) {
       $rulename = q#'.$rulename.'#;
       $self->{test_log_msgs} = ();
@@ -925,7 +1001,7 @@
     if ($eval_pluginsref->{$function}) {
       # let plugins get the name of the rule that is currently being run,
       # and ensure their eval functions exist
-      $evalstr .= '
+       print {$eval_fh} '
 
         $self->{current_rule_name} = $rulename;
         $self->register_plugin_eval_glue(q#'.$function.'#);
@@ -937,7 +1013,7 @@
     # no plugin is loaded for those hooks
     if ($have_start_rules) {
       # XXX - should we use helper function here?
-      $evalstr .= '
+       print {$eval_fh} '
 
         $self->{main}->call_plugins("start_rules", {
                 permsgstatus => $self,
@@ -948,7 +1024,7 @@
       ';
     }
  
-    $evalstr .= '
+     print {$eval_fh} '
 
       eval {
         $result = $self->' . $function . ' (@extraevalargs '. $argstr .' );
@@ -959,7 +1035,7 @@
 
     if ($have_ran_rule) {
       # XXX - should we use helper function here?
-      $evalstr .= '
+       print {$eval_fh} '
 
         $self->{main}->call_plugins("ran_rule", {
             permsgstatus => $self, ruletype => "eval", rulename => $rulename
@@ -968,7 +1044,7 @@
       ';
     }
 
-    $evalstr .= '
+     print {$eval_fh} '
 
       if ($result) {
         $self->got_hit($rulename, $prepend2desc, ruletype => "eval", value => $result);
@@ -981,31 +1057,20 @@
   # don't free the eval ruleset here -- we need it in the compiled code!
 
   # nothing done in the loop, that means no rules 
-  return unless ($evalstr);
- 
-  $evalstr = <<"EOT";
-{
-  package $package_name;
-
-    sub ${methodname} {
-      my (\$self, \@extraevalargs) = \@_;
-
-      my \$scoresptr = \$self->{conf}->{scores};
-      my \$prepend2desc = q#$prepend2desc#;
-      my \$rulename;
-      my \$result;
-
-      $evalstr
+ print {$eval_fh} "
     }
 
   1;
 }
-EOT
+";
+
+  $eval_fh->close();
+  dbg("brining in: " . $code_file );
 
   undef &{$methodname};
-  eval $evalstr;
+  eval { do $code_file; };
 
-  if ($@) {
+    if ($@) {
     warn "rules: failed to compile eval tests, skipping some: $@\n";
     $self->{rule_errors}++;
   }
