infocalypse
 
(Steve Dougherty)
2013-06-24: Update identity search to reflect LCWoT changes.

Update identity search to reflect LCWoT changes. It is no longer an error for more than MaxIdentites to match. There is a field containing the number of matched identities. It also became clear that nicknames require a wildcard to match as with startswith(), whereas the ID uses startswith() already.

diff --git a/infocalypse/wot.py b/infocalypse/wot.py
--- a/infocalypse/wot.py
+++ b/infocalypse/wot.py
@@ -254,12 +254,18 @@ def resolve_identity(ui, truster, identi
     # TODO: LCWoT allows limiting by context, but how to make sure otherwise?
     # TODO: Should this manually ensure an identity has a vcs context
     # otherwise?
+
+    # LCWoT can have * to allow a wildcard match, but a wildcard alone is not
+    # allowed. See Lucine Term Modifiers documentation. The nickname uses
+    # this syntax but the ID is inherently startswith().
     params = {'Message': 'GetIdentitiesByPartialNickname',
               'Truster': truster,
-              'PartialNickname': nickname_prefix,
+              'PartialNickname':
+              nickname_prefix + '*' if nickname_prefix else '',
               'PartialID': key_prefix,
-              'MaxIdentities': 1,  # Match must be unambiguous.
+              'MaxIdentities': 2,
               'Context': 'vcs'}
+
     response = \
         node.fcpPluginMessage(async=False,
                               plugin_name="plugins.WebOfTrust.WebOfTrust",
@@ -270,25 +276,21 @@ def resolve_identity(ui, truster, identi
         ui.warn('Unexpected reply. Got {0}\n'.format(response))
         return
     elif response['Replies.Message'] == 'Identities':
-        # TODO: What if no identities matched?
-        return read_identity(response, 0)
-    elif response['Replies.Message'] == 'Error':
-        # The difficulty here is that the message type is Error for both an
-        # unrecognized message type and ambiguous search terms.
-        # TODO: This seems likely to break - the Description seems intended
-        # for human readers and will probably change.
-        if response['Replies.Description'].startswith('Number of matched'):
-            # Supported version of LCWoT - terms ambiguous.
-            ui.warn("'{0}@{1}' is ambiguous.".format(nickname_prefix,
-                                                     key_prefix))
+        matches = response['Replies.IdentitiesMatched']
+        if matches == 0:
+            ui.warn("No identities match '{0}'\n".format(identity))
             return
-        elif response['Replies.Description'].startswith('Unknown message') or \
-                response['Replies.Description'].startswith('Could not match'):
-            # Not supported; check for exact identity.
-            ui.warn('Searching by partial nickname/key not supported.')
+        elif matches == 1:
+            return read_identity(response, 0)
+        else:
+            ui.warn("'{0}' is ambiguous.\n".format(identity))
+            return
 
-    # Attempt to search failed - check for exact key. Here key_prefix must be
-    # a complete key for the lookup to succeed.
+    # Partial matching not supported, or unknown truster. The only difference
+    # in the errors is human-readable, so just try the exact match.
+    assert response['Replies.Message'] == 'Error'
+
+    # key_prefix must be a complete key for the lookup to succeed.
     params = {'Message': 'GetIdentity',
               'Truster': truster,
               'Identity': key_prefix}
@@ -297,6 +299,11 @@ def resolve_identity(ui, truster, identi
                               plugin_name="plugins.WebOfTrust.WebOfTrust",
                               plugin_params=params)[0]
 
+    if response['Replies.Message'] == 'Error':
+        # Searching by exact public key hash, not matching.
+        ui.warn("No such identity '{0}'.\n".format(identity))
+        return
+
     # There should be only one result.
     # Depends on https://bugs.freenetproject.org/view.php?id=5729
     return read_identity(response, 0)