#!/usr/local/bin/perl # ---------------------------------------------------------- # LOCAL CONFIGURATION # ---------------------------------------------------------- # what's the URL to this script? you need to change this. $this_script = "https://gislab.museum.state.il.us:/animate/animate.cgi"; # ---------------------------------------------------------- # DOCUMENTATION # ---------------------------------------------------------- $apologia = <<'END OF APOLOGIA'; animate.cgi v0.5.3 mengwong@pobox.com Mon Sep 25 22:22:47 EDT 1995 brought to you by pobox.com lifetime email addresses and urls, web consulting https://pobox.com/pobox/ $Id: animate.pl,v 1.2 1995/07/21 10:47:02 mengwong Exp mengwong $ ------------------------------------------------------------ INTRODUCTION netscape 1.1 supports animation, through the mechanism of server push, and the mime-type x-mixed-replace. it also supports client-pull. see https://home.netscape.com/home/demo/1.1b1/pushpull.html for the description, and https://home.netscape.com/home/demo/1.1b1/mozilla/doc.html for an actual example. SERVER PUSH This perl script makes serving animations very easy and very flexible. the example provided by netscape uses a C program, which is specific to that example. by contrast, this script is extensible and widely applicable. CLIENT PULL This script also supports guided-tour functionality; you can put together a file describing where you want to go and how long to wait between stops, and this script will take you on a hands-free tour of those sites. ------------------------------------------------------------ CONTENTS Server push: instructions Server push: extensions Server push: real-world examples and other scripts Client pull: instructions Troubleshooting If you still have trouble To Do ------------------------------------------------------------ SERVER PUSH: INSTRUCTIONS here's what to do. i'm assuming you already have your images -- a series of .gif or .jpg files, all the same dimensions. you've described the order of animation in a text file that lists the .gif or .jpg filenames, one per line. the images are called foo1.gif fooo2.gif foo3.gif. they're listed in the file called bar.txt. all files involved are, for now, in the same directory, though it will become obvious how to make things work when the files are spread across different directories. in your file, you say and this script takes care of everything else. you *did* remember to rename this script fron animate.pl to animate.cgi, didn't you? ------------------------------------------------------------ SERVER PUSH: EXTENSIONS there are two types of lines in the file: plain lines and control lines. plain lines contain either sleep commands or filenames. control lines make the script do, well, it what the control line tells it to. for example, suppose we have four images: a, b, c, d. SLEEP N the script sleeps N seconds. a b sleep 10 c d would theoretically display the first two images, pause ten seconds, then display the next two, and stop. reason i say "theoretically" is because your httpd server may buffer output, so results may not look quite as you'd expect. REPEAT N the script repeats everything from the last control line to here, N times, in forward order. a b repeat 2 c d repeat 2 would display a,b,a,b,c,d,c,d REVERSE REPEAT N repeats things just like before, but in reverse order. a b repeat 2 c d reverse repeat 2 would display a,b,a,b,c,d,d,c,d,c LOOP REPEAT N the images "bounce" off their surrounding control lines N times. a b repeat 2 c d loop repeat 2 would display a,b,a,b,c,d,d,c,c,d AD NAUSEUM the whole thing loops until stopped. ------------------------------------------------------------ SERVER PUSH: REAL-WORLD EXAMPLES AND OTHER SCRIPTS see also https://www.nhgs.tec.va.us/smehrotr/cgi-bin/smehrotr/nph-cylinder if your everyday speech is suffused with words such as "dude" and "like", go to https://bakmes.colorado.edu:80/~bicanic/ for, like, a cool and totally rad explanation of what goes on in an essentially identical script. pages that invoke this script include https://icg.stwing.upenn.edu/pushpull/pobox/animate.normal.html https://icg.stwing.upenn.edu/pushpull/bug.html ------------------------------------------------------------ CLIENT PULL: INSTRUCTIONS Put together a file that follows the format pause url pause url pause url suppose the file is called tour.txt, in the directory /home/www/html/tour.txt. The animate script is in /cgi-bin/animate.cgi. You'd call the script with the URL /cgi-bin/animate.cgi?file=/home/www/html/tour.txt&step=1 And the script will take care of everything else. In this case, /home/www/html/tour.txt is a full unix pathname to tour.txt. To see this in action, try at: https://icg.pobox.com/pushpull/guidedtour/ ------------------------------------------------------------ TO DO Server Push has marvelous looping stuff built into it. I want to implement the same for Client Pull. Get listed with Netscape. Convince this script that Server Push can be done with entire standalone documents as well as inline animations. ------------------------------------------------------------ TROUBLESHOOTING first thing to check CHECK YOUR PERMISSIONS! the httpd server runs with a different identity than yourself. you need to chmod a+rX everything, so it can read your files. your error_logs says malformed header from script you might not be calling perl correctly; edit the first line of this script to properly reflect the location of perl on your system, which can be found using 'which perl' at the unix prompt. script aborts with "check file permissions on XXX" use an absolute pathname to the file that contains the list of images. chmod a+r the file. ------------------------------------------------------------ IF YOU STILL HAVE TROUBLE email animate-support@icg.pobox.com with a complete description. include as much of this information as possible: * what's the server's operating system * what's the server's httpd server make and model * are you the httpd server admin or a user * are you sure your server permits cgi scripts * what's the first line of the animate script * when, at the unix prompt, you type which perl what does it say? (hint: the above two questions should have the same answer) * what's the full unix pathname of the animate script * what's the full unix pathname of the images you're showing * what's the full unix pathname of the file listing those images * what's the url you're using to call animate.cgi * a url of a sample page that exhibits the error * what happens when you run the script in unix with no arguments * an ls -l of the relevant directories and files * relevant messages from the error_log if i don't get back to you after a week, resend your message. ------------------------------------------------------------ END OF APOLOGIA # ---------------------------------------------------------- # no user-serviceable parts below this line # ---------------------------------------------------------- # called as refresh, not animate &clientpull if ($ENV{'QUERY_STRING'} =~ /file=/i); %suffixes = ( "gif", "image/gif", "jpeg", "image/jpeg", "jpg", "image/jpeg", "jpe", "image/jpeg", "tiff", "image/tiff", "tif", "image/tiff", "pnm", "image/x-portable-anymap", "pbm", "image/x-portable-bitmap", "pgm", "image/x-portable-graymap", "ppm", "image/x-portable-pixmap", "rgb", "image/x-rgb", "xbm", "image/x-xbitmap", "xpm", "image/x-xpixmap", "xwd", "image/x-xwindowdump", "html", "text/html", "htm", "text/html", "txt", "text/plain", "tsv", "text/tab-separated-values", ); if ($#ARGV < 0) { die "$0: need to know which file describes animation sequence.\n"; } $boundary = "brought to you by pobox.com"; # pobox.com provides lifetime virtual email addresses and urls. # for more info, goto https://pobox.com/pobox/ or email info@pobox.com if ($ARGV[0] =~ /^(.*\/)[^\/]*/) { $dirname = $1; } else { $dirname = ""; } open (CONTENT, $ARGV[0]) || die "unable to open $ARGV[0]: $!\n"; @content = (); chop @content; close CONTENT; @content = grep(! /^\s*(\#.*)?$/,@content); # remove blank lines and comments if ($content[-1] eq "ad nauseum") { $adnauseum = 1; pop @content; } $/ = 0; $| = 1; print "Content-Type: multipart/x-mixed-replace;boundary=$boundary\n"; print "\n--$boundary\n"; START: # warn "starting ...\n"; $controlmark = 0; for (0 .. $#content) { # iterate through the original file # -------------------- # NORMAL REPEAT # -------------------- if ($content[$_] =~ /^repeat (\d+)/i) { $repeat = $1; while ($repeat > 0) { foreach $loopposition ($controlmark..($_-1)) { push(@toshow,$loopposition); } $repeat--; } $controlmark = $_+1; # -------------------- # REVERSE REPEAT # -------------------- } elsif ($content[$_] =~ /^reverse repeat (\d+)/i) { $repeat = $1; while ($repeat > 0) { foreach $loopposition (reverse ($controlmark..($_-1))) { push(@toshow,$loopposition); } $repeat--; } $controlmark = $_+1; # -------------------- # LOOP REPEAT # -------------------- } elsif ($content[$_] =~ /^loop repeat (\d+)/i) { $repeat = $1; while ($repeat > 0) { foreach $loopposition (reverse ($controlmark..($_-1))) { push(@toshow,$loopposition); } $repeat--; last if ($repeat <= 0); foreach $loopposition ($controlmark..($_-1)) { push(@toshow,$loopposition); } $repeat--; } $controlmark = $_+1; # -------------------- # FILENAME or SLEEP # -------------------- } else { push(@toshow,$_); } } # uncomment for debugging purposes # warn "\@toshow is now @toshow.\n"; for (@toshow) { &dump($_); } goto START if ($adnauseum); # when will it die? hm. httpd 1.3R doesn't seem to close # the file descriptor quite right. the problem seems to be # fixed with 1.4. ############# script terminates. sub dump { # takes the index of a @content line to show local ($loopposition) = $_[0]; if ($content[$loopposition] =~ /^sleep (\d*)/i) { #----------------SLEEP sleep $1; return; } ($extension = $content[$loopposition]) =~ s/\.\w+$/$1/i; $contenttype = ($suffixes{$extension} || "text/html"); print "Content-Type: $contenttype\n"; print "\n"; open (CURRENT, $dirname.$content[$loopposition]) || warn "$0: unable to open $dirname$content[$_]: $!\n"; select CURRENT; $| = 1; select STDOUT; print (); close CURRENT; if ($loopposition == $#toshow) { print "\n--$boundary--\n"; } else { print "\n--$boundary\n"; } } sub clientpull { $localtime = localtime; # this will break unless you have perl 5 @args = split(/&/,$ENV{'QUERY_STRING'}); for (@args) { ($key, $val) = split(/=/,$_,2); $val =~ s/\+/ /g; $val =~ s/\%(..)/pack("c",$1)/ge; $in{$key} = $val; } # we expect %in to contain the following values: # file = relative pathname from this script's CWD to a descriptor file # step = numerical index to where we are now, to be incremented &abort ("not called with enough info.\n") unless ($in{'file'} && $in{'step'}); &abort ("check file permissions on $in{'file'}.\n") unless (open(FILE,$in{'file'})); while (chop ($_=)) { push(@file,$_."\n"); next if (/^\s*(\#.*)?$/); s/^\s*//; ($pause,$url) = split(' ',$_,2); $steps[++$step] = "$pause $url"; } close (FILE); ($pause && $url) || &abort("couldn't find needed info in $in{'file'}\n"); $step = $in{'step'}; ($pause, $url) = split(' ', $steps[$step]); $step++; if ($steps[$step]) { # pass the buck ... $refreshline = "Refresh: $pause;URL=$this_script?file=$in{'file'}&step=$step\n"; } else { # the buck has to stop somewhere, hm? $refreshline = ""; } print <<"EOREDIRECT"; Location: $url ${refreshline}Content-type: text/html Document moved

Document moved

This document has moved to $url. This script will call $this_script again in $pause seconds. EOREDIRECT exit; } sub abort { $" = "\n"; print <<"EOABORT"; Content-type: text/html Doh. Stuff ain\'t working like it should. Consider this an abortion. The complaint, specifically, is:
$_[0]

Diagnostics:

\$url: $url
\$this_script: $this_script
\$step: $step
\$in{'file'}: $in{'file'}
\$in{'step'}: $in{'step'}
contents of file:
@file

EOABORT exit; }