http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.04.2.tar.gz
[xscreensaver] / hacks / webcollage
index bb3c66ef6ded01d0434310ae4c87528fb52b21b9..260230abba83d01c820af5991d726579efbcc9f9 100755 (executable)
@@ -35,32 +35,36 @@ use POSIX qw(strftime);
 
 
 my $progname = $0; $progname =~ s@.*/@@g;
-my $version = q{ $Revision: 1.87 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/;
+my $version = q{ $Revision: 1.93 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/;
 my $copyright = "WebCollage $version, Copyright (c) 1999-2002" .
     " Jamie Zawinski <jwz\@jwz.org>\n" .
     "            http://www.jwz.org/xscreensaver/\n";
 
 
 
-my @search_methods = (  30, "imagevista", \&pick_from_alta_vista_images,
-                        28, "altavista",  \&pick_from_alta_vista_text,
-                        18, "yahoorand",  \&pick_from_yahoo_random_link,
-                        14, "googleimgs", \&pick_from_google_images,
+my @search_methods = (  40, "imagevista", \&pick_from_alta_vista_images,
+                        30, "altavista",  \&pick_from_alta_vista_text,
+                        19, "yahoorand",  \&pick_from_yahoo_random_link,
+                         9, "lycos",      \&pick_from_lycos_text,
                          2, "yahoonews",  \&pick_from_yahoo_news_text,
-                         8, "lycos",      \&pick_from_lycos_text,
 
                      # Hotbot gives me "no matches" just about every time.
                      # Then I try the same URL again, and it works.  I guess
                      # it caches searches, and webcollage always busts its
                      # cache and time out?  Or it just sucks.
                      #   0, "hotbot",     \&pick_from_hotbot_text,
+
+                     # Google asked (nicely) for me to stop searching them.
+                     #   0, "googlenums", \&pick_from_google_image_numbers,
+                     #   0, "googleimgs", \&pick_from_google_images,
+
                       );
 
 # programs we can use to write to the root window (tried in ascending order.)
 #
 my @root_displayers = (
   "chbg       -once -xscreensaver -max_size 100",
-  "xv         -root -quit -viewonly -noresetroot -quick24 -rmode 5" .
+  "xv         -root -quit -viewonly +noresetroot -quick24 -rmode 5" .
   "           -rfg black -rbg black",
   "xli        -quiet -onroot -center -border black",
   "xloadimage -quiet -onroot -center -border black",
@@ -137,6 +141,8 @@ my %warningless_sites = (
   "yimg.com"                => 1,  # This is where dailynews.yahoo.com stores
   "eimg.com"                => 1,  # its images, so pick_from_yahoo_news_text()
                                    # hits this every time.
+
+  "driftnet"                => 1,  # builtin...
 );
 
 
@@ -178,6 +184,12 @@ my $min_gif_area = (120 * 120);
 my $no_output_p = 0;
 my $urls_only_p = 0;
 
+my @pids_to_kill = ();  # forked pids we should kill when we exit, if any.
+
+my $driftnet_magic = 'driftnet';
+my $driftnet_dir = undef;
+my $default_driftnet_cmd = "driftnet -a -m 100";
+
 my $wordlist;
 
 my %rejected_urls;
@@ -348,6 +360,10 @@ sub get_document {
   my ( $url, $referer, $timeout ) = @_;
   my $start = time;
 
+  if (defined($referer) && $referer eq $driftnet_magic) {
+    return get_driftnet_file ($url);
+  }
+
   my $orig_url = $url;
   my $loop_count = 0;
   my $max_loop_count = 4;
@@ -1009,9 +1025,8 @@ sub pick_from_alta_vista_images {
   foreach my $u (@subpages) {
 
     # altavista is encoding their URLs now.
-    next unless ($u =~
-    m@^/r\?ck_sm=[a-zA-Z0-9]+\&ref=[a-zA-Z0-9]+(\&uid=[a-zA-Z0-9]+)?\&r=(.*)@);
-    $u = url_unquote($2);
+    next unless ($u =~ m@^/r.*\&r=([^&]+).*@);
+    $u = url_unquote($1);
 
     next unless ($u =~ m@^http://@i);    #  skip non-HTTP or relative URLs
     next if ($u =~ m@[/.]altavista\.com\b@i);     # skip altavista builtins
@@ -1033,7 +1048,7 @@ sub pick_from_alta_vista_images {
 \f
 ############################################################################
 #
-# Pick images by feeding random words into Google Image Search
+# Pick images by feeding random words into Google Image Search.
 # By Charles Gales <gales@us.ibm.com>
 #
 ############################################################################
@@ -1080,6 +1095,65 @@ sub pick_from_google_images {
 }
 
 
+\f
+############################################################################
+#
+# Pick images by feeding random *numbers* into Google Image Search.
+# By jwz, suggested by from Ian O'Donnell.
+#
+############################################################################
+
+
+# googlenums
+sub pick_from_google_image_numbers {
+  my ( $timeout ) = @_;
+
+  my $max = 9999;
+  my $number = int(rand($max));
+
+  $number = sprintf("%04d", $number)
+    if (rand() < 0.3);
+
+  my $words = "$number";
+  my $page = (int(rand(40)) + 1);
+  my $num = 20;     # 20 images per page
+  my $search_url = $google_images_url . $words;
+
+  if ($page > 1) {
+    $search_url .= "&start=" . $page*$num;     # page number
+    $search_url .= "&num="   . $num;            #images per page
+  }
+
+  my ($search_hit_count, @subpages) =
+    pick_from_search_engine ($timeout, $search_url, $words);
+
+  my @candidates = ();
+  my %referers;
+  foreach my $u (@subpages) {
+    next unless ($u =~ m@imgres\?imgurl@i);    #  All pics start with this
+    next if ($u =~ m@[/.]google\.com\b@i);     # skip google builtins
+
+    if ($u =~ m@^/imgres\?imgurl=(.*?)\&imgrefurl=(.*?)\&@) {
+      my $ref = $2;
+      my $img = "http://$1";
+
+      LOG ($verbose_filter, "  candidate: $ref");
+      push @candidates, $img;
+      $referers{$img} = $ref;
+    }
+  }
+
+  @candidates = depoison (@candidates);
+  return () if ($#candidates < 0);
+  my $i = int(rand($#candidates+1));
+  my $img = $candidates[$i];
+  my $ref = $referers{$img};
+
+  LOG ($verbose_load, "picked image " . ($i+1) . ": $img (on $ref)");
+  return ($ref, $img);
+}
+
+
 \f
 ############################################################################
 #
@@ -1119,8 +1193,7 @@ sub pick_from_alta_vista_text {
     # onMouseOver to make it look like they're not!  Well, it makes it
     # easier for us to identify search results...
     #
-    next unless ($u =~
-      m@^/r\?ck_sm=[a-zA-Z0-9]+\&ref=[a-zA-Z0-9]+\&uid=[a-zA-Z0-9]+\&r=(.*)@);
+    next unless ($u =~ m@^/r.*\&r=([^&]+).*@);
     $u = url_unquote($1);
 
     LOG ($verbose_filter, "  candidate: $u");
@@ -1204,7 +1277,13 @@ sub pick_from_lycos_text {
     # Lycos plays exact the same redirection game as hotbot.
     # Note that "id=0" is used for internal advertising links,
     # and 1+ are used for  search results.
-    next unless ($u =~ m@^http://click.hotbot.com/director.asp\?id=[1-9]\d*&target=([^&]+)@);
+    next unless ($u =~ m@^http://click.hotbot.com/director.asp
+                         .*
+                         [?&]id=[1-9]\d*
+                         .*
+                         \&target=([^&]+)
+                         .*
+                        @x);
     $u = url_decode($1);
 
     LOG ($verbose_filter, "  candidate: $u");
@@ -1252,6 +1331,113 @@ sub pick_from_yahoo_news_text {
 
 
 
+\f
+############################################################################
+#
+# Pick images by waiting for driftnet to populate a temp dir with files.
+# Requires driftnet version 0.1.5 or later.
+# (Driftnet is a program by Chris Lightfoot that sniffs your local ethernet
+# for images being downloaded by others.)
+# Driftnet/webcollage integration by jwz.
+#
+############################################################################
+
+# driftnet
+sub pick_from_driftnet {
+  my ( $timeout ) = @_;
+
+  my $id = $driftnet_magic;
+  my $dir = $driftnet_dir;
+  my $start = time;
+  my $now;
+
+  error ("\$driftnet_dir unset?") unless ($dir);
+  $dir =~ s@/+$@@;
+
+  error ("$dir unreadable") unless (-d "$dir/.");
+
+  $timeout = $http_timeout unless ($timeout);
+  $last_search = $id;
+
+  while ($now = time, $now < $start + $timeout) {
+    local *DIR;
+    opendir (DIR, $dir) || error ("$dir: $!");
+    while (my $file = readdir(DIR)) {
+      next if ($file =~ m/^\./);
+      $file = "$dir/$file";
+      closedir DIR;
+      LOG ($verbose_load, "picked file $file ($id)");
+      return ($id, $file);
+    }
+    closedir DIR;
+  }
+  LOG (($verbose_net || $verbose_load), "timed out for $id");
+  return ();
+}
+
+
+sub get_driftnet_file {
+  my ($file) = @_;
+
+  error ("\$driftnet_dir unset?") unless ($driftnet_dir);
+
+  my $id = $driftnet_magic;
+  my $re = qr/$driftnet_dir/;
+  error ("$id: $file not in $driftnet_dir?")
+    unless ($file =~ m@^$re@o);
+
+  local *IN;
+  open (IN, $file) || error ("$id: $file: $!");
+  my $body = '';
+  while (<IN>) { $body .= $_; }
+  close IN;
+  unlink ($file);
+  return ($id, $body);
+}
+
+
+sub spawn_driftnet {
+  my ($cmd) = @_;
+
+  # make a directory to use.
+  while (1) {
+    my $tmp = $ENV{TEMPDIR} || "/tmp";
+    $driftnet_dir = sprintf ("$tmp/driftcollage-%08x", rand(0xffffffff));
+    LOG ($verbose_exec, "mkdir $driftnet_dir");
+    last if mkdir ($driftnet_dir, 0700);
+  }
+
+  if (! ($cmd =~ m/\s/)) {
+    # if the command didn't have any arguments in it, then it must be just
+    # a pointer to the executable.  Append the default args to it.
+    my $dargs = $default_driftnet_cmd;
+    $dargs =~ s/^[^\s]+//;
+    $cmd .= $dargs;
+  }
+
+  # point the driftnet command at our newly-minted private directory.
+  #
+  $cmd .= " -d $driftnet_dir";
+  $cmd .= ">/dev/null" unless ($verbose_exec);
+
+  my $pid = fork();
+  if ($pid < 0) { error ("fork: $!\n"); }
+  if ($pid) {
+    # parent fork
+    push @pids_to_kill, $pid;
+    LOG ($verbose_exec, "forked for \"$cmd\"");
+  } else {
+    # child fork
+    nontrapping_system ($cmd) || error ("exec: $!");
+  }
+
+  # wait a bit, then make sure the process actually started up.
+  #
+  sleep (1);
+  error ("pid $pid failed to start \"$cmd\"")
+    unless (1 == kill (0, $pid));
+}
+
 \f
 ############################################################################
 #
@@ -1263,7 +1449,6 @@ sub pick_from_yahoo_news_text {
 # Picks a random image on a random page, and returns two URLs:
 # the page containing the image, and the image.
 # Returns () if nothing found this time.
-# Uses the url-randomizer 1 time in 5, else the image randomizer.
 #
 
 sub pick_image {
@@ -1488,6 +1673,11 @@ sub save_recent_url {
   $_ = $url;
   my ($site) = m@^http://([^ \t\n\r/:]+)@;
 
+  if ($base eq $driftnet_magic) {
+    $site = $driftnet_magic;
+    @recent_images = ();
+  }
+
   my $done = 0;
   foreach (@recent_images) {
     if ($_ eq $url) {
@@ -1571,10 +1761,12 @@ sub jpeg_size {
   while (ord($ch) != 0xDA && $i < $L) {
     # Find next marker, beginning with 0xFF.
     while (ord($ch) != 0xFF) {
+      return () if (length($body) <= $i);
       $ch = substr($body, $i, 1); $i++;
     }
     # markers can be padded with any number of 0xFF.
     while (ord($ch) == 0xFF) {
+      return () if (length($body) <= $i);
       $ch = substr($body, $i, 1); $i++;
     }
 
@@ -1586,6 +1778,7 @@ sub jpeg_size {
         ($marker != 0xC4) &&
         ($marker != 0xCC)) {  # it's a SOFn marker
       $i += 3;
+      return () if (length($body) <= $i);
       my $s = substr($body, $i, 4); $i += 4;
       my ($a,$b,$c,$d) = unpack("C"x4, $s);
       return (($c<<8|$d), ($a<<8|$b));
@@ -1593,6 +1786,7 @@ sub jpeg_size {
     } else {
       # We must skip variables, since FFs in variable names aren't
       # valid JPEG markers.
+      return () if (length($body) <= $i);
       my $s = substr($body, $i, 2); $i += 2;
       my ($c1, $c2) = unpack ("C"x2, $s);
       my $length = ($c1 << 8) | $c2;
@@ -1636,6 +1830,24 @@ sub bellrand {
 }
 
 
+sub signal_cleanup {
+  my ($sig) = @_;
+  print STDERR blurb() . (defined($sig)
+                          ? "caught signal $sig."
+                          : "exiting.")
+                       . "\n"
+    if ($verbose_exec);
+
+  x_cleanup();
+
+  if (@pids_to_kill) {
+    print STDERR blurb() . "killing: " . join(' ', @pids_to_kill) . "\n";
+    kill ('TERM', @pids_to_kill);
+  }
+
+  exit 1;
+}
+
 ##############################################################################
 #
 # Generating a list of urls only
@@ -1670,14 +1882,10 @@ my $background = undef;
 my $img_width;            # size of the image being generated.
 my $img_height;
 
-my $delay = 0;
-
+my $delay = 2;
 
 sub x_cleanup {
-  my ($sig) = @_;
-  print STDERR blurb() . "caught signal $sig.\n" if ($verbose_exec);
   unlink $image_ppm, $image_tmp1, $image_tmp2;
-  exit 1;
 }
 
 
@@ -1856,17 +2064,6 @@ sub x_or_pbm_output {
   #
   $ppm_to_root_window_cmd = pick_root_displayer();
 
-
-  $SIG{HUP}  = \&x_cleanup;
-  $SIG{INT}  = \&x_cleanup;
-  $SIG{QUIT} = \&x_cleanup;
-  $SIG{ABRT} = \&x_cleanup;
-  $SIG{KILL} = \&x_cleanup;
-  $SIG{TERM} = \&x_cleanup;
-
-  # Need this so that if giftopnm dies, we don't die.
-  $SIG{PIPE} = 'IGNORE';
-
   if (!$img_width || !$img_height) {
     $_ = "xdpyinfo";
     which ($_) || error "$_ not found on \$PATH.";
@@ -1978,7 +2175,13 @@ sub paste_image {
 
   my ($iw, $ih);
 
-  if (defined ($webcollage_helper)) {
+  # If we are using the webcollage-helper, then we do not need to convert this
+  # image to a PPM.  But, if we're using a filter command, we still must, since
+  # that's what the filters expect (webcollage-helper can read PPMs, so that's
+  # fine.)
+  #
+  if (defined ($webcollage_helper) &&
+      !defined ($filter_cmd)) {
 
     ($iw, $ih) = image_size ($body);
     if (!$iw || !$ih) {
@@ -2210,8 +2413,20 @@ sub paste_image {
   # cumulative.
   #
   if ($post_filter_cmd) {
+
+    my $cmd;
+
     $target = $image_tmp1;
-    $rc = nontrapping_system "($post_filter_cmd) < $image_ppm > $target";
+    if (!defined ($webcollage_helper)) {
+      $cmd = "($post_filter_cmd) < $image_ppm > $target";
+    } else {
+      # Blah, my scripts need the JPEG data, but some other folks need
+      # the PPM data -- what to do?  Ignore the problem, that's what!
+#     $cmd = "djpeg < $image_ppm | ($post_filter_cmd) > $target";
+      $cmd = "($post_filter_cmd) < $image_ppm > $target";
+    }
+
+    $rc = nontrapping_system ($cmd);
     if ($rc != 0) {
       LOG ($verbose_pbm, "filter failed: \"$post_filter_cmd\"\n");
       return;
@@ -2257,12 +2472,29 @@ sub paste_image {
 }
 
 
+sub init_signals {
+
+  $SIG{HUP}  = \&signal_cleanup;
+  $SIG{INT}  = \&signal_cleanup;
+  $SIG{QUIT} = \&signal_cleanup;
+  $SIG{ABRT} = \&signal_cleanup;
+  $SIG{KILL} = \&signal_cleanup;
+  $SIG{TERM} = \&signal_cleanup;
+
+  # Need this so that if giftopnm dies, we don't die.
+  $SIG{PIPE} = 'IGNORE';
+}
+
+END { signal_cleanup(); }
+
+
 sub main {
   $| = 1;
   srand(time ^ $$);
 
   my $verbose = 0;
   my $dict;
+  my $driftnet_cmd = 0;
 
   $current_state = "init";
   $load_method = "none";
@@ -2314,6 +2546,13 @@ sub main {
       $http_proxy = shift @ARGV;
     } elsif ($_ eq "-dictionary" || $_ eq "-dict") {
       $dict = shift @ARGV;
+    } elsif ($_ eq "-driftnet" || $_ eq "--driftnet") {
+      @search_methods = ( 100, "driftnet", \&pick_from_driftnet );
+      if (! ($ARGV[0] =~ m/^-/)) {
+        $driftnet_cmd = shift @ARGV;
+      } else {
+        $driftnet_cmd = $default_driftnet_cmd;
+      }
     } elsif ($_ eq "-debug" || $_ eq "--debug") {
       my $which = shift @ARGV;
       my @rest = @search_methods;
@@ -2333,11 +2572,13 @@ sub main {
       LOG (1, "DEBUG: using only \"$which\"");
 
     } else {
-      print STDERR "$copyright\nusage: $progname [-root]" .
-                 " [-display dpy] [-root] [-verbose] [-timeout secs]\n" .
-                 "\t\t  [-delay secs] [-filter cmd] [-filter2 cmd]\n" .
-                 "\t\t  [-dictionary dictionary-file]\n" .
-                 "\t\t  [-http-proxy host[:port]]\n";
+      print STDERR "$copyright\nusage: $progname " .
+              "[-root] [-display dpy] [-verbose] [-debug which]\n" .
+        "\t\t  [-timeout secs] [-delay secs] [-filter cmd] [-filter2 cmd]\n" .
+        "\t\t  [-no-output] [-urls-only] [-background color] [-size WxH]\n" .
+        "\t\t  [-dictionary dictionary-file] [-http-proxy host[:port]]\n" .
+        "\t\t  [-driftnet [driftnet-program-and-args]]\n" .
+        "\n";
       exit 1;
     }
   }
@@ -2417,6 +2658,10 @@ sub main {
     pick_dictionary();
   }
 
+  init_signals();
+
+  spawn_driftnet ($driftnet_cmd) if ($driftnet_cmd);
+
   if ($urls_only_p) {
     url_only_output;
   } else {