Line data Source code
1 : /*
2 : * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 :
18 : #ifdef HAVE_CONFIG_H
19 : #include "config.h"
20 : #endif
21 :
22 : #include "conversation_interface.h"
23 :
24 : #include <cerrno>
25 : #include <cstring>
26 :
27 : #include "logger.h"
28 : #include "manager.h"
29 : #include "jamidht/commit_message.h"
30 : #include "jamidht/jamiaccount.h"
31 : #include "jamidht/collaborative_editing.h"
32 : #include "jamidht/conversation_module.h"
33 :
34 : namespace libjami {
35 :
36 : std::string
37 156 : startConversation(const std::string& accountId)
38 : {
39 156 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
40 156 : if (auto* convModule = acc->convModule(true))
41 156 : return convModule->startConversation();
42 0 : return {};
43 : }
44 :
45 : std::string
46 1 : startFeedConversation(const std::string& accountId)
47 : {
48 1 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
49 1 : if (auto* convModule = acc->convModule(true))
50 1 : return convModule->startConversation(jami::ConversationMode::FEED);
51 0 : return {};
52 : }
53 :
54 : void
55 169 : acceptConversationRequest(const std::string& accountId, const std::string& conversationId)
56 : {
57 169 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
58 169 : if (auto* convModule = acc->convModule(true))
59 507 : convModule->acceptConversationRequest(conversationId);
60 169 : }
61 :
62 : void
63 3 : declineConversationRequest(const std::string& accountId, const std::string& conversationId)
64 : {
65 3 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
66 3 : acc->declineConversationRequest(conversationId);
67 3 : }
68 :
69 : bool
70 15 : removeConversation(const std::string& accountId, const std::string& conversationId)
71 : {
72 15 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
73 15 : if (auto* convModule = acc->convModule(true))
74 15 : return convModule->removeConversation(conversationId);
75 0 : return false;
76 : }
77 :
78 : std::vector<std::string>
79 52 : getConversations(const std::string& accountId)
80 : {
81 52 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
82 52 : if (auto* convModule = acc->convModule(true))
83 52 : return convModule->getConversations();
84 5 : return {};
85 : }
86 :
87 : std::vector<std::map<std::string, std::string>>
88 20 : getActiveCalls(const std::string& accountId, const std::string& conversationId)
89 : {
90 20 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
91 20 : if (auto* convModule = acc->convModule(true))
92 20 : return convModule->getActiveCalls(conversationId);
93 0 : return {};
94 : }
95 :
96 : std::vector<std::map<std::string, std::string>>
97 95 : getConversationRequests(const std::string& accountId)
98 : {
99 95 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
100 95 : if (auto* convModule = acc->convModule(true))
101 95 : return convModule->getConversationRequests();
102 0 : return {};
103 : }
104 :
105 : void
106 3 : updateConversationInfos(const std::string& accountId,
107 : const std::string& conversationId,
108 : const std::map<std::string, std::string>& infos)
109 : {
110 3 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
111 3 : if (auto* convModule = acc->convModule(true))
112 3 : convModule->updateConversationInfos(conversationId, infos);
113 3 : }
114 :
115 : std::map<std::string, std::string>
116 5 : conversationInfos(const std::string& accountId, const std::string& conversationId)
117 : {
118 5 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
119 5 : if (auto* convModule = acc->convModule(true))
120 5 : return convModule->conversationInfos(conversationId);
121 0 : return {};
122 : }
123 :
124 : void
125 5 : setConversationPreferences(const std::string& accountId,
126 : const std::string& conversationId,
127 : const std::map<std::string, std::string>& prefs)
128 : {
129 5 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
130 5 : if (auto* convModule = acc->convModule(true))
131 5 : convModule->setConversationPreferences(conversationId, prefs);
132 5 : }
133 :
134 : std::map<std::string, std::string>
135 4 : getConversationPreferences(const std::string& accountId, const std::string& conversationId)
136 : {
137 4 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
138 4 : if (auto* convModule = acc->convModule(true))
139 4 : return convModule->getConversationPreferences(conversationId);
140 0 : return {};
141 : }
142 :
143 : // Member management
144 : void
145 174 : addConversationMember(const std::string& accountId, const std::string& conversationId, const std::string& contactUri)
146 : {
147 174 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
148 174 : if (auto* convModule = acc->convModule(true)) {
149 174 : dht::InfoHash h(contactUri);
150 174 : if (not h) {
151 0 : JAMI_ERROR("addConversationMember: invalid contact URI `{}`", contactUri);
152 0 : return;
153 : }
154 174 : convModule->addConversationMember(conversationId, h);
155 174 : }
156 : }
157 :
158 : void
159 14 : removeConversationMember(const std::string& accountId, const std::string& conversationId, const std::string& contactUri)
160 : {
161 14 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
162 14 : if (auto* convModule = acc->convModule(true)) {
163 14 : dht::InfoHash h(contactUri);
164 14 : if (not h) {
165 0 : JAMI_ERROR("removeConversationMember: invalid contact URI `{}`", contactUri);
166 0 : return;
167 : }
168 14 : convModule->removeConversationMember(conversationId, h);
169 14 : }
170 : }
171 :
172 : std::vector<std::map<std::string, std::string>>
173 26 : getConversationMembers(const std::string& accountId, const std::string& conversationId)
174 : {
175 26 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
176 26 : if (auto* convModule = acc->convModule(true))
177 26 : return convModule->getConversationMembers(conversationId, true);
178 0 : return {};
179 : }
180 :
181 : std::vector<std::string>
182 2 : getConversationPermissions(const std::string& accountId, const std::string& conversationId)
183 : {
184 2 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
185 2 : if (auto* convModule = acc->convModule(true))
186 2 : return convModule->getConversationPermissions(conversationId);
187 0 : return {};
188 : }
189 :
190 : // Message send/load
191 : void
192 98 : sendMessage(const std::string& accountId,
193 : const std::string& conversationId,
194 : const std::string& message,
195 : const std::string& commitId,
196 : const int32_t& flag)
197 : {
198 98 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
199 98 : if (auto* convModule = acc->convModule(true)) {
200 98 : if (flag == 0 /* Reply or simple commit */) {
201 89 : convModule->sendMessage(conversationId, message, commitId);
202 9 : } else if (flag == 1 /* message edition */) {
203 6 : convModule->editMessage(conversationId, message, commitId);
204 3 : } else if (flag == 2 /* reaction */) {
205 3 : convModule->reactToMessage(conversationId, message, commitId);
206 : }
207 98 : }
208 98 : }
209 :
210 : uint32_t
211 3 : loadConversation(const std::string& accountId,
212 : const std::string& conversationId,
213 : const std::string& fromMessage,
214 : size_t n)
215 : {
216 3 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
217 3 : if (auto* convModule = acc->convModule(true))
218 3 : return convModule->loadConversation(conversationId, fromMessage, n);
219 0 : return 0;
220 : }
221 :
222 : uint32_t
223 0 : loadSwarmUntil(const std::string& accountId,
224 : const std::string& conversationId,
225 : const std::string& fromMessage,
226 : const std::string& toMessage)
227 : {
228 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
229 0 : if (auto* convModule = acc->convModule(true))
230 0 : return convModule->loadSwarmUntil(conversationId, fromMessage, toMessage);
231 0 : return 0;
232 : }
233 :
234 : uint32_t
235 4 : countInteractions(const std::string& accountId,
236 : const std::string& conversationId,
237 : const std::string& toId,
238 : const std::string& fromId,
239 : const std::string& authorUri)
240 : {
241 4 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
242 4 : if (auto* convModule = acc->convModule(true))
243 4 : return convModule->countInteractions(conversationId, toId, fromId, authorUri);
244 0 : return 0;
245 : }
246 :
247 : void
248 0 : clearCache(const std::string& accountId, const std::string& conversationId)
249 : {
250 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
251 0 : if (auto* convModule = acc->convModule(true))
252 0 : convModule->clearCache(conversationId);
253 0 : }
254 :
255 : uint32_t
256 4 : searchConversation(const std::string& accountId,
257 : const std::string& conversationId,
258 : const std::string& author,
259 : const std::string& lastId,
260 : const std::string& regexSearch,
261 : const std::string& type,
262 : const int64_t& after,
263 : const int64_t& before,
264 : const uint32_t& maxResult,
265 : const int32_t& flag)
266 : {
267 4 : uint32_t res = 0;
268 4 : jami::Filter filter {author, lastId, regexSearch, type, after, before, maxResult, flag != 0};
269 16 : for (const auto& accId : jami::Manager::instance().getAccountList()) {
270 12 : if (!accountId.empty() && accId != accountId)
271 8 : continue;
272 4 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accId)) {
273 4 : res = std::uniform_int_distribution<uint32_t>()(acc->rand);
274 4 : if (auto* convModule = acc->convModule(true)) {
275 4 : convModule->search(res, conversationId, filter);
276 : }
277 4 : }
278 4 : }
279 4 : return res;
280 4 : }
281 :
282 : void
283 0 : reloadConversationsAndRequests(const std::string& accountId)
284 : {
285 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
286 0 : acc->reloadContacts();
287 0 : if (auto* convModule = acc->convModule(true)) {
288 0 : convModule->reloadRequests();
289 0 : convModule->loadConversations();
290 : }
291 0 : }
292 0 : }
293 :
294 : std::string
295 25 : createCollaborativeDocument(const std::string& accountId,
296 : const std::string& conversationId,
297 : const std::string& name,
298 : const std::string& mimeType)
299 : {
300 25 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
301 25 : return acc->collaborativeEditing()->createDocument(conversationId, name, mimeType);
302 0 : return {};
303 : }
304 :
305 : std::vector<uint8_t>
306 24 : openCollaborativeDocument(const std::string& accountId, const std::string& conversationId, const std::string& documentId)
307 : {
308 24 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
309 24 : return acc->collaborativeEditing()->openDocument(conversationId, documentId);
310 0 : return {};
311 : }
312 :
313 : bool
314 1 : removeCollaborativeDocument(const std::string& accountId,
315 : const std::string& conversationId,
316 : const std::string& documentId)
317 : {
318 1 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
319 1 : return acc->collaborativeEditing()->removeDocument(conversationId, documentId);
320 0 : return false;
321 : }
322 :
323 : bool
324 4 : removeCollaborativeDocumentLocally(const std::string& accountId,
325 : const std::string& conversationId,
326 : const std::string& documentId)
327 : {
328 4 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
329 4 : return acc->collaborativeEditing()->removeDocumentLocally(conversationId, documentId);
330 0 : return false;
331 : }
332 :
333 : void
334 15 : closeCollaborativeDocument(const std::string& accountId,
335 : const std::string& conversationId,
336 : const std::string& documentId)
337 : {
338 15 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
339 15 : acc->collaborativeEditing()->closeDocument(conversationId, documentId);
340 15 : }
341 :
342 : void
343 13 : applyCollaborativeUpdate(const std::string& accountId,
344 : const std::string& conversationId,
345 : const std::string& documentId,
346 : const std::vector<uint8_t>& update)
347 : {
348 13 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
349 13 : acc->collaborativeEditing()->applyUpdate(conversationId, documentId, update);
350 13 : }
351 :
352 : void
353 1 : setCollaborativeAwareness(const std::string& accountId,
354 : const std::string& conversationId,
355 : const std::string& documentId,
356 : const std::string& state)
357 : {
358 1 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
359 1 : acc->collaborativeEditing()->setAwareness(conversationId, documentId, state);
360 1 : }
361 :
362 : std::vector<uint8_t>
363 7 : collaborativeDocumentState(const std::string& accountId,
364 : const std::string& conversationId,
365 : const std::string& documentId)
366 : {
367 7 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
368 7 : return acc->collaborativeEditing()->documentState(conversationId, documentId);
369 0 : return {};
370 : }
371 :
372 : void
373 2 : setCollaborativeDocumentName(const std::string& accountId,
374 : const std::string& conversationId,
375 : const std::string& documentId,
376 : const std::string& name)
377 : {
378 2 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
379 2 : acc->collaborativeEditing()->setName(conversationId, documentId, name);
380 2 : }
381 :
382 : std::string
383 2 : collaborativeDocumentName(const std::string& accountId, const std::string& conversationId, const std::string& documentId)
384 : {
385 2 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
386 2 : return acc->collaborativeEditing()->documentName(conversationId, documentId);
387 0 : return {};
388 : }
389 :
390 : std::vector<std::map<std::string, std::string>>
391 97 : getCollaborativeDocuments(const std::string& accountId, const std::string& conversationId)
392 : {
393 97 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
394 97 : return acc->collaborativeEditing()->documents(conversationId);
395 0 : return {};
396 : }
397 :
398 : std::vector<std::map<std::string, std::string>>
399 105 : getCollaborativeDocumentHistory(const std::string& accountId,
400 : const std::string& conversationId,
401 : const std::string& documentId,
402 : uint32_t max)
403 : {
404 105 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
405 105 : return acc->collaborativeEditing()->history(conversationId, documentId, max);
406 0 : return {};
407 : }
408 :
409 : std::vector<uint8_t>
410 3 : collaborativeDocumentStateAt(const std::string& accountId,
411 : const std::string& conversationId,
412 : const std::string& documentId,
413 : const std::string& commitId)
414 : {
415 3 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
416 3 : return acc->collaborativeEditing()->documentStateAt(conversationId, documentId, commitId);
417 0 : return {};
418 : }
419 :
420 : std::string
421 1 : addCollaborativeAttachment(const std::string& accountId,
422 : const std::string& conversationId,
423 : const std::string& documentId,
424 : const std::vector<uint8_t>& data)
425 : {
426 1 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
427 1 : return acc->collaborativeEditing()->addAttachment(conversationId, documentId, data);
428 0 : return {};
429 : }
430 :
431 : std::vector<uint8_t>
432 3 : collaborativeAttachment(const std::string& accountId,
433 : const std::string& conversationId,
434 : const std::string& documentId,
435 : const std::string& attachmentId)
436 : {
437 3 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
438 3 : return acc->collaborativeEditing()->attachment(conversationId, documentId, attachmentId);
439 0 : return {};
440 : }
441 :
442 : } // namespace libjami
|