\n"
+ "
%s
\n"
+ "
\n",
+ esc_title);
+
+ readme = fopen ("README", "r");
+ if (opt_readme && (readme = fopen ("README", "r")))
+ {
+ fputs ("
\n", stdout);
+ while (fgets (line, sizeof line, readme))
+ {
+ int no_lf = 0;
+ /* Eat up the rest of an incomplete line. */
+ if (!*line)
+ no_lf = 1;
+ else if (line[strlen (line)-1] != '\n')
+ {
+ no_lf = 1;
+ while ((c = getc (readme)) != EOF && c != '\n')
+ ;
+ }
+
+ /* Replace empty lines with a leading doc by an empty
+ * line. These lines are used on FTP servers to avoid
+ * problems with broken FTP cleints. */
+ if (*line == '.')
+ {
+ for (p=line+1; (*p == ' ' || *p == '\t' || *p == '\n'); p++)
+ ;
+ if (!*p)
+ {
+ putchar ('\n');
+ *line = 0;
+ }
+ }
+
+ if (*line)
+ fputs (html_escape_detect_link (line), stdout);
+ if (no_lf)
+ putchar ('\n');
+ }
+ fputs ("
\n", stdout);
+ fclose (readme);
+ }
+ fputs ("
\n", stdout);
+
+ }
+ else
+ {
+ printf ("\n"
+ "\n"
+ "
Index of %s\n"
+ "\n"
+ "\n"
+ "
Index of %s
\n"
+ "
\n",
+ esc_title, esc_title);
+ }
+}
+
+
+static void
+print_footer (void)
+{
+ if (!opt_html)
+ return;
+
+ if (opt_gpgweb)
+ {
+ fputs ("\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n", stdout);
+ }
+ else
+ {
+ printf ("
\n"
+ "\n"
+ "\n");
+ }
+}
+
+
+/* Print COUNT directories from the array SORTED. */
+static void
+print_dirs (finfo_t *sorted, int count, const char *directory)
+{
+ int idx;
+ finfo_t fi;
+ int any = 0;
+
+ for (idx=0; idx < count; idx++)
+ {
+ fi = sorted[idx];
+ if (!fi->is_dir)
+ continue;
+
+ if (!any && opt_html)
+ {
+ any = 1;
+
+ if (opt_gpgweb)
+ {
+ fputs ("
Directories
\n"
+ "
\n"
+ "
\n", stdout);
+
+ if (strcmp (directory, "/"))
+ fputs (" | "
+ ""
+ "Parent Directory |
\n", stdout);
+ }
+ else
+ {
+ fputs ("  | "
+ "Directories |
\n",
+ stdout);
+ if (strcmp (directory, "/"))
+ fputs (""
+ "Parent Directory |
\n", stdout);
+ }
+ }
+
+ if (opt_gpgweb)
+ printf (" | "
+ "%s |
\n",
+ html_escape_href (fi->name), html_escape (fi->name));
+ else if (opt_html)
+ printf ("%s |
\n",
+ html_escape_href (fi->name), html_escape (fi->name));
+ else
+ printf ("D %s\n", fi->name);
+ }
+
+ if (any && opt_gpgweb)
+ {
+ fputs ("
\n"
+ "
\n\n", stdout);
+ }
+}
+
+
+/* Print COUNT files from the array SORTED. */
+static void
+print_files (finfo_t *sorted, int count)
+{
+ int idx;
+ finfo_t fi;
+ int any = 0;
+
+ for (idx=0; idx < count; idx++)
+ {
+ fi = sorted[idx];
+ if (!fi->is_reg)
+ continue;
+
+ if (!any && opt_html)
+ {
+ any = 1;
+ if (opt_gpgweb)
+ {
+ fputs ("
Files
\n"
+ "
\n"
+ "
\n", stdout);
+ }
+ else
+ fputs ("Files |
\n",
+ stdout);
+
+ }
+
+ if (opt_gpgweb)
+ printf (" | "
+ "%s | "
+ "%s | %s |
\n",
+ strstr (fi->name, ".sig")? "document":
+ strstr (fi->name, ".tar")? "tar" : "document",
+ html_escape_href (fi->name), html_escape (fi->name),
+ format_time (fi->mtime), format_size (fi->size));
+ else if (opt_html)
+ printf ("%s | "
+ "%s | %s |
\n",
+ html_escape_href (fi->name), html_escape (fi->name),
+ format_time (fi->mtime), format_size (fi->size));
+ else
+ printf ("F %s\n", fi->name);
+ }
+
+ if (any && opt_gpgweb)
+ {
+ fputs ("
\n"
+ "
\n\n", stdout);
+ }
+}
+
+
+/* Scan DIRECTORY and print an index.
+ * FIXME: This does a chdir and does not preserve the old PWD.
+ * The fix is to build the full filename beofre stat'ing.
+ */
+static void
+scan_directory (const char *directory, const char *title)
+{
+ DIR *dir;
+ struct dirent *dentry;
+ finfo_t fi;
+ finfo_t finfo = NULL;
+ finfo_t *sorted;
+ int count = 0;
+ int idx;
+ size_t len;
+ strlist_t sl;
+
+ dir = opendir (directory);
+ if (!dir)
+ {
+ err ("can't open directory '%s': %s\n", directory, strerror (errno));
+ return;
+ }
+
+ while (errno=0,(dentry = readdir (dir)))
+ {
+ if (*dentry->d_name == '.')
+ continue; /* Skip self, parent, and hidden directories. */
+ len = strlen (dentry->d_name);
+ if (!len)
+ continue; /* Empty filenames should actually not exist. */
+ if (dentry->d_name[len-1] == '~')
+ continue; /* Skip backup files. */
+ for (sl = opt_exclude; sl; sl = sl->next)
+ if (!strcmp (sl->d, dentry->d_name))
+ break;
+ if (sl)
+ continue; /* Skip excluded names. */
+ fi = xcalloc (1, sizeof *fi + strlen (dentry->d_name));
+ strcpy (fi->name, dentry->d_name);
+ fi->next = finfo;
+ finfo = fi;
+ count++;
+ }
+ if (errno)
+ die ("error reading directory '%s': %s\n", directory, strerror (errno));
+ closedir (dir);
+
+ sorted = xcalloc (count, sizeof *sorted);
+ for (fi=finfo, idx=0; fi; fi = fi->next)
+ sorted[idx++] = fi;
+
+ inf ("directory '%s' has %d files\n", directory, count);
+ qsort (sorted, count, sizeof *sorted, sort_finfo);
+
+ if (chdir (directory))
+ die ("cannot chdir to '%s': %s\n", directory, strerror (errno));
+
+ for (idx=0; idx < count; idx++)
+ {
+ struct stat sb;
+
+ fi = sorted[idx];
+ if (stat (fi->name, &sb))
+ {
+ err ("cannot stat '%s': %s\n", fi->name, strerror (errno));
+ continue;
+ }
+
+ fi->is_dir = !!S_ISDIR(sb.st_mode);
+ fi->is_reg = !!S_ISREG(sb.st_mode);
+ fi->size = fi->is_reg? sb.st_size : 0;
+ fi->mtime = sb.st_mtime;
+ }
+
+ print_header (title);
+ if (opt_files_first)
+ {
+ print_files (sorted, count);
+ print_dirs (sorted, count, directory);
+ }
+ else
+ {
+ print_dirs (sorted, count, directory);
+ print_files (sorted, count);
+ }
+ print_footer ();
+
+ /* We create the index file in the current directory. */
+ if (opt_index)
+ {
+ FILE *indexfp = fopen (".ftp-index", "w");
+ if (!indexfp)
+ die ("error creating .ftp-index in '%s': %s\n",
+ directory, strerror (errno));
+
+ for (idx=0; idx < count; idx++)
+ {
+ fi = sorted[idx];
+ fprintf (indexfp, "%s:%c:%llu:%lu:\n",
+ percent_escape (fi->name),
+ fi->is_dir? 'd':
+ fi->is_reg? 'r': '?',
+ fi->size,
+ (unsigned long)fi->mtime);
+ }
+ if (ferror (indexfp))
+ die ("error writing .ftp-index in '%s': %s\n",
+ directory, strerror (errno));
+ /* Fixme: Check for close errors. */
+ fclose (indexfp);
+ }
+
+ free (sorted);
+ while ((fi = finfo))
+ {
+ fi = finfo->next;
+ free (finfo);
+ finfo = fi;
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int last_argc = -1;
+ strlist_t sl;
+
+ if (argc < 1)
+ die ("Hey, read up on how to use exec(2)\n");
+ argv++; argc--;
+
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--"))
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--help"))
+ {
+ fputs ("usage: " PGMNAME " [options] directory [title]\n"
+ "Print an index for an FTP directory.\n\n"
+ "Options:\n"
+ " --verbose verbose diagnostics\n"
+ " --debug flyswatter\n"
+ " --reverse reverse sort order\n"
+ " --reverse-ver reverse only the version number order\n"
+ " --files-first print files before directories\n"
+ " --html output HTML\n"
+ " --gpgweb output HTML as used at gnupg.org\n"
+ " --readme include README file\n"
+ " --index create an .ftp-index file\n"
+ " --exclude NAME ignore file NAME\n"
+ , stdout);
+ exit (0);
+ }
+ else if (!strcmp (*argv, "--verbose"))
+ {
+ opt_verbose++;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--debug"))
+ {
+ opt_debug++;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--reverse"))
+ {
+ opt_reverse = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--reverse-ver"))
+ {
+ opt_reverse_ver = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--files-first"))
+ {
+ opt_files_first = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--readme"))
+ {
+ opt_readme = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--html"))
+ {
+ opt_html = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--index"))
+ {
+ opt_index = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--gpgweb"))
+ {
+ opt_gpgweb = opt_html = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--exclude"))
+ {
+ argc--; argv++;
+ if (!argc || !**argv)
+ die ("argument missing for option '%s'\n", argv[-1]);
+ sl = xmalloc (sizeof *sl + strlen (*argv));
+ strcpy (sl->d, *argv);
+ sl->next = opt_exclude;
+ opt_exclude = sl;
+ argc--; argv++;
+ }
+ else if (!strncmp (*argv, "--", 2))
+ die ("unknown option '%s' (use --help)\n", *argv);
+ }
+
+ if (argc < 1 || argc > 2)
+ die ("usage: " PGMNAME " [options] directory [title]\n");
+
+
+ scan_directory (argv[0], argv[1]? argv[1]:argv[0]);
+
+
+ return 0;
+}
+
+/*
+Local Variables:
+compile-command: "cc -Wall -g -o ftp-indexer ftp-indexer.c"
+End:
+*/
diff --git a/web/share/site.css b/web/share/site.css
index b34693f..c075577 100644
--- a/web/share/site.css
+++ b/web/share/site.css
@@ -1,758 +1,764 @@
/* site.css
*
* This code is Copyright 1998--2013 The GnuPG Project and licensed
* under a Creative Commons Attribution-ShareAlike 3.0 Unported
* License. See the file copying.org for details.
*/
/* Color names as used by lolo's old site design:
* gray #5c6064
* lightblue #d0dce8
* darkpurple #784c6c
* lightpurple #f0f0fc
* grayedlightpurple #ebebf4
*/
body {
background: #f0f0fc;
font-family: "Proxima Nova Regular","Segoe UI",Roboto,"Droid Sans","Helvetica Neue",Arial,sans-serif;
font-weight: 400;
height: 100%;
}
/*
div#wrapper {
background: transparent url(/share/email-envelope.png) top right no-repeat;
}
*/
div#wrapper,
div#footer {
max-width: 850px;
margin: auto;
}
h1,
h2,
h3 {
color: #000;
font-family: "Helvetica Neue",Arial,sans-serif;
font-weight: bold;
font-variant: small-caps;
letter-spacing: 0.1em;
}
h1,
h2 {
font-size: x-large;
}
h3 {
font-size: 1em;
}
/*
Links
*/
a:link {
/* color: #784c6c;*/
font-weight: bold;
text-decoration: none;
}
a:hover {
background-color: #d0dce8;
font-weight: bold;
text-decoration: none;
}
a:visited {
/* color: #5c6064; */
font-weight: bold;
text-decoration: none;
}
a.img:hover {
background-color: #f0f0fc;
}
/*
Raise attention
*/
li.important,
span.important {
color: red;
}
div.urgent {
width: 85%;
text-align: center;
border: solid red;
font-weight: bold;
}
.ii {
display: none !important;
}
/*
Other elements as commonly used by org-mode
*/
p {
margin-top: 1%;
}
img {
border-width: 0;
}
img.lfloat {
float: left;
margin-right: 1em;
}
img.rfloat {
float: right;
margin-left: 1em;
}
/* The figure class is used by the blog entries. We use display
to suppress the figure number inserted by org-mode. */
.figure {
border: 1px solid #808080;
margin: 0 1em 0.5em 0.5em;
padding: 0.5em;
text-align: center;
}
/* Use an outer div with this class to move an org figure to the left.
Note that org uses a fixed class for a figure and we use this hack
to override it. */
div.figure-left {
float: left;
}
div.figure {
float: right;
margin-right:0 !important;
}
.figure p {
margin: 0;
padding: 0.5em 0 0.2em 0;
}
.figure-number {
display: none !important;
}
.underline {
text-decoration: underline;
}
.example {
overflow: auto;
}
.correction {
color: #ff0000;
}
.postdate {
font-weight: normal;
font-style: italic;
}
div.entry-qotd p {
padding-left: 20%;
margin-bottom: 0;
}
div.entry-qotd {
margin-bottom: 3%;
}
#kicker {
padding-top: 5%;
font-size: 125%;
border-bottom: 3px #FFb580 solid;
font-family: verdana,helvetica;
margin-bottom: 2%;
}
#header {
background: transparent;
height: 150px;
padding: 0px;
}
#header a.logo img {
height: 120px;
}
#header a.logo:hover img {
background: transparent;
opacity: 0.4;
}
#header a,
#header a:hover {
background: transparent;
}
#cornerImage {
width: 128px;
height: 130px;
margin-top: -7.5em;
margin-left: 82%;
padding: 0;
padding-right: 2%;
}
/*
Navigation
*/
/* Reset the link attributes for nav except for hover */
nav a:visited,
a:link {
color: #757575;
font-weight: bold;
text-decoration: none;
}
nav ul,
ul ul.sub-menu {
margin: 0;
padding: 0;
z-index: 5;
}
nav ul {
box-shadow: 0px 0px 9px rgba(0,0,0,0.15);
padding: 0 20px;
border-radius: 10px;
background: #efefef;
list-style: none;
}
nav ul li,
ul ul.sub-menu li {
list-style-type: none;
display: inline-block;
}
/*Link Appearance*/
nav ul li a,
ul li ul.sub-menu li a {
text-decoration: none;
color: #fff;
padding: 10px;
display:inline-block;
}
/*Make the parent of sub-menu relative*/
nav ul li {
position: relative;
}
/*sub menu*/
nav ul li ul.sub-menu {
display:none;
}
nav ul li:hover ul.sub-menu {
display:block;
background: #5f6975;
color: #fff;
z-index: 99;
border-radius: 0px;
position: absolute;
top: 37px;
left: 0;
}
nav ul ul li {
border-bottom: 1px solid #575f6a;
position: relative;
width: 100%;
}
nav ul ul li a {
display:block !important;
}
nav ul ul li a:hover {
background: #4b545f;
}
/* The second menu line for stop menu with sub-menus.
This is a non-nested list. */
nav.subnav {
margin-top: 1.5em;
}
nav.subnav ul {
display: inline-table;
list-style: none;
color: #757575;
position: relative;
box-shadow: 0px 0px 5px rgba(0,0,0,0.15);
border-radius: 6px;
background-color: #efefef;
}
nav.subnav ul li a {
display: block;
font-weight: normal;
text-decoration: none;
padding: 0 30px 0 10px;
}
nav * li a.selected {
color: #0093DD;
}
/*
The bottom menu
*/
#nav_bottom ul {
list-style: none;
padding-left: 0;
margin-left: 0;
float: left;
}
#nav_bottom li {
float: left;
padding-right: 3em;
}
#nav_bottom p {
clear: left;
padding-top: 1em;
}
#nav_bottom a {
clear: left;
font-variant: normal;
}
/*
Other stuff
*/
main {
}
main ul {
list-style: square;
padding-left: 0;
margin-left: 1em;
}
div#content {
background-color: #fff;
margin-top: 1em;
padding: 1em;
box-shadow: 0 1px 1px rgba(154,170,207,0.1);
}
div#content a,
div#footer a {
color: #0093DD !important;
}
div.outline-text-2 {
margin: 0;
padding: 0.5em 0.5em 0 0;
border-top: 2px solid #DEECF9;
border-right: 2px solid #DEECF9;
}
div.outline-text-3 {
padding-top: 3px;
padding-right: 3px;
border-top: 1px solid #E2EEFA;
border-right: 1px solid #E2EEFA;
}
div.outline-text-2,
div.outline-text-3 {
margin-bottom: 2em;
}
div.outline-text-3,
div > h3 {
/*margin-left: 1em;*/
}
h2,
h3 {
margin-bottom: 0;
padding-bottom: 0;
}
h3 {
font-size: 1em;
}
/* Not anymore used:
#rightColumn {
float: right;
width: 18%;
margin-left: 5%;
margin-right: 2%;
margin-top: 2%;
}
#rightColumn ul {
list-style: square;
padding-left: 0;
margin-left: 1em;
}
*/
.morelink {
font-size: smaller;
font-variant: normal;
font-weight: normal;
text-decoration: none;
}
.morelink:after {
content: "{more}";
}
/* Note that the .footerbox takes care of the padding. */
#cpyright {
padding-top: 0em;
}
#smallnote {
font-size: 0.8em;
}
.smallnote {
font-size: 0.8em;
}
#footer {
border-top: 2px solid #5c6064;
margin-top: 5em;
margin-left: 5%;
margin-right: 5%;
clear: both;
font-size: 0.8em;
}
#checkoutSummary {
background-color: #f0f0f0;
}
.articleRight {
float: right;
padding: 2%;
}
pre {
border: thin black solid;
background-color: #efefef;
padding: 0.5em;
overflow: auto;
}
+pre.ftp-readme {
+ border: none;
+ background-color: #ffffff;
+}
+
+
/* Classes used by makeinfo (manuals). */
pre.display {
font-family:inherit;
}
pre.format {
font-family:inherit;
}
pre.smalldisplay {
font-family:inherit;
font-size:smaller;
}
pre.smallformat {
font-family:inherit;
font-size:smaller;
}
pre.smallexample {
font-size:smaller;
}
pre.smalllisp {
font-size:smaller;
}
span.sc {
font-variant:small-caps;
}
span.roman {
font-family:serif;
font-weight:normal;
}
span.sansserif {
font-family:sans-serif;
font-weight:normal;
}
/* Table related rules as used by org-mode. */
table {
margin-left: 5%;
}
.left {
margin-left: 0px;
margin-right: auto;
text-align: left;
}
.center {
margin-left: auto;
margin-right: auto;
text-align: center;
}
.right {
margin-left: auto;
margin-right: 0px;
text-align: right;
}
th.left {
text-align:center;
}
th.center {
text-align:center;
}
th.right {
text-align:center;
}
th.wideright {
text-align:center;
padding-left: 25px;
}
td.left {
text-align:left;
padding-left: 10px;
}
td.center {
text-align:center;
}
td.right {
text-align:right;
padding-right: 10px;
}
td.wideright {
text-align: right;
padding-left: 25px;
}
/* Footnotes for org-mode. */
h2.footnotes {
font-size: 100%;
}
#footnotes {
font-size: 75%;
}
.footnum {
font-size: 1em;
float: left;
}
/* Tag cloudlist. */
#tagcloudlist ul {
list-style: none;
float: left;
}
#tagcloudlist li {
float: left;
line-height: 130%;
font-variant: small-caps;
padding-right: 1em;
}
#tagcloudlist li:before {
content: "\00bb\00a0";
}
#tagcloudlist p {
clear: left;
padding-top: 1em;
font-size: 0.8em;
}
#tagcloudlist p.doclear {
clear: left;
padding-top: 0;
padding-bottom: 0;
margin-top: 0;
margin-bottom: 0;
}
#tagcloudlist a {
font-variant: normal;
font-size: 0.8em;
}
/* A box of logos. */
.logobox p {
margin-top: 20px;
}
.logobox img {
margin-right: 20px;
}
/* A box used for small graphics at the page bottom.
The images are right aligned, a single P is used
to clear the alignment. */
.footerbox {
margin-top: 12px;
margin-bottom: 5px;
}
.footerbox img {
float: right;
}
.footerbox p {
margin-top: 0px;
margin-bottom: 0px;
clear: both;
}
/* Used by the list of people. */
.people {
float: left;
margin-top: 1em;
margin-right: 1em;
margin-bottom: 1em;
min-width: 120px;
}
/* Forms */
.inputpanel {
background-color: #FAEBD7;
}
/* Donation stuff. */
.buttonbox {
margin-top: 20px;
margin-bottom: 20px;
float: none;
}
.donate-button {
overflow: hidden;
display: inline-block;
background-image: linear-gradient(#28A0E5, #015E94);
/* border: 0px none; */
padding-left: 10px;
padding-right: 10px;
text-decoration: none;
border-radius: 5px;
box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.2);
cursor: pointer;
line-height: 30px;
font-size: 14px;
font-weight: bold;
color: #fff;
float: left;
margin-right: 20px;
margin-bottom: 20px;
}
.donate-button-low {
overflow: hidden;
display: inline-block;
background-image: linear-gradient(#28A0E5, #015E94);
/* border: 0px none;*/
padding-left: 10px;
padding-right: 10px;
text-decoration: none;
border-radius: 4px;
box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.2);
cursor: pointer;
line-height: 20px;
font-size: 14px;
font-weight: bold;
color: #fff;
float: left;
margin-right: 20px;
margin-bottom: 20px;
margin-top: 5px;
}
.donation-progress {
border: solid 1px;
width: 100%;
height: 18px;
background-color: #ff0;
}
.donation-progress p {
position: relative;
font-size: 14px;
top: -18px;
left: 0;
margin-top: 0;
margin-left: 5px;
margin-right: 5px;
margin-bottom: 0;
padding-bottom: 2px;
}
.donation-progress-bar {
background-color: #0a0;
}
/* EOF */