Repository: profanity-im/profanity (c)

Issue:
OMEMO: Autocomplete suggests fingerprints not belonging to the selected contact
The OMEMO autocomplete feature suggests fingerprints not belonging to the selected contact.

Steps to reproduce:
1. Enable omemo (set policy to automatic / always - not tested if this is needed to reproduce...)
2. Show the fingerprint list of one of your contacts
3. Write `/omemo trust <contact>` and use tab for autocompletion
-> Many fingerprints are suggested, not only the ones belonging to the contact


Discussion:
Yes so far it's all the fingerprints we get.
AFAICT we don't have access to the first argument of a command from the autocompletion command.
So I can't filter out fingerprints easily.
@pasis, @boothj5  can you confirm?
If we don't solve this (ever or for 0.7.0) then we should document the usage at https://profanity-im.github.io/omemo.html

Maybe also mentioning that people should enable carbons (or auto enabling them for 0.7.0 since I think that most people want them and only some prefer to disable them). And describing that they need to trust their own keys of other devices.

Mentioning that file transfer is not encrypted since its another XEP too.

So that they know how to use OMEMO properly with Profanity and what works and what doesn'.
I documented this on the website now. We will release 0.7.0 as it is and hope users read the documentation.

Planning to tackle this for 0.8.0.
> AFAICT we don't have access to the first argument of a command from the autocompletion command.
So I can't filter out fingerprints easily.

@paulfariello  We could create a new function. Autocomplete still has it in the `input` argument.
We should merge all omemo autocomplete functions into a single one in order to filter the fingerprints.

Patch:
diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c
--- a/src/command/cmd_ac.c
+++ b/src/command/cmd_ac.c
@@ -114,7 +114,7 @@ static char* _logging_autocomplete(ProfWin *window, const char *const input, gbo
 static char* _color_autocomplete(ProfWin *window, const char *const input, gboolean previous);
 static char* _avatar_autocomplete(ProfWin *window, const char *const input, gboolean previous);
 
-static char* _script_autocomplete_func(const char *const prefix, gboolean previous);
+static char* _script_autocomplete_func(const char *const prefix, gboolean previous, void *context);
 
 static char* _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previous);
 
@@ -1512,7 +1512,7 @@ _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previ
         "/history", "/vercheck", "/privileges", "/wrap", "/carbons", "/lastactivity", "/os"};
 
     for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
-        result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice, previous);
+        result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice, previous, NULL);
         if (result) {
             return result;
         }
@@ -1544,7 +1544,7 @@ _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previ
         // Remove quote character before and after names when doing autocomplete
         char *unquoted = strip_arg_quotes(input);
         for (i = 0; i < ARRAY_SIZE(contact_choices); i++) {
-            result = autocomplete_param_with_func(unquoted, contact_choices[i], roster_contact_autocomplete, previous);
+            result = autocomplete_param_with_func(unquoted, contact_choices[i], roster_contact_autocomplete, previous, NULL);
             if (result) {
                 free(unquoted);
                 return result;
@@ -1554,7 +1554,7 @@ _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previ
 
         gchar *resource_choices[] = { "/caps", "/software", "/ping" };
         for (i = 0; i < ARRAY_SIZE(resource_choices); i++) {
-            result = autocomplete_param_with_func(input, resource_choices[i], roster_fulljid_autocomplete, previous);
+            result = autocomplete_param_with_func(input, resource_choices[i], roster_fulljid_autocomplete, previous, NULL);
             if (result) {
                 return result;
             }
@@ -1563,7 +1563,7 @@ _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previ
 
     gchar *invite_choices[] = { "/join" };
     for (i = 0; i < ARRAY_SIZE(invite_choices); i++) {
-        result = autocomplete_param_with_func(input, invite_choices[i], muc_invites_find, previous);
+        result = autocomplete_param_with_func(input, invite_choices[i], muc_invites_find, previous, NULL);
         if (result) {
             return result;
         }
@@ -1672,11 +1672,11 @@ static char*
 _sub_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 {
     char *result = NULL;
-    result = autocomplete_param_with_func(input, "/sub allow", presence_sub_request_find, previous);
+    result = autocomplete_param_with_func(input, "/sub allow", presence_sub_request_find, previous, NULL);
     if (result) {
         return result;
     }
-    result = autocomplete_param_with_func(input, "/sub deny", presence_sub_request_find, previous);
+    result = autocomplete_param_with_func(input, "/sub deny", presence_sub_request_find, previous, NULL);
     if (result) {
         return result;
     }
@@ -1692,7 +1692,7 @@ static char*
 _tray_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 {
     char *result = NULL;
-    result = autocomplete_param_with_func(input, "/tray read", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/tray read", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
@@ -1724,7 +1724,7 @@ _who_autocomplete(ProfWin *window, const char *const input, gboolean previous)
                 "/who unavailable" };
 
             for (i = 0; i < ARRAY_SIZE(group_commands); i++) {
-                result = autocomplete_param_with_func(input, group_commands[i], roster_group_autocomplete, previous);
+                result = autocomplete_param_with_func(input, group_commands[i], roster_group_autocomplete, previous, NULL);
                 if (result) {
                     return result;
                 }
@@ -1772,7 +1772,7 @@ _roster_autocomplete(ProfWin *window, const char *const input, gboolean previous
     if (result) {
         return result;
     }
-    result = autocomplete_param_with_func(input, "/roster resource join", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/roster resource join", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
@@ -1804,47 +1804,47 @@ _roster_autocomplete(ProfWin *window, const char *const input, gboolean previous
     if (result) {
         return result;
     }
-    result = autocomplete_param_with_func(input, "/roster count zero", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/roster count zero", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
-    result = autocomplete_param_with_func(input, "/roster color", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/roster color", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
 
     jabber_conn_status_t conn_status = connection_get_status();
     if (conn_status == JABBER_CONNECTED) {
-        result = autocomplete_param_with_func(input, "/roster nick", roster_barejid_autocomplete, previous);
+        result = autocomplete_param_with_func(input, "/roster nick", roster_barejid_autocomplete, previous, NULL);
         if (result) {
             return result;
         }
-        result = autocomplete_param_with_func(input, "/roster clearnick", roster_barejid_autocomplete, previous);
+        result = autocomplete_param_with_func(input, "/roster clearnick", roster_barejid_autocomplete, previous, NULL);
         if (result) {
             return result;
         }
-        result = autocomplete_param_with_func(input, "/roster remove", roster_barejid_autocomplete, previous);
+        result = autocomplete_param_with_func(input, "/roster remove", roster_barejid_autocomplete, previous, NULL);
         if (result) {
             return result;
         }
 
-        result = autocomplete_param_with_func(input, "/roster group show", roster_group_autocomplete, previous);
+        result = autocomplete_param_with_func(input, "/roster group show", roster_group_autocomplete, previous, NULL);
         if (result) {
             return result;
         }
-        result = autocomplete_param_no_with_func(input, "/roster group add", 5, roster_contact_autocomplete, previous);
+        result = autocomplete_param_no_with_func(input, "/roster group add", 5, roster_contact_autocomplete, previous, NULL);
         if (result) {
             return result;
         }
-        result = autocomplete_param_no_with_func(input, "/roster group remove", 5, roster_contact_autocomplete, previous);
+        result = autocomplete_param_no_with_func(input, "/roster group remove", 5, roster_contact_autocomplete, previous, NULL);
         if (result) {
             return result;
         }
-        result = autocomplete_param_with_func(input, "/roster group add", roster_group_autocomplete, previous);
+        result = autocomplete_param_with_func(input, "/roster group add", roster_group_autocomplete, previous, NULL);
         if (result) {
             return result;
         }
-        result = autocomplete_param_with_func(input, "/roster group remove", roster_group_autocomplete, previous);
+        result = autocomplete_param_with_func(input, "/roster group remove", roster_group_autocomplete, previous, NULL);
         if (result) {
             return result;
         }
@@ -1882,7 +1882,7 @@ _roster_autocomplete(ProfWin *window, const char *const input, gboolean previous
     if (result) {
         return result;
     }
-    result = autocomplete_param_with_func(input, "/roster wrap", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/roster wrap", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
@@ -1923,7 +1923,7 @@ _blocked_autocomplete(ProfWin *window, const char *const input, gboolean previou
 {
     char *result = NULL;
 
-    result = autocomplete_param_with_func(input, "/blocked remove", blocked_ac_find, previous);
+    result = autocomplete_param_with_func(input, "/blocked remove", blocked_ac_find, previous, NULL);
     if (result) {
         return result;
     }
@@ -1961,7 +1961,7 @@ _bookmark_autocomplete(ProfWin *window, const char *const input, gboolean previo
                 || (num_args == 4 && (g_strcmp0(args[2], "autojoin") == 0) && !space_at_end))  {
             GString *beginning = g_string_new("/bookmark");
             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
-            found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous);
+            found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
                 g_strfreev(args);
@@ -1982,7 +1982,7 @@ _bookmark_autocomplete(ProfWin *window, const char *const input, gboolean previo
                 || (num_args == 6 && (g_strcmp0(args[4], "autojoin") == 0) && !space_at_end))  {
             GString *beginning = g_string_new("/bookmark");
             g_string_append_printf(beginning, " %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4]);
-            found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous);
+            found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
                 g_strfreev(args);
@@ -2003,7 +2003,7 @@ _bookmark_autocomplete(ProfWin *window, const char *const input, gboolean previo
                 || (num_args == 8 && (g_strcmp0(args[6], "autojoin") == 0) && !space_at_end))  {
             GString *beginning = g_string_new("/bookmark");
             g_string_append_printf(beginning, " %s %s %s %s %s %s %s", args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
-            found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous);
+            found = autocomplete_param_with_func(input, beginning->str, prefs_autocomplete_boolean_choice, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
                 g_strfreev(args);
@@ -2014,19 +2014,19 @@ _bookmark_autocomplete(ProfWin *window, const char *const input, gboolean previo
 
     g_strfreev(args);
 
-    found = autocomplete_param_with_func(input, "/bookmark remove", bookmark_find, previous);
+    found = autocomplete_param_with_func(input, "/bookmark remove", bookmark_find, previous, NULL);
     if (found) {
         return found;
     }
-    found = autocomplete_param_with_func(input, "/bookmark join", bookmark_find, previous);
+    found = autocomplete_param_with_func(input, "/bookmark join", bookmark_find, previous, NULL);
     if (found) {
         return found;
     }
-    found = autocomplete_param_with_func(input, "/bookmark update", bookmark_find, previous);
+    found = autocomplete_param_with_func(input, "/bookmark update", bookmark_find, previous, NULL);
     if (found) {
         return found;
     }
-    found = autocomplete_param_with_func(input, "/bookmark invites", prefs_autocomplete_boolean_choice, previous);
+    found = autocomplete_param_with_func(input, "/bookmark invites", prefs_autocomplete_boolean_choice, previous, NULL);
     if (found) {
         return found;
     }
@@ -2041,7 +2041,7 @@ _notify_autocomplete(ProfWin *window, const char *const input, gboolean previous
     int i = 0;
     char *result = NULL;
 
-    result = autocomplete_param_with_func(input, "/notify room trigger remove", prefs_autocomplete_room_trigger, previous);
+    result = autocomplete_param_with_func(input, "/notify room trigger remove", prefs_autocomplete_room_trigger, previous, NULL);
     if (result) {
         return result;
     }
@@ -2049,7 +2049,7 @@ _notify_autocomplete(ProfWin *window, const char *const input, gboolean previous
     gchar *boolean_choices1[] = { "/notify room current", "/notify chat current", "/notify typing current",
         "/notify room text", "/notify chat text" };
     for (i = 0; i < ARRAY_SIZE(boolean_choices1); i++) {
-        result = autocomplete_param_with_func(input, boolean_choices1[i], prefs_autocomplete_boolean_choice, previous);
+        result = autocomplete_param_with_func(input, boolean_choices1[i], prefs_autocomplete_boolean_choice, previous, NULL);
         if (result) {
             return result;
         }
@@ -2082,7 +2082,7 @@ _notify_autocomplete(ProfWin *window, const char *const input, gboolean previous
 
     gchar *boolean_choices2[] = { "/notify invite", "/notify sub", "/notify mention", "/notify trigger"};
     for (i = 0; i < ARRAY_SIZE(boolean_choices2); i++) {
-        result = autocomplete_param_with_func(input, boolean_choices2[i], prefs_autocomplete_boolean_choice, previous);
+        result = autocomplete_param_with_func(input, boolean_choices2[i], prefs_autocomplete_boolean_choice, previous, NULL);
         if (result) {
             return result;
         }
@@ -2116,7 +2116,7 @@ _autoaway_autocomplete(ProfWin *window, const char *const input, gboolean previo
         return result;
     }
 
-    result = autocomplete_param_with_func(input, "/autoaway check", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/autoaway check", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
@@ -2133,11 +2133,11 @@ _log_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 {
     char *result = NULL;
 
-    result = autocomplete_param_with_func(input, "/log rotate", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/log rotate", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
-    result = autocomplete_param_with_func(input, "/log shared", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/log shared", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
@@ -2154,7 +2154,7 @@ _autoconnect_autocomplete(ProfWin *window, const char *const input, gboolean pre
 {
     char *result = NULL;
 
-    result = autocomplete_param_with_func(input, "/autoconnect set", accounts_find_enabled, previous);
+    result = autocomplete_param_with_func(input, "/autoconnect set", accounts_find_enabled, previous, NULL);
     if (result) {
         return result;
     }
@@ -2175,7 +2175,7 @@ _otr_autocomplete(ProfWin *window, const char *const input, gboolean previous)
     jabber_conn_status_t conn_status = connection_get_status();
 
     if (conn_status == JABBER_CONNECTED) {
-        found = autocomplete_param_with_func(input, "/otr start", roster_contact_autocomplete, previous);
+        found = autocomplete_param_with_func(input, "/otr start", roster_contact_autocomplete, previous, NULL);
         if (found) {
             return found;
         }
@@ -2198,7 +2198,7 @@ _otr_autocomplete(ProfWin *window, const char *const input, gboolean previous)
                 g_string_append(beginning, args[1]);
             }
 
-            found = autocomplete_param_with_func(input, beginning->str, roster_contact_autocomplete, previous);
+            found = autocomplete_param_with_func(input, beginning->str, roster_contact_autocomplete, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
                 g_strfreev(args);
@@ -2229,7 +2229,7 @@ _pgp_autocomplete(ProfWin *window, const char *const input, gboolean previous)
     jabber_conn_status_t conn_status = connection_get_status();
 
     if (conn_status == JABBER_CONNECTED) {
-        found = autocomplete_param_with_func(input, "/pgp start", roster_contact_autocomplete, previous);
+        found = autocomplete_param_with_func(input, "/pgp start", roster_contact_autocomplete, previous, NULL);
         if (found) {
             return found;
         }
@@ -2250,7 +2250,7 @@ _pgp_autocomplete(ProfWin *window, const char *const input, gboolean previous)
             g_string_append(beginning, " ");
             g_string_append(beginning, args[1]);
         }
-        found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous);
+        found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous, NULL);
         g_string_free(beginning, TRUE);
         if (found) {
             g_strfreev(args);
@@ -2261,7 +2261,7 @@ _pgp_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 #endif
 
     if (conn_status == JABBER_CONNECTED) {
-        found = autocomplete_param_with_func(input, "/pgp setkey", roster_barejid_autocomplete, previous);
+        found = autocomplete_param_with_func(input, "/pgp setkey", roster_barejid_autocomplete, previous, NULL);
         if (found) {
             return found;
         }
@@ -2293,12 +2293,12 @@ _omemo_autocomplete(ProfWin *window, const char *const input, gboolean previous)
     jabber_conn_status_t conn_status = connection_get_status();
 
     if (conn_status == JABBER_CONNECTED) {
-        found = autocomplete_param_with_func(input, "/omemo start", roster_contact_autocomplete, previous);
+        found = autocomplete_param_with_func(input, "/omemo start", roster_contact_autocomplete, previous, NULL);
         if (found) {
             return found;
         }
 
-        found = autocomplete_param_with_func(input, "/omemo fingerprint", roster_contact_autocomplete, previous);
+        found = autocomplete_param_with_func(input, "/omemo fingerprint", roster_contact_autocomplete, previous, NULL);
         if (found) {
             return found;
         }
@@ -2306,20 +2306,32 @@ _omemo_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 
 #ifdef HAVE_OMEMO
         if (window->type == WIN_CHAT) {
-            found = autocomplete_param_with_func(input, "/omemo trust", omemo_fingerprint_autocomplete, previous);
+            ProfChatWin *chatwin = (ProfChatWin*)window;
+            assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
+            found = autocomplete_param_with_func(input, "/omemo trust", omemo_fingerprint_autocomplete, previous, chatwin->barejid);
             if (found) {
                 return found;
             }
         } else {
-            found = autocomplete_param_with_func(input, "/omemo trust", roster_contact_autocomplete, previous);
+            found = autocomplete_param_with_func(input, "/omemo trust", roster_contact_autocomplete, previous, NULL);
             if (found) {
                 return found;
             }
 
-            found = autocomplete_param_no_with_func(input, "/omemo trust", 4, omemo_fingerprint_autocomplete, previous);
-            if (found) {
-                return found;
+            int num_tokens = count_tokens(input);
+            if (num_tokens == 4) {
+                gboolean result;
+                gchar **args = parse_args(input, 2, 3, &result);
+                if (result) {
+                    gchar *jid = g_strdup(args[1]);
+                    found = autocomplete_param_no_with_func(input, "/omemo trust", 4, omemo_fingerprint_autocomplete, previous, jid);
+                    if (found) {
+                        return found;
+                    }
+                }
             }
+
+            return NULL;
         }
 #endif
     }
@@ -2467,7 +2479,7 @@ _theme_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 }
 
 static char*
-_script_autocomplete_func(const char *const prefix, gboolean previous)
+_script_autocomplete_func(const char *const prefix, gboolean previous, void *context)
 {
     if (script_show_ac == NULL) {
         script_show_ac = autocomplete_new();
@@ -2489,14 +2501,14 @@ _script_autocomplete(ProfWin *window, const char *const input, gboolean previous
 {
     char *result = NULL;
     if (strncmp(input, "/script show ", 13) == 0) {
-        result = autocomplete_param_with_func(input, "/script show", _script_autocomplete_func, previous);
+        result = autocomplete_param_with_func(input, "/script show", _script_autocomplete_func, previous, NULL);
         if (result) {
             return result;
         }
     }
 
     if (strncmp(input, "/script run ", 12) == 0) {
-        result = autocomplete_param_with_func(input, "/script run", _script_autocomplete_func, previous);
+        result = autocomplete_param_with_func(input, "/script run", _script_autocomplete_func, previous, NULL);
         if (result) {
             return result;
         }
@@ -2529,12 +2541,12 @@ _resource_autocomplete(ProfWin *window, const char *const input, gboolean previo
         }
     }
 
-    found = autocomplete_param_with_func(input, "/resource title", prefs_autocomplete_boolean_choice, previous);
+    found = autocomplete_param_with_func(input, "/resource title", prefs_autocomplete_boolean_choice, previous, NULL);
     if (found) {
         return found;
     }
 
-    found = autocomplete_param_with_func(input, "/resource message", prefs_autocomplete_boolean_choice, previous);
+    found = autocomplete_param_with_func(input, "/resource message", prefs_autocomplete_boolean_choice, previous, NULL);
     if (found) {
         return found;
     }
@@ -2552,12 +2564,12 @@ _wintitle_autocomplete(ProfWin *window, const char *const input, gboolean previo
 {
     char *found = NULL;
 
-    found = autocomplete_param_with_func(input, "/wintitle show", prefs_autocomplete_boolean_choice, previous);
+    found = autocomplete_param_with_func(input, "/wintitle show", prefs_autocomplete_boolean_choice, previous, NULL);
     if (found) {
         return found;
     }
 
-    found = autocomplete_param_with_func(input, "/wintitle goodbye", prefs_autocomplete_boolean_choice, previous);
+    found = autocomplete_param_with_func(input, "/wintitle goodbye", prefs_autocomplete_boolean_choice, previous, NULL);
     if (found) {
         return found;
     }
@@ -2575,7 +2587,7 @@ _inpblock_autocomplete(ProfWin *window, const char *const input, gboolean previo
 {
     char *found = NULL;
 
-    found = autocomplete_param_with_func(input, "/inpblock dynamic", prefs_autocomplete_boolean_choice, previous);
+    found = autocomplete_param_with_func(input, "/inpblock dynamic", prefs_autocomplete_boolean_choice, previous, NULL);
     if (found) {
         return found;
     }
@@ -2663,7 +2675,7 @@ _form_field_autocomplete(ProfWin *window, const char *const input, gboolean prev
             switch (field_type)
             {
                 case FIELD_BOOLEAN:
-                    found = autocomplete_param_with_func(input, split[0], prefs_autocomplete_boolean_choice, previous);
+                    found = autocomplete_param_with_func(input, split[0], prefs_autocomplete_boolean_choice, previous, NULL);
                     break;
                 case FIELD_LIST_SINGLE:
                     found = autocomplete_param_with_ac(input, split[0], value_ac, TRUE, previous);
@@ -2699,7 +2711,7 @@ _occupants_autocomplete(ProfWin *window, const char *const input, gboolean previ
         return found;
     }
 
-    found = autocomplete_param_with_func(input, "/occupants color", prefs_autocomplete_boolean_choice, previous);
+    found = autocomplete_param_with_func(input, "/occupants color", prefs_autocomplete_boolean_choice, previous, NULL);
     if (found) {
         return found;
     }
@@ -2734,7 +2746,7 @@ _occupants_autocomplete(ProfWin *window, const char *const input, gboolean previ
         return found;
     }
 
-    found = autocomplete_param_with_func(input, "/occupants wrap", prefs_autocomplete_boolean_choice, previous);
+    found = autocomplete_param_with_func(input, "/occupants wrap", prefs_autocomplete_boolean_choice, previous, NULL);
     if (found) {
         return found;
     }
@@ -2961,12 +2973,12 @@ _tls_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 {
     char *result = NULL;
 
-    result = autocomplete_param_with_func(input, "/tls revoke", tlscerts_complete, previous);
+    result = autocomplete_param_with_func(input, "/tls revoke", tlscerts_complete, previous, NULL);
     if (result) {
         return result;
     }
 
-    result = autocomplete_param_with_func(input, "/tls cert", tlscerts_complete, previous);
+    result = autocomplete_param_with_func(input, "/tls cert", tlscerts_complete, previous, NULL);
     if (result) {
         return result;
     }
@@ -3017,12 +3029,12 @@ _receipts_autocomplete(ProfWin *window, const char *const input, gboolean previo
 {
     char *result = NULL;
 
-    result = autocomplete_param_with_func(input, "/receipts send", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/receipts send", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
 
-    result = autocomplete_param_with_func(input, "/receipts request", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/receipts request", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
@@ -3131,7 +3143,7 @@ _connect_autocomplete(ProfWin *window, const char *const input, gboolean previou
 
     g_strfreev(args);
 
-    found = autocomplete_param_with_func(input, "/connect", accounts_find_enabled, previous);
+    found = autocomplete_param_with_func(input, "/connect", accounts_find_enabled, previous, NULL);
     if (found) {
         return found;
     }
@@ -3192,7 +3204,7 @@ _join_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 
     g_strfreev(args);
 
-    found = autocomplete_param_with_func(input, "/join", bookmark_find, previous);
+    found = autocomplete_param_with_func(input, "/join", bookmark_find, previous, NULL);
     if (found) {
         return found;
     }
@@ -3229,13 +3241,13 @@ _console_autocomplete(ProfWin *window, const char *const input, gboolean previou
 static char*
 _win_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 {
-    return autocomplete_param_with_func(input, "/win", win_autocomplete, previous);
+    return autocomplete_param_with_func(input, "/win", win_autocomplete, previous, NULL);
 }
 
 static char*
 _close_autocomplete(ProfWin *window, const char *const input, gboolean previous)
 {
-    return autocomplete_param_with_func(input, "/close", win_close_autocomplete, previous);
+    return autocomplete_param_with_func(input, "/close", win_close_autocomplete, previous, NULL);
 }
 
 static char*
@@ -3339,7 +3351,7 @@ _account_autocomplete(ProfWin *window, const char *const input, gboolean previou
                 || (num_args == 4 && (g_strcmp0(args[2], "startscript") == 0) && !space_at_end))  {
             GString *beginning = g_string_new("/account");
             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
-            found = autocomplete_param_with_func(input, beginning->str, _script_autocomplete_func, previous);
+            found = autocomplete_param_with_func(input, beginning->str, _script_autocomplete_func, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
                 g_strfreev(args);
@@ -3373,7 +3385,7 @@ _account_autocomplete(ProfWin *window, const char *const input, gboolean previou
                 || (num_args == 4 && (g_strcmp0(args[2], "pgpkeyid") == 0) && !space_at_end))  {
             GString *beginning = g_string_new("/account");
             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
-            found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous);
+            found = autocomplete_param_with_func(input, beginning->str, p_gpg_autocomplete_key, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
                 g_strfreev(args);
@@ -3407,7 +3419,7 @@ _account_autocomplete(ProfWin *window, const char *const input, gboolean previou
         "/account default set" };
 
     for (i = 0; i < ARRAY_SIZE(account_choice); i++) {
-        found = autocomplete_param_with_func(input, account_choice[i], accounts_find_all, previous);
+        found = autocomplete_param_with_func(input, account_choice[i], accounts_find_all, previous, NULL);
         if (found) {
             return found;
         }
@@ -3422,7 +3434,7 @@ _presence_autocomplete(ProfWin *window, const char *const input, gboolean previo
 {
     char *found = NULL;
 
-    found = autocomplete_param_with_func(input, "/presence titlebar", prefs_autocomplete_boolean_choice, previous);
+    found = autocomplete_param_with_func(input, "/presence titlebar", prefs_autocomplete_boolean_choice, previous, NULL);
     if (found) {
         return found;
     }
@@ -3470,7 +3482,7 @@ _rooms_autocomplete(ProfWin *window, const char *const input, gboolean previous)
         }
         if ((num_args == 1 && g_strcmp0(args[0], "service") == 0 && space_at_end) ||
                 (num_args == 2 && g_strcmp0(args[0], "service") == 0 && !space_at_end)) {
-            found = autocomplete_param_with_func(input, "/rooms service", muc_confserver_find, previous);
+            found = autocomplete_param_with_func(input, "/rooms service", muc_confserver_find, previous, NULL);
             if (found) {
                 g_strfreev(args);
                 return found;
@@ -3498,7 +3510,7 @@ _rooms_autocomplete(ProfWin *window, const char *const input, gboolean previous)
                 (num_args == 4 && g_strcmp0(args[2], "service") == 0 && !space_at_end)) {
             GString *beginning = g_string_new("/rooms");
             g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
-            found = autocomplete_param_with_func(input, beginning->str, muc_confserver_find, previous);
+            found = autocomplete_param_with_func(input, beginning->str, muc_confserver_find, previous, NULL);
             g_string_free(beginning, TRUE);
             if (found) {
                 g_strfreev(args);
@@ -3564,7 +3576,7 @@ _clear_autocomplete(ProfWin *window, const char *const input, gboolean previous)
         return result;
     }
 
-    result = autocomplete_param_with_func(input, "/clear persist_history", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/clear persist_history", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
@@ -3585,12 +3597,12 @@ _invite_autocomplete(ProfWin *window, const char *const input, gboolean previous
     jabber_conn_status_t conn_status = connection_get_status();
 
     if (conn_status == JABBER_CONNECTED) {
-        result = autocomplete_param_with_func(input, "/invite send", roster_contact_autocomplete, previous);
+        result = autocomplete_param_with_func(input, "/invite send", roster_contact_autocomplete, previous, NULL);
         if (result) {
             return result;
         }
 
-        result = autocomplete_param_with_func(input, "/invite decline", muc_invites_find, previous);
+        result = autocomplete_param_with_func(input, "/invite decline", muc_invites_find, previous, NULL);
         if (result) {
             return result;
         }
@@ -3636,7 +3648,7 @@ _status_autocomplete(ProfWin *window, const char *const input, gboolean previous
             }
         // roster completion
         } else {
-            result = autocomplete_param_with_func(unquoted, "/status get", roster_contact_autocomplete, previous);
+            result = autocomplete_param_with_func(unquoted, "/status get", roster_contact_autocomplete, previous, NULL);
             if (result) {
                 free(unquoted);
                 return result;
@@ -3659,12 +3671,12 @@ _logging_autocomplete(ProfWin *window, const char *const input, gboolean previou
         return result;
     }
 
-    result = autocomplete_param_with_func(input, "/logging chat", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/logging chat", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
 
-    result = autocomplete_param_with_func(input, "/logging group", prefs_autocomplete_boolean_choice, previous);
+    result = autocomplete_param_with_func(input, "/logging group", prefs_autocomplete_boolean_choice, previous, NULL);
     if (result) {
         return result;
     }
@@ -3692,7 +3704,7 @@ _avatar_autocomplete(ProfWin *window, const char *const input, gboolean previous
 
     jabber_conn_status_t conn_status = connection_get_status();
     if (conn_status == JABBER_CONNECTED) {
-        result = autocomplete_param_with_func(input, "/avatar", roster_barejid_autocomplete, previous);
+        result = autocomplete_param_with_func(input, "/avatar", roster_barejid_autocomplete, previous, NULL);
         if (result) {
             return result;
         }
diff --git a/src/config/accounts.c b/src/config/accounts.c
--- a/src/config/accounts.c
+++ b/src/config/accounts.c
@@ -97,13 +97,13 @@ accounts_close(void)
 }
 
 char*
-accounts_find_enabled(const char *const prefix, gboolean previous)
+accounts_find_enabled(const char *const prefix, gboolean previous, void *context)
 {
     return autocomplete_complete(enabled_ac, prefix, TRUE, previous);
 }
 
 char*
-accounts_find_all(const char *const prefix, gboolean previous)
+accounts_find_all(const char *const prefix, gboolean previous, void *context)
 {
     return autocomplete_complete(all_ac, prefix, TRUE, previous);
 }
diff --git a/src/config/accounts.h b/src/config/accounts.h
--- a/src/config/accounts.h
+++ b/src/config/accounts.h
@@ -44,8 +44,8 @@
 void accounts_load(void);
 void accounts_close(void);
 
-char* accounts_find_all(const char *const prefix, gboolean previous);
-char* accounts_find_enabled(const char *const prefix, gboolean previous);
+char* accounts_find_all(const char *const prefix, gboolean previous, void *context);
+char* accounts_find_enabled(const char *const prefix, gboolean previous, void *context);
 void accounts_reset_all_search(void);
 void accounts_reset_enabled_search(void);
 void accounts_add(const char *jid, const char *altdomain, const int port, const char *const tls_policy);
diff --git a/src/config/preferences.c b/src/config/preferences.c
--- a/src/config/preferences.c
+++ b/src/config/preferences.c
@@ -218,7 +218,7 @@ prefs_close(void)
 }
 
 char*
-prefs_autocomplete_boolean_choice(const char *const prefix, gboolean previous)
+prefs_autocomplete_boolean_choice(const char *const prefix, gboolean previous, void *context)
 {
     return autocomplete_complete(boolean_choice_ac, prefix, TRUE, previous);
 }
@@ -230,7 +230,7 @@ prefs_reset_boolean_choice(void)
 }
 
 char*
-prefs_autocomplete_room_trigger(const char *const prefix, gboolean previous)
+prefs_autocomplete_room_trigger(const char *const prefix, gboolean previous, void *context)
 {
     return autocomplete_complete(room_trigger_ac, prefix, TRUE, previous);
 }
diff --git a/src/config/preferences.h b/src/config/preferences.h
--- a/src/config/preferences.h
+++ b/src/config/preferences.h
@@ -183,10 +183,10 @@ void prefs_reload(void);
 char* prefs_find_login(char *prefix);
 void prefs_reset_login_search(void);
 
-char* prefs_autocomplete_boolean_choice(const char *const prefix, gboolean previous);
+char* prefs_autocomplete_boolean_choice(const char *const prefix, gboolean previous, void *context);
 void prefs_reset_boolean_choice(void);
 
-char* prefs_autocomplete_room_trigger(const char *const prefix, gboolean previous);
+char* prefs_autocomplete_room_trigger(const char *const prefix, gboolean previous, void *context);
 void prefs_reset_room_trigger_ac(void);
 
 gint prefs_get_gone(void);
diff --git a/src/config/tlscerts.c b/src/config/tlscerts.c
--- a/src/config/tlscerts.c
+++ b/src/config/tlscerts.c
@@ -369,7 +369,7 @@ tlscerts_get_trusted(const char * const fingerprint)
 }
 
 char*
-tlscerts_complete(const char *const prefix, gboolean previous)
+tlscerts_complete(const char *const prefix, gboolean previous, void *context)
 {
     return autocomplete_complete(certs_ac, prefix, TRUE, previous);
 }
diff --git a/src/config/tlscerts.h b/src/config/tlscerts.h
--- a/src/config/tlscerts.h
+++ b/src/config/tlscerts.h
@@ -90,7 +90,7 @@ void tlscerts_free(TLSCertificate *cert);
 
 GList* tlscerts_list(void);
 
-char* tlscerts_complete(const char *const prefix, gboolean previous);
+char* tlscerts_complete(const char *const prefix, gboolean previous, void *context);
 
 void tlscerts_reset_ac(void);
 
diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c
--- a/src/omemo/omemo.c
+++ b/src/omemo/omemo.c
@@ -108,7 +108,7 @@ struct omemo_context_t {
     GHashTable *known_devices;
     GString *known_devices_filename;
     GKeyFile *known_devices_keyfile;
-    Autocomplete fingerprint_ac;
+    GHashTable *fingerprint_ac;
 };
 
 static omemo_context omemo_ctx;
@@ -125,14 +125,14 @@ omemo_init(void)
     pthread_mutexattr_settype(&omemo_ctx.attr, PTHREAD_MUTEX_RECURSIVE);
     pthread_mutex_init(&omemo_ctx.lock, &omemo_ctx.attr);
 
-    omemo_ctx.fingerprint_ac = autocomplete_new();
+    omemo_ctx.fingerprint_ac = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)autocomplete_free);
 }
 
 void
 omemo_close(void)
 {
     if (omemo_ctx.fingerprint_ac) {
-        autocomplete_free(omemo_ctx.fingerprint_ac);
+        g_hash_table_destroy(omemo_ctx.fingerprint_ac);
         omemo_ctx.fingerprint_ac = NULL;
     }
 }
@@ -1300,15 +1300,27 @@ omemo_key_free(omemo_key_t *key)
 }
 
 char*
-omemo_fingerprint_autocomplete(const char *const search_str, gboolean previous)
+omemo_fingerprint_autocomplete(const char *const search_str, gboolean previous, void *context)
 {
-    return autocomplete_complete(omemo_ctx.fingerprint_ac, search_str, FALSE, previous);
+    Autocomplete ac = g_hash_table_lookup(omemo_ctx.fingerprint_ac, context);
+    if (ac != NULL) {
+        return autocomplete_complete(ac, search_str, FALSE, previous);
+    } else {
+        return NULL;
+    }
 }
 
 void
 omemo_fingerprint_autocomplete_reset(void)
 {
-    autocomplete_reset(omemo_ctx.fingerprint_ac);
+    gpointer value;
+    GHashTableIter iter;
+    g_hash_table_iter_init(&iter, omemo_ctx.fingerprint_ac);
+
+    while (g_hash_table_iter_next(&iter, NULL, &value)) {
+        Autocomplete ac = value;
+        autocomplete_reset(ac);
+    }
 }
 
 gboolean
@@ -1596,8 +1608,14 @@ _cache_device_identity(const char *const jid, uint32_t device_id, ec_public_key
     g_free(device_id_str);
     omemo_known_devices_keyfile_save();
 
+    Autocomplete ac = g_hash_table_lookup(omemo_ctx.fingerprint_ac, jid);
+    if (ac == NULL) {
+        ac = autocomplete_new();
+        g_hash_table_insert(omemo_ctx.fingerprint_ac, strdup(jid), ac);
+    }
+
     char *formatted_fingerprint = omemo_format_fingerprint(fingerprint);
-    autocomplete_add(omemo_ctx.fingerprint_ac, formatted_fingerprint);
+    autocomplete_add(ac, formatted_fingerprint);
     free(formatted_fingerprint);
     free(fingerprint);
 }
diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h
--- a/src/omemo/omemo.h
+++ b/src/omemo/omemo.h
@@ -82,7 +82,7 @@ void omemo_trust(const char *const jid, const char *const fingerprint);
 void omemo_untrust(const char *const jid, const char *const fingerprint);
 GList *omemo_known_device_identities(const char *const jid);
 gboolean omemo_is_trusted_identity(const char *const jid, const char *const fingerprint);
-char *omemo_fingerprint_autocomplete(const char *const search_str, gboolean previous);
+char *omemo_fingerprint_autocomplete(const char *const search_str, gboolean previous, void *context);
 void omemo_fingerprint_autocomplete_reset(void);
 gboolean omemo_automatic_start(const char *const recipient);
 
diff --git a/src/pgp/gpg.c b/src/pgp/gpg.c
--- a/src/pgp/gpg.c
+++ b/src/pgp/gpg.c
@@ -753,7 +753,7 @@ p_gpg_free_decrypted(char *decrypted)
 }
 
 char*
-p_gpg_autocomplete_key(const char *const search_str, gboolean previous)
+p_gpg_autocomplete_key(const char *const search_str, gboolean previous, void *context)
 {
     return autocomplete_complete(key_ac, search_str, TRUE, previous);
 }
diff --git a/src/pgp/gpg.h b/src/pgp/gpg.h
--- a/src/pgp/gpg.h
+++ b/src/pgp/gpg.h
@@ -68,7 +68,7 @@ void p_gpg_verify(const char *const barejid, const char *const sign);
 char* p_gpg_encrypt(const char *const barejid, const char *const message, const char *const fp);
 char* p_gpg_decrypt(const char *const cipher);
 void p_gpg_free_decrypted(char *decrypted);
-char* p_gpg_autocomplete_key(const char *const search_str, gboolean previous);
+char* p_gpg_autocomplete_key(const char *const search_str, gboolean previous, void *context);
 void p_gpg_autocomplete_key_reset(void);
 char* p_gpg_format_fp_str(char *fp);
 
diff --git a/src/tools/autocomplete.c b/src/tools/autocomplete.c
--- a/src/tools/autocomplete.c
+++ b/src/tools/autocomplete.c
@@ -285,7 +285,7 @@ autocomplete_complete(Autocomplete ac, const gchar *search_str, gboolean quote,
 }
 
 char*
-autocomplete_param_with_func(const char *const input, char *command, autocomplete_func func, gboolean previous)
+autocomplete_param_with_func(const char *const input, char *command, autocomplete_func func, gboolean previous, void *context)
 {
     GString *auto_msg = NULL;
     char *result = NULL;
@@ -302,7 +302,7 @@ autocomplete_param_with_func(const char *const input, char *command, autocomplet
         }
         prefix[inp_len - len] = '\0';
 
-        char *found = func(prefix, previous);
+        char *found = func(prefix, previous, context);
         if (found) {
             auto_msg = g_string_new(command_cpy);
             g_string_append(auto_msg, found);
@@ -347,7 +347,7 @@ autocomplete_param_with_ac(const char *const input, char *command, Autocomplete
 }
 
 char*
-autocomplete_param_no_with_func(const char *const input, char *command, int arg_number, autocomplete_func func, gboolean previous)
+autocomplete_param_no_with_func(const char *const input, char *command, int arg_number, autocomplete_func func, gboolean previous, void *context)
 {
     if (strncmp(input, command, strlen(command)) == 0) {
         GString *result_str = NULL;
@@ -362,7 +362,7 @@ autocomplete_param_no_with_func(const char *const input, char *command, int arg_
 
             // autocomplete param
             if (comp_str) {
-                char *found = func(comp_str, previous);
+                char *found = func(comp_str, previous, context);
                 if (found) {
                     result_str = g_string_new("");
                     g_string_append(result_str, start_str);
diff --git a/src/tools/autocomplete.h b/src/tools/autocomplete.h
--- a/src/tools/autocomplete.h
+++ b/src/tools/autocomplete.h
@@ -38,7 +38,7 @@
 
 #include <glib.h>
 
-typedef char* (*autocomplete_func)(const char *const, gboolean);
+typedef char* (*autocomplete_func)(const char *const, gboolean, void *);
 typedef struct autocomplete_t *Autocomplete;
 
 // allocate new autocompleter with no items
@@ -63,13 +63,13 @@ GList* autocomplete_create_list(Autocomplete ac);
 gint autocomplete_length(Autocomplete ac);
 
 char* autocomplete_param_with_func(const char *const input, char *command,
-    autocomplete_func func, gboolean previous);
+    autocomplete_func func, gboolean previous, void *context);
 
 char* autocomplete_param_with_ac(const char *const input, char *command,
     Autocomplete ac, gboolean quote, gboolean previous);
 
 char* autocomplete_param_no_with_func(const char *const input, char *command,
-    int arg_number, autocomplete_func func, gboolean previous);
+    int arg_number, autocomplete_func func, gboolean previous, void *context);
 
 void autocomplete_reset(Autocomplete ac);
 
diff --git a/src/ui/window_list.c b/src/ui/window_list.c
--- a/src/ui/window_list.c
+++ b/src/ui/window_list.c
@@ -1093,13 +1093,13 @@ wins_create_summary(gboolean unread)
 }
 
 char*
-win_autocomplete(const char *const search_str, gboolean previous)
+win_autocomplete(const char *const search_str, gboolean previous, void *context)
 {
     return autocomplete_complete(wins_ac, search_str, TRUE, previous);
 }
 
 char*
-win_close_autocomplete(const char *const search_str, gboolean previous)
+win_close_autocomplete(const char *const search_str, gboolean previous, void *context)
 {
     return autocomplete_complete(wins_close_ac, search_str, TRUE, previous);
 }
diff --git a/src/ui/window_list.h b/src/ui/window_list.h
--- a/src/ui/window_list.h
+++ b/src/ui/window_list.h
@@ -94,9 +94,9 @@ void wins_swap(int source_win, int target_win);
 void wins_hide_subwin(ProfWin *window);
 void wins_show_subwin(ProfWin *window);
 
-char* win_autocomplete(const char *const search_str, gboolean previous);
+char* win_autocomplete(const char *const search_str, gboolean previous, void *context);
 void win_reset_search_attempts(void);
-char* win_close_autocomplete(const char *const search_str, gboolean previous);
+char* win_close_autocomplete(const char *const search_str, gboolean previous, void *context);
 void win_close_reset_search_attempts(void);
 
 #endif
diff --git a/src/xmpp/blocking.c b/src/xmpp/blocking.c
--- a/src/xmpp/blocking.c
+++ b/src/xmpp/blocking.c
@@ -93,7 +93,7 @@ blocked_list(void)
 }
 
 char*
-blocked_ac_find(const char *const search_str, gboolean previous)
+blocked_ac_find(const char *const search_str, gboolean previous, void *context)
 {
     return autocomplete_complete(blocked_ac, search_str, TRUE, previous);
 }
diff --git a/src/xmpp/bookmark.c b/src/xmpp/bookmark.c
--- a/src/xmpp/bookmark.c
+++ b/src/xmpp/bookmark.c
@@ -222,7 +222,7 @@ bookmark_get_list(void)
 }
 
 char*
-bookmark_find(const char *const search_str, gboolean previous)
+bookmark_find(const char *const search_str, gboolean previous, void *context)
 {
     return autocomplete_complete(bookmark_ac, search_str, TRUE, previous);
 }
diff --git a/src/xmpp/muc.c b/src/xmpp/muc.c
--- a/src/xmpp/muc.c
+++ b/src/xmpp/muc.c
@@ -181,13 +181,13 @@ muc_confserver_reset_ac(void)
 }
 
 char*
-muc_invites_find(const char *const search_str, gboolean previous)
+muc_invites_find(const char *const search_str, gboolean previous, void *context)
 {
     return autocomplete_complete(invite_ac, search_str, TRUE, previous);
 }
 
 char*
-muc_confserver_find(const char *const search_str, gboolean previous)
+muc_confserver_find(const char *const search_str, gboolean previous, void *context)
 {
     return autocomplete_complete(confservers_ac, search_str, TRUE, previous);
 }
diff --git a/src/xmpp/muc.h b/src/xmpp/muc.h
--- a/src/xmpp/muc.h
+++ b/src/xmpp/muc.h
@@ -126,7 +126,7 @@ char* muc_roster_nick_change_complete(const char *const room, const char *const
 
 void muc_confserver_add(const char *const server);
 void muc_confserver_reset_ac(void);
-char* muc_confserver_find(const char *const search_str, gboolean previous);
+char* muc_confserver_find(const char *const search_str, gboolean previous, void *context);
 void muc_confserver_clear(void);
 
 void muc_invites_add(const char *const room, const char *const password);
@@ -135,7 +135,7 @@ gint muc_invites_count(void);
 GList* muc_invites(void);
 gboolean muc_invites_contain(const char *const room);
 void muc_invites_reset_ac(void);
-char* muc_invites_find(const char *const search_str, gboolean previous);
+char* muc_invites_find(const char *const search_str, gboolean previous, void *context);
 void muc_invites_clear(void);
 char* muc_invite_password(const char *const room);
 
diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c
--- a/src/xmpp/presence.c
+++ b/src/xmpp/presence.c
@@ -161,7 +161,7 @@ presence_clear_sub_requests(void)
 }
 
 char*
-presence_sub_request_find(const char *const search_str, gboolean previous)
+presence_sub_request_find(const char *const search_str, gboolean previous, void *context)
 {
     return autocomplete_complete(sub_requests_ac, search_str, TRUE, previous);
 }
diff --git a/src/xmpp/roster_list.c b/src/xmpp/roster_list.c
--- a/src/xmpp/roster_list.c
+++ b/src/xmpp/roster_list.c
@@ -487,7 +487,7 @@ roster_has_pending_subscriptions(void)
 }
 
 char*
-roster_contact_autocomplete(const char *const search_str, gboolean previous)
+roster_contact_autocomplete(const char *const search_str, gboolean previous, void *context)
 {
     assert(roster != NULL);
 
@@ -495,7 +495,7 @@ roster_contact_autocomplete(const char *const search_str, gboolean previous)
 }
 
 char*
-roster_fulljid_autocomplete(const char *const search_str, gboolean previous)
+roster_fulljid_autocomplete(const char *const search_str, gboolean previous, void *context)
 {
     assert(roster != NULL);
 
@@ -550,7 +550,7 @@ roster_get_groups(void)
 }
 
 char*
-roster_group_autocomplete(const char *const search_str, gboolean previous)
+roster_group_autocomplete(const char *const search_str, gboolean previous, void *context)
 {
     assert(roster != NULL);
 
@@ -558,7 +558,7 @@ roster_group_autocomplete(const char *const search_str, gboolean previous)
 }
 
 char*
-roster_barejid_autocomplete(const char *const search_str, gboolean previous)
+roster_barejid_autocomplete(const char *const search_str, gboolean previous, void *context)
 {
     assert(roster != NULL);
 
diff --git a/src/xmpp/roster_list.h b/src/xmpp/roster_list.h
--- a/src/xmpp/roster_list.h
+++ b/src/xmpp/roster_list.h
@@ -63,12 +63,12 @@ char* roster_barejid_from_name(const char *const name);
 GSList* roster_get_contacts(roster_ord_t order);
 GSList* roster_get_contacts_online(void);
 gboolean roster_has_pending_subscriptions(void);
-char* roster_contact_autocomplete(const char *const search_str, gboolean previous);
-char* roster_fulljid_autocomplete(const char *const search_str, gboolean previous);
+char* roster_contact_autocomplete(const char *const search_str, gboolean previous, void *context);
+char* roster_fulljid_autocomplete(const char *const search_str, gboolean previous, void *context);
 GSList* roster_get_group(const char *const group, roster_ord_t order);
 GList* roster_get_groups(void);
-char* roster_group_autocomplete(const char *const search_str, gboolean previous);
-char* roster_barejid_autocomplete(const char *const search_str, gboolean previous);
+char* roster_group_autocomplete(const char *const search_str, gboolean previous, void *context);
+char* roster_barejid_autocomplete(const char *const search_str, gboolean previous, void *context);
 GSList* roster_get_contacts_by_presence(const char *const presence);
 char* roster_get_msg_display_name(const char *const barejid, const char *const resource);
 gint roster_compare_name(PContact a, PContact b);
diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h
--- a/src/xmpp/xmpp.h
+++ b/src/xmpp/xmpp.h
@@ -188,7 +188,7 @@ void presence_subscription(const char *const jid, const jabber_subscr_t action);
 GList* presence_get_subscription_requests(void);
 gint presence_sub_request_count(void);
 void presence_reset_sub_request_search(void);
-char* presence_sub_request_find(const char *const search_str, gboolean previous);
+char* presence_sub_request_find(const char *const search_str, gboolean previous, void *context);
 void presence_join_room(const char *const room, const char *const nick, const char *const passwd);
 void presence_change_room_nick(const char *const room, const char *const nick);
 void presence_leave_chat_room(const char *const room_jid);
@@ -237,7 +237,7 @@ gboolean bookmark_update(const char *jid, const char *nick, const char *password
 gboolean bookmark_remove(const char *jid);
 gboolean bookmark_join(const char *jid);
 GList* bookmark_get_list(void);
-char* bookmark_find(const char *const search_str, gboolean previous);
+char* bookmark_find(const char *const search_str, gboolean previous, void *context);
 void bookmark_autocomplete_reset(void);
 gboolean bookmark_exists(const char *const room);
 
@@ -250,7 +250,7 @@ void roster_send_remove(const char *const barejid);
 GList* blocked_list(void);
 gboolean blocked_add(char *jid);
 gboolean blocked_remove(char *jid);
-char* blocked_ac_find(const char *const search_str, gboolean previous);
+char* blocked_ac_find(const char *const search_str, gboolean previous, void *context);
 void blocked_ac_reset(void);
 
 void form_destroy(DataForm *form);


Test patch:
diff --git a/tests/unittests/config/stub_accounts.c b/tests/unittests/config/stub_accounts.c
--- a/tests/unittests/config/stub_accounts.c
+++ b/tests/unittests/config/stub_accounts.c
@@ -14,7 +14,7 @@ char * accounts_find_all(char *prefix)
     return NULL;
 }
 
-char * accounts_find_enabled(char *prefix)
+char * accounts_find_enabled(char *prefix, void *context)
 {
     return NULL;
 }
diff --git a/tests/unittests/pgp/stub_gpg.c b/tests/unittests/pgp/stub_gpg.c
--- a/tests/unittests/pgp/stub_gpg.c
+++ b/tests/unittests/pgp/stub_gpg.c
@@ -56,7 +56,7 @@ void p_gpg_free_keys(GHashTable *keys) {}
 
 void p_gpg_autocomplete_key_reset(void) {}
 
-char * p_gpg_autocomplete_key(const char * const search_str, gboolean previous)
+char * p_gpg_autocomplete_key(const char * const search_str, gboolean previous, void *context)
 {
     return NULL;
 }
diff --git a/tests/unittests/test_roster_list.c b/tests/unittests/test_roster_list.c
--- a/tests/unittests/test_roster_list.c
+++ b/tests/unittests/test_roster_list.c
@@ -178,7 +178,7 @@ void find_first_exists(void **state)
 
     char *search = strdup("B");
 
-    char *result = roster_contact_autocomplete(search, FALSE);
+    char *result = roster_contact_autocomplete(search, FALSE, NULL);
     assert_string_equal("Bob", result);
     free(result);
     free(search);
@@ -192,7 +192,7 @@ void find_second_exists(void **state)
     roster_add("Dave", NULL, NULL, NULL, FALSE);
     roster_add("Bob", NULL, NULL, NULL, FALSE);
 
-    char *result = roster_contact_autocomplete("Dav", FALSE);
+    char *result = roster_contact_autocomplete("Dav", FALSE, NULL);
     assert_string_equal("Dave", result);
     free(result);
     roster_destroy();
@@ -205,7 +205,7 @@ void find_third_exists(void **state)
     roster_add("Dave", NULL, NULL, NULL, FALSE);
     roster_add("Bob", NULL, NULL, NULL, FALSE);
 
-    char *result = roster_contact_autocomplete("Ja", FALSE);
+    char *result = roster_contact_autocomplete("Ja", FALSE, NULL);
     assert_string_equal("James", result);
     free(result);
     roster_destroy();
@@ -218,7 +218,7 @@ void find_returns_null(void **state)
     roster_add("Dave", NULL, NULL, NULL, FALSE);
     roster_add("Bob", NULL, NULL, NULL, FALSE);
 
-    char *result = roster_contact_autocomplete("Mike", FALSE);
+    char *result = roster_contact_autocomplete("Mike", FALSE, NULL);
     assert_null(result);
     roster_destroy();
 }
@@ -226,7 +226,7 @@ void find_returns_null(void **state)
 void find_on_empty_returns_null(void **state)
 {
     roster_create();
-    char *result = roster_contact_autocomplete("James", FALSE);
+    char *result = roster_contact_autocomplete("James", FALSE, NULL);
     assert_null(result);
     roster_destroy();
 }
@@ -238,8 +238,8 @@ void find_twice_returns_second_when_two_match(void **state)
     roster_add("Jamie", NULL, NULL, NULL, FALSE);
     roster_add("Bob", NULL, NULL, NULL, FALSE);
 
-    char *result1 = roster_contact_autocomplete("Jam", FALSE);
-    char *result2 = roster_contact_autocomplete(result1, FALSE);
+    char *result1 = roster_contact_autocomplete("Jam", FALSE, NULL);
+    char *result2 = roster_contact_autocomplete(result1, FALSE, NULL);
     assert_string_equal("Jamie", result2);
     free(result1);
     free(result2);
@@ -260,11 +260,11 @@ void find_five_times_finds_fifth(void **state)
     roster_add("Jamy", NULL, NULL, NULL, FALSE);
     roster_add("Jamz", NULL, NULL, NULL, FALSE);
 
-    char *result1 = roster_contact_autocomplete("Jam", FALSE);
-    char *result2 = roster_contact_autocomplete(result1, FALSE);
-    char *result3 = roster_contact_autocomplete(result2, FALSE);
-    char *result4 = roster_contact_autocomplete(result3, FALSE);
-    char *result5 = roster_contact_autocomplete(result4, FALSE);
+    char *result1 = roster_contact_autocomplete("Jam", FALSE, NULL);
+    char *result2 = roster_contact_autocomplete(result1, FALSE, NULL);
+    char *result3 = roster_contact_autocomplete(result2, FALSE, NULL);
+    char *result4 = roster_contact_autocomplete(result3, FALSE, NULL);
+    char *result5 = roster_contact_autocomplete(result4, FALSE, NULL);
     assert_string_equal("Jamo", result5);
     free(result1);
     free(result2);
@@ -281,9 +281,9 @@ void find_twice_returns_first_when_two_match_and_reset(void **state)
     roster_add("Jamie", NULL, NULL, NULL, FALSE);
     roster_add("Bob", NULL, NULL, NULL, FALSE);
 
-    char *result1 = roster_contact_autocomplete("Jam", FALSE);
+    char *result1 = roster_contact_autocomplete("Jam", FALSE, NULL);
     roster_reset_search_attempts();
-    char *result2 = roster_contact_autocomplete(result1, FALSE);
+    char *result2 = roster_contact_autocomplete(result1, FALSE, NULL);
     assert_string_equal("James", result2);
     free(result1);
     free(result2);
diff --git a/tests/unittests/xmpp/stub_xmpp.c b/tests/unittests/xmpp/stub_xmpp.c
--- a/tests/unittests/xmpp/stub_xmpp.c
+++ b/tests/unittests/xmpp/stub_xmpp.c
@@ -151,7 +151,7 @@ gint presence_sub_request_count(void)
 
 void presence_reset_sub_request_search(void) {}
 
-char * presence_sub_request_find(const char * const search_str, gboolean previous)
+char * presence_sub_request_find(const char * const search_str, gboolean previous, void *context)
 {
     return  NULL;
 }
@@ -266,7 +266,7 @@ GList * bookmark_get_list(void)
     return mock_ptr_type(GList *);
 }
 
-char * bookmark_find(const char * const search_str, gboolean previous)
+char * bookmark_find(const char * const search_str, gboolean previous, void *context)
 {
     return NULL;
 }
@@ -314,7 +314,7 @@ gboolean blocked_remove(char *jid)
     return TRUE;
 }
 
-char* blocked_ac_find(const char *const search_str, gboolean previous)
+char* blocked_ac_find(const char *const search_str, gboolean previous, void *context)
 {
     return NULL;
 }