Add Goteo data collect scripts.
authorWerner Koch <wk@gnupg.org>
Thu, 6 Feb 2014 16:34:45 +0000 (17:34 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 6 Feb 2014 16:35:54 +0000 (17:35 +0100)
misc/accounts.gnupg.net/htbin/goteo-collect.cgi [new file with mode: 0755]
misc/accounts.gnupg.net/htdocs/goteo-collect-thx.html.in [new file with mode: 0644]
misc/accounts.gnupg.net/htdocs/goteo-collect.html.in [new file with mode: 0644]
misc/accounts.gnupg.net/htdocs/logo-gnupg-light-purple-bg.png [new file with mode: 0644]
misc/accounts.gnupg.net/htdocs/site.css [new file with mode: 0644]
misc/accounts.gnupg.net/upload [new file with mode: 0755]

diff --git a/misc/accounts.gnupg.net/htbin/goteo-collect.cgi b/misc/accounts.gnupg.net/htbin/goteo-collect.cgi
new file mode 100755 (executable)
index 0000000..146d606
--- /dev/null
@@ -0,0 +1,260 @@
+#!/usr/bin/perl -T
+
+# goteo-collect.cgi   - Collect data for rewards of the 2013 Goteo campaign
+# Copyright (C) 2014 g10 Code GmbH
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This scripts presents a customized page to collect information for
+# the Goteo campaign rewards.  it expects a template file
+# goteo-collect.html.in with certain '@' delimited variables and data
+# file /var/log/gnupg.net/goteo-collect.input with the information to
+# be presented to the user.  The result will be logged to the file
+# /var/log/gnupg.net/goteo-collect in a mail header like format to be
+# later processed using GNU recutils or addrutil.  The input is
+# expected to be colon separated with one record per line.  All values
+# use percent encoding but may use unencoded spaces.  The fields are:
+#
+# 1. id      := A random string to identify the record.  This is
+#               part of the URL send by mail to the respective
+#               contributor.
+# 2. account := The Goteo account name
+# 3. name    := Name of the contributor
+# 4. reward  := Type of the reward: 't' = t-shirt
+#                                   'm' = mail address
+#                                   's' = sticker
+# 5. mail    := real mail address
+# 6. address := The address data (only required for 't')
+
+#
+# Note that this script needs libmime-base32-perl.
+
+# Preparing the inpout data.  We received the Input data as
+# spreadshit. The follwoing steps have been used to create the input
+# data:
+#  - Use gnumeric to create a CSV file.
+#  - Run addrutil like this
+#
+#     tail -n+2 FILE \
+#       ./addrutil -FGoteo-ID -FUser -FName -FMail -FAmount -FProblem \
+#                  -FAnon -FReward -FAddress -FDate --readcsv   \
+#       | sed '/^Address:/ s/ , , ,//' | sed '/^Address:/ s/,/\n/g' > data
+#
+#    Now we have the data in an easy to read format.  The tool addrutil is
+#    available at 'http://git.gnupg.org/cgi-bin/gitweb.cgi\
+#                  ?p=wk-misc.git;f=addrutil.c;a=blob_plain'
+#
+#  - Change some more strings:
+#       cat data \
+#       | sed 's/^Reward: An @GnuPG.*/Reward: m/' \
+#       | sed 's/^Reward: .*sticker.*/Reward: s/' \
+#       | sed 's/^Reward: .*tshirt.*/Reward: t/'  \
+#       | sed 's/^Reward: .*Listed.*/Reward: l/' > newdata
+#
+#   cat data | sed 's/^Reward: An @GnuPG.*/Reward: m/' | sed 's/^Reward: .*sticker.*/Reward: s/'| sed 's/^Reward: .*tshirt.*/Reward: t/'  | sed 's/^Reward: .*Listed.*/Reward: l/'
+#
+#  - To add a unique ID use this command
+#
+#    awk '/^Goteo-ID:/ {cmd="gpg -a --gen-random 0 15 | tr +/ 42"; cmd | getline foo; print "Id: " foo; close(cmd); }; {print}' data >newdata
+#
+#  - To finally create the input data
+#    fields="-FId -FUser -FName -FReward -FMail -FAddress"
+#     ( ./addrutil -SReward=t $fields data \
+#      && ./addrutil -SReward=m $fields data) > goteo-collect.input
+#
+
+
+
+use CGI;
+use POSIX qw(strftime);
+use Fcntl qw(:flock SEEK_END);
+use MIME::Base32 qw( RFC );
+
+my $time = strftime "%Y-%m-%d %H:%M:%S", gmtime;
+my $htdocs = '/var/www/all/accounts.gnupg.net/htdocs/';
+
+my $q  = new CGI;
+
+my $id = $q->param("id");
+my $mode = $q->param("mode");
+my $address = "";
+my $txid = "";
+my $errorstr = "";
+my $tsize= "";
+
+sub get_txid {
+    local $data;
+
+    open (DEVRAND, "<", "/dev/urandom");
+    read (DEVRAND, $data, 6);
+    close (DEVRAND);
+    MIME::Base32::encode($data);
+}
+
+# Write the collected data out to the log file.  On return
+# $txid has the transaction id.
+sub write_logfile {
+    open(LOGFILE, ">>", "/var/log/gnupg.net/goteo-collect")
+        || die "error opening log file: $!";
+    flock(LOGFILE, LOCK_EX) || die "error locking log file: $!";
+    seek(LOGFILE, 0, SEEK_END) || die "error seek to end of log file: $!";
+
+    $txid = &get_txid();
+
+    print LOGFILE "Start: $time\n";
+    print LOGFILE "txid: $txid\n";
+    print LOGFILE "reward: $reward\n";
+    foreach $name ($q->param) {
+        $value = $q->param($name);
+        if ($name !~ /^Start/i) {
+            $value =~ s/\r//g;
+            chomp $value;
+            $value =~ s/\n/\n  /g;
+            print LOGFILE "$name: $value\n";
+        }
+    }
+    print LOGFILE "\n";
+
+    flock(LOGFILE, LOCK_UN) || die "error unlocking log file: $!";
+    close(LOGFILE) || die "error closing log file: $!";
+}
+
+
+# Find the item for $id and fill in all numbers.  Return false if not
+# found.
+sub find_item {
+    local $tmpid;
+    open(INPUTFILE, "<", "/var/log/gnupg.net/goteo-collect.input")
+        || die "error opening input file: $!";
+    while (<INPUTFILE>) {
+        chomp;
+        ($tmpid, $account, $name, $reward, $mail, $address) = split (/:/);
+        if ($tmpid eq $id) {
+            close(INPUTFILE);
+            $account =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/ge;
+            $name =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/ge;
+            $mail =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/ge;
+            $address =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/ge;
+            return 1;
+        }
+    }
+    close(INPUTFILE);
+    0;
+}
+
+
+sub write_template {
+    local $fname = shift;
+    local $indel = 0;
+    local $fulladdress;
+
+
+    if ( "$address" =~ /^$name/ ) {
+        $fulladdress = $address;
+    } else {
+        $fulladdress = "$name\n$address";
+    }
+
+    open TEMPLATE, $htdocs . $fname;
+    while (<TEMPLATE>) {
+        if ($indel) {
+            $indel = 0 if (/<!--END_/);
+            next;
+        }
+        elsif (($reward eq 'm') && /^<!--BEGIN_T_SHIRT/) {
+            $indel = 1;
+            next;
+        }
+        elsif (($reward eq 't') && /^<!--BEGIN_MAIL/) {
+            $indel = 1;
+            next;
+        }
+
+        # Only one replacement allowed to avoid recursive replacements
+        s/\x40ID\x40/$id/g
+        || s/\x40NAME\x40/$name/g
+        || s/\x40ACCOUNT\x40/$account/g
+        || s/\x40ADDRESS\x40/$fulladdress/g
+        || s/\x40MAIL\x40/$mail/g
+        || s/\x40REWARD\x40/$reward/g
+        || s/\x40TXID\x40/$txid/g
+        || s/\x40TSIZE\x40/$tsize/g
+        || s/\x40MAILBOX\x40/$mailbox/g
+        || s/\x40MAILBOX2\x40/$mailbox2/g
+        || s/\x40ERRORSTR\x40/$errorstr/g;
+
+        print;
+    }
+    close TEMPLATE;
+}
+
+
+# Write a page with all the data for the goteo account.
+sub write_main_page {
+    print $q->header(-type=>'text/html', -charset=>'utf-8');
+    print "\n";
+    &write_template("goteo-collect.html.in");
+}
+
+sub write_error_page {
+    local $text = shift;
+
+    $errorstr = '<p style="color: red;">' . $text . '</p>';
+    # Keep the entered values.
+    $mail = $q->param('mail');
+    $address = $q->param('address');
+    $mailbox = $q->param('mailbox');
+    $mailbox2 = $q->param('mailbox2');
+    &write_main_page();
+}
+
+# Write a page with the collected data
+sub write_thanks_page {
+    print $q->header(-type=>'text/html', -charset=>'utf-8');
+    print "\n";
+    $mail = $q->param('mail');
+    $address = $q->param('address');
+    $mailbox = $q->param('mailbox');
+    $mailbox2 = $q->param('mailbox2');
+    $tsize    = $q->param('tsize');
+    &write_template("goteo-collect-thx.html.in");
+}
+
+
+#
+# Main
+#
+if ($id eq '') {
+    print $q->header('text/html');
+    print $q->start_html('Error');
+    print $q->h1('Bad request - please use the correct URL');
+    print $q->end_html;
+}
+elsif (not &find_item()) {
+    print $q->header('text/html');
+    print $q->start_html('Error');
+    print $q->h1('No such URL');
+    print $q->p('Please verify that you used the URL from the mail');
+    print $q->end_html;
+}
+elsif ($mode eq 'response') {
+    if ($q->param('mail') !~ /[a-zA-Z0-9]+@[a-zA-Z]+/ ) {
+        write_error_page('Invalid mail address given!');
+    }
+    elsif ($reward eq 't' and $q->param('tsize') !~ /^[SLX]$/ ) {
+        write_error_page('Size of t-shirt not given!');
+    }
+    else {
+        write_logfile();
+        write_thanks_page();
+    }
+}
+else {
+    &write_main_page();
+}
diff --git a/misc/accounts.gnupg.net/htdocs/goteo-collect-thx.html.in b/misc/accounts.gnupg.net/htdocs/goteo-collect-thx.html.in
new file mode 100644 (file)
index 0000000..f85aaaa
--- /dev/null
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+  <title>gnupg.net account management - GNU Privacy Guard</title>
+  <link href="/site.css" rel="stylesheet" />
+</head>
+<body>
+<table class="layout" cellspacing="30" summary="">
+<col width="20%" /><col width="80%" />
+<tbody>
+  <tr id="top-page">
+  <td class="layout" colspan="2">
+  <table class="frame" width="100%" summary="">
+  <col width="30%" /><col width="*" /><col width="30%" />
+  <col width="23" />
+<tbody>
+  <tr>
+    <td class="frame-head">&nbsp;</td>
+    <td class="frame-head">
+      <a href="http://gnupg.org"
+         ><img src="/logo-gnupg-light-purple-bg.png" alt="[GnuPG Logo]"
+               width="356" height="120" /></a></td>
+    <td class="frame-head">&nbsp;</td>
+    <td class="frame-right">&nbsp;</td>
+  </tr>
+  <tr>
+    <td class="frame-bottom-lang">&middot; English &middot; &nbsp;</td>
+    <td class="frame-bottom-lang">&nbsp;</td>
+    <td class="frame-bottom-mirror">&nbsp;</td>
+    <td class="frame-corner">&nbsp;</td>
+  </tr>
+</tbody>
+</table>
+</td>
+</tr>
+<tr>
+  <td class="layout">
+    <table class="frame" width="100%" summary="">
+      <col width="*" /><col width="23" />
+      <tbody>
+       <tr>
+         <td class="frame-navb">Links
+           <ul class="frame-navb">
+             <li class="frame-navb"><a href="http://www.gnupg.org">GnuPG</a></li>
+           </ul>
+         </td>
+         <td class="frame-right">&nbsp;</td>
+       </tr>
+       <tr>
+         <td class="frame-bottom">&nbsp;</td>
+         <td class="frame-corner">&nbsp;</td>
+       </tr>
+       <tr>
+         <td class="frame-spacing">&nbsp;</td>
+       </tr>
+      </tbody>
+    </table>
+  </td>
+
+  <td class="layout">
+    <table class="frame" width="100%" summary="">
+      <col width="*" /><col width="23" />
+      <tbody>
+       <tr>
+         <td class="frame-cont">
+
+<!-- Begin Content -->
+
+<h1>gnupg.net account management</h1>
+
+<p>Information received.</p>
+
+<!--BEGIN_T_SHIRT-->
+<p>Please have some patience until information for all contributors
+   has been collected.  As soon as we are ready to ship the t-shirts,
+   we will notify you by mail and post
+   a <a href="http://blog.gnupg.org">blog item</a></p>
+
+<p>We now have this data on file:</p>
+<pre>
+Name: @NAME@
+Mail: @MAIL@
+Size: @TSIZE@
+Address:
+@ADDRESS@
+</pre>
+<!--END_T_SHIRT-->
+
+<!--BEGIN_MAIL-->
+<p>Please have some patience until information for all mail accounts
+   has been collected. You will receive a mail telling you when your
+   new mail address is ready for use.</p>
+
+<p>We now have this data on file:</p>
+<pre>
+Name: @NAME@
+Mail: @MAIL@
+Choice1: @MAILBOX@@gnupg.net
+Choice2: @MAILBOX2@@gnupg.net
+</pre>
+
+We may also have a public key on file.  You may update the public key at
+any later time.
+
+<!--END_MAIL-->
+
+<p>If we ever run into problems, we may ask you for a transaction id.
+  Please note it down:</p>
+<pre>@TXID@</pre>
+
+<p>Thank you.</p>
+
+
+<!-- End Content -->
+</td>
+</tr>
+</tbody>
+</table>
+</body>
+</html>
diff --git a/misc/accounts.gnupg.net/htdocs/goteo-collect.html.in b/misc/accounts.gnupg.net/htdocs/goteo-collect.html.in
new file mode 100644 (file)
index 0000000..b13079d
--- /dev/null
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+  <title>gnupg.net account management - GNU Privacy Guard</title>
+  <link href="/site.css" rel="stylesheet" />
+</head>
+<body>
+<table class="layout" cellspacing="30" summary="">
+<col width="20%" /><col width="80%" />
+<tbody>
+  <tr id="top-page">
+  <td class="layout" colspan="2">
+  <table class="frame" width="100%" summary="">
+  <col width="30%" /><col width="*" /><col width="30%" />
+  <col width="23" />
+<tbody>
+  <tr>
+    <td class="frame-head">&nbsp;</td>
+    <td class="frame-head">
+      <a href="http://gnupg.org"
+         ><img src="/logo-gnupg-light-purple-bg.png" alt="[GnuPG Logo]"
+               width="356" height="120" /></a></td>
+    <td class="frame-head">&nbsp;</td>
+    <td class="frame-right">&nbsp;</td>
+  </tr>
+  <tr>
+    <td class="frame-bottom-lang">&middot; English &middot; &nbsp;</td>
+    <td class="frame-bottom-lang">&nbsp;</td>
+    <td class="frame-bottom-mirror">&nbsp;</td>
+    <td class="frame-corner">&nbsp;</td>
+  </tr>
+</tbody>
+</table>
+</td>
+</tr>
+<tr>
+  <td class="layout">
+    <table class="frame" width="100%" summary="">
+      <col width="*" /><col width="23" />
+      <tbody>
+       <tr>
+         <td class="frame-navb">Links
+           <ul class="frame-navb">
+             <li class="frame-navb"><a href="http://www.gnupg.org">GnuPG</a></li>
+           </ul>
+         </td>
+         <td class="frame-right">&nbsp;</td>
+       </tr>
+       <tr>
+         <td class="frame-bottom">&nbsp;</td>
+         <td class="frame-corner">&nbsp;</td>
+       </tr>
+       <tr>
+         <td class="frame-spacing">&nbsp;</td>
+       </tr>
+      </tbody>
+    </table>
+  </td>
+
+  <td class="layout">
+    <table class="frame" width="100%" summary="">
+      <col width="*" /><col width="23" />
+      <tbody>
+       <tr>
+         <td class="frame-cont">
+
+<!-- Begin Content -->
+
+<h1>gnupg.net account management</h1>
+
+<p>Hello @NAME@!</p>
+
+@ERRORSTR@
+
+<p>You received a mail pointing you to this page.  First of all we
+   like to thank you for supporting the development of GnuPG by taking
+   an active part in the crowdfunding campaign.</p>
+
+<!--BEGIN_T_SHIRT-->
+<p>You requested a GnuPG t-shirt as your reward.  We now need to collect some
+   additional information so that we are able to ship the t-shirt.</p>
+<!--END_T_SHIRT-->
+
+<!--BEGIN_MAIL-->
+<p>You requested a GnuPG.net mail alias as your reward.  We now need
+   to collect some additional information so that we are able to setup
+   the account.</p>
+<!--END_MAIL-->
+
+<form action="/htbin/goteo-collect.cgi?id=@ID@" method="post">
+<input type="hidden" name="id" value="@ID@" />
+<input type="hidden" name="mode" value="response" />
+
+<!--BEGIN_T_SHIRT-->
+<p>Please select the size for the t-shirt:</p>
+<p>
+  <input type="radio" name="tsize" value="S">Size S</input><br/>
+  <input type="radio" name="tsize" value="L">Size L</input><br/>
+  <input type="radio" name="tsize" value="X">Size XL</input><br/>
+</p>
+
+<p>Please double check the shipping address (e.g. name and country
+  given) and change if necessary: :<p>
+<textarea cols="80" rows="6" style="width:500px" name="address"
+                >@ADDRESS@
+</textarea>
+
+
+<p>Please also enter an email address we can use in case of delivery
+problems:</p>
+<p><input type="text" size="80" style="width:500px" name="mail"
+          value="@MAIL@" /></p>
+<!--END_T_SHIRT-->
+
+
+<!--BEGIN_MAIL-->
+<p>Please enter your desired mailbox name without the name (if you enter
+"foo" the mail address wil be "foo@gnupg.net").</p>
+<p><input type="text" size="40" style="width:200px" name="mailbox"
+          value="@ACCOUNT@" />@gnupg.net</p>
+<p>In case that address has already been assigned, please enter your
+  second choice:</p>
+<p><input type="text" size="40" style="width:200px" name="mailbox2"
+          value="" />@gnupg.net</p>
+
+<p>Your new address will be an alias to your real mail address.
+Please enter this forwarding mail address:</p>
+<p><input type="text" size="80" style="width:500px" name="mail"
+          value="@MAIL@" /></p>
+
+<p>All mail received at your new gnupg.net address will be forwarded to
+that address.  We will also use this address to contact you in case of
+problems.  The gnupg.net mail server has greylisting enabled as well
+as some minor sanity checks.  No strong spam or virus checking is
+done.  You may not send mail via that server.</p>
+
+<p>We may eventually add a service to retrieve public keys for
+   gnupg.net.  If you want that, please paste the fingerprint of your
+   public key or the entire key into the field below.</p>
+<textarea cols="80" rows="10" style="width:500px" name="pubkey"
+                ></textarea>
+
+<!--END_MAIL-->
+
+
+
+<p><input type="submit" value="Send" /></p>
+
+</form>
+
+
+
+<!-- End Content -->
+</td>
+</tr>
+</tbody>
+</table>
+</body>
+</html>
diff --git a/misc/accounts.gnupg.net/htdocs/logo-gnupg-light-purple-bg.png b/misc/accounts.gnupg.net/htdocs/logo-gnupg-light-purple-bg.png
new file mode 100644 (file)
index 0000000..41264d9
Binary files /dev/null and b/misc/accounts.gnupg.net/htdocs/logo-gnupg-light-purple-bg.png differ
diff --git a/misc/accounts.gnupg.net/htdocs/site.css b/misc/accounts.gnupg.net/htdocs/site.css
new file mode 100644 (file)
index 0000000..8e5fcc4
--- /dev/null
@@ -0,0 +1,273 @@
+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;
+}
+BLOCKQUOTE {
+  border: 1px solid black;
+  padding: 1em;
+}
+BODY {
+  margin-left: 0px;
+  margin-right: 0px;
+  text-align: left;
+  color: black;
+  background-color: #f0f0fc;
+  font-family: sans-serif;
+  font-weight: normal;
+  text-decoration: none;
+}
+DD {
+  padding-bottom: 1em;
+}
+H1
+{
+  font-size: large;
+}
+h2 {
+       font-size: 1em;
+       margin: 2em 0 1em;
+}
+H1:first-letter,
+H2:first-letter {
+  font-size: x-large;
+}
+H3:first-letter {
+  font-size: large;
+}
+H1,
+H2,
+H3 {
+  color: #5c6064;
+  font-weight: bold;
+  font-variant: small-caps;
+  letter-spacing: 0.1em;
+}
+H1:first-letter,
+H2:first-letter,
+H3:first-letter {
+  color: #784c6c;
+}
+IMG {
+  border: none;
+}
+LI.important {
+  color: red;
+}
+P.out-of-date {
+  font-style: italic;
+  font-size: small;
+}
+PRE,
+DIV.samp {
+  background-color: #ebebf4;
+  margin: 1em;
+  border: 1px solid black;
+  padding: 1em;
+  font-size: small;
+}
+SPAN.important {
+  color: red;
+}
+DIV.urgent {
+  width: 85%;
+  text-align: center;
+  border: solid red;
+  font-weight: bold;
+}
+TABLE.layout {
+  background-color: transparent;
+  border-collapse: separate;
+  border: none;
+  max-width: 1200px;
+}
+TD.layout {
+  border: 1px none black;
+  padding: 0px;
+  text-align: right;
+  vertical-align: top;
+}
+TABLE.frame {
+  background-color: transparent;
+  border-collapse: collapse;
+  border: 1px none black;
+}
+TD.frame-right {
+  border-left: 2px solid #784c6c;
+}
+TD.frame-bottom,
+TD.frame-bottom-lang,
+TD.frame-bottom-mirror {
+  color: #5c6064;
+  border-top: 2px solid #5c6064;
+  text-align: left;
+  font-size: small;
+  font-weight: bold;
+}
+TD.frame-bottom-lang,
+TD.frame-bottom-mirror {
+  font-size: x-small;
+}
+TD.frame-bottom-mirror {
+  text-align: right;
+}
+TD.frame-corner {
+  border-top: 2px solid #5c6064;
+  border-left: 2px solid #784c6c;
+}
+TD.frame-spacing {
+  border: none;
+  height: 30px;
+}
+TD.frame-head {
+  padding: 0px 0px 1em 0px;
+  border: none;
+  text-align: center;
+  vertical-align: middle;
+  font-size: large;
+  font-variant: small-caps;
+  font-weight: bold;
+  letter-spacing: 0.3em;
+}
+TD.frame-head-blockquote {
+  padding: 0px 1em 1em 1em;
+  border-bottom: 2px solid #5c6064;
+  vertical-align: middle;
+  font-family: sans-serif;
+  text-align: center;
+  text-decoration: none;
+  font-size: x-small;
+  font-variant: small-caps;
+  letter-spacing: 0.3em;
+}
+SPAN.g {
+  color: #784c6c;
+  font-size: x-large;
+}
+SPAN.nu {
+  color: #784c6c;
+}
+SPAN.pg {
+  color: #5c6064;
+  font-size: x-large;
+}
+A.lang {
+  font-size: x-small;
+}
+A.lang:visited {
+  color: #784c6c;
+}
+TD.frame-navb {
+  padding: 0px 0.3em 0.5em 0.3em;
+  text-align: left;
+  font-size: small;
+}
+UL.frame-navb {
+  margin: 0px;
+  margin-left: 1em;
+  padding-left: 1em;
+}
+UL.frame-navb:first-line {
+  margin: 0px;
+  padding-left: 1em;
+}
+LI.frame-navb {
+}
+TD.frame-cont {
+  padding: 0px 1em 1.5em 1em;
+  text-align: left;
+  vertical-align: top;
+}
+DIV.frame-foot {
+  text-align: center;
+  font-size: x-small;
+  color: #5c6064;
+}
+A.foot:link {
+  color: #5c6064;
+  font-size: x-small;
+  font-weight: normal;
+  text-decoration: underline;
+}
+A.foot:visited {
+  color: #5c6064;
+  font-size: x-small;
+  font-weight: normal;
+  text-decoration: underline;
+}
+A.foot:hover {
+  font-size: x-small;
+  font-weight: normal;
+}
+#footer-legal {
+       padding: 0.3em 0;
+       font-size: 1.5em;
+       background: #DCDCFF;
+}
+/*PHP list subscription confirmation box*/
+.subscribed {
+       background-color: #D4D4D4;
+       padding: 0.5em;
+}
+
+.left
+, .captioned-image.left {
+       float: left;
+       margin-left: 0!important;
+}
+
+.right
+, .captioned-image.right {
+       float: right;
+       margin-right:0!important;
+}
+
+/*Blog rules*/
+.entry {
+       clear: both;
+}
+
+/* The perma link .  */
+.permalink {
+    float: right;
+    font-style: italic;
+    font-size: 0.6em;
+    margin-bottom: 1em;
+}
+
+a.permalink:before {
+    content: "{permanent link}";
+}
+
+
+/*Image caption rules*/
+.captioned-img {
+       border: 1px solid #808080;
+       margin: 0 1em 0.5em 0.5em;
+       padding: 0.5em;
+       text-align: center;
+}
+
+.captioned-img p {
+       margin: 0;
+       padding: 0.5em 0 0.2em 0;
+}
+
+.orange-text {
+       color: #C57A04;
+}
+
+/* eof */
\ No newline at end of file
diff --git a/misc/accounts.gnupg.net/upload b/misc/accounts.gnupg.net/upload
new file mode 100755 (executable)
index 0000000..24d70b6
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+set -e
+
+if [ "$(pwd  | awk -F/ '{print $NF}')" != "accounts.gnupg.net" ]; then
+  echo "upload: not invoked from the accounts.gnupg.net directory" >&2;
+  exit 1
+fi
+
+rsync -vr --links --exclude '*~' --exclude upload \
+   . alberti.gnupg.org:/var/www/all/accounts.gnupg.net/
+
+#eof