MessageParser.java

  1package eu.siacs.conversations.parser;
  2
  3import net.java.otr4j.session.Session;
  4import net.java.otr4j.session.SessionStatus;
  5
  6import eu.siacs.conversations.entities.Account;
  7import eu.siacs.conversations.entities.Contact;
  8import eu.siacs.conversations.entities.Conversation;
  9import eu.siacs.conversations.entities.Message;
 10import eu.siacs.conversations.entities.MucOptions;
 11import eu.siacs.conversations.http.HttpConnectionManager;
 12import eu.siacs.conversations.services.MessageArchiveService;
 13import eu.siacs.conversations.services.XmppConnectionService;
 14import eu.siacs.conversations.utils.CryptoHelper;
 15import eu.siacs.conversations.xml.Element;
 16import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
 17import eu.siacs.conversations.xmpp.chatstate.ChatState;
 18import eu.siacs.conversations.xmpp.jid.Jid;
 19import eu.siacs.conversations.xmpp.pep.Avatar;
 20import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
 21
 22public class MessageParser extends AbstractParser implements
 23		OnMessagePacketReceived {
 24	public MessageParser(XmppConnectionService service) {
 25		super(service);
 26	}
 27
 28	private boolean extractChatState(Conversation conversation, final Element element) {
 29		ChatState state = ChatState.parse(element);
 30		if (state != null && conversation != null) {
 31			final Account account = conversation.getAccount();
 32			Jid from = element.getAttributeAsJid("from");
 33			if (from != null && from.toBareJid().equals(account.getJid().toBareJid())) {
 34				conversation.setOutgoingChatState(state);
 35				return false;
 36			} else {
 37				return conversation.setIncomingChatState(state);
 38			}
 39		}
 40		return false;
 41	}
 42
 43	private Message parseChat(MessagePacket packet, Account account) {
 44		final Jid jid = packet.getFrom();
 45		if (jid == null) {
 46			return null;
 47		}
 48		Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, jid.toBareJid(), false);
 49		String pgpBody = getPgpBody(packet);
 50		Message finishedMessage;
 51		if (pgpBody != null) {
 52			finishedMessage = new Message(conversation,
 53					pgpBody, Message.ENCRYPTION_PGP, Message.STATUS_RECEIVED);
 54		} else {
 55			finishedMessage = new Message(conversation,
 56					packet.getBody(), Message.ENCRYPTION_NONE,
 57					Message.STATUS_RECEIVED);
 58		}
 59		finishedMessage.setRemoteMsgId(packet.getId());
 60		finishedMessage.markable = isMarkable(packet);
 61		if (conversation.getMode() == Conversation.MODE_MULTI
 62				&& !jid.isBareJid()) {
 63			final Jid trueCounterpart = conversation.getMucOptions()
 64					.getTrueCounterpart(jid.getResourcepart());
 65			if (trueCounterpart != null) {
 66				updateLastseen(packet, account, trueCounterpart, false);
 67			}
 68			finishedMessage.setType(Message.TYPE_PRIVATE);
 69			finishedMessage.setTrueCounterpart(trueCounterpart);
 70			if (conversation.hasDuplicateMessage(finishedMessage)) {
 71				return null;
 72			}
 73		} else {
 74			updateLastseen(packet, account, true);
 75		}
 76		finishedMessage.setCounterpart(jid);
 77		finishedMessage.setTime(getTimestamp(packet));
 78		extractChatState(conversation,packet);
 79		return finishedMessage;
 80	}
 81
 82	private Message parseOtrChat(MessagePacket packet, Account account) {
 83		final Jid to = packet.getTo();
 84		final Jid from = packet.getFrom();
 85		if (to == null || from == null) {
 86			return null;
 87		}
 88		boolean properlyAddressed = !to.isBareJid() || account.countPresences() == 1;
 89		Conversation conversation = mXmppConnectionService
 90				.findOrCreateConversation(account, from.toBareJid(), false);
 91		String presence;
 92		if (from.isBareJid()) {
 93			presence = "";
 94		} else {
 95			presence = from.getResourcepart();
 96		}
 97		extractChatState(conversation, packet);
 98		updateLastseen(packet, account, true);
 99		String body = packet.getBody();
100		if (body.matches("^\\?OTRv\\d{1,2}\\?.*")) {
101			conversation.endOtrIfNeeded();
102		}
103		if (!conversation.hasValidOtrSession()) {
104			if (properlyAddressed) {
105				conversation.startOtrSession(presence,false);
106			} else {
107				return null;
108			}
109		} else {
110			String foreignPresence = conversation.getOtrSession()
111					.getSessionID().getUserID();
112			if (!foreignPresence.equals(presence)) {
113				conversation.endOtrIfNeeded();
114				if (properlyAddressed) {
115					conversation.startOtrSession(presence, false);
116				} else {
117					return null;
118				}
119			}
120		}
121		try {
122			conversation.setLastReceivedOtrMessageId(packet.getId());
123			Session otrSession = conversation.getOtrSession();
124			SessionStatus before = otrSession.getSessionStatus();
125			body = otrSession.transformReceiving(body);
126			SessionStatus after = otrSession.getSessionStatus();
127			if ((before != after) && (after == SessionStatus.ENCRYPTED)) {
128				conversation.setNextEncryption(Message.ENCRYPTION_OTR);
129				mXmppConnectionService.onOtrSessionEstablished(conversation);
130			} else if ((before != after) && (after == SessionStatus.FINISHED)) {
131				conversation.setNextEncryption(Message.ENCRYPTION_NONE);
132				conversation.resetOtrSession();
133				mXmppConnectionService.updateConversationUi();
134			}
135			if ((body == null) || (body.isEmpty())) {
136				return null;
137			}
138			if (body.startsWith(CryptoHelper.FILETRANSFER)) {
139				String key = body.substring(CryptoHelper.FILETRANSFER.length());
140				conversation.setSymmetricKey(CryptoHelper.hexToBytes(key));
141				return null;
142			}
143			Message finishedMessage = new Message(conversation, body, Message.ENCRYPTION_OTR,
144					Message.STATUS_RECEIVED);
145			finishedMessage.setTime(getTimestamp(packet));
146			finishedMessage.setRemoteMsgId(packet.getId());
147			finishedMessage.markable = isMarkable(packet);
148			finishedMessage.setCounterpart(from);
149			conversation.setLastReceivedOtrMessageId(null);
150			return finishedMessage;
151		} catch (Exception e) {
152			conversation.resetOtrSession();
153			return null;
154		}
155	}
156
157	private Message parseGroupchat(MessagePacket packet, Account account) {
158		int status;
159		final Jid from = packet.getFrom();
160		if (from == null) {
161			return null;
162		}
163		if (mXmppConnectionService.find(account.pendingConferenceLeaves,
164				account, from.toBareJid()) != null) {
165			return null;
166		}
167		Conversation conversation = mXmppConnectionService
168				.findOrCreateConversation(account, from.toBareJid(), true);
169		final Jid trueCounterpart = conversation.getMucOptions().getTrueCounterpart(from.getResourcepart());
170		if (trueCounterpart != null) {
171			updateLastseen(packet, account, trueCounterpart, false);
172		}
173		if (packet.hasChild("subject")) {
174			conversation.setHasMessagesLeftOnServer(true);
175			conversation.getMucOptions().setSubject(packet.findChild("subject").getContent());
176			mXmppConnectionService.updateConversationUi();
177			return null;
178		}
179
180		final Element x = packet.findChild("x", "http://jabber.org/protocol/muc#user");
181		if (from.isBareJid() && (x == null || !x.hasChild("status"))) {
182			return null;
183		} else if (from.isBareJid() && x.hasChild("status")) {
184			for(Element child : x.getChildren()) {
185				if (child.getName().equals("status")) {
186					String code = child.getAttribute("code");
187					if (code.contains(MucOptions.STATUS_CODE_ROOM_CONFIG_CHANGED)) {
188						mXmppConnectionService.fetchConferenceConfiguration(conversation);
189					}
190				}
191			}
192			return null;
193		}
194
195		if (from.getResourcepart().equals(conversation.getMucOptions().getActualNick())) {
196			if (mXmppConnectionService.markMessage(conversation,
197					packet.getId(), Message.STATUS_SEND_RECEIVED)) {
198				return null;
199			} else if (packet.getId() == null) {
200				Message message = conversation.findSentMessageWithBody(packet.getBody());
201				if (message != null) {
202					mXmppConnectionService.markMessage(message,Message.STATUS_SEND_RECEIVED);
203					return null;
204				} else {
205					status = Message.STATUS_SEND;
206				}
207			} else {
208				status = Message.STATUS_SEND;
209			}
210		} else {
211			status = Message.STATUS_RECEIVED;
212		}
213		String pgpBody = getPgpBody(packet);
214		Message finishedMessage;
215		if (pgpBody == null) {
216			finishedMessage = new Message(conversation,
217					packet.getBody(), Message.ENCRYPTION_NONE, status);
218		} else {
219			finishedMessage = new Message(conversation, pgpBody,
220					Message.ENCRYPTION_PGP, status);
221		}
222		finishedMessage.setRemoteMsgId(packet.getId());
223		finishedMessage.markable = isMarkable(packet);
224		finishedMessage.setCounterpart(from);
225		if (status == Message.STATUS_RECEIVED) {
226			finishedMessage.setTrueCounterpart(conversation.getMucOptions()
227					.getTrueCounterpart(from.getResourcepart()));
228		}
229		if (packet.hasChild("delay")
230				&& conversation.hasDuplicateMessage(finishedMessage)) {
231			return null;
232		}
233		finishedMessage.setTime(getTimestamp(packet));
234		return finishedMessage;
235	}
236
237	private Message parseCarbonMessage(final MessagePacket packet, final Account account) {
238		int status;
239		final Jid fullJid;
240		Element forwarded;
241		if (packet.hasChild("received", "urn:xmpp:carbons:2")) {
242			forwarded = packet.findChild("received", "urn:xmpp:carbons:2")
243					.findChild("forwarded", "urn:xmpp:forward:0");
244			status = Message.STATUS_RECEIVED;
245		} else if (packet.hasChild("sent", "urn:xmpp:carbons:2")) {
246			forwarded = packet.findChild("sent", "urn:xmpp:carbons:2")
247					.findChild("forwarded", "urn:xmpp:forward:0");
248			status = Message.STATUS_SEND;
249		} else {
250			return null;
251		}
252		if (forwarded == null) {
253			return null;
254		}
255		Element message = forwarded.findChild("message");
256		if (message == null) {
257			return null;
258		}
259		if (!message.hasChild("body")) {
260			if (status == Message.STATUS_RECEIVED
261					&& message.getAttribute("from") != null) {
262				parseNonMessage(message, account);
263			} else if (status == Message.STATUS_SEND
264					&& message.hasChild("displayed", "urn:xmpp:chat-markers:0")) {
265				final Jid to = message.getAttributeAsJid("to");
266				if (to != null) {
267					final Conversation conversation = mXmppConnectionService.find(
268							mXmppConnectionService.getConversations(), account,
269							to.toBareJid());
270					if (conversation != null) {
271						mXmppConnectionService.markRead(conversation);
272					}
273				}
274			}
275			return null;
276		}
277		if (status == Message.STATUS_RECEIVED) {
278			fullJid = message.getAttributeAsJid("from");
279			if (fullJid == null) {
280				return null;
281			} else {
282				updateLastseen(message, account, true);
283			}
284		} else {
285			fullJid = message.getAttributeAsJid("to");
286			if (fullJid == null) {
287				return null;
288			}
289		}
290		if (message.hasChild("x","http://jabber.org/protocol/muc#user")
291				&& "chat".equals(message.getAttribute("type"))) {
292			return null;
293		}
294		Conversation conversation = mXmppConnectionService
295				.findOrCreateConversation(account, fullJid.toBareJid(), false);
296		String pgpBody = getPgpBody(message);
297		Message finishedMessage;
298		if (pgpBody != null) {
299			finishedMessage = new Message(conversation, pgpBody,
300					Message.ENCRYPTION_PGP, status);
301		} else {
302			String body = message.findChild("body").getContent();
303			finishedMessage = new Message(conversation, body,
304					Message.ENCRYPTION_NONE, status);
305		}
306		extractChatState(conversation,message);
307		finishedMessage.setTime(getTimestamp(message));
308		finishedMessage.setRemoteMsgId(message.getAttribute("id"));
309		finishedMessage.markable = isMarkable(message);
310		finishedMessage.setCounterpart(fullJid);
311		if (conversation.getMode() == Conversation.MODE_MULTI
312				&& !fullJid.isBareJid()) {
313			finishedMessage.setType(Message.TYPE_PRIVATE);
314			finishedMessage.setTrueCounterpart(conversation.getMucOptions()
315					.getTrueCounterpart(fullJid.getResourcepart()));
316			if (conversation.hasDuplicateMessage(finishedMessage)) {
317				return null;
318			}
319		}
320		return finishedMessage;
321	}
322
323	private Message parseMamMessage(MessagePacket packet, final Account account) {
324		final Element result = packet.findChild("result","urn:xmpp:mam:0");
325		if (result == null ) {
326			return null;
327		}
328		final MessageArchiveService.Query query = this.mXmppConnectionService.getMessageArchiveService().findQuery(result.getAttribute("queryid"));
329		if (query!=null) {
330			query.incrementTotalCount();
331		}
332		final Element forwarded = result.findChild("forwarded","urn:xmpp:forward:0");
333		if (forwarded == null) {
334			return null;
335		}
336		final Element message = forwarded.findChild("message");
337		if (message == null) {
338			return null;
339		}
340		final Element body = message.findChild("body");
341		if (body == null || message.hasChild("private","urn:xmpp:carbons:2") || message.hasChild("no-copy","urn:xmpp:hints")) {
342			return null;
343		}
344		int encryption;
345		String content = getPgpBody(message);
346		if (content != null) {
347			encryption = Message.ENCRYPTION_PGP;
348		} else {
349			encryption = Message.ENCRYPTION_NONE;
350			content = body.getContent();
351		}
352		if (content == null) {
353			return null;
354		}
355		final long timestamp = getTimestamp(forwarded);
356		final Jid to = message.getAttributeAsJid("to");
357		final Jid from = message.getAttributeAsJid("from");
358		Jid counterpart;
359		int status;
360		Conversation conversation;
361		if (from!=null && to != null && from.toBareJid().equals(account.getJid().toBareJid())) {
362			status = Message.STATUS_SEND;
363			conversation = this.mXmppConnectionService.findOrCreateConversation(account,to.toBareJid(),false,query);
364			counterpart = to;
365		} else if (from !=null && to != null) {
366			status = Message.STATUS_RECEIVED;
367			conversation = this.mXmppConnectionService.findOrCreateConversation(account,from.toBareJid(),false,query);
368			counterpart = from;
369		} else {
370			return null;
371		}
372		Message finishedMessage = new Message(conversation,content,encryption,status);
373		finishedMessage.setTime(timestamp);
374		finishedMessage.setCounterpart(counterpart);
375		finishedMessage.setRemoteMsgId(message.getAttribute("id"));
376		finishedMessage.setServerMsgId(result.getAttribute("id"));
377		if (conversation.hasDuplicateMessage(finishedMessage)) {
378			return null;
379		}
380		if (query!=null) {
381			query.incrementMessageCount();
382		}
383		return finishedMessage;
384	}
385
386	private void parseError(final MessagePacket packet, final Account account) {
387		final Jid from = packet.getFrom();
388		mXmppConnectionService.markMessage(account, from.toBareJid(),
389				packet.getId(), Message.STATUS_SEND_FAILED);
390	}
391
392	private void parseNonMessage(Element packet, Account account) {
393		final Jid from = packet.getAttributeAsJid("from");
394		if (account.getJid().equals(from)) {
395			return;
396		}
397		if (extractChatState(from == null ? null : mXmppConnectionService.find(account,from), packet)) {
398			mXmppConnectionService.updateConversationUi();
399		}
400		Invite invite = extractInvite(packet);
401		if (invite != null && invite.jid != null) {
402			Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, invite.jid, true);
403			if (!conversation.getMucOptions().online()) {
404				conversation.getMucOptions().setPassword(invite.password);
405				mXmppConnectionService.databaseBackend.updateConversation(conversation);
406				mXmppConnectionService.joinMuc(conversation);
407				mXmppConnectionService.updateConversationUi();
408			}
409		}
410		if (packet.hasChild("event", "http://jabber.org/protocol/pubsub#event")) {
411			Element event = packet.findChild("event",
412					"http://jabber.org/protocol/pubsub#event");
413			parseEvent(event, from, account);
414		} else if (from != null && packet.hasChild("displayed", "urn:xmpp:chat-markers:0")) {
415			String id = packet
416					.findChild("displayed", "urn:xmpp:chat-markers:0")
417					.getAttribute("id");
418			updateLastseen(packet, account, true);
419			final Message displayedMessage = mXmppConnectionService.markMessage(account, from.toBareJid(), id, Message.STATUS_SEND_DISPLAYED);
420			Message message = displayedMessage == null ? null :displayedMessage.prev();
421			while (message != null
422					&& message.getStatus() == Message.STATUS_SEND_RECEIVED
423					&& message.getTimeSent() < displayedMessage.getTimeSent()) {
424				mXmppConnectionService.markMessage(message, Message.STATUS_SEND_DISPLAYED);
425				message = message.prev();
426			}
427		} else if (from != null
428				&& packet.hasChild("received", "urn:xmpp:chat-markers:0")) {
429			String id = packet.findChild("received", "urn:xmpp:chat-markers:0")
430					.getAttribute("id");
431			updateLastseen(packet, account, false);
432			mXmppConnectionService.markMessage(account, from.toBareJid(),
433					id, Message.STATUS_SEND_RECEIVED);
434		} else if (from != null
435				&& packet.hasChild("received", "urn:xmpp:receipts")) {
436			String id = packet.findChild("received", "urn:xmpp:receipts")
437					.getAttribute("id");
438			updateLastseen(packet, account, false);
439			mXmppConnectionService.markMessage(account, from.toBareJid(),
440					id, Message.STATUS_SEND_RECEIVED);
441		}
442	}
443
444	private class Invite {
445		Jid jid;
446		String password;
447		Invite(Jid jid, String password) {
448			this.jid = jid;
449			this.password = password;
450		}
451	}
452
453	private Invite extractInvite(Element message) {
454		Element x = message.findChild("x","http://jabber.org/protocol/muc#user");
455		if (x != null) {
456			Element invite = x.findChild("invite");
457			if (invite != null) {
458				Element pw = x.findChild("password");
459				return new Invite(message.getAttributeAsJid("from"), pw != null ? pw.getContent(): null);
460			}
461		} else {
462			x = message.findChild("x","jabber:x:conference");
463			if (x != null) {
464				return new Invite(x.getAttributeAsJid("jid"),x.getAttribute("password"));
465			}
466		}
467		return null;
468	}
469
470	private void parseEvent(final Element event, final Jid from, final Account account) {
471		Element items = event.findChild("items");
472		if (items == null) {
473			return;
474		}
475		String node = items.getAttribute("node");
476		if (node == null) {
477			return;
478		}
479		if (node.equals("urn:xmpp:avatar:metadata")) {
480			Avatar avatar = Avatar.parseMetadata(items);
481			if (avatar != null) {
482				avatar.owner = from;
483				if (mXmppConnectionService.getFileBackend().isAvatarCached(
484						avatar)) {
485					if (account.getJid().toBareJid().equals(from)) {
486						if (account.setAvatar(avatar.getFilename())) {
487							mXmppConnectionService.databaseBackend
488									.updateAccount(account);
489						}
490						mXmppConnectionService.getAvatarService().clear(
491								account);
492						mXmppConnectionService.updateConversationUi();
493						mXmppConnectionService.updateAccountUi();
494					} else {
495						Contact contact = account.getRoster().getContact(
496								from);
497						contact.setAvatar(avatar);
498						mXmppConnectionService.getAvatarService().clear(
499								contact);
500						mXmppConnectionService.updateConversationUi();
501						mXmppConnectionService.updateRosterUi();
502					}
503				} else {
504					mXmppConnectionService.fetchAvatar(account, avatar);
505				}
506			}
507		} else if (node.equals("http://jabber.org/protocol/nick")) {
508			Element item = items.findChild("item");
509			if (item != null) {
510				Element nick = item.findChild("nick",
511						"http://jabber.org/protocol/nick");
512				if (nick != null) {
513					if (from != null) {
514						Contact contact = account.getRoster().getContact(
515								from);
516						contact.setPresenceName(nick.getContent());
517						mXmppConnectionService.getAvatarService().clear(account);
518						mXmppConnectionService.updateConversationUi();
519						mXmppConnectionService.updateAccountUi();
520					}
521				}
522			}
523		}
524	}
525
526	private String getPgpBody(Element message) {
527		Element child = message.findChild("x", "jabber:x:encrypted");
528		if (child == null) {
529			return null;
530		} else {
531			return child.getContent();
532		}
533	}
534
535	private boolean isMarkable(Element message) {
536		return message.hasChild("markable", "urn:xmpp:chat-markers:0");
537	}
538
539	@Override
540	public void onMessagePacketReceived(Account account, MessagePacket packet) {
541		Message message = null;
542		this.parseNick(packet, account);
543		if ((packet.getType() == MessagePacket.TYPE_CHAT || packet.getType() == MessagePacket.TYPE_NORMAL)) {
544			if ((packet.getBody() != null)
545					&& (packet.getBody().startsWith("?OTR"))) {
546				message = this.parseOtrChat(packet, account);
547				if (message != null) {
548					message.markUnread();
549				}
550			} else if (packet.hasChild("body") && extractInvite(packet) == null) {
551				message = this.parseChat(packet, account);
552				if (message != null) {
553					message.markUnread();
554				}
555			} else if (packet.hasChild("received", "urn:xmpp:carbons:2")
556					|| (packet.hasChild("sent", "urn:xmpp:carbons:2"))) {
557				message = this.parseCarbonMessage(packet, account);
558				if (message != null) {
559					if (message.getStatus() == Message.STATUS_SEND) {
560						account.activateGracePeriod();
561						mXmppConnectionService.markRead(message.getConversation());
562					} else {
563						message.markUnread();
564					}
565				}
566			} else if (packet.hasChild("result","urn:xmpp:mam:0")) {
567				message = parseMamMessage(packet, account);
568				if (message != null) {
569					Conversation conversation = message.getConversation();
570					conversation.add(message);
571					mXmppConnectionService.databaseBackend.createMessage(message);
572				}
573				return;
574			} else if (packet.hasChild("fin","urn:xmpp:mam:0")) {
575				Element fin = packet.findChild("fin","urn:xmpp:mam:0");
576				mXmppConnectionService.getMessageArchiveService().processFin(fin);
577			} else {
578				parseNonMessage(packet, account);
579			}
580		} else if (packet.getType() == MessagePacket.TYPE_GROUPCHAT) {
581			message = this.parseGroupchat(packet, account);
582			if (message != null) {
583				if (message.getStatus() == Message.STATUS_RECEIVED) {
584					message.markUnread();
585				} else {
586					mXmppConnectionService.markRead(message.getConversation());
587					account.activateGracePeriod();
588				}
589			}
590		} else if (packet.getType() == MessagePacket.TYPE_ERROR) {
591			this.parseError(packet, account);
592			return;
593		} else if (packet.getType() == MessagePacket.TYPE_HEADLINE) {
594			this.parseHeadline(packet, account);
595			return;
596		}
597		if ((message == null) || (message.getBody() == null)) {
598			return;
599		}
600		if ((mXmppConnectionService.confirmMessages())
601				&& ((packet.getId() != null))) {
602			if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) {
603				MessagePacket receipt = mXmppConnectionService
604						.getMessageGenerator().received(account, packet,
605								"urn:xmpp:chat-markers:0");
606				mXmppConnectionService.sendMessagePacket(account, receipt);
607			}
608			if (packet.hasChild("request", "urn:xmpp:receipts")) {
609				MessagePacket receipt = mXmppConnectionService
610						.getMessageGenerator().received(account, packet,
611								"urn:xmpp:receipts");
612				mXmppConnectionService.sendMessagePacket(account, receipt);
613			}
614		}
615		Conversation conversation = message.getConversation();
616		conversation.add(message);
617		if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().advancedStreamFeaturesLoaded()) {
618			if (conversation.setLastMessageTransmitted(System.currentTimeMillis())) {
619				mXmppConnectionService.updateConversation(conversation);
620			}
621		}
622
623		if (message.getStatus() == Message.STATUS_RECEIVED
624				&& conversation.getOtrSession() != null
625				&& !conversation.getOtrSession().getSessionID().getUserID()
626				.equals(message.getCounterpart().getResourcepart())) {
627			conversation.endOtrIfNeeded();
628		}
629
630		if (packet.getType() != MessagePacket.TYPE_ERROR) {
631			if (message.getEncryption() == Message.ENCRYPTION_NONE
632					|| mXmppConnectionService.saveEncryptedMessages()) {
633				mXmppConnectionService.databaseBackend.createMessage(message);
634			}
635		}
636		final HttpConnectionManager manager = this.mXmppConnectionService.getHttpConnectionManager();
637		if (message.trusted() && message.bodyContainsDownloadable() && manager.getAutoAcceptFileSize() > 0) {
638			manager.createNewConnection(message);
639		} else if (!message.isRead()) {
640			mXmppConnectionService.getNotificationService().push(message);
641		}
642		mXmppConnectionService.updateConversationUi();
643	}
644
645	private void parseHeadline(MessagePacket packet, Account account) {
646		if (packet.hasChild("event", "http://jabber.org/protocol/pubsub#event")) {
647			Element event = packet.findChild("event",
648					"http://jabber.org/protocol/pubsub#event");
649			parseEvent(event, packet.getFrom(), account);
650		}
651	}
652
653	private void parseNick(MessagePacket packet, Account account) {
654		Element nick = packet.findChild("nick",
655				"http://jabber.org/protocol/nick");
656		if (nick != null) {
657			if (packet.getFrom() != null) {
658				Contact contact = account.getRoster().getContact(
659						packet.getFrom());
660				contact.setPresenceName(nick.getContent());
661			}
662		}
663	}
664}