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 parsePlainTextChat(MessagePacket packet, Account account) {
25 String[] fromParts = packet.getFrom().split("/");
26 Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, fromParts[0],false);
27 String body = packet.getBody();
28 return new Message(conversation, packet.getFrom(), body, Message.ENCRYPTION_NONE, Message.STATUS_RECIEVED);
29 }
30
31 public Message parsePgpChat(String pgpBody, MessagePacket packet, Account account) {
32 String[] fromParts = packet.getFrom().split("/");
33 Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, fromParts[0],false);
34 return new Message(conversation, packet.getFrom(), pgpBody, Message.ENCRYPTION_PGP, Message.STATUS_RECIEVED);
35 }
36
37 public Message parseOtrChat(MessagePacket packet, Account account) {
38 boolean properlyAddressed = (packet.getTo().split("/").length == 2) || (account.countPresences() == 1);
39 String[] fromParts = packet.getFrom().split("/");
40 Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, fromParts[0],false);
41 String body = packet.getBody();
42 if (!conversation.hasValidOtrSession()) {
43 if (properlyAddressed) {
44 Log.d("xmppService","starting new otr session with "+packet.getFrom()+" because no valid otr session has been found");
45 conversation.startOtrSession(mXmppConnectionService.getApplicationContext(), fromParts[1],false);
46 } else {
47 Log.d("xmppService",account.getJid()+": ignoring otr session with "+fromParts[0]);
48 return null;
49 }
50 } else {
51 String foreignPresence = conversation.getOtrSession().getSessionID().getUserID();
52 if (!foreignPresence.equals(fromParts[1])) {
53 conversation.resetOtrSession();
54 if (properlyAddressed) {
55 Log.d("xmppService","replacing otr session with "+packet.getFrom());
56 conversation.startOtrSession(mXmppConnectionService.getApplicationContext(), fromParts[1],false);
57 } else {
58 return null;
59 }
60 }
61 }
62 try {
63 Session otrSession = conversation.getOtrSession();
64 SessionStatus before = otrSession
65 .getSessionStatus();
66 body = otrSession.transformReceiving(body);
67 SessionStatus after = otrSession.getSessionStatus();
68 if ((before != after)
69 && (after == SessionStatus.ENCRYPTED)) {
70 Log.d(LOGTAG, "otr session etablished");
71 List<Message> messages = conversation
72 .getMessages();
73 for (int i = 0; i < messages.size(); ++i) {
74 Message msg = messages.get(i);
75 if ((msg.getStatus() == Message.STATUS_UNSEND)
76 && (msg.getEncryption() == Message.ENCRYPTION_OTR)) {
77 MessagePacket outPacket = mXmppConnectionService.prepareMessagePacket(
78 account, msg, otrSession);
79 msg.setStatus(Message.STATUS_SEND);
80 mXmppConnectionService.databaseBackend.updateMessage(msg);
81 account.getXmppConnection()
82 .sendMessagePacket(outPacket);
83 }
84 }
85 mXmppConnectionService.updateUi(conversation, false);
86 } else if ((before != after) && (after == SessionStatus.FINISHED)) {
87 conversation.resetOtrSession();
88 Log.d(LOGTAG,"otr session stoped");
89 }
90 //isEmpty is a work around for some weird clients which send emtpty strings over otr
91 if ((body == null)||(body.isEmpty())) {
92 return null;
93 }
94 return new Message(conversation, packet.getFrom(), body, Message.ENCRYPTION_OTR,Message.STATUS_RECIEVED);
95 } catch (Exception e) {
96 conversation.resetOtrSession();
97 return null;
98 }
99 }
100
101 public Message parseGroupchat(MessagePacket packet, Account account) {
102 int status;
103 String[] fromParts = packet.getFrom().split("/");
104 Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, fromParts[0],true);
105 if (packet.hasChild("subject")) {
106 conversation.getMucOptions().setSubject(packet.findChild("subject").getContent());
107 mXmppConnectionService.updateUi(conversation, false);
108 return null;
109 }
110 if ((fromParts.length == 1)) {
111 return null;
112 }
113 String counterPart = fromParts[1];
114 if (counterPart.equals(conversation.getMucOptions().getNick())) {
115 if (mXmppConnectionService.markMessage(conversation, packet.getId(), Message.STATUS_SEND)) {
116 return null;
117 } else {
118 status = Message.STATUS_SEND;
119 }
120 } else {
121 status = Message.STATUS_RECIEVED;
122 }
123 String pgpBody = getPgpBody(packet);
124 if (pgpBody==null) {
125 return new Message(conversation, counterPart, packet.getBody(), Message.ENCRYPTION_NONE, status);
126 } else {
127 return new Message(conversation, counterPart, pgpBody, Message.ENCRYPTION_PGP, status);
128 }
129 }
130
131 public Message parseCarbonMessage(MessagePacket packet,Account account) {
132 int status;
133 String fullJid;
134 Element forwarded;
135 if (packet.hasChild("received")) {
136 forwarded = packet.findChild("received").findChild(
137 "forwarded");
138 status = Message.STATUS_RECIEVED;
139 } else if (packet.hasChild("sent")) {
140 forwarded = packet.findChild("sent").findChild(
141 "forwarded");
142 status = Message.STATUS_SEND;
143 } else {
144 return null;
145 }
146 if (forwarded==null) {
147 return null;
148 }
149 Element message = forwarded.findChild("message");
150 if ((message == null) || (!message.hasChild("body")))
151 return null; // either malformed or boring
152 if (status == Message.STATUS_RECIEVED) {
153 fullJid = message.getAttribute("from");
154 } else {
155 fullJid = message.getAttribute("to");
156 }
157 String[] parts = fullJid.split("/");
158 Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, parts[0],false);
159 return new Message(conversation,fullJid, message.findChild("body").getContent(), Message.ENCRYPTION_NONE,status);
160 }
161
162 public void parseError(MessagePacket packet, Account account) {
163 String[] fromParts = packet.getFrom().split("/");
164 mXmppConnectionService.markMessage(account, fromParts[0], packet.getId(), Message.STATUS_SEND_FAILED);
165 }
166
167 public String getPgpBody(MessagePacket packet) {
168 Element child = packet.findChild("x", "jabber:x:encrypted");
169 if (child==null) {
170 return null;
171 } else {
172 return child.getContent();
173 }
174 }
175}