我正在使用 aSmack 和 Openfire。
经过大量研究,我发现 Openfire 不支持消息归档并安装了插件 OpenArchive。
现在归档工作正常,所有消息都存储正常。
现在在客户端,我尝试发送一个 IQ 节 来检索存档的聊天记录。
首先,我添加了一个 IQ Provider,如下所示:
pm.addIQProvider("list", "urn:xmpp:archive", new ListIQProvider());
然后我用了:
final IQ iq = new IQ()
{
@Override public String getChildElementXML()
{
return "<list xmlns='urn:xmpp:archive' with='test@customOpenfire.com'><set xmlns='http://jabber.org/protocol/rsm'><max xmlns='http://jabber.org/protocol/rsm'>30</max></set> </list>";
}
};
iq.setType(IQ.Type.GET);
iq.setPacketID("987654321");
xmppConnection.sendPacket(iq);
它运行良好,我收到了回复。
<iq id="987654321" to="admin@customOpenfire.com/Smack" type="result">
<list xmlns="urn:xmpp:archive">
<chat with="test@customOpenfire.com" start="2014-04-06T12:11:28.674Z"/>
<chat with="test@customOpenfire.com" start="2014-04-03T16:55:59.523Z"/>
<chat with="test@customOpenfire.com" start="2014-04-05T16:33:03.377Z"/>
<chat with="test@customOpenfire.com" start="2014-04-02T14:32:10.499Z"/>
<chat with="test@customOpenfire.com" start="2014-04-06T12:47:52.961Z"/>
<chat with="test@customOpenfire.com" start="2014-04-03T14:46:24.877Z"/>
<chat with="test@customOpenfire.com" start="2014-04-06T12:37:14.608Z"/>
<chat with="test@customOpenfire.com" start="2014-04-03T15:48:46.642Z"/>
<chat with="test@customOpenfire.com" start="2014-04-02T13:46:07.750Z"/>
<chat with="test@customOpenfire.com" start="2014-04-04T18:25:57.968Z"/>
<chat with="test@customOpenfire.com" start="2014-04-03T19:08:45.238Z"/>
<chat with="test@customOpenfire.com" start="2014-04-04T18:47:19.067Z"/>
<chat with="test@customOpenfire.com" start="2014-04-04T19:34:27.819Z"/>
<chat with="test@customOpenfire.com" start="2014-04-02T15:09:13.140Z"/>
<chat with="test@customOpenfire.com" start="2014-04-03T18:30:36.804Z"/>
<chat with="test@customOpenfire.com" start="2014-04-05T14:09:34.973Z"/>
<chat with="test@customOpenfire.com" start="2014-04-04T22:47:54.363Z"/>
<chat with="test@customOpenfire.com" start="2014-04-02T15:32:44.540Z"/>
<chat with="test@customOpenfire.com" start="2014-04-03T17:18:37.940Z"/>
<chat with="test@customOpenfire.com" start="2014-04-03T13:37:15.630Z"/>
<chat with="test@customOpenfire.com" start="2014-04-04T17:10:39.116Z"/>
<set xmlns="http://jabber.org/protocol/rsm">
<first index="0">66</first>
<last>139</last>
<count>21</count>
</set>
</list>
</iq>
然后我想检索实际消息,所以我发送了这个 IQ 节:
final IQ iq = new IQ()
{
@Override public String getChildElementXML()
{
return "<retrieve xmlns='urn:xmpp:archive' with='test@customOpenfire.com'><set xmlns='http://jabber.org/protocol/rsm'><max xmlns='http://jabber.org/protocol/rsm'>30</max></set> </retrieve>";
}
};
iq.setType(IQ.Type.GET);
iq.setPacketID("987654321");
xmppConnection.sendPacket(iq);
当然是在我创建了自定义提供程序并将其添加如下之后:
pm.addIQProvider("retrieve", "urn:xmpp:archive", new ChatIQProvider());
我应该收到类似的东西:
<iq xmlns="jabber:client" type="result" id="hgfg" to="admin@customOpenfire.com/7dd0f2fc">
<chat xmlns="urn:xmpp:archive" with="test@customOpenfire.com" start="2014-04-02T13:46:07.750Z">
<from secs="0" jid="test@customOpenfire.com">
<body>hello</body>
</from>
<to secs="2">
<body>hey</body>
</to>
<from secs="5" jid="test@customOpenfire.com">
<body>test</body>
</from>
<set xmlns="http://jabber.org/protocol/rsm">
<first index="0">0</first>
<last>2</last>
<count>3</count>
</set>
</chat>
但在我的数据包监听器中,结果未被解析,其处理方式与如果我删除 ListIQProvider() 时处理list 节 的方式相同。
这是我的自定义类:
ChatIQ:
public class ChatIQ extends IQ {
private String xmlns;
private String with;
private String start;
private List<From> froms;
private Set set;
public ChatIQ()
{
this.froms = new ArrayList<ChatIQ.From>();
}
public String getXmlns()
{
return xmlns;
}
public void setXmlns(String xmlns)
{
this.xmlns = xmlns;
}
public String getWith()
{
return with;
}
public void setWith(String with)
{
this.with = with;
}
public String getStart()
{
return start;
}
public void setStart(String start)
{
this.start = start;
}
public void addFrom(From from)
{
froms.add(from);
}
public List<From> getFroms()
{
return froms;
}
public Set getSet()
{
return set;
}
public void setSet(Set set)
{
this.set = set;
}
@Override
public String getChildElementXML()
{
StringBuilder builder = new StringBuilder("<chat xmlns=\"urn:xmpp:archive\"");
builder.append("with=\"").append(with).append("\"");
builder.append(" start=\"");
builder.append(start);
builder.append("\">");
for(From from : froms)
{
builder.append(from.toXml());
}
builder.append(set.toXml());
builder.append("</chat>");
return builder.toString();
}
public static class From
{
private String secs;
private String jid;
private Body body;
public String getSecs()
{
return secs;
}
public void setSecs(String secs)
{
this.secs = secs;
}
public String getJid()
{
return jid;
}
public void setJid(String jid)
{
this.jid = jid;
}
public Body getBody()
{
return body;
}
public void setBody(Body body)
{
this.body = body;
}
public String toXml()
{
StringBuilder builder = new StringBuilder("<from ");
builder.append("secs=\"").append(secs).append("\" ");
builder.append("jid=\"").append(jid).append("\" >");
builder.append(body.toXml());
builder.append("</from>");
return builder.toString();
}
}
public static class Body
{
private String message;
public Body(String message)
{
this.message = message;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
public Object toXml()
{
StringBuilder builder = new StringBuilder("<body>");
builder.append(message);
builder.append("</body>");
return builder.toString();
}
}
public static class Set {
private int last;
private int count;
private int indexAtt;
private int first;
public Set()
{
}
public int getLast()
{
return last;
}
public void setLast(int last)
{
this.last = last;
}
public int getCount()
{
return count;
}
public void setCount(int count)
{
this.count = count;
}
public int getIndexAtt()
{
return indexAtt;
}
public void setIndexAtt(int indexAtt)
{
this.indexAtt = indexAtt;
}
public int getFirst()
{
return first;
}
public void setFirst(int first)
{
this.first = first;
}
public String toXml()
{
StringBuilder builder = new StringBuilder("<set xmlns=\"http://jabber.org/protocol/rsm\">");
builder.append("<first index=\"").append(indexAtt).append("\">").append(first).append("</first>");
builder.append("<last>").append(last).append("</last>");
builder.append("<count>").append(count).append("</count>");
builder.append("</set>");
return builder.toString();
}
}
}
ChatIQProvider:
public class ChatIQProvider implements IQProvider {
public ChatIQProvider()
{
}
@Override
public IQ parseIQ(XmlPullParser parser) throws Exception
{
Log.d("CHAT IQ PROVIDER", String.format("Received iq packet, namespace[%s], name[%s]", parser.getNamespace(), parser.getName()));
ChatIQ iq = new ChatIQ();
ChatIQ.Set set = new Set();
boolean done = false;
From from = new From();
String secs = "", jid = "";
while (!done)
{
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG)
{
if (parser.getName().equals("from"))
{
secs = parser.getAttributeValue("", "secs");
jid = parser.getAttributeValue("", "jid");
from = new From();
iq.addFrom(from);
}
else if(parser.getName().equals("body") && from.getBody()==null)
{
ChatIQ.Body body = new Body(parser.nextText());
from.setBody(body);
}
else if (parser.getName().equals("first"))
{
int index = parseInt(parser.getAttributeValue("", "index"));
set.setIndexAtt(index);
int first = parseInt(parser.nextText());
set.setFirst(first);
}
else if (parser.getName().equals("last"))
{
int last = parseInt(parser.nextText());
set.setLast(last);
}
else if (parser.getName().equals("count"))
{
int count = parseInt(parser.nextText());
set.setCount(count);
}
}
else if (eventType == XmlPullParser.END_TAG)
{
if (parser.getName().equals("chat"))
{
iq.setSet(set);
done = true;
}
}
}
return iq;
}
private int parseInt(String integer)
{
return Integer.parseInt((integer != null ? integer : "0"));
}
}
我的问题如下:
谢谢。
最佳答案
我解决了这个问题,但我忘了在这里为可能有同样问题的其他人发布答案。 无论如何,修复非常简单。而不是:
pm.addIQProvider("retrieve", "urn:xmpp:archive", new ChatIQProvider());
我应该使用:
pm.addIQProvider("chat", "urn:xmpp:archive", new ChatIQProvider());
我必须注册 IQ 响应的子标签的名称,而不是请求的名称,因此是“聊天”而不是“检索”。
希望这会有所帮助,因为我在 android smack api 中找不到任何关于使用自定义 IQ 的示例。
由于评论太长,我把它加在这里。
给你:
ListIQProvider:
public class ListIQProvider implements IQProvider {
public ListIQProvider()
{
}
@Override
public IQ parseIQ(XmlPullParser parser) throws Exception
{
ListIQ iq = new ListIQ();
ListIQ.Set set = new Set();
boolean done = false;
String with = "", start = "";
while (!done)
{
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG)
{
if (parser.getName().equals("chat"))
{
with = parser.getAttributeValue("", "with");
start = parser.getAttributeValue("", "start");
iq.addChat(new Chat(with, start));
}
else if (parser.getName().equals("first"))
{
int index = parseInt(parser.getAttributeValue("", "index"));
set.setIndexAtt(index);
int first = parseInt(parser.nextText());
set.setFirst(first);
}
else if (parser.getName().equals("last"))
{
int last = parseInt(parser.nextText());
set.setLast(last);
}
else if (parser.getName().equals("count"))
{
int count = parseInt(parser.nextText());
set.setCount(count);
}
}
else if (eventType == XmlPullParser.END_TAG)
{
if (parser.getName().equals("list"))
{
iq.setSet(set);
done = true;
}
}
}
return iq;
}
private int parseInt(String integer)
{
return Integer.parseInt((integer != null ? integer : "0"));
}
列表智商:
public class ListIQ extends IQ {
private List<Chat> chats;
private Set set;
public ListIQ()
{
this.chats = new ArrayList<ListIQ.Chat>();
}
public Set getSet()
{
return set;
}
public void setSet(Set set)
{
this.set = set;
}
public void addChat(Chat chat)
{
chats.add(chat);
}
public List<Chat> getChats()
{
return chats;
}
@Override
public String getChildElementXML()
{
StringBuilder builder = new StringBuilder("<list xmlns=\"urn:xmpp:archive\">");
for (Chat chat : chats)
{
builder.append(chat.toXml());
}
builder.append(set.toXml());
builder.append("</list>");
return builder.toString();
}
public static class Chat {
private String with;
private String start;
public Chat()
{
}
public Chat(String with, String start)
{
this.with = with;
this.start = start;
}
public String getWith()
{
return with;
}
public void setWith(String with)
{
this.with = with;
}
public String getStart()
{
return start;
}
public void setStart(String start)
{
this.start = start;
}
public String toXml()
{
StringBuilder builder = new StringBuilder("<chat with=\"");
builder.append(with).append("\"");
builder.append(" start=\"");
builder.append(start);
builder.append("\"/>");
return builder.toString();
}
}
public static class Set {
private int last;
private int count;
private int indexAtt;
private int first;
public Set()
{
}
public int getLast()
{
return last;
}
public void setLast(int last)
{
this.last = last;
}
public int getCount()
{
return count;
}
public void setCount(int count)
{
this.count = count;
}
public int getIndexAtt()
{
return indexAtt;
}
public void setIndexAtt(int indexAtt)
{
this.indexAtt = indexAtt;
}
public int getFirst()
{
return first;
}
public void setFirst(int first)
{
this.first = first;
}
public String toXml()
{
StringBuilder builder = new StringBuilder("<set xmlns=\"http://jabber.org/protocol/rsm\">");
builder.append("<first index=\"").append(indexAtt).append("\">").append(first).append("</first>");
builder.append("<last>").append(last).append("</last>");
builder.append("<count>").append(count).append("</count>");
builder.append("</set>");
return builder.toString();
}
}
}
我只是使用这个类,在连接 Xmpp 连接后立即调用 ServiceProviders.Register_Providers(ProviderManager.getInstance());。
服务提供商:
public class ServiceProviders
{
public static void Register_Providers(ProviderManager pm)
{
Log.e("PROVIDER", "START");
// 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());
pm.addIQProvider("query", "http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());
pm.addExtensionProvider("x", "jabber:x:data", new DataFormProvider());
// archive
pm.addIQProvider("list", "urn:xmpp:archive", new ListIQProvider());
pm.addIQProvider("chat", "urn:xmpp:archive", new ChatIQProvider());
}
}
@HirenPatel
首先,您需要将归档插件 添加到Openfire。 然后在客户端中的Xmpp 连接之后,您必须注册您的提供商,包括帮助检索聊天消息的提供商:
pm.addIQProvider("list", "urn:xmpp:archive", new ListIQProvider());
pm.addIQProvider("chat", "urn:xmpp:archive", new ChatIQProvider());
然后您需要发送一个 IQ 节,如下所示:
final IQ iq = new IQ()
{
@Override public String getChildElementXML()
{
return "<retrieve xmlns='urn:xmpp:archive' with='test@customOpenfire.com'><set xmlns='http://jabber.org/protocol/rsm'><max xmlns='http://jabber.org/protocol/rsm'>30</max></set> </retrieve>";
}
};
iq.setType(IQ.Type.GET);
iq.setPacketID("987654321");
xmppConnection.sendPacket(iq);
关于android - 无法识别 IQ Custom 提供商,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22895874/
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳
我在pry中定义了一个函数:to_s,但我无法调用它。这个方法去哪里了,怎么调用?pry(main)>defto_spry(main)*'hello'pry(main)*endpry(main)>to_s=>"main"我的ruby版本是2.1.2看了一些答案和搜索后,我认为我得到了正确的答案:这个方法用在什么地方?在irb或pry中定义方法时,会转到Object.instance_methods[1]pry(main)>defto_s[1]pry(main)*'hello'[1]pry(main)*end=>:to_s[2]pry(main)>defhello[2]pry(main)
我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类
当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub
GivenIamadumbprogrammerandIamusingrspecandIamusingsporkandIwanttodebug...mmm...let'ssaaay,aspecforPhone.那么,我应该把“require'ruby-debug'”行放在哪里,以便在phone_spec.rb的特定点停止处理?(我所要求的只是一个大而粗的箭头,即使是一个有挑战性的程序员也能看到:-3)我已经尝试了很多位置,除非我没有正确测试它们,否则会发生一些奇怪的事情:在spec_helper.rb中的以下位置:require'rubygems'require'spork'
我正在学习http://ruby.railstutorial.org/chapters/static-pages上的RubyonRails教程并遇到以下错误StaticPagesHomepageshouldhavethecontent'SampleApp'Failure/Error:page.shouldhave_content('SampleApp')Capybara::ElementNotFound:Unabletofindxpath"/html"#(eval):2:in`text'#./spec/requests/static_pages_spec.rb:7:in`(root)'