如何使用Smack在XMPP服务器中按用户名搜索已注册用户?

7
我正在使用asmack库开发Android聊天应用程序。我正在使用EJABBERD XMPP服务器。我已经完成了一些功能,包括登录、注册和花名册条目等。
现在我想从XMPP服务器中搜索已注册的用户以发送好友请求。我谷歌了一些代码,但仍然没有成功。
我正在使用以下代码来从XMPP服务器搜索用户:
UserSearchManager userSearchManager = new UserSearchManager(connection);
Form searchForm = userSearchManager.getSearchForm("search." + connection.getServiceName());
Form answerForm = searchForm.createAnswerForm();
answerForm.setAnswer("Name", true);
answerForm.setAnswer("search", "test"); // here i'm passsing the Text value to search

ReportedData resultData;
resultData = userSearchManager.getSearchResults(answerForm, "search."+ connection.getServiceName());

Iterator<Row> it = resultData.getRows();
Row row = null;
while (it.hasNext()) {
    String value = it.next().toString();
    Log.i("Iteartor values......", " " + value);
    System.out.println("Jabber_id :" + row.getValues("jid").next().toString());
    System.out.println("Name :" + row.getValues("Name").next().toString());
    row = it.next();
}

当我执行以上代码时,在LogCat中出现了以下错误。
service-unavailable(503)

    at org.jivesoftware.smackx.search.UserSearch.getSearchForm(UserSearch.java:84)

    at org.jivesoftware.smackx.search.UserSearchManager.getSearchForm(UserSearchManager.java:73)

需要做哪些改变才能获得搜索结果?
ejabberd.cfg
%%%   =======
%%%   MODULES

%%
%% Modules enabled in all ejabberd virtual hosts.
%%
{modules,
 [
  {mod_adhoc,    []},
  {mod_announce, [{access, announce}]}, % requires mod_adhoc
  {mod_caps,     []},
  {mod_configure,[]}, % requires mod_adhoc
  {mod_admin_extra, []},
  {mod_disco,    []},
  %%{mod_echo,   [{host, "echo.localhost"}]},
  {mod_irc,      []},
  %% NOTE that mod_http_fileserver must also be enabled in the
  %% "request_handlers" clause of the "ejabberd_http" listener
  %% configuration (see the "LISTENING PORTS" section above).
  %%{mod_http_fileserver, [
  %%                       {docroot, "/var/www"}, 
  %%                       {accesslog, "/var/log/ejabberd/access.log"}
  %%                      ]},
  {mod_last,     []},
  {mod_muc,      [
          %%{host, "conference.@HOST@"},
          {access, muc},
          {access_create, muc},
          {access_persistent, muc},
          {access_admin, muc_admin},
          {max_users, 500}
         ]},
  %%{mod_muc_log,[]},
  {mod_offline,  [{access_max_user_messages, max_user_offline_messages}]},
  {mod_privacy,  []},
  {mod_private,  []},
  {mod_proxy65,  [
          {access, local},
          {shaper, c2s_shaper}
         ]},
  {mod_pubsub,   [ % requires mod_caps
          {access_createnode, pubsub_createnode},
          {pep_sendlast_offline, false},
          {last_item_cache, false},
          %%{plugins, ["default", "pep"]}
          {plugins, ["flat", "hometree", "pep"]}  % pep requires mod_caps
         ]},
  {mod_register, [
          %%
          %% After successful registration, the user receives
          %% a message with this subject and body.
          %%
          {welcome_message, {"Welcome!",
                     "Welcome to a Jabber service powered by Debian. "
                     "For information about Jabber visit "
                     "http://www.jabber.org"}},
          %% Replace it with 'none' if you don't want to send such message:
          %%{welcome_message, none},

          %%
          %% When a user registers, send a notification to
          %% these Jabber accounts.
          %%
          %%{registration_watchers, ["admin1@example.org"]},

          {access, register}
         ]},
  {mod_roster,   []},
  %%{mod_service_log,[]},
  %%{mod_shared_roster,[]},
  {mod_stats,    []},
  {mod_time,     []},
  {mod_vcard,    []},
  {mod_version,  []}
 ]}.

503 表示服务暂时不可用(繁忙?)。您是否检查了服务器此时是否过载?通常,您可以通过短暂延迟和重试来处理此类错误..也许在逐渐增加的延迟下..并让用户知道远程服务器似乎很忙..然后最终失败。 - ErstwhileIII
1
您正在将搜索请求发送到服务器的 search 子域,但是 mod_vcard 的默认配置是使用 vjud 子域。能否包含您的 ejabberd 配置中相关的部分? - legoscia
感谢您的回复,@ErstwhileIII。我重新启动了服务器并尝试了一次,但仍然显示相同的错误。除了在xmpp中搜索用户之外,其余的事情都很好。如果服务繁忙,您能告诉我如何处理吗? - Prabhu
你可能需要调查一下网络服务器日志。 - ErstwhileIII
感谢您的回复@legoscia,很抱歉我不熟悉ejabberd,如何将搜索子域更改为vjud。我已经提供了ejabberd.cfg的一部分。您能告诉我如何将其设置为vjud吗? - Prabhu
5个回答

6

由于ejabberd的默认配置是将搜索服务保留在vjud.example.com而不是search.example.com,因此您需要更改以下行:

Form searchForm = userSearchManager.getSearchForm("search." + connection.getServiceName());

转换为:

Form searchForm = userSearchManager.getSearchForm("vjud." + connection.getServiceName());

感谢@legoscia。我按照上面的指示修复了那个错误。但是当我执行以下代码时(answerForm.setAnswer("Username", true); answerForm.setAnswer("search", "*"); )它显示以下错误。java.lang.IllegalArgumentException: Field not found for the specified variable name. at org.jivesoftware.smackx.Form.setAnswer(Form.java:253) at com.mypackage.roster.RosterData.searchExample(RosterData.java:292)所以请问一下,Ejabberd是否支持我们传递的字段,例如:用户名,我是否传递了正确的字段来搜索用户名。 - Prabhu

4

我刚刚在使用XMPP搜索功能时遇到了一些问题。如果你在使用ejabberd,我可以提供帮助。

  • First, I use ejabberd with mysql. So I went into the mysql db and found that there are two tables: vcard and vcard_search. So if vcard_search is empty, you will not be able to search. So make sure that your client registers a user's vcard because with this vcard_search will be populated as well as vcard tables.
  • For the client, I use smack 4.1.0 (latest smack library that I consider to be stable). Just use the following code snippet and results will be there. So the trick is to set the answer just once with "user" and jabber user id. Ejabberd does not support "Username".

    public boolean userExists(XMPPConnection mXMPPConnection, String jid) {
        //ProviderManager.getInstance().addIQProvider("query","jabber:iq:search", new UserSearchManager().Provider());
        ProviderManager.addIQProvider("query", "jabber:iq:search", new UserSearch.Provider());
        ProviderManager.addIQProvider("query", "jabber:iq:vjud", new UserSearch.Provider());
        UserSearchManager searchManager = new UserSearchManager(mXMPPConnection);
        try {
    
            List<String> services = searchManager.getSearchServices();
            if (services == null || services.size() < 1)
                return false;
            for (String service : services) {
                Log.e("SERVICE", service);
            }
            Form searchForm;
            try {
                searchForm = searchManager.getSearchForm(services.get(0));
                Form answerForm = searchForm.createAnswerForm();
                try {
                    answerForm.setAnswer("user", jid);
                } catch (IllegalStateException ex) {
                    ex.printStackTrace();
                    return false;
                }
                //answerForm.setAnswer("search", jid);
                ReportedData data;
                try {
                    data = searchManager.getSearchResults(answerForm, services.get(0));
                    Log.e("HERE\t", "1");
                    if (data.getRows() != null) {
                        List<ReportedData.Row> rowList = data.getRows();
                        if (rowList.size() > 0) {
                            Log.e("HERE\t", "2");
                            return true;
                        } else
                            return false;
    
                    }
                } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | SmackException.NotConnectedException e) {
                    e.printStackTrace();
                    return false;
                }
    
    
            } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | SmackException.NotConnectedException e) {
                e.printStackTrace();
                return false;
            }
    
        } catch (SmackException.NoResponseException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) {
            e.printStackTrace();
            return false;
        }
    
        return false;
    }
    

4
legoscia已经解释,你的搜索服务域名可能有误。这可能是service-unavailable(503)错误的原因。Erstwhilell将XMPP错误代码与HTTP错误代码混淆,其中503通常表示负载过重的HTTP服务器,但在XMPP世界中,503的含义略有不同:服务不可用(原因未说明/任何原因)。

请注意,Smack包含一个方便的方法来查找搜索服务(如果有的话):UserSearchManager.getSearchService()。因此,一个良好的实现将如下所示:

UserSearchManager usm = …
Collection<String> services = usm.getSearchService();
if (services.isEmtpy())
    throw new Exception("No search services available");
Form searchForm = userSearchManager.getSearchForm(services.iterator().next());

2

Ejabberd不支持字段值"Username",它在openfire中使用。请在ejabberd中使用字段值"user",并将参数作为字符串传递。


-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接