/* cgit.c: cgi for the git scm
 *
 * Copyright (C) 2006 Lars Hjemli
 * Copyright (C) 2010 Jason A. Donenfeld <Jason@zx2c4.com>
 *
 * 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(&ctx.cfg.mimetypes, xstrdup(name));
	item->util = xstrdup(value);
}

struct cgit_filter *new_filter(const char *cmd, int extra_args)
{
	struct cgit_filter *f;

	if (!cmd || !cmd[0])
		return NULL;

	f = xmalloc(sizeof(struct cgit_filter));
	f->cmd = xstrdup(cmd);
	f->argv = xmalloc((2 + extra_args) * sizeof(char *));
	f->argv[0] = f->cmd;
	f->argv[1] = NULL;
	return f;
}

static void process_cached_repolist(const char *path);

void repo_config(struct cgit_repo *repo, const char *name, const char *value)
{
	if (!strcmp(name, "name"))
		repo->name = xstrdup(value);
	else if (!strcmp(name, "clone-url"))
		repo->clone_url = xstrdup(value);
	else if (!strcmp(name, "desc"))
		repo->desc = xstrdup(value);
	else if (!strcmp(name, "owner"))
		repo->owner = xstrdup(value);
	else if (!strcmp(name, "defbranch"))
		repo->defbranch = xstrdup(value);
	else if (!strcmp(name, "snapshots"))
		repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value);
	else if (!strcmp(name, "enable-commit-graph"))
		repo->enable_commit_graph = ctx.cfg.enable_commit_graph * atoi(value);
	else if (!strcmp(name, "enable-log-filecount"))
		repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
	else if (!strcmp(name, "enable-log-linecount"))
		repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
	else if (!strcmp(name, "enable-remote-branches"))
		repo->enable_remote_branches = atoi(value);
	else if (!strcmp(name, "enable-subject-links"))
		repo->enable_subject_links = atoi(value);
	else if (!strcmp(name, "max-stats"))
		repo->max_stats = cgit_find_stats_period(value, NULL);
	else if (!strcmp(name, "module-link"))
		repo->module_link= xstrdup(value);
	else if (!strcmp(name, "section"))
		repo->section = xstrdup(value);
	else if (!strcmp(name, "readme") && value != NULL) {
		repo->readme = xstrdup(value);
	} else if (ctx.cfg.enable_filter_overrides) {
		if (!strcmp(name, "about-filter"))
			repo->about_filter = new_filter(value, 0);
		else if (!strcmp(name, "commit-filter"))
			repo->commit_filter = new_filter(value, 0);
		else if (!strcmp(name, "source-filter"))
			repo->source_filter = new_filter(value, 1);
	}
}

void config_cb(const char *name, const char *value)
{
	if (!strcmp(name, "section") || !strcmp(name, "repo.group"))
		ctx.cfg.section = xstrdup(value);
	else if (!strcmp(name, "repo.url"))
		ctx.repo = cgit_add_repo(value);
	else if (ctx.repo && !strcmp(name, "repo.path"))
		ctx.repo->path = trim_end(value, '/');
	else if (ctx.repo && !prefixcmp(name, "repo."))
		repo_config(ctx.repo, name + 5, value);
	else if (!strcmp(name, "readme"))
		ctx.cfg.readme = xstrdup(value);
	else 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, "strict-export"))
		ctx.cfg.strict_export = 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-filter-overrides"))
		ctx.cfg.enable_filter_overrides = atoi(value);
	else if (!strcmp(name, "enable-gitweb-owner"))
		ctx.cfg.enable_gitweb_owner = atoi(value);
	else if (!strcmp(name, "enable-index-links"))
		ctx.cfg.enable_index_links = atoi(value);
	else if (!strcmp(name, "enable-commit-graph"))
		ctx.cfg.enable_commit_graph = 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, "enable-remote-branches"))
		ctx.cfg.enable_remote_branches = atoi(value);
	else if (!strcmp(name, "enable-subject-links"))
		ctx.cfg.enable_subject_links = atoi(value);
	else if (!strcmp(name, "enable-tree-linenumbers"))
		ctx.cfg.enable_tree_linenumbers = 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(expand_macros(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-scanrc-ttl"))
		ctx.cfg.cache_scanrc_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, "about-filter"))
		ctx.cfg.about_filter = new_filter(value, 0);
	else if (!strcmp(name, "commit-filter"))
		ctx.cfg.commit_filter = new_filter(value, 0);
	else if (!strcmp(name, "embedded"))
		ctx.cfg.embedded = atoi(value);
	else if (!strcmp(name, "max-atom-items"))
		ctx.cfg.max_atom_items = 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-blob-size"))
		ctx.cfg.max_blob_size = 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, "project-list"))
		ctx.cfg.project_list = xstrdup(expand_macros(value));
	else if (!strcmp(name, "scan-path"))
		if (!ctx.cfg.nocache && ctx.cfg.cache_size)
			process_cached_repolist(expand_macros(value));
		else if (ctx.cfg.project_list)
			scan_projects(expand_macros(value),
				      ctx.cfg.project_list, repo_config);
		else
			scan_tree(expand_macros(value), repo_config);
	else if (!strcmp(name, "section-from-path"))
		ctx.cfg.section_from_path = atoi(value);
	else if (!strcmp(name, "source-filter"))
		ctx.cfg.source_filter = new_filter(value, 1);
	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, "side-by-side-diffs"))
		ctx.cfg.ssdiff = 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, "remove-suffix"))
		ctx.cfg.remove_suffix = 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, "include"))
		parse_configfile(expand_macros(value), config_cb);
}

static void querystring_cb(const char *name, const char *value)
{
	if (!value)
		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")) {
		if (*value == '/')
			value++;
		ctx.qry.url = xstrdup(value);
		cgit_parse_url(value);
	} else if (!strcmp(name, "qt")) {
		ctx.qry.grep = xstrdup(value);
	} else if (!strcmp(name, "q")) {
		ctx.qry.search = xstrdup(value);
	} else if (!strcmp(name, "h")) {
		ctx.qry.head = xstrdup(value);
		ctx.qry.has_symref = 1;
	} else if (!strcmp(name, "id")) {
		ctx.qry.sha1 = xstrdup(value);
		ctx.qry.has_sha1 = 1;
	} else if (!strcmp(name, "id2")) {
		ctx.qry.sha2 = xstrdup(value);
		ctx.qry.has_sha1 = 1;
	} else if (!strcmp(name, "ofs")) {
		ctx.qry.ofs = atoi(value);
	} else if (!strcmp(name, "path")) {
		ctx.qry.path = trim_end(value, '/');
	} else if (!strcmp(name, "name")) {
		ctx.qry.name = xstrdup(value);
	} else if (!strcmp(name, "mimetype")) {
		ctx.qry.mimetype = xstrdup(value);
	} else if (!strcmp(name, "s")){
		ctx.qry.sort = xstrdup(value);
	} else if (!strcmp(name, "showmsg")) {
		ctx.qry.showmsg = atoi(value);
	} else if (!strcmp(name, "period")) {
		ctx.qry.period = xstrdup(value);
	} else if (!strcmp(name, "ss")) {
		ctx.qry.ssdiff = atoi(value);
	} else if (!strcmp(name, "all")) {
		ctx.qry.show_all = atoi(value);
	} else if (!strcmp(name, "context")) {
		ctx.qry.context = atoi(value);
	} else if (!strcmp(name, "ignorews")) {
		ctx.qry.ignorews = atoi(value);
	}
}

char *xstrdupn(const char *str)
{
	return (str ? xstrdup(str) : NULL);
}

static void prepare_context(struct cgit_context *ctx)
{
	memset(ctx, 0, sizeof(*ctx));
	ctx->cfg.agefile = "info/web/last-modified";
	ctx->cfg.nocache = 0;
	ctx->cfg.cache_size = 0;
	ctx->cfg.cache_dynamic_ttl = 5;
	ctx->cfg.cache_max_create_time = 5;
	ctx->cfg.cache_repo_ttl = 5;
	ctx->cfg.cache_root = CGIT_CACHE_ROOT;
	ctx->cfg.cache_root_ttl = 5;
	ctx->cfg.cache_scanrc_ttl = 15;
	ctx->cfg.cache_static_ttl = -1;
	ctx->cfg.css = "/cgit.css";
	ctx->cfg.logo = "/cgit.png";
	ctx->cfg.local_time = 0;
	ctx->cfg.enable_gitweb_owner = 1;
	ctx->cfg.enable_tree_linenumbers = 1;
	ctx->cfg.max_repo_count = 50;
	ctx->cfg.max_commit_count = 50;
	ctx->cfg.max_lock_attempts = 5;
	ctx->cfg.max_msg_len = 80;
	ctx->cfg.max_repodesc_len = 80;
	ctx->cfg.max_blob_size = 0;
	ctx->cfg.max_stats = 0;
	ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
	ctx->cfg.project_list = NULL;
	ctx->cfg.renamelimit = -1;
	ctx->cfg.remove_suffix = 0;
	ctx->cfg.robots = "index, nofollow";
	ctx->cfg.root_title = "Git repository browser";
	ctx->cfg.root_desc = "a fast webinterface for the git dscm";
	ctx->cfg.script_name = CGIT_SCRIPT_NAME;
	ctx->cfg.section = "";
	ctx->cfg.summary_branches = 10;
	ctx->cfg.summary_log = 10;
	ctx->cfg.summary_tags = 10;
	ctx->cfg.max_atom_items = 10;
	ctx->cfg.ssdiff = 0;
	ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG"));
	ctx->env.http_host = xstrdupn(getenv("HTTP_HOST"));
	ctx->env.https = xstrdupn(getenv("HTTPS"));
	ctx->env.no_http = xstrdupn(getenv("NO_HTTP"));
	ctx->env.path_info = xstrdupn(getenv("PATH_INFO"));
	ctx->env.query_string = xstrdupn(getenv("QUERY_STRING"));
	ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD"));
	ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME"));
	ctx->env.server_name = xstrdupn(getenv("SERVER_NAME"));
	ctx->env.server_port = xstrdupn(getenv("SERVER_PORT"));
	ctx->page.mimetype = "text/html";
	ctx->page.charset = PAGE_ENCODING;
	ctx->page.filename = NULL;
	ctx->page.size = 0;
	ctx->page.modified = time(NULL);
	ctx->page.expires = ctx->page.modified;
	ctx->page.etag = NULL;
	memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list));
	if (ctx->env.script_name)
		ctx->cfg.script_name = ctx->env.script_name;
	if (ctx->env.query_string)
		ctx->qry.raw = ctx->env.query_string;
	if (!ctx->env.cgit_config)
		ctx->env.cgit_config = CGIT_CONFIG;
}

struct refmatch {
	char *req_ref;
	char *first_ref;
	int match;
};

int find_current_ref(const char *refname, const unsigned char *sha1,
		     int flags, void *cb_data)
{
	struct refmatch *info;

	info = (struct refmatch *)cb_data;
	if (!strcmp(refname, info->req_ref))
		info->match = 1;
	if (!info->first_ref)
		info->first_ref = xstrdup(refname);
	return info->match;
}

char *find_default_branch(struct cgit_repo *repo)
{
	struct refmatch info;
	char *ref;

	info.req_ref = repo->defbranch;
	info.first_ref = NULL;
	info.match = 0;
	for_each_branch_ref(find_current_ref, &info);
	if (info.match)
		ref = info.req_ref;
	else
		ref = info.first_ref;
	if (ref)
		ref = xstrdup(ref);
	return ref;
}

static int prepare_repo_cmd(struct cgit_context *ctx)
{
	char *tmp;
	unsigned char sha1[20];
	int nongit = 0;

	setenv("GIT_DIR", ctx->repo->path, 1);
	setup_git_directory_gently(&nongit);
	if (nongit) {
		ctx->page.title = fmt("%s - %s", ctx->cfg.root_title,
				      "config error");
		tmp = fmt("Not a git repository: '%s'", ctx->repo->path);
		ctx->repo = NULL;
		cgit_print_http_headers(ctx);
		cgit_print_docstart(ctx);
		cgit_print_pageheader(ctx);
		cgit_print_error(tmp);
		cgit_print_docend();
		return 1;
	}
	ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc);

	if (!ctx->qry.head) {
		ctx->qry.nohead = 1;
		ctx->qry.head = find_default_branch(ctx->repo);
		ctx->repo->defbranch<style>pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */</style><div class="highlight"><pre><span></span>		    GNU GENERAL PUBLIC LICENSE
		       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

			    Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation&#39;s software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author&#39;s protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors&#39; reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone&#39;s free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

		    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The &quot;Program&quot;, below,
refers to any such program or work, and a &quot;work based on the Program&quot;
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term &quot;modification&quot;.)  Each licensee is addressed as &quot;you&quot;.

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program&#39;s
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
alon