-rw-r--r-- | cgit.c | 2 | ||||
-rw-r--r-- | cgit.h | 1 | ||||
-rw-r--r-- | cgitrc.5.txt | 4 | ||||
-rw-r--r-- | ui-atom.c | 2 | ||||
-rw-r--r-- | ui-commit.c | 12 | ||||
-rw-r--r-- | ui-patch.c | 6 | ||||
-rw-r--r-- | ui-tag.c | 2 | ||||
-rw-r--r-- | ui-tree.c | 8 |
8 files changed, 29 insertions, 8 deletions
@@ -1,157 +1,159 @@ /* cgit.c: cgi for the git scm * * Copyright (C) 2006 Lars Hjemli * * Licensed under GNU General Public License v2 * (see COPYING for full license text) */ #include "cgit.h" #include "cache.h" #include "cmd.h" #include "configfile.h" #include "html.h" #include "ui-shared.h" #include "ui-stats.h" #include "scan-tree.h" const char *cgit_version = CGIT_VERSION; void add_mimetype(const char *name, const char *value) { struct string_list_item *item; item = string_list_insert(xstrdup(name), &ctx.cfg.mimetypes); item->util = xstrdup(value); } void config_cb(const char *name, const char *value) { if (!strcmp(name, "root-title")) ctx.cfg.root_title = xstrdup(value); else if (!strcmp(name, "root-desc")) ctx.cfg.root_desc = xstrdup(value); else if (!strcmp(name, "root-readme")) ctx.cfg.root_readme = xstrdup(value); else if (!strcmp(name, "css")) ctx.cfg.css = xstrdup(value); else if (!strcmp(name, "favicon")) ctx.cfg.favicon = xstrdup(value); else if (!strcmp(name, "footer")) ctx.cfg.footer = xstrdup(value); else if (!strcmp(name, "head-include")) ctx.cfg.head_include = xstrdup(value); else if (!strcmp(name, "header")) ctx.cfg.header = xstrdup(value); else if (!strcmp(name, "logo")) ctx.cfg.logo = xstrdup(value); else if (!strcmp(name, "index-header")) ctx.cfg.index_header = xstrdup(value); else if (!strcmp(name, "index-info")) ctx.cfg.index_info = xstrdup(value); else if (!strcmp(name, "logo-link")) ctx.cfg.logo_link = xstrdup(value); else if (!strcmp(name, "module-link")) ctx.cfg.module_link = xstrdup(value); else if (!strcmp(name, "virtual-root")) { ctx.cfg.virtual_root = trim_end(value, '/'); if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) ctx.cfg.virtual_root = ""; } else if (!strcmp(name, "nocache")) ctx.cfg.nocache = atoi(value); + else if (!strcmp(name, "noplainemail")) + ctx.cfg.noplainemail = atoi(value); else if (!strcmp(name, "noheader")) ctx.cfg.noheader = atoi(value); else if (!strcmp(name, "snapshots")) ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); else if (!strcmp(name, "enable-index-links")) ctx.cfg.enable_index_links = atoi(value); else if (!strcmp(name, "enable-log-filecount")) ctx.cfg.enable_log_filecount = atoi(value); else if (!strcmp(name, "enable-log-linecount")) ctx.cfg.enable_log_linecount = atoi(value); else if (!strcmp(name, "max-stats")) ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); else if (!strcmp(name, "cache-size")) ctx.cfg.cache_size = atoi(value); else if (!strcmp(name, "cache-root")) ctx.cfg.cache_root = xstrdup(value); else if (!strcmp(name, "cache-root-ttl")) ctx.cfg.cache_root_ttl = atoi(value); else if (!strcmp(name, "cache-repo-ttl")) ctx.cfg.cache_repo_ttl = atoi(value); else if (!strcmp(name, "cache-static-ttl")) ctx.cfg.cache_static_ttl = atoi(value); else if (!strcmp(name, "cache-dynamic-ttl")) ctx.cfg.cache_dynamic_ttl = atoi(value); else if (!strcmp(name, "embedded")) ctx.cfg.embedded = atoi(value); else if (!strcmp(name, "max-message-length")) ctx.cfg.max_msg_len = atoi(value); else if (!strcmp(name, "max-repodesc-length")) ctx.cfg.max_repodesc_len = atoi(value); else if (!strcmp(name, "max-repo-count")) ctx.cfg.max_repo_count = atoi(value); else if (!strcmp(name, "max-commit-count")) ctx.cfg.max_commit_count = atoi(value); else if (!strcmp(name, "summary-log")) ctx.cfg.summary_log = atoi(value); else if (!strcmp(name, "summary-branches")) ctx.cfg.summary_branches = atoi(value); else if (!strcmp(name, "summary-tags")) ctx.cfg.summary_tags = atoi(value); else if (!strcmp(name, "agefile")) ctx.cfg.agefile = xstrdup(value); else if (!strcmp(name, "renamelimit")) ctx.cfg.renamelimit = atoi(value); else if (!strcmp(name, "robots")) ctx.cfg.robots = xstrdup(value); else if (!strcmp(name, "clone-prefix")) ctx.cfg.clone_prefix = xstrdup(value); else if (!strcmp(name, "local-time")) ctx.cfg.local_time = atoi(value); else if (!prefixcmp(name, "mimetype.")) add_mimetype(name + 9, value); else if (!strcmp(name, "repo.group")) ctx.cfg.repo_group = xstrdup(value); else if (!strcmp(name, "repo.url")) ctx.repo = cgit_add_repo(value); else if (!strcmp(name, "repo.name")) ctx.repo->name = xstrdup(value); else if (ctx.repo && !strcmp(name, "repo.path")) ctx.repo->path = trim_end(value, '/'); else if (ctx.repo && !strcmp(name, "repo.clone-url")) ctx.repo->clone_url = xstrdup(value); else if (ctx.repo && !strcmp(name, "repo.desc")) ctx.repo->desc = xstrdup(value); else if (ctx.repo && !strcmp(name, "repo.owner")) ctx.repo->owner = xstrdup(value); else if (ctx.repo && !strcmp(name, "repo.defbranch")) ctx.repo->defbranch = xstrdup(value); else if (ctx.repo && !strcmp(name, "repo.snapshots")) ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); else if (ctx.repo && !strcmp(name, "repo.max-stats")) ctx.repo->max_stats = cgit_find_stats_period(value, NULL); else if (ctx.repo && !strcmp(name, "repo.module-link")) ctx.repo->module_link= xstrdup(value); else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { if (*value == '/') ctx.repo->readme = xstrdup(value); else ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); } else if (!strcmp(name, "include")) parse_configfile(value, config_cb); } static void querystring_cb(const char *name, const char *value) { if (!strcmp(name,"r")) { ctx.qry.repo = xstrdup(value); ctx.repo = cgit_get_repoinfo(value); } else if (!strcmp(name, "p")) { ctx.qry.page = xstrdup(value); } else if (!strcmp(name, "url")) { ctx.qry.url = xstrdup(value); @@ -76,179 +76,180 @@ struct cgit_repolist { struct commitinfo { struct commit *commit; char *author; char *author_email; unsigned long author_date; char *committer; char *committer_email; unsigned long committer_date; char *subject; char *msg; char *msg_encoding; }; struct taginfo { char *tagger; char *tagger_email; unsigned long tagger_date; char *msg; }; struct refinfo { const char *refname; struct object *object; union { struct taginfo *tag; struct commitinfo *commit; }; }; struct reflist { struct refinfo **refs; int alloc; int count; }; struct cgit_query { int has_symref; int has_sha1; char *raw; char *repo; char *page; char *search; char *grep; char *head; char *sha1; char *sha2; char *path; char *name; char *mimetype; char *url; char *period; int ofs; int nohead; char *sort; int showmsg; }; struct cgit_config { char *agefile; char *cache_root; char *clone_prefix; char *css; char *favicon; char *footer; char *head_include; char *header; char *index_header; char *index_info; char *logo; char *logo_link; char *module_link; char *repo_group; char *robots; char *root_title; char *root_desc; char *root_readme; char *script_name; char *virtual_root; int cache_size; int cache_dynamic_ttl; int cache_max_create_time; int cache_repo_ttl; int cache_root_ttl; int cache_static_ttl; int embedded; int enable_index_links; int enable_log_filecount; int enable_log_linecount; int local_time; int max_repo_count; int max_commit_count; int max_lock_attempts; int max_msg_len; int max_repodesc_len; int max_stats; int nocache; + int noplainemail; int noheader; int renamelimit; int snapshots; int summary_branches; int summary_log; int summary_tags; struct string_list mimetypes; }; struct cgit_page { time_t modified; time_t expires; size_t size; char *mimetype; char *charset; char *filename; char *etag; char *title; int status; char *statusmsg; }; struct cgit_context { struct cgit_query qry; struct cgit_config cfg; struct cgit_repo *repo; struct cgit_page page; }; struct cgit_snapshot_format { const char *suffix; const char *mimetype; write_archive_fn_t write_func; int bit; }; extern const char *cgit_version; extern struct cgit_repolist cgit_repolist; extern struct cgit_context ctx; extern const struct cgit_snapshot_format cgit_snapshot_formats[]; extern struct cgit_repo *cgit_add_repo(const char *url); extern struct cgit_repo *cgit_get_repoinfo(const char *url); extern void cgit_repo_config_cb(const char *name, const char *value); extern int chk_zero(int result, char *msg); extern int chk_positive(int result, char *msg); extern int chk_non_negative(int result, char *msg); extern char *trim_end(const char *str, char c); extern char *strlpart(char *txt, int maxlen); extern char *strrpart(char *txt, int maxlen); extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, int flags, void *cb_data); extern void *cgit_free_commitinfo(struct commitinfo *info); extern int cgit_diff_files(const unsigned char *old_sha1, const unsigned char *new_sha1, unsigned long *old_size, unsigned long *new_size, int *binary, linediff_fn fn); extern void cgit_diff_tree(const unsigned char *old_sha1, const unsigned char *new_sha1, filepair_fn fn, const char *prefix); extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); extern char *fmt(const char *format,...); extern struct commitinfo *cgit_parse_commit(struct commit *commit); extern struct taginfo *cgit_parse_tag(struct tag *tag); extern void cgit_parse_url(const char *url); extern const char *cgit_repobasename(const char *reponame); extern int cgit_parse_snapshots_mask(const char *str); #endif /* CGIT_H */ diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 7256ec0..0412f64 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -69,192 +69,196 @@ enable-index-links:: each repo in the repository index (specifically, to the "summary", "commit" and "tree" pages). Default value: "0". enable-log-filecount:: Flag which, when set to "1", will make cgit print the number of modified files for each commit on the repository log page. Default value: "0". enable-log-linecount:: Flag which, when set to "1", will make cgit print the number of added and removed lines for each commit on the repository log page. Default value: "0". favicon:: Url used as link to a shortcut icon for cgit. If specified, it is suggested to use the value "/favicon.ico" since certain browsers will ignore other values. Default value: none. footer:: The content of the file specified with this option will be included verbatim at the bottom of all pages (i.e. it replaces the standard "generated by..." message. Default value: none. head-include:: The content of the file specified with this option will be included verbatim in the html HEAD section on all pages. Default value: none. header:: The content of the file specified with this option will be included verbatim at the top of all pages. Default value: none. include:: Name of a configfile to include before the rest of the current config- file is parsed. Default value: none. index-header:: The content of the file specified with this option will be included verbatim above the repository index. This setting is deprecated, and will not be supported by cgit-1.0 (use root-readme instead). Default value: none. index-info:: The content of the file specified with this option will be included verbatim below the heading on the repository index page. This setting is deprecated, and will not be supported by cgit-1.0 (use root-desc instead). Default value: none. local-time:: Flag which, if set to "1", makes cgit print commit and tag times in the servers timezone. Default value: "0". logo:: Url which specifies the source of an image which will be used as a logo on all cgit pages. logo-link:: Url loaded when clicking on the cgit logo image. If unspecified the calculated url of the repository index page will be used. Default value: none. max-commit-count:: Specifies the number of entries to list per page in "log" view. Default value: "50". max-message-length:: Specifies the maximum number of commit message characters to display in "log" view. Default value: "80". max-repo-count:: Specifies the number of entries to list per page on the repository index page. Default value: "50". max-repodesc-length:: Specifies the maximum number of repo description characters to display on the repository index page. Default value: "80". max-stats:: Set the default maximum statistics period. Valid values are "week", "month", "quarter" and "year". If unspecified, statistics are disabled. Default value: none. See also: "repo.max-stats". mimetype.<ext>:: Set the mimetype for the specified filename extension. This is used by the `plain` command when returning blob content. module-link:: Text which will be used as the formatstring for a hyperlink when a submodule is printed in a directory listing. The arguments for the formatstring are the path and SHA1 of the submodule commit. Default value: "./?repo=%s&page=commit&id=%s" nocache:: If set to the value "1" caching will be disabled. This settings is deprecated, and will not be honored starting with cgit-1.0. Default value: "0". +noplainemail:: + If set to "1" showing full author email adresses will be disabled. + Default value: "0". + noheader:: Flag which, when set to "1", will make cgit omit the standard header on all pages. Default value: none. See also: "embedded". renamelimit:: Maximum number of files to consider when detecting renames. The value "-1" uses the compiletime value in git (for further info, look at `man git-diff`). Default value: "-1". repo.group:: A value for the current repository group, which all repositories specified after this setting will inherit. Default value: none. robots:: Text used as content for the "robots" meta-tag. Default value: "index, nofollow". root-desc:: Text printed below the heading on the repository index page. Default value: "a fast webinterface for the git dscm". root-readme:: The content of the file specified with this option will be included verbatim below the "about" link on the repository index page. Default value: none. root-title:: Text printed as heading on the repository index page. Default value: "Git Repository Browser". snapshots:: Text which specifies the default (and allowed) set of snapshot formats supported by cgit. The value is a space-separated list of zero or more of the following values: "tar" uncompressed tar-file "tar.gz" gzip-compressed tar-file "tar.bz2" bzip-compressed tar-file "zip" zip-file Default value: none. summary-branches:: Specifies the number of branches to display in the repository "summary" view. Default value: "10". summary-log:: Specifies the number of log entries to display in the repository "summary" view. Default value: "10". summary-tags:: Specifies the number of tags to display in the repository "summary" view. Default value: "10". virtual-root:: Url which, if specified, will be used as root for all cgit links. It will also cause cgit to generate 'virtual urls', i.e. urls like '/cgit/tree/README' as opposed to '?r=cgit&p=tree&path=README'. Default value: none. NOTE: cgit has recently learned how to use PATH_INFO to achieve the same kind of virtual urls, so this option will probably be deprecated. REPOSITORY SETTINGS ------------------- repo.clone-url:: A list of space-separated urls which can be used to clone this repo. Default value: none. repo.defbranch:: The name of the default branch for this repository. If no such branch exists in the repository, the first branch name (when sorted) is used as default instead. Default value: "master". repo.desc:: The value to show as repository description. Default value: none. repo.enable-log-filecount:: A flag which can be used to disable the global setting `enable-log-filecount'. Default value: none. repo.enable-log-linecount:: A flag which can be used to disable the global setting `enable-log-linecount'. Default value: none. repo.max-stats:: Override the default maximum statistics period. Valid values are equal to the values specified for the global "max-stats" setting. Default value: none. repo.name:: The value to show as repository name. Default value: <repo.url>. repo.owner:: A value used to identify the owner of the repository. Default value: none. repo.path:: An absolute path to the repository directory. For non-bare repositories @@ -1,131 +1,131 @@ /* ui-atom.c: functions for atom feeds * * Copyright (C) 2008 Lars Hjemli * * Licensed under GNU General Public License v2 * (see COPYING for full license text) */ #include "cgit.h" #include "html.h" #include "ui-shared.h" void add_entry(struct commit *commit, char *host) { char delim = '&'; char *hex; char *mail, *t, *t2; struct commitinfo *info; info = cgit_parse_commit(commit); hex = sha1_to_hex(commit->object.sha1); html("<entry>\n"); html("<title>"); html_txt(info->subject); html("</title>\n"); html("<updated>"); cgit_print_date(info->author_date, FMT_ATOMDATE, ctx.cfg.local_time); html("</updated>\n"); html("<author>\n"); if (info->author) { html("<name>"); html_txt(info->author); html("</name>\n"); } - if (info->author_email) { + if (info->author_email && !ctx.cfg.noplainemail) { mail = xstrdup(info->author_email); t = strchr(mail, '<'); if (t) t++; else t = mail; t2 = strchr(t, '>'); if (t2) *t2 = '\0'; html("<email>"); html_txt(t); html("</email>\n"); free(mail); } html("</author>\n"); html("<published>"); cgit_print_date(info->author_date, FMT_ATOMDATE, ctx.cfg.local_time); html("</published>\n"); if (host) { html("<link rel='alternate' type='text/html' href='"); html(cgit_httpscheme()); html_attr(host); html_attr(cgit_pageurl(ctx.repo->url, "commit", NULL)); if (ctx.cfg.virtual_root) delim = '?'; htmlf("%cid=%s", delim, hex); html("'/>\n"); } htmlf("<id>%s</id>\n", hex); html("<content type='text'>\n"); html_txt(info->msg); html("</content>\n"); html("<content type='xhtml'>\n"); html("<div xmlns='http://www.w3.org/1999/xhtml'>\n"); html("<pre>\n"); html_txt(info->msg); html("</pre>\n"); html("</div>\n"); html("</content>\n"); html("</entry>\n"); cgit_free_commitinfo(info); } void cgit_print_atom(char *tip, char *path, int max_count) { char *host; const char *argv[] = {NULL, tip, NULL, NULL, NULL}; struct commit *commit; struct rev_info rev; int argc = 2; if (!tip) argv[1] = ctx.qry.head; if (path) { argv[argc++] = "--"; argv[argc++] = path; } init_revisions(&rev, NULL); rev.abbrev = DEFAULT_ABBREV; rev.commit_format = CMIT_FMT_DEFAULT; rev.verbose_header = 1; rev.show_root_diff = 0; rev.max_count = max_count; setup_revisions(argc, argv, &rev, NULL); prepare_revision_walk(&rev); host = cgit_hosturl(); ctx.page.mimetype = "text/xml"; ctx.page.charset = "utf-8"; cgit_print_http_headers(&ctx); html("<feed xmlns='http://www.w3.org/2005/Atom'>\n"); html("<title>"); html_txt(ctx.repo->name); html("</title>\n"); html("<subtitle>"); html_txt(ctx.repo->desc); html("</subtitle>\n"); if (host) { html("<link rel='alternate' type='text/html' href='"); html(cgit_httpscheme()); html_attr(host); html_attr(cgit_repourl(ctx.repo->url)); html("'/>\n"); } while ((commit = get_revision(&rev)) != NULL) { add_entry(commit, host); free(commit->buffer); commit->buffer = NULL; free_commit_list(commit->parents); commit->parents = NULL; } html("</feed>\n"); } diff --git a/ui-commit.c b/ui-commit.c index 41ce70e..9fdb8ee 100644 --- a/ui-commit.c +++ b/ui-commit.c @@ -1,106 +1,110 @@ /* ui-commit.c: generate commit view * * Copyright (C) 2006 Lars Hjemli * * Licensed under GNU General Public License v2 * (see COPYING for full license text) */ #include "cgit.h" #include "html.h" #include "ui-shared.h" #include "ui-diff.h" #include "ui-log.h" void cgit_print_commit(char *hex) { struct commit *commit, *parent; struct commitinfo *info; struct commit_list *p; unsigned char sha1[20]; char *tmp; int parents = 0; if (!hex) hex = ctx.qry.head; if (get_sha1(hex, sha1)) { cgit_print_error(fmt("Bad object id: %s", hex)); return; } commit = lookup_commit_reference(sha1); if (!commit) { cgit_print_error(fmt("Bad commit reference: %s", hex)); return; } info = cgit_parse_commit(commit); load_ref_decorations(); html("<table summary='commit info' class='commit-info'>\n"); html("<tr><th>author</th><td>"); html_txt(info->author); - html(" "); - html_txt(info->author_email); + if (!ctx.cfg.noplainemail) { + html(" "); + html_txt(info->author_email); + } html("</td><td class='right'>"); cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time); html("</td></tr>\n"); html("<tr><th>committer</th><td>"); html_txt(info->committer); - html(" "); - html_txt(info->committer_email); + if (!ctx.cfg.noplainemail) { + html(" "); + html_txt(info->committer_email); + } html("</td><td class='right'>"); cgit_print_date(info->committer_date, FMT_LONGDATE, ctx.cfg.local_time); html("</td></tr>\n"); html("<tr><th>commit</th><td colspan='2' class='sha1'>"); tmp = sha1_to_hex(commit->object.sha1); cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp); html(" ("); cgit_patch_link("patch", NULL, NULL, NULL, tmp); html(")</td></tr>\n"); html("<tr><th>tree</th><td colspan='2' class='sha1'>"); tmp = xstrdup(hex); cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL, ctx.qry.head, tmp, NULL); html("</td></tr>\n"); for (p = commit->parents; p ; p = p->next) { parent = lookup_commit_reference(p->item->object.sha1); if (!parent) { html("<tr><td colspan='3'>"); cgit_print_error("Error reading parent commit"); html("</td></tr>"); continue; } html("<tr><th>parent</th>" "<td colspan='2' class='sha1'>"); cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, ctx.qry.head, sha1_to_hex(p->item->object.sha1)); html(" ("); cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex, sha1_to_hex(p->item->object.sha1), NULL); html(")</td></tr>"); parents++; } if (ctx.repo->snapshots) { html("<tr><th>download</th><td colspan='2' class='sha1'>"); cgit_print_snapshot_links(ctx.qry.repo, ctx.qry.head, hex, ctx.repo->snapshots); html("</td></tr>"); } html("</table>\n"); html("<div class='commit-subject'>"); html_txt(info->subject); show_commit_decorations(commit); html("</div>"); html("<div class='commit-msg'>"); html_txt(info->msg); html("</div>"); if (parents < 3) { if (parents) tmp = sha1_to_hex(commit->parents->item->object.sha1); else tmp = NULL; cgit_print_diff(ctx.qry.sha1, tmp, NULL); } cgit_free_commitinfo(info); } @@ -15,111 +15,115 @@ static void print_line(char *line, int len) char c = line[len-1]; line[len-1] = '\0'; htmlf("%s\n", line); line[len-1] = c; } static void header(unsigned char *sha1, char *path1, int mode1, unsigned char *sha2, char *path2, int mode2) { char *abbrev1, *abbrev2; int subproject; subproject = (S_ISGITLINK(mode1) || S_ISGITLINK(mode2)); htmlf("diff --git a/%s b/%s\n", path1, path2); if (is_null_sha1(sha1)) path1 = "dev/null"; if (is_null_sha1(sha2)) path2 = "dev/null"; if (mode1 == 0) htmlf("new file mode %.6o\n", mode2); if (mode2 == 0) htmlf("deleted file mode %.6o\n", mode1); if (!subproject) { abbrev1 = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV)); abbrev2 = xstrdup(find_unique_abbrev(sha2, DEFAULT_ABBREV)); htmlf("index %s..%s", abbrev1, abbrev2); free(abbrev1); free(abbrev2); if (mode1 != 0 && mode2 != 0) { htmlf(" %.6o", mode1); if (mode2 != mode1) htmlf("..%.6o", mode2); } htmlf("\n--- a/%s\n", path1); htmlf("+++ b/%s\n", path2); } } static void filepair_cb(struct diff_filepair *pair) { unsigned long old_size = 0; unsigned long new_size = 0; int binary = 0; header(pair->one->sha1, pair->one->path, pair->one->mode, pair->two->sha1, pair->two->path, pair->two->mode); if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) { if (S_ISGITLINK(pair->one->mode)) print_line(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52); if (S_ISGITLINK(pair->two->mode)) print_line(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52); return; } if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size, &new_size, &binary, print_line)) html("Error running diff"); if (binary) html("Binary files differ\n"); } void cgit_print_patch(char *hex) { struct commit *commit; struct commitinfo *info; unsigned char sha1[20], old_sha1[20]; char *patchname; if (!hex) hex = ctx.qry.head; if (get_sha1(hex, sha1)) { cgit_print_error(fmt("Bad object id: %s", hex)); return; } commit = lookup_commit_reference(sha1); if (!commit) { cgit_print_error(fmt("Bad commit reference: %s", hex)); return; } info = cgit_parse_commit(commit); if (commit->parents && commit->parents->item) hashcpy(old_sha1, commit->parents->item->object.sha1); else hashclr(old_sha1); patchname = fmt("%s.patch", sha1_to_hex(sha1)); ctx.page.mimetype = "text/plain"; ctx.page.filename = patchname; cgit_print_http_headers(&ctx); htmlf("From %s Mon Sep 17 00:00:00 2001\n", sha1_to_hex(sha1)); - htmlf("From: %s %s\n", info->author, info->author_email); + htmlf("From: %s", info->author); + if (!ctx.cfg.noplainemail) { + htmlf(" %s", info->author_email); + } + html("\n"); html("Date: "); cgit_print_date(info->author_date, "%a, %d %b %Y %H:%M:%S %z%n", ctx.cfg.local_time); htmlf("Subject: %s\n\n", info->subject); if (info->msg && *info->msg) { htmlf("%s", info->msg); if (info->msg[strlen(info->msg) - 1] != '\n') html("\n"); } html("---\n"); cgit_diff_tree(old_sha1, sha1, filepair_cb, NULL); html("--\n"); htmlf("cgit %s\n", CGIT_VERSION); cgit_free_commitinfo(info); } @@ -1,89 +1,89 @@ /* ui-tag.c: display a tag * * Copyright (C) 2007 Lars Hjemli * * Licensed under GNU General Public License v2 * (see COPYING for full license text) */ #include "cgit.h" #include "html.h" #include "ui-shared.h" static void print_tag_content(char *buf) { char *p; if (!buf) return; html("<div class='commit-subject'>"); p = strchr(buf, '\n'); if (p) *p = '\0'; html_txt(buf); html("</div>"); if (p) { html("<div class='commit-msg'>"); html_txt(++p); html("</div>"); } } void cgit_print_tag(char *revname) { unsigned char sha1[20]; struct object *obj; struct tag *tag; struct taginfo *info; if (get_sha1(revname, sha1)) { cgit_print_error(fmt("Bad tag reference: %s", revname)); return; } obj = parse_object(sha1); if (!obj) { cgit_print_error(fmt("Bad object id: %s", sha1_to_hex(sha1))); return; } if (obj->type == OBJ_TAG) { tag = lookup_tag(sha1); if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) { cgit_print_error(fmt("Bad tag object: %s", revname)); return; } html("<table class='commit-info'>\n"); htmlf("<tr><td>Tag name</td><td>"); html_txt(revname); htmlf(" (%s)</td></tr>\n", sha1_to_hex(sha1)); if (info->tagger_date > 0) { html("<tr><td>Tag date</td><td>"); cgit_print_date(info->tagger_date, FMT_LONGDATE, ctx.cfg.local_time); html("</td></tr>\n"); } if (info->tagger) { html("<tr><td>Tagged by</td><td>"); html_txt(info->tagger); - if (info->tagger_email) { + if (info->tagger_email && !ctx.cfg.noplainemail) { html(" "); html_txt(info->tagger_email); } html("</td></tr>\n"); } html("<tr><td>Tagged object</td><td>"); cgit_object_link(tag->tagged); html("</td></tr>\n"); html("</table>\n"); print_tag_content(info->msg); } else { html("<table class='commit-info'>\n"); htmlf("<tr><td>Tag name</td><td>"); html_txt(revname); html("</td></tr>\n"); html("<tr><td>Tagged object</td><td>"); cgit_object_link(obj); html("</td></tr>\n"); html("</table>\n"); } return; } @@ -10,225 +10,231 @@ #include "cgit.h" #include "html.h" #include "ui-shared.h" char *curr_rev; char *match_path; int header = 0; static void print_text_buffer(char *buf, unsigned long size) { unsigned long lineno, idx; const char *numberfmt = "<a class='no' id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a>\n"; html("<table summary='blob content' class='blob'>\n"); html("<tr><td class='linenumbers'><pre>"); idx = 0; lineno = 0; if (size) { htmlf(numberfmt, ++lineno); while(idx < size - 1) { // skip absolute last newline if (buf[idx] == '\n') htmlf(numberfmt, ++lineno); idx++; } } html("</pre></td>\n"); html("<td class='lines'><pre><code>"); html_txt(buf); html("</code></pre></td></tr></table>\n"); } #define ROWLEN 32 static void print_binary_buffer(char *buf, unsigned long size) { unsigned long ofs, idx; static char ascii[ROWLEN + 1]; html("<table summary='blob content' class='bin-blob'>\n"); html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>"); for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) { htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs); for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) htmlf("%*s%02x", idx == 16 ? 4 : 1, "", buf[idx] & 0xff); html(" </td><td class='hex'>"); for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.'; ascii[idx] = '\0'; html_txt(ascii); html("</td></tr>\n"); } html("</table>\n"); } static void print_object(const unsigned char *sha1, char *path) { enum object_type type; char *buf; unsigned long size; type = sha1_object_info(sha1, &size); if (type == OBJ_BAD) { cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(sha1))); return; } buf = read_sha1_file(sha1, &type, &size); if (!buf) { cgit_print_error(fmt("Error reading object %s", sha1_to_hex(sha1))); return; } html(" ("); cgit_plain_link("plain", NULL, NULL, ctx.qry.head, curr_rev, path); htmlf(")<br/>blob: %s\n", sha1_to_hex(sha1)); if (buffer_is_binary(buf, size)) print_binary_buffer(buf, size); else print_text_buffer(buf, size); } static int ls_item(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned int mode, int stage, void *cbdata) { char *name; char *fullpath; + char *class; enum object_type type; unsigned long size = 0; name = xstrdup(pathname); fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "", ctx.qry.path ? "/" : "", name); if (!S_ISGITLINK(mode)) { type = sha1_object_info(sha1, &size); if (type == OBJ_BAD) { htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", name, sha1_to_hex(sha1)); return 0; } } html("<tr><td class='ls-mode'>"); cgit_print_filemode(mode); html("</td><td>"); if (S_ISGITLINK(mode)) { htmlf("<a class='ls-mod' href='"); html_attr(fmt(ctx.repo->module_link, name, sha1_to_hex(sha1))); html("'>"); html_txt(name); html("</a>"); } else if (S_ISDIR(mode)) { cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, curr_rev, fullpath); } else { - cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head, + class = strrchr(name, '.'); + if (class != NULL) { + class = fmt("ls-blob %s", class + 1); + } else + class = "ls-blob"; + cgit_tree_link(name, NULL, class, ctx.qry.head, curr_rev, fullpath); } htmlf("</td><td class='ls-size'>%li</td>", size); html("<td>"); cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev, fullpath, 0, NULL, NULL, ctx.qry.showmsg); if (ctx.repo->max_stats) cgit_stats_link("stats", NULL, "button", ctx.qry.head, fullpath); html("</td></tr>\n"); free(name); return 0; } static void ls_head() { html("<table summary='tree listing' class='list'>\n"); html("<tr class='nohover'>"); html("<th class='left'>Mode</th>"); html("<th class='left'>Name</th>"); html("<th class='right'>Size</th>"); html("<th/>"); html("</tr>\n"); header = 1; } static void ls_tail() { if (!header) return; html("</table>\n"); header = 0; } static void ls_tree(const unsigned char *sha1, char *path) { struct tree *tree; tree = parse_tree_indirect(sha1); if (!tree) { cgit_print_error(fmt("Not a tree object: %s", sha1_to_hex(sha1))); return; } ls_head(); read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL); ls_tail(); } static int walk_tree(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *cbdata) { static int state; static char buffer[PATH_MAX]; char *url; if (state == 0) { memcpy(buffer, base, baselen); strcpy(buffer+baselen, pathname); url = cgit_pageurl(ctx.qry.repo, "tree", fmt("h=%s&path=%s", curr_rev, buffer)); html("/"); cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head, curr_rev, buffer); if (strcmp(match_path, buffer)) return READ_TREE_RECURSIVE; if (S_ISDIR(mode)) { state = 1; ls_head(); return READ_TREE_RECURSIVE; } else { print_object(sha1, buffer); return 0; } } ls_item(sha1, base, baselen, pathname, mode, stage, NULL); return 0; } /* * Show a tree or a blob * rev: the commit pointing at the root tree object * path: path to tree or blob */ void cgit_print_tree(const char *rev, char *path) { unsigned char sha1[20]; struct commit *commit; const char *paths[] = {path, NULL}; |