infocalypse
 
(Steve Dougherty)
2013-06-20: Merge previous head with fixed merge.

Merge previous head with fixed merge.

diff --git a/infocalypse/__init__.py b/infocalypse/__init__.py
--- a/infocalypse/__init__.py
+++ b/infocalypse/__init__.py
@@ -339,555 +339,15 @@ d kar bott at com cast dot net
 import os
 
 from commands import *
+
 from mercurial import commands, extensions, util, hg, dispatch, discovery
 from mercurial.i18n import _
+
 import freenetrepo
 
-from infcmds import get_config_info, execute_create, execute_pull, \
-     execute_push, execute_setup, execute_copy, execute_reinsert, \
-     execute_info
-
-from fmscmds import execute_fmsread, execute_fmsnotify, get_uri_from_hash, \
-     execute_setupfms
-
-from sitecmds import execute_putsite, execute_genkey
-from wikicmds import execute_wiki, execute_wiki_apply
-from arccmds import execute_arc_create, execute_arc_pull, execute_arc_push, \
-     execute_arc_reinsert
-
-from config import read_freesite_cfg
-from validate import is_hex_string, is_fms_id
-
-def set_target_version(ui_, repo, opts, params, msg_fmt):
-    """ INTERNAL: Update TARGET_VERSION in params. """
-
-    revs = opts.get('rev') or None
-    if not revs is None:
-        for rev in revs:
-            repo.changectx(rev) # Fail if we don't have the rev.
-
-        params['TO_VERSIONS'] = tuple(revs)
-        ui_.status(msg_fmt % ' '.join([ver[:12] for ver in revs]))
-    else:
-        # REDFLAG: get rid of default versions arguments?
-        params['TO_VERSIONS'] = tuple([hexlify(head) for head in repo.heads()])
-        #print "set_target_version -- using all head"
-        #print params['TO_VERSIONS']
-
-def infocalypse_create(ui_, repo, **opts):
-    """ Create a new Infocalypse repository in Freenet. """
-    params, stored_cfg = get_config_info(ui_, opts)
-
-    insert_uri = ''
-    attributes = None
-    if opts['uri'] != '' and opts['wot'] != '':
-        ui_.warn("Please specify only one of --uri or --wot.\n")
-        return
-    elif opts['uri'] != '':
-        insert_uri = opts['uri']
-    elif opts['wot'] != '':
-        # Expecting wot_id/repo_name.R<redundancy num>/edition/
-        wot_id, repo_desc = opts['wot'].split('/', 1)
-
-        import wot
-
-        ui_.status("Querying WoT for local identities.\n")
-
-        attributes = wot.resolve_local_identity(ui_, wot_id)
-        if attributes is None:
-            # Something went wrong; the function already printed an error.
-            return
-
-        ui_.status('Found {0}@{1}\n'.format(attributes['Nickname'],
-                                            attributes['Identity']))
-
-        insert_uri = attributes['InsertURI']
-
-        # LCWoT returns URIs with a "freenet:" prefix, and WoT does not. The
-        # rest of Infocalypse does not support the prefix. The local way to fix
-        # this is to remove it here, but the more flexible way that is also
-        # more work is to expand support to the rest of Infocalypse.
-        # TODO: More widespread support for "freenet:" URI prefix.
-        prefix = "freenet:"
-        if insert_uri.startswith(prefix):
-            insert_uri = insert_uri[len(prefix):]
-
-        # URI is USK@key/WebOfTrust/<edition>, but we only want USK@key
-        insert_uri = insert_uri.split('/', 1)[0]
-        insert_uri += '/' + repo_desc
-
-        # Add "vcs" context. No-op if the identity already has it.
-        msg_params = {'Message':'AddContext',
-                      'Identity': attributes['Identity'],
-                      'Context': 'vcs'}
-
-        import fcp
-        node = fcp.FCPNode()
-        vcs_response =\
-            node.fcpPluginMessage(async=False,
-                                  plugin_name="plugins.WebOfTrust.WebOfTrust",
-                                  plugin_params=msg_params)[0]
-
-        if vcs_response['header'] != 'FCPPluginReply' or\
-                'Replies.Message' not in vcs_response or\
-                vcs_response['Replies.Message'] != 'ContextAdded':
-            ui_.warn("Failed to add context. Got {0}\n.".format(vcs_response))
-            return
-
-        # TODO: Would it be friendlier to include the nickname as well?
-        stored_cfg.set_wot_identity(stored_cfg.get_request_uri(repo.root),
-                                    attributes['Identity'])
-    else:
-        ui_.warn("Please set the insert key with either --uri or --wot.\n")
-
-    set_target_version(ui_, repo, opts, params,
-                       "Only inserting to version(s): %s\n")
-    params['INSERT_URI'] = insert_uri
-    inserted_to = execute_create(ui_, repo, params, stored_cfg)
-
-    # TODO: Move into some function. How to separate local success context?
-    if inserted_to is not None and attributes is not None and \
-       stored_cfg.has_wot_identity(stored_cfg.get_request_uri(repo.root)):
-        import wot
-        wot.update_repo_listing(ui_, attributes['Identity'])
-
-def infocalypse_copy(ui_, repo, **opts):
-    """ Copy an Infocalypse repository to a new URI. """
-    params, stored_cfg = get_config_info(ui_, opts)
-
-    insert_uri = opts['inserturi']
-    if insert_uri == '':
-        # REDFLAG: fix parameter definition so that it is required?
-        ui_.warn("Please set the insert URI with --inserturi.\n")
-        return
-
-    request_uri = opts['requesturi']
-    if request_uri == '':
-        request_uri = stored_cfg.get_request_uri(repo.root)
-        if not request_uri:
-            ui_.warn("There is no stored request URI for this repo.\n"
-                     "Please set one with the --requesturi option.\n")
-            return
-
-    params['INSERT_URI'] = insert_uri
-    params['REQUEST_URI'] = request_uri
-    execute_copy(ui_, repo, params, stored_cfg)
-
-def infocalypse_reinsert(ui_, repo, **opts):
-    """ Reinsert the current version of an Infocalypse repository. """
-    params, stored_cfg = get_config_info(ui_, opts)
-
-    request_uri = opts['uri']
-    if request_uri == '':
-        request_uri = stored_cfg.get_request_uri(repo.root)
-        if not request_uri:
-            ui_.warn("There is no stored request URI for this repo.\n"
-                     "Do a fn-pull from a repository USK and try again.\n")
-            return
-
-    level = opts['level']
-    if level < 1 or level > 5:
-        ui_.warn("level must be 1,2,3,4 or 5.\n")
-        return
-
-    insert_uri = stored_cfg.get_dir_insert_uri(repo.root)
-    if not insert_uri:
-        if level == 1 or level == 4:
-            ui_.warn(("You can't re-insert at level %i without the "
-                     + "insert URI.\n") % level)
-            return
-
-        ui_.status("No insert URI. Will skip re-insert "
-                   +"of top key.\n")
-        insert_uri = None
-
-    params['INSERT_URI'] = insert_uri
-    params['REQUEST_URI'] = request_uri
-    params['REINSERT_LEVEL'] = level
-    execute_reinsert(ui_, repo, params, stored_cfg)
-
-def infocalypse_pull(ui_, repo, **opts):
-    """ Pull from an Infocalypse repository in Freenet.
-     """
-    params, stored_cfg = get_config_info(ui_, opts)
-
-    if opts['hash']:
-        # Use FMS to lookup the uri from the repo hash.
-        if opts['uri'] != '':
-            ui_.warn("Ignoring --uri because --hash is set!\n")
-        if len(opts['hash']) != 1:
-            raise util.Abort("Only one --hash value is allowed.")
-        params['FMSREAD_HASH'] = opts['hash'][0]
-        params['FMSREAD_ONLYTRUSTED'] = bool(opts['onlytrusted'])
-        request_uri = get_uri_from_hash(ui_, repo, params, stored_cfg)
-    elif opts['wot']:
-        import wot
-        if opts['truster']:
-            truster = opts['truster']
-        else :
-            truster = stored_cfg.get_wot_identity(
-                stored_cfg.get_dir_insert_uri(repo.root))
-        # TODO: Require repo name, not full path as part of the --wot. Look
-        # it up from the XML.
-        # TODO: Insert XML.
-
-        # Expecting <id stuff>/reponame
-        wot_id, repo_name = opts['wot'].split('/', 1)
-
-        # TODO: How to handle redundancy? Does Infocalypse automatically try
-        # an R0 if an R1 fails?
-
-        repositories = wot.read_repo_listing(ui_, truster, wot_id)
-        if repo_name not in repositories:
-            ui_.warn("Could not find repository named \"{0}\".\n".format(repo_name))
-            return
-
-        request_uri = repositories[repo_name]
-    else:
-        request_uri = opts['uri']
-
-    if request_uri == '':
-        request_uri = stored_cfg.get_request_uri(repo.root)
-        if not request_uri:
-            ui_.warn("There is no stored request URI for this repo.\n"
-                     "Please set one with the --uri option.\n")
-            return
-
-    params['REQUEST_URI'] = request_uri
-    # Hmmmm... can't really implement rev.
-    execute_pull(ui_, repo, params, stored_cfg)
-
-def infocalypse_push(ui_, repo, **opts):
-    """ Push to an Infocalypse repository in Freenet. """
-    params, stored_cfg = get_config_info(ui_, opts)
-    insert_uri = opts['uri']
-    if insert_uri == '':
-        insert_uri = stored_cfg.get_dir_insert_uri(repo.root)
-        if not insert_uri:
-            ui_.warn("There is no stored insert URI for this repo.\n"
-                    "Please set one with the --uri option.\n")
-            return
-
-    set_target_version(ui_, repo, opts, params,
-                       "Only pushing to version(s): %s\n")
-    params['INSERT_URI'] = insert_uri
-    #if opts['requesturi'] != '':
-    #    # DOESN'T search the insert uri index.
-    #    ui_.status(("Copying from:\n%s\nTo:\n%s\n\nThis is an "
-    #                + "advanced feature. "
-    #                + "I hope you know what you're doing.\n") %
-    #               (opts['requesturi'], insert_uri))
-    #    params['REQUEST_URI'] = opts['requesturi']
-
-    inserted_to = execute_push(ui_, repo, params, stored_cfg)
-    # TODO: Messy.
-    if inserted_to is not None and stored_cfg.has_wot_identity(stored_cfg
-    .get_request_uri(repo.root)):
-        import wot
-        wot.update_repo_listing(ui_, stored_cfg.get_wot_identity(stored_cfg
-    .get_request_uri(repo.root)))
-
-def infocalypse_info(ui_, repo, **opts):
-    """ Display information about an Infocalypse repository.
-     """
-    # FCP not required. Hmmm... Hack
-    opts['fcphost'] = ''
-    opts['fcpport'] = 0
-    params, stored_cfg = get_config_info(ui_, opts)
-    request_uri = opts['uri']
-    if request_uri == '':
-        request_uri = stored_cfg.get_request_uri(repo.root)
-        if not request_uri:
-            ui_.warn("There is no stored request URI for this repo.\n"
-                     "Please set one with the --uri option.\n")
-            return
-
-    params['REQUEST_URI'] = request_uri
-    execute_info(ui_, repo, params, stored_cfg)
-
-def parse_trust_args(params, opts):
-    """ INTERNAL: Helper function to parse  --hash and --fmsid. """
-    if opts.get('hash', []) == []:
-        raise util.Abort("Use --hash to set the USK hash.")
-    if len(opts['hash']) != 1:
-        raise util.Abort("Only one --hash value is allowed.")
-    if not is_hex_string(opts['hash'][0]):
-        raise util.Abort("[%s] doesn't look like a USK hash." %
-                         opts['hash'][0])
-
-    if opts.get('fmsid', []) == []:
-        raise util.Abort("Use --fmsid to set the FMS id.")
-    if len(opts['fmsid']) != 1:
-        raise util.Abort("Only one --fmsid value is allowed.")
-    if not is_fms_id(opts['fmsid'][0]):
-        raise util.Abort("[%s] doesn't look like an FMS id."
-                         % opts['fmsid'][0])
-
-    params['FMSREAD_HASH'] = opts['hash'][0]
-    params['FMSREAD_FMSID'] = opts['fmsid'][0]
-
-def parse_fmsread_subcmd(params, opts):
-    """ INTERNAL: Parse subcommand for fmsread."""
-    if opts['listall']:
-        params['FMSREAD'] = 'listall'
-    elif opts['list']:
-        params['FMSREAD'] = 'list'
-    elif opts['showtrust']:
-        params['FMSREAD'] = 'showtrust'
-    elif opts['trust']:
-        params['FMSREAD'] = 'trust'
-        parse_trust_args(params, opts)
-    elif opts['untrust']:
-        params['FMSREAD'] = 'untrust'
-        parse_trust_args(params, opts)
-    else:
-        params['FMSREAD'] = 'update'
-
-def infocalypse_fmsread(ui_, repo, **opts):
-    """ Read repository update information from fms.
-    """
-    # FCP not required. Hmmm... Hack
-    opts['fcphost'] = ''
-    opts['fcpport'] = 0
-    params, stored_cfg = get_config_info(ui_, opts)
-    request_uri = opts['uri']
-    if request_uri == '':
-        request_uri = stored_cfg.get_request_uri(repo.root)
-        if not request_uri:
-            ui_.status("There is no stored request URI for this repo.\n")
-            request_uri = None
-    parse_fmsread_subcmd(params, opts)
-    params['DRYRUN'] = opts['dryrun']
-    params['REQUEST_URI'] = request_uri
-    execute_fmsread(ui_, params, stored_cfg)
-
-def infocalypse_fmsnotify(ui_, repo, **opts):
-    """ Post a msg with the current repository USK index to fms.
-    """
-    params, stored_cfg = get_config_info(ui_, opts)
-    insert_uri = stored_cfg.get_dir_insert_uri(repo.root)
-    if not insert_uri and not (opts['submitbundle'] or
-                               opts['submitwiki']):
-        ui_.warn("You can't notify because there's no stored "
-                 + "insert URI for this repo.\n"
-                 + "Run from the directory you inserted from.\n")
-        return
-
-    params['ANNOUNCE'] = opts['announce']
-    params['SUBMIT_BUNDLE'] = opts['submitbundle']
-    params['SUBMIT_WIKI'] = opts['submitwiki']
-    if params['SUBMIT_WIKI'] or params['SUBMIT_BUNDLE']:
-        request_uri = stored_cfg.get_request_uri(repo.root)
-        if not request_uri:
-            ui_.warn("There is no stored request URI for this repo.\n")
-            raise util.Abort("No request URI.")
-        params['REQUEST_URI'] = request_uri
-
-    params['DRYRUN'] = opts['dryrun']
-    params['INSERT_URI'] = insert_uri
-    execute_fmsnotify(ui_, repo, params, stored_cfg)
-
-MSG_BAD_INDEX = 'You must set --index to a value >= 0.'
-def infocalypse_putsite(ui_, repo, **opts):
-    """ Insert an update to a freesite.
-    """
-
-    if opts['createconfig']:
-        if opts['wiki']:
-            raise util.Abort("Use fn-wiki --createconfig.")
-        params = {'SITE_CREATE_CONFIG':True}
-        execute_putsite(ui_, repo, params)
-        return
-
-    params, stored_cfg = get_config_info(ui_, opts)
-    if opts['key'] != '': # order important
-        params['SITE_KEY'] = opts['key']
-        if not (params['SITE_KEY'].startswith('SSK') or
-                params['SITE_KEY'] == 'CHK@'):
-            raise util.Abort("--key must be a valid SSK "
-                             + "insert key or CHK@.")
-
-    params['ISWIKI'] = opts['wiki']
-    read_freesite_cfg(ui_, repo, params, stored_cfg)
-
-    try:
-        # --index not required for CHK@
-        if not params['SITE_KEY'].startswith('CHK'):
-            params['SITE_INDEX'] = int(opts['index'])
-            if params['SITE_INDEX'] < 0:
-                raise ValueError()
-        else:
-            params['SITE_INDEX'] = -1
-    except ValueError:
-        raise util.Abort(MSG_BAD_INDEX)
-    except TypeError:
-        raise util.Abort(MSG_BAD_INDEX)
-
-    params['DRYRUN'] = opts['dryrun']
-
-    if not params.get('SITE_KEY', None):
-        insert_uri = stored_cfg.get_dir_insert_uri(repo.root)
-        if not insert_uri:
-            ui_.warn("You don't have the insert URI for this repo.\n"
-                     + "Supply a private key with --key or fn-push "
-                     + "the repo.\n")
-            return # REDFLAG: hmmm... abort?
-        params['SITE_KEY'] = 'SSK' + insert_uri.split('/')[0][3:]
-
-    execute_putsite(ui_, repo, params)
-
-def infocalypse_wiki(ui_, repo, **opts):
-    """ View and edit the current repository as a wiki. """
-    if os.getcwd() != repo.root:
-        raise util.Abort("You must be in the repository root directory.")
-
-    subcmds = ('run', 'createconfig', 'apply')
-    required = sum([bool(opts[cmd]) for cmd in subcmds])
-    if required == 0:
-        raise util.Abort("You must specify either --run, " +
-                         "--createconfig, --apply")
-    if required > 1:
-        raise util.Abort("Use either --run, --createconfig, or --apply")
-
-    if opts['apply'] != '':
-        params, stored_cfg = get_config_info(ui_, opts)
-        params['REQUEST_URI'] = opts['apply']
-        execute_wiki_apply(ui_, repo, params, stored_cfg)
-        return
-
-    if opts['fcphost'] != '' or opts['fcpport'] != 0:
-        raise util.Abort("--fcphost, --fcpport only for --apply")
-
-    # hmmmm.... useless copy?
-    params = {'WIKI' : [cmd for cmd in subcmds if opts[cmd]][0],
-              'HTTP_PORT': opts['http_port'],
-              'HTTP_BIND': opts['http_bind']}
-    execute_wiki(ui_, repo, params)
-
-def infocalypse_genkey(ui_, **opts):
-    """ Print a new SSK key pair. """
-    params, dummy = get_config_info(ui_, opts)
-    execute_genkey(ui_, params)
-
-def infocalypse_setup(ui_, **opts):
-    """ Setup the extension for use for the first time. """
-
-    execute_setup(ui_,
-                  opts['fcphost'],
-                  opts['fcpport'],
-                  opts['tmpdir'])
-
-    if not opts['nofms']:
-        execute_setupfms(ui_, opts)
-    else:
-        ui_.status("Skipped FMS configuration because --nofms was set.\n")
-
-    if not opts['nowot']:
-        import wot
-        wot.execute_setup_wot(ui_, opts)
-    else:
-        ui_.status("Skipped WoT configuration because --nowot was set.\n")
-
-def infocalypse_setupfms(ui_, **opts):
-    """ Setup or modify the fms configuration. """
-    # REQUIRES config file.
-    execute_setupfms(ui_, opts)
-
-
-# TODO: Why ui with trailing underscore? Is there a global "ui" somewhere?
-def infocalypse_setupwot(ui_, **opts):
-    import wot
-    wot.execute_setup_wot(ui_, opts)
-
-
-#----------------------------------------------------------"
-def do_archive_create(ui_, opts, params, stored_cfg):
-    """ fn-archive --create."""
-    insert_uri = opts['uri']
-    if insert_uri == '':
-        raise util.Abort("Please set the insert URI with --uri.")
-
-    params['INSERT_URI'] = insert_uri
-    params['FROM_DIR'] = os.getcwd()
-    execute_arc_create(ui_, params, stored_cfg)
-
-def do_archive_push(ui_, opts, params, stored_cfg):
-    """ fn-archive --push."""
-    insert_uri = opts['uri']
-    if insert_uri == '':
-        insert_uri = (
-            stored_cfg.get_dir_insert_uri(params['ARCHIVE_CACHE_DIR']))
-        if not insert_uri:
-            ui_.warn("There is no stored insert URI for this archive.\n"
-                     "Please set one with the --uri option.\n")
-            raise util.Abort("No Insert URI.")
-
-    params['INSERT_URI'] = insert_uri
-    params['FROM_DIR'] = os.getcwd()
-
-    execute_arc_push(ui_, params, stored_cfg)
-
-def do_archive_pull(ui_, opts, params, stored_cfg):
-    """ fn-archive --pull."""
-    request_uri = opts['uri']
-
-    if request_uri == '':
-        request_uri = (
-            stored_cfg.get_request_uri(params['ARCHIVE_CACHE_DIR']))
-        if not request_uri:
-            ui_.warn("There is no stored request URI for this archive.\n"
-                     "Please set one with the --uri option.\n")
-            raise util.Abort("No request URI.")
-
-    params['REQUEST_URI'] = request_uri
-    params['TO_DIR'] = os.getcwd()
-    execute_arc_pull(ui_,  params, stored_cfg)
-
-ILLEGAL_FOR_REINSERT = ('uri', 'aggressive', 'nosearch')
-def do_archive_reinsert(ui_, opts, params, stored_cfg):
-    """ fn-archive --reinsert."""
-    illegal = [value for value in ILLEGAL_FOR_REINSERT
-               if value in opts and opts[value]]
-    if illegal:
-        raise util.Abort("--uri, --aggressive, --nosearch illegal " +
-                         "for reinsert.")
-    request_uri = stored_cfg.get_request_uri(params['ARCHIVE_CACHE_DIR'])
-    if request_uri is None:
-        ui_.warn("There is no stored request URI for this archive.\n" +
-                 "Run fn-archive --pull first!.\n")
-        raise util.Abort(" No request URI, can't re-insert")
-
-    insert_uri = stored_cfg.get_dir_insert_uri(params['ARCHIVE_CACHE_DIR'])
-    params['REQUEST_URI'] = request_uri
-    params['INSERT_URI'] = insert_uri
-    params['FROM_DIR'] = os.getcwd() # hmmm not used.
-    params['REINSERT_LEVEL'] = 3
-    execute_arc_reinsert(ui_, params, stored_cfg)
-
-ARCHIVE_SUBCMDS = {'create':do_archive_create,
-                   'push':do_archive_push,
-                   'pull':do_archive_pull,
-                   'reinsert':do_archive_reinsert}
-ARCHIVE_CACHE_DIR = '.ARCHIVE_CACHE'
-def infocalypse_archive(ui_, **opts):
-    """ Commands to maintain a non-hg incremental archive."""
-    subcmd = [value for value in ARCHIVE_SUBCMDS if opts[value]]
-    if len(subcmd) > 1:
-        raise util.Abort("--create, --pull, --push are mutally exclusive. " +
-                         "Only specify one.")
-    if len(subcmd) > 0:
-        subcmd = subcmd[0]
-    else:
-        subcmd = "pull"
-
-    params, stored_cfg = get_config_info(ui_, opts)
-    params['ARCHIVE_CACHE_DIR'] = os.path.join(os.getcwd(), ARCHIVE_CACHE_DIR)
-
-    if not subcmd in ARCHIVE_SUBCMDS:
-        raise util.Abort("Unhandled subcommand: " + subcmd)
-
-    # 2 qt?
-    ARCHIVE_SUBCMDS[subcmd](ui_, opts, params, stored_cfg)
+_freenetschemes = ('freenet', )
+for _scheme in _freenetschemes:
+    hg.schemes[_scheme] = freenetrepo
 
 #----------------------------------------------------------"
 
@@ -1019,6 +479,7 @@ cmdtable = {
     "fn-setup": (infocalypse_setup,
                  [('', 'tmpdir', '~/infocalypse_tmp', 'temp directory'),
                   ('', 'nofms', None, 'skip FMS configuration'),
+                  ('', 'nowot', None, 'skip WoT configuration'),
                   ('', 'fmsid', '', "fmsid (only part before '@'!)"),
                   ('', 'timeout', 30, "fms socket timeout in seconds")]
                  + WOT_OPTS
diff --git a/infocalypse/infcmds.py b/infocalypse/infcmds.py
--- a/infocalypse/infcmds.py
+++ b/infocalypse/infcmds.py
@@ -495,12 +495,8 @@ def is_redundant(uri):
 ############################################################
 # User feedback? success, failure?
 def execute_create(ui_, repo, params, stored_cfg):
-    """
-    Run the create command.
-    Return the URIs the repo was inserted to, or None in the case of an error.
-    """
+    """ Run the create command. """
     update_sm = None
-    inserted_to = None
     try:
         update_sm = setup(ui_, repo, params, stored_cfg)
         # REDFLAG: Do better.
@@ -520,9 +516,9 @@ def execute_create(ui_, repo, params, st
         run_until_quiescent(update_sm, params['POLL_SECS'])
 
         if update_sm.get_state(QUIESCENT).arrived_from(((FINISHING,))):
-            inserted_to = update_sm.get_state(INSERTING_URI).get_request_uris()
             ui_.status("Inserted to:\n%s\n" %
-                       '\n'.join(inserted_to))
+                       '\n'.join(update_sm.get_state(INSERTING_URI).
+                                 get_request_uris()))
         else:
             ui_.status("Create failed.\n")
 
@@ -530,8 +526,6 @@ def execute_create(ui_, repo, params, st
     finally:
         cleanup(update_sm)
 
-    return inserted_to
-
 # REDFLAG: LATER: make this work without a repo?
 def execute_copy(ui_, repo, params, stored_cfg):
     """ Run the copy command. """
@@ -612,14 +606,10 @@ def execute_reinsert(ui_, repo, params, 
         cleanup(update_sm)
 
 def execute_push(ui_, repo, params, stored_cfg):
-    """
-    Run the push command.
-    Return the URIs the repo was inserted to if it changed, or None otherwise.
-    """
+    """ Run the push command. """
 
     assert params.get('REQUEST_URI', None) is None
     update_sm = None
-    inserted_to = None
     try:
         update_sm = setup(ui_, repo, params, stored_cfg)
         request_uri, is_keypair = do_key_setup(ui_, update_sm, params,
@@ -636,9 +626,9 @@ def execute_push(ui_, repo, params, stor
         run_until_quiescent(update_sm, params['POLL_SECS'])
 
         if update_sm.get_state(QUIESCENT).arrived_from(((FINISHING,))):
-            inserted_to = update_sm.get_state(INSERTING_URI).get_request_uris()
             ui_.status("Inserted to:\n%s\n" %
-                       '\n'.join(inserted_to))
+                       '\n'.join(update_sm.get_state(INSERTING_URI).
+                                 get_request_uris()))
         else:
             extra = ''
             if update_sm.ctx.get('UP_TO_DATE', False):
@@ -649,8 +639,6 @@ def execute_push(ui_, repo, params, stor
     finally:
         cleanup(update_sm)
 
-    return inserted_to
-
 def execute_pull(ui_, repo, params, stored_cfg):
     """ Run the pull command. """
     update_sm = None
diff --git a/infocalypse/wot.py b/infocalypse/wot.py
--- a/infocalypse/wot.py
+++ b/infocalypse/wot.py
@@ -1,3 +1,4 @@
+import string
 import fcp
 from config import Config
 import xml.etree.ElementTree as ET
@@ -320,9 +321,14 @@ def to_freemail_address(identity):
     # addresses are not case sensitive, so some clients may mangle case.
     # See https://github.com/zidel/Freemail/blob/v0.2.2.1/docs/spec/spec.tex#L32
 
-    for item in identity.iteritem():
+    for item in identity.iteritems():
         if item[1] == 'Freemail' and item[0].startswith('Context'):
-            return identity['Nickname'] + '@' + b32encode(base64decode(
-                identity['Identity'])) + 'freemail'
+            re_encode = b32encode(base64decode(identity['Identity']))
+            # Remove trailing '=' padding.
+            re_encode = re_encode.rstrip('=')
+
+            # Freemail addresses are lower case.
+            return string.lower(identity['Nickname'] + '@' + re_encode +
+                                '.freemail')
 
     return None