Contact management ================== This section will present how to find and add a contact from the DHT to the client. The usage of a name server will not be explained here. If you'd like more details about that, please read {doc}`name-server-protocol`. ## Presence on the network ### Announce the presence on the DHT The presence is pretty simple to announce on the DHT. In fact, it's just a value containing the device hash (see the previous section, {doc}`account-management`) on the hash corresponding to the fingerprint of the key. So, if we have the account `bf5f1e21d3eb2c1246946aa49d5dcf3e5b9cb1b9` with the device `62fbdff0ce86f368c7d3c2682539e5ba9e06404f`, the following defined value will be sent over the DHT: ```cpp /** * Device announcement stored on DHT. */ struct DeviceAnnouncement : public dht::SignedValue { private: using BaseClass = dht::SignedValue; public: static const constexpr dht::ValueType& TYPE = dht::ValueType::USER_DATA; dht::InfoHash dev; std::shared_ptr pk; MSGPACK_DEFINE_MAP(dev, pk) }; ``` (This value can be put with `dht_.put(h, VALUE, dht::DoneCallback{}, {}, true);`, as a permanent put). If the device is announced, the device is present. For now, there is no way to delete or edit a value on the DHT (this will come when OpenDHT will supports ECC). So, the presence always have a delay for now (mean delay: expire-time/2, so 2min30 for now). ### Get if a contact is present Now our presence on the network, it's time to get if somebody is present on the DHT. With the previous section, it's easy to do the reverse process. To know if somebody is present on the DHT (ex: `bf5f1e21d3eb2c1246946aa49d5dcf3e5b9cb1b9`), we have to get value at `bf5f1e21d3eb2c1246946aa49d5dcf3e5b9cb1b9` and retrieve the `DeviceAnnouncement` on this hash. The related code in the ring daemon is in `ringaccount.cpp`: ```cpp auto shared = std::static_pointer_cast(shared_from_this()); auto treatedDevices = std::make_shared>(); dht_.get(to, [to](dht::crypto::RevocationList&& crl){ tls::CertificateStore::instance().pinRevocationList(to.toString(), std::move(crl)); return true; }); dht_.get(to, [shared,to,treatedDevices,op](DeviceAnnouncement&& dev) { if (dev.from != to) return true; if (treatedDevices->emplace(dev.dev).second) op(shared, dev.dev); return true; }, [=](bool /*ok*/){ { std::lock_guard lock(shared->buddyInfoMtx); auto buddy_info_it = shared->trackedBuddies_.find(to); if (buddy_info_it != shared->trackedBuddies_.end()) { if (not treatedDevices->empty()) { for (auto& device_id : *treatedDevices) shared->onTrackedBuddyOnline(buddy_info_it, device_id); } else shared->onTrackedBuddyOffline(buddy_info_it); } } RING_DBG("[Account %s] found %lu devices for %s", getAccountID().c_str(), treatedDevices->size(), to.to_c_str()); if (end) end(shared, not treatedDevices->empty()); }); ``` And that's all. ### Client perspective ```xml Ask be be notified when 'uri' presence change An account from which get request presence informations A SIP uri to watch Notify when a registered presence uri presence informations changes The associated account The registered URI Is the URI present or not A string containing informations from the user (human readable) The account from which the presence will be emitted Is this account present or not A message transmitted by the server to other users ``` Are the main APIs for clients. `subscribeBuddy` will listen on the DHT to detect presence changes and `newBuddyNotification` will be sent whenever a new status is detected: + The status sent to the client is now 0=offline (no device found on the DHT), 1=dht_presence (at least a device is found on the DHT), 2=connected (with a TCP + SIP channel, so ready to exchange data). + `lineStatus` will contain any custom status sent by the peer (e.g. *Lunch Time!*) `publish` is used for publishing a custom note (`status` is ignored for Jami accounts, note will contain the custom status). RFC3863 is used to send status over the SIP connection. ## Pending request ### Send a request **TODO craft request** Finally, once the trust request is crafted, we can push the request to the following hash: `InfoHash("inbox:" + deviceId)` The following code is used in the daemon: ```cpp dht_.putEncrypted(dht::InfoHash::get("inbox:"+dev.toString()), dev, dht::TrustRequest(DHT_TYPE_NS, payload)); ``` ### Receiving a request **TODO** (Accept/Block/Discard) ## Daemon API All methods to follow the presence of a buddy is located in the `PresenceManager` such as: ```xml Notify when a registered presence uri presence informations changes The associated account The registered URI Is the URI present or not A string containing informations from the user (human readable) ``` All methods and signals used to manage trust requests and contacts are in the `ConfigurationManager` such as: ```xml A list of contact request details. Details: - from: account ID of sender - received: UNIX timestamp of reception date - payload: attached payload True if the operation succeeded. True if the operation succeeded. Notify clients that a new contact request has been received. True if the the contact should be banned. If false, the contact is removed from the contact list (banned or not). ``` If you want some examples, these methods are used into `contactmodel.cpp` in LRC.