PageRenderTime 524ms CodeModel.GetById 81ms app.highlight 145ms RepoModel.GetById 133ms app.codeStats 2ms

/tags/v2-98/mh/bin/dailystrips

#
Perl | 1390 lines | 1082 code | 217 blank | 91 comment | 205 complexity | 2a05508a6fcb44e1cd7dc090cb55932f MD5 | raw file
   1#!/usr/bin/perl
   2
   3#
   4# Program Summary:
   5#
   6# Name:             dailystrips
   7# Description:      creates an HTML page containing a number of online comics, with an easily exensible framework
   8# Author:           Andrew Medico <amedico@amedico.dhs.org>
   9# Created:          23 Nov 2000, 23:33 EST
  10# Last Modified:    24 Aug 2003, 16:55 
  11# Current Revision: 1.0.28
  12#
  13
  14
  15# Set up
  16use strict;
  17no strict qw(refs);
  18
  19use LWP::UserAgent;
  20use HTTP::Request;
  21use POSIX qw(strftime);
  22use Getopt::Long;
  23use File::Copy;
  24
  25
  26# Variables
  27my (%options, $version, $time_today, @localtime_today, @localtime_yesterday, @localtime_tomorrow, $long_date, $short_date,
  28    $short_date_yesterday, $short_date_tomorrow, @get, @strips, %defs, $known_strips, %groups, $known_groups, %classes, $val,
  29    $link_tomorrow, $no_dateparse, @base_dirparts);
  30
  31$version = "1.0.28";
  32
  33$time_today = time;
  34
  35
  36# Get options
  37GetOptions(\%options, 'quiet|q','verbose','output=s','lite','local|l','noindex',
  38	'archive|a','dailydir|d','stripdir','save|s','nostale','date=s',
  39	'new|n','defs=s','nopersonal','basedir=s','list','proxy=s',
  40	'proxyauth=s','noenvproxy','nospaces','useragent=s','version|v','help|h',
  41	'avantgo', 'random','nosystem','stripnav','nosymlinks','titles=s',
  42	'retries=s','clean=s','updates=s','noupdates') or exit 1;
  43
  44# Process options:
  45#  Note: Blocks have been ordered so that we only do as much as absolutely
  46#  necessary if an error is encountered (i.e. do not load defs if --version
  47#  specified)
  48
  49# Help and version override anything else
  50if ($options{'help'}) {
  51	print
  52"Usage: $0 [OPTION] STRIPS
  53STRIPS can be a mix of strip names and group names
  54(group names must be preceeded by an '\@' symbol)
  55'all' may be used to retrieve all known strips,
  56or use option --list to list available strips and groups
  57
  58Options:
  59  -q  --quiet                Turn off progress messages		
  60      --verbose              Turn on extra progress information, overrides -q
  61      --list                 List available strips
  62      --random               Download a random strip
  63      --defs FILE            Use alternate strips definition file
  64      --nopersonal           Ignore ~/.dailystrips.defs
  65      --nosystem             Ignore system-wide definitions
  66      --updates              Read updated defs from FILE instead of
  67                             ~/.dailystrips-updates.def
  68      --noupdates            Ignore updated defs file 
  69      --output FILE          Output HTML to FILE instead of STDOUT
  70                             (does not apply to local mode)
  71      --lite                 Output a reduced HTML page
  72      --stripnav             Add links for navigation within the page
  73      --titles STRING        Customize HTML output
  74  -l  --local                Output HTML to file and save strips locally
  75      --noindex              Disable symlinking current page to index.html
  76                             (local mode only)
  77  -a  --archive              Generate archive.html as a list of all days,
  78                             (local mode only)
  79  -d  --dailydir             Create a separate directory for each day's images
  80                             (local mode only)
  81      --stripdir             Create a separate directory for each strip's
  82                             images (local mode only)
  83  -s  --save                 If it appears that a particular strip has been
  84                             downloaded, does not attempt to re-download it
  85                             (local mode only)
  86      --nostale              If a new strip is not available, displays an error
  87                             in the HTML output instead of showing the old image
  88      --nosymlinks           Do not use symlinks for day-to-day duplicates
  89      --date DATE            Use value DATE instead of local time
  90                             (DATE is parsed by Date::Parse function)
  91      --avantgo              Format images for viewing with Avantgo on PDAs
  92                             (local mode only)
  93      --basedir DIR          Work in specified directory instead of current
  94                             directory (program will look here for previous HTML
  95                             file and save new files here, etc.)
  96      --proxy host:port      Use specified HTTP proxy server (overrides
  97                             environment proxy, if set)
  98      --proxyauth user:pass  Set username and password for proxy server
  99      --noenvproxy           Ignore the http_proxy environment variable, if set
 100      --nospaces             Remove spaces from image filenames (local mode
 101                             only)
 102      --useragent STRING     Set User-Agent: header to STRING (default is none)
 103      --retries NUM          When downloading items, retry NUM times instead of
 104                             default 3 times
 105      --clean NUM            Keep only the latest NUM days of files; remove all
 106                             older files
 107  -v  --version              Print version number
 108";
 109
 110
 111	if ($^O =~ /Win32/ ) {
 112		print
 113"Additional Win32 Notes:
 114
 115Windows lacks a number of features and programs found on *NIX, so a number of
 116changes must be made to the program's operation:
 117
 1181. --date and --avantgo are not available
 1192. Personal and update definition files may or may not work
 1203. System-wide definition files are not supported
 121";
 122	} # ' please emacs perlmode
 123
 124print "\nBugs and comments to dailystrips\@amedico.dhs.org\n";
 125
 126	exit;
 127}
 128
 129if ($options{'version'}) {
 130		print "dailystrips version $version\n";
 131		exit;
 132}
 133
 134
 135if ($options{'date'}) {
 136	eval "require Date::Parse";
 137	if ($@ ne "") {
 138		die "Error: cannot use --date - Date::Parse not installed\n";
 139	} else {
 140		import Date::Parse;
 141	}
 142
 143	unless ($time_today = str2time($options{'date'})) {
 144		die "Error: invalid date specified\n";
 145	}
 146}
 147
 148
 149# setup time variables (needed during defs parsing)
 150@localtime_today = localtime $time_today;
 151#long_date = strftime("\%A, \%B \%e, \%Y", @localtime_today);
 152$long_date = strftime("\%A, \%B \%d, \%Y", @localtime_today); 
 153
 154$short_date = strftime("\%Y.\%m.\%d", @localtime_today);
 155
 156@localtime_yesterday = localtime($time_today - ( 24 * 60 * 60 ));
 157$short_date_yesterday = strftime("\%Y.\%m.\%d", @localtime_yesterday);
 158@localtime_tomorrow = localtime ($time_today + 24 * 60 * 60);
 159$short_date_tomorrow = strftime("\%Y.\%m.\%d", @localtime_tomorrow);
 160
 161
 162# Get strip definitions now - info used below
 163unless ($options{'defs'}) {
 164	if ($^O =~ /Win32/ ) {
 165		$options{'defs'} = 'strips.def';
 166	} else {
 167		$options{'defs'} = '/usr/share/dailystrips/strips.def';
 168	}
 169}
 170
 171&get_defs($options{'defs'});
 172
 173
 174# Load updated defs file
 175unless (defined $options{'updates'})
 176{
 177        $options{'updates'} = &get_homedir() . "/.dailystrips-updates.def";
 178}
 179
 180
 181unless($options{'noupdates'})
 182{
 183	if (-r $options{'updates'}) {
 184		&get_defs($options{'updates'});
 185	}
 186}
 187
 188# Get system configurable strip definitions now
 189unless ($options{'nosystem'}) {
 190	unless (($^O =~ /Win32/) or (! -r '/etc/dailystrips.defs')) {
 191		&get_defs('/etc/dailystrips.defs');
 192	}
 193}
 194
 195unless ($options{'nopersonal'}){
 196	my $personal_defs = &get_homedir()  . "/.dailystrips.defs";
 197	if (-r $personal_defs) {
 198		&get_defs($personal_defs);
 199	}
 200}
 201
 202$known_strips = join('|', sort keys %defs);
 203$known_groups = join('|', sort keys %groups);
 204
 205if ($options{'random'}) {
 206	my @known_strips_array = keys %defs;
 207
 208	push(@get, $known_strips_array[(rand $#known_strips_array)]);
 209
 210	undef @known_strips_array;
 211} else {
 212	# Only strips/groups to download remain in @ARGV
 213	# Unconfigured options were already trapped by Getopts with an 'unknown option'
 214	# error
 215	for (@ARGV) {
 216		if (/^($known_strips|all)$/io) {
 217			if ($_ eq "all") {
 218				push (@get, split(/\|/, $known_strips));
 219			} else {
 220				push(@get, $_);
 221			}
 222		} elsif (/^@/) {
 223			if (/^@($known_groups)$/io) {
 224				push(@get, split(/;/, $groups{$1}{'strips'}));
 225			} else {
 226				die "Error: unknown group: $_\n";
 227			}
 228		} else {
 229			die "Error: unknown strip: $_\n";
 230		}
 231	}
 232}
 233
 234if ($options{'list'}) {
 235format =
 236@<<<<<<<<<<<<<<<<<<<<<<<< 	@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 237$_, $val
 238.
 239	print "Available strips:\n";
 240	for (split(/\|/, $known_strips)) {
 241		$val = $defs{$_}{'name'};
 242		write;
 243	}
 244	
 245	print "\nAvailable groups:\n";
 246	for (split(/\|/, $known_groups)) {
 247		$val = $groups{$_}{'desc'};
 248		write;
 249	}
 250	exit;
 251}
 252
 253if ($options{'dailydir'} and $options{'stripdir'}) {
 254		die "Error: --dailydir and --stripdir cannot be used together\n";
 255}
 256
 257#Set proxy
 258if ($options{'proxy'}) {
 259		$options{'proxy'} =~ /^(http:\/\/)?(.*?):(.+?)\/?$/i;
 260		unless ($2 and $3) {
 261			die "Error: incorrectly formatted proxy server ('http://server:port' expected)\n";
 262		}
 263				
 264		$options{'proxy'} = "http://$2:$3";
 265}
 266
 267if (!$options{'noenvproxy'} and !$options{'proxy'} and $ENV{'http_proxy'} ) {
 268	$ENV{'http_proxy'} =~ /(http:\/\/)?(.*?):(.+?)\/?$/i;
 269	unless ($2 and $3) {
 270		die "Error: incorrectly formatted proxy server environment variable\n('http://server:port' expected)\n";
 271	}
 272			
 273	$options{'proxy'} = "http://$2:$3";
 274}
 275
 276if ($options{'proxyauth'}) {
 277	unless ($options{'proxyauth'} =~ /^.+?:.+?$/) {
 278			die "Error: incorrectly formatted proxy credentials ('user:pass' expected)\n";
 279	}
 280}
 281
 282
 283# Handle/validate other options
 284if ($options{'clean'} =~ m/\D/) {
 285	die "Error: 'clean' value must be numeric\n";
 286}
 287
 288if ($options{'retries'} =~ m/\D/) {
 289	die "Error: 'retries' value must be numeric\n";
 290}
 291
 292unless ($options{'retries'}) {
 293	$options{'retries'} = 3;
 294}
 295
 296
 297if ($options{'basedir'}) {
 298	unless (chdir $options{'basedir'}) {
 299		die "Error: could not change directory to $options{'basedir'}\n";
 300	}
 301}
 302
 303if ($options{'titles'}) {
 304	$options{'titles'} .= " ";
 305}
 306
 307unless (@get) {
 308	die "Error: no strip specified (--list to list available strips)\n";
 309}
 310
 311
 312# verbose overrides quiet
 313if ($options{'verbose'} and $options{'quiet'}) {
 314	undef $options{'quiet'};
 315}
 316
 317
 318# Un-needed vars
 319undef $known_strips; undef $known_groups; undef $val;
 320
 321
 322# Go
 323unless ($options{'quiet'}) {
 324	warn "dailystrips $version starting:\n";
 325}
 326
 327
 328# Report proxy settings
 329if ($options{'proxy'}) {
 330	if ($options{'verbose'}) {
 331		warn "Using proxy server $options{'proxy'}\n";
 332	}
 333	
 334	if ($options{'verbose'} and $options{'proxy_auth'}) {
 335		warn "Using proxy server authentication\n";
 336	}
 337}
 338
 339
 340if ($options{'local'}) {
 341	unless ($options{'quiet'}) {
 342		warn "Operating in local mode\n";
 343	}
 344	
 345	if ($options{'dailydir'}) {
 346		unless ($options{'quiet'}) {
 347			warn "Operating in daily directory mode\n";
 348		}
 349		
 350		unless (-d $short_date) {
 351			# any issues with masks and Win32?
 352			unless(mkdir ($short_date, 0755)) {
 353				die "Error: could not create today's directory ($short_date/)\n";
 354			}
 355		}
 356	}
 357	
 358	unless(open(STDOUT, ">dailystrips-$short_date.html")) {
 359		die "Error: could not open HTML file (dailystrips-$short_date.html) for writing\n";
 360	}
 361
 362	unless ($options{'date'}) {
 363		unless ($options{'noindex'}) {
 364			unless ($^O =~ /Win32/) {
 365				unlink("index.html");
 366				system("ln -s dailystrips-$short_date.html index.html");
 367			}
 368		}
 369	}
 370
 371	if ($options{'archive'}) {
 372	
 373		unless (-e "archive.html") {
 374			# Doesn't exist.. create
 375			open(ARCHIVE, ">archive.html") or die "Error: could not create archive.html\n";
 376			print ARCHIVE
 377"<html>
 378
 379<head>
 380	<title>$options{'titles'}dailystrips archive</title>
 381</head>
 382
 383<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#0000ff\" vlink=\"#ff00ff\" alink=\"#ff0000\">
 384
 385<p align=\"center\">\n
 386
 387<font face=\"helvetica,arial\" size=\"14pt\">$options{'titles'}dailystrips archive</font>
 388
 389</p>
 390
 391<p>
 392<font face=\"helvetica,arial\">
 393<!--insert below-->
 394</font>
 395</p>
 396
 397</body>
 398
 399</html>";
 400			close(ARCHIVE);
 401		}
 402		
 403		open(ARCHIVE, "<archive.html") or die "Error: could not open archive.html for reading\n";
 404		my @archive = <ARCHIVE>;
 405		close(ARCHIVE);
 406
 407		unless (grep(/<a href="dailystrips-$short_date.html">/, @archive)) {
 408			for (@archive) {
 409				if (s/(<!--insert below-->)/$1\n<a href="dailystrips-$short_date.html">$long_date<\/a><br>/) {
 410					unless(open(ARCHIVE, ">archive.html")) {
 411						die "Error: could not open archive.html for writing\n";
 412					}
 413					
 414					print ARCHIVE @archive;
 415					close(ARCHIVE);
 416					last;
 417				}
 418			}
 419		}
 420	}
 421	
 422	# Update previous day's file with a "Next Day" link to today's file
 423	if (open(PREVIOUS, "<dailystrips-$short_date_yesterday.html")) {
 424		my @previous_page = <PREVIOUS>;
 425		close(PREVIOUS);
 426	
 427		# Don't bother if no tag exists in the file (because it has already been updated)
 428		if (grep(/<!--nextday-->/, @previous_page)) {
 429			my $match_count;
 430
 431			for (@previous_page) {
 432				if (s/<!--nextday-->/ | <a href="dailystrips-$short_date.html">Next day<\/a>/) {
 433					$match_count++;
 434					last if ($match_count == 2);
 435				}
 436			}
 437		
 438			if (open(PREVIOUS, ">dailystrips-$short_date_yesterday.html")) {
 439				print PREVIOUS @previous_page;
 440				close(PREVIOUS);
 441			} else {
 442				 warn "Warning: could not open dailystrips-$short_date_yesterday.html for writing\n";
 443			}
 444		} else {
 445			warn "Warning: did not find any tag in previous day's file to make today's link\n";
 446		}
 447	} else {
 448		warn "Warning: could not open dailystrips-$short_date_yesterday.html for reading\n";
 449	}
 450
 451
 452} elsif ($options{'output'}) {
 453	unless ($options{'quiet'}) {
 454		warn "Writing to file $options{'output'}\n";
 455	}
 456	
 457	unless (open(STDOUT, ">$options{'output'}")) {
 458		die "Error: Could not open output file ($options{'output'}) for writing\n";
 459	}
 460}
 461
 462
 463# Download image URLs
 464unless ($options{'quiet'}) {
 465	if ($options{'verbose'}) {
 466		warn "\nRetrieving URLS:\n"
 467	} else {
 468		print STDERR "\nRetrieving URLS..."
 469	}
 470}
 471for (@get) {
 472	if ($options{'verbose'}) { warn "Retrieving URL for $_\n" }
 473	&get_strip($_);
 474}
 475unless ($options{'quiet'}) {
 476	if ($options{'verbose'}) {
 477		warn "Retrieving URLS: done\n"
 478	} else {
 479		warn "done\n"
 480	}
 481}
 482
 483if (-e "dailystrips-$short_date_tomorrow.html") {
 484	$link_tomorrow = " | <a href=\"dailystrips-$short_date_tomorrow.html\">Next day</a>"
 485} else {
 486	$link_tomorrow = "<!--nextday-->"
 487}
 488
 489
 490# Generate HTML page
 491if ($options{'lite'}) {
 492	print "<font face=\"helvetica\" size=\"+2\"><b><u>$options{'titles'}dailystrips for $long_date</u></b></font><br><br>\n";
 493} else {
 494	my $topanchor;
 495	if ($options{'stripnav'}) {
 496		$topanchor = "\n<a name=\"top\">\n";
 497	}
 498
 499	print
 500"<html>
 501
 502<head>
 503	<title>$options{'titles'}dailystrips for $long_date</title>
 504</head>
 505
 506<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#ff00ff\">
 507$topanchor
 508<center>
 509	<font face=\"helvetica\" size=\"+2\"><b><u>$options{'titles'}dailystrips for $long_date</u></b></font>
 510</center>
 511
 512<p><font face=\"helvetica\">
 513&lt; <a href=\"dailystrips-$short_date_yesterday.html\">Previous day</a>$link_tomorrow";
 514	
 515	if ($options{'archive'}) {
 516		print " | <a href=\"archive.html\">Archives</a>";
 517	}
 518	
 519	print
 520" &gt;
 521</font></p>
 522";
 523
 524	if ($options{'stripnav'}) {
 525		print "<font face=\"helvetica\">Strips:</font><br>\n";
 526		for (@strips) {
 527			my ($strip, $name) = (split(/;/, $_))[0,1];
 528			print "<a href=\"#$strip\">$name</A>&nbsp;&nbsp;";
 529		}
 530		print "\n<br><br>";
 531	}
 532
 533	print "\n\n<table border=\"0\">\n";
 534}
 535
 536
 537if ($options{'local'} and !$options{'quiet'}) {
 538	if ($options{'verbose'}) {
 539		warn "\nDownloading strip files:\n"
 540	} else {
 541		print STDERR "Downloading strip files...";
 542	}
 543}
 544
 545for (@strips) {
 546	my ($strip, $name, $homepage, $img_addr, $referer, $prefetch, $artist) = split(/;/, $_);
 547	my ($img_line, $local_name, $local_name_dir, $local_name_file, $local_name_ext, $image, $ext,
 548	   $local_name_yesterday, $local_name_yesterday_dir, $local_name_yesterday_file, $local_name_yesterday_ext);
 549	
 550	if ($options{'verbose'} and $options{'local'}) {
 551		warn "Downloading strip file for " . lc((split(/;/, $_))[0]) . "\n";
 552	}
 553	
 554	if ($img_addr =~ "^unavail") {
 555		if ($options{'verbose'}) {
 556			warn "Error: $strip: could not retrieve URL\n";
 557		}
 558
 559		$img_line = "[Error - unable to retrieve URL]";
 560	} else {
 561		if ($options{'local'}) {
 562			# local mode - download strips
 563			$img_addr =~ /http:\/\/(.*)\/(.*)\.(.*?)([?&].+)?$/;
 564			if (defined $3) { $ext = ".$3" }
 565
 566			# prepare file names
 567			if ($options{'stripdir'}) {
 568 				$local_name_yesterday = "$name/$short_date_yesterday$ext";
 569 				$local_name_yesterday_dir = "$name/";
 570 				$local_name_yesterday_file = $short_date_yesterday;
 571 				$local_name_yesterday_ext = $ext;
 572 				
 573 				$local_name = "$name/$short_date$ext";
 574 				$local_name_dir = "$name/";
 575 				$local_name_file = "$short_date";
 576 				$local_name_ext = "$ext";
 577 			} elsif ($options{'dailydir'}) {
 578				$local_name_yesterday = "$short_date_yesterday/$name-$short_date_yesterday$ext";
 579				$local_name_yesterday_dir = "$short_date_yesterday/";	
 580				$local_name_yesterday_file = "$name-$short_date_yesterday";
 581				$local_name_yesterday_ext = "$ext";
 582				
 583				$local_name = "$short_date/$name-$short_date$ext";
 584				$local_name_dir = "$short_date/";
 585				$local_name_file = "$name-$short_date";
 586				$local_name_ext = "$ext";
 587			} else {
 588				$local_name_yesterday = "$name-$short_date_yesterday$ext";				
 589				$local_name_yesterday_dir = "./";
 590				$local_name_yesterday_file = "$name-$short_date_yesterday";
 591				$local_name_yesterday_ext = "$ext";
 592				
 593				$local_name = "$name-$short_date$ext";
 594				$local_name_dir = "./";
 595				$local_name_file = "$name-$short_date";
 596				$local_name_ext = "$ext";
 597			}
 598			
 599			if ($options{'nospaces'}) {
 600				# impossible to tell for sure if previous day's file
 601				# used --nospaces or not, but this should work more
 602				# often
 603				$local_name_yesterday =~ s/\s+//g;
 604				$local_name_yesterday_dir =~ s/\s+//g;
 605				$local_name_yesterday_file =~ s/\s+//g;
 606				
 607				$local_name =~ s/\s+//g;
 608				$local_name_dir =~ s/\s+//g;
 609				$local_name_file =~ s/\s+//g;
 610 			}
 611			
 612			# do ops that depend on file name
 613			if ($options{'stripdir'}) {
 614 				unless (-d $local_name_dir) {
 615	 				# any issues with masks and Win32?
 616 					mkdir $local_name_dir, 0755;
 617 				}
 618 			}
 619									
 620			if ($options{'save'} and  -e $local_name) {
 621				# already have a suitable local file - skip downloading
 622				if ($options{'avantgo'}) {
 623					$img_line = &make_avantgo_table($local_name, $ext);
 624				} else {
 625					$img_addr = $local_name;
 626					$img_addr =~ s/ /\%20/go;
 627					if ($options{'stripnav'}) {
 628						$img_line = "<img src=\"$img_addr\" alt=\"$name\"><br><a href=\"#top\">Return to top</a>";
 629					} else {
 630						$img_line = "<img src=\"$img_addr\" alt=\"$name\">";
 631					}
 632				}
 633			} else {			
 634				# need to download
 635				if ($prefetch) {
 636					if (&http_get($prefetch, $referer) =~ m/^ERROR/) {
 637						warn "Error: $strip: could not download prefetch URL\n";
 638						$image = "ERROR";
 639					} else {
 640						$image = &http_get($img_addr, $referer);
 641					}
 642				} else {
 643					$image = &http_get($img_addr, $referer);
 644					#$image = &http_get($img_addr, "");
 645				}
 646				
 647				if ($image =~ /^ERROR/) {
 648					# couldn't get the image
 649					# FIXME: what to do if a file for the day has already been
 650					# downloaded, but downloading fails when script is run again
 651					# that day? maybe reuse existing file instead of throwing
 652					# error?
 653					if (-e $local_name) {
 654						# an image file for today already exists.. jump to outputting code
 655						#warn "DEBUG: couldn't download strip, but we already have it\n";
 656						goto HAVE_IMAGE;
 657					} else {
 658						if ($options{'verbose'}) {
 659							warn "Error: $strip: could not download strip\n";
 660						}
 661					}
 662				
 663					$img_line = "[Error - unable to download image]";
 664				} else {
 665					HAVE_IMAGE:
 666					# got the image
 667					if ($^O =~ /Win32/) {
 668						# can't do any diff checking on windows (easily, that is - it is doable)
 669						open(IMAGE, ">$local_name");
 670						binmode(IMAGE);
 671						print IMAGE $image;
 672						close(IMAGE);
 673					
 674						$img_addr = $local_name;
 675						$img_addr =~ s/ /\%20/go;
 676						if ($options{'stripnav'}) {
 677							$img_line = "<img src=\"$img_addr\" alt=\"$name\"><br><a href=\"#top\">Return to top</a>";
 678						} else {
 679							$img_line = "<img src=\"$img_addr\" alt=\"$name\">";
 680						}
 681					} else {
 682						# FIXME: only download to .tmp if earlier file exists
 683						open(IMAGE, ">$local_name.tmp");
 684						binmode(IMAGE);
 685						print IMAGE $image;
 686						close(IMAGE);
 687				
 688						if (-e $local_name and system("diff \"$local_name\" \"$local_name.tmp\" >/dev/null 2>&1") == 0) {
 689							# already downloaded the same strip earlier today
 690							unlink("$local_name.tmp");
 691						
 692							if ($options{'avantgo'}) {
 693								$img_line = &make_avantgo_table($local_name, $ext);
 694							} else {
 695								$img_addr = $local_name;
 696								$img_addr =~ s/ /\%20/go;
 697								if ($options{'stripnav'}) {
 698									$img_line = "<img src=\"$img_addr\" alt=\"$name\"><br><a href=\"#top\">Return to top</a>";
 699								} else {
 700									$img_line = "<img src=\"$img_addr\" alt=\"$name\">";
 701								}
 702							}
 703						} elsif (system("diff \"$local_name_yesterday\" \"$local_name.tmp\" >/dev/null 2>&1") == 0) {
 704							# same strip as yesterday
 705							if ($options{'nosymlinks'}) {
 706								system("mv","$local_name.tmp","$local_name");
 707							} else {
 708								unlink("$local_name.tmp");
 709								if ($options{'stripdir'} or $options{'dailydir'}) {
 710									system("ln -s \"../$local_name_yesterday\" \"$local_name\" >/dev/null 2>&1");
 711								} else {
 712									system("ln -s \"$local_name_yesterday\" \"$local_name\" >/dev/null 2>&1");
 713								}
 714
 715							}
 716							
 717							if ($options{'nostale'}) {
 718								$img_line = "[Error - new strip not available]";
 719							} else {
 720								$img_addr = $local_name;
 721								$img_addr =~ s/ /\%20/go;
 722								if ($options{'stripnav'}) {
 723									$img_line = "<img src=\"$img_addr\" alt=\"$name\"><br><a href=\"#top\">Return to top</a>";
 724								} else {
 725									$img_line = "<img src=\"$img_addr\" alt=\"$name\">";
 726								}
 727							}								
 728						} else {
 729							# completely new strip
 730							#  possible to get here by:
 731							#   -downloading a strip for the first time in a day
 732							#   -downloading an updated strip that replaces an old one downloaded at
 733							#    an earlier time on the same day
 734							system("mv","$local_name.tmp","$local_name");
 735						
 736							if ($options{'avantgo'}) {
 737								&make_avantgo_files($local_name, $local_name_ext);
 738								$img_line = &make_avantgo_table($local_name, $ext);
 739							} else {
 740								$img_addr = $local_name;
 741								$img_addr =~ s/ /\%20/go;
 742								if ($options{'stripnav'}) {
 743									$img_line = "<img src=\"$img_addr\" alt=\"$name\"><br><a href=\"#top\">Return to top</a>";
 744								} else {
 745									$img_line = "<img src=\"$img_addr\" alt=\"$name\">";
 746								}
 747							}
 748						}
 749					}
 750				}
 751			}
 752
 753		} else {
 754			# regular mode - just give addresses to strips on their webserver
 755			if ($options{'stripnav'}) {
 756				$img_line = "<img src=\"$img_addr\" alt=\"$name\"><br><a href=\"#top\">Return to top</a>";
 757			} else {
 758				$img_line = "<img src=\"$img_addr\" alt=\"$name\">";
 759			}
 760		}
 761	}
 762		
 763	if ($artist) {
 764		$artist = " by $artist";
 765	}
 766	
 767	if ($options{'lite'}){
 768		print
 769"<font face=\"helvetica\" size=\"+1\"><b><a href=\"$homepage\">$name</a>$artist</b></font><br>
 770$img_line<br>
 771<br>
 772";
 773	} else {
 774		my $stripanchor;
 775		if ($options{'stripnav'}) {
 776			$stripanchor = "<a name=\"$strip\">";
 777		}
 778		
 779		print
 780"	<tr>
 781		<td>
 782			<font face=\"helvetica\" size=\"+1\"><b>$stripanchor<a href=\"$homepage\">$name</a>$artist</b></font>
 783		</td>
 784	</tr>
 785	<tr>
 786		<td>
 787			$img_line
 788			<p>&nbsp;</p>
 789		</td>
 790	</tr>
 791";
 792	}
 793}
 794
 795if ($options{'local'} and !$options{'quiet'}) {
 796	if ($options{'verbose'}) {
 797		warn "Downloading strip files: done\n"
 798	} else {
 799		warn "done\n"
 800	}
 801}
 802
 803unless ($options{'lite'}) {
 804	print
 805"</table>
 806
 807<p><font face=\"helvetica\">
 808&lt; <a href=\"dailystrips-$short_date_yesterday.html\">Previous day</a>$link_tomorrow";
 809
 810	if ($options{'archive'}) {
 811		print " | <a href=\"archive.html\">Archives</a>";
 812	}
 813	
 814	print
 815" &gt;
 816</font></p>
 817
 818<font face=\"helvetica\">Generated by dailystrips $version</font>
 819
 820</body>
 821
 822</html>
 823";
 824}
 825
 826if (!$options{'date'} and !$options{'noindex'} and $^O =~ /Win32/) {
 827	# no symlinks on windows.. just make a copy of the file
 828	close(STDOUT);
 829	copy("dailystrips-$short_date.html","index.html");
 830}
 831
 832
 833# Clean out old files, if requested
 834if ($options{'clean'}) {
 835	unless ($options{'quiet'}) {
 836		print STDERR "Cleaning files older than $options{'clean'} days...";
 837	}
 838	
 839	unless (system("perl -S dailystrips-clean --quiet $options{'clean'}")) {
 840		unless ($options{'quiet'}) {
 841			print STDERR "done\n";
 842		}
 843	}
 844	else {
 845		warn "failed\nWarning: could not run dailystrips-clean script\n";
 846	}
 847	
 848	
 849}
 850
 851sub http_get {
 852	my ($url, $referer) = @_;
 853	my ($request, $response, $status);
 854
 855	# default value
 856	#unless ($retries) {
 857	#	$retries = 3;
 858	#}
 859
 860	if ($referer eq "") {$referer = $url;}
 861
 862	my $headers = new HTTP::Headers;
 863	$headers->proxy_authorization_basic(split(/:/, $options{'proxyauth'}));
 864	$headers->referer($referer);
 865	
 866	my $ua = LWP::UserAgent->new;
 867	$ua->agent($options{'useragent'});
 868	$ua->proxy('http', $options{'proxy'});
 869	
 870	for (1 .. $options{'retries'}) {
 871		# main request
 872		$request = HTTP::Request->new('GET', $url, $headers);				
 873		$response = $ua->request($request);
 874		($status = $response->status_line()) =~ s/^(\d+)/$1:/;
 875
 876		if ($response->is_error()) {
 877			if ($options{'verbose'}) {
 878				warn "Warning: could not download $url: $status (attempt $_ of $options{'retries'})\n";
 879			}
 880		} else {
 881			return $response->content;
 882		}
 883	}
 884
 885	# if we get here, URL retrieval completely failed
 886	warn "Warning: failed to download $url\n";
 887	return "ERROR: $status";
 888}
 889
 890sub get_strip {
 891	my ($strip) = @_;
 892	my ($page, $addr);
 893	
 894	if ($options{'date'} and $defs{$strip}{'provides'} eq "latest") {
 895		if ($options{'verbose'}) {
 896			warn "Warning: strip $strip not compatible with --date, skipping\n";
 897		}
 898		
 899		next;
 900	}
 901	
 902	if ($defs{$strip}{'type'} eq "search") {
 903		$page = &http_get($defs{$strip}{'searchpage'});
 904
 905		if ($page =~ /^ERROR/) {
 906			if ($options{'verbose'}) {
 907				warn "Error: $strip: could not download searchpage $defs{$strip}{'searchpage'}\n";
 908			}
 909			
 910			$addr = "unavail-server";
 911		} else {
 912			$page =~ /$defs{$strip}{'searchpattern'}/si;
 913			my @regexmatch;
 914			for (1..9) {
 915				$regexmatch[$_] = ${$_};
 916				#warn "regex match #$_: ${$_}\n";	
 917			}
 918
 919			unless (${$defs{$strip}{'matchpart'}}) {
 920				if ($options{'verbose'}) {
 921					warn "Error: $strip: searchpattern $defs{$strip}{'searchpattern'} did not match anything in searchpage $defs{$strip}{'searchpage'}\n";
 922				}
 923				
 924				$addr = "unavail-nomatch";
 925			} else {
 926				my $match = ${$defs{$strip}{'matchpart'}};
 927
 928				if ($defs{$strip}{'imageurl'}) {
 929					$addr = $defs{$strip}{'imageurl'};
 930					$addr =~ s/\$match_(\d)/$regexmatch[$1]/ge;
 931					$addr =~ s/\$match/$match/ge;
 932				} else {
 933					$addr = $defs{$strip}{'baseurl'} . $match . $defs{$strip}{'urlsuffix'};
 934				}
 935			}
 936		}
 937		
 938	} elsif ($defs{$strip}{'type'} eq "generate") {
 939		$addr = $defs{$strip}{'baseurl'} . $defs{$strip}{'imageurl'};
 940	}
 941	
 942	unless ($addr =~ /^(http:\/\/|unavail)/io) { $addr = "http://" . $addr }
 943	
 944	push(@strips,"$strip;$defs{$strip}{'name'};$defs{$strip}{'homepage'};$addr;$defs{$strip}{'referer'};$defs{$strip}{'prefetch'};$defs{$strip}{'artist'}");
 945}
 946
 947sub get_defs {
 948	my $defs_file = shift;
 949	my ($strip, $class, $sectype, $group);
 950	my $line;
 951	
 952	unless(open(DEFS, "<$defs_file")) {
 953		die "Error: could not open strip definitions file $defs_file\n";
 954	}
 955	
 956	my @defs_file = <DEFS>;
 957	close(DEFS);
 958	
 959	if ($options{'verbose'}) {
 960		warn "Loading definitions from file $defs_file\n";
 961	}
 962	
 963	for (@defs_file) {
 964		$line++;
 965		
 966		chomp;
 967		s/#(.*)//; s/^\s*//; s/\s*$//;
 968
 969		next if $_ eq "";
 970
 971		if (!$sectype) {
 972			if (/^strip\s+(\w+)$/i)
 973			{
 974				if (defined ($defs{$1}))
 975				{
 976					undef $defs{$1};
 977				}
 978				
 979				$strip = $1;
 980				$sectype = "strip";
 981			}
 982			elsif (/^class\s+(.*)$/i)
 983			{
 984				if (defined ($classes{$1}))
 985				{
 986					undef $classes{$1};
 987				}
 988							
 989				$class = $1;
 990				$sectype = "class";
 991			}
 992			elsif (/^group\s+(.*)$/i)
 993			{
 994				if (defined ($groups{$1}))
 995				{
 996					undef $groups{$1};
 997				}
 998			
 999				$group = $1;
1000				$sectype = "group";
1001			}
1002			elsif (/^(.*)/)
1003			{
1004				die "Error: Unknown keyword '$1' at $defs_file line $line\n";
1005			}
1006		}
1007		elsif (/^end$/i)
1008		{
1009			if ($sectype eq "class")
1010			{
1011				undef $class
1012			}		
1013			elsif ($sectype eq "strip")
1014			{
1015				if ($defs{$strip}{'useclass'}) {
1016					my $using_class = $defs{$strip}{'useclass'};
1017					
1018					# import vars from class
1019					for (qw(homepage searchpage searchpattern baseurl imageurl urlsuffix referer prefetch artist)) {
1020						if ($classes{$using_class}{$_} and !$defs{$strip}{$_}) {
1021							my $classvar = $classes{$using_class}{$_};
1022							$classvar =~ s/(\$[0-9])/$defs{$strip}{$1}/g;
1023							$classvar =~ s/\$strip/$strip/g;
1024							$defs{$strip}{$_} = $classvar;
1025						}
1026					}
1027				
1028					for (qw(type matchpart provides)) {
1029						if ($classes{$using_class}{$_} and !$defs{$strip}{$_}) {
1030							$defs{$strip}{$_} = $classes{$using_class}{$_};
1031						}
1032					}	
1033				}	
1034						
1035				#substitute auto vars for real vals here/set defaults
1036				unless ($defs{$strip}{'searchpage'}) {$defs{$strip}{'searchpage'} = $defs{$strip}{'homepage'}}
1037				unless ($defs{$strip}{'referer'})    {
1038					if ($defs{$strip}{'searchpage'}) {
1039						$defs{$strip}{'referer'} = $defs{$strip}{'searchpage'}
1040					} else {
1041						$defs{$strip}{'referer'} = $defs{$strip}{'homepage'}
1042					}
1043				}
1044				
1045				#other vars in definition
1046				for (qw(homepage searchpage searchpattern imageurl baseurl urlsuffix referer prefetch)) {
1047					if ($defs{$strip}{$_}) {
1048						$defs{$strip}{$_} =~ s/\$(name|homepage|searchpage|searchpattern|imageurl|baseurl|referer|prefetch)/$defs{$strip}{$1}/g;
1049					}
1050				}			
1051		
1052				#dates		
1053				for (qw(homepage searchpage searchpattern imageurl baseurl urlsuffix referer prefetch)) {
1054					if ($defs{$strip}{$_}) {
1055						$defs{$strip}{$_} =~ s/(\%(-?)[a-zA-Z])/strftime("$1", @localtime_today)/ge;
1056					}
1057				}
1058				
1059				# <code:> stuff
1060				for (qw(homepage searchpage searchpattern imageurl baseurl urlsuffix referer)) {
1061					if ($defs{$strip}{$_}) {
1062						$defs{$strip}{$_} =~ s/<code:(.*?)(?<!\\)>/&my_eval($1)/ge;
1063					}
1064				}
1065				
1066				#sanity check vars
1067				for (qw(name homepage type)) {
1068					unless ($defs{$strip}{$_}) {
1069						die "Error: strip $strip has no '$_' value\n";
1070					}
1071				}
1072				
1073				for (qw(homepage searchpage baseurl imageurl)){	
1074					if ($defs{$strip}{$_} and $defs{$strip}{$_} !~ /^http:\/\//io) {
1075						die "Error: strip $strip has invalid $_\n"
1076					}
1077				}
1078				
1079				if ($defs{$strip}{'type'} eq "search") {
1080					unless ($defs{$strip}{'searchpattern'}) {
1081						die "Error: strip $strip has no 'searchpattern' value in $defs_file\n";
1082					}
1083					
1084					unless ($defs{$strip}{'searchpattern'} =~ /\(.+\)/) {
1085						die "Error: strip $strip has no parentheses in searchpattern\n";
1086					}
1087					
1088					unless ($defs{$strip}{'matchpart'}) {
1089						#die "Error: strip $strip has no 'matchpart' value in $defs_file\n";
1090						$defs{$strip}{'matchpart'} = 1;
1091					}
1092					
1093					if ($defs{$strip}{'imageurl'} and ($defs{$strip}{'baseurl'} or $defs{$strip}{'urlsuffix'})) {
1094						die "Error: strip $strip: cannot use both 'imageurl' at the same time as 'baseurl'\nor 'urlsuffix'\n";
1095					}
1096				} elsif ($defs{$strip}{'type'} eq "generate") {
1097					unless ($defs{$strip}{'imageurl'}) {
1098						die "Error: strip $strip has no 'imageurl' value in $defs_file\n";
1099					}
1100				}
1101				
1102				unless ($defs{$strip}{'provides'}) {
1103					die "Error: strip $strip has no 'provides' value in $defs_file\n";
1104				}
1105				
1106				#debugger
1107				#foreach my $strip (keys %defs) {
1108				#	foreach my $key (qw(homepage searchpage searchpattern imageurl baseurl referer prefetch)) {
1109				#		warn "DEBUG: $strip:$key=$defs{$strip}{$key}\n";
1110				#	}
1111				#	#warn "DEBUG: $strip:name=$defs{$strip}{'name'}\n";
1112				#}
1113			
1114				undef $strip;
1115			}
1116			elsif ($sectype eq "group")
1117			{
1118				chop $groups{$group}{'strips'};
1119				
1120				unless ($groups{$group}{'desc'}) {
1121					$groups{$group}{'desc'} = "[No description]";
1122				}
1123				
1124				undef $group;
1125			}
1126			
1127			undef $sectype;
1128		}
1129		elsif ($sectype eq "class") {
1130			if (/^homepage\s+(.+)$/i) {
1131				$classes{$class}{'homepage'} = $1;
1132			}
1133			elsif (/^type\s+(.+)$/i)
1134			{
1135				unless ($1 =~ /^(search|generate)$/io) {
1136					die "Error: invalid type at $defs_file line $line\n";
1137				}
1138				
1139				$classes{$class}{'type'} = $1;
1140			}
1141			elsif (/^searchpage\s+(.+)$/i)
1142			{
1143				$classes{$class}{'searchpage'} = $1;
1144			}
1145			elsif (/^searchpattern\s+(.+)$/i)
1146			{
1147				$classes{$class}{'searchpattern'} = $1;
1148			}
1149			elsif (/^matchpart\s+(.+)$/i)
1150			{
1151				unless ($1 =~ /^(\d)$/) {
1152					die "Error: invalid 'matchpart' at $defs_file line $line\n";
1153				}
1154				
1155				$classes{$class}{'matchpart'} = $1;
1156			}
1157			elsif (/^baseurl\s+(.+)$/i)
1158			{
1159				$classes{$class}{'baseurl'} = $1;
1160			}
1161			elsif (/^urlsuffix\s+(.+)$/i)
1162			{
1163				$classes{$class}{'urlsufix'} = $1;
1164			}
1165			elsif (/^imageurl\s+(.+)$/i)
1166			{
1167				$classes{$class}{'imageurl'} = $1;
1168			}
1169			elsif (/^referer\s+(.+)$/i)
1170			{
1171				$classes{$class}{'referer'} = $1;
1172			}
1173			elsif (/^prefetch\s+(.+)$/i)
1174			{
1175				$classes{$class}{'prefetch'} = $1;
1176			}
1177			elsif (/^provides\s+(.+)$/i)
1178			{
1179				unless ($1 =~ /^(any|latest)$/i) {
1180					die "Error: invalid 'provides' at $defs_file line $line\n";
1181				}
1182
1183				$classes{$class}{'provides'} = $1;
1184			}
1185			elsif (/^artist\s+(.+)$/i)
1186			{
1187				$classes{$class}{'artist'} = $1;
1188			}
1189			elsif (/^(.+)\s+?/)
1190			{
1191				die "Unknown keyword '$1' at $defs_file line $line\n";
1192			}
1193		}
1194		elsif ($sectype eq "strip") {
1195			if (/^name\s+(.+)$/i)
1196			{
1197				$defs{$strip}{'name'} = $1;
1198			}
1199			elsif (/^useclass\s+(.+)$/i)
1200			{
1201				unless (defined $classes{$1}) {
1202					die "Error: strip $strip references invalid class $1 at $defs_file line $line\n";
1203				}
1204
1205				$defs{$strip}{'useclass'} = $1;
1206			}
1207			elsif (/^homepage\s+(.+)$/i) {
1208				$defs{$strip}{'homepage'} = $1;
1209			}
1210			elsif (/^type\s+(.+)$/i)
1211			{
1212				unless ($1 =~ /^(search|generate)$/i) {
1213					die "Error: invalid 'type' at $defs_file line $line\n";
1214				}
1215				
1216				$defs{$strip}{'type'} = $1;
1217			}
1218			elsif (/^searchpage\s+(.+)$/i)
1219			{
1220				$defs{$strip}{'searchpage'} = $1;
1221			}
1222			elsif (/^searchpattern\s+(.+)$/i)
1223			{
1224				$defs{$strip}{'searchpattern'} = $1;
1225			}
1226			elsif (/^matchpart\s+(.+)$/i)
1227			{
1228				unless ($1 =~ /^(\d+)$/) {
1229					die "Error: invalid 'matchpart' at $defs_file line $line\n";
1230				}
1231				
1232				$defs{$strip}{'matchpart'} = $1;
1233			}
1234			elsif (/^baseurl\s+(.+)$/i)
1235			{
1236				$defs{$strip}{'baseurl'} = $1;
1237			}
1238			elsif (/^urlsuffix\s+(.+)$/i)
1239			{
1240				$defs{$strip}{'urlsuffix'} = $1;
1241			}
1242			elsif (/^imageurl\s+(.+)$/i)
1243			{
1244				$defs{$strip}{'imageurl'} = $1;
1245			}
1246			elsif (/^referer\s+(.+)$/i)
1247			{
1248				$defs{$strip}{'referer'} = $1;
1249			}
1250			elsif (/^prefetch\s+(.+)$/i)
1251			{
1252				$defs{$strip}{'prefetch'} = $1;
1253			}
1254			elsif (/^(\$\d)\s+(.+)$/)
1255			{
1256				$defs{$strip}{$1} = $2;
1257			}
1258			elsif (/^provides\s+(.+)$/i)
1259			{
1260				unless ($1 =~ /^(any|latest)$/i) {
1261					die "Error: invalid 'provides' at $defs_file line $line\n";
1262				}
1263				
1264				$defs{$strip}{'provides'} = $1;
1265			}
1266			elsif (/^artist\s+(.+)$/i)
1267			{
1268				$defs{$strip}{'artist'} = $1;
1269			}
1270			elsif (/^(.+)\s+?/)
1271			{
1272				die "Error: Unknown keyword '$1' at $defs_file line $line, in strip $strip\n";
1273			}
1274		} elsif ($sectype eq  "group") {
1275			if (/^desc\s+(.+)$/i)
1276			{
1277				$groups{$group}{'desc'} = $1;
1278			}
1279			elsif (/^include\s+(.+)$/i)
1280			{
1281				$groups{$group}{'strips'} .= join(';', split(/\s+/, $1)) . ";";
1282			}
1283			elsif (/^exclude\s+(.+)$/i)
1284			{
1285				$groups{$group}{'nostrips'} .= join(';', split(/\s+/, $1)) . ";";
1286			}
1287			elsif (/^(.+)\s+?/)
1288			{
1289				die "Error: Unknown keyword '$1' at $defs_file line $line, in group $group\n";
1290			}
1291		}
1292	}
1293	
1294	# Post-processing validation
1295	for $group (keys %groups) {
1296		my (@strips, %nostrips, @okstrips);
1297		
1298		if (defined($groups{$group}{'nostrips'})) {
1299			@strips = sort(keys(%defs));
1300			foreach (split (/;/,$groups{$group}{'nostrips'})) {
1301				$nostrips{$_} = 1;
1302			}
1303		} else {
1304			@strips = split(/;/, $groups{$group}{'strips'});
1305			%nostrips = ();   #empty
1306		}
1307
1308		foreach (@strips) {
1309			unless ($defs{$_}) {
1310				warn "Warning: group $group references non-existant strip $_\n";
1311			}
1312			
1313			next if ($nostrips{$_});
1314			push (@okstrips,$_);
1315		}
1316		$groups{$group}{'strips'} = join(';',@okstrips);
1317	}
1318	
1319}
1320
1321sub my_eval {
1322	my ($code) = @_;
1323	
1324	$code =~ s/\\\>/\>/g;
1325	
1326	return eval $code;
1327	#print STDERR "DEBUG: eval returned: " . scalar(eval $code) . ", errors: $!\n";
1328}
1329
1330sub make_avantgo_table {
1331	my ($file, $file_ext) = @_;
1332	my ($rows, $cols, $table);
1333	
1334	my $dimensions = `identify \"$file\"`;
1335	
1336	$dimensions =~ m/^$file (\d+)x(\d+)/;
1337	my $width = $1; my $height = $2;
1338	
1339	if (int($width/160) != ($width/160)) {
1340		$cols = int($width/160) + 1;
1341	} else {
1342		$cols = $width/160;
1343	}
1344	
1345	if (int($height/160) != ($height/160)) {
1346		$rows = int($height/160) + 1;
1347	} else {
1348		$rows = $height/160;
1349	}
1350	
1351	my $file_base = $file; $file_base =~ s/$file_ext$//;
1352
1353	$file_base =~ s/ /\%20/g;
1354	
1355	$table = "<table border=0 cellspacing=0 cellpadding=0>";
1356	foreach my $row (0 .. ($rows-1)) {
1357		$table .= "<tr>";
1358		foreach my $col (0 .. ($cols-1)) {
1359			$table .= "<td><img src=$file_base-" . (($row * $cols) + $col) . "$file_ext></td>";
1360		
1361		}
1362		$table .= "</tr>";
1363	}
1364	$table .= "</table>";
1365	
1366	return $table;
1367}
1368
1369sub make_avantgo_files {
1370	my ($file, $file_ext) = @_;
1371
1372	my $file_base = $file; $file_base =~ s/$file_ext$//;
1373
1374	system("convert -crop 160x160 \"$file\" \"$file_base-\%d$file_ext\"");
1375}
1376
1377sub get_homedir
1378{
1379	if ($^O =~ /Win32/ )
1380	{
1381		my $dir = $ENV{'USERPROFILE'};
1382		if ($dir eq "") {$dir = $ENV{'WINDIR'};}
1383		$dir =~ s|\\|/|g;
1384		return $dir; 
1385        }
1386	else
1387	{
1388		return (getpwuid($>))[7];
1389        }
1390}