Make JavaScript *actually* optional
[gitweb] / gitweb.cgi
index f8d82f71d879edf6fabc48b7fbb7e848f80d275a..515d80cbded1e58b0ed9d2f5e34280752b23f4df 100755 (executable)
@@ -887,7 +887,6 @@ our %actions = (
        "patch" => \&git_patch,
        "patches" => \&git_patches,
        "remotes" => \&git_remotes,
-       "rss" => \&git_rss,
        "atom" => \&git_atom,
        "search" => \&git_search,
        "search_help" => \&git_search_help,
@@ -907,7 +906,7 @@ our %actions = (
 # finally, we have the hash of allowed extra_options for the commands that
 # allow them
 our %allowed_options = (
-       "--no-merges" => [ qw(rss atom log shortlog history) ],
+       "--no-merges" => [ qw(atom log shortlog history) ],
 );
 
 # fill %input_params with the CGI parameters. All values except for 'opt'
@@ -4027,40 +4026,36 @@ sub run_highlighter {
 ## functions printing HTML: header, footer, error page
 
 sub get_page_title {
-       my $title = to_utf8($site_name);
-
+       # Formats:
+       # SITE_NAME
+       # SITE_NAME - projects in FILTER
+       # PROJECT - SITE_NAME
+       # PROJECT ACTION - SITE_NAME
+       # FILENAME - PROJECT ACTION - SITE_NAME
+       my $title;
        unless (defined $project) {
+               $title = to_utf8($site_name);
                if (defined $project_filter) {
                        $title .= " - projects in '" . esc_path($project_filter) . "'";
                }
                return $title;
        }
-       $title .= " - " . to_utf8($project);
-
-       return $title unless (defined $action);
-       $title .= "/$action"; # $action is US-ASCII (7bit ASCII)
+       $title = to_utf8($project);
 
-       return $title unless (defined $file_name);
-       $title .= " - " . esc_path($file_name);
-       if ($action eq "tree" && $file_name !~ m|/$|) {
-               $title .= "/";
+       if (defined $action) {
+               $title .= " $action"; # $action is US-ASCII (7bit ASCII)
+               if (defined $file_name) {
+                       $title = " - " . $title;
+                       if ($action eq "tree" && $file_name !~ m|/$|) {
+                               $title = "/" . $title;
+                       }
+                       $title = esc_path($file_name) . $title;
+               }
        }
 
-       return $title;
-}
+       $title .= " - " . to_utf8($site_name);
 
-sub get_content_type_html {
-       # require explicit support from the UA if we are to send the page as
-       # 'application/xhtml+xml', otherwise send it as plain old 'text/html'.
-       # we have to do this because MSIE sometimes globs '*/*', pretending to
-       # support xhtml+xml but choking when it gets what it asked for.
-       if (defined $cgi->http('HTTP_ACCEPT') &&
-           $cgi->http('HTTP_ACCEPT') =~ m/(,|;|\s|^)application\/xhtml\+xml(,|;|\s|$)/ &&
-           $cgi->Accept('application/xhtml+xml') != 0) {
-               return 'application/xhtml+xml';
-       } else {
-               return 'text/html';
-       }
+       return $title;
 }
 
 sub print_feed_meta {
@@ -4070,7 +4065,7 @@ sub print_feed_meta {
                        $href_params{'-title'} = 'log';
                }
 
-               foreach my $format (qw(RSS Atom)) {
+               foreach my $format (qw(Atom)) {
                        my $type = lc($format);
                        my %link_attr = (
                                '-rel' => 'alternate',
@@ -4117,17 +4112,17 @@ sub print_header_links {
        # print out each stylesheet that exist, providing backwards capability
        # for those people who defined $stylesheet in a config file
        if (defined $stylesheet) {
-               print '<link rel="stylesheet" type="text/css" href="'.esc_url($stylesheet).'"/>'."\n";
+               print '<link rel="stylesheet" href="'.esc_url($stylesheet).'"/>'."\n";
        } else {
                foreach my $stylesheet (@stylesheets) {
                        next unless $stylesheet;
-                       print '<link rel="stylesheet" type="text/css" href="'.esc_url($stylesheet).'"/>'."\n";
+                       print '<link rel="stylesheet" href="'.esc_url($stylesheet).'"/>'."\n";
                }
        }
        print_feed_meta()
                if ($status eq '200 OK');
        if (defined $favicon) {
-               print qq(<link rel="shortcut icon" href=").esc_url($favicon).qq(" type="image/png" />\n);
+               print qq(<link rel="icon" href=").esc_url($favicon).qq("/>\n);
        }
 }
 
@@ -4188,8 +4183,7 @@ sub print_search_form {
        if ($use_pathinfo) {
                $action .= "/".esc_url($project);
        }
-       print $cgi->start_form(-method => "get", -action => $action) .
-             "<div class=\"search\">\n" .
+       print $cgi->start_form(-method => "get", -action => $action, -role => "search") .
              (!$use_pathinfo &&
              $cgi->input({-name=>"p", -value=>$project, -type=>"hidden"}) . "\n") .
              $cgi->input({-name=>"a", -value=>"search", -type=>"hidden"}) . "\n" .
@@ -4203,7 +4197,6 @@ sub print_search_form {
              $cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
                             -checked => $search_use_regexp) .
              "</span>" .
-             "</div>" .
              $cgi->end_form() . "\n";
 }
 
@@ -4213,27 +4206,25 @@ sub git_header_html {
        my %opts = @_;
 
        my $title = get_page_title();
-       my $content_type = get_content_type_html();
-       print $cgi->header(-type=>$content_type, -charset => 'utf-8',
+       # I wanted to switch to text/html, but it uses nested <a> in a couple of places (e.g. log refs are links inside the commit summary link), which is invalid but works in the XML syntax. Pity.
+       # (Various other invalid HTML is produced that HTML would have fixed but XHTML allows to be broken, like table > tr, lacking tbody.)
+       # TODO: reduce the doctype to <!DOCTYPE html>, but that takes replacing entities like &sdot; with ⋅.
+       print $cgi->header(-type => 'application/xhtml+xml', -charset => 'utf-8',
                           -status=> $status, -expires => $expires)
                unless ($opts{'-no_http_header'});
-       my $mod_perl_version = $ENV{'MOD_PERL'} ? " $ENV{'MOD_PERL'}" : '';
        print <<EOF;
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
-<!-- git web interface version $version, (C) 2005-2006, Kay Sievers <kay.sievers\@vrfy.org>, Christian Gierke -->
-<!-- git core binaries version $git_version -->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-AU" lang="en-AU">
 <head>
-<meta http-equiv="content-type" content="$content_type; charset=utf-8"/>
-<meta name="generator" content="gitweb/$version git/$git_version$mod_perl_version"/>
+<meta charset="utf-8"/>
 <meta name="robots" content="index, nofollow"/>
 <title>$title</title>
 EOF
        # the stylesheet, favicon etc urls won't work correctly with path_info
        # unless we set the appropriate base URL
        if ($ENV{'PATH_INFO'}) {
-               print "<base href=\"".esc_url($base_url)."\" />\n";
+               print "<base href=\"".esc_url($base_url)."\"/>\n";
        }
        print_header_links($status);
 
@@ -4241,14 +4232,11 @@ EOF
                print to_utf8($site_html_head_string);
        }
 
-       print "</head>\n" .
-             "<body>\n";
-
        if (defined $site_header && -f $site_header) {
                insert_file($site_header);
        }
 
-       print "<div class=\"page_header\">\n";
+       print "</head>\n<body>\n<header class=\"page_header\">\n";
        if (defined $logo) {
                print $cgi->a({-href => esc_url($logo_url),
                               -title => $logo_label},
@@ -4258,18 +4246,23 @@ EOF
                                         -class => "logo"}));
        }
        print_nav_breadcrumbs(%opts);
-       print "</div>\n";
+       print "</header>\n";
 
+       print "<nav class=\"page_subhead\">\n";
+}
+
+sub git_end_subhead_html {
        my $have_search = gitweb_check_feature('search');
        if (defined $project && $have_search) {
                print_search_form();
        }
+       print "</nav>\n";
 }
 
 sub git_footer_html {
        my $feed_class = 'rss_logo';
 
-       print "<div class=\"page_footer\">\n";
+       print "<footer class=\"page_footer\">\n";
        if (defined $project) {
                my $descr = git_get_project_description($project);
                if (defined $descr) {
@@ -4282,7 +4275,7 @@ sub git_footer_html {
                }
                $href_params{'-title'} ||= 'log';
 
-               foreach my $format (qw(RSS Atom)) {
+               foreach my $format (qw(Atom)) {
                        $href_params{'action'} = lc($format);
                        print $cgi->a({-href => href(%href_params),
                                      -title => "$href_params{'-title'} $format feed",
@@ -4297,7 +4290,7 @@ sub git_footer_html {
                                             project_filter => $project_filter),
                              -class => $feed_class}, "TXT") . "\n";
        }
-       print "</div>\n"; # class="page_footer"
+       print "</footer>\n"; # class="page_footer"
 
        if (defined $t0 && gitweb_check_feature('timed')) {
                print "<div id=\"generating_info\">\n";
@@ -4310,17 +4303,17 @@ sub git_footer_html {
                      $number_of_git_cmds.
                      '</span> git commands '.
                      " to generate.\n";
-               print "</div>\n"; # class="page_footer"
+               print "</div>\n";
        }
 
        if (defined $site_footer && -f $site_footer) {
                insert_file($site_footer);
        }
 
-       print qq!<script type="text/javascript" src="!.esc_url($javascript).qq!"></script>\n!;
        if (defined $action &&
            $action eq 'blame_incremental') {
-               print qq!<script type="text/javascript">\n!.
+               print qq!<script src="!.esc_url($javascript).qq!"></script>\n!;
+               print qq!<script>\n!.
                      qq!startBlame("!. esc_attr(href(action=>"blame_data", -replay=>1)) .qq!",\n!.
                      qq!           "!. esc_attr(href()) .qq!");\n!.
                      qq!</script>\n!;
@@ -4328,17 +4321,20 @@ sub git_footer_html {
                my ($jstimezone, $tz_cookie, $datetime_class) =
                        gitweb_get_feature('javascript-timezone');
 
-               print qq!<script type="text/javascript">\n!.
-                     qq!window.onload = function () {\n!;
-               if (gitweb_check_feature('javascript-actions')) {
-                       print qq!       fixLinks();\n!;
-               }
-               if ($jstimezone && $tz_cookie && $datetime_class) {
-                       print qq!       var tz_cookie = { name: '$tz_cookie', expires: 14, path: '/' };\n!. # in days
-                             qq!       onloadTZSetup('$jstimezone', tz_cookie, '$datetime_class');\n!;
+               if (gitweb_check_feature('javascript-actions') || ($jstimezone && $tz_cookie && $datetime_class)) {
+                       print qq!<script src="!.esc_url($javascript).qq!"></script>\n!;
+                       print qq!<script>\n!.
+                               qq!window.onload = function () {\n!;
+                       if (gitweb_check_feature('javascript-actions')) {
+                               print qq!       fixLinks();\n!;
+                       }
+                       if ($jstimezone && $tz_cookie && $datetime_class) {
+                               print qq!       var tz_cookie = { name: '$tz_cookie', expires: 14, path: '/' };\n!. # in days
+                                       qq!     onloadTZSetup('$jstimezone', tz_cookie, '$datetime_class');\n!;
+                       }
+                       print qq!};\n!.
+                               qq!</script>\n!;
                }
-               print qq!};\n!.
-                     qq!</script>\n!;
        }
 
        print "</body>\n" .
@@ -4372,6 +4368,7 @@ sub die_error {
                503 => '503 Service Unavailable',
        );
        git_header_html($http_responses{$status}, undef, %opts);
+       git_end_subhead_html();
        print <<EOF;
 <div class="page_body">
 <br /><br />
@@ -4394,7 +4391,6 @@ EOF
 
 sub git_print_page_nav {
        my ($current, $suppress, $head, $treehead, $treebase, $extra) = @_;
-       $extra = '' if !defined $extra; # pager or formats
 
        my @navs = qw(summary shortlog log commit commitdiff tree);
        if ($suppress) {
@@ -4438,8 +4434,9 @@ sub git_print_page_nav {
                 map { $_ eq $current ?
                       $_ : $cgi->a({-href => ($arg{$_}{_href} ? $arg{$_}{_href} : href(%{$arg{$_}}))}, "$_")
                 } @navs);
-       print "<br/>\n$extra<br/>\n" .
-             "</div>\n";
+       print "<br/>\n$extra" if defined $extra; # pager or formats
+       print "</div>\n";
+       git_end_subhead_html();
 }
 
 # returns a submenu for the navigation of the refs views (tags, heads,
@@ -4552,9 +4549,6 @@ sub format_timestamp_html {
        }
 
        my $localtime_format = '(%02d:%02d %s)';
-       if ($date->{'hour_local'} < 6) {
-               $localtime_format = '(<span class="atnight">%02d:%02d</span> %s)';
-       }
        $strtime .= ' ' .
                    sprintf($localtime_format,
                            $date->{'hour_local'}, $date->{'minute_local'}, $date->{'tz_local'});
@@ -4589,7 +4583,7 @@ sub git_print_authorship_rows {
        @people = ('author', 'committer') unless @people;
        foreach my $who (@people) {
                my %wd = parse_date($co->{"${who}_epoch"}, $co->{"${who}_tz"});
-               print "<tr><td>$who</td><td>" .
+               print "<tr><th>$who</th><td>" .
                      format_search_author($co->{"${who}_name"}, $who,
                                           esc_html($co->{"${who}_name"})) . " " .
                      format_search_author($co->{"${who}_email"}, $who,
@@ -4688,11 +4682,6 @@ sub git_print_log {
 
                print format_log_line_html($line) . "<br/>\n";
        }
-
-       if ($opts{'-final_empty_line'}) {
-               # end with single empty line
-               print "<br/>\n" unless $skip_blank_line;
-       }
 }
 
 # return link target (what link points to)
@@ -5934,13 +5923,12 @@ sub git_log_body {
                      $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") .
                      " | " .
                      $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") .
-                     "<br/>\n" .
                      "</div>\n";
                      git_print_authorship(\%co, -tag => 'span');
-                     print "<br/>\n</div>\n";
+                     print "</div>\n";
 
                print "<div class=\"log_body\">\n";
-               git_print_log($co{'comment'}, -final_empty_line=> 1);
+               git_print_log($co{'comment'});
                print "</div>\n";
        }
        if ($extra) {
@@ -6445,8 +6433,8 @@ sub git_search_files {
                        }
                        print "<div class=\"pre\">" .
                                $cgi->a({-href => $file_href.'#l'.$lno,
-                                       -class => "linenr"}, sprintf('%4i', $lno)) .
-                               ' ' .  $ltext . "</div>\n";
+                                       -class => "linenr"}, sprintf('%4i ', $lno)) .
+                               $ltext . "</div>\n";
                }
        }
        if ($lastfile) {
@@ -6540,6 +6528,7 @@ sub git_project_list {
        }
 
        git_header_html();
+       git_end_subhead_html();
        if (defined $home_text && -f $home_text) {
                print "<div class=\"index_include\">\n";
                insert_file($home_text);
@@ -6629,14 +6618,13 @@ sub git_summary {
        git_header_html();
        git_print_page_nav('summary','', $head);
 
-       print "<div class=\"title\">&nbsp;</div>\n";
        print "<table class=\"projects_list\">\n" .
-             "<tr id=\"metadata_desc\"><td>description</td><td>" . esc_html($descr) . "</td></tr>\n";
+             "<tr id=\"metadata_desc\"><th>description</th><td>" . esc_html($descr) . "</td></tr>\n";
         if ($owner and not $omit_owner) {
-               print  "<tr id=\"metadata_owner\"><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
+               print  "<tr id=\"metadata_owner\"><th>owner</th><td>" . esc_html($owner) . "</td></tr>\n";
         }
        if (defined $cd{'rfc2822'}) {
-               print "<tr id=\"metadata_lchange\"><td>last change</td>" .
+               print "<tr id=\"metadata_lchange\"><th>last change</th>" .
                      "<td>".format_timestamp_html(\%cd)."</td></tr>\n";
        }
 
@@ -6659,7 +6647,7 @@ sub git_summary {
                        # without ability to add tags, don't show if there are none
                        my $cloud = git_populate_project_tagcloud($ctags);
                        print "<tr id=\"metadata_ctags\">" .
-                             "<td>content tags</td>" .
+                             "<th>content tags</th>" .
                              "<td>".git_show_project_tagcloud($cloud, 48)."</td>" .
                              "</tr>\n";
                }
@@ -6730,7 +6718,7 @@ sub git_tag {
        print "<div class=\"title_text\">\n" .
              "<table class=\"object_header\">\n" .
              "<tr>\n" .
-             "<td>object</td>\n" .
+             "<th>object</th>\n" .
              "<td>" . $cgi->a({-class => "list", -href => href(action=>$tag{'type'}, hash=>$tag{'object'})},
                               $tag{'object'}) . "</td>\n" .
              "<td class=\"link\">" . $cgi->a({-href => href(action=>$tag{'type'}, hash=>$tag{'object'})},
@@ -7178,9 +7166,8 @@ sub git_blob {
                git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
                git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
        } else {
-               print "<div class=\"page_nav\">\n" .
-                     "<br/><br/></div>\n" .
-                     "<div class=\"title\">".esc_html($hash)."</div>\n";
+               git_end_subhead_html();
+               print "<div class=\"title\">".esc_html($hash)."</div>\n";
        }
        git_print_page_path($file_name, "blob", $hash_base);
        print "<div class=\"page_body\">\n";
@@ -7199,7 +7186,7 @@ sub git_blob {
                        chomp $line;
                        $nr++;
                        $line = untabify($line);
-                       printf qq!<div class="pre"><a id="l%i" href="%s#l%i" class="linenr">%4i</a> %s</div>\n!,
+                       printf qq!<div class="pre"><a id="l%i" href="%s#l%i" class="linenr">%4i </a>%s</div>\n!,
                               $nr, esc_attr(href(-replay => 1)), $nr, $nr,
                               $highlight ? sanitize($line) : esc_html($line, -nbsp=>1);
                }
@@ -7261,8 +7248,7 @@ sub git_tree {
                git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
        } else {
                undef $hash_base;
-               print "<div class=\"page_nav\">\n";
-               print "<br/><br/></div>\n";
+               git_end_subhead_html();
                print "<div class=\"title\">".esc_html($hash)."</div>\n";
        }
        if (defined $file_name) {
@@ -7609,9 +7595,9 @@ sub git_commit {
        print "<div class=\"title_text\">\n" .
              "<table class=\"object_header\">\n";
        git_print_authorship_rows(\%co);
-       print "<tr><td>commit</td><td class=\"sha1\">$co{'id'}</td></tr>\n";
+       print "<tr><th>commit</th><td class=\"sha1\">$co{'id'}</td></tr>\n";
        print "<tr>" .
-             "<td>tree</td>" .
+             "<th>tree</th>" .
              "<td class=\"sha1\">" .
              $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash),
                       class => "list"}, $co{'tree'}) .
@@ -7628,7 +7614,7 @@ sub git_commit {
 
        foreach my $par (@$parents) {
                print "<tr>" .
-                     "<td>parent</td>" .
+                     "<th>parent</th>" .
                      "<td class=\"sha1\">" .
                      $cgi->a({-href => href(action=>"commit", hash=>$par),
                               class => "list"}, $par) .
@@ -7786,7 +7772,8 @@ sub git_blobdiff {
                        git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
                        git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
                } else {
-                       print "<div class=\"page_nav\"><br/>$formats_nav<br/></div>\n";
+                       print "<div class=\"page_nav\"><br/>$formats_nav</div>\n";
+                       git_end_subhead_html();
                        print "<div class=\"title\">".esc_html("$hash vs $hash_parent")."</div>\n";
                }
                if (defined $file_name) {
@@ -8024,7 +8011,7 @@ sub git_commitdiff {
                print "<div class=\"page_body\">\n";
                if (@{$co{'comment'}} > 1) {
                        print "<div class=\"log\">\n";
-                       git_print_log($co{'comment'}, -final_empty_line=> 1, -remove_title => 1);
+                       git_print_log($co{'comment'}, -remove_title => 1);
                        print "</div>\n"; # class="log"
                }
 
@@ -8202,15 +8189,14 @@ sub git_shortlog {
 }
 
 ## ......................................................................
-## feeds (RSS, Atom; OPML)
+## feeds (Atom; OPML)
 
 sub git_feed {
        my $format = shift || 'atom';
        my $have_blame = gitweb_check_feature('blame');
 
        # Atom: http://www.atomenabled.org/developers/syndication/
-       # RSS:  http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
-       if ($format ne 'rss' && $format ne 'atom') {
+       if ($format ne 'atom') {
                die_error(400, "Unknown web feed format");
        }
 
@@ -8262,9 +8248,7 @@ sub git_feed {
        if (defined $descr) {
                $descr = esc_html($descr);
        } else {
-               $descr = "$project " .
-                        ($format eq 'rss' ? 'RSS' : 'Atom') .
-                        " feed";
+               $descr = "$project Atom feed";
        }
        my $owner = git_get_project_owner($project);
        $owner = esc_html($owner);
@@ -8280,60 +8264,32 @@ sub git_feed {
        }
        $alt_url = esc_attr($alt_url);
        print qq!<?xml version="1.0" encoding="utf-8"?>\n!;
-       if ($format eq 'rss') {
-               print <<XML;
-<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
-<channel>
-XML
-               print "<title>$title</title>\n" .
-                     "<link>$alt_url</link>\n" .
-                     "<description>$descr</description>\n" .
-                     "<language>en</language>\n" .
-                     # project owner is responsible for 'editorial' content
-                     "<managingEditor>$owner</managingEditor>\n";
-               if (defined $logo || defined $favicon) {
-                       # prefer the logo to the favicon, since RSS
-                       # doesn't allow both
-                       my $img = esc_url($logo || $favicon);
-                       print "<image>\n" .
-                             "<url>$img</url>\n" .
-                             "<title>$title</title>\n" .
-                             "<link>$alt_url</link>\n" .
-                             "</image>\n";
-               }
-               if (%latest_date) {
-                       print "<pubDate>$latest_date{'rfc2822'}</pubDate>\n";
-                       print "<lastBuildDate>$latest_date{'rfc2822'}</lastBuildDate>\n";
-               }
-               print "<generator>gitweb v.$version/$git_version</generator>\n";
-       } elsif ($format eq 'atom') {
-               print <<XML;
+       print <<XML;
 <feed xmlns="http://www.w3.org/2005/Atom">
 XML
-               print "<title>$title</title>\n" .
-                     "<subtitle>$descr</subtitle>\n" .
-                     '<link rel="alternate" type="text/html" href="' .
-                     $alt_url . '" />' . "\n" .
-                     '<link rel="self" type="' . $content_type . '" href="' .
-                     $cgi->self_url() . '" />' . "\n" .
-                     "<id>" . esc_url(href(-full=>1)) . "</id>\n" .
-                     # use project owner for feed author
-                     "<author><name>$owner</name></author>\n";
-               if (defined $favicon) {
-                       print "<icon>" . esc_url($favicon) . "</icon>\n";
-               }
-               if (defined $logo) {
-                       # not twice as wide as tall: 72 x 27 pixels
-                       print "<logo>" . esc_url($logo) . "</logo>\n";
-               }
-               if (! %latest_date) {
-                       # dummy date to keep the feed valid until commits trickle in:
-                       print "<updated>1970-01-01T00:00:00Z</updated>\n";
-               } else {
-                       print "<updated>$latest_date{'iso-8601'}</updated>\n";
-               }
-               print "<generator version='$version/$git_version'>gitweb</generator>\n";
+       print "<title>$title</title>\n" .
+             "<subtitle>$descr</subtitle>\n" .
+             '<link rel="alternate" type="text/html" href="' .
+             $alt_url . '" />' . "\n" .
+             '<link rel="self" type="' . $content_type . '" href="' .
+             $cgi->self_url() . '" />' . "\n" .
+             "<id>" . esc_url(href(-full=>1)) . "</id>\n" .
+             # use project owner for feed author
+             "<author><name>$owner</name></author>\n";
+       if (defined $favicon) {
+               print "<icon>" . esc_url($favicon) . "</icon>\n";
        }
+       if (defined $logo) {
+               # not twice as wide as tall: 72 x 27 pixels
+               print "<logo>" . esc_url($logo) . "</logo>\n";
+       }
+       if (! %latest_date) {
+               # dummy date to keep the feed valid until commits trickle in:
+               print "<updated>1970-01-01T00:00:00Z</updated>\n";
+       } else {
+               print "<updated>$latest_date{'iso-8601'}</updated>\n";
+       }
+       print "<generator version='$version/$git_version'>gitweb</generator>\n";
 
        # contents
        for (my $i = 0; $i <= $#commitlist; $i++) {
@@ -8356,39 +8312,27 @@ XML
 
                # print element (entry, item)
                my $co_url = href(-full=>1, action=>"commitdiff", hash=>$commit);
-               if ($format eq 'rss') {
-                       print "<item>\n" .
-                             "<title>" . esc_html($co{'title'}) . "</title>\n" .
-                             "<author>" . esc_html($co{'author'}) . "</author>\n" .
-                             "<pubDate>$cd{'rfc2822'}</pubDate>\n" .
-                             "<guid isPermaLink=\"true\">$co_url</guid>\n" .
-                             "<link>" . esc_html($co_url) . "</link>\n" .
-                             "<description>" . esc_html($co{'title'}) . "</description>\n" .
-                             "<content:encoded>" .
-                             "<![CDATA[\n";
-               } elsif ($format eq 'atom') {
-                       print "<entry>\n" .
-                             "<title type=\"html\">" . esc_html($co{'title'}) . "</title>\n" .
-                             "<updated>$cd{'iso-8601'}</updated>\n" .
-                             "<author>\n" .
-                             "  <name>" . esc_html($co{'author_name'}) . "</name>\n";
-                       if ($co{'author_email'}) {
-                               print "  <email>" . esc_html($co{'author_email'}) . "</email>\n";
-                       }
-                       print "</author>\n" .
-                             # use committer for contributor
-                             "<contributor>\n" .
-                             "  <name>" . esc_html($co{'committer_name'}) . "</name>\n";
-                       if ($co{'committer_email'}) {
-                               print "  <email>" . esc_html($co{'committer_email'}) . "</email>\n";
-                       }
-                       print "</contributor>\n" .
-                             "<published>$cd{'iso-8601'}</published>\n" .
-                             "<link rel=\"alternate\" type=\"text/html\" href=\"" . esc_attr($co_url) . "\" />\n" .
-                             "<id>" . esc_html($co_url) . "</id>\n" .
-                             "<content type=\"xhtml\" xml:base=\"" . esc_url($my_url) . "\">\n" .
-                             "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n";
-               }
+               print "<entry>\n" .
+                     "<title type=\"html\">" . esc_html($co{'title'}) . "</title>\n" .
+                     "<updated>$cd{'iso-8601'}</updated>\n" .
+                     "<author>\n" .
+                     "  <name>" . esc_html($co{'author_name'}) . "</name>\n";
+               if ($co{'author_email'}) {
+                       print "  <email>" . esc_html($co{'author_email'}) . "</email>\n";
+               }
+               print "</author>\n" .
+                     # use committer for contributor
+                     "<contributor>\n" .
+                     "  <name>" . esc_html($co{'committer_name'}) . "</name>\n";
+               if ($co{'committer_email'}) {
+                       print "  <email>" . esc_html($co{'committer_email'}) . "</email>\n";
+               }
+               print "</contributor>\n" .
+                     "<published>$cd{'iso-8601'}</published>\n" .
+                     "<link rel=\"alternate\" type=\"text/html\" href=\"" . esc_attr($co_url) . "\" />\n" .
+                     "<id>" . esc_html($co_url) . "</id>\n" .
+                     "<content type=\"xhtml\" xml:base=\"" . esc_url($my_url) . "\">\n" .
+                     "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n";
                my $comment = $co{'comment'};
                print "<pre>\n";
                foreach my $line (@$comment) {
@@ -8424,27 +8368,13 @@ XML
                        print "] ".
                              "$file</li>\n";
                }
-               if ($format eq 'rss') {
-                       print "</ul>]]>\n" .
-                             "</content:encoded>\n" .
-                             "</item>\n";
-               } elsif ($format eq 'atom') {
-                       print "</ul>\n</div>\n" .
-                             "</content>\n" .
-                             "</entry>\n";
-               }
+               print "</ul>\n</div>\n" .
+                     "</content>\n" .
+                     "</entry>\n";
        }
 
        # end of feed
-       if ($format eq 'rss') {
-               print "</channel>\n</rss>\n";
-       } elsif ($format eq 'atom') {
-               print "</feed>\n";
-       }
-}
-
-sub git_rss {
-       git_feed('rss');
+       print "</feed>\n";
 }
 
 sub git_atom {
@@ -8476,7 +8406,7 @@ sub git_opml {
   <title>$title OPML Export$filter</title>
 </head>
 <body>
-<outline text="git RSS feeds">
+<outline text="git Atom feeds">
 XML
 
        foreach my $pr (@list) {
@@ -8492,9 +8422,9 @@ XML
                }
 
                my $path = esc_html(chop_str($proj{'path'}, 25, 5));
-               my $rss  = esc_attr(href('project' => $proj{'path'}, 'action' => 'rss', -full => 1));
+               my $atom  = esc_attr(href('project' => $proj{'path'}, 'action' => 'atom', -full => 1));
                my $html = esc_attr(href('project' => $proj{'path'}, 'action' => 'summary', -full => 1));
-               print "<outline type=\"rss\" text=\"$path\" title=\"$path\" xmlUrl=\"$rss\" htmlUrl=\"$html\"/>\n";
+               print "<outline type=\"rss\" text=\"$path\" title=\"$path\" xmlUrl=\"$atom\" htmlUrl=\"$html\"/>\n";
        }
        print <<XML;
 </outline>