jamiaccount: improve vCard synchronization

Because of the ConnectionManager, the daemon is now able to send
direct messages such as typing indications and read status. This
can be also used to move current features and improve it.

This patch is a first step to improve vCard syncing. The idea is
to send the vCard directly when a peer is connected. To avoid to
send the vCard everytime, a state is written in the cache directory.

In the future, a method to update the vCard as soon as the client
updates its profile will be possible.

Change-Id: I3801cbe04b3441f67ea6685aa2047e5a545958e5
parent 60926a66
......@@ -661,6 +661,18 @@
</arg>
</signal>
<signal name="profileReceived" tp:name-for-bindings="profileReceived">
<tp:added version="9.2.0"/>
<tp:docstring>
Notify clients that a vcard has been received
</tp:docstring>
<arg type="s" name="accountID"/>
<arg type="s" name="from"/>
<arg type="s" name="vcard"/>
</signal>
<method name="setIsComposing" tp:name-for-bindings="setIsComposing">
<tp:added version="7.9.0"/>
<tp:docstring>
......
......@@ -190,6 +190,7 @@ DBusClient::initLibrary(int flags)
exportable_callback<ConfigurationSignal::Error>(bind(&DBusConfigurationManager::errorAlert, confM, _1)),
exportable_callback<ConfigurationSignal::IncomingAccountMessage>(bind(&DBusConfigurationManager::incomingAccountMessage, confM, _1, _2, _3, _4 )),
exportable_callback<ConfigurationSignal::AccountMessageStatusChanged>(bind(&DBusConfigurationManager::accountMessageStatusChanged, confM, _1, _2, _3, _4 )),
exportable_callback<ConfigurationSignal::ProfileReceived>(bind(&DBusConfigurationManager::profileReceived, confM, _1, _2, _3 )),
exportable_callback<ConfigurationSignal::ComposingStatusChanged>(bind(&DBusConfigurationManager::composingStatusChanged, confM, _1, _2, _3 )),
exportable_callback<ConfigurationSignal::IncomingTrustRequest>(bind(&DBusConfigurationManager::incomingTrustRequest, confM, _1, _2, _3, _4 )),
exportable_callback<ConfigurationSignal::ContactAdded>(bind(&DBusConfigurationManager::contactAdded, confM, _1, _2, _3 )),
......
......@@ -35,6 +35,7 @@ public:
virtual void volatileAccountDetailsChanged(const std::string& account_id, const std::map<std::string, std::string>& details){}
virtual void incomingAccountMessage(const std::string& /*account_id*/, const std::string& /*message_id*/, const std::string& /*from*/, const std::map<std::string, std::string>& /*payload*/){}
virtual void accountMessageStatusChanged(const std::string& /*account_id*/, uint64_t /*message_id*/, const std::string& /*to*/, int /*state*/){}
virtual void profileReceived(const std::string& /*account_id*/, const std::string& /*from*/, const std::string& /*vCard*/){}
virtual void composingStatusChanged(const std::string& /*account_id*/, const std::string& /*from*/, int /*state*/){}
virtual void knownDevicesChanged(const std::string& /*account_id*/, const std::map<std::string, std::string>& /*devices*/){}
virtual void exportOnRingEnded(const std::string& /*account_id*/, int /*state*/, const std::string& /*pin*/){}
......@@ -243,6 +244,7 @@ public:
virtual void historyChanged(void){}
virtual void stunStatusFailure(const std::string& account_id){}
virtual void accountDetailsChanged(const std::string& account_id, const std::map<std::string, std::string>& details){}
virtual void profileReceived(const std::string& /*account_id*/, const std::string& /*from*/, const std::string& /*vCard*/) {}
virtual void registrationStateChanged(const std::string& account_id, const std::string& state, int code, const std::string& detail_str){}
virtual void volatileAccountDetailsChanged(const std::string& account_id, const std::map<std::string, std::string>& details){}
virtual void incomingAccountMessage(const std::string& /*account_id*/, const std::string& /*message_id*/, const std::string& /*from*/, const std::map<std::string, std::string>& /*payload*/){}
......
......@@ -264,6 +264,7 @@ void init(ConfigurationCallback* confM, Callback* callM, PresenceCallback* presM
exportable_callback<ConfigurationSignal::Error>(bind(&ConfigurationCallback::errorAlert, confM, _1)),
exportable_callback<ConfigurationSignal::IncomingAccountMessage>(bind(&ConfigurationCallback::incomingAccountMessage, confM, _1, _2, _3, _4 )),
exportable_callback<ConfigurationSignal::AccountMessageStatusChanged>(bind(&ConfigurationCallback::accountMessageStatusChanged, confM, _1, _2, _3, _4 )),
exportable_callback<ConfigurationSignal::ProfileReceived>(bind(&ConfigurationCallback::profileReceived, confM, _1, _2, _3 )),
exportable_callback<ConfigurationSignal::ComposingStatusChanged>(bind(&ConfigurationCallback::composingStatusChanged, confM, _1, _2, _3 )),
exportable_callback<ConfigurationSignal::IncomingTrustRequest>(bind(&ConfigurationCallback::incomingTrustRequest, confM, _1, _2, _3, _4 )),
exportable_callback<ConfigurationSignal::ContactAdded>(bind(&ConfigurationCallback::contactAdded, confM, _1, _2, _3 )),
......
......@@ -34,6 +34,7 @@ public:
virtual void volatileAccountDetailsChanged(const std::string& account_id, const std::map<std::string, std::string>& details){}
virtual void incomingAccountMessage(const std::string& /*account_id*/, const std::string& /*from*/, const std::map<std::string, std::string>& /*payload*/){}
virtual void accountMessageStatusChanged(const std::string& /*account_id*/, uint64_t /*message_id*/, const std::string& /*to*/, int /*state*/){}
virtual void profileReceived(const std::string& /*account_id*/, const std::string& /*from*/, const std::string& /*vCard*/){}
virtual void knownDevicesChanged(const std::string& /*account_id*/, const std::map<std::string, std::string>& /*devices*/){}
virtual void exportOnRingEnded(const std::string& /*account_id*/, int /*state*/, const std::string& /*pin*/){}
......@@ -233,6 +234,7 @@ public:
virtual void volatileAccountDetailsChanged(const std::string& account_id, const std::map<std::string, std::string>& details){}
virtual void incomingAccountMessage(const std::string& /*account_id*/, const std::string& /*from*/, const std::map<std::string, std::string>& /*payload*/){}
virtual void accountMessageStatusChanged(const std::string& /*account_id*/, uint64_t /*message_id*/, const std::string& /*to*/, int /*state*/){}
virtual void profileReceived(const std::string& /*account_id*/, const std::string& /*from*/, const std::string& /*vCard*/){}
virtual void knownDevicesChanged(const std::string& /*account_id*/, const std::map<std::string, std::string>& /*devices*/){}
virtual void exportOnRingEnded(const std::string& /*account_id*/, int /*state*/, const std::string& /*pin*/){}
......
......@@ -151,6 +151,7 @@ void init(const v8::Handle<v8::Value> &funcMap){
exportable_callback<ConfigurationSignal::KnownDevicesChanged>(bind(&knownDevicesChanged, _1, _2 )),
exportable_callback<ConfigurationSignal::IncomingAccountMessage>(bind(&incomingAccountMessage, _1, _2, _3, _4 )),
exportable_callback<ConfigurationSignal::AccountMessageStatusChanged>(bind(&accountMessageStatusChanged, _1, _2, _3, _4 )),
exportable_callback<ConfigurationSignal::ProfileReceived>(bind(&profileReceived, _1, _2, _3, _4 )),
exportable_callback<ConfigurationSignal::IncomingTrustRequest>(bind(&incomingTrustRequest, _1, _2, _3, _4 )),
};
......
......@@ -63,6 +63,7 @@ getSignalHandlers()
exported_callback<DRing::ConfigurationSignal::IncomingAccountMessage>(),
exported_callback<DRing::ConfigurationSignal::ComposingStatusChanged>(),
exported_callback<DRing::ConfigurationSignal::AccountMessageStatusChanged>(),
exported_callback<DRing::ConfigurationSignal::ProfileReceived>(),
exported_callback<DRing::ConfigurationSignal::IncomingTrustRequest>(),
exported_callback<DRing::ConfigurationSignal::ContactAdded>(),
exported_callback<DRing::ConfigurationSignal::ContactRemoved>(),
......
......@@ -55,13 +55,13 @@ generateUID()
}
constexpr const uint32_t MAX_BUFFER_SIZE {65534}; /* Channeled max packet size */
//==============================================================================
class DataTransfer : public Stream
{
public:
DataTransfer(DRing::DataTransferId id) : Stream(), id {id} {}
DataTransfer(DRing::DataTransferId id, InternalCompletionCb cb = {})
: Stream(), id {id}, internalCompletionCb_ {std::move(cb)} {}
virtual ~DataTransfer() = default;
......@@ -116,11 +116,14 @@ protected:
mutable DRing::DataTransferInfo info_;
mutable std::atomic_bool started_ {false};
std::atomic_bool wasStarted_ {false};
InternalCompletionCb internalCompletionCb_ {};
};
void
DataTransfer::emit(DRing::DataTransferEventCode code) const
{
if (internalCompletionCb_)
return; // VCard transfer is just for the daemon
{
std::lock_guard<std::mutex> lk {infoMutex_};
info_.lastEvent = code;
......@@ -253,7 +256,10 @@ OptimisticMetaOutgoingInfo::info() const
class SubOutgoingFileTransfer final : public DataTransfer
{
public:
SubOutgoingFileTransfer(DRing::DataTransferId tid, const std::string& peerUri, std::shared_ptr<OptimisticMetaOutgoingInfo> metaInfo);
SubOutgoingFileTransfer(DRing::DataTransferId tid,
const std::string& peerUri,
const InternalCompletionCb& cb,
std::shared_ptr<OptimisticMetaOutgoingInfo> metaInfo);
~SubOutgoingFileTransfer();
void close() noexcept override;
......@@ -316,6 +322,7 @@ private:
onRecvCb_(std::move(buf));
}
JAMI_DBG() << "FTP#" << getId() << ": sent " << info_.bytesProgress << " bytes";
if (internalCompletionCb_) internalCompletionCb_(info_.path);
emit(DRing::DataTransferEventCode::finished);
});
}
......@@ -334,8 +341,9 @@ private:
SubOutgoingFileTransfer::SubOutgoingFileTransfer(DRing::DataTransferId tid,
const std::string& peerUri,
const InternalCompletionCb& cb,
std::shared_ptr<OptimisticMetaOutgoingInfo> metaInfo)
: DataTransfer(tid), metaInfo_(std::move(metaInfo)), peerUri_(peerUri)
: DataTransfer(tid, cb), metaInfo_(std::move(metaInfo)), peerUri_(peerUri)
{
info_ = metaInfo_->info();
......@@ -457,11 +465,11 @@ SubOutgoingFileTransfer::emit(DRing::DataTransferEventCode code) const
class OutgoingFileTransfer final : public DataTransfer
{
public:
OutgoingFileTransfer(DRing::DataTransferId tid, const DRing::DataTransferInfo& info);
OutgoingFileTransfer(DRing::DataTransferId tid, const DRing::DataTransferInfo& info, const InternalCompletionCb& cb);
~OutgoingFileTransfer() {}
std::shared_ptr<DataTransfer> startNewOutgoing(const std::string& peer_uri) {
auto newTransfer = std::make_shared<SubOutgoingFileTransfer>(id, peer_uri, this->metaInfo_);
auto newTransfer = std::make_shared<SubOutgoingFileTransfer>(id, peer_uri, internalCompletionCb_, metaInfo_);
subtransfer_.emplace_back(newTransfer);
newTransfer->start();
return newTransfer;
......@@ -502,8 +510,8 @@ private:
mutable std::vector<std::shared_ptr<SubOutgoingFileTransfer>> subtransfer_;
};
OutgoingFileTransfer::OutgoingFileTransfer(DRing::DataTransferId tid, const DRing::DataTransferInfo& info)
: DataTransfer(tid)
OutgoingFileTransfer::OutgoingFileTransfer(DRing::DataTransferId tid, const DRing::DataTransferInfo& info, const InternalCompletionCb& cb)
: DataTransfer(tid, cb)
{
fileutils::openStream(input_, info.path, std::ios::binary);
if (!input_)
......@@ -533,7 +541,10 @@ OutgoingFileTransfer::close() noexcept
class IncomingFileTransfer final : public DataTransfer
{
public:
IncomingFileTransfer(DRing::DataTransferId, const DRing::DataTransferInfo&, DRing::DataTransferId);
IncomingFileTransfer(DRing::DataTransferId,
const DRing::DataTransferInfo&,
DRing::DataTransferId,
const InternalCompletionCb& cb);
bool start() override;
......@@ -561,8 +572,9 @@ private:
IncomingFileTransfer::IncomingFileTransfer(DRing::DataTransferId tid,
const DRing::DataTransferInfo& info,
DRing::DataTransferId internalId)
: DataTransfer(tid), internalId_(internalId)
DRing::DataTransferId internalId,
const InternalCompletionCb& cb)
: DataTransfer(tid, cb), internalId_(internalId)
{
JAMI_WARN() << "[FTP] incoming transfert of " << info.totalSize << " byte(s): " << info.displayName;
......@@ -576,8 +588,16 @@ IncomingFileTransfer::requestFilename()
emit(DRing::DataTransferEventCode::wait_host_acceptance);
#if 1
// Now wait for DataTransferFacade::acceptFileTransfer() call
filenamePromise_.get_future().wait();
if (internalCompletionCb_) {
std::string filename = fileutils::get_cache_dir() + DIR_SEPARATOR_STR + std::to_string(id);
fileutils::ofstream(filename);
if (not fileutils::isFile(filename))
throw std::system_error(errno, std::generic_category());
info_.path = filename;
} else {
// Now wait for DataTransferFacade::acceptFileTransfer() call
filenamePromise_.get_future().wait();
}
#else
// For DEBUG only
char filename[] = "/tmp/ring_XXXXXX";
......@@ -622,8 +642,13 @@ IncomingFileTransfer::close() noexcept
JAMI_DBG() << "[FTP] file closed, rx " << info_.bytesProgress
<< " on " << info_.totalSize;
if (info_.bytesProgress >= info_.totalSize)
emit(DRing::DataTransferEventCode::finished);
if (info_.bytesProgress >= info_.totalSize) {
if (internalCompletionCb_) {
internalCompletionCb_(info_.path);
} else {
emit(DRing::DataTransferEventCode::finished);
}
}
else
emit(DRing::DataTransferEventCode::closed_by_host);
}
......@@ -664,8 +689,9 @@ public:
std::unordered_map<DRing::DataTransferId, std::shared_ptr<DataTransfer>> map_;
std::shared_ptr<DataTransfer> createOutgoingFileTransfer(const DRing::DataTransferInfo& info,
DRing::DataTransferId& tid);
std::shared_ptr<IncomingFileTransfer> createIncomingFileTransfer(const DRing::DataTransferInfo&, const DRing::DataTransferId&);
DRing::DataTransferId& tid,
InternalCompletionCb cb = {});
std::shared_ptr<IncomingFileTransfer> createIncomingFileTransfer(const DRing::DataTransferInfo&, const DRing::DataTransferId&, InternalCompletionCb cb);
std::shared_ptr<DataTransfer> getTransfer(const DRing::DataTransferId&);
void cancel(DataTransfer&);
void onConnectionRequestReply(const DRing::DataTransferId&, PeerConnection*);
......@@ -689,10 +715,11 @@ DataTransferFacade::Impl::getTransfer(const DRing::DataTransferId& id)
std::shared_ptr<DataTransfer>
DataTransferFacade::Impl::createOutgoingFileTransfer(const DRing::DataTransferInfo& info,
DRing::DataTransferId& tid)
DRing::DataTransferId& tid,
InternalCompletionCb cb)
{
tid = generateUID();
auto transfer = std::make_shared<OutgoingFileTransfer>(tid, info);
auto transfer = std::make_shared<OutgoingFileTransfer>(tid, info, cb);
{
std::lock_guard<std::mutex> lk {mapMutex_};
map_.emplace(tid, transfer);
......@@ -702,10 +729,10 @@ DataTransferFacade::Impl::createOutgoingFileTransfer(const DRing::DataTransferIn
}
std::shared_ptr<IncomingFileTransfer>
DataTransferFacade::Impl::createIncomingFileTransfer(const DRing::DataTransferInfo& info, const DRing::DataTransferId& internal_id)
DataTransferFacade::Impl::createIncomingFileTransfer(const DRing::DataTransferInfo& info, const DRing::DataTransferId& internal_id, InternalCompletionCb cb)
{
auto tid = generateUID();
auto transfer = std::make_shared<IncomingFileTransfer>(tid, info, internal_id);
auto transfer = std::make_shared<IncomingFileTransfer>(tid, info, internal_id, cb);
{
std::lock_guard<std::mutex> lk {mapMutex_};
map_.emplace(tid, transfer);
......@@ -754,7 +781,8 @@ DataTransferFacade::list() const noexcept
DRing::DataTransferError
DataTransferFacade::sendFile(const DRing::DataTransferInfo& info,
DRing::DataTransferId& tid) noexcept
DRing::DataTransferId& tid,
const InternalCompletionCb& cb) noexcept
{
auto account = Manager::instance().getAccount<JamiAccount>(info.accountId);
if (!account) {
......@@ -768,7 +796,7 @@ DataTransferFacade::sendFile(const DRing::DataTransferInfo& info,
}
try {
pimpl_->createOutgoingFileTransfer(info, tid);
pimpl_->createOutgoingFileTransfer(info, tid, cb);
} catch (const std::exception& ex) {
JAMI_ERR() << "[XFER] exception during createFileTransfer(): " << ex.what();
return DRing::DataTransferError::io;
......@@ -780,7 +808,7 @@ DataTransferFacade::sendFile(const DRing::DataTransferInfo& info,
// Example: Ring account supports multi-devices, each can answer to the request.
// NOTE: this will create a PeerConnection for each files. This connection need to be shut when finished
account->requestPeerConnection(
info.peer, tid,
info.peer, tid, static_cast<bool>(cb),
[this, tid] (PeerConnection* connection) {
pimpl_->onConnectionRequestReply(tid, connection);
},
......@@ -879,9 +907,11 @@ DataTransferFacade::info(const DRing::DataTransferId& id,
}
DRing::DataTransferId
DataTransferFacade::createIncomingTransfer(const DRing::DataTransferInfo &info, const DRing::DataTransferId& internal_id)
DataTransferFacade::createIncomingTransfer(const DRing::DataTransferInfo &info,
const DRing::DataTransferId& internal_id,
const InternalCompletionCb& cb)
{
auto transfer = pimpl_->createIncomingFileTransfer(info, internal_id);
auto transfer = pimpl_->createIncomingFileTransfer(info, internal_id, cb);
if (!transfer)
return {};
return transfer->getId();
......
......@@ -34,6 +34,8 @@ struct IncomingFileInfo {
std::shared_ptr<Stream> stream;
};
typedef std::function<void(const std::string&)> InternalCompletionCb;
/// Front-end to data transfer service
class DataTransferFacade
{
......@@ -46,7 +48,8 @@ public:
/// \see DRing::sendFile
DRing::DataTransferError sendFile(const DRing::DataTransferInfo& info,
DRing::DataTransferId& id) noexcept;
DRing::DataTransferId& id,
const InternalCompletionCb& cb = {}) noexcept;
/// \see DRing::acceptFileTransfer
DRing::DataTransferError acceptAsFile(const DRing::DataTransferId& id,
......@@ -68,7 +71,9 @@ public:
int64_t& progress) const noexcept;
/// Used by p2p.cpp
DRing::DataTransferId createIncomingTransfer(const DRing::DataTransferInfo &info, const DRing::DataTransferId& internal_id);
DRing::DataTransferId createIncomingTransfer(const DRing::DataTransferInfo &info,
const DRing::DataTransferId& internal_id,
const InternalCompletionCb& cb);
/// Create an IncomingFileTransfer object.
/// \return a shared pointer on created Stream object, or nullptr in case of error
......
......@@ -294,6 +294,10 @@ struct DRING_PUBLIC ConfigurationSignal {
constexpr static const char* name = "AccountMessageStatusChanged";
using cb_type = void(const std::string& /*account_id*/, uint64_t /*message_id*/, const std::string& /*to*/, int /*state*/);
};
struct DRING_PUBLIC ProfileReceived {
constexpr static const char* name = "ProfileReceived";
using cb_type = void(const std::string& /*account_id*/, const std::string& /*from*/, const std::string& /*vcard*/);
};
struct DRING_PUBLIC ComposingStatusChanged {
constexpr static const char* name = "ComposingStatusChanged";
using cb_type = void(const std::string& /*account_id*/, const std::string& /*from*/, int /*status*/);
......
......@@ -86,6 +86,9 @@
#include <cstddef>
#include <ciso646>
#include <pj/ctype.h>
#include <pjlib-util/md5.h>
namespace jami { namespace fileutils {
// returns true if directory exists
......@@ -973,6 +976,31 @@ ofstream(const std::string& path, std::ios_base::openmode mode)
#endif
}
std::string
md5File(const std::string& path)
{
return md5sum(loadFile(path));
}
std::string
md5sum(const std::vector<uint8_t>& buffer)
{
pj_md5_context pms;
pj_md5_init(&pms);
pj_md5_update(&pms, (const uint8_t*)buffer.data(), buffer.size());
unsigned char digest[16];
pj_md5_final(&pms, digest);
char hash[32];
for (int i = 0; i < 16; ++i)
pj_val_to_hex_digit(digest[i], &hash[2 * i]);
return {hash, 32};
}
int
accessFile(const std::string& file, int mode)
{
......
......@@ -154,6 +154,9 @@ void openStream(std::ofstream& file, const std::string& path, std::ios_base::ope
std::ifstream ifstream(const std::string& path, std::ios_base::openmode mode = std::ios_base::in);
std::ofstream ofstream(const std::string& path, std::ios_base::openmode mode = std::ios_base::out);
std::string md5File(const std::string& path);
std::string md5sum(const std::vector<uint8_t>& buffer);
/**
* Windows compatibility wrapper for checking read-only attribute
*/
......
......@@ -36,11 +36,13 @@ namespace jami {
FtpServer::FtpServer(const std::string& account_id,
const std::string& peer_uri,
const DRing::DataTransferId& outId)
const DRing::DataTransferId& outId,
InternalCompletionCb&& cb)
: Stream()
, accountId_ {account_id}
, peerUri_ {peer_uri}
, outId_ {outId}
, cb_ {std::move(cb)}
{}
DRing::DataTransferId
......@@ -71,7 +73,7 @@ FtpServer::startNewFile()
info.totalSize = fileSize_;
info.bytesProgress = 0;
rx_ = 0;
transferId_ = Manager::instance().dataTransfers->createIncomingTransfer(info, outId_); // return immediately
transferId_ = Manager::instance().dataTransfers->createIncomingTransfer(info, outId_, cb_); // return immediately
isTreatingRequest_ = true;
out_ = Manager::instance().dataTransfers->onIncomingFileRequest(transferId_); // we block here until answer from client
isTreatingRequest_ = false;
......
......@@ -35,7 +35,10 @@ using RecvCb = std::function<void(std::vector<uint8_t>&& buf)>;
class FtpServer final : public Stream
{
public:
FtpServer(const std::string& account_id, const std::string& peer_uri, const DRing::DataTransferId& outId = 0);
FtpServer(const std::string& account_id,
const std::string& peer_uri,
const DRing::DataTransferId& outId = 0,
InternalCompletionCb&& cb = {});
bool read(std::vector<uint8_t>& buffer) const override;
bool write(const std::vector<uint8_t>& buffer) override;
......@@ -60,6 +63,7 @@ private:
const std::string accountId_;
const std::string peerUri_;
std::atomic_bool isVCard_ {false};
std::atomic_bool isTreatingRequest_ {false};
DRing::DataTransferId transferId_ {0};
IncomingFileInfo out_ {0, nullptr};
......@@ -74,6 +78,7 @@ private:
FtpState state_ {FtpState::PARSE_HEADERS};
RecvCb onRecvCb_ {};
InternalCompletionCb cb_ {};
};
} // namespace jami
......@@ -69,6 +69,7 @@
#include "string_utils.h"
#include "array_size.h"
#include "archiver.h"
#include "data_transfer.h"
#include "config/yamlparser.h"
#include "security/certstore.h"
......@@ -119,6 +120,12 @@ struct TextMessageCtx {
std::shared_ptr<PendingConfirmation> confirmation;
};
struct VCardMessageCtx {
std::shared_ptr<std::atomic_int> success;
int total;
std::string path;
};
namespace Migration {
enum class State { // Contains all the Migration states
......@@ -2014,10 +2021,12 @@ JamiAccount::doRegister_()
return result;
});
connectionManager_->onChannelRequest([this](const std::string& /* deviceId */, const std::string& name) {
auto isFile = name.substr(0, 7) == "file://";
auto isVCard = name.substr(0, 8) == "vcard://";
if (name == "sip") {
return true;
} else if (name.substr(0, 7) == "file://") {
auto tid_str = name.substr(7);
} else if (isFile or isVCard) {
auto tid_str = isFile? name.substr(7) : name.substr(8);
uint64_t tid;
std::istringstream iss(tid_str);
iss >> tid;
......@@ -2033,10 +2042,12 @@ JamiAccount::doRegister_()
auto cert = tls::CertificateStore::instance().getCertificate(deviceId);
if (!cert || !cert->issuer) return;
auto peerId = cert->issuer->getId().toString();
auto isFile = name.substr(0, 7) == "file://";
auto isVCard = name.substr(0, 8) == "vcard://";
if (name == "sip") {
cacheSIPConnection(std::move(channel), peerId, deviceId);
} else if (name.substr(0, 7) == "file://") {
auto tid_str = name.substr(7);
} else if (isFile or isVCard) {
auto tid_str = isFile? name.substr(7) : name.substr(8);
auto it = incomingFileTransfers_.find(tid_str);
// Note, outgoing file transfers are ignored.
if (it == incomingFileTransfers_.end()) return;
......@@ -2044,7 +2055,12 @@ JamiAccount::doRegister_()
uint64_t tid;
std::istringstream iss(tid_str);
iss >> tid;
dhtPeerConnector_->onIncomingConnection(peerId, tid, std::move(channel));
dhtPeerConnector_->onIncomingConnection(peerId, tid, std::move(channel),
[peerId, accountId=getAccountID()](const std::string& path) {
auto vCard = fileutils::loadTextFile(path);
emitSignal<DRing::ConfigurationSignal::ProfileReceived>(accountId, peerId, vCard);
fileutils::remove(path, true);
});
}
}
});
......@@ -2801,94 +2817,17 @@ JamiAccount::sendTextMessage(const std::string& to, const std::map<std::string,
}
auto& it = deviceConnIt->second.back();
auto transport = it.transport;
auto channel = it.channel;
if (!channel || !channel->underlyingICE()) {
messageEngine_.onMessageSent(to, token, false);
JAMI_WARN("A SIP transport exists without Channel, this is a bug. Please report");
// Remove connection in incorrect state
deviceConnIt = sipConns.erase(deviceConnIt);
continue;
}
// Build SIP Message
// "deviceID@IP"
auto toURI = getToUri(to + "@" + channel->underlyingICE()->getRemoteAddress(0).toString(true));
std::string from = getFromUri();
pjsip_tx_data* tdata;
// Build SIP message
constexpr pjsip_method msg_method = {PJSIP_OTHER_METHOD, jami::sip_utils::CONST_PJ_STR("MESSAGE")};
pj_str_t pjFrom = pj_str((char*) from.c_str());
pj_str_t pjTo = pj_str((char*) toURI.c_str());
// Create request.
pj_status_t status = pjsip_endpt_create_request(link_.getEndpoint(), &msg_method,
&pjTo, &pjFrom, &pjTo, nullptr, nullptr, -1,
nullptr, &tdata);
if (status != PJ_SUCCESS) {
JAMI_ERR("Unable to create request: %s", sip_utils::sip_strerror(status).c_str());
messageEngine_.onMessageSent(to, token, false);
++deviceConnIt;
continue;
}
// Add Date Header.
pj_str_t date_str;
constexpr auto key = sip_utils::CONST_PJ_STR("Date");
pjsip_hdr *hdr;
auto time = std::time(nullptr);
auto date = std::ctime(&time);
// the erase-remove idiom for a cstring, removes _all_ new lines with in date
*std::remove(date, date+strlen(date), '\n') = '\0';
// Add Header
hdr = reinterpret_cast<pjsip_hdr*>(pjsip_date_hdr_create(tdata->pool, &key, pj_cstr(&date_str, date)));
pjsip_msg_add_hdr(tdata->msg, hdr);
// https://tools.ietf.org/html/rfc5438#section-6.3
auto token_str = to_hex_string(token);
auto pjMessageId = sip_utils::CONST_PJ_STR(token_str);
hdr = reinterpret_cast<pjsip_hdr*>(pjsip_generic_string_hdr_create(tdata->pool, &STR_MESSAGE_ID, &pjMessageId));
pjsip_msg_add_hdr(tdata->msg, hdr);
// Add user agent header.
pjsip_hdr *hdr_list;
constexpr auto pJuseragent = sip_utils::CONST_PJ_STR("Jami");
constexpr pj_str_t STR_USER_AGENT = jami::sip_utils::CONST_PJ_STR("User-Agent");
// Add Header
hdr_list = reinterpret_cast<pjsip_hdr*>(pjsip_user_agent_hdr_create(tdata->pool, &STR_USER_AGENT, &pJuseragent));
pjsip_msg_add_hdr(tdata->msg, hdr_list);
// Init tdata
const pjsip_tpselector tp_sel = SIPVoIPLink::getTransportSelector(transport->get());
status = pjsip_tx_data_set_transport(tdata, &tp_sel);
if (status != PJ_SUCCESS) {
JAMI_ERR("Unable to create request: %s", sip_utils::sip_strerror(status).c_str());
messageEngine_.onMessageSent(to, token, false);
++