commit - d19d9fcec89a7d18ca8325b70f5edde7b4e6369a
commit + 1abb18e1777172a9f4149a0f50c4cecfd024f02c
blob - 89fbdaf8d8a786bf4d6905228fbfa6fcc47cf03d
blob + dd6dbe5f5b29eee48c7bcc972741e3a471d95c6b
--- gotwebd/fcgi.c
+++ gotwebd/fcgi.c
memcpy(c->server_name, val, val_len);
c->server_name[val_len] = '\0';
}
+
+ if (name_len == 5 &&
+ strncmp(buf, "HTTPS", 5) == 0)
+ c->https = 1;
buf += name_len + val_len;
n -= name_len - val_len;
blob - 50fee3056b1e5f7a9bc78f255201d8b1539a2995
blob + 89718fdd602637e74ca5a949af1e7cfda57b723d
--- gotwebd/got_operations.c
+++ gotwebd/got_operations.c
repo_dir->name) == -1)
return got_error_from_errno("asprintf");
- if (qs->commit == NULL && qs->action == TAGS) {
+ if (qs->commit == NULL && (qs->action == TAGS || qs->action == RSS)) {
error = got_ref_open(&ref, repo, qs->headref, 0);
if (error)
goto err;
blob - 28042467bba28194c9543f1b05ca9cfc5cfd644e
blob + 6030878cfe25783394593d7d14af1bd6e577f4be
--- gotwebd/gotweb.c
+++ gotwebd/gotweb.c
#include "proc.h"
#include "gotwebd.h"
+#include "tmpl.h"
static const struct querystring_keys querystring_keys[] = {
{ "action", ACTION },
{ "tag", TAG },
{ "tags", TAGS },
{ "tree", TREE },
+ { "rss", RSS },
};
static const struct got_error *gotweb_init_querystring(struct querystring **);
if (error)
goto done;
error = got_output_file_blob(c);
+ if (error) {
+ log_warnx("%s: %s", __func__, error->msg);
+ goto err;
+ }
+ goto done;
+ }
+
+ if (qs->action == RSS) {
+ error = gotweb_render_content_type(c,
+ "application/rss+xml;charset=utf-8");
+ if (error) {
+ log_warnx("%s: %s", __func__, error->msg);
+ goto err;
+ }
+
+ error = got_get_repo_tags(c, D_MAXSLCOMMDISP);
if (error) {
log_warnx("%s: %s", __func__, error->msg);
goto err;
}
+ if (gotweb_render_rss(c->tp) == -1)
+ goto err;
goto done;
}
return "tags";
case TREE:
return "tree";
+ case RSS:
+ return "rss";
default:
return NULL;
}
}
int
+gotweb_render_absolute_url(struct request *c, struct gotweb_url *url)
+{
+ struct template *tp = c->tp;
+ const char *proto = c->https ? "https" : "http";
+
+ if (fcgi_puts(tp, proto) == -1 ||
+ fcgi_puts(tp, "://") == -1 ||
+ tp_htmlescape(tp, c->server_name) == -1 ||
+ tp_htmlescape(tp, c->document_uri) == -1)
+ return -1;
+
+ return gotweb_render_url(c, url);
+}
+
+int
gotweb_link(struct request *c, struct gotweb_url *url, const char *fmt, ...)
{
va_list ap;
const char *hours = "hours ago", *minutes = "minutes ago";
const char *seconds = "seconds ago", *now = "right now";
char *s;
- char datebuf[29];
+ char datebuf[64];
+ size_t r;
*repo_age = NULL;
if (asprintf(repo_age, "%s UTC", datebuf) == -1)
return got_error_from_errno("asprintf");
break;
+ case TM_RFC822:
+ if (gmtime_r(&committer_time, &tm) == NULL)
+ return got_error_from_errno("gmtime_r");
+
+ r = strftime(datebuf, sizeof(datebuf),
+ "%a, %d %b %Y %H:%M:%S GMT", &tm);
+ if (r == 0)
+ return got_error(GOT_ERR_NO_SPACE);
+
+ *repo_age = strdup(datebuf);
+ if (*repo_age == NULL)
+ return got_error_from_errno("asprintf");
+ break;
}
return NULL;
}
blob - 38161394053fe7a7aca451c50b25e97bb1f80898
blob + c54fe3683dc1d915d6d3fa880753b93adc5252e5
--- gotwebd/gotwebd.h
+++ gotwebd/gotwebd.h
char http_host[GOTWEBD_MAXTEXT];
char document_uri[MAX_DOCUMENT_URI];
char server_name[MAX_SERVER_NAME];
+ int https;
uint8_t request_started;
};
TAG,
TAGS,
TREE,
+ RSS,
ACTIONS__MAX,
};
enum gotweb_ref_tm {
TM_DIFF,
TM_LONG,
+ TM_RFC822,
};
extern struct gotwebd *gotwebd_env;
const struct got_error *gotweb_escape_html(char **, const char *);
const char *gotweb_action_name(int);
int gotweb_render_url(struct request *, struct gotweb_url *);
+int gotweb_render_absolute_url(struct request *, struct gotweb_url *);
int gotweb_link(struct request *, struct gotweb_url *, const char *, ...)
__attribute__((__format__(printf, 3, 4)))
__attribute__((__nonnull__(3)));
int gotweb_render_briefs(struct template *);
int gotweb_render_navs(struct template *);
int gotweb_render_commits(struct template *);
+int gotweb_render_rss(struct template *);
/* parse.y */
int parse_config(const char *, struct gotwebd *);
blob - a822e44c28412ddbf85071a448bc1fca3266812d
blob + d694fb2afcffcc2b7f3319fcff1c1f49c6545ed5
--- gotwebd/pages.tmpl
+++ gotwebd/pages.tmpl
#include <sys/types.h>
#include <sys/queue.h>
+#include <ctype.h>
#include <event.h>
#include <stdint.h>
#include <stdlib.h>
#include "gotwebd.h"
#include "tmpl.h"
+static inline int rss_tag_item(struct template *, struct repo_tag *);
+static inline int rss_author(struct template *, char *);
+
static int
gotweb_render_age(struct template *tp, time_t time, int ref_tm)
{
.index_page = -1,
.page = -1,
.path = repo_dir->name,
+ }, rss = {
+ .action = RSS,
+ .index_page = -1,
+ .page = -1,
+ .path = repo_dir->name,
};
!}
<div class="index_wrapper">
<a href="{{ render gotweb_render_url(tp->tp_arg, &tags) }}">tags</a>
{{ " | " }}
<a href="{{ render gotweb_render_url(tp->tp_arg, &tree) }}">tree</a>
+ {{ " | " }}
+ <a href="{{ render gotweb_render_url(tp->tp_arg, &rss) }}">rss</a>
</div>
<div class="dotted_line"></div>
</div>
{{ render gotweb_render_navs(tp) }}
{{ end }}
</div>
+{{ end }}
+
+{{ define gotweb_render_rss(struct template *tp) }}
+{!
+ struct request *c = tp->tp_arg;
+ struct server *srv = c->srv;
+ struct transport *t = c->t;
+ struct repo_dir *repo_dir = t->repo_dir;
+ struct repo_tag *rt;
+ struct gotweb_url summary = {
+ .action = SUMMARY,
+ .index_page = -1,
+ .page = -1,
+ .path = repo_dir->name,
+ };
+!}
+<?xml version="1.0" encoding="UTF-8"?>
+<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
+ <channel>
+ <title>Tags of {{ repo_dir->name }}</title>
+ <link>
+ <![CDATA[
+ {{ render gotweb_render_absolute_url(c, &summary) }}
+ ]]>
+ </link>
+ {{ if srv->show_repo_description }}
+ <description>{{ repo_dir->description }}</description>
+ {{ end }}
+ {{ tailq-foreach rt &t->repo_tags entry }}
+ {{ render rss_tag_item(tp, rt) }}
+ {{ end }}
+ </channel>
+</rss>
+{{ end }}
+
+{{ define rss_tag_item(struct template *tp, struct repo_tag *rt) }}
+{!
+ struct request *c = tp->tp_arg;
+ struct transport *t = c->t;
+ struct repo_dir *repo_dir = t->repo_dir;
+ char *tag_name = rt->tag_name;
+ struct gotweb_url tag = {
+ .action = TAG,
+ .index_page = -1,
+ .page = -1,
+ .path = repo_dir->name,
+ .commit = rt->commit_id,
+ };
+
+ if (strncmp(tag_name, "refs/tags/", 10) == 0)
+ tag_name += 10;
+!}
+<item>
+ <title>{{ repo_dir->name }} {{" "}} {{ tag_name }}</title>
+ <link>
+ <![CDATA[
+ {{ render gotweb_render_absolute_url(c, &tag) }}
+ ]]>
+ </link>
+ <description>
+ <![CDATA[<pre>{{ rt->tag_commit }}</pre>]]>
+ </description>
+ {{ render rss_author(tp, rt->tagger) }}
+ <guid isPermaLink="false">{{ rt->commit_id }}</guid>
+ <pubDate>
+ {{ render gotweb_render_age(tp, rt->tagger_time, TM_RFC822) }}
+ </pubDate>
+</item>
{{ end }}
+
+{{ define rss_author(struct template *tp, char *author) }}
+{!
+ char *t, *mail;
+
+ /* what to do if the author name contains a paren? */
+ if (strchr(author, '(') != NULL || strchr(author, ')') != NULL)
+ return 0;
+
+ t = strchr(author, '<');
+ if (t == NULL)
+ return 0;
+ *t = '\0';
+ mail = t+1;
+
+ while (isspace((unsigned char)*--t))
+ *t = '\0';
+
+ t = strchr(mail, '>');
+ if (t == NULL)
+ return 0;
+ *t = '\0';
+!}
+<author>
+ {{ mail }} {{" "}} ({{ author }})
+</author>
+{{ end }}