]> git.donarmstrong.com Git - deb_pkgs/libapache-gallery-perl.git/blobdiff - lib/Apache/Gallery.pm
[svn-buildpackage] Tagging libapache-gallery-perl 1.0.2-1
[deb_pkgs/libapache-gallery-perl.git] / lib / Apache / Gallery.pm
index d543fcaa980519818f48c0516de7c3185df4917b..ee9f63af81e4c0ea3eaa09c7e11abdc556b9e366 100644 (file)
@@ -1,13 +1,13 @@
 package Apache::Gallery;
 
-# $Author: mil $ $Rev: 316 $
-# $Date: 2006-08-04 16:28:06 +0300 (Fri, 04 Aug 2006) $
+# $Author: mil $ $Rev: 335 $
+# $Date: 2011-06-08 20:47:46 +0200 (Wed, 08 Jun 2011) $
 
 use strict;
 
 use vars qw($VERSION);
 
-$VERSION = "1.0RC3";
+$VERSION = "1.0.2";
 
 BEGIN {
 
@@ -25,7 +25,7 @@ BEGIN {
                require Apache2::SubRequest;
                require Apache2::Const;
        
-               Apache2::Const->import(-compile => 'OK','DECLINED','FORBIDDEN','NOT_FOUND');
+               Apache2::Const->import(-compile => 'OK','DECLINED','FORBIDDEN','NOT_FOUND','HTTP_NOT_MODIFIED');
 
                $::MP2 = 1;
        } else {
@@ -50,6 +50,9 @@ use POSIX qw(floor);
 use URI::Escape;
 use CGI;
 use CGI::Cookie;
+use Encode;
+use HTTP::Date;
+use Digest::MD5 qw(md5_base64);
 
 use Data::Dumper;
 
@@ -61,6 +64,10 @@ sub handler {
 
        my $r = shift or Apache2::RequestUtil->request();
 
+       unless (($r->method eq 'HEAD') or ($r->method eq 'GET')) {
+               return $::MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED();
+       }
+
        if ((not $memoized) and ($r->dir_config('GalleryMemoize'))) {
                require Memoize;
                Memoize::memoize('get_imageinfo');
@@ -68,12 +75,14 @@ sub handler {
        }
 
        $r->headers_out->{"X-Powered-By"} = "apachegallery.dk $VERSION - Hest design!";
-       $r->headers_out->{"X-Gallery-Version"} = '$Rev: 316 $ $Date: 2006-08-04 16:28:06 +0300 (Fri, 04 Aug 2006) $';
+       $r->headers_out->{"X-Gallery-Version"} = '$Rev: 335 $ $Date: 2011-06-08 20:47:46 +0200 (Wed, 08 Jun 2011) $';
 
        my $filename = $r->filename;
        $filename =~ s/\/$//;
        my $topdir = $filename;
 
+       my $media_rss_enabled = $r->dir_config('GalleryEnableMediaRss');
+
        # Just return the http headers if the client requested that
        if ($r->header_only) {
 
@@ -81,7 +90,7 @@ sub handler {
                        $r->send_http_header;
                }
 
-       if (-f $filename or -d $filename) {
+               if (-f $filename or -d $filename) {
                        return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
                }
                else {
@@ -139,6 +148,20 @@ sub handler {
                $r->content_type($subr->content_type());
 
                if ($::MP2) {
+                       my $fileinfo = stat($file);
+
+                       my $nonce = md5_base64($fileinfo->ino.$fileinfo->mtime);
+                       if ($r->headers_in->{"If-None-Match"} eq $nonce) {
+                               return Apache2::Const::HTTP_NOT_MODIFIED();
+                       }
+
+                       if ($r->headers_in->{"If-Modified-Since"} && str2time($r->headers_in->{"If-Modified-Since"}) < $fileinfo->mtime) {
+                               return Apache2::Const::HTTP_NOT_MODIFIED();
+                       }
+
+                       $r->headers_out->{"Content-Length"} = $fileinfo->size; 
+                       $r->headers_out->{"Last-Modified-Date"} = time2str($fileinfo->mtime); 
+                       $r->headers_out->{"ETag"} = $nonce;
                        $r->sendfile($file);
                        return Apache2::Const::OK();
                }
@@ -160,7 +183,7 @@ sub handler {
 
        my $doc_pattern = $r->dir_config('GalleryDocFile');
        unless ($doc_pattern) {
-               $doc_pattern = '\.(mpe?g|avi|mov|asf|wmv|doc|mp3|ogg|pdf|rtf|wav|dlt|html?|csv|eps)$'
+               $doc_pattern = '\.(mpe?g|avi|mov|asf|wmv|doc|mp3|ogg|pdf|rtf|wav|dlt|txt|html?|csv|eps)$'
        }
        my $img_pattern = $r->dir_config('GalleryImgFile');
        unless ($img_pattern) {
@@ -185,13 +208,16 @@ sub handler {
                # Instead of reading the templates every single time
                # we need them, create a hash of template names and
                # the associated Text::Template objects.
-               my %templates = create_templates({layout    => "$tpl_dir/layout.tpl",
-                                                 index     => "$tpl_dir/index.tpl",
-                                                 directory => "$tpl_dir/directory.tpl",
-                                                 picture   => "$tpl_dir/picture.tpl",
-                                                 file      => "$tpl_dir/file.tpl",
-                                                 comment   => "$tpl_dir/dircomment.tpl",
-                                                 nocomment => "$tpl_dir/nodircomment.tpl",
+               my %templates = create_templates({layout       => "$tpl_dir/layout.tpl",
+                                                 index        => "$tpl_dir/index.tpl",
+                                                 directory    => "$tpl_dir/directory.tpl",
+                                                 picture      => "$tpl_dir/picture.tpl",
+                                                 file         => "$tpl_dir/file.tpl",
+                                                 comment      => "$tpl_dir/dircomment.tpl",
+                                                 nocomment    => "$tpl_dir/nodircomment.tpl",
+                                                 rss          => "$tpl_dir/rss.tpl",
+                                                 rss_item     => "$tpl_dir/rss_item.tpl",
+                                                 navdirectory => "$tpl_dir/navdirectory.tpl",
                                                 });
 
 
@@ -200,7 +226,11 @@ sub handler {
                my %tpl_vars;
 
                $tpl_vars{TITLE} = "Index of: $uri";
-               $tpl_vars{META} = " ";
+
+               if ($media_rss_enabled) {
+                       # Put the RSS feed on all directory listings
+                       $tpl_vars{META} = '<link rel="alternate" href="?rss=1" type="application/rss+xml" title="" id="gallery" />';
+               }
 
                unless (opendir (DIR, $filename)) {
                        show_error ($r, 500, $!, "Unable to access directory $filename: $!");
@@ -321,7 +351,8 @@ sub handler {
 
                                my $fileurl = $uri."/".$file;
 
-                               if (-d $thumbfilename) {
+                               # Debian bug #619625 <http://bugs.debian.org/619625>
+                               if (-d $thumbfilename && ! -e $thumbfilename . ".ignore") {
                                        my $dirtitle = '';
                                        if (-e $thumbfilename . ".folder") {
                                                $dirtitle = get_filecontent($thumbfilename . ".folder");
@@ -335,8 +366,10 @@ sub handler {
                                                                                    FILE    => $dirtitle,
                                                                                   }
                                                                           );
+
                                }
-                               elsif (-f $thumbfilename && $thumbfilename =~ /$doc_pattern/i && $thumbfilename !~ /$img_pattern/i) {
+                               # Debian bug #619625 <http://bugs.debian.org/619625>
+                               elsif (-f $thumbfilename && $thumbfilename =~ /$doc_pattern/i && $thumbfilename !~ /$img_pattern/i && ! -e $thumbfilename . ".ignore") {
                                        my $type = lc($1);
                                        my $stat = stat($thumbfilename);
                                        my $size = $stat->size;
@@ -348,23 +381,29 @@ sub handler {
                                                $filetype = "text-$type";
                                        } elsif ($thumbfilename =~ m/\.(mp3|ogg|wav)$/i) {
                                                $filetype = "sound-$type";
-                                       } elsif ($thumbfilename =~ m/\.(doc|pdf|rtf|csv|eps)$/i) {
+                                       } elsif ($thumbfilename =~ m/$doc_pattern/i) {
                                                $filetype = "application-$type";
                                        } else {
                                                $filetype = "unknown";
                                        }
 
+                                       # Debian bug #348724 <http://bugs.debian.org/348724>
+                                       # not images
+                                       my $filetitle = $file;
+                                       $filetitle =~ s/_/ /g if $r->dir_config('GalleryUnderscoresToSpaces');
+
                                        $tpl_vars{FILES} .=
                                             $templates{file}->fill_in(HASH => {%tpl_vars,
                                                                                FILEURL => uri_escape($fileurl, $escape_rule),
                                                                                ALT => "Size: $size Bytes",
-                                                                               FILE => $file,
+                                                                               FILE => $filetitle,
                                                                                TYPE => $type,
                                                                                FILETYPE => $filetype,
                                                                               }
                                                                      );
                                }
-                               elsif (-f $thumbfilename) {
+                               # Debian bug #619625 <http://bugs.debian.org/619625>
+                               elsif (-f $thumbfilename && ! -e $thumbfilename . ".ignore") {
 
                                        my ($width, $height, $type) = imgsize($thumbfilename);
                                        next if $type eq 'Data stream is not a known image file format';
@@ -377,8 +416,14 @@ sub handler {
                                        my $cached = get_scaled_picture_name($thumbfilename, $thumbnailwidth, $thumbnailheight);
 
                                        my $rotate = readfile_getnum($r, $imageinfo, $thumbfilename.".rotate");
+
+                                       # Debian bug #348724 <http://bugs.debian.org/348724>
+                                       # HTML <img> tag, alt attribute
+                                       my $filetitle = $file;
+                                       $filetitle =~ s/_/ /g if $r->dir_config('GalleryUnderscoresToSpaces');
+
                                        my %file_vars = (FILEURL => uri_escape($fileurl, $escape_rule),
-                                                        FILE    => $file,
+                                                        FILE    => $filetitle,
                                                         DATE    => $imageinfo->{DateTimeOriginal} ? $imageinfo->{DateTimeOriginal} : '', # should this really be a stat of the file instead of ''?
                                                         SRC     => uri_escape($uri."/.cache/$cached", $escape_rule),
                                                         HEIGHT => (grep($rotate==$_, (1, 3)) ? $thumbnailwidth : $thumbnailheight),
@@ -388,6 +433,19 @@ sub handler {
                                                                                                 %file_vars,
                                                                                                },
                                                                                       );
+
+                                       if ($media_rss_enabled) {
+                                               my ($content_image_width, undef, $content_image_height) = get_image_display_size($cgi, $r, $width, $height);
+                                               my %item_vars = ( 
+                                                       THUMBNAIL => uri_escape($uri."/.cache/$cached", $escape_rule),
+                                                       LINK      => uri_escape($fileurl, $escape_rule),
+                                                       TITLE     => $file,
+                                                       CONTENT   => uri_escape($uri."/.cache/".$content_image_width."x".$content_image_height."-".$file, $escape_rule)
+                                               );
+                                               $tpl_vars{ITEMS} .= $templates{rss_item}->fill_in(HASH => { 
+                                                       %item_vars
+                                               });
+                                       }
                                }
                        }
                }
@@ -396,6 +454,71 @@ sub handler {
                        $tpl_vars{BROWSELINKS} = "";
                }
 
+               # Generate prev and next directory menu items
+               $filename =~ m/(.*)\/.*?$/;
+               my $parent_filename = $1;
+
+               $r->document_root =~ m/(.*)\/$/;
+               my $root_path = $1;
+               print STDERR "$filename vs $root_path\n";
+               if ($filename ne $root_path) {
+                       unless (opendir (PARENT_DIR, $parent_filename)) {
+                               show_error ($r, 500, $!, "Unable to access parent directory $parent_filename: $!");
+                               return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
+                       }
+       
+                       # Debian bug #619625 <http://bugs.debian.org/619625>
+                       my @neighbour_directories = grep { !/^\./ && -d "$parent_filename/$_" && ! -e "$parent_filename/$_" . ".ignore" } readdir (PARENT_DIR);
+                       my $dirsortby;
+                       if (defined($r->dir_config('GalleryDirSortBy'))) {
+                               $dirsortby=$r->dir_config('GalleryDirSortBy');
+                       } else {
+                               $dirsortby=$r->dir_config('GallerySortBy');
+                       }
+                       if ($dirsortby && $dirsortby =~ m/^(size|atime|mtime|ctime)$/) {
+                               @neighbour_directories = map(/^\d+ (.*)/, sort map(stat("$parent_filename/$_")->$dirsortby()." $_", @neighbour_directories));
+                       } else {
+                               @neighbour_directories = sort @neighbour_directories;
+                       }
+
+                       closedir(PARENT_DIR);
+
+                       my $neightbour_counter = 0;
+                       foreach my $neighbour_directory (@neighbour_directories) {
+                               if ($parent_filename.'/'.$neighbour_directory eq $filename) {
+                                       if ($neightbour_counter > 0) {
+                                               print STDERR "prev directory is " .$neighbour_directories[$neightbour_counter-1] ."\n";
+                                               my $linktext = $neighbour_directories[$neightbour_counter-1];
+                                               if (-e $parent_filename.'/'.$neighbour_directories[$neightbour_counter-1] . ".folder") {
+                                                       $linktext = get_filecontent($parent_filename.'/'.$neighbour_directories[$neightbour_counter-1] . ".folder");
+                                               }
+                                               my %info = (
+                                               URL => "../".$neighbour_directories[$neightbour_counter-1],
+                                               LINK_NAME => "<<< $linktext",
+                                               DIR_FILES => "",
+                                               );
+                                               $tpl_vars{PREV_DIR_FILES} = $templates{navdirectory}->fill_in(HASH=> {%info});
+                                               print STDERR $tpl_vars{PREV_DIR_FILES} ."\n";
+
+                                       }
+                                       if ($neightbour_counter < scalar @neighbour_directories - 1) {
+                                               my $linktext = $neighbour_directories[$neightbour_counter+1];
+                                               if (-e $parent_filename.'/'.$neighbour_directories[$neightbour_counter+1] . ".folder") {
+                                                       $linktext = get_filecontent($parent_filename.'/'.$neighbour_directories[$neightbour_counter+1] . ".folder");
+                                               }
+                                               my %info = (
+                                               URL => "../".$neighbour_directories[$neightbour_counter+1],
+                                               LINK_NAME => "$linktext >>>",
+                                               DIR_FILES => "",
+                                               );
+                                               $tpl_vars{NEXT_DIR_FILES} = $templates{navdirectory}->fill_in(HASH=> {%info});
+                                               print STDERR "next directory is " .$neighbour_directories[$neightbour_counter+1] ."\n";
+                                       }
+                               }
+                               $neightbour_counter++;
+                       }
+               }
+
                if (-f $topdir . '.comment') {
                        my $comment_ref = get_comment($topdir . '.comment');
                        my %comment_vars;
@@ -407,11 +530,15 @@ sub handler {
                        $tpl_vars{DIRCOMMENT} = $templates{nocomment}->fill_in(HASH=>\%tpl_vars);
                }
 
-               $tpl_vars{MAIN} = $templates{index}->fill_in(HASH => \%tpl_vars);
-
-               $tpl_vars{MAIN} = $templates{layout}->fill_in(HASH => \%tpl_vars);
+               if ($cgi->param('rss')) {
+                       $tpl_vars{MAIN} = $templates{rss}->fill_in(HASH => \%tpl_vars);
+                       $r->content_type('application/rss+xml');
+               } else {
+                       $tpl_vars{MAIN} = $templates{index}->fill_in(HASH => \%tpl_vars);
+                       $tpl_vars{MAIN} = $templates{layout}->fill_in(HASH => \%tpl_vars);
+                       $r->content_type('text/html');
+               }
 
-               $r->content_type('text/html');
                $r->headers_out->{'Content-Length'} = length($tpl_vars{MAIN});
 
                if (!$::MP2) {
@@ -447,54 +574,10 @@ sub handler {
                }
 
                my ($orig_width, $orig_height, $type) = imgsize($filename);
-               my $width = $orig_width;
 
                my $imageinfo = get_imageinfo($r, $filename, $type, $orig_width, $orig_height);
 
-               my $original_size=$orig_height;
-               if ($orig_width>$orig_height) {
-                       $original_size=$orig_width;
-               }
-
-               # Check if the selected width is allowed
-               my @sizes = split (/ /, $r->dir_config('GallerySizes') ? $r->dir_config('GallerySizes') : '640 800 1024 1600');
-
-               my %cookies = fetch CGI::Cookie;
-
-               if ($cgi->param('width')) {
-                       unless ((grep $cgi->param('width') == $_, @sizes) or ($cgi->param('width') == $original_size)) {
-                               show_error($r, 200, "Invalid width", "The specified width is invalid");
-                               return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
-                       }
-
-                       $width = $cgi->param('width');
-                       my $cookie = new CGI::Cookie(-name => 'GallerySize', -value => $width, -expires => '+6M');
-                       $r->headers_out->{'Set-Cookie'} = $cookie;
-
-               } elsif ($cookies{'GallerySize'} && (grep $cookies{'GallerySize'}->value == $_, @sizes)) {
-
-                       $width = $cookies{'GallerySize'}->value;
-
-               } else {
-                       $width = $sizes[0];
-               }       
-
-               my $scale;
-               my $image_width;
-               if ($orig_width<$orig_height) {
-                       $scale = ($orig_height ? $width/$orig_height: 1);
-                       $image_width=$width*$orig_width/$orig_height;
-               }
-               else {
-                       $scale = ($orig_width ? $width/$orig_width : 1);
-                       $image_width = $width;
-               }
-
-               my $height = $orig_height * $scale;
-
-               $image_width = floor($image_width);
-               $width       = floor($width);
-               $height      = floor($height);
+               my ($image_width, $width, $height, $original_size) = get_image_display_size($cgi, $r, $orig_width, $orig_height);
 
                my $cached = get_scaled_picture_name($filename, $image_width, $height);
                
@@ -537,7 +620,7 @@ sub handler {
                        show_error($r, 500, "Unable to access directory", "Unable to access directory $path");
                        return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
                }
-               my @pictures = grep { /$img_pattern/i } readdir (DATADIR);
+               my @pictures = grep { /$img_pattern/i && ! -e "$path/$_" . ".ignore" } readdir (DATADIR);
                closedir(DATADIR);
                @pictures = gallerysort($r, @pictures);
 
@@ -610,6 +693,9 @@ sub handler {
                        $foundcomment = 1;
                        $tpl_vars{COMMENT} = $comment_ref->{COMMENT} . '<br />' if $comment_ref->{COMMENT};
                        $tpl_vars{TITLE} = $comment_ref->{TITLE} if $comment_ref->{TITLE};
+               } elsif ($r->dir_config('GalleryCommentExifKey')) {
+                       my $comment = decode("utf8", $imageinfo->{$r->dir_config('GalleryCommentExifKey')});
+                       $tpl_vars{COMMENT} = encode("iso-8859-1", $comment);
                } else {
                        $tpl_vars{COMMENT} = '';
                }
@@ -677,6 +763,7 @@ sub handler {
                # Fill in sizes and determine if any are smaller than the
                # actual image. If they are, $scaleable=1
                my $scaleable = 0;
+               my @sizes = split (/ /, $r->dir_config('GallerySizes') ? $r->dir_config('GallerySizes') : '640 800 1024 1600');
                foreach my $size (@sizes) {
                        if ($size<=$original_size) {
                                my %sizes_vars;
@@ -769,7 +856,7 @@ sub cache_dir {
 
        unless ($r->dir_config('GalleryCacheDir')) {
 
-               $cache_root = '/var/tmp/Apache-Gallery/';
+               $cache_root = '/var/cache/www/';
                if ($r->server->is_virtual) {
                        $cache_root = File::Spec->catdir($cache_root, $r->server->server_hostname);
                } else {
@@ -970,6 +1057,59 @@ sub get_thumbnailsize {
        return ($width, $height);
 }
 
+sub get_image_display_size {
+       my ($cgi, $r, $orig_width, $orig_height) = @_;
+
+       my $width = $orig_width;
+
+       my $original_size=$orig_height;
+       if ($orig_width>$orig_height) {
+               $original_size=$orig_width;
+       }
+
+       # Check if the selected width is allowed
+       my @sizes = split (/ /, $r->dir_config('GallerySizes') ? $r->dir_config('GallerySizes') : '640 800 1024 1600');
+
+       my %cookies = fetch CGI::Cookie;
+
+       if ($cgi->param('width')) {
+               unless ((grep $cgi->param('width') == $_, @sizes) or ($cgi->param('width') == $original_size)) {
+                       show_error($r, 200, "Invalid width", "The specified width is invalid");
+                       return $::MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
+               }
+
+               $width = $cgi->param('width');
+               my $cookie = new CGI::Cookie(-name => 'GallerySize', -value => $width, -expires => '+6M');
+               $r->headers_out->{'Set-Cookie'} = $cookie;
+
+       } elsif ($cookies{'GallerySize'} && (grep $cookies{'GallerySize'}->value == $_, @sizes)) {
+
+               $width = $cookies{'GallerySize'}->value;
+
+       } else {
+               $width = $sizes[0];
+       }       
+
+       my $scale;
+       my $image_width;
+       if ($orig_width<$orig_height) {
+               $scale = ($orig_height ? $width/$orig_height: 1);
+               $image_width=$width*$orig_width/$orig_height;
+       }
+       else {
+               $scale = ($orig_width ? $width/$orig_width : 1);
+               $image_width = $width;
+       }
+
+       my $height = $orig_height * $scale;
+
+       $image_width = floor($image_width);
+       $width       = floor($width);
+       $height      = floor($height);
+
+       return ($image_width, $width, $height, $original_size);
+}
+
 sub get_imageinfo {
        my ($r, $file, $type, $width, $height) = @_;
        my $imageinfo = {};
@@ -1193,11 +1333,13 @@ sub readfile_getnum {
 
        my $rotate = 0;
 
+       print STDERR "orientation: ".$imageinfo->{Orientation}."\n";
        # Check to see if the image contains the Orientation EXIF key,
        # but allow user to override using rotate
        if (!defined($r->dir_config("GalleryAutoRotate")) 
                || $r->dir_config("GalleryAutoRotate") eq "1") {
                if (defined($imageinfo->{Orientation})) {
+                       print STDERR $imageinfo->{Orientation}."\n";
                        if ($imageinfo->{Orientation} eq 'right_top') {
                                $rotate=1;
                        }       
@@ -1521,7 +1663,7 @@ directories.
 The options are set in the httpd.conf/.htaccess file using the syntax:
 B<PerlSetVar OptionName 'value'>
 
-Example: B<PerlSetVar GalleryCacheDir '/var/tmp/Apache-Gallery/'>
+Example: B<PerlSetVar GalleryCacheDir '/var/cache/www/'>
 
 =over 4
 
@@ -1538,9 +1680,9 @@ to 0.
 =item B<GalleryCacheDir>
 
 Directory where Apache::Gallery should create its cache with scaled
-pictures. The default is /var/tmp/Apache-Gallery/ . Here, a directory
-for each virtualhost or location will be created automaticly. Make
-sure your webserver has write access to the CacheDir.
+pictures. The default is /var/cache/www/ . Here, a directory for each
+virtualhost or location will be created automatically. Make sure your
+webserver has write access to the CacheDir.
 
 =item B<GalleryTemplateDir>
 
@@ -1657,7 +1799,7 @@ If you set this option to 'variables' the items you configure in GalleryInfo
 will be available to your templates as $EXIF_<KEYNAME> (in all uppercase). 
 That means that with the default setting "Picture Taken => DateTimeOriginal, 
 Flash => Flash" you will have the variables $EXIF_DATETIMEORIGINAL and 
-$EXIF_FLASH avilable to your templates. You can place them
+$EXIF_FLASH available to your templates. You can place them
 anywhere you want.
 
 =item B<GalleryRootPath>
@@ -1687,7 +1829,7 @@ Pattern matching the files you want Apache::Gallery to view in the index
 as normal files. All other filetypes will still be served by Apache::Gallery
 but are not visible in the index.
 
-The default is '\.(mpe?g|avi|mov|asf|wmv|doc|mp3|ogg|pdf|rtf|wav|dlt|html?|csv|eps)$'
+The default is '\.(mpe?g|avi|mov|asf|wmv|doc|mp3|ogg|pdf|rtf|wav|dlt|txt|html?|csv|eps)$'
 
 =item B<GalleryTTFDir>
 
@@ -1770,7 +1912,22 @@ Quality at 50:
 =item B<GalleryUnderscoresToSpaces>
 
 Set this option to 1 to convert underscores to spaces in the listing
-of directory names.
+of directory and file names, as well as in the alt attribute for HTML
+<img> tags.
+
+=back
+
+=over 4
+
+=item B<GalleryCommentExifKey>
+
+Set this option to e.g. ImageDescription to use this field as comments
+for images.
+
+=item B<GalleryEnableMediaRss>
+
+Set this option to 1 to enable generation of a media RSS feed. This
+can be used e.g. together with the PicLens plugin from http://piclens.com
 
 =back
 
@@ -1782,7 +1939,7 @@ of directory names.
 
 Some cameras, like the Canon G3, detects the orientation of a picture
 and adds this info to the EXIF header. Apache::Gallery detects this
-and automaticly rotates images with this info.
+and automatically rotates images with this info.
 
 If your camera does not support this, you can rotate the images 
 manually, This can also be used to override the rotate information
@@ -1790,7 +1947,7 @@ from a camera that supports that. You can also disable this behavior
 with the GalleryAutoRotate option.
 
 To use this functionality you have to create file with the name of the 
-picture you want rotated appened with ".rotate". The file should include 
+picture you want rotated appended with ".rotate". The file should include 
 a number where these numbers are supported:
 
        "1", rotates clockwise by 90 degree
@@ -1801,6 +1958,11 @@ So if we want to rotate "Picture1234.jpg" 90 degrees clockwise we would
 create a file in the same directory called "Picture1234.jpg.rotate" with
 the number 1 inside of it.
 
+=item B<Ignore directories/files>
+
+To ignore a directory or a file (of any kind, not only images) you
+create a <directory|file>.ignore file.
+
 =item B<Comments>
 
 To include comments for a directory you create a <directory>.comment
@@ -1822,6 +1984,10 @@ The visible name of the folder is by default identical to the name of
 the folder, but can be changed by creating a file <directory>.folder
 with the visible name of the folder.
 
+It is also possible to set GalleryCommentExifKey to the name of an EXIF
+field containing the comment, e.g. ImageDescription. The EXIF comment is
+overridden by the .comment file if it exists.
+
 =back
 
 =head1 DEPENDENCIES
@@ -1856,7 +2022,7 @@ Michael Legart <michael@legart.dk>
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (C) 2001-2005 Michael Legart <michael@legart.dk>
+Copyright (C) 2001-2011 Michael Legart <michael@legart.dk>
 
 Templates designed by Thomas Kjaer <tk@lnx.dk>