I have this code, almost unmodified from examples:
UserSearchManager usm = new UserSearchManager(conn);
Form searchForm = usm.getSearchForm("search.myserver.com");
Form answerForm = searchForm.createAnswerForm();
answerForm.setAnswer("Username", true);
answerForm.setAnswer("search", contact.getJid());
ReportedData data = usm.getSearchResults(answerForm, "search.myserver.com");
This works perfectly in a Desktop environment, using Smack library, but I can't get it to work in Android (where I have to use asmack).
The problem is searchForm is null because getSearchForm returns null. This seems to be pretty odd as I can't seem to find any documentation on which cases that method should return null.
The server is Openfire, if it helps.
Update 04/2014
The original answer below contains now old and outdated information. Since aSmack 0.8 it's no longer necessary to manually configure the provider manager. Calling SmackAndroid.init(Context)
as the aSmack README tells you to do, takes care of all necessary initializations.
Original Answer
In the end, the problem was global to all asmack. It seems it's a known issue: the smack.providers file, usually in /META-INF folder in normal versions of smack, can't be loaded in Android because its jar packaging. So all the providers must be initialized by hand, as shown in Mike Ryan's answer in this thread: http://community.igniterealtime.org/message/201866#201866
I removed the stuff that didn't worked for me, and this is the result.
public void configure(ProviderManager pm) {
// Private Data Storage
pm.addIQProvider("query","jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider());
// Time
try {
pm.addIQProvider("query","jabber:iq:time", Class.forName("org.jivesoftware.smackx.packet.Time"));
} catch (ClassNotFoundException e) {
Log.w("TestClient", "Can't load class for org.jivesoftware.smackx.packet.Time");
}
// Roster Exchange
pm.addExtensionProvider("x","jabber:x:roster", new RosterExchangeProvider());
// Message Events
pm.addExtensionProvider("x","jabber:x:event", new MessageEventProvider());
// Chat State
pm.addExtensionProvider("active","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
pm.addExtensionProvider("composing","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
pm.addExtensionProvider("paused","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
pm.addExtensionProvider("inactive","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
pm.addExtensionProvider("gone","http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
// XHTML
pm.addExtensionProvider("html","http://jabber.org/protocol/xhtml-im", new XHTMLExtensionProvider());
// Group Chat Invitations
pm.addExtensionProvider("x","jabber:x:conference", new GroupChatInvitation.Provider());
// Service Discovery # Items
pm.addIQProvider("query","http://jabber.org/protocol/disco#items", new DiscoverItemsProvider());
// Service Discovery # Info
pm.addIQProvider("query","http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());
// Data Forms
pm.addExtensionProvider("x","jabber:x:data", new DataFormProvider());
// MUC User
pm.addExtensionProvider("x","http://jabber.org/protocol/muc#user", new MUCUserProvider());
// MUC Admin
pm.addIQProvider("query","http://jabber.org/protocol/muc#admin", new MUCAdminProvider());
// MUC Owner
pm.addIQProvider("query","http://jabber.org/protocol/muc#owner", new MUCOwnerProvider());
// Delayed Delivery
pm.addExtensionProvider("x","jabber:x:delay", new DelayInformationProvider());
// Version
try {
pm.addIQProvider("query","jabber:iq:version", Class.forName("org.jivesoftware.smackx.packet.Version"));
} catch (ClassNotFoundException e) {
// Not sure what's happening here.
}
// VCard
pm.addIQProvider("vCard","vcard-temp", new VCardProvider());
// Offline Message Requests
pm.addIQProvider("offline","http://jabber.org/protocol/offline", new OfflineMessageRequest.Provider());
// Offline Message Indicator
pm.addExtensionProvider("offline","http://jabber.org/protocol/offline", new OfflineMessageInfo.Provider());
// Last Activity
pm.addIQProvider("query","jabber:iq:last", new LastActivity.Provider());
// User Search
pm.addIQProvider("query","jabber:iq:search", new UserSearch.Provider());
// SharedGroupsInfo
pm.addIQProvider("sharedgroup","http://www.jivesoftware.org/protocol/sharedgroup", new SharedGroupsInfo.Provider());
// JEP-33: Extended Stanza Addressing
pm.addExtensionProvider("addresses","http://jabber.org/protocol/address", new MultipleAddressesProvider());
// FileTransfer
pm.addIQProvider("si","http://jabber.org/protocol/si", new StreamInitiationProvider());
pm.addIQProvider("query","http://jabber.org/protocol/bytestreams", new BytestreamsProvider());
// Privacy
pm.addIQProvider("query","jabber:iq:privacy", new PrivacyProvider());
pm.addIQProvider("command", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider());
pm.addExtensionProvider("malformed-action", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.MalformedActionError());
pm.addExtensionProvider("bad-locale", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadLocaleError());
pm.addExtensionProvider("bad-payload", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadPayloadError());
pm.addExtensionProvider("bad-sessionid", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadSessionIDError());
pm.addExtensionProvider("session-expired", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.SessionExpiredError());
}
I only commented a couple lines, and voilà. This should be called before instantiating XMPPConnection, with a line like this:
configure(ProviderManager.getInstance());
Now I'll have to deal with my other problems, but at least this one is solved :)
In the code example XmppTool.java, getSearchFrom
is used in searchUsers()
.
public List<User> searchUsers(String serverDomain,String userName){
List<User> list = new ArrayList<User>();
UserSearchManager userSearchManager = new UserSearchManager(con);
try {
Form searchForm = userSearchManager.getSearchForm("search."+serverDomain);
Form answerForm = searchForm.createAnswerForm();
answerForm.setAnswer("Username", true);
answerForm.setAnswer("Name", true);
answerForm.setAnswer("search", userName);
ReportedData data = userSearchManager.getSearchResults(answerForm, "search."+serverDomain);
Iterator<Row> rows = data.getRows();
while(rows.hasNext()){
User user = new User();
Row row = rows.next();
user.setUserName(row.getValues("Username").next().toString());
user.setName(row.getValues("Name").next().toString());
SLog.i(tag, user.toString());
list.add(user);
}
} catch (XMPPException e) {
SLog.e(tag, Log.getStackTraceString(e));
}
return list;
}
You may refer to the global settings in the java file to repair your code.
The Javadoc of UserSearchManager explains as follows:
The UserSearchManager is a facade built upon Jabber Search Services (JEP-055) to allow for searching repositories on a Jabber Server. This implementation allows for transparency of implementation of searching (DataForms or No DataForms), but allows the user to simply use the DataForm model for both types of support.
XMPPConnection con = new XMPPConnection("jabber.org");
con.login("john", "doe");
UserSearchManager search = new UserSearchManager(con, "users.jabber.org");
Form searchForm = search.getSearchForm();
Form answerForm = searchForm.createAnswerForm();
answerForm.setAnswer("last", "DeMoro");
ReportedData data = search.getSearchResults(answerForm);
// Use Returned Data