1package eu.siacs.conversations.generator;
2
3
4import android.util.Base64;
5
6import org.whispersystems.libaxolotl.IdentityKey;
7import org.whispersystems.libaxolotl.ecc.ECPublicKey;
8import org.whispersystems.libaxolotl.state.PreKeyRecord;
9import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
10
11import java.util.ArrayList;
12import java.util.List;
13import java.util.Set;
14
15import eu.siacs.conversations.crypto.axolotl.AxolotlService;
16import eu.siacs.conversations.entities.Account;
17import eu.siacs.conversations.entities.Conversation;
18import eu.siacs.conversations.entities.DownloadableFile;
19import eu.siacs.conversations.services.MessageArchiveService;
20import eu.siacs.conversations.services.XmppConnectionService;
21import eu.siacs.conversations.utils.PhoneHelper;
22import eu.siacs.conversations.utils.Xmlns;
23import eu.siacs.conversations.xml.Element;
24import eu.siacs.conversations.xmpp.forms.Data;
25import eu.siacs.conversations.xmpp.jid.Jid;
26import eu.siacs.conversations.xmpp.pep.Avatar;
27import eu.siacs.conversations.xmpp.stanzas.IqPacket;
28
29public class IqGenerator extends AbstractGenerator {
30
31 public IqGenerator(final XmppConnectionService service) {
32 super(service);
33 }
34
35 public IqPacket discoResponse(final IqPacket request) {
36 final IqPacket packet = new IqPacket(IqPacket.TYPE.RESULT);
37 packet.setId(request.getId());
38 packet.setTo(request.getFrom());
39 final Element query = packet.addChild("query",
40 "http://jabber.org/protocol/disco#info");
41 query.setAttribute("node", request.query().getAttribute("node"));
42 final Element identity = query.addChild("identity");
43 identity.setAttribute("category", "client");
44 identity.setAttribute("type", IDENTITY_TYPE);
45 identity.setAttribute("name", getIdentityName());
46 for (final String feature : getFeatures()) {
47 query.addChild("feature").setAttribute("var", feature);
48 }
49 return packet;
50 }
51
52 public IqPacket versionResponse(final IqPacket request) {
53 final IqPacket packet = request.generateResponse(IqPacket.TYPE.RESULT);
54 Element query = packet.query("jabber:iq:version");
55 query.addChild("name").setContent(IDENTITY_NAME);
56 query.addChild("version").setContent(getIdentityVersion());
57 return packet;
58 }
59
60 protected IqPacket publish(final String node, final Element item) {
61 final IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
62 final Element pubsub = packet.addChild("pubsub",
63 "http://jabber.org/protocol/pubsub");
64 final Element publish = pubsub.addChild("publish");
65 publish.setAttribute("node", node);
66 publish.addChild(item);
67 return packet;
68 }
69
70 protected IqPacket retrieve(String node, Element item) {
71 final IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
72 final Element pubsub = packet.addChild("pubsub",
73 "http://jabber.org/protocol/pubsub");
74 final Element items = pubsub.addChild("items");
75 items.setAttribute("node", node);
76 if (item != null) {
77 items.addChild(item);
78 }
79 return packet;
80 }
81
82 public IqPacket publishAvatar(Avatar avatar) {
83 final Element item = new Element("item");
84 item.setAttribute("id", avatar.sha1sum);
85 final Element data = item.addChild("data", "urn:xmpp:avatar:data");
86 data.setContent(avatar.image);
87 return publish("urn:xmpp:avatar:data", item);
88 }
89
90 public IqPacket publishAvatarMetadata(final Avatar avatar) {
91 final Element item = new Element("item");
92 item.setAttribute("id", avatar.sha1sum);
93 final Element metadata = item
94 .addChild("metadata", "urn:xmpp:avatar:metadata");
95 final Element info = metadata.addChild("info");
96 info.setAttribute("bytes", avatar.size);
97 info.setAttribute("id", avatar.sha1sum);
98 info.setAttribute("height", avatar.height);
99 info.setAttribute("width", avatar.height);
100 info.setAttribute("type", avatar.type);
101 return publish("urn:xmpp:avatar:metadata", item);
102 }
103
104 public IqPacket retrievePepAvatar(final Avatar avatar) {
105 final Element item = new Element("item");
106 item.setAttribute("id", avatar.sha1sum);
107 final IqPacket packet = retrieve("urn:xmpp:avatar:data", item);
108 packet.setTo(avatar.owner);
109 return packet;
110 }
111
112 public IqPacket retrieveVcardAvatar(final Avatar avatar) {
113 final IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
114 packet.setTo(avatar.owner);
115 packet.addChild("vCard", "vcard-temp");
116 return packet;
117 }
118
119 public IqPacket retrieveAvatarMetaData(final Jid to) {
120 final IqPacket packet = retrieve("urn:xmpp:avatar:metadata", null);
121 if (to != null) {
122 packet.setTo(to);
123 }
124 return packet;
125 }
126
127 public IqPacket retrieveDeviceIds(final Jid to) {
128 final IqPacket packet = retrieve(AxolotlService.PEP_DEVICE_LIST, null);
129 if(to != null) {
130 packet.setTo(to);
131 }
132 return packet;
133 }
134
135 public IqPacket retrieveBundlesForDevice(final Jid to, final int deviceid) {
136 final IqPacket packet = retrieve(AxolotlService.PEP_BUNDLES+":"+deviceid, null);
137 if(to != null) {
138 packet.setTo(to);
139 }
140 return packet;
141 }
142
143 public IqPacket publishDeviceIds(final Set<Integer> ids) {
144 final Element item = new Element("item");
145 final Element list = item.addChild("list", AxolotlService.PEP_PREFIX);
146 for(Integer id:ids) {
147 final Element device = new Element("device");
148 device.setAttribute("id", id);
149 list.addChild(device);
150 }
151 return publish(AxolotlService.PEP_DEVICE_LIST, item);
152 }
153
154 public IqPacket publishBundles(final SignedPreKeyRecord signedPreKeyRecord, final IdentityKey identityKey,
155 final Set<PreKeyRecord> preKeyRecords, final int deviceId) {
156 final Element item = new Element("item");
157 final Element bundle = item.addChild("bundle", AxolotlService.PEP_PREFIX);
158 final Element signedPreKeyPublic = bundle.addChild("signedPreKeyPublic");
159 signedPreKeyPublic.setAttribute("signedPreKeyId", signedPreKeyRecord.getId());
160 ECPublicKey publicKey = signedPreKeyRecord.getKeyPair().getPublicKey();
161 signedPreKeyPublic.setContent(Base64.encodeToString(publicKey.serialize(),Base64.DEFAULT));
162 final Element signedPreKeySignature = bundle.addChild("signedPreKeySignature");
163 signedPreKeySignature.setContent(Base64.encodeToString(signedPreKeyRecord.getSignature(),Base64.DEFAULT));
164 final Element identityKeyElement = bundle.addChild("identityKey");
165 identityKeyElement.setContent(Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT));
166
167 final Element prekeys = bundle.addChild("prekeys", AxolotlService.PEP_PREFIX);
168 for(PreKeyRecord preKeyRecord:preKeyRecords) {
169 final Element prekey = prekeys.addChild("preKeyPublic");
170 prekey.setAttribute("preKeyId", preKeyRecord.getId());
171 prekey.setContent(Base64.encodeToString(preKeyRecord.getKeyPair().getPublicKey().serialize(), Base64.DEFAULT));
172 }
173
174 return publish(AxolotlService.PEP_BUNDLES+":"+deviceId, item);
175 }
176
177 public IqPacket queryMessageArchiveManagement(final MessageArchiveService.Query mam) {
178 final IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
179 final Element query = packet.query("urn:xmpp:mam:0");
180 query.setAttribute("queryid",mam.getQueryId());
181 final Data data = new Data();
182 data.setFormType("urn:xmpp:mam:0");
183 if (mam.muc()) {
184 packet.setTo(mam.getWith());
185 } else if (mam.getWith()!=null) {
186 data.put("with", mam.getWith().toString());
187 }
188 data.put("start",getTimestamp(mam.getStart()));
189 data.put("end",getTimestamp(mam.getEnd()));
190 query.addChild(data);
191 if (mam.getPagingOrder() == MessageArchiveService.PagingOrder.REVERSE) {
192 query.addChild("set", "http://jabber.org/protocol/rsm").addChild("before").setContent(mam.getReference());
193 } else if (mam.getReference() != null) {
194 query.addChild("set", "http://jabber.org/protocol/rsm").addChild("after").setContent(mam.getReference());
195 }
196 return packet;
197 }
198 public IqPacket generateGetBlockList() {
199 final IqPacket iq = new IqPacket(IqPacket.TYPE.GET);
200 iq.addChild("blocklist", Xmlns.BLOCKING);
201
202 return iq;
203 }
204
205 public IqPacket generateSetBlockRequest(final Jid jid) {
206 final IqPacket iq = new IqPacket(IqPacket.TYPE.SET);
207 final Element block = iq.addChild("block", Xmlns.BLOCKING);
208 block.addChild("item").setAttribute("jid", jid.toBareJid().toString());
209 return iq;
210 }
211
212 public IqPacket generateSetUnblockRequest(final Jid jid) {
213 final IqPacket iq = new IqPacket(IqPacket.TYPE.SET);
214 final Element block = iq.addChild("unblock", Xmlns.BLOCKING);
215 block.addChild("item").setAttribute("jid", jid.toBareJid().toString());
216 return iq;
217 }
218
219 public IqPacket generateSetPassword(final Account account, final String newPassword) {
220 final IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
221 packet.setTo(account.getServer());
222 final Element query = packet.addChild("query", Xmlns.REGISTER);
223 final Jid jid = account.getJid();
224 query.addChild("username").setContent(jid.getLocalpart());
225 query.addChild("password").setContent(newPassword);
226 return packet;
227 }
228
229 public IqPacket changeAffiliation(Conversation conference, Jid jid, String affiliation) {
230 List<Jid> jids = new ArrayList<>();
231 jids.add(jid);
232 return changeAffiliation(conference,jids,affiliation);
233 }
234
235 public IqPacket changeAffiliation(Conversation conference, List<Jid> jids, String affiliation) {
236 IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
237 packet.setTo(conference.getJid().toBareJid());
238 packet.setFrom(conference.getAccount().getJid());
239 Element query = packet.query("http://jabber.org/protocol/muc#admin");
240 for(Jid jid : jids) {
241 Element item = query.addChild("item");
242 item.setAttribute("jid", jid.toString());
243 item.setAttribute("affiliation", affiliation);
244 }
245 return packet;
246 }
247
248 public IqPacket changeRole(Conversation conference, String nick, String role) {
249 IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
250 packet.setTo(conference.getJid().toBareJid());
251 packet.setFrom(conference.getAccount().getJid());
252 Element item = packet.query("http://jabber.org/protocol/muc#admin").addChild("item");
253 item.setAttribute("nick", nick);
254 item.setAttribute("role", role);
255 return packet;
256 }
257
258 public IqPacket requestHttpUploadSlot(Jid host, DownloadableFile file) {
259 IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
260 packet.setTo(host);
261 Element request = packet.addChild("request",Xmlns.HTTP_UPLOAD);
262 request.addChild("filename").setContent(file.getName());
263 request.addChild("size").setContent(String.valueOf(file.getExpectedSize()));
264 return packet;
265 }
266}