LCOV - code coverage report
Current view: top level - src/jamidht - conversation.h (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 93.8 % 48 45
Test Date: 2026-08-24 08:14:20 Functions: 87.5 % 16 14

            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              : #pragma once
      19              : 
      20              : #include "jamidht/commit_message.h"
      21              : #include "jamidht/conversationrepository.h"
      22              : #include "jamidht/gitsocket.h"
      23              : #include "conversationrepository.h"
      24              : #include "swarm/swarm_protocol.h"
      25              : #include "jami/conversation_interface.h"
      26              : #include "jamidht/typers.h"
      27              : #include "string_utils.h"
      28              : #include "timestamp.h"
      29              : 
      30              : #include <json/json.h>
      31              : #include <msgpack.hpp>
      32              : 
      33              : #include <chrono>
      34              : #include <functional>
      35              : #include <string>
      36              : #include <vector>
      37              : #include <map>
      38              : #include <memory>
      39              : #include <set>
      40              : 
      41              : #include <asio.hpp>
      42              : 
      43              : namespace dhtnet {
      44              : class ChannelSocket;
      45              : } // namespace dhtnet
      46              : 
      47              : namespace jami {
      48              : 
      49              : namespace ConversationMapKeys {
      50              : static constexpr const char* ID {"id"};
      51              : static constexpr const char* CREATED {"created"};
      52              : static constexpr const char* REMOVED {"removed"};
      53              : static constexpr const char* ERASED {"erased"};
      54              : static constexpr const char* MEMBERS {"members"};
      55              : static constexpr const char* LAST_DISPLAYED {"lastDisplayed"};
      56              : static constexpr const char* RECEIVED {"received"};
      57              : static constexpr const char* DECLINED {"declined"};
      58              : static constexpr const char* FROM {"from"};
      59              : static constexpr const char* CONVERSATIONID {"conversationId"};
      60              : static constexpr const char* METADATAS {"metadatas"};
      61              : static constexpr const char* MODE {"mode"};
      62              : // Millisecond-resolution variants. Legacy keys above keep carrying seconds
      63              : // so that older devices (which ignore unknown keys) remain compatible.
      64              : static constexpr const char* CREATED_MS {"createdMs"};
      65              : static constexpr const char* REMOVED_MS {"removedMs"};
      66              : static constexpr const char* ERASED_MS {"erasedMs"};
      67              : static constexpr const char* RECEIVED_MS {"receivedMs"};
      68              : static constexpr const char* DECLINED_MS {"declinedMs"};
      69              : static constexpr const char* INVITED {"invited"};
      70              : } // namespace ConversationMapKeys
      71              : 
      72              : namespace ConversationDirectories {
      73              : static constexpr std::string_view PREFERENCES {"preferences"};
      74              : static constexpr std::string_view STATUS {"status"};
      75              : static constexpr std::string_view SENDING {"sending"};
      76              : static constexpr std::string_view FETCHED {"fetched"};
      77              : static constexpr std::string_view ACTIVE_CALLS {"activeCalls"};
      78              : static constexpr std::string_view HOSTED_CALLS {"hostedCalls"};
      79              : static constexpr std::string_view CACHED {"cached"};
      80              : static constexpr std::string_view MOBILE_NODES {"mobileNodes"};
      81              : } // namespace ConversationDirectories
      82              : 
      83              : namespace ConversationPreferences {
      84              : static constexpr const char* HOST_CONFERENCES = "hostConferences";
      85              : }
      86              : 
      87              : struct MobileNodeTarget
      88              : {
      89              :     NodeId device;
      90              :     std::string uri;
      91              : };
      92              : 
      93              : class JamiAccount;
      94              : class ConversationRepository;
      95              : class TransferManager;
      96              : enum class ConversationMode;
      97              : 
      98              : /**
      99              :  * A ConversationRequest is a request which corresponds to a trust request, but for conversations
     100              :  * It's signed by the sender and contains the members list, the conversationId, and the metadatas
     101              :  * such as the conversation's vcard, etc. (TODO determine)
     102              :  * Transmitted via the UDP DHT
     103              :  */
     104              : struct ConversationRequest
     105              : {
     106              :     std::string conversationId;
     107              :     std::string from;
     108              :     std::map<std::string, std::string> metadatas;
     109              : 
     110              :     TimePoint received {};
     111              :     TimePoint declined {};
     112              : 
     113          232 :     ConversationRequest() = default;
     114              :     ConversationRequest(const Json::Value& json);
     115              : 
     116              :     Json::Value toJson() const;
     117              :     std::map<std::string, std::string> toMap() const;
     118              : 
     119              :     bool operator==(const ConversationRequest& o) const
     120              :     {
     121              :         auto m = toMap();
     122              :         auto om = o.toMap();
     123              :         return m.size() == om.size() && std::equal(m.begin(), m.end(), om.begin());
     124              :     }
     125              : 
     126          413 :     bool isOneToOne() const
     127              :     {
     128              :         try {
     129         1239 :             return metadatas.at("mode") == "0";
     130           41 :         } catch (...) {
     131           41 :         }
     132           41 :         return true;
     133              :     }
     134              : 
     135          146 :     ConversationMode mode() const
     136              :     {
     137              :         try {
     138          438 :             return to_enum<ConversationMode>(metadatas.at("mode"));
     139           30 :         } catch (...) {
     140           30 :         }
     141           30 :         return ConversationMode::ONE_TO_ONE;
     142              :     }
     143              : 
     144              :     // Hand-written msgpack serialization (replaces MSGPACK_DEFINE_MAP) to emit
     145              :     // dual keys: legacy seconds (received/declined) + milliseconds (receivedMs/declinedMs).
     146              :     // Readers prefer the ms keys and fall back to seconds * 1000.
     147              :     template<typename Packer>
     148          181 :     void msgpack_pack(Packer& pk) const
     149              :     {
     150          181 :         int64_t receivedSec = toSecondsSinceEpoch(received);
     151          181 :         int64_t declinedSec = toSecondsSinceEpoch(declined);
     152          181 :         int64_t receivedMs = toMillisecondsSinceEpoch(received);
     153          181 :         int64_t declinedMs = toMillisecondsSinceEpoch(declined);
     154              :         msgpack::type::make_define_map(ConversationMapKeys::FROM,
     155          181 :                                        from,
     156              :                                        ConversationMapKeys::CONVERSATIONID,
     157          181 :                                        conversationId,
     158              :                                        ConversationMapKeys::METADATAS,
     159          181 :                                        metadatas,
     160              :                                        ConversationMapKeys::RECEIVED,
     161              :                                        receivedSec,
     162              :                                        ConversationMapKeys::DECLINED,
     163              :                                        declinedSec,
     164              :                                        ConversationMapKeys::RECEIVED_MS,
     165              :                                        receivedMs,
     166              :                                        ConversationMapKeys::DECLINED_MS,
     167              :                                        declinedMs)
     168          181 :             .msgpack_pack(pk);
     169          181 :     }
     170              :     void msgpack_unpack(const msgpack::object& o);
     171              :     void msgpack_object(msgpack::object* o, msgpack::zone& z) const;
     172              : };
     173              : 
     174              : struct ConvInfo
     175              : {
     176              :     std::string id {};
     177              :     TimePoint created {};
     178              :     TimePoint removed {};
     179              :     TimePoint erased {};
     180              :     std::set<std::string> members;
     181              :     std::string lastDisplayed {};
     182              :     ConversationMode mode {0};
     183              :     // Last time we explicitly (re-)invited a given peer (via addConversationMember()/
     184              :     // sendTrustRequest()), keyed by peer URI.
     185              :     std::map<std::string, TimePoint> invited {};
     186              : 
     187          670 :     ConvInfo() = default;
     188          176 :     ConvInfo(const ConvInfo&) = default;
     189            0 :     ConvInfo(ConvInfo&&) = default;
     190          471 :     ConvInfo(const std::string& id)
     191          471 :         : id(id) {};
     192              :     explicit ConvInfo(const Json::Value& json);
     193              : 
     194        13386 :     bool isRemoved() const { return removed >= created; }
     195              : 
     196         2743 :     ConvInfo& operator=(const ConvInfo&) = default;
     197          313 :     ConvInfo& operator=(ConvInfo&&) = default;
     198              : 
     199              :     Json::Value toJson() const;
     200              : 
     201              :     // Hand-written msgpack serialization (replaces MSGPACK_DEFINE_MAP) to emit
     202              :     // dual keys: legacy seconds (created/removed/erased) + milliseconds
     203              :     // (createdMs/removedMs/erasedMs). Readers prefer the ms keys and fall back
     204              :     // to seconds * 1000.
     205              :     template<typename Packer>
     206         3201 :     void msgpack_pack(Packer& pk) const
     207              :     {
     208         3201 :         int64_t createdSec = toSecondsSinceEpoch(created);
     209         3201 :         int64_t removedSec = toSecondsSinceEpoch(removed);
     210         3200 :         int64_t erasedSec = toSecondsSinceEpoch(erased);
     211         3201 :         int64_t createdMs = toMillisecondsSinceEpoch(created);
     212         3200 :         int64_t removedMs = toMillisecondsSinceEpoch(removed);
     213         3200 :         int64_t erasedMs = toMillisecondsSinceEpoch(erased);
     214         3200 :         std::map<std::string, int64_t> invitedMs;
     215         6779 :         for (const auto& [uri, t] : invited)
     216         3577 :             invitedMs[uri] = toMillisecondsSinceEpoch(t);
     217              :         msgpack::type::make_define_map(ConversationMapKeys::ID,
     218         3201 :                                        id,
     219              :                                        ConversationMapKeys::CREATED,
     220              :                                        createdSec,
     221              :                                        ConversationMapKeys::REMOVED,
     222              :                                        removedSec,
     223              :                                        ConversationMapKeys::ERASED,
     224              :                                        erasedSec,
     225              :                                        ConversationMapKeys::MEMBERS,
     226         3201 :                                        members,
     227              :                                        ConversationMapKeys::LAST_DISPLAYED,
     228         3201 :                                        lastDisplayed,
     229              :                                        ConversationMapKeys::MODE,
     230         3201 :                                        mode,
     231              :                                        ConversationMapKeys::CREATED_MS,
     232              :                                        createdMs,
     233              :                                        ConversationMapKeys::REMOVED_MS,
     234              :                                        removedMs,
     235              :                                        ConversationMapKeys::ERASED_MS,
     236              :                                        erasedMs,
     237              :                                        ConversationMapKeys::INVITED,
     238              :                                        invitedMs)
     239         3201 :             .msgpack_pack(pk);
     240         3201 :     }
     241              :     void msgpack_unpack(const msgpack::object& o);
     242              :     void msgpack_object(msgpack::object* o, msgpack::zone& z) const;
     243              : };
     244              : 
     245              : using OnPullCb = std::function<void(bool fetchOk)>;
     246              : using OnLoadMessages = std::function<void(std::vector<libjami::SwarmMessage>&& messages)>;
     247              : using OnCommitCb = std::function<void(const std::string&)>;
     248              : using OnDoneCb = std::function<void(bool, const std::string&)>;
     249              : using OnMembersChanged = std::function<void(const std::set<std::string>&)>;
     250              : using DeviceId = dht::PkId;
     251              : using GitSocketList = std::map<DeviceId, GitSocket>;
     252              : using ChannelCb = std::function<bool(const std::shared_ptr<dhtnet::ChannelSocket>&)>;
     253              : using NeedSocketCb
     254              :     = std::function<void(const std::string&, const std::string&, ChannelCb&&, const std::string&, bool noNewSocket)>;
     255              : 
     256              : class Conversation : public std::enable_shared_from_this<Conversation>
     257              : {
     258              : public:
     259              :     Conversation(const std::shared_ptr<JamiAccount>& account,
     260              :                  ConversationMode mode,
     261              :                  const std::string& otherMember = "");
     262              :     Conversation(const std::shared_ptr<JamiAccount>& account, const std::string& conversationId = "");
     263              :     Conversation(const std::shared_ptr<JamiAccount>& account,
     264              :                  const std::string& remoteDevice,
     265              :                  const std::string& conversationId);
     266              :     ~Conversation();
     267              : 
     268              :     /**
     269              :      * Print the state of the DRT linked to the conversation
     270              :      */
     271              :     void monitor();
     272              : 
     273              : #ifdef LIBJAMI_TEST
     274              :     enum class BootstrapStatus { FAILED, FALLBACK, SUCCESS };
     275              :     /**
     276              :      * Used by the tests to get whenever the DRT is connected/disconnected
     277              :      */
     278              :     void onBootstrapStatus(const std::function<void(std::string, BootstrapStatus)>& cb);
     279              : 
     280              :     std::vector<libjami::SwarmMessage> loadMessagesSync(const LogOptions& options);
     281              :     void announce(const std::vector<std::map<std::string, std::string>>& commits, bool commitFromSelf = false);
     282              :     void announce(const std::string& commitId, bool commitFromSelf = false);
     283              : #endif
     284              : 
     285              :     /**
     286              :      * Bootstrap swarm manager to other peers
     287              :      * @param onBootstrapped     Callback called when connection is established successfully
     288              :      * @param knownDevices       Optional list of live devices to seed the DRT with.
     289              :      *                           Normally empty: candidates are fed by the per-device
     290              :      *                           presence monitoring through addKnownDevices().
     291              :      */
     292              :     void bootstrap(std::function<void()> onBootstrapped, const std::vector<DeviceId>& knownDevices = {});
     293              : 
     294              :     /**
     295              :      * Add known devices to the swarm manager
     296              :      * @param devices
     297              :      * @param memberUri
     298              :      */
     299              :     void addKnownDevices(const std::vector<DeviceId>& devices, const std::string& memberUri);
     300              : 
     301              :     /**
     302              :      * Proactively connect a device in the swarm, bypassing DRT bucket checks.
     303              :      * Used when a TCP link to the device already exists.
     304              :      * @param deviceId
     305              :      */
     306              :     void connectNode(const DeviceId& deviceId);
     307              : 
     308              :     /**
     309              :      * Refresh active calls.
     310              :      * @note: If the host crash during a call, when initializing, we need to update
     311              :      * and commit all the crashed calls
     312              :      * @return  Commits added
     313              :      */
     314              :     std::vector<std::string> commitsEndedCalls();
     315              : 
     316              :     void onMembersChanged(OnMembersChanged&& cb);
     317              : 
     318              :     /**
     319              :      * Set the callback that will be called whenever a new socket will be needed
     320              :      * @param cb
     321              :      */
     322              :     void onNeedSocket(NeedSocketCb cb);
     323              :     /**
     324              :      * Add swarm connection to the DRT
     325              :      * @param channel       Related channel
     326              :      */
     327              :     void addSwarmChannel(std::shared_ptr<dhtnet::ChannelSocket> channel);
     328              : 
     329              :     /**
     330              :      * Get conversation's id
     331              :      * @return conversation Id
     332              :      */
     333              :     std::string id() const;
     334              : 
     335              :     // Member management
     336              :     /**
     337              :      * Add conversation member
     338              :      * @param uri   Member to add
     339              :      * @param cb    On done cb
     340              :      */
     341              :     void addMember(const std::string& contactUri, const OnDoneCb& cb = {});
     342              :     void removeMember(const std::string& contactUri, bool isDevice, const OnDoneCb& cb = {});
     343              :     /**
     344              :      * @param includeInvited        If we want invited members
     345              :      * @param includeLeft           If we want left members
     346              :      * @param includeBanned         If we want banned members
     347              :      * @return a vector of member details:
     348              :      * {
     349              :      *  "uri":"xxx",
     350              :      *  "role":"member/admin/invited",
     351              :      *  "lastDisplayed":"id"
     352              :      *  ...
     353              :      * }
     354              :      */
     355              :     std::vector<std::map<std::string, std::string>> getMembers(bool includeInvited = false,
     356              :                                                                bool includeLeft = false,
     357              :                                                                bool includeBanned = false) const;
     358              : 
     359              :     /**
     360              :      * @param filter           If we want to remove one member
     361              :      * @param filteredRoles    If we want to ignore some roles
     362              :      * @return members' uris
     363              :      */
     364              :     std::set<std::string> memberUris(std::string_view filter = {},
     365              :                                      const std::set<MemberRole>& filteredRoles = {MemberRole::INVITED,
     366              :                                                                                   MemberRole::LEFT,
     367              :                                                                                   MemberRole::BANNED}) const;
     368              : 
     369              :     std::vector<std::map<std::string, std::string>> getTrackedMembers() const;
     370              : 
     371              :     /**
     372              :      * Get peers to sync with. This is mostly managed by the DRT
     373              :      * @return all connected nodes and nodes with a git socket
     374              :      */
     375              :     std::vector<NodeId> peersToSyncWith() const;
     376              :     /**
     377              :      * Get the mobile nodes this device is responsible for waking up
     378              :      * when a new message must be synced. Mobile nodes are not actively
     379              :      * connected to the DRT, so they are notified via a DHT message
     380              :      * (converted to a push notification by the proxy).
     381              :      * @return mobile nodes we are closer to than any connected node
     382              :      */
     383              :     std::vector<MobileNodeTarget> mobileNodesToNotify() const;
     384              :     /**
     385              :      * Check if we're at least connected to one node
     386              :      * @return if the DRT is connected
     387              :      */
     388              :     bool isBootstrapped() const;
     389              :     /**
     390              :      * Retrieve the uri from a deviceId
     391              :      * @note used by swarm manager (peersToSyncWith)
     392              :      * @param deviceId
     393              :      * @return corresponding issuer
     394              :      */
     395              :     std::string uriFromDevice(const std::string& deviceId) const;
     396              : 
     397              :     /**
     398              :      * The devices recorded in the repository, per member.
     399              :      * @return member uri -> that member's device ids
     400              :      */
     401              :     std::map<std::string, std::vector<DeviceId>> memberDevices() const;
     402              : 
     403              :     /**
     404              :      * Join a conversation
     405              :      * @return commit id to send
     406              :      */
     407              :     std::string join();
     408              : 
     409              :     /**
     410              :      * Test if an URI is a member
     411              :      * @param uri       URI to test
     412              :      * @return true if uri is a member
     413              :      */
     414              :     bool isMember(const std::string& uri, bool includeInvited = false) const;
     415              :     bool isMemberBanned(const std::string& uri) const;
     416              :     bool isDeviceBanned(const std::string& deviceId) const;
     417              : 
     418              :     /**
     419              :      * Check if a device is authorized to clone or interact with the conversation.
     420              :      * Assumption: the deviceId must already be a confirmed device of the user.
     421              :      * @param uri               URI of the user
     422              :      * @param deviceId          Device id to check
     423              :      * @param includeInvited    If true, consider invited members as authorized.
     424              :      */
     425              :     bool isPeerAuthorized(const std::string& uri, const std::string& deviceId, bool includeInvited = false) const;
     426              : 
     427              :     void createCommit(CommitMessage&& message, OnCommitCb&& onCommit = {}, OnDoneCb&& cb = {});
     428              : 
     429              :     /**
     430              :      * Get a range of messages
     431              :      * @param cb        The callback when loaded
     432              :      * @param options   The log options
     433              :      */
     434              :     void loadMessages(const OnLoadMessages& cb, const LogOptions& options);
     435              :     /**
     436              :      * For every loaded TEXT message that has no bodyOverwrite in pluginData, runs the plugin
     437              :      * ChatServicesManager transform to obtain one.  If the plugin produces a bodyOverwrite,
     438              :      * stores it in pluginData and emits SwarmMessageUpdated for the affected message
     439              :      * (edition commits signal the original message; originals signal themselves).
     440              :      * No-op when no plugin chat handlers are registered.
     441              :      */
     442              :     void loadMissingBodyOverwrites() const;
     443              :     /**
     444              :      * Drops all bodyOverwrite entries from the loaded message history, then calls
     445              :      * loadMissingBodyOverwrites() to re-derive them from scratch via the plugin transform.
     446              :      * Use when plugin chat handlers are reloaded or their transform logic has changed.
     447              :      */
     448              :     void reloadBodyOverwriteMessages() const;
     449              :     /**
     450              :      * Stores or clears the plugin-provided bodyOverwrite for a single message.
     451              :      * An empty bodyOverwrite sets the entry to "" (marks the message as processed with no
     452              :      * overwrite, preventing reprocessing); a non-empty value replaces it.
     453              :      * If messageId refers to an edition commit, SwarmMessageUpdated is emitted for the
     454              :      * original message (the one clients display); otherwise it is emitted for messageId itself.
     455              :      * @param messageId     Id of the message (original or edition commit) to update.
     456              :      * @param bodyOverwrite Plugin-transformed body text, or empty to clear the override.
     457              :      */
     458              :     void updateMessageBodyOverwrite(const std::string& messageId, const std::string& bodyOverwrite) const;
     459              :     /**
     460              :      * Removes all bodyOverwrite entries from every message in the loaded history and emits
     461              :      * SwarmMessageUpdated for each affected message so clients revert to the original
     462              :      * body.  Edition commits are resolved to their original message before signalling.
     463              :      */
     464              :     void clearBodyOverwrites() const;
     465              :     /**
     466              :      * Clear all cached messages
     467              :      */
     468              :     void clearCache();
     469              :     /**
     470              :      * Check if a commit exists in the repository
     471              :      * @param commitId The commit id to check
     472              :      * @return true if the commit was found, false if not or if an error occurred
     473              :      */
     474              :     bool hasCommit(const std::string& commitId) const;
     475              :     /**
     476              :      * Retrieve one commit
     477              :      * @param   commitId
     478              :      * @return  The commit if found
     479              :      */
     480              :     std::optional<ConversationCommit> getCommit(const std::string& commitId) const;
     481              :     /**
     482              :      * List every collaborative document announced in this conversation, by scanning the
     483              :      * repository for COLLAB_DOC commits rather than the loaded message history. Lets a
     484              :      * client show the editable documents without first paging in the (possibly old)
     485              :      * announcing messages.
     486              :      * @return  one map per COLLAB_DOC commit ("uri" = document id, "displayName",
     487              :      *          "mimeType", "author", "timestamp"), newest first
     488              :      */
     489              :     std::vector<std::map<std::string, std::string>> collaborativeDocuments() const;
     490              :     /**
     491              :      * Get last commit id
     492              :      * @return last commit id
     493              :      */
     494              :     std::string lastCommitId() const;
     495              : 
     496              :     /**
     497              :      * Fetch and merge from peer
     498              :      * @param deviceId  Peer device
     499              :      * @param cb        On pulled callback
     500              :      * @param commitId  Commit id that triggered this fetch
     501              :      * @return true if callback will be called later
     502              :      */
     503              :     bool pull(const std::string& deviceId, OnPullCb&& cb, std::string commitId = "");
     504              :     /**
     505              :      * Fetch new commits and re-ask for waiting files
     506              :      * @param member
     507              :      * @param deviceId
     508              :      * @param cb        cf pull()
     509              :      * @param commitId  cf pull()
     510              :      */
     511              :     void sync(const std::string& member, const std::string& deviceId, OnPullCb&& cb, std::string commitId = "");
     512              : 
     513              :     /**
     514              :      * Generate an invitation to send to new contacts
     515              :      * @param sent  timestamp of the explicit action that caused this invite to be (re)sent
     516              :      *              (e.g. addConversationMember()). Callers that merely relay/resend an
     517              :      *              already-generated invite must pass the originally recorded timestamp.
     518              :      * @return the invite to send
     519              :      */
     520              :     std::map<std::string, std::string> generateInvitation(TimePoint sent) const;
     521              : 
     522              :     /**
     523              :      * Leave a conversation
     524              :      * @return commit id to send
     525              :      */
     526              :     std::string leave();
     527              : 
     528              :     /**
     529              :      * Set a conversation as removing (when loading convInfo and still not sync)
     530              :      * @todo: not a big fan to see this here. can be set in the constructor
     531              :      * cause it's used by jamiaccount when loading conversations
     532              :      */
     533              :     void setRemovingFlag();
     534              : 
     535              :     /**
     536              :      * Check if we are removing the conversation
     537              :      * @return true if left the room
     538              :      */
     539              :     bool isRemoving();
     540              : 
     541              :     /**
     542              :      * Erase all related datas
     543              :      */
     544              :     void erase();
     545              : 
     546              :     /**
     547              :      * Get conversation's mode
     548              :      * @return the mode
     549              :      */
     550              :     ConversationMode mode() const;
     551              : 
     552              :     /**
     553              :      * For a collaborative document (mode DOCUMENT), the id of the conversation
     554              :      * that announced it, read from the initial commit.
     555              :      * @return empty for any other mode
     556              :      */
     557              :     std::string parentConversationId() const;
     558              : 
     559              :     /**
     560              :      * For a collaborative document, the MIME type of what it holds, read from
     561              :      * the initial commit.
     562              :      * @return empty for any other mode
     563              :      */
     564              :     std::string documentMimeType() const;
     565              : 
     566              :     /**
     567              :      * For a collaborative document, every CRDT update persisted in the
     568              :      * repository, oldest first: the base64-encoded lines of the body of each
     569              :      * checkpoint commit, in the order they must be replayed.
     570              :      */
     571              :     std::vector<std::string> documentUpdates() const;
     572              : 
     573              :     /**
     574              :      * Same as documentUpdates() but only up to (and including) the given
     575              :      * commit, to rebuild the document as it was at that point.
     576              :      * @return std::nullopt when the commit is unknown, as opposed to an empty
     577              :      *         document at a known commit
     578              :      */
     579              :     std::optional<std::vector<std::string>> documentUpdatesAt(const std::string& commitId) const;
     580              : 
     581              :     /**
     582              :      * For a collaborative document, its persisted history: one map per
     583              :      * checkpoint commit, newest first, with keys "id", "author", "device",
     584              :      * "timestamp" and "deltas" (the number of updates the checkpoint carries).
     585              :      * @param max  stop after this many entries; 0 for no limit
     586              :      */
     587              :     std::vector<std::map<std::string, std::string>> documentHistory(size_t max) const;
     588              : 
     589              :     /**
     590              :      * For a collaborative document, store an attachment and announce the
     591              :      * commit to the swarm.
     592              :      * @return {attachmentId, commitId}; commitId is empty when the same
     593              :      *         content was already attached (nothing new to announce) and both
     594              :      *         are empty on failure
     595              :      */
     596              :     std::pair<std::string, std::string> addDocumentAttachment(const std::vector<uint8_t>& data);
     597              : 
     598              :     /**
     599              :      * For a collaborative document, read an attachment's content at HEAD.
     600              :      */
     601              :     std::vector<uint8_t> documentAttachment(const std::string& attachmentId) const;
     602              : 
     603              :     /**
     604              :      * For a collaborative document, list the attachment ids present at HEAD.
     605              :      */
     606              :     std::vector<std::string> documentAttachmentIds() const;
     607              : 
     608              :     /**
     609              :      * One to one util, get initial members
     610              :      * @return initial members
     611              :      */
     612              :     std::vector<std::string> getInitialMembers() const;
     613              :     bool isInitialMember(const std::string& uri) const;
     614              : 
     615              :     /**
     616              :      * Change repository's infos
     617              :      * @param map       New infos (supported keys: title, description, avatar)
     618              :      * @param cb        On commited
     619              :      */
     620              :     void updateInfos(const std::map<std::string, std::string>& map, const OnDoneCb& cb = {});
     621              : 
     622              :     /**
     623              :      * Change user's preferences
     624              :      * @param map       New preferences
     625              :      */
     626              :     void updatePreferences(const std::map<std::string, std::string>& map);
     627              : 
     628              :     /**
     629              :      * Retrieve current infos (title, description, avatar, mode)
     630              :      * @return infos
     631              :      */
     632              :     std::map<std::string, std::string> infos() const;
     633              :     /**
     634              :      * Retrieve current preferences (color, notification, etc)
     635              :      * @param includeLastModified       If we want to know when the preferences were modified
     636              :      * @return preferences
     637              :      */
     638              :     std::map<std::string, std::string> preferences(bool includeLastModified) const;
     639              :     std::vector<uint8_t> vCard() const;
     640              : 
     641              :     /////// File transfer
     642              : 
     643              :     /**
     644              :      * Access to transfer manager
     645              :      */
     646              :     std::shared_ptr<TransferManager> dataTransfer() const;
     647              : 
     648              :     /**
     649              :      * Choose if we can accept channel request
     650              :      * @param member        member to check
     651              :      * @param fileId        file transfer to check (needs to be waiting)
     652              :      * @param verifyShaSum  for debug only
     653              :      * @return if we accept the channel request
     654              :      */
     655              :     bool onFileChannelRequest(const std::string& member,
     656              :                               const std::string& fileId,
     657              :                               std::filesystem::path& path,
     658              :                               std::string& sha3sum) const;
     659              :     /**
     660              :      * Adds a file to the waiting list and ask members
     661              :      * @param interactionId     Related interaction id
     662              :      * @param fileId            Related id
     663              :      * @param path              Destination
     664              :      * @param member            Member if we know from who to pull file
     665              :      * @param deviceId          Device if we know from who to pull file
     666              :      * @return id of the file
     667              :      */
     668              :     bool downloadFile(const std::string& interactionId,
     669              :                       const std::string& fileId,
     670              :                       const std::string& path,
     671              :                       const std::string& member = "",
     672              :                       const std::string& deviceId = "");
     673              : 
     674              :     /**
     675              :      * Reset fetched information
     676              :      */
     677              :     void clearFetched();
     678              :     /**
     679              :      * Store information about who fetch or not. This simplify sync (sync when a device without the
     680              :      * last fetch is detected)
     681              :      * @param deviceId
     682              :      * @param commitId
     683              :      */
     684              :     void hasFetched(const std::string& deviceId, const std::string& commitId);
     685              : 
     686              :     /**
     687              :      * Store last read commit (returned in getMembers)
     688              :      * @param uri               Of the member
     689              :      * @param interactionId     Last interaction displayed
     690              :      * @return if updated
     691              :      */
     692              :     bool setMessageDisplayed(const std::string& uri, const std::string& interactionId);
     693              :     /**
     694              :      * Retrieve last displayed and fetch status per member
     695              :      * @return A map with the following structure:
     696              :      * {uri, {
     697              :      *          {"fetch", "commitId"},
     698              :      *          {"fetched_ts", "timestamp"},
     699              :      *          {"read", "commitId"},
     700              :      *          {"read_ts", "timestamp"}
     701              :      *       }
     702              :      * }
     703              :      */
     704              :     std::map<std::string, std::map<std::string, std::string>> messageStatus() const;
     705              :     /**
     706              :      * Update fetch/read status
     707              :      * @param messageStatus     A map with the following structure:
     708              :      * {uri, {
     709              :      *          {"fetch", "commitId"},
     710              :      *          {"fetched_ts", "timestamp"},
     711              :      *          {"read", "commitId"},
     712              :      *          {"read_ts", "timestamp"}
     713              :      *       }
     714              :      * }
     715              :      */
     716              :     void updateMessageStatus(const std::map<std::string, std::map<std::string, std::string>>& messageStatus);
     717              :     void onMessageStatusChanged(
     718              :         const std::function<void(const std::map<std::string, std::map<std::string, std::string>>&)>& cb);
     719              :     /**
     720              :      * Retrieve how many interactions there is from HEAD to interactionId
     721              :      * @param toId      "" for getting the whole history
     722              :      * @param fromId    "" => HEAD
     723              :      * @param authorURI author to stop counting
     724              :      * @return number of interactions since interactionId
     725              :      */
     726              :     uint32_t countInteractions(const std::string& toId,
     727              :                                const std::string& fromId = "",
     728              :                                const std::string& authorUri = "") const;
     729              :     /**
     730              :      * Search in the conversation via a filter
     731              :      * @param req       Id of the request
     732              :      * @param filter    Parameters for the search
     733              :      * @param flag      To check when search is finished
     734              :      * @note triggers messagesFound
     735              :      */
     736              :     void search(uint32_t req, const Filter& filter, const std::shared_ptr<std::atomic_int>& flag) const;
     737              :     /**
     738              :      * Host a conference in the conversation
     739              :      * @note the message must have "confId"
     740              :      * @note Update hostedCalls_ and commit in the conversation
     741              :      * @param message       message to commit
     742              :      * @param cb            callback triggered when committed
     743              :      */
     744              :     void hostConference(CommitMessage&& message, OnDoneCb&& cb = {});
     745              :     /**
     746              :      * Announce the end of a call
     747              :      * @note the message must have "confId"
     748              :      * @note called when conference is finished
     749              :      * @param message       message to commit
     750              :      * @param cb            callback triggered when committed
     751              :      */
     752              :     void removeActiveConference(CommitMessage&& message, OnDoneCb&& cb = {});
     753              :     /**
     754              :      * Check if we're currently hosting this conference
     755              :      * @param confId
     756              :      * @return true if hosting
     757              :      */
     758              :     bool isHosting(const std::string& confId) const;
     759              :     /**
     760              :      * Return current detected calls
     761              :      * @return a vector of map with the following keys: "id", "uri", "device"
     762              :      */
     763              :     std::vector<std::map<std::string, std::string>> currentCalls() const;
     764              : 
     765              :     /**
     766              :      * Git operations will need a ChannelSocket for cloning/fetching commits
     767              :      * Because libgit2 is a C library, we store the pointer in the corresponding conversation
     768              :      * and the GitTransport will inject to libgit2 whenever needed
     769              :      */
     770              :     std::shared_ptr<dhtnet::ChannelSocket> gitSocket(const DeviceId& deviceId) const;
     771              :     void addGitSocket(const DeviceId& deviceId, const std::shared_ptr<dhtnet::ChannelSocket>& socket);
     772              :     /** If @p expected is set, only remove the socket if it is still the registered one. */
     773              :     void removeGitSocket(const DeviceId& deviceId, const std::shared_ptr<dhtnet::ChannelSocket>& expected = {});
     774              : 
     775              :     /**
     776              :      * Stop SwarmManager, bootstrap and gitSockets
     777              :      */
     778              :     void shutdownConnections();
     779              : 
     780              :     /**
     781              :      * If we change from one network to one another, we will need to update the state of the connections
     782              :      */
     783              :     void connectivityChanged();
     784              : 
     785              :     /**
     786              :      * @return getAllNodes()    Nodes that are linked to the conversation
     787              :      */
     788              :     std::vector<jami::DeviceId> getDeviceIdList() const;
     789              : 
     790              :     /**
     791              :      * Get Typers object
     792              :      * @return Typers object
     793              :      */
     794              :     std::shared_ptr<Typers> typers() const;
     795              : 
     796              :     /**
     797              :      * Get connectivity information for the conversation
     798              :      * @return map of connectivity info
     799              :      */
     800              :     std::vector<std::map<std::string, std::string>> getConnectivity() const;
     801              : 
     802              : private:
     803              :     std::shared_ptr<Conversation> shared() { return std::static_pointer_cast<Conversation>(shared_from_this()); }
     804              :     std::shared_ptr<Conversation const> shared() const
     805              :     {
     806              :         return std::static_pointer_cast<Conversation const>(shared_from_this());
     807              :     }
     808         4453 :     std::weak_ptr<Conversation> weak() { return std::static_pointer_cast<Conversation>(shared_from_this()); }
     809            0 :     std::weak_ptr<Conversation const> weak() const
     810              :     {
     811            0 :         return std::static_pointer_cast<Conversation const>(shared_from_this());
     812              :     }
     813              : 
     814              :     // Private because of weak()
     815              :     class Impl;
     816              :     std::unique_ptr<Impl> pimpl_;
     817              : };
     818              : 
     819              : } // namespace jami
        

Generated by: LCOV version 2.0-1