1 /*
2  * %kadu copyright begin%
3  * Copyright 2011, 2012 Wojciech Treter (juzefwt@gmail.com)
4  * Copyright 2011, 2012, 2013 Bartosz Brachaczek (b.brachaczek@gmail.com)
5  * Copyright 2011, 2012, 2013, 2014, 2015 Rafał Przemysław Malinowski (rafal.przemyslaw.malinowski@gmail.com)
6  * %kadu copyright end%
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "jabber-chat-service.h"
23 
24 #include "services/jabber-chat-state-service.h"
25 #include "services/jabber-resource-service.h"
26 #include "services/jabber-room-chat-service.h"
27 #include "jabber-protocol.h"
28 #include "jid.h"
29 
30 #include "buddies/buddy-manager.h"
31 #include "buddies/buddy-set.h"
32 #include "chat/chat-details-room.h"
33 #include "chat/chat-manager.h"
34 #include "chat/chat-storage.h"
35 #include "chat/chat.h"
36 #include "chat/type/chat-type-contact.h"
37 #include "chat/type/chat-type-manager.h"
38 #include "configuration/configuration.h"
39 #include "configuration/deprecated-configuration-api.h"
40 #include "contacts/contact-manager.h"
41 #include "contacts/contact-set.h"
42 #include "formatted-string/composite-formatted-string.h"
43 #include "formatted-string/formatted-string-factory.h"
44 #include "formatted-string/formatted-string-plain-text-visitor.h"
45 #include "gui/windows/message-dialog.h"
46 #include "html/html-conversion.h"
47 #include "html/html-string.h"
48 #include "message/message-storage.h"
49 #include "message/message.h"
50 #include "message/raw-message.h"
51 #include "misc/misc.h"
52 #include "services/raw-message-transformer-service.h"
53 #include "debug.h"
54 
55 #include <QtGui/QTextDocument>
56 #include <qxmpp/QXmppMessage.h>
57 
JabberChatService(QXmppClient * client,Account account,QObject * parent)58 JabberChatService::JabberChatService(QXmppClient *client, Account account, QObject *parent) :
59 		ChatService{account, parent},
60 		m_client{client}
61 {
62 	connect(m_client, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(handleReceivedMessage(QXmppMessage)));
63 }
64 
~JabberChatService()65 JabberChatService::~JabberChatService()
66 {
67 }
68 
setChatManager(ChatManager * chatManager)69 void JabberChatService::setChatManager(ChatManager *chatManager)
70 {
71 	m_chatManager = chatManager;
72 }
73 
setChatStorage(ChatStorage * chatStorage)74 void JabberChatService::setChatStorage(ChatStorage *chatStorage)
75 {
76 	m_chatStorage = chatStorage;
77 }
78 
setChatTypeManager(ChatTypeManager * chatTypeManager)79 void JabberChatService::setChatTypeManager(ChatTypeManager *chatTypeManager)
80 {
81 	m_chatTypeManager = chatTypeManager;
82 }
83 
setContactManager(ContactManager * contactManager)84 void JabberChatService::setContactManager(ContactManager *contactManager)
85 {
86 	m_contactManager = contactManager;
87 }
88 
setChatStateService(JabberChatStateService * chatStateService)89 void JabberChatService::setChatStateService(JabberChatStateService *chatStateService)
90 {
91 	m_chatStateService = chatStateService;
92 }
93 
setFormattedStringFactory(FormattedStringFactory * formattedStringFactory)94 void JabberChatService::setFormattedStringFactory(FormattedStringFactory *formattedStringFactory)
95 {
96 	m_formattedStringFactory = formattedStringFactory;
97 }
98 
setMessageStorage(MessageStorage * messageStorage)99 void JabberChatService::setMessageStorage(MessageStorage *messageStorage)
100 {
101 	m_messageStorage = messageStorage;
102 }
103 
setResourceService(JabberResourceService * resourceService)104 void JabberChatService::setResourceService(JabberResourceService *resourceService)
105 {
106 	m_resourceService = resourceService;
107 }
108 
setRoomChatService(JabberRoomChatService * roomChatService)109 void JabberChatService::setRoomChatService(JabberRoomChatService *roomChatService)
110 {
111 	m_roomChatService = roomChatService;
112 }
113 
maxMessageLength() const114 int JabberChatService::maxMessageLength() const
115 {
116 	return 60000;
117 }
118 
chatMessageType(const Chat & chat,const QString & bareJid) const119 QXmppMessage::Type JabberChatService::chatMessageType(const Chat &chat, const QString &bareJid) const
120 {
121 	auto chatType = m_chatTypeManager->chatType(chat.type());
122 	if (!chatType)
123 		return QXmppMessage::QXmppMessage::Normal;
124 
125 	if (chatType->name() == "Room")
126 		return QXmppMessage::GroupChat;
127 
128 	if (m_contactMessageTypes.contains(bareJid))
129 		return m_contactMessageTypes.value(bareJid);
130 	else
131 		return QXmppMessage::Chat;
132 }
133 
sendMessage(const Message & message)134 bool JabberChatService::sendMessage(const Message &message)
135 {
136 	if (!m_client)
137 		return false;
138 
139 	auto jid = m_resourceService->bestChatJid(message.messageChat());
140 	if (jid.isEmpty())
141 		return false;
142 
143 	auto xmppMessage = QXmppMessage{};
144 	auto formattedContent = m_formattedStringFactory->fromHtml(message.content());
145 
146 	FormattedStringPlainTextVisitor plainTextVisitor;
147 	formattedContent->accept(&plainTextVisitor);
148 
149 	auto plain = plainTextVisitor.result();
150 	if (rawMessageTransformerService())
151 		plain = QString::fromUtf8(rawMessageTransformerService()->transform(plain.toUtf8(), {message}).rawContent());
152 
153 	xmppMessage.setBody(plain);
154 	xmppMessage.setFrom(m_client.data()->clientPresence().id());
155 	xmppMessage.setStamp(QDateTime::currentDateTime());
156 	xmppMessage.setTo(jid.full());
157 	xmppMessage.setType(chatMessageType(message.messageChat(), jid.bare()));
158 
159 	m_client.data()->sendPacket(m_chatStateService->withSentChatState(xmppMessage));
160 
161 	return true;
162 }
163 
sendRawMessage(const Chat & chat,const QByteArray & rawMessage)164 bool JabberChatService::sendRawMessage(const Chat &chat, const QByteArray &rawMessage)
165 {
166 	if (!m_client)
167 		return false;
168 
169 	auto jid = m_resourceService->bestChatJid(chat);
170 	if (jid.isEmpty())
171 		return false;
172 
173 	auto xmppMessage = QXmppMessage{};
174 
175 	xmppMessage.setBody(rawMessage);
176 	xmppMessage.setFrom(m_client.data()->clientPresence().id());
177 	xmppMessage.setStamp(QDateTime::currentDateTime());
178 	xmppMessage.setTo(jid.full());
179 	xmppMessage.setType(chatMessageType(chat, jid.bare()));
180 
181 	m_client.data()->sendPacket(m_chatStateService->withSentChatState(xmppMessage));
182 
183 	return true;
184 }
185 
handleReceivedMessage(const QXmppMessage & xmppMessage)186 void JabberChatService::handleReceivedMessage(const QXmppMessage &xmppMessage)
187 {
188 	if (!m_formattedStringFactory)
189 		return;
190 
191 	m_chatStateService->extractReceivedChatState(xmppMessage);
192 
193 	if (xmppMessage.body().isEmpty())
194 		return;
195 
196 	if (xmppMessage.type() == QXmppMessage::Type::Error) // #1642
197 		return;
198 
199 	auto message = xmppMessage.type() == QXmppMessage::GroupChat
200 		? m_roomChatService->handleReceivedMessage(xmppMessage)
201 		: handleNormalReceivedMessage(xmppMessage);
202 	if (message.isNull())
203 		return;
204 
205 	message.setType(MessageTypeReceived);
206 	message.setSendDate(xmppMessage.stamp().toLocalTime());
207 	message.setReceiveDate(QDateTime::currentDateTime());
208 
209 	auto body = xmppMessage.body();
210 	if (rawMessageTransformerService())
211 		body = QString::fromUtf8(rawMessageTransformerService()->transform(body.toUtf8(), message).rawContent());
212 
213 	message.setContent(normalizeHtml(plainToHtml(body)));
214 
215 	auto id = xmppMessage.from();
216 	auto resourceIndex = id.indexOf('/');
217 	if (resourceIndex >= 0)
218 		id = id.mid(0, resourceIndex);
219 	m_contactMessageTypes.insert(id, xmppMessage.type());
220 
221 	emit messageReceived(message);
222 }
223 
handleNormalReceivedMessage(const QXmppMessage & xmppMessage)224 Message JabberChatService::handleNormalReceivedMessage(const QXmppMessage &xmppMessage)
225 {
226 	auto jid = Jid::parse(xmppMessage.from());
227 
228 	auto contact = m_contactManager->byId(account(), jid.bare(), ActionCreateAndAdd);
229 	auto chat = ChatTypeContact::findChat(m_chatManager, m_chatStorage, contact, ActionCreateAndAdd);
230 
231 	contact.addProperty("jabber:chat-resource", jid.resource(), CustomProperties::NonStorable);
232 
233 	auto message = m_messageStorage->create();
234 	message.setMessageChat(chat);
235 	message.setMessageSender(contact);
236 
237 	return message;
238 }
239 
leaveChat(const Chat & chat)240 void JabberChatService::leaveChat(const Chat& chat)
241 {
242 	if (m_roomChatService->isRoomChat(chat))
243 		m_roomChatService->leaveChat(chat);
244 }
245 
246 #include "moc_jabber-chat-service.cpp"
247