infocalypse
 
(Steve Dougherty)
2013-06-21: Add per-repo Freemail password configuration.

Add per-repo Freemail password configuration.

diff --git a/infocalypse/__init__.py b/infocalypse/__init__.py
--- a/infocalypse/__init__.py
+++ b/infocalypse/__init__.py
@@ -499,10 +499,9 @@ cmdtable = {
                     "[options]"),
 
     "fn-setupfreemail": (infocalypse_setupfreemail,
-                         [('', 'password', '', 'Freemail password')]
-                         + WOT_OPTS
+                         WOT_OPTS
                          + FCP_OPTS,
-                         "[--truster nick@key] --password <password>"),
+                         "[--truster nick@key]"),
 
     "fn-archive": (infocalypse_archive,
                   [('', 'uri', '', 'Request URI for --pull, Insert URI ' +
@@ -527,7 +526,6 @@ commands.norepo += ' fn-setupfms'
 commands.norepo += ' fn-genkey'
 commands.norepo += ' fn-archive'
 commands.norepo += ' fn-setupwot'
-commands.norepo += ' fn-setupfreemail'
 
 
 ## Wrap core commands for use with freenet keys.
diff --git a/infocalypse/commands.py b/infocalypse/commands.py
--- a/infocalypse/commands.py
+++ b/infocalypse/commands.py
@@ -465,20 +465,24 @@ def infocalypse_setupwot(ui_, **opts):
     wot.execute_setup_wot(ui_, opts)
 
 
-# TODO: Should Freemail setup also be part of fn-setup?
-# TODO: Should there be per-Identity config? Then each one would have a list
-# of repos and optionally a Freemail password.
-# Nah, FMS config is global.
-def infocalypse_setupfreemail(ui, **opts):
-    if 'truster' in opts:
-        identity = opts['truster']
+def infocalypse_setupfreemail(ui, repo, **opts):
+    """
+    Set a Freemail password. If --truster is not given uses the default
+    truster.
+    """
+    import wot
+    # TODO: Here --truster doesn't make sense. There is no trust involved.
+    # TODO: Should this be part of the normal fn-setup?
+    wot.execute_setup_freemail(ui, get_truster(ui, repo, opts))
+
+
+def get_truster(ui, repo, opts):
+    if opts['truster']:
+        return opts['truster']
     else:
         cfg = Config().from_ui(ui)
-        identity = cfg.defaults['TRUSTER']
-    import wot
-    # TODO: Should this be part of the normal fn-setup?
-    wot.execute_setup_freemail(ui, identity)
-
+        # TODO: What about if there's no request URI set?
+        return '@' + cfg.get_wot_identity(cfg.get_request_uri(repo.root))
 
 #----------------------------------------------------------"
 def do_archive_create(ui_, opts, params, stored_cfg):
diff --git a/infocalypse/config.py b/infocalypse/config.py
--- a/infocalypse/config.py
+++ b/infocalypse/config.py
@@ -127,6 +127,8 @@ class Config:
         self.insert_usks = {}
         # repo id -> publisher WoT identity
         self.wot_identities = {}
+        # WoT public key hash -> Freemail password
+        self.freemail_passwords = {}
         # fms_id -> (usk_hash, ...) map
         self.fmsread_trust_map = DEFAULT_TRUST.copy()
         self.fmsread_groups = DEFAULT_GROUPS
@@ -219,6 +221,22 @@ class Config:
         """
         return normalize(for_usk_or_id) in self.wot_identities
 
+    def set_freemail_password(self, wot_identity, password):
+        """
+        Set the password for the given WoT identity.
+        """
+        self.freemail_passwords[wot_identity] = password
+
+    def get_freemail_password(self, wot_identity):
+        """
+        Return the password associated with the given WoT identity,
+        or None if one is not set.
+        """
+        if wot_identity in self.freemail_passwords:
+            return self.freemail_passwords[wot_identity]
+        else:
+            return None
+
     # Hmmm... really nescessary?
     def get_dir_insert_uri(self, repo_dir):
         """ Return the insert USK for repo_dir or None. """
@@ -328,6 +346,11 @@ class Config:
                 cfg.wot_identities[repo_id] = parser.get('wot_identities',
                                                          repo_id)
 
+        if parser.has_section('freemail_passwords'):
+            for wot_id in parser.options('freemail_passwords'):
+                cfg.freemail_passwords[wot_id] = parser.get(
+                    'freemail_passwords', wot_id)
+
         # ignored = fms_id|usk_hash|usk_hash|...
         if parser.has_section('fmsread_trust_map'):
             cfg.fmsread_trust_map.clear() # Wipe defaults.
@@ -408,6 +431,10 @@ class Config:
         parser.add_section('wot_identities')
         for repo_id in cfg.wot_identities:
             parser.set('wot_identities', repo_id, cfg.wot_identities[repo_id])
+        parser.add_section('freemail_passwords')
+        for wot_id in cfg.freemail_passwords:
+            parser.set('freemail_passwords', wot_id, cfg.freemail_passwords[
+                wot_id])
         parser.add_section('fmsread_trust_map')
         for index, fms_id in enumerate(cfg.fmsread_trust_map):
             entry = cfg.fmsread_trust_map[fms_id]
diff --git a/infocalypse/wot.py b/infocalypse/wot.py
--- a/infocalypse/wot.py
+++ b/infocalypse/wot.py
@@ -117,10 +117,49 @@ def execute_setup_wot(ui_, opts):
     Config.to_file(cfg)
 
 
-def execute_setup_freemail(ui, identity, password):
+def execute_setup_freemail(ui, wot_identifier):
+    """
+    Prompt for, test, and set a Freemail password for the identity.
+    """
+    local_id = resolve_local_identity(ui, wot_identifier)
 
-    # TODO: get truster from config; check password.
-    pass
+    if local_id is None:
+        return
+
+    address = to_freemail_address(local_id)
+
+    if address is None:
+        ui.warn("{0}@{1} does not have a Freemail address.\n".format(
+            local_id['Nickname'], local_id['Identity']))
+        return
+
+    password = ui.getpass()
+    if password is None:
+        ui.warn("Cannot prompt for a password in a non-interactive context.")
+        return
+
+    ui.status("Checking password for {0}@{1}.\n".format(local_id['Nickname'],
+                                                        local_id['Identity']))
+
+    cfg = config.Config()
+    cfg.from_ui(ui)
+
+    # Check that the password works.
+    try:
+        # TODO: Is this the correct way to get the configured host?
+        smtp = smtplib.SMTP(cfg.defaults['HOST'], FREEMAIL_SMTP_PORT)
+        smtp.login(address, password)
+    except smtplib.SMTPAuthenticationError, e:
+        ui.warn("Could not log in using password '{0}'.\n".format(password))
+        ui.warn("Got '{0}'\n".format(e.smtp_error))
+        return
+    except smtplib.SMTPConnectError, e:
+        ui.warn("Could not connect to server.\n")
+        ui.warn("Got '{0}'\n".format(e.smtp_error))
+        return
+
+    cfg.set_freemail_password(wot_identifier, password)
+    ui.status("Password set.\n")
 
 
 def resolve_local_identity(ui, identity):