List for cgit developers and users
 help / color / mirror / Atom feed
* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
@ 2013-11-27 15:17 mail
  2013-11-27 16:17 ` list
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: mail @ 2013-11-27 15:17 UTC (permalink / raw)


---
 cgit.c       |  3 +++
 cgit.h       |  5 +++++
 cgitrc.5.txt |  4 ++++
 parsing.c    | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 shared.c     |  6 ++++++
 ui-commit.c  | 10 ++++++++++
 ui-log.c     |  5 +++++
 ui-refs.c    | 10 ++++++++++
 ui-tag.c     |  5 +++++
 9 files changed, 95 insertions(+)

diff --git a/cgit.c b/cgit.c
index 861352a..fe82580 100644
--- a/cgit.c
+++ b/cgit.c
@@ -183,6 +183,8 @@ static void config_cb(const char *name, const char *value)
 		ctx.cfg.enable_index_owner = atoi(value);
 	else if (!strcmp(name, "enable-commit-graph"))
 		ctx.cfg.enable_commit_graph = atoi(value);
+	else if (!strcmp(name, "enable-gravatar"))
+		ctx.cfg.enable_gravatar = atoi(value);
 	else if (!strcmp(name, "enable-log-filecount"))
 		ctx.cfg.enable_log_filecount = atoi(value);
 	else if (!strcmp(name, "enable-log-linecount"))
@@ -368,6 +370,7 @@ static void prepare_context(struct cgit_context *ctx)
 	ctx->cfg.logo = "/cgit.png";
 	ctx->cfg.favicon = "/favicon.ico";
 	ctx->cfg.local_time = 0;
+	ctx->cfg.enable_gravatar = 0;
 	ctx->cfg.enable_http_clone = 1;
 	ctx->cfg.enable_index_owner = 1;
 	ctx->cfg.enable_tree_linenumbers = 1;
diff --git a/cgit.h b/cgit.h
index a474d77..ab22e67 100644
--- a/cgit.h
+++ b/cgit.h
@@ -107,9 +107,11 @@ struct commitinfo {
 	struct commit *commit;
 	char *author;
 	char *author_email;
+	char *author_gravatar;
 	unsigned long author_date;
 	char *committer;
 	char *committer_email;
+	char *committer_gravatar;
 	unsigned long committer_date;
 	char *subject;
 	char *msg;
@@ -119,6 +121,7 @@ struct commitinfo {
 struct taginfo {
 	char *tagger;
 	char *tagger_email;
+	char *tagger_gravatar;
 	unsigned long tagger_date;
 	char *msg;
 };
@@ -208,6 +211,7 @@ struct cgit_config {
 	int enable_index_links;
 	int enable_index_owner;
 	int enable_commit_graph;
+	int enable_gravatar;
 	int enable_log_filecount;
 	int enable_log_linecount;
 	int enable_remote_branches;
@@ -337,6 +341,7 @@ extern char *fmtalloc(const char *format,...);
 
 extern struct commitinfo *cgit_parse_commit(struct commit *commit);
 extern struct taginfo *cgit_parse_tag(struct tag *tag);
+char *cgit_get_gravatar(const char *email);
 extern void cgit_parse_url(const char *url);
 
 extern const char *cgit_repobasename(const char *reponame);
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 633cb00..b6017c2 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -180,6 +180,10 @@ enable-git-config::
 	to the corresponding "repo." key in cgit. Default value: "0". See also:
 	scan-path, section-from-path.
 
+enable-gravatar::
+	Flag which, when set to "1", will enable cgit to show gravatar icon
+	for author, committer and tagger email address. Default value: "0".
+
 favicon::
 	Url used as link to a shortcut icon for cgit. It is suggested to use
 	the value "/favicon.ico" since certain browsers will ignore other
diff --git a/parsing.c b/parsing.c
index 658621d..a8005f6 100644
--- a/parsing.c
+++ b/parsing.c
@@ -8,6 +8,9 @@
 
 #include "cgit.h"
 
+/* we need md5 hashing algorithm to calculate Gravatar URL */
+#include <openssl/md5.h>
+
 /*
  * url syntax: [repo ['/' cmd [ '/' path]]]
  *   repo: any valid repo url, may contain '/'
@@ -133,8 +136,10 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
 	ret->commit = commit;
 	ret->author = NULL;
 	ret->author_email = NULL;
+	ret->author_gravatar = NULL;
 	ret->committer = NULL;
 	ret->committer_email = NULL;
+	ret->committer_gravatar = NULL;
 	ret->subject = NULL;
 	ret->msg = NULL;
 	ret->msg_encoding = NULL;
@@ -155,11 +160,17 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
 			&ret->author_date);
 	}
 
+	if (ctx.cfg.enable_gravatar && ret->author_email != NULL) 
+		ret->author_gravatar = cgit_get_gravatar(ret->author_email);
+
 	if (p && !strncmp(p, "committer ", 9)) {
 		p = parse_user(p + 9, &ret->committer, &ret->committer_email,
 			&ret->committer_date);
 	}
 
+	if (ctx.cfg.enable_gravatar && ret->committer_email != NULL) 
+		ret->committer_gravatar = cgit_get_gravatar(ret->committer_email);
+
 	if (p && !strncmp(p, "encoding ", 9)) {
 		p += 9;
 		t = strchr(p, '\n');
@@ -230,6 +241,7 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
 	ret = xmalloc(sizeof(*ret));
 	ret->tagger = NULL;
 	ret->tagger_email = NULL;
+	ret->tagger_gravatar = NULL;
 	ret->tagger_date = 0;
 	ret->msg = NULL;
 
@@ -249,6 +261,9 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
 		}
 	}
 
+	if (ctx.cfg.enable_gravatar && ret->tagger_email != NULL)
+		ret->tagger_gravatar = cgit_get_gravatar(ret->tagger_email);
+
 	// skip empty lines between headers and message
 	while (p && *p == '\n')
 		p++;
@@ -258,3 +273,35 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
 	free(data);
 	return ret;
 }
+
+char * cgit_get_gravatar(const char * email) {
+    	int n, length;
+	MD5_CTX c;
+	unsigned char digest[16];
+	char hex[33];
+	char * gravatar = malloc(67);
+
+	/* skip brackets! */
+	email++;
+	length = strlen(email) - 1;
+
+	MD5_Init(&c);
+
+	while (length > 0) {
+		if (length > 512)
+			MD5_Update(&c, email, 512);
+		else
+			MD5_Update(&c, email, length);
+		length -= 512;
+		email += 512;
+	}
+
+	MD5_Final(digest, &c);
+
+	for (n = 0; n < 16; ++n)
+		snprintf(&(hex[n*2]), 16*2, "%02x", (unsigned int)digest[n]);
+
+	sprintf(gravatar, "http://www.gravatar.com/avatar/%s?s=", hex);
+
+	return gravatar;
+}
diff --git a/shared.c b/shared.c
index 919a99e..8ae8c3b 100644
--- a/shared.c
+++ b/shared.c
@@ -93,8 +93,12 @@ void *cgit_free_commitinfo(struct commitinfo *info)
 {
 	free(info->author);
 	free(info->author_email);
+	if (info->author_gravatar)
+		free(info->author_gravatar);
 	free(info->committer);
 	free(info->committer_email);
+	if (info->committer_gravatar)
+		free(info->committer_gravatar);
 	free(info->subject);
 	free(info->msg);
 	free(info->msg_encoding);
@@ -204,6 +208,8 @@ static void cgit_free_taginfo(struct taginfo *tag)
 		free(tag->tagger);
 	if (tag->tagger_email)
 		free(tag->tagger_email);
+	if (tag->tagger_gravatar)
+		free(tag->tagger_gravatar);
 	if (tag->msg)
 		free(tag->msg);
 	free(tag);
diff --git a/ui-commit.c b/ui-commit.c
index ef85a49..eed3ab6 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -44,6 +44,11 @@ void cgit_print_commit(char *hex, const char *prefix)
 	cgit_print_diff_ctrls();
 	html("<table summary='commit info' class='commit-info'>\n");
 	html("<tr><th>author</th><td>");
+	if (ctx.cfg.enable_gravatar && info->author_gravatar) {
+		html("<img src='");
+		html(info->author_gravatar);
+		html("' width=16 height=16 alt='Gravatar' \\>");
+	}
 	html_txt(info->author);
 	if (!ctx.cfg.noplainemail) {
 		html(" ");
@@ -53,6 +58,11 @@ void cgit_print_commit(char *hex, const char *prefix)
 	cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time);
 	html("</td></tr>\n");
 	html("<tr><th>committer</th><td>");
+	if (ctx.cfg.enable_gravatar && info->committer_gravatar) {
+		html("<img src='");
+		html(info->committer_gravatar);
+		html("' width=16 height=16 alt='Gravatar' \\>");
+	}
 	html_txt(info->committer);
 	if (!ctx.cfg.noplainemail) {
 		html(" ");
diff --git a/ui-log.c b/ui-log.c
index 6f1249b..9974139 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -168,6 +168,11 @@ static void print_commit(struct commit *commit, struct rev_info *revs)
 			 sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);
 	show_commit_decorations(commit);
 	html("</td><td>");
+	if (ctx.cfg.enable_gravatar && info->author_gravatar) {
+		html("<img src='");
+		html(info->author_gravatar);
+		html("' width=16 height=16 alt='Gravatar' \\>");
+	}
 	html_txt(info->author);
 
 	if (revs->graph) {
diff --git a/ui-refs.c b/ui-refs.c
index 0ae0612..8714b2d 100644
--- a/ui-refs.c
+++ b/ui-refs.c
@@ -77,6 +77,11 @@ static int print_branch(struct refinfo *ref)
 	if (ref->object->type == OBJ_COMMIT) {
 		cgit_commit_link(info->subject, NULL, NULL, name, NULL, NULL, 0);
 		html("</td><td>");
+		if (ctx.cfg.enable_gravatar && info->author_gravatar) {
+			html("<img src='");
+			html(info->author_gravatar);
+			html("' width=16 height=16 alt='Gravatar' \\>");
+		}
 		html_txt(info->author);
 		html("</td><td colspan='2'>");
 		cgit_print_age(info->commit->date, -1, NULL);
@@ -154,6 +159,11 @@ static int print_tag(struct refinfo *ref)
 		cgit_object_link(obj);
 	html("</td><td>");
 	if (info) {
+		if (ctx.cfg.enable_gravatar && info->tagger_gravatar) {
+			html("<img src='");
+			html(info->tagger_gravatar);
+			html("' width=16 height=16 alt='Gravatar' \\>");
+		}
 		if (info->tagger)
 			html(info->tagger);
 	} else if (ref->object->type == OBJ_COMMIT) {
diff --git a/ui-tag.c b/ui-tag.c
index aea7958..ad402da 100644
--- a/ui-tag.c
+++ b/ui-tag.c
@@ -77,6 +77,11 @@ void cgit_print_tag(char *revname)
 		}
 		if (info->tagger) {
 			html("<tr><td>tagged by</td><td>");
+			if (ctx.cfg.enable_gravatar && info->tagger_gravatar) {
+				html("<img src='");
+				html(info->tagger_gravatar);
+				html("' width=16 height=16 alt='Gravatar' \\>");
+			}
 			html_txt(info->tagger);
 			if (info->tagger_email && !ctx.cfg.noplainemail) {
 				html(" ");
-- 
1.8.4.2



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2013-11-27 15:17 [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger mail
@ 2013-11-27 16:17 ` list
  2013-11-27 16:37 ` john
  2013-11-27 16:46 ` lekensteyn
  2 siblings, 0 replies; 17+ messages in thread
From: list @ 2013-11-27 16:17 UTC (permalink / raw)


Christian Hesse <mail at eworm.de> on Wed, 2013/11/27 16:17:
> ---
>  cgit.c       |  3 +++
>  cgit.h       |  5 +++++
>  cgitrc.5.txt |  4 ++++
>  parsing.c    | 47 +++++++++++++++++++++++++++++++++++++++++++++++
>  shared.c     |  6 ++++++
>  ui-commit.c  | 10 ++++++++++
>  ui-log.c     |  5 +++++
>  ui-refs.c    | 10 ++++++++++
>  ui-tag.c     |  5 +++++
>  9 files changed, 95 insertions(+)

This has some minor bugs, for example mail addresses have to be converted to
lower case before hashing. And probably it makes sense to fetch smaller
images than the default 80 pixel...

However I would like to get some comments, I will update things when this
(is going to be) merged upstream.

Thanks!
-- 
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Chris           get my mail address:    */=0;b=c[a++];)
putchar(b-1/(/*               gcc -o sig sig.c && ./sig    */b/42*2-3)*42);}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://lists.zx2c4.com/pipermail/cgit/attachments/20131127/88725a6e/attachment.asc>


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2013-11-27 15:17 [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger mail
  2013-11-27 16:17 ` list
@ 2013-11-27 16:37 ` john
  2013-11-27 20:51   ` list
  2013-11-27 16:46 ` lekensteyn
  2 siblings, 1 reply; 17+ messages in thread
From: john @ 2013-11-27 16:37 UTC (permalink / raw)


On Wed, Nov 27, 2013 at 04:17:17PM +0100, Christian Hesse wrote:
> diff --git a/parsing.c b/parsing.c
> index 658621d..a8005f6 100644
> --- a/parsing.c
> +++ b/parsing.c
> @@ -8,6 +8,9 @@
>  
>  #include "cgit.h"
>  
> +/* we need md5 hashing algorithm to calculate Gravatar URL */
> +#include <openssl/md5.h>

We don't currently depend on OpenSSL, except via Git which can use
alternative SHA-1 implementations.

At the very least Debian will not distribute GPL'd packages
linked against OpenSSL [1].

[1] http://lintian.debian.org/tags/possible-gpl-code-linked-with-openssl.html

> +char * cgit_get_gravatar(const char * email) {
> +    	int n, length;
> +	MD5_CTX c;
> +	unsigned char digest[16];
> +	char hex[33];
> +	char * gravatar = malloc(67);
> +
> +	/* skip brackets! */
> +	email++;
> +	length = strlen(email) - 1;
> +
> +	MD5_Init(&c);
> +
> +	while (length > 0) {
> +		if (length > 512)
> +			MD5_Update(&c, email, 512);
> +		else
> +			MD5_Update(&c, email, length);
> +		length -= 512;
> +		email += 512;
> +	}
> +
> +	MD5_Final(digest, &c);

Would it be possible to extract everything from MD5_Init to MD5_Final to
a function that just computes the MD5 of a string?  That should make it
easier to add alternative implementations.

> +	for (n = 0; n < 16; ++n)
> +		snprintf(&(hex[n*2]), 16*2, "%02x", (unsigned int)digest[n]);
> +
> +	sprintf(gravatar, "http://www.gravatar.com/avatar/%s?s=", hex);
> +
> +	return gravatar;
> +}


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2013-11-27 15:17 [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger mail
  2013-11-27 16:17 ` list
  2013-11-27 16:37 ` john
@ 2013-11-27 16:46 ` lekensteyn
  2013-11-27 20:59   ` list
  2 siblings, 1 reply; 17+ messages in thread
From: lekensteyn @ 2013-11-27 16:46 UTC (permalink / raw)


Hi,

See below for review.

On Wednesday 27 November 2013 16:17:17 Christian Hesse wrote:
> ---
>  cgit.c       |  3 +++
>  cgit.h       |  5 +++++
>  cgitrc.5.txt |  4 ++++
>  parsing.c    | 47 +++++++++++++++++++++++++++++++++++++++++++++++
>  shared.c     |  6 ++++++
>  ui-commit.c  | 10 ++++++++++
>  ui-log.c     |  5 +++++
>  ui-refs.c    | 10 ++++++++++
>  ui-tag.c     |  5 +++++
>  9 files changed, 95 insertions(+)

[..]

> @@ -258,3 +273,35 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
>  	free(data);
>  	return ret;
>  }
> +
> +char * cgit_get_gravatar(const char * email) {
> +    	int n, length;
> +	MD5_CTX c;
> +	unsigned char digest[16];
> +	char hex[33];
> +	char * gravatar = malloc(67);
> +
> +	/* skip brackets! */
> +	email++;
> +	length = strlen(email) - 1;

> +
> +	MD5_Init(&c);
> +
> +	while (length > 0) {
> +		if (length > 512)
> +			MD5_Update(&c, email, 512);
> +		else
> +			MD5_Update(&c, email, length);
Seems like an error from Stackoverflow[1]? According to the manual page, the 
length is in bytes, not bits.

 [1]: http://stackoverflow.com/a/8389763/427545

> +		length -= 512;
> +		email += 512;
> +	}
> +
> +	MD5_Final(digest, &c);

Since you know the full string onbeforehand, you should also be able to use 
MD5() directly. Something like (openssl):

    MD5(email, length, digest);

As you mentioned, email addresses should be converted to lower case first 
according to http://en.gravatar.com/site/implement/hash/. The below str_to_hex 
was written before I knew that.

> +
> +	for (n = 0; n < 16; ++n)
> +		snprintf(&(hex[n*2]), 16*2, "%02x", (unsigned int)digest[n]);

This 16*2 is bogus, if you are at the 30th position, you only have two bytes 
left. What about adding a new md5_to_hex() function, similar to sha1_to_hex() 
in git? Here is a generic approach:

/* gets a string representing the binary data. dst_str must have a
 * size of at least src_len * 2 + 1 bytes. */
    void str_to_hex(char *dst_str, const unsigned char *src_bytes,
                    size_t src_len) {
        const char *hex = "0123456789abcdef";
        int n;

        for (n = 0; n < src_len; ++n) {
            unsigned char val = *src_bytes++;
            *dst_str++ = hex[val >> 4];
            *dst_str++ = hex[val & 0xf];
        }

        *dst_str = 0;
    }

    str_to_hex(hex, digest, 16);

The emailaddress limitation could probably be resolved here by repeatedly 
calling:

    MD5_Update(&c, tolower(email[n]), 1)

> +
> +	sprintf(gravatar, "http://www.gravatar.com/avatar/%s?s=", hex);

Use "//www.gravatar.com/.." instead for HTTPS sites?

> +
> +	return gravatar;
> +}

[..]

> --- a/ui-commit.c
> +++ b/ui-commit.c
> @@ -44,6 +44,11 @@ void cgit_print_commit(char *hex, const char *prefix)
>  	cgit_print_diff_ctrls();
>  	html("<table summary='commit info' class='commit-info'>\n");
>  	html("<tr><th>author</th><td>");
> +	if (ctx.cfg.enable_gravatar && info->author_gravatar) {
> +		html("<img src='");
> +		html(info->author_gravatar);
> +		html("' width=16 height=16 alt='Gravatar' \\>");
> +	}
>  	html_txt(info->author);
>  	if (!ctx.cfg.noplainemail) {
>  		html(" ");
> @@ -53,6 +58,11 @@ void cgit_print_commit(char *hex, const char *prefix)
>  	cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time);
>  	html("</td></tr>\n");
>  	html("<tr><th>committer</th><td>");
> +	if (ctx.cfg.enable_gravatar && info->committer_gravatar) {
> +		html("<img src='");
> +		html(info->committer_gravatar);
> +		html("' width=16 height=16 alt='Gravatar' \\>");

SHouldn't that \\ become a / for XHTML? 

> +	}
>  	html_txt(info->committer);
>  	if (!ctx.cfg.noplainemail) {
>  		html(" ");
> diff --git a/ui-log.c b/ui-log.c
> index 6f1249b..9974139 100644
> --- a/ui-log.c
> +++ b/ui-log.c
> @@ -168,6 +168,11 @@ static void print_commit(struct commit *commit, struct
> rev_info *revs) sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);
>  	show_commit_decorations(commit);
>  	html("</td><td>");
> +	if (ctx.cfg.enable_gravatar && info->author_gravatar) {
> +		html("<img src='");
> +		html(info->author_gravatar);
> +		html("' width=16 height=16 alt='Gravatar' \\>");

Same here, "/>" instead of "\>".

> +	}
>  	html_txt(info->author);
> 
>  	if (revs->graph) {
> diff --git a/ui-refs.c b/ui-refs.c
> index 0ae0612..8714b2d 100644
> --- a/ui-refs.c
> +++ b/ui-refs.c
> @@ -77,6 +77,11 @@ static int print_branch(struct refinfo *ref)
>  	if (ref->object->type == OBJ_COMMIT) {
>  		cgit_commit_link(info->subject, NULL, NULL, name, NULL, NULL, 0);
>  		html("</td><td>");
> +		if (ctx.cfg.enable_gravatar && info->author_gravatar) {
> +			html("<img src='");
> +			html(info->author_gravatar);
> +			html("' width=16 height=16 alt='Gravatar' \\>");

Same..

> +		}
>  		html_txt(info->author);
>  		html("</td><td colspan='2'>");
>  		cgit_print_age(info->commit->date, -1, NULL);
> @@ -154,6 +159,11 @@ static int print_tag(struct refinfo *ref)
>  		cgit_object_link(obj);
>  	html("</td><td>");
>  	if (info) {
> +		if (ctx.cfg.enable_gravatar && info->tagger_gravatar) {
> +			html("<img src='");
> +			html(info->tagger_gravatar);
> +			html("' width=16 height=16 alt='Gravatar' \\>");

Same..

> +		}
>  		if (info->tagger)
>  			html(info->tagger);
>  	} else if (ref->object->type == OBJ_COMMIT) {
> diff --git a/ui-tag.c b/ui-tag.c
> index aea7958..ad402da 100644
> --- a/ui-tag.c
> +++ b/ui-tag.c
> @@ -77,6 +77,11 @@ void cgit_print_tag(char *revname)
>  		}
>  		if (info->tagger) {
>  			html("<tr><td>tagged by</td><td>");
> +			if (ctx.cfg.enable_gravatar && info->tagger_gravatar) {
> +				html("<img src='");
> +				html(info->tagger_gravatar);
> +				html("' width=16 height=16 alt='Gravatar' \\>");

Yep, also wrong slashes.

> +			}
>  			html_txt(info->tagger);
>  			if (info->tagger_email && !ctx.cfg.noplainemail) {
>  				html(" ");

Regards,
Peter


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2013-11-27 16:37 ` john
@ 2013-11-27 20:51   ` list
  2013-11-27 21:00     ` john
  0 siblings, 1 reply; 17+ messages in thread
From: list @ 2013-11-27 20:51 UTC (permalink / raw)


John Keeping <john at keeping.me.uk> on Wed, 2013/11/27 16:37:
> On Wed, Nov 27, 2013 at 04:17:17PM +0100, Christian Hesse wrote:
> > diff --git a/parsing.c b/parsing.c
> > index 658621d..a8005f6 100644
> > --- a/parsing.c
> > +++ b/parsing.c
> > @@ -8,6 +8,9 @@
> >  
> >  #include "cgit.h"
> >  
> > +/* we need md5 hashing algorithm to calculate Gravatar URL */
> > +#include <openssl/md5.h>
> 
> We don't currently depend on OpenSSL, except via Git which can use
> alternative SHA-1 implementations.
> 
> At the very least Debian will not distribute GPL'd packages
> linked against OpenSSL [1].
> 
> [1]
> http://lintian.debian.org/tags/possible-gpl-code-linked-with-openssl.html

Damn licensing stuff... Ok, but cgit is already linked against libcrypt which
belongs to openssl.

Any ideas what to use instead? Shipping a complete MD5 implementation is a
bad idea I think.

> > +char * cgit_get_gravatar(const char * email) {
> > +    	int n, length;
> > +	MD5_CTX c;
> > +	unsigned char digest[16];
> > +	char hex[33];
> > +	char * gravatar = malloc(67);
> > +
> > +	/* skip brackets! */
> > +	email++;
> > +	length = strlen(email) - 1;
> > +
> > +	MD5_Init(&c);
> > +
> > +	while (length > 0) {
> > +		if (length > 512)
> > +			MD5_Update(&c, email, 512);
> > +		else
> > +			MD5_Update(&c, email, length);
> > +		length -= 512;
> > +		email += 512;
> > +	}
> > +
> > +	MD5_Final(digest, &c);
> 
> Would it be possible to extract everything from MD5_Init to MD5_Final to
> a function that just computes the MD5 of a string?  That should make it
> easier to add alternative implementations.

I updated the code to use MD5(...), but that is still openssl.

> > +	for (n = 0; n < 16; ++n)
> > +		snprintf(&(hex[n*2]), 16*2, "%02x", (unsigned
> > int)digest[n]); +
> > +	sprintf(gravatar, "http://www.gravatar.com/avatar/%s?s=", hex);
> > +
> > +	return gravatar;
> > +}

-- 
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Chris           get my mail address:    */=0;b=c[a++];)
putchar(b-1/(/*               gcc -o sig sig.c && ./sig    */b/42*2-3)*42);}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://lists.zx2c4.com/pipermail/cgit/attachments/20131127/d426bc4f/attachment.asc>


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2013-11-27 16:46 ` lekensteyn
@ 2013-11-27 20:59   ` list
  2013-11-27 21:14     ` mail
  0 siblings, 1 reply; 17+ messages in thread
From: list @ 2013-11-27 20:59 UTC (permalink / raw)


Peter Wu <lekensteyn at gmail.com> on Wed, 2013/11/27 17:46:
> Hi,
> 
> See below for review.
> 
> On Wednesday 27 November 2013 16:17:17 Christian Hesse wrote:
> > ---
> >  cgit.c       |  3 +++
> >  cgit.h       |  5 +++++
> >  cgitrc.5.txt |  4 ++++
> >  parsing.c    | 47 +++++++++++++++++++++++++++++++++++++++++++++++
> >  shared.c     |  6 ++++++
> >  ui-commit.c  | 10 ++++++++++
> >  ui-log.c     |  5 +++++
> >  ui-refs.c    | 10 ++++++++++
> >  ui-tag.c     |  5 +++++
> >  9 files changed, 95 insertions(+)
> 
> [..]
> 
> > @@ -258,3 +273,35 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
> >  	free(data);
> >  	return ret;
> >  }
> > +
> > +char * cgit_get_gravatar(const char * email) {
> > +    	int n, length;
> > +	MD5_CTX c;
> > +	unsigned char digest[16];
> > +	char hex[33];
> > +	char * gravatar = malloc(67);
> > +
> > +	/* skip brackets! */
> > +	email++;
> > +	length = strlen(email) - 1;
> 
> > +
> > +	MD5_Init(&c);
> > +
> > +	while (length > 0) {
> > +		if (length > 512)
> > +			MD5_Update(&c, email, 512);
> > +		else
> > +			MD5_Update(&c, email, length);
> Seems like an error from Stackoverflow[1]? According to the manual page,
> the length is in bytes, not bits.
> 
>  [1]: http://stackoverflow.com/a/8389763/427545
> 
> > +		length -= 512;
> > +		email += 512;
> > +	}
> > +
> > +	MD5_Final(digest, &c);
> 
> Since you know the full string onbeforehand, you should also be able to use 
> MD5() directly. Something like (openssl):
> 
>     MD5(email, length, digest);

Updated it to use MD5(...).

Though the licensing issue remain...

> As you mentioned, email addresses should be converted to lower case first 
> according to http://en.gravatar.com/site/implement/hash/. The below
> str_to_hex was written before I knew that.
> 
> > +
> > +	for (n = 0; n < 16; ++n)
> > +		snprintf(&(hex[n*2]), 16*2, "%02x", (unsigned
> > int)digest[n]);
> 
> This 16*2 is bogus, if you are at the 30th position, you only have two
> bytes left. What about adding a new md5_to_hex() function, similar to
> sha1_to_hex() in git? Here is a generic approach:
> 
> /* gets a string representing the binary data. dst_str must have a
>  * size of at least src_len * 2 + 1 bytes. */
>     void str_to_hex(char *dst_str, const unsigned char *src_bytes,
>                     size_t src_len) {
>         const char *hex = "0123456789abcdef";
>         int n;
> 
>         for (n = 0; n < src_len; ++n) {
>             unsigned char val = *src_bytes++;
>             *dst_str++ = hex[val >> 4];
>             *dst_str++ = hex[val & 0xf];
>         }
> 
>         *dst_str = 0;
>     }
> 
>     str_to_hex(hex, digest, 16);
> 
> The emailaddress limitation could probably be resolved here by repeatedly 
> calling:
> 
>     MD5_Update(&c, tolower(email[n]), 1)

I updated my code. It duplicates the string now, makes it lower case and uses
your function to calculate hex.

> > +
> > +	sprintf(gravatar, "http://www.gravatar.com/avatar/%s?s=", hex);
> 
> Use "//www.gravatar.com/.." instead for HTTPS sites?

Did not know this works. Great!

> > +
> > +	return gravatar;
> > +}
> 
> [..]
>
> > @@ -53,6 +58,11 @@ void cgit_print_commit(char *hex, const char *prefix)
> >  	cgit_print_date(info->author_date, FMT_LONGDATE,
> > ctx.cfg.local_time); html("</td></tr>\n");
> >  	html("<tr><th>committer</th><td>");
> > +	if (ctx.cfg.enable_gravatar && info->committer_gravatar) {
> > +		html("<img src='");
> > +		html(info->committer_gravatar);
> > +		html("' width=16 height=16 alt='Gravatar' \\>");
> 
> SHouldn't that \\ become a / for XHTML? 

I was sitting in my car on the way home when I thought about why I had to
escape this...

Of course you are right.

[...]

Thanks for your review! I will reply with an updated patch later.
-- 
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Chris           get my mail address:    */=0;b=c[a++];)
putchar(b-1/(/*               gcc -o sig sig.c && ./sig    */b/42*2-3)*42);}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://lists.zx2c4.com/pipermail/cgit/attachments/20131127/5ebac967/attachment.asc>


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2013-11-27 20:51   ` list
@ 2013-11-27 21:00     ` john
  0 siblings, 0 replies; 17+ messages in thread
From: john @ 2013-11-27 21:00 UTC (permalink / raw)


On Wed, Nov 27, 2013 at 09:51:33PM +0100, Christian Hesse wrote:
> John Keeping <john at keeping.me.uk> on Wed, 2013/11/27 16:37:
> > On Wed, Nov 27, 2013 at 04:17:17PM +0100, Christian Hesse wrote:
> > > diff --git a/parsing.c b/parsing.c
> > > index 658621d..a8005f6 100644
> > > --- a/parsing.c
> > > +++ b/parsing.c
> > > @@ -8,6 +8,9 @@
> > >  
> > >  #include "cgit.h"
> > >  
> > > +/* we need md5 hashing algorithm to calculate Gravatar URL */
> > > +#include <openssl/md5.h>
> > 
> > We don't currently depend on OpenSSL, except via Git which can use
> > alternative SHA-1 implementations.
> > 
> > At the very least Debian will not distribute GPL'd packages
> > linked against OpenSSL [1].
> > 
> > [1]
> > http://lintian.debian.org/tags/possible-gpl-code-linked-with-openssl.html
> 
> Damn licensing stuff... Ok, but cgit is already linked against libcrypt which
> belongs to openssl.
> 
> Any ideas what to use instead? Shipping a complete MD5 implementation is a
> bad idea I think.

I think writing against OpenSSL is fine, everyone else tends to have a
compatibility layer for that API anyway.  But it would be nice to define
a MD5_HEADER variable in a similar way to git.git's SHA1_HEADER.

> > > +char * cgit_get_gravatar(const char * email) {
> > > +    	int n, length;
> > > +	MD5_CTX c;
> > > +	unsigned char digest[16];
> > > +	char hex[33];
> > > +	char * gravatar = malloc(67);
> > > +
> > > +	/* skip brackets! */
> > > +	email++;
> > > +	length = strlen(email) - 1;
> > > +
> > > +	MD5_Init(&c);
> > > +
> > > +	while (length > 0) {
> > > +		if (length > 512)
> > > +			MD5_Update(&c, email, 512);
> > > +		else
> > > +			MD5_Update(&c, email, length);
> > > +		length -= 512;
> > > +		email += 512;
> > > +	}
> > > +
> > > +	MD5_Final(digest, &c);
> > 
> > Would it be possible to extract everything from MD5_Init to MD5_Final to
> > a function that just computes the MD5 of a string?  That should make it
> > easier to add alternative implementations.
> 
> I updated the code to use MD5(...), but that is still openssl.
> 
> > > +	for (n = 0; n < 16; ++n)
> > > +		snprintf(&(hex[n*2]), 16*2, "%02x", (unsigned
> > > int)digest[n]); +
> > > +	sprintf(gravatar, "http://www.gravatar.com/avatar/%s?s=", hex);
> > > +
> > > +	return gravatar;
> > > +}


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2013-11-27 20:59   ` list
@ 2013-11-27 21:14     ` mail
  2013-11-27 22:11       ` lekensteyn
  0 siblings, 1 reply; 17+ messages in thread
From: mail @ 2013-11-27 21:14 UTC (permalink / raw)


---
 cgit.c       |  3 +++
 cgit.h       |  8 ++++++++
 cgitrc.5.txt |  4 ++++
 parsing.c    | 41 +++++++++++++++++++++++++++++++++++++++++
 shared.c     | 23 +++++++++++++++++++++++
 ui-commit.c  | 10 ++++++++++
 ui-log.c     |  5 +++++
 ui-refs.c    | 10 ++++++++++
 ui-tag.c     |  5 +++++
 9 files changed, 109 insertions(+)

diff --git a/cgit.c b/cgit.c
index 861352a..fe82580 100644
--- a/cgit.c
+++ b/cgit.c
@@ -183,6 +183,8 @@ static void config_cb(const char *name, const char *value)
 		ctx.cfg.enable_index_owner = atoi(value);
 	else if (!strcmp(name, "enable-commit-graph"))
 		ctx.cfg.enable_commit_graph = atoi(value);
+	else if (!strcmp(name, "enable-gravatar"))
+		ctx.cfg.enable_gravatar = atoi(value);
 	else if (!strcmp(name, "enable-log-filecount"))
 		ctx.cfg.enable_log_filecount = atoi(value);
 	else if (!strcmp(name, "enable-log-linecount"))
@@ -368,6 +370,7 @@ static void prepare_context(struct cgit_context *ctx)
 	ctx->cfg.logo = "/cgit.png";
 	ctx->cfg.favicon = "/favicon.ico";
 	ctx->cfg.local_time = 0;
+	ctx->cfg.enable_gravatar = 0;
 	ctx->cfg.enable_http_clone = 1;
 	ctx->cfg.enable_index_owner = 1;
 	ctx->cfg.enable_tree_linenumbers = 1;
diff --git a/cgit.h b/cgit.h
index a474d77..c5c03fb 100644
--- a/cgit.h
+++ b/cgit.h
@@ -107,9 +107,11 @@ struct commitinfo {
 	struct commit *commit;
 	char *author;
 	char *author_email;
+	char *author_gravatar;
 	unsigned long author_date;
 	char *committer;
 	char *committer_email;
+	char *committer_gravatar;
 	unsigned long committer_date;
 	char *subject;
 	char *msg;
@@ -119,6 +121,7 @@ struct commitinfo {
 struct taginfo {
 	char *tagger;
 	char *tagger_email;
+	char *tagger_gravatar;
 	unsigned long tagger_date;
 	char *msg;
 };
@@ -208,6 +211,7 @@ struct cgit_config {
 	int enable_index_links;
 	int enable_index_owner;
 	int enable_commit_graph;
+	int enable_gravatar;
 	int enable_log_filecount;
 	int enable_log_linecount;
 	int enable_remote_branches;
@@ -337,6 +341,7 @@ extern char *fmtalloc(const char *format,...);
 
 extern struct commitinfo *cgit_parse_commit(struct commit *commit);
 extern struct taginfo *cgit_parse_tag(struct tag *tag);
+char *cgit_get_gravatar(const char *email);
 extern void cgit_parse_url(const char *url);
 
 extern const char *cgit_repobasename(const char *reponame);
@@ -352,4 +357,7 @@ extern int readfile(const char *path, char **buf, size_t *size);
 
 extern char *expand_macros(const char *txt);
 
+void str_to_hex(char *dst_str, const unsigned char *src_bytes,
+		size_t src_len);
+
 #endif /* CGIT_H */
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 633cb00..b6017c2 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -180,6 +180,10 @@ enable-git-config::
 	to the corresponding "repo." key in cgit. Default value: "0". See also:
 	scan-path, section-from-path.
 
+enable-gravatar::
+	Flag which, when set to "1", will enable cgit to show gravatar icon
+	for author, committer and tagger email address. Default value: "0".
+
 favicon::
 	Url used as link to a shortcut icon for cgit. It is suggested to use
 	the value "/favicon.ico" since certain browsers will ignore other
diff --git a/parsing.c b/parsing.c
index 658621d..bd87999 100644
--- a/parsing.c
+++ b/parsing.c
@@ -8,6 +8,9 @@
 
 #include "cgit.h"
 
+/* we need md5 hashing algorithm to calculate Gravatar URL */
+#include <openssl/md5.h>
+
 /*
  * url syntax: [repo ['/' cmd [ '/' path]]]
  *   repo: any valid repo url, may contain '/'
@@ -133,8 +136,10 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
 	ret->commit = commit;
 	ret->author = NULL;
 	ret->author_email = NULL;
+	ret->author_gravatar = NULL;
 	ret->committer = NULL;
 	ret->committer_email = NULL;
+	ret->committer_gravatar = NULL;
 	ret->subject = NULL;
 	ret->msg = NULL;
 	ret->msg_encoding = NULL;
@@ -155,11 +160,17 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
 			&ret->author_date);
 	}
 
+	if (ctx.cfg.enable_gravatar && ret->author_email != NULL)
+		ret->author_gravatar = cgit_get_gravatar(ret->author_email);
+
 	if (p && !strncmp(p, "committer ", 9)) {
 		p = parse_user(p + 9, &ret->committer, &ret->committer_email,
 			&ret->committer_date);
 	}
 
+	if (ctx.cfg.enable_gravatar && ret->committer_email != NULL)
+		ret->committer_gravatar = cgit_get_gravatar(ret->committer_email);
+
 	if (p && !strncmp(p, "encoding ", 9)) {
 		p += 9;
 		t = strchr(p, '\n');
@@ -230,6 +241,7 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
 	ret = xmalloc(sizeof(*ret));
 	ret->tagger = NULL;
 	ret->tagger_email = NULL;
+	ret->tagger_gravatar = NULL;
 	ret->tagger_date = 0;
 	ret->msg = NULL;
 
@@ -249,6 +261,9 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
 		}
 	}
 
+	if (ctx.cfg.enable_gravatar && ret->tagger_email != NULL)
+		ret->tagger_gravatar = cgit_get_gravatar(ret->tagger_email);
+
 	// skip empty lines between headers and message
 	while (p && *p == '\n')
 		p++;
@@ -258,3 +273,29 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
 	free(data);
 	return ret;
 }
+
+char * cgit_get_gravatar(const char *email) {
+	unsigned char digest[16];
+	char hex[33], *lower, *tmp;
+	char *gravatar;
+
+	gravatar = malloc(77);
+
+	/* duplicate to lower and skip brackets! */
+	lower = strdup(email + 1);
+	lower[strlen(lower) - 1] = '\0';
+
+	/* make the chars lower case */
+	for (tmp = lower; *tmp; ++tmp)
+		*tmp = tolower(*tmp);
+
+	MD5((unsigned char *)lower, strlen(lower), digest);
+
+	str_to_hex(hex, digest, 16);
+
+	sprintf(gravatar, "//www.gravatar.com/avatar/%s?s=16&amp;d=retro", hex);
+
+	free(lower);
+
+	return gravatar;
+}
diff --git a/shared.c b/shared.c
index 919a99e..a383dfa 100644
--- a/shared.c
+++ b/shared.c
@@ -93,8 +93,12 @@ void *cgit_free_commitinfo(struct commitinfo *info)
 {
 	free(info->author);
 	free(info->author_email);
+	if (info->author_gravatar)
+		free(info->author_gravatar);
 	free(info->committer);
 	free(info->committer_email);
+	if (info->committer_gravatar)
+		free(info->committer_gravatar);
 	free(info->subject);
 	free(info->msg);
 	free(info->msg_encoding);
@@ -204,6 +208,8 @@ static void cgit_free_taginfo(struct taginfo *tag)
 		free(tag->tagger);
 	if (tag->tagger_email)
 		free(tag->tagger_email);
+	if (tag->tagger_gravatar)
+		free(tag->tagger_gravatar);
 	if (tag->msg)
 		free(tag->msg);
 	free(tag);
@@ -588,3 +594,20 @@ char *expand_macros(const char *txt)
 	}
 	return result;
 }
+
+/* gets a string representing the binary data. dst_str must have a
+ * size of at least src_len * 2 + 1 bytes. */
+void str_to_hex(char *dst_str, const unsigned char *src_bytes,
+		size_t src_len) {
+	const char *hex = "0123456789abcdef";
+	int n;
+
+	for (n = 0; n < src_len; ++n) {
+		unsigned char val = *src_bytes++;
+
+		*dst_str++ = hex[val >> 4];
+		*dst_str++ = hex[val & 0xf];
+	}
+
+	*dst_str = 0;
+}
diff --git a/ui-commit.c b/ui-commit.c
index ef85a49..6303408 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -44,6 +44,11 @@ void cgit_print_commit(char *hex, const char *prefix)
 	cgit_print_diff_ctrls();
 	html("<table summary='commit info' class='commit-info'>\n");
 	html("<tr><th>author</th><td>");
+	if (ctx.cfg.enable_gravatar && info->author_gravatar) {
+		html("<img src='");
+		html(info->author_gravatar);
+		html("' width=16 height=16 alt='Gravatar' /> ");
+	}
 	html_txt(info->author);
 	if (!ctx.cfg.noplainemail) {
 		html(" ");
@@ -53,6 +58,11 @@ void cgit_print_commit(char *hex, const char *prefix)
 	cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time);
 	html("</td></tr>\n");
 	html("<tr><th>committer</th><td>");
+	if (ctx.cfg.enable_gravatar && info->committer_gravatar) {
+		html("<img src='");
+		html(info->committer_gravatar);
+		html("' width=16 height=16 alt='Gravatar' /> ");
+	}
 	html_txt(info->committer);
 	if (!ctx.cfg.noplainemail) {
 		html(" ");
diff --git a/ui-log.c b/ui-log.c
index 6f1249b..7cdcca2 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -168,6 +168,11 @@ static void print_commit(struct commit *commit, struct rev_info *revs)
 			 sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);
 	show_commit_decorations(commit);
 	html("</td><td>");
+	if (ctx.cfg.enable_gravatar && info->author_gravatar) {
+		html("<img src='");
+		html(info->author_gravatar);
+		html("' width=16 height=16 alt='Gravatar' /> ");
+	}
 	html_txt(info->author);
 
 	if (revs->graph) {
diff --git a/ui-refs.c b/ui-refs.c
index 0ae0612..6e67799 100644
--- a/ui-refs.c
+++ b/ui-refs.c
@@ -77,6 +77,11 @@ static int print_branch(struct refinfo *ref)
 	if (ref->object->type == OBJ_COMMIT) {
 		cgit_commit_link(info->subject, NULL, NULL, name, NULL, NULL, 0);
 		html("</td><td>");
+		if (ctx.cfg.enable_gravatar && info->author_gravatar) {
+			html("<img src='");
+			html(info->author_gravatar);
+			html("' width=16 height=16 alt='Gravatar' /> ");
+		}
 		html_txt(info->author);
 		html("</td><td colspan='2'>");
 		cgit_print_age(info->commit->date, -1, NULL);
@@ -154,6 +159,11 @@ static int print_tag(struct refinfo *ref)
 		cgit_object_link(obj);
 	html("</td><td>");
 	if (info) {
+		if (ctx.cfg.enable_gravatar && info->tagger_gravatar) {
+			html("<img src='");
+			html(info->tagger_gravatar);
+			html("' width=16 height=16 alt='Gravatar' /> ");
+		}
 		if (info->tagger)
 			html(info->tagger);
 	} else if (ref->object->type == OBJ_COMMIT) {
diff --git a/ui-tag.c b/ui-tag.c
index aea7958..1e041d0 100644
--- a/ui-tag.c
+++ b/ui-tag.c
@@ -77,6 +77,11 @@ void cgit_print_tag(char *revname)
 		}
 		if (info->tagger) {
 			html("<tr><td>tagged by</td><td>");
+			if (ctx.cfg.enable_gravatar && info->tagger_gravatar) {
+				html("<img src='");
+				html(info->tagger_gravatar);
+				html("' width=16 height=16 alt='Gravatar' /> ");
+			}
 			html_txt(info->tagger);
 			if (info->tagger_email && !ctx.cfg.noplainemail) {
 				html(" ");
-- 
1.8.4.2



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2013-11-27 21:14     ` mail
@ 2013-11-27 22:11       ` lekensteyn
  2013-11-27 22:59         ` list
  0 siblings, 1 reply; 17+ messages in thread
From: lekensteyn @ 2013-11-27 22:11 UTC (permalink / raw)


On Wednesday 27 November 2013 22:14:22 Christian Hesse wrote:
> +char * cgit_get_gravatar(const char *email) {
> +       unsigned char digest[16];
> +       char hex[33], *lower, *tmp;
> +       char *gravatar;
> +
> +       gravatar = malloc(77);

I do not quite like this magic number, does anyone have problems with
creating a GRAVATAR_URL macro? 77 seems also small enough to throw on the
stack. (Btw, len("//www.gravatar.com/avatar/?s=16&amp;d=retro") + 32 + 1
says that the length is 76 including nul byte).

> +       /* duplicate to lower and skip brackets! */
> +       lower = strdup(email + 1);
> +       lower[strlen(lower) - 1] = '\0';

Ahh, I though it was off by one, but apparently you remove the brackets. OK.

> +
> +       /* make the chars lower case */
> +       for (tmp = lower; *tmp; ++tmp)
> +               *tmp = tolower(*tmp);
> +
> +       MD5((unsigned char *)lower, strlen(lower), digest);
> +
> +       str_to_hex(hex, digest, 16);
> +
> +       sprintf(gravatar, "//www.gravatar.com/avatar/%s?s=16&amp;d=retro", hex);

It seems ugly to me to store the HTML-escaped URL here. What do you think of
using just "&" here and html_txt() when outputting the URL? Processing these
few chars and performing an extra write() should not hurt performance.

Regarding the GRAVATAR_URL macro mentioned earlier, if used that could
also be inserted here. A comment could then describe why this URL is used
(16x16 image using "awesome generated, 8-bit arcade-style pixelated faces"
as default, https://en.gravatar.com/site/implement/images/)

> +       free(lower);
> +
> +       return gravatar;
> +}

Regards,
Peter


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2013-11-27 22:11       ` lekensteyn
@ 2013-11-27 22:59         ` list
  2013-11-27 23:00           ` mail
  0 siblings, 1 reply; 17+ messages in thread
From: list @ 2013-11-27 22:59 UTC (permalink / raw)


Peter Wu <lekensteyn at gmail.com> on Wed, 2013/11/27 23:11:
> On Wednesday 27 November 2013 22:14:22 Christian Hesse wrote:
> > +char * cgit_get_gravatar(const char *email) {
> > +       unsigned char digest[16];
> > +       char hex[33], *lower, *tmp;
> > +       char *gravatar;
> > +
> > +       gravatar = malloc(77);
> 
> I do not quite like this magic number, does anyone have problems with
> creating a GRAVATAR_URL macro? 77 seems also small enough to throw on the
> stack. (Btw, len("//www.gravatar.com/avatar/?s=16&amp;d=retro") + 32 + 1
> says that the length is 76 including nul byte).

Created a GRAVATAR_URL macro now. I do prefer this solution as well.

Got rid of some more magic numbers for MD5 hashing.

> > +       /* duplicate to lower and skip brackets! */
> > +       lower = strdup(email + 1);
> > +       lower[strlen(lower) - 1] = '\0';
> 
> Ahh, I though it was off by one, but apparently you remove the brackets. OK.
> 
> > +
> > +       /* make the chars lower case */
> > +       for (tmp = lower; *tmp; ++tmp)
> > +               *tmp = tolower(*tmp);
> > +
> > +       MD5((unsigned char *)lower, strlen(lower), digest);
> > +
> > +       str_to_hex(hex, digest, 16);
> > +
> > +       sprintf(gravatar,
> > "//www.gravatar.com/avatar/%s?s=16&amp;d=retro", hex);
> 
> It seems ugly to me to store the HTML-escaped URL here. What do you think of
> using just "&" here and html_txt() when outputting the URL? Processing these
> few chars and performing an extra write() should not hurt performance.

Agreed.

> Regarding the GRAVATAR_URL macro mentioned earlier, if used that could
> also be inserted here. A comment could then describe why this URL is used
> (16x16 image using "awesome generated, 8-bit arcade-style pixelated faces"
> as default, https://en.gravatar.com/site/implement/images/)

Done.

> > +       free(lower);
> > +
> > +       return gravatar;
> > +}

I will replay with my updated patch.

-- 
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Chris           get my mail address:    */=0;b=c[a++];)
putchar(b-1/(/*               gcc -o sig sig.c && ./sig    */b/42*2-3)*42);}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://lists.zx2c4.com/pipermail/cgit/attachments/20131127/49b03159/attachment.asc>


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2013-11-27 22:59         ` list
@ 2013-11-27 23:00           ` mail
  0 siblings, 0 replies; 17+ messages in thread
From: mail @ 2013-11-27 23:00 UTC (permalink / raw)


---
 cgit.c       |  3 +++
 cgit.h       |  8 ++++++++
 cgitrc.5.txt |  4 ++++
 parsing.c    | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 shared.c     | 23 +++++++++++++++++++++++
 ui-commit.c  | 10 ++++++++++
 ui-log.c     |  5 +++++
 ui-refs.c    | 10 ++++++++++
 ui-tag.c     |  5 +++++
 9 files changed, 119 insertions(+)

diff --git a/cgit.c b/cgit.c
index 861352a..fe82580 100644
--- a/cgit.c
+++ b/cgit.c
@@ -183,6 +183,8 @@ static void config_cb(const char *name, const char *value)
 		ctx.cfg.enable_index_owner = atoi(value);
 	else if (!strcmp(name, "enable-commit-graph"))
 		ctx.cfg.enable_commit_graph = atoi(value);
+	else if (!strcmp(name, "enable-gravatar"))
+		ctx.cfg.enable_gravatar = atoi(value);
 	else if (!strcmp(name, "enable-log-filecount"))
 		ctx.cfg.enable_log_filecount = atoi(value);
 	else if (!strcmp(name, "enable-log-linecount"))
@@ -368,6 +370,7 @@ static void prepare_context(struct cgit_context *ctx)
 	ctx->cfg.logo = "/cgit.png";
 	ctx->cfg.favicon = "/favicon.ico";
 	ctx->cfg.local_time = 0;
+	ctx->cfg.enable_gravatar = 0;
 	ctx->cfg.enable_http_clone = 1;
 	ctx->cfg.enable_index_owner = 1;
 	ctx->cfg.enable_tree_linenumbers = 1;
diff --git a/cgit.h b/cgit.h
index a474d77..c5c03fb 100644
--- a/cgit.h
+++ b/cgit.h
@@ -107,9 +107,11 @@ struct commitinfo {
 	struct commit *commit;
 	char *author;
 	char *author_email;
+	char *author_gravatar;
 	unsigned long author_date;
 	char *committer;
 	char *committer_email;
+	char *committer_gravatar;
 	unsigned long committer_date;
 	char *subject;
 	char *msg;
@@ -119,6 +121,7 @@ struct commitinfo {
 struct taginfo {
 	char *tagger;
 	char *tagger_email;
+	char *tagger_gravatar;
 	unsigned long tagger_date;
 	char *msg;
 };
@@ -208,6 +211,7 @@ struct cgit_config {
 	int enable_index_links;
 	int enable_index_owner;
 	int enable_commit_graph;
+	int enable_gravatar;
 	int enable_log_filecount;
 	int enable_log_linecount;
 	int enable_remote_branches;
@@ -337,6 +341,7 @@ extern char *fmtalloc(const char *format,...);
 
 extern struct commitinfo *cgit_parse_commit(struct commit *commit);
 extern struct taginfo *cgit_parse_tag(struct tag *tag);
+char *cgit_get_gravatar(const char *email);
 extern void cgit_parse_url(const char *url);
 
 extern const char *cgit_repobasename(const char *reponame);
@@ -352,4 +357,7 @@ extern int readfile(const char *path, char **buf, size_t *size);
 
 extern char *expand_macros(const char *txt);
 
+void str_to_hex(char *dst_str, const unsigned char *src_bytes,
+		size_t src_len);
+
 #endif /* CGIT_H */
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 633cb00..b6017c2 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -180,6 +180,10 @@ enable-git-config::
 	to the corresponding "repo." key in cgit. Default value: "0". See also:
 	scan-path, section-from-path.
 
+enable-gravatar::
+	Flag which, when set to "1", will enable cgit to show gravatar icon
+	for author, committer and tagger email address. Default value: "0".
+
 favicon::
 	Url used as link to a shortcut icon for cgit. It is suggested to use
 	the value "/favicon.ico" since certain browsers will ignore other
diff --git a/parsing.c b/parsing.c
index 658621d..35087c3 100644
--- a/parsing.c
+++ b/parsing.c
@@ -8,6 +8,17 @@
 
 #include "cgit.h"
 
+/* we need md5 hashing algorithm to calculate Gravatar URL */
+#include <openssl/md5.h>
+
+/* This is the URL for Gravatar.
+ * Starting with double slash makes it automatically use the right protocol,
+ * e.g. https for cgit on encrypted sites. The default parameters make this
+ * fetch 16x16 pixel images, with "awesome generated, 8-bit arcade-style
+ * pixelated faces".
+ * https://en.gravatar.com/site/implement/images/ */
+#define GRAVATAR_URL "//www.gravatar.com/avatar/%s?s=16&d=retro"
+
 /*
  * url syntax: [repo ['/' cmd [ '/' path]]]
  *   repo: any valid repo url, may contain '/'
@@ -133,8 +144,10 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
 	ret->commit = commit;
 	ret->author = NULL;
 	ret->author_email = NULL;
+	ret->author_gravatar = NULL;
 	ret->committer = NULL;
 	ret->committer_email = NULL;
+	ret->committer_gravatar = NULL;
 	ret->subject = NULL;
 	ret->msg = NULL;
 	ret->msg_encoding = NULL;
@@ -155,11 +168,17 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
 			&ret->author_date);
 	}
 
+	if (ctx.cfg.enable_gravatar && ret->author_email != NULL)
+		ret->author_gravatar = cgit_get_gravatar(ret->author_email);
+
 	if (p && !strncmp(p, "committer ", 9)) {
 		p = parse_user(p + 9, &ret->committer, &ret->committer_email,
 			&ret->committer_date);
 	}
 
+	if (ctx.cfg.enable_gravatar && ret->committer_email != NULL)
+		ret->committer_gravatar = cgit_get_gravatar(ret->committer_email);
+
 	if (p && !strncmp(p, "encoding ", 9)) {
 		p += 9;
 		t = strchr(p, '\n');
@@ -230,6 +249,7 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
 	ret = xmalloc(sizeof(*ret));
 	ret->tagger = NULL;
 	ret->tagger_email = NULL;
+	ret->tagger_gravatar = NULL;
 	ret->tagger_date = 0;
 	ret->msg = NULL;
 
@@ -249,6 +269,9 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
 		}
 	}
 
+	if (ctx.cfg.enable_gravatar && ret->tagger_email != NULL)
+		ret->tagger_gravatar = cgit_get_gravatar(ret->tagger_email);
+
 	// skip empty lines between headers and message
 	while (p && *p == '\n')
 		p++;
@@ -258,3 +281,31 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
 	free(data);
 	return ret;
 }
+
+char * cgit_get_gravatar(const char *email) {
+	unsigned char digest[MD5_DIGEST_LENGTH];
+	char hex[MD5_DIGEST_LENGTH * 2 + 1], *lower, *tmp;
+	char *gravatar;
+
+	/* The URL includes %s, which is replaced later on. So we do not need
+	 * extra space for termination. */
+	gravatar = malloc(strlen(GRAVATAR_URL) + MD5_DIGEST_LENGTH * 2);
+
+	/* duplicate to lower and skip brackets! */
+	lower = strdup(email + 1);
+	lower[strlen(lower) - 1] = '\0';
+
+	/* make the chars lower case */
+	for (tmp = lower; *tmp; ++tmp)
+		*tmp = tolower(*tmp);
+
+	MD5((unsigned char *)lower, strlen(lower), digest);
+
+	str_to_hex(hex, digest, MD5_DIGEST_LENGTH);
+
+	sprintf(gravatar, GRAVATAR_URL, hex);
+
+	free(lower);
+
+	return gravatar;
+}
diff --git a/shared.c b/shared.c
index 919a99e..a383dfa 100644
--- a/shared.c
+++ b/shared.c
@@ -93,8 +93,12 @@ void *cgit_free_commitinfo(struct commitinfo *info)
 {
 	free(info->author);
 	free(info->author_email);
+	if (info->author_gravatar)
+		free(info->author_gravatar);
 	free(info->committer);
 	free(info->committer_email);
+	if (info->committer_gravatar)
+		free(info->committer_gravatar);
 	free(info->subject);
 	free(info->msg);
 	free(info->msg_encoding);
@@ -204,6 +208,8 @@ static void cgit_free_taginfo(struct taginfo *tag)
 		free(tag->tagger);
 	if (tag->tagger_email)
 		free(tag->tagger_email);
+	if (tag->tagger_gravatar)
+		free(tag->tagger_gravatar);
 	if (tag->msg)
 		free(tag->msg);
 	free(tag);
@@ -588,3 +594,20 @@ char *expand_macros(const char *txt)
 	}
 	return result;
 }
+
+/* gets a string representing the binary data. dst_str must have a
+ * size of at least src_len * 2 + 1 bytes. */
+void str_to_hex(char *dst_str, const unsigned char *src_bytes,
+		size_t src_len) {
+	const char *hex = "0123456789abcdef";
+	int n;
+
+	for (n = 0; n < src_len; ++n) {
+		unsigned char val = *src_bytes++;
+
+		*dst_str++ = hex[val >> 4];
+		*dst_str++ = hex[val & 0xf];
+	}
+
+	*dst_str = 0;
+}
diff --git a/ui-commit.c b/ui-commit.c
index ef85a49..4fa5b83 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -44,6 +44,11 @@ void cgit_print_commit(char *hex, const char *prefix)
 	cgit_print_diff_ctrls();
 	html("<table summary='commit info' class='commit-info'>\n");
 	html("<tr><th>author</th><td>");
+	if (ctx.cfg.enable_gravatar && info->author_gravatar) {
+		html("<img src='");
+		html_txt(info->author_gravatar);
+		html("' width=16 height=16 alt='Gravatar' /> ");
+	}
 	html_txt(info->author);
 	if (!ctx.cfg.noplainemail) {
 		html(" ");
@@ -53,6 +58,11 @@ void cgit_print_commit(char *hex, const char *prefix)
 	cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time);
 	html("</td></tr>\n");
 	html("<tr><th>committer</th><td>");
+	if (ctx.cfg.enable_gravatar && info->committer_gravatar) {
+		html("<img src='");
+		html_txt(info->committer_gravatar);
+		html("' width=16 height=16 alt='Gravatar' /> ");
+	}
 	html_txt(info->committer);
 	if (!ctx.cfg.noplainemail) {
 		html(" ");
diff --git a/ui-log.c b/ui-log.c
index 6f1249b..c1bbc00 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -168,6 +168,11 @@ static void print_commit(struct commit *commit, struct rev_info *revs)
 			 sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);
 	show_commit_decorations(commit);
 	html("</td><td>");
+	if (ctx.cfg.enable_gravatar && info->author_gravatar) {
+		html("<img src='");
+		html_txt(info->author_gravatar);
+		html("' width=16 height=16 alt='Gravatar' /> ");
+	}
 	html_txt(info->author);
 
 	if (revs->graph) {
diff --git a/ui-refs.c b/ui-refs.c
index 0ae0612..5e6dda9 100644
--- a/ui-refs.c
+++ b/ui-refs.c
@@ -77,6 +77,11 @@ static int print_branch(struct refinfo *ref)
 	if (ref->object->type == OBJ_COMMIT) {
 		cgit_commit_link(info->subject, NULL, NULL, name, NULL, NULL, 0);
 		html("</td><td>");
+		if (ctx.cfg.enable_gravatar && info->author_gravatar) {
+			html("<img src='");
+			html_txt(info->author_gravatar);
+			html("' width=16 height=16 alt='Gravatar' /> ");
+		}
 		html_txt(info->author);
 		html("</td><td colspan='2'>");
 		cgit_print_age(info->commit->date, -1, NULL);
@@ -154,6 +159,11 @@ static int print_tag(struct refinfo *ref)
 		cgit_object_link(obj);
 	html("</td><td>");
 	if (info) {
+		if (ctx.cfg.enable_gravatar && info->tagger_gravatar) {
+			html("<img src='");
+			html_txt(info->tagger_gravatar);
+			html("' width=16 height=16 alt='Gravatar' /> ");
+		}
 		if (info->tagger)
 			html(info->tagger);
 	} else if (ref->object->type == OBJ_COMMIT) {
diff --git a/ui-tag.c b/ui-tag.c
index aea7958..865d6d7 100644
--- a/ui-tag.c
+++ b/ui-tag.c
@@ -77,6 +77,11 @@ void cgit_print_tag(char *revname)
 		}
 		if (info->tagger) {
 			html("<tr><td>tagged by</td><td>");
+			if (ctx.cfg.enable_gravatar && info->tagger_gravatar) {
+				html("<img src='");
+				html_txt(info->tagger_gravatar);
+				html("' width=16 height=16 alt='Gravatar' /> ");
+			}
 			html_txt(info->tagger);
 			if (info->tagger_email && !ctx.cfg.noplainemail) {
 				html(" ");
-- 
1.8.4.2



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2014-01-09  8:52     ` mail
@ 2014-01-09 15:13       ` Jason
  0 siblings, 0 replies; 17+ messages in thread
From: Jason @ 2014-01-09 15:13 UTC (permalink / raw)


On Thu, Jan 9, 2014 at 9:52 AM, Christian Hesse <mail at eworm.de> wrote:
>
> Looks like you have applied this with your changes to jd/zx2c4-deployment. I
> am fine with that. Or do you want an updated patch from me?

It's okay; I've got it handled.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2014-01-08 16:00   ` Jason
@ 2014-01-09  9:13     ` mail
  0 siblings, 0 replies; 17+ messages in thread
From: mail @ 2014-01-09  9:13 UTC (permalink / raw)


"Jason A. Donenfeld" <Jason at zx2c4.com> on Wed, 2014/01/08 17:00:
> Sorry for the extended nitpicks....
> 
> On Wed, Jan 8, 2014 at 4:23 PM, Christian Hesse <mail at eworm.de> wrote:
> > +char *cgit_get_gravatar(const char *email)
> > +{
> > +
> > +       /* duplicate to lower and skip brackets! */
> > +       lower = strdup(email + 1);
> > +       lower[strlen(lower) - 1] = '\0';
> 
> Can email ever be passed in with no length at all? Or without
> brackets? It's not immediately clear to me from looking briefly at
> parse_user in parsing.c.

A really good question. Let's think about parse_user()... If t does not
include brackets the string ends up in name. If it does include brackets the
address ends up in email, including the brackets. So does (mode == 2 && *p ==
'\n') ever get true? Probably we have a piece of dead code.

I think email always includes brackets or is NULL. In later case
cgit_get_gravatar() is not executed, so everything should be fine.
-- 
Schoene Gruesse
Chris
                         O< ascii ribbon campaign
                   stop html mail - www.asciiribbon.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.zx2c4.com/pipermail/cgit/attachments/20140109/8fbd411d/attachment.asc>


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2014-01-08 15:56   ` Jason
@ 2014-01-09  8:52     ` mail
  2014-01-09 15:13       ` Jason
  0 siblings, 1 reply; 17+ messages in thread
From: mail @ 2014-01-09  8:52 UTC (permalink / raw)


"Jason A. Donenfeld" <Jason at zx2c4.com> on Wed, 2014/01/08 16:56:
> On Wed, Jan 8, 2014 at 4:23 PM, Christian Hesse <mail at eworm.de> wrote:
> > +       gravatar = malloc(strlen(GRAVATAR_URL) + MD5_DIGEST_LENGTH * 2 +
> > 1);
> 
> xmalloc
> 
> > +       lower = strdup(email + 1);
> 
> xstrdup

Looks like you have applied this with your changes to jd/zx2c4-deployment. I
am fine with that. Or do you want an updated patch from me?
-- 
Schoene Gruesse
Chris
                         O< ascii ribbon campaign
                   stop html mail - www.asciiribbon.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.zx2c4.com/pipermail/cgit/attachments/20140109/be594b1c/attachment.asc>


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2014-01-08 15:23 ` [PATCH " mail
  2014-01-08 15:56   ` Jason
@ 2014-01-08 16:00   ` Jason
  2014-01-09  9:13     ` mail
  1 sibling, 1 reply; 17+ messages in thread
From: Jason @ 2014-01-08 16:00 UTC (permalink / raw)


Sorry for the extended nitpicks....

On Wed, Jan 8, 2014 at 4:23 PM, Christian Hesse <mail at eworm.de> wrote:
> +char *cgit_get_gravatar(const char *email)
> +{
> +
> +       /* duplicate to lower and skip brackets! */
> +       lower = strdup(email + 1);
> +       lower[strlen(lower) - 1] = '\0';


Can email ever be passed in with no length at all? Or without
brackets? It's not immediately clear to me from looking briefly at
parse_user in parsing.c.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2014-01-08 15:23 ` [PATCH " mail
@ 2014-01-08 15:56   ` Jason
  2014-01-09  8:52     ` mail
  2014-01-08 16:00   ` Jason
  1 sibling, 1 reply; 17+ messages in thread
From: Jason @ 2014-01-08 15:56 UTC (permalink / raw)


On Wed, Jan 8, 2014 at 4:23 PM, Christian Hesse <mail at eworm.de> wrote:
> +       gravatar = malloc(strlen(GRAVATAR_URL) + MD5_DIGEST_LENGTH * 2 + 1);

xmalloc

> +       lower = strdup(email + 1);

xstrdup


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger
  2014-01-08 15:12 [RESEND PATCH " Jason
@ 2014-01-08 15:23 ` mail
  2014-01-08 15:56   ` Jason
  2014-01-08 16:00   ` Jason
  0 siblings, 2 replies; 17+ messages in thread
From: mail @ 2014-01-08 15:23 UTC (permalink / raw)


---
 cgit.c       |  3 +++
 cgit.h       |  8 ++++++++
 cgitrc.5.txt |  4 ++++
 parsing.c    | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 shared.c     | 23 +++++++++++++++++++++++
 ui-commit.c  | 10 ++++++++++
 ui-log.c     |  5 +++++
 ui-refs.c    | 10 ++++++++++
 ui-tag.c     |  5 +++++
 9 files changed, 118 insertions(+)

diff --git a/cgit.c b/cgit.c
index 861352a..fe82580 100644
--- a/cgit.c
+++ b/cgit.c
@@ -183,6 +183,8 @@ static void config_cb(const char *name, const char *value)
 		ctx.cfg.enable_index_owner = atoi(value);
 	else if (!strcmp(name, "enable-commit-graph"))
 		ctx.cfg.enable_commit_graph = atoi(value);
+	else if (!strcmp(name, "enable-gravatar"))
+		ctx.cfg.enable_gravatar = atoi(value);
 	else if (!strcmp(name, "enable-log-filecount"))
 		ctx.cfg.enable_log_filecount = atoi(value);
 	else if (!strcmp(name, "enable-log-linecount"))
@@ -368,6 +370,7 @@ static void prepare_context(struct cgit_context *ctx)
 	ctx->cfg.logo = "/cgit.png";
 	ctx->cfg.favicon = "/favicon.ico";
 	ctx->cfg.local_time = 0;
+	ctx->cfg.enable_gravatar = 0;
 	ctx->cfg.enable_http_clone = 1;
 	ctx->cfg.enable_index_owner = 1;
 	ctx->cfg.enable_tree_linenumbers = 1;
diff --git a/cgit.h b/cgit.h
index a474d77..c5c03fb 100644
--- a/cgit.h
+++ b/cgit.h
@@ -107,9 +107,11 @@ struct commitinfo {
 	struct commit *commit;
 	char *author;
 	char *author_email;
+	char *author_gravatar;
 	unsigned long author_date;
 	char *committer;
 	char *committer_email;
+	char *committer_gravatar;
 	unsigned long committer_date;
 	char *subject;
 	char *msg;
@@ -119,6 +121,7 @@ struct commitinfo {
 struct taginfo {
 	char *tagger;
 	char *tagger_email;
+	char *tagger_gravatar;
 	unsigned long tagger_date;
 	char *msg;
 };
@@ -208,6 +211,7 @@ struct cgit_config {
 	int enable_index_links;
 	int enable_index_owner;
 	int enable_commit_graph;
+	int enable_gravatar;
 	int enable_log_filecount;
 	int enable_log_linecount;
 	int enable_remote_branches;
@@ -337,6 +341,7 @@ extern char *fmtalloc(const char *format,...);
 
 extern struct commitinfo *cgit_parse_commit(struct commit *commit);
 extern struct taginfo *cgit_parse_tag(struct tag *tag);
+char *cgit_get_gravatar(const char *email);
 extern void cgit_parse_url(const char *url);
 
 extern const char *cgit_repobasename(const char *reponame);
@@ -352,4 +357,7 @@ extern int readfile(const char *path, char **buf, size_t *size);
 
 extern char *expand_macros(const char *txt);
 
+void str_to_hex(char *dst_str, const unsigned char *src_bytes,
+		size_t src_len);
+
 #endif /* CGIT_H */
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 633cb00..b6017c2 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -180,6 +180,10 @@ enable-git-config::
 	to the corresponding "repo." key in cgit. Default value: "0". See also:
 	scan-path, section-from-path.
 
+enable-gravatar::
+	Flag which, when set to "1", will enable cgit to show gravatar icon
+	for author, committer and tagger email address. Default value: "0".
+
 favicon::
 	Url used as link to a shortcut icon for cgit. It is suggested to use
 	the value "/favicon.ico" since certain browsers will ignore other
diff --git a/parsing.c b/parsing.c
index 658621d..74becd7 100644
--- a/parsing.c
+++ b/parsing.c
@@ -8,6 +8,17 @@
 
 #include "cgit.h"
 
+/* we need md5 hashing algorithm to calculate Gravatar URL */
+#include <openssl/md5.h>
+
+/* This is the URL for Gravatar.
+ * Starting with double slash makes it automatically use the right protocol,
+ * e.g. https for cgit on encrypted sites. The default parameters make this
+ * fetch 16x16 pixel images, with "awesome generated, 8-bit arcade-style
+ * pixelated faces".
+ * https://en.gravatar.com/site/implement/images/ */
+#define GRAVATAR_URL "//www.gravatar.com/avatar/%s?s=16&d=retro"
+
 /*
  * url syntax: [repo ['/' cmd [ '/' path]]]
  *   repo: any valid repo url, may contain '/'
@@ -133,8 +144,10 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
 	ret->commit = commit;
 	ret->author = NULL;
 	ret->author_email = NULL;
+	ret->author_gravatar = NULL;
 	ret->committer = NULL;
 	ret->committer_email = NULL;
+	ret->committer_gravatar = NULL;
 	ret->subject = NULL;
 	ret->msg = NULL;
 	ret->msg_encoding = NULL;
@@ -155,11 +168,17 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
 			&ret->author_date);
 	}
 
+	if (ctx.cfg.enable_gravatar && ret->author_email != NULL)
+		ret->author_gravatar = cgit_get_gravatar(ret->author_email);
+
 	if (p && !strncmp(p, "committer ", 9)) {
 		p = parse_user(p + 9, &ret->committer, &ret->committer_email,
 			&ret->committer_date);
 	}
 
+	if (ctx.cfg.enable_gravatar && ret->committer_email != NULL)
+		ret->committer_gravatar = cgit_get_gravatar(ret->committer_email);
+
 	if (p && !strncmp(p, "encoding ", 9)) {
 		p += 9;
 		t = strchr(p, '\n');
@@ -230,6 +249,7 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
 	ret = xmalloc(sizeof(*ret));
 	ret->tagger = NULL;
 	ret->tagger_email = NULL;
+	ret->tagger_gravatar = NULL;
 	ret->tagger_date = 0;
 	ret->msg = NULL;
 
@@ -249,6 +269,9 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
 		}
 	}
 
+	if (ctx.cfg.enable_gravatar && ret->tagger_email != NULL)
+		ret->tagger_gravatar = cgit_get_gravatar(ret->tagger_email);
+
 	// skip empty lines between headers and message
 	while (p && *p == '\n')
 		p++;
@@ -258,3 +281,30 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
 	free(data);
 	return ret;
 }
+
+char *cgit_get_gravatar(const char *email)
+{
+	unsigned char digest[MD5_DIGEST_LENGTH];
+	char hex[MD5_DIGEST_LENGTH * 2 + 1], *lower, *tmp;
+	char *gravatar;
+
+	gravatar = malloc(strlen(GRAVATAR_URL) + MD5_DIGEST_LENGTH * 2 + 1);
+
+	/* duplicate to lower and skip brackets! */
+	lower = strdup(email + 1);
+	lower[strlen(lower) - 1] = '\0';
+
+	/* make the chars lower case */
+	for (tmp = lower; *tmp; ++tmp)
+		*tmp = tolower(*tmp);
+
+	MD5((unsigned char *)lower, strlen(lower), digest);
+
+	str_to_hex(hex, digest, MD5_DIGEST_LENGTH);
+
+	sprintf(gravatar, GRAVATAR_URL, hex);
+
+	free(lower);
+
+	return gravatar;
+}
diff --git a/shared.c b/shared.c
index 919a99e..a383dfa 100644
--- a/shared.c
+++ b/shared.c
@@ -93,8 +93,12 @@ void *cgit_free_commitinfo(struct commitinfo *info)
 {
 	free(info->author);
 	free(info->author_email);
+	if (info->author_gravatar)
+		free(info->author_gravatar);
 	free(info->committer);
 	free(info->committer_email);
+	if (info->committer_gravatar)
+		free(info->committer_gravatar);
 	free(info->subject);
 	free(info->msg);
 	free(info->msg_encoding);
@@ -204,6 +208,8 @@ static void cgit_free_taginfo(struct taginfo *tag)
 		free(tag->tagger);
 	if (tag->tagger_email)
 		free(tag->tagger_email);
+	if (tag->tagger_gravatar)
+		free(tag->tagger_gravatar);
 	if (tag->msg)
 		free(tag->msg);
 	free(tag);
@@ -588,3 +594,20 @@ char *expand_macros(const char *txt)
 	}
 	return result;
 }
+
+/* gets a string representing the binary data. dst_str must have a
+ * size of at least src_len * 2 + 1 bytes. */
+void str_to_hex(char *dst_str, const unsigned char *src_bytes,
+		size_t src_len) {
+	const char *hex = "0123456789abcdef";
+	int n;
+
+	for (n = 0; n < src_len; ++n) {
+		unsigned char val = *src_bytes++;
+
+		*dst_str++ = hex[val >> 4];
+		*dst_str++ = hex[val & 0xf];
+	}
+
+	*dst_str = 0;
+}
diff --git a/ui-commit.c b/ui-commit.c
index ef85a49..4fa5b83 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -44,6 +44,11 @@ void cgit_print_commit(char *hex, const char *prefix)
 	cgit_print_diff_ctrls();
 	html("<table summary='commit info' class='commit-info'>\n");
 	html("<tr><th>author</th><td>");
+	if (ctx.cfg.enable_gravatar && info->author_gravatar) {
+		html("<img src='");
+		html_txt(info->author_gravatar);
+		html("' width=16 height=16 alt='Gravatar' /> ");
+	}
 	html_txt(info->author);
 	if (!ctx.cfg.noplainemail) {
 		html(" ");
@@ -53,6 +58,11 @@ void cgit_print_commit(char *hex, const char *prefix)
 	cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time);
 	html("</td></tr>\n");
 	html("<tr><th>committer</th><td>");
+	if (ctx.cfg.enable_gravatar && info->committer_gravatar) {
+		html("<img src='");
+		html_txt(info->committer_gravatar);
+		html("' width=16 height=16 alt='Gravatar' /> ");
+	}
 	html_txt(info->committer);
 	if (!ctx.cfg.noplainemail) {
 		html(" ");
diff --git a/ui-log.c b/ui-log.c
index c154f69..24a5c47 100644
--- a/ui-log.c
+++ b/ui-log.c
@@ -168,6 +168,11 @@ static void print_commit(struct commit *commit, struct rev_info *revs)
 			 sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);
 	show_commit_decorations(commit);
 	html("</td><td>");
+	if (ctx.cfg.enable_gravatar && info->author_gravatar) {
+		html("<img src='");
+		html_txt(info->author_gravatar);
+		html("' width=16 height=16 alt='Gravatar' /> ");
+	}
 	html_txt(info->author);
 
 	if (revs->graph) {
diff --git a/ui-refs.c b/ui-refs.c
index 0ae0612..5e6dda9 100644
--- a/ui-refs.c
+++ b/ui-refs.c
@@ -77,6 +77,11 @@ static int print_branch(struct refinfo *ref)
 	if (ref->object->type == OBJ_COMMIT) {
 		cgit_commit_link(info->subject, NULL, NULL, name, NULL, NULL, 0);
 		html("</td><td>");
+		if (ctx.cfg.enable_gravatar && info->author_gravatar) {
+			html("<img src='");
+			html_txt(info->author_gravatar);
+			html("' width=16 height=16 alt='Gravatar' /> ");
+		}
 		html_txt(info->author);
 		html("</td><td colspan='2'>");
 		cgit_print_age(info->commit->date, -1, NULL);
@@ -154,6 +159,11 @@ static int print_tag(struct refinfo *ref)
 		cgit_object_link(obj);
 	html("</td><td>");
 	if (info) {
+		if (ctx.cfg.enable_gravatar && info->tagger_gravatar) {
+			html("<img src='");
+			html_txt(info->tagger_gravatar);
+			html("' width=16 height=16 alt='Gravatar' /> ");
+		}
 		if (info->tagger)
 			html(info->tagger);
 	} else if (ref->object->type == OBJ_COMMIT) {
diff --git a/ui-tag.c b/ui-tag.c
index aea7958..865d6d7 100644
--- a/ui-tag.c
+++ b/ui-tag.c
@@ -77,6 +77,11 @@ void cgit_print_tag(char *revname)
 		}
 		if (info->tagger) {
 			html("<tr><td>tagged by</td><td>");
+			if (ctx.cfg.enable_gravatar && info->tagger_gravatar) {
+				html("<img src='");
+				html_txt(info->tagger_gravatar);
+				html("' width=16 height=16 alt='Gravatar' /> ");
+			}
 			html_txt(info->tagger);
 			if (info->tagger_email && !ctx.cfg.noplainemail) {
 				html(" ");
-- 
1.8.5.2



^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2014-01-09 15:13 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-27 15:17 [PATCH 1/1] enable cgit to show gravatar for author, committer and tagger mail
2013-11-27 16:17 ` list
2013-11-27 16:37 ` john
2013-11-27 20:51   ` list
2013-11-27 21:00     ` john
2013-11-27 16:46 ` lekensteyn
2013-11-27 20:59   ` list
2013-11-27 21:14     ` mail
2013-11-27 22:11       ` lekensteyn
2013-11-27 22:59         ` list
2013-11-27 23:00           ` mail
2014-01-08 15:12 [RESEND PATCH " Jason
2014-01-08 15:23 ` [PATCH " mail
2014-01-08 15:56   ` Jason
2014-01-09  8:52     ` mail
2014-01-09 15:13       ` Jason
2014-01-08 16:00   ` Jason
2014-01-09  9:13     ` mail

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).