{"schema":"libjg2-1",
"vpath":"/git/",
"avatar":"/git/avatar/",
"alang":"",
"gen_ut":1745906578,
"reponame":"cgit",
"desc":"CGI gitweb",
"owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://warmcat.com/repo/cgit",
"f":3,
"items": [
{"schema":"libjg2-1",
"cid":"440437d17485a0627f0d73de06702231",
"commit": {"type":"commit",
"time": 1530589916,
"time_ofs": 480,
"oid_tree": { "oid": "7a6fc22f39356ad8953f440a0c7d247b43490d2f", "alias": []},
"oid":{ "oid": "8e0d0542c942f32a223e23e357691dd9b0702fd2", "alias": [ "refs/heads/small-features"]},
"msg": "native inline gravatar",
"sig_commit": { "git_time": { "time": 1530589916, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },
"sig_author": { "git_time": { "time": 1530589916, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" }},
"body": "native inline gravatar\n\nThis adds native inline gravatar images where cgit\nalready produces names and emails. Its server\nload is minimal compared to using an external filter.\nBy using a simple caching scheme, it reduces the\nnumber of md5 digest computations needed by reusing\nthe last result if the email is the same as is\noften the case with patch series.\n\nSet\n\ngravatar\u003d1\n\nin config to enable it.\n\nAt the time of writing, libravatar is shutting down in\n2 months, so it's not targeted.\n\nhttps://blog.libravatar.org/posts/Libravatar.org_is_shutting_down_on_2018-09-01/\n\nIt duplicates the css and style used on the cgit site.\n\nGeneration of the log view normally involves 50 x invocations\nof the email-filter, even for lua that is expensive if your site\nis busy.\n\nThis implementation stashes the last email + md5 result it\nprocessed, on the basis patches often come in a series from the\nsame author. If so, it can skip the md5 compuatation. On\nthe first page of local cgit tree this reduces the number of md5s\nin the 50-entry log list to 12, without needing a more complex cache.\n\nSigned-off-by: Andy Green \u003candy@warmcat.com\u003e\n"
,
"diff": "diff --git a/cgit.c b/cgit.c\nindex 2d42e04..c938719 100644\n--- a/cgit.c\n+++ b/cgit.c\n@@ -153,6 +153,8 @@ static void config_cb(const char *name, const char *value)\n \t\tctx.cfg.virtual_root \u003d ensure_end(value, '/');\n \telse if (!strcmp(name, \u0022noplainemail\u0022))\n \t\tctx.cfg.noplainemail \u003d atoi(value);\n+\telse if (!strcmp(name, \u0022gravatar\u0022))\n+\t\tctx.cfg.gravatar \u003d atoi(value);\n \telse if (!strcmp(name, \u0022noheader\u0022))\n \t\tctx.cfg.noheader \u003d atoi(value);\n \telse if (!strcmp(name, \u0022snapshots\u0022))\ndiff --git a/cgit.css b/cgit.css\nindex 30c480a..cf369ed 100644\n--- a/cgit.css\n+++ b/cgit.css\n@@ -900,3 +900,33 @@ div#cgit table.ssdiff td.space {\n div#cgit table.ssdiff td.space div {\n \tmin-height: 3em;\n }\n+\n+div#cgit span.libravatar img.onhover {\n+ display: none;\n+ border: 1px solid gray;\n+ padding: 0px;\n+ -webkit-border-radius: 4px;\n+ -moz-border-radius: 4px;\n+ border-radius: 4px;\n+ width: 128px;\n+ height: 128px;\n+}\n+\n+div#cgit span.libravatar img.inline {\n+ -webkit-border-radius: 3px;\n+ -moz-border-radius: 3px;\n+ border-radius: 3px;\n+ width: 13px;\n+ height: 13px;\n+ margin-right: 0.2em;\n+ opacity: 0.6;\n+}\n+\n+div#cgit span.libravatar:hover \u003e img.onhover {\n+ display: block;\n+ position: absolute;\n+ margin-left: 1.5em;\n+ background-color: #eeeeee;\n+ box-shadow: 2px 2px 7px rgba(100,100,100,0.75);\n+}\n+\ndiff --git a/cgit.h b/cgit.h\nindex abb8515..b009328 100644\n--- a/cgit.h\n+++ b/cgit.h\n@@ -239,6 +239,7 @@ struct cgit_config {\n \tint enable_html_serving;\n \tint enable_tree_linenumbers;\n \tint enable_git_config;\n+\tint gravatar;\n \tint local_time;\n \tint max_atom_items;\n \tint max_repo_count;\n@@ -392,4 +393,7 @@ extern char *expand_macros(const char *txt);\n \n extern char *get_mimetype_for_filename(const char *filename);\n \n+extern int cgit_md5( const unsigned char *input, size_t ilen,\n+ unsigned char output[16] );\n+\n #endif /* CGIT_H */\ndiff --git a/cgit.mk b/cgit.mk\nindex 3fcc1ca..b3195f4 100644\n--- a/cgit.mk\n+++ b/cgit.mk\n@@ -73,6 +73,7 @@ CGIT_OBJ_NAMES +\u003d cmd.o\n CGIT_OBJ_NAMES +\u003d configfile.o\n CGIT_OBJ_NAMES +\u003d filter.o\n CGIT_OBJ_NAMES +\u003d html.o\n+CGIT_OBJ_NAMES +\u003d md5.o\n CGIT_OBJ_NAMES +\u003d parsing.o\n CGIT_OBJ_NAMES +\u003d scan-tree.o\n CGIT_OBJ_NAMES +\u003d shared.o\ndiff --git a/cgitrc.5.txt b/cgitrc.5.txt\nindex 4aadc59..00900b1 100644\n--- a/cgitrc.5.txt\n+++ b/cgitrc.5.txt\n@@ -227,6 +227,12 @@ footer::\n \tverbatim at the bottom of all pages (i.e. it replaces the standard\n \t\u0022generated by...\u0022 message. Default value: none.\n \n+gravatar::\n+\tIf set to nonzero, enables the native generation of gravatar images\n+\tinline with names and emails. This should not be set if you are\n+\tusing \u0022email-filter\u0022 to similarly produce the images. However this\n+\toption is cheaper serverside than using an external script.\n+\n head-include::\n \tThe content of the file specified with this option will be included\n \tverbatim in the html HEAD section on all pages. Default value: none.\ndiff --git a/html.c b/html.c\nindex 7f81965..7cdea72 100644\n--- a/html.c\n+++ b/html.c\n@@ -10,6 +10,9 @@\n #include \u0022html.h\u0022\n #include \u0022url.h\u0022\n \n+char last_email[128];\n+char last_md5_hex[(2 * 16) + 1];\n+\n /* Percent-encoding of each character, except: a-zA-Z0-9!$()*,./:;@- */\n static const char* url_escape_table[256] \u003d {\n \t\u0022%00\u0022, \u0022%01\u0022, \u0022%02\u0022, \u0022%03\u0022, \u0022%04\u0022, \u0022%05\u0022, \u0022%06\u0022, \u0022%07\u0022,\n@@ -342,3 +345,53 @@ void http_parse_querystring(const char *txt, void (*fn)(const char *name, const \n \t\tfree(name);\n \t}\n }\n+\n+static const char *hex \u003d \u00220123456789abcdef\u0022;\n+\n+void html_email(const char *name, const char *email)\n+{\n+\tunsigned char *md5_in \u003d (unsigned char *)email,\n+\t\t md5_out[16];\n+\tchar *p;\n+\tint len, n;\n+\n+\tif (!ctx.cfg.gravatar) {\n+\t\thtml_txt(email);\n+\n+\t\treturn;\n+\t}\n+\n+\t/* patches often come in series... */\n+\tif (!strcmp(email, last_email))\n+\t\tgoto emit;\n+\n+\tif (*email \u003d\u003d '\u003c')\n+\t\tmd5_in++;\n+\n+\tlen \u003d strlen((char *)md5_in);\n+\n+\tif (md5_in[len - 1] \u003d\u003d '\u003e')\n+\t\tlen --;\n+\n+\tcgit_md5(md5_in, len, md5_out);\n+\tp \u003d last_md5_hex;\n+\tfor (n \u003d 0; n \u003c sizeof(md5_out); n++) {\n+\t\t*p++ \u003d hex[md5_out[n] \u003e\u003e 4];\n+\t\t*p++ \u003d hex[md5_out[n] \u0026 0xf];\n+\t}\n+\t*p \u003d '\u005c0';\n+\n+\tstrncpy(last_email, email, sizeof(last_email) - 1);\n+\tlast_email[sizeof(last_email) - 1] \u003d '\u005c0';\n+\n+emit:\n+\thtmlf(\u0022\u003cspan class\u003d'libravatar'\u003e\u0022\n+\t \u0022\u003cimg class\u003d'inline' src\u003d'//www.gravatar.com/avatar/%s\u0022\n+\t \u0022?s\u003d13\u0026amp;d\u003dretro' width\u003d'13' height\u003d'13' alt\u003d'Gravatar' /\u003e\u0022\n+\t \u0022\u003cimg class\u003d'onhover' src\u003d'//www.gravatar.com/avatar/%s\u0022\n+\t \u0022?s\u003d128\u0026amp;d\u003dretro'/\u003e\u0022, last_md5_hex, last_md5_hex);\n+\tif (name)\n+\t\thtml_txt(name);\n+\telse\n+\t\thtml_txt(email);\n+}\ndiff --git a/html.h b/html.h\nindex fa4de77..971bcae 100644\n--- a/html.h\n+++ b/html.h\n@@ -31,7 +31,7 @@ extern void html_link_open(const char *url, const char *title, const char *class\n extern void html_link_close(void);\n extern void html_fileperm(unsigned short mode);\n extern int html_include(const char *filename);\n-\n+extern void html_email(const char *name, const char *email);\n extern void http_parse_querystring(const char *txt, void (*fn)(const char *name, const char *value));\n \n #endif /* HTML_H */\ndiff --git a/md5.c b/md5.c\nnew file mode 100644\nindex 0000000..74c1b67\n--- /dev/null\n+++ b/md5.c\n@@ -0,0 +1,288 @@\n+/*\n+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved\n+ * SPDX-License-Identifier: Apache-2.0\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \u0022License\u0022); you may\n+ * not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \u0022AS IS\u0022 BASIS, WITHOUT\n+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+#include \u003cstdint.h\u003e\n+#include \u003cstddef.h\u003e\n+#include \u003cstring.h\u003e\n+#include \u003cstdio.h\u003e\n+\n+typedef struct {\n+ uint32_t total[2]; /*!\u003c number of bytes processed */\n+ uint32_t state[4]; /*!\u003c intermediate digest state */\n+ unsigned char buffer[64]; /*!\u003c data block being processed */\n+} mbedtls_md5_context;\n+\n+/*\n+ * The MD5 algorithm was designed by Ron Rivest in 1991.\n+ *\n+ * http://www.ietf.org/rfc/rfc1321.txt\n+ */\n+\n+#define GET_UINT32_LE(n,b,i) \u005c\n+{ \u005c\n+ (n) \u003d ( (uint32_t) (b)[(i) ] ) \u005c\n+ | ( (uint32_t) (b)[(i) + 1] \u003c\u003c 8 ) \u005c\n+ | ( (uint32_t) (b)[(i) + 2] \u003c\u003c 16 ) \u005c\n+ | ( (uint32_t) (b)[(i) + 3] \u003c\u003c 24 ); \u005c\n+}\n+\n+#define PUT_UINT32_LE(n,b,i) \u005c\n+{ \u005c\n+ (b)[(i) ] \u003d (unsigned char) ( ( (n) ) \u0026 0xFF ); \u005c\n+ (b)[(i) + 1] \u003d (unsigned char) ( ( (n) \u003e\u003e 8 ) \u0026 0xFF ); \u005c\n+ (b)[(i) + 2] \u003d (unsigned char) ( ( (n) \u003e\u003e 16 ) \u0026 0xFF ); \u005c\n+ (b)[(i) + 3] \u003d (unsigned char) ( ( (n) \u003e\u003e 24 ) \u0026 0xFF ); \u005c\n+}\n+\n+static int\n+mbedtls_internal_md5_process( mbedtls_md5_context *ctx,\n+ const unsigned char data[64] )\n+{\n+ uint32_t X[16], A, B, C, D;\n+\n+ GET_UINT32_LE( X[ 0], data, 0 );\n+ GET_UINT32_LE( X[ 1], data, 4 );\n+ GET_UINT32_LE( X[ 2], data, 8 );\n+ GET_UINT32_LE( X[ 3], data, 12 );\n+ GET_UINT32_LE( X[ 4], data, 16 );\n+ GET_UINT32_LE( X[ 5], data, 20 );\n+ GET_UINT32_LE( X[ 6], data, 24 );\n+ GET_UINT32_LE( X[ 7], data, 28 );\n+ GET_UINT32_LE( X[ 8], data, 32 );\n+ GET_UINT32_LE( X[ 9], data, 36 );\n+ GET_UINT32_LE( X[10], data, 40 );\n+ GET_UINT32_LE( X[11], data, 44 );\n+ GET_UINT32_LE( X[12], data, 48 );\n+ GET_UINT32_LE( X[13], data, 52 );\n+ GET_UINT32_LE( X[14], data, 56 );\n+ GET_UINT32_LE( X[15], data, 60 );\n+\n+#define S(x,n) ((x \u003c\u003c n) | ((x \u0026 0xFFFFFFFF) \u003e\u003e (32 - n)))\n+\n+#define P(a,b,c,d,k,s,t) \u005c\n+{ \u005c\n+ a +\u003d F(b,c,d) + X[k] + t; a \u003d S(a,s) + b; \u005c\n+}\n+\n+ A \u003d ctx-\u003estate[0];\n+ B \u003d ctx-\u003estate[1];\n+ C \u003d ctx-\u003estate[2];\n+ D \u003d ctx-\u003estate[3];\n+\n+#define F(x,y,z) (z ^ (x \u0026 (y ^ z)))\n+\n+ P( A, B, C, D, 0, 7, 0xD76AA478 );\n+ P( D, A, B, C, 1, 12, 0xE8C7B756 );\n+ P( C, D, A, B, 2, 17, 0x242070DB );\n+ P( B, C, D, A, 3, 22, 0xC1BDCEEE );\n+ P( A, B, C, D, 4, 7, 0xF57C0FAF );\n+ P( D, A, B, C, 5, 12, 0x4787C62A );\n+ P( C, D, A, B, 6, 17, 0xA8304613 );\n+ P( B, C, D, A, 7, 22, 0xFD469501 );\n+ P( A, B, C, D, 8, 7, 0x698098D8 );\n+ P( D, A, B, C, 9, 12, 0x8B44F7AF );\n+ P( C, D, A, B, 10, 17, 0xFFFF5BB1 );\n+ P( B, C, D, A, 11, 22, 0x895CD7BE );\n+ P( A, B, C, D, 12, 7, 0x6B901122 );\n+ P( D, A, B, C, 13, 12, 0xFD987193 );\n+ P( C, D, A, B, 14, 17, 0xA679438E );\n+ P( B, C, D, A, 15, 22, 0x49B40821 );\n+\n+#undef F\n+\n+#define F(x,y,z) (y ^ (z \u0026 (x ^ y)))\n+\n+ P( A, B, C, D, 1, 5, 0xF61E2562 );\n+ P( D, A, B, C, 6, 9, 0xC040B340 );\n+ P( C, D, A, B, 11, 14, 0x265E5A51 );\n+ P( B, C, D, A, 0, 20, 0xE9B6C7AA );\n+ P( A, B, C, D, 5, 5, 0xD62F105D );\n+ P( D, A, B, C, 10, 9, 0x02441453 );\n+ P( C, D, A, B, 15, 14, 0xD8A1E681 );\n+ P( B, C, D, A, 4, 20, 0xE7D3FBC8 );\n+ P( A, B, C, D, 9, 5, 0x21E1CDE6 );\n+ P( D, A, B, C, 14, 9, 0xC33707D6 );\n+ P( C, D, A, B, 3, 14, 0xF4D50D87 );\n+ P( B, C, D, A, 8, 20, 0x455A14ED );\n+ P( A, B, C, D, 13, 5, 0xA9E3E905 );\n+ P( D, A, B, C, 2, 9, 0xFCEFA3F8 );\n+ P( C, D, A, B, 7, 14, 0x676F02D9 );\n+ P( B, C, D, A, 12, 20, 0x8D2A4C8A );\n+\n+#undef F\n+\n+#define F(x,y,z) (x ^ y ^ z)\n+\n+ P( A, B, C, D, 5, 4, 0xFFFA3942 );\n+ P( D, A, B, C, 8, 11, 0x8771F681 );\n+ P( C, D, A, B, 11, 16, 0x6D9D6122 );\n+ P( B, C, D, A, 14, 23, 0xFDE5380C );\n+ P( A, B, C, D, 1, 4, 0xA4BEEA44 );\n+ P( D, A, B, C, 4, 11, 0x4BDECFA9 );\n+ P( C, D, A, B, 7, 16, 0xF6BB4B60 );\n+ P( B, C, D, A, 10, 23, 0xBEBFBC70 );\n+ P( A, B, C, D, 13, 4, 0x289B7EC6 );\n+ P( D, A, B, C, 0, 11, 0xEAA127FA );\n+ P( C, D, A, B, 3, 16, 0xD4EF3085 );\n+ P( B, C, D, A, 6, 23, 0x04881D05 );\n+ P( A, B, C, D, 9, 4, 0xD9D4D039 );\n+ P( D, A, B, C, 12, 11, 0xE6DB99E5 );\n+ P( C, D, A, B, 15, 16, 0x1FA27CF8 );\n+ P( B, C, D, A, 2, 23, 0xC4AC5665 );\n+\n+#undef F\n+\n+#define F(x,y,z) (y ^ (x | ~z))\n+\n+ P( A, B, C, D, 0, 6, 0xF4292244 );\n+ P( D, A, B, C, 7, 10, 0x432AFF97 );\n+ P( C, D, A, B, 14, 15, 0xAB9423A7 );\n+ P( B, C, D, A, 5, 21, 0xFC93A039 );\n+ P( A, B, C, D, 12, 6, 0x655B59C3 );\n+ P( D, A, B, C, 3, 10, 0x8F0CCC92 );\n+ P( C, D, A, B, 10, 15, 0xFFEFF47D );\n+ P( B, C, D, A, 1, 21, 0x85845DD1 );\n+ P( A, B, C, D, 8, 6, 0x6FA87E4F );\n+ P( D, A, B, C, 15, 10, 0xFE2CE6E0 );\n+ P( C, D, A, B, 6, 15, 0xA3014314 );\n+ P( B, C, D, A, 13, 21, 0x4E0811A1 );\n+ P( A, B, C, D, 4, 6, 0xF7537E82 );\n+ P( D, A, B, C, 11, 10, 0xBD3AF235 );\n+ P( C, D, A, B, 2, 15, 0x2AD7D2BB );\n+ P( B, C, D, A, 9, 21, 0xEB86D391 );\n+\n+#undef F\n+\n+ ctx-\u003estate[0] +\u003d A;\n+ ctx-\u003estate[1] +\u003d B;\n+ ctx-\u003estate[2] +\u003d C;\n+ ctx-\u003estate[3] +\u003d D;\n+\n+ return( 0 );\n+}\n+\n+static int\n+mbedtls_md5_update_ret( mbedtls_md5_context *ctx,\n+ const unsigned char *input,\n+ size_t ilen )\n+{\n+ int ret;\n+ size_t fill;\n+ uint32_t left;\n+\n+ if( ilen \u003d\u003d 0 )\n+ return( 0 );\n+\n+ left \u003d ctx-\u003etotal[0] \u0026 0x3F;\n+ fill \u003d 64 - left;\n+\n+ ctx-\u003etotal[0] +\u003d (uint32_t) ilen;\n+ ctx-\u003etotal[0] \u0026\u003d 0xFFFFFFFF;\n+\n+ if( ctx-\u003etotal[0] \u003c (uint32_t) ilen )\n+ ctx-\u003etotal[1]++;\n+\n+ if( left \u0026\u0026 ilen \u003e\u003d fill )\n+ {\n+ memcpy( (void *) (ctx-\u003ebuffer + left), input, fill );\n+ if( ( ret \u003d mbedtls_internal_md5_process( ctx, ctx-\u003ebuffer ) ) !\u003d 0 )\n+ return( ret );\n+\n+ input +\u003d fill;\n+ ilen -\u003d fill;\n+ left \u003d 0;\n+ }\n+\n+ while( ilen \u003e\u003d 64 )\n+ {\n+ if( ( ret \u003d mbedtls_internal_md5_process( ctx, input ) ) !\u003d 0 )\n+ return( ret );\n+\n+ input +\u003d 64;\n+ ilen -\u003d 64;\n+ }\n+\n+ if( ilen \u003e 0 )\n+ {\n+ memcpy( (void *) (ctx-\u003ebuffer + left), input, ilen );\n+ }\n+\n+ return( 0 );\n+}\n+\n+static const unsigned char md5_padding[64] \u003d\n+{\n+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n+};\n+\n+static int\n+mbedtls_md5_finish_ret( mbedtls_md5_context *ctx,\n+ unsigned char output[16] )\n+{\n+ int ret;\n+ uint32_t last, padn;\n+ uint32_t high, low;\n+ unsigned char msglen[8];\n+\n+ high \u003d ( ctx-\u003etotal[0] \u003e\u003e 29 )\n+ | ( ctx-\u003etotal[1] \u003c\u003c 3 );\n+ low \u003d ( ctx-\u003etotal[0] \u003c\u003c 3 );\n+\n+ PUT_UINT32_LE( low, msglen, 0 );\n+ PUT_UINT32_LE( high, msglen, 4 );\n+\n+ last \u003d ctx-\u003etotal[0] \u0026 0x3F;\n+ padn \u003d ( last \u003c 56 ) ? ( 56 - last ) : ( 120 - last );\n+\n+ if( ( ret \u003d mbedtls_md5_update_ret( ctx, md5_padding, padn ) ) !\u003d 0 )\n+ return( ret );\n+\n+ if( ( ret \u003d mbedtls_md5_update_ret( ctx, msglen, 8 ) ) !\u003d 0 )\n+ return( ret );\n+\n+ PUT_UINT32_LE( ctx-\u003estate[0], output, 0 );\n+ PUT_UINT32_LE( ctx-\u003estate[1], output, 4 );\n+ PUT_UINT32_LE( ctx-\u003estate[2], output, 8 );\n+ PUT_UINT32_LE( ctx-\u003estate[3], output, 12 );\n+\n+ return( 0 );\n+}\n+\n+int cgit_md5( const unsigned char *input, size_t ilen,\n+ unsigned char output[16] )\n+{\n+ int ret;\n+ mbedtls_md5_context ctx;\n+\n+ memset( \u0026ctx, 0, sizeof(ctx) );\n+\n+ ctx.state[0] \u003d 0x67452301;\n+ ctx.state[1] \u003d 0xEFCDAB89;\n+ ctx.state[2] \u003d 0x98BADCFE;\n+ ctx.state[3] \u003d 0x10325476;\n+\n+ if( ( ret \u003d mbedtls_md5_update_ret( \u0026ctx, input, ilen ) ) !\u003d 0 )\n+ goto exit;\n+\n+ ret \u003d mbedtls_md5_finish_ret( \u0026ctx, output );\n+\n+exit:\n+ return( ret );\n+}\ndiff --git a/ui-commit.c b/ui-commit.c\nindex 995cb93..30655b9 100644\n--- a/ui-commit.c\n+++ b/ui-commit.c\n@@ -51,7 +51,7 @@ void cgit_print_commit(char *hex, const char *prefix)\n \thtml_txt(info-\u003eauthor);\n \tif (!ctx.cfg.noplainemail) {\n \t\thtml(\u0022 \u0022);\n-\t\thtml_txt(info-\u003eauthor_email);\n+\t\thtml_email(NULL, info-\u003eauthor_email);\n \t}\n \tcgit_close_filter(ctx.repo-\u003eemail_filter);\n \thtml(\u0022\u003c/td\u003e\u003ctd class\u003d'right'\u003e\u0022);\n@@ -63,7 +63,7 @@ void cgit_print_commit(char *hex, const char *prefix)\n \thtml_txt(info-\u003ecommitter);\n \tif (!ctx.cfg.noplainemail) {\n \t\thtml(\u0022 \u0022);\n-\t\thtml_txt(info-\u003ecommitter_email);\n+\t\thtml_email(NULL, info-\u003ecommitter_email);\n \t}\n \tcgit_close_filter(ctx.repo-\u003eemail_filter);\n \thtml(\u0022\u003c/td\u003e\u003ctd class\u003d'right'\u003e\u0022);\ndiff --git a/ui-log.c b/ui-log.c\nindex d696e20..37f603d 100644\n--- a/ui-log.c\n+++ b/ui-log.c\n@@ -242,7 +242,7 @@ static void print_commit(struct commit *commit, struct rev_info *revs)\n \tshow_commit_decorations(commit);\n \thtml(\u0022\u003c/td\u003e\u003ctd\u003e\u0022);\n \tcgit_open_filter(ctx.repo-\u003eemail_filter, info-\u003eauthor_email, \u0022log\u0022);\n-\thtml_txt(info-\u003eauthor);\n+\thtml_email(info-\u003eauthor, info-\u003eauthor_email);\n \tcgit_close_filter(ctx.repo-\u003eemail_filter);\n \n \tif (revs-\u003egraph) {\ndiff --git a/ui-refs.c b/ui-refs.c\nindex 2ec3858..2d7b625 100644\n--- a/ui-refs.c\n+++ b/ui-refs.c\n@@ -70,7 +70,7 @@ static int print_branch(struct refinfo *ref)\n \t\tcgit_commit_link(info-\u003esubject, NULL, NULL, name, NULL, NULL);\n \t\thtml(\u0022\u003c/td\u003e\u003ctd\u003e\u0022);\n \t\tcgit_open_filter(ctx.repo-\u003eemail_filter, info-\u003eauthor_email, \u0022refs\u0022);\n-\t\thtml_txt(info-\u003eauthor);\n+\t\thtml_email(info-\u003eauthor, info-\u003eauthor_email);\n \t\tcgit_close_filter(ctx.repo-\u003eemail_filter);\n \t\thtml(\u0022\u003c/td\u003e\u003ctd colspan\u003d'2'\u003e\u0022);\n \t\tcgit_print_age(info-\u003ecommitter_date, info-\u003ecommitter_tz, -1);\n@@ -116,12 +116,12 @@ static int print_tag(struct refinfo *ref)\n \tif (info) {\n \t\tif (info-\u003etagger) {\n \t\t\tcgit_open_filter(ctx.repo-\u003eemail_filter, info-\u003etagger_email, \u0022refs\u0022);\n-\t\t\thtml_txt(info-\u003etagger);\n+\t\t\thtml_email(info-\u003etagger, info-\u003etagger_email);\n \t\t\tcgit_close_filter(ctx.repo-\u003eemail_filter);\n \t\t}\n \t} else if (ref-\u003eobject-\u003etype \u003d\u003d OBJ_COMMIT) {\n \t\tcgit_open_filter(ctx.repo-\u003eemail_filter, ref-\u003ecommit-\u003eauthor_email, \u0022refs\u0022);\n-\t\thtml_txt(ref-\u003ecommit-\u003eauthor);\n+\t\thtml_email(ref-\u003ecommit-\u003eauthor, ref-\u003ecommit-\u003eauthor_email);\n \t\tcgit_close_filter(ctx.repo-\u003eemail_filter);\n \t}\n \thtml(\u0022\u003c/td\u003e\u003ctd colspan\u003d'2'\u003e\u0022);\ndiff --git a/ui-tag.c b/ui-tag.c\nindex 2c96c37..387fadf 100644\n--- a/ui-tag.c\n+++ b/ui-tag.c\n@@ -86,7 +86,7 @@ void cgit_print_tag(char *revname)\n \t\t\thtml_txt(info-\u003etagger);\n \t\t\tif (info-\u003etagger_email \u0026\u0026 !ctx.cfg.noplainemail) {\n \t\t\t\thtml(\u0022 \u0022);\n-\t\t\t\thtml_txt(info-\u003etagger_email);\n+\t\t\t\thtml_email(NULL, info-\u003etagger_email);\n \t\t\t}\n \t\t\tcgit_close_filter(ctx.repo-\u003eemail_filter);\n \t\t\thtml(\u0022\u003c/td\u003e\u003c/tr\u003e\u005cn\u0022);\n","s":{"c":1745906578,"u": 8779}}
],"g": 11475,"chitpc": 0,"ehitpc": 0,"indexed":0
,
"ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "0000"}