MessageParser.java

  1package eu.siacs.conversations.parser;
  2
  3import java.util.List;
  4
  5import net.java.otr4j.session.Session;
  6import net.java.otr4j.session.SessionStatus;
  7import android.util.Log;
  8import eu.siacs.conversations.entities.Account;
  9import eu.siacs.conversations.entities.Conversation;
 10import eu.siacs.conversations.entities.Message;
 11import eu.siacs.conversations.services.XmppConnectionService;
 12import eu.siacs.conversations.xml.Element;
 13import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
 14
 15public class MessageParser {
 16
 17	protected static final String LOGTAG = "xmppService";
 18	private XmppConnectionService mXmppConnectionService;
 19
 20	public MessageParser(XmppConnectionService service) {
 21		this.mXmppConnectionService = service;
 22	}
 23
 24	public Message parseChat(MessagePacket packet, Account account) {
 25		String[] fromParts = packet.getFrom().split("/");
 26		Conversation conversation = mXmppConnectionService
 27				.findOrCreateConversation(account, fromParts[0], false);
 28		String pgpBody = getPgpBody(packet);
 29		if (pgpBody != null) {
 30			return new Message(conversation, packet.getFrom(), pgpBody,
 31					Message.ENCRYPTION_PGP, Message.STATUS_RECIEVED);
 32		} else {
 33			return new Message(conversation, packet.getFrom(),
 34					packet.getBody(), Message.ENCRYPTION_NONE,
 35					Message.STATUS_RECIEVED);
 36		}
 37	}
 38
 39	public Message parseOtrChat(MessagePacket packet, Account account) {
 40		boolean properlyAddressed = (packet.getTo().split("/").length == 2)
 41				|| (account.countPresences() == 1);
 42		String[] fromParts = packet.getFrom().split("/");
 43		Conversation conversation = mXmppConnectionService
 44				.findOrCreateConversation(account, fromParts[0], false);
 45		String body = packet.getBody();
 46		if (!conversation.hasValidOtrSession()) {
 47			if (properlyAddressed) {
 48				Log.d("xmppService",
 49						"starting new otr session with "
 50								+ packet.getFrom()
 51								+ " because no valid otr session has been found");
 52				conversation.startOtrSession(
 53						mXmppConnectionService.getApplicationContext(),
 54						fromParts[1], false);
 55			} else {
 56				Log.d("xmppService", account.getJid()
 57						+ ": ignoring otr session with " + fromParts[0]);
 58				return null;
 59			}
 60		} else {
 61			String foreignPresence = conversation.getOtrSession()
 62					.getSessionID().getUserID();
 63			if (!foreignPresence.equals(fromParts[1])) {
 64				conversation.resetOtrSession();
 65				if (properlyAddressed) {
 66					Log.d("xmppService",
 67							"replacing otr session with " + packet.getFrom());
 68					conversation.startOtrSession(
 69							mXmppConnectionService.getApplicationContext(),
 70							fromParts[1], false);
 71				} else {
 72					return null;
 73				}
 74			}
 75		}
 76		try {
 77			Session otrSession = conversation.getOtrSession();
 78			SessionStatus before = otrSession.getSessionStatus();
 79			body = otrSession.transformReceiving(body);
 80			SessionStatus after = otrSession.getSessionStatus();
 81			if ((before != after) && (after == SessionStatus.ENCRYPTED)) {
 82				Log.d(LOGTAG, "otr session etablished");
 83				List<Message> messages = conversation.getMessages();
 84				for (int i = 0; i < messages.size(); ++i) {
 85					Message msg = messages.get(i);
 86					if ((msg.getStatus() == Message.STATUS_UNSEND)
 87							&& (msg.getEncryption() == Message.ENCRYPTION_OTR)) {
 88						MessagePacket outPacket = mXmppConnectionService
 89								.prepareMessagePacket(account, msg, otrSession);
 90						msg.setStatus(Message.STATUS_SEND);
 91						mXmppConnectionService.databaseBackend
 92								.updateMessage(msg);
 93						account.getXmppConnection()
 94								.sendMessagePacket(outPacket);
 95					}
 96				}
 97				mXmppConnectionService.updateUi(conversation, false);
 98			} else if ((before != after) && (after == SessionStatus.FINISHED)) {
 99				conversation.resetOtrSession();
100				Log.d(LOGTAG, "otr session stoped");
101			}
102			// isEmpty is a work around for some weird clients which send emtpty
103			// strings over otr
104			if ((body == null) || (body.isEmpty())) {
105				return null;
106			}
107			return new Message(conversation, packet.getFrom(), body,
108					Message.ENCRYPTION_OTR, Message.STATUS_RECIEVED);
109		} catch (Exception e) {
110			conversation.resetOtrSession();
111			return null;
112		}
113	}
114
115	public Message parseGroupchat(MessagePacket packet, Account account) {
116		int status;
117		String[] fromParts = packet.getFrom().split("/");
118		Conversation conversation = mXmppConnectionService
119				.findOrCreateConversation(account, fromParts[0], true);
120		if (packet.hasChild("subject")) {
121			conversation.getMucOptions().setSubject(
122					packet.findChild("subject").getContent());
123			mXmppConnectionService.updateUi(conversation, false);
124			return null;
125		}
126		if ((fromParts.length == 1)) {
127			return null;
128		}
129		String counterPart = fromParts[1];
130		if (counterPart.equals(conversation.getMucOptions().getNick())) {
131			if (mXmppConnectionService.markMessage(conversation,
132					packet.getId(), Message.STATUS_SEND)) {
133				return null;
134			} else {
135				status = Message.STATUS_SEND;
136			}
137		} else {
138			status = Message.STATUS_RECIEVED;
139		}
140		String pgpBody = getPgpBody(packet);
141		if (pgpBody == null) {
142			return new Message(conversation, counterPart, packet.getBody(),
143					Message.ENCRYPTION_NONE, status);
144		} else {
145			return new Message(conversation, counterPart, pgpBody,
146					Message.ENCRYPTION_PGP, status);
147		}
148	}
149
150	public Message parseCarbonMessage(MessagePacket packet, Account account) {
151		int status;
152		String fullJid;
153		Element forwarded;
154		if (packet.hasChild("received")) {
155			forwarded = packet.findChild("received").findChild("forwarded");
156			status = Message.STATUS_RECIEVED;
157		} else if (packet.hasChild("sent")) {
158			forwarded = packet.findChild("sent").findChild("forwarded");
159			status = Message.STATUS_SEND;
160		} else {
161			return null;
162		}
163		if (forwarded == null) {
164			return null;
165		}
166		Element message = forwarded.findChild("message");
167		if ((message == null) || (!message.hasChild("body")))
168			return null; // either malformed or boring
169		if (status == Message.STATUS_RECIEVED) {
170			fullJid = message.getAttribute("from");
171		} else {
172			fullJid = message.getAttribute("to");
173		}
174		String[] parts = fullJid.split("/");
175		Conversation conversation = mXmppConnectionService
176				.findOrCreateConversation(account, parts[0], false);
177		String pgpBody = getPgpBody(message);
178		if (pgpBody != null) {
179			return new Message(conversation, fullJid, pgpBody,
180					Message.ENCRYPTION_PGP, status);
181		} else {
182			String body = message.findChild("body").getContent();
183			return new Message(conversation, fullJid, body,
184					Message.ENCRYPTION_NONE, status);
185		}
186	}
187
188	public void parseError(MessagePacket packet, Account account) {
189		String[] fromParts = packet.getFrom().split("/");
190		mXmppConnectionService.markMessage(account, fromParts[0],
191				packet.getId(), Message.STATUS_SEND_FAILED);
192	}
193
194	private String getPgpBody(Element packet) {
195		Element child = packet.findChild("x", "jabber:x:encrypted");
196		if (child == null) {
197			return null;
198		} else {
199			return child.getContent();
200		}
201	}
202}