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