Skip to content
Snippets Groups Projects
Select Git revision
  • e0b3b4adec1fa0d3c49a4d656523cb170d10b52a
  • master default protected
  • stable/20250815.1
  • stable/20250815.0
  • nightly/20250815.0
  • nightly/20250806.0
  • nightly/20250805.0
  • beta/202508051403
  • beta/202508051107
  • nightly/20250722.0
  • beta/202507211539
  • stable/20250718.0
  • nightly/20250718.0
  • nightly/20250714.0
  • beta/202507141552
  • beta/202506161038
  • stable/20250613.0
  • nightly/20250613.0
  • beta/202506101658
  • stable/20250610.0
  • nightly/20250610.0
  • beta/202506091027
22 results

datatransfermodel.cpp

Blame
  • Amin Bandali's avatar
    Amin Bandali authored
    This is libjamiclient from the jami-libclient.git repository as of
    767c45b8b09806ac05cbada720864df93588c047, with the following changes:
    
    * src/libclient/newaccountmodel.cpp:
    (NewAccountModelPimpl::removeFromAccounts): The lock wait inside
    '#ifdef CHK_FREEABLE_BEFORE_ERASE_ACCOUNT' was not updated when the
    type of 'accounts' was changed over the years from this:
    std::map<std::string, account::Info>
    to this:
    std::map<QString, std::pair<account::Info, std::shared_ptr<Database>>>
    Basically we need to get the 'first' of the pair for 'account::Info'.
    So we now do that.
    
    * src/libclient/avmodel.cpp:
    * src/libclient/callbackshandler.cpp:
    * src/libclient/contactmodel.cpp:
    * src/libclient/conversationmodel.cpp:
    * src/libclient/database.cpp:
    * src/libclient/namedirectory.cpp:
    * src/libclient/newaccountmodel.cpp:
    * src/libclient/newcallmodel.cpp:
    * src/libclient/newdevicemodel.cpp:
    * src/libclient/peerdiscoverymodel.cpp:
    * src/libclient/pluginmodel.cpp:
    * src/libclient/smartinfohub.cpp:
    * src/libclient/vcard.h:
    * src/libclient/authority/storagehelper.cpp:  Replace Qt's 'foreach'
    with 'Q_FOREACH' and its 'emit' with 'Q_EMIT' because in the client-qt
    code base we have '-DQT_NO_KEYWORDS' to avoid conflicts with other
    libraries we use.
    
    * cmake/FindLibJami.cmake: Import cmake/FindRing.cmake from the
    jami-libclient.git repository.  Then, rename RING_BUILD_DIR to
    LIBJAMI_BUILD_DIR (though the old name is still supported for now).
    Also update other references of Ring to Jami.  Further, add additional
    calls to 'find_library' to make sure specified local paths for libjami
    are checked before system-wide ones (in case of older/obsolete libjami
    being available system-wide, which might happen on GNU/Linux systems).
    
    * translations/lrc_*.ts: Import translation files from the libclient
    repository.  The message location paths were corrected by running
    "sed -i 's|../src|&/libclient|g' lrc_*.ts" in 'translations/'.
    
    .tx/config: Add section for the newly-imported libclient translations.
    
    * CMakeLists.txt: Reformat, plus various fixes and cleanups, such as
    changing indentation to 2 spaces and wrapping lines at 70 characters,
    renaming the parent directory of translations from 'ring' to 'jami',
    and using all lowercase function calls.  Also add copyright headers.
    
    * src/app/appsettingsmanager.cpp:
    (AppSettingsManager::loadTranslations):
    * src/app/utilsadapter.cpp (UtilsAdapter::supportedLang): Update to
    adapt to the renaming of the parent directory of translations from
    'ring' to 'jami'.
    
    GitLab: #748
    Change-Id: I86e3b0fb30e554755023e7b858b6a0d132cd59ab
    e0b3b4ad
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    datatransfermodel.cpp 10.00 KiB
    /****************************************************************************
     *    Copyright (C) 2018-2022 Savoir-faire Linux Inc.                       *
     *   Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>       *
     *                                                                          *
     *   This library is free software; you can redistribute it and/or          *
     *   modify it under the terms of the GNU Lesser General Public             *
     *   License as published by the Free Software Foundation; either           *
     *   version 2.1 of the License, or (at your option) any later version.     *
     *                                                                          *
     *   This library is distributed in the hope that it will be useful,        *
     *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
     *   Lesser General Public License for more details.                        *
     *                                                                          *
     *   You should have received a copy of the GNU General Public License      *
     *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
     ***************************************************************************/
    
    // LRC
    #include "api/datatransfermodel.h"
    
    // Dbus
    #include "dbus/configurationmanager.h"
    
    // DRing
    #include <datatransfer_interface.h>
    
    // Std
    #include <map>
    #include <stdexcept>
    #include <type_traits>
    
    // Qt
    #include <QDir>
    #include <QFileInfo>
    #include <QtCore/QStandardPaths>
    #include <QUuid>
    
    namespace lrc {
    namespace api {
    
    // DRING to LRC event code conversion
    static inline datatransfer::Status
    convertDataTransferEvent(DRing::DataTransferEventCode event)
    {
        switch (event) {
        case DRing::DataTransferEventCode::invalid:
            return datatransfer::Status::INVALID;
        case DRing::DataTransferEventCode::created:
            return datatransfer::Status::on_connection;
        case DRing::DataTransferEventCode::unsupported:
            return datatransfer::Status::unsupported;
        case DRing::DataTransferEventCode::wait_peer_acceptance:
            return datatransfer::Status::on_connection;
        case DRing::DataTransferEventCode::wait_host_acceptance:
            return datatransfer::Status::on_connection;
        case DRing::DataTransferEventCode::ongoing:
            return datatransfer::Status::on_progress;
        case DRing::DataTransferEventCode::finished:
            return datatransfer::Status::success;
        case DRing::DataTransferEventCode::closed_by_host:
            return datatransfer::Status::stop_by_host;
        case DRing::DataTransferEventCode::closed_by_peer:
            return datatransfer::Status::stop_by_peer;
        case DRing::DataTransferEventCode::invalid_pathname:
            return datatransfer::Status::invalid_pathname;
        case DRing::DataTransferEventCode::unjoinable_peer:
            return datatransfer::Status::unjoinable_peer;
        case DRing::DataTransferEventCode::timeout_expired:
            return datatransfer::Status::timeout_expired;
        }
        throw std::runtime_error("BUG: broken convertDataTransferEvent() switch");
    }
    
    class DataTransferModel::Impl : public QObject
    {
        Q_OBJECT
    
    public:
        Impl(DataTransferModel& up_link);
    
        QString getUniqueFilePath(const QString& filename, const QString& path = "");
    
        DataTransferModel& upLink;
        MapStringString file2InteractionId;
        MapStringString interactionToFileId; // stricly the reverse map of file2InteractionId
    };
    
    DataTransferModel::Impl::Impl(DataTransferModel& up_link)
        : QObject {}
        , upLink {up_link}
    {}
    
    QString
    DataTransferModel::Impl::getUniqueFilePath(const QString& filename, const QString& path)
    {
        auto base = filename;
        QString ext = QFileInfo(base).completeSuffix();
        if (!ext.isEmpty())
            ext = ext.prepend(".");
    
        QFileInfo fi(filename);
        auto p = !path.isEmpty() ? path : fi.dir().path();
        base = QDir(p).filePath(fi.baseName() + ext);
        if (!QFile::exists(base))
            return base;
    
        base.chop(ext.size());
        QString ret;
        for (int suffix = 1;; suffix++) {
            ret = QString("%1 (%2)%3").arg(base).arg(suffix).arg(ext);
            if (!QFile::exists(ret)) {
                return ret;
            }
        }
    }
    
    void
    DataTransferModel::registerTransferId(const QString& fileId, const QString& interactionId)
    {
        pimpl_->file2InteractionId[fileId] = interactionId;
        pimpl_->interactionToFileId.remove(interactionId); // Because a file transfer can be retried
        pimpl_->interactionToFileId[interactionId] = fileId;
    }
    
    DataTransferModel::DataTransferModel()
        : QObject(nullptr)
        , pimpl_ {std::make_unique<Impl>(*this)}
    {}
    
    DataTransferModel::~DataTransferModel() = default;
    
    void
    DataTransferModel::transferInfo(const QString& accountId,
                                    const QString& fileId,
                                    datatransfer::Info& lrc_info)
    {
        DataTransferInfo infoFromDaemon;
        if (ConfigurationManager::instance().dataTransferInfo(accountId, fileId, infoFromDaemon) == 0) {
            lrc_info.uid = fileId;
            lrc_info.status = convertDataTransferEvent(
                DRing::DataTransferEventCode(infoFromDaemon.lastEvent));
            lrc_info.isOutgoing = !(infoFromDaemon.flags
                                    & (1 << uint32_t(DRing::DataTransferFlags::direction)));
            lrc_info.totalSize = infoFromDaemon.totalSize;
            lrc_info.progress = infoFromDaemon.bytesProgress;
            lrc_info.path = infoFromDaemon.path;
            lrc_info.displayName = infoFromDaemon.displayName;
            lrc_info.accountId = infoFromDaemon.accountId;
            lrc_info.peerUri = infoFromDaemon.peer;
            lrc_info.conversationId = infoFromDaemon.conversationId;
            // lrc_info.timestamp = ?
            return;
        }
    
        lrc_info.status = datatransfer::Status::INVALID;
    }
    
    void
    DataTransferModel::sendFile(const QString& accountId,
                                const QString& peer_uri,
                                const QString& conversationId,
                                const QString& filePath,
                                const QString& displayName)
    {
        if (conversationId.isEmpty()) {
            // Fallback
            DataTransferInfo info;
    #ifdef ENABLE_LIBWRAP
            DRing::DataTransferId id;
    #else
            qulonglong id;
    #endif
            info.accountId = accountId;
            info.peer = peer_uri;
            info.path = filePath;
            info.conversationId = conversationId;
            info.displayName = displayName;
            info.bytesProgress = 0;
            if (ConfigurationManager::instance().sendFileLegacy(info, id) != 0)
                qWarning() << "DataTransferModel::sendFile(), error";
            return;
        }
    
        ConfigurationManager::instance().sendFile(accountId,
                                                  conversationId,
                                                  filePath,
                                                  displayName,
                                                  {} /* TODO parent */);
    }
    
    void
    DataTransferModel::fileTransferInfo(const QString& accountId,
                                        const QString& conversationId,
                                        const QString& fileId,
                                        QString& path,
                                        qlonglong& total,
                                        qlonglong& progress)
    {
        ConfigurationManager::instance()
            .fileTransferInfo(accountId, conversationId, fileId, path, total, progress);
    }
    
    QString
    DataTransferModel::accept(const QString& accountId, const QString& fileId, const QString& filePath)
    {
        auto uniqueFilePath = pimpl_->getUniqueFilePath(filePath);
        auto daemonFileId = pimpl_->interactionToFileId[fileId];
        ConfigurationManager::instance().acceptFileTransfer(accountId, daemonFileId, uniqueFilePath);
        return uniqueFilePath;
    }
    
    void
    DataTransferModel::download(const QString& accountId,
                                const QString& convId,
                                const QString& interactionId,
                                const QString& fileId,
                                const QString& path)
    {
        ConfigurationManager::instance().downloadFile(accountId, convId, interactionId, fileId, path);
    }
    
    void
    DataTransferModel::copyTo(const QString& accountId,
                              const QString& convId,
                              const QString& interactionId,
                              const QString& destPath,
                              const QString& displayName)
    {
        auto fileId = getFileIdFromInteractionId(interactionId);
        if (fileId.isEmpty()) {
            qWarning() << "Cannot find any file for " << interactionId;
            return;
        }
        QString path;
        qlonglong total, progress;
    
        fileTransferInfo(accountId, convId, fileId, path, total, progress);
    
        auto src = QFile(path);
        auto srcfi = QFileInfo(path);
        if (!src.exists())
            return;
    
        auto filename = displayName;
        if (displayName.isEmpty())
            filename = srcfi.isSymLink() ? srcfi.symLinkTarget() : path;
        auto dest = pimpl_->getUniqueFilePath(filename, destPath);
        qDebug() << "Copy to " << dest;
        src.copy(dest);
    }
    
    void
    DataTransferModel::cancel(const QString& accountId,
                              const QString& conversationId,
                              const QString& interactionId)
    {
        ConfigurationManager::instance().cancelDataTransfer(accountId,
                                                            conversationId,
                                                            getFileIdFromInteractionId(interactionId));
    }
    
    QString
    DataTransferModel::getInteractionIdFromFileId(const QString& fileId)
    {
        return pimpl_->file2InteractionId[fileId];
    }
    
    QString
    DataTransferModel::getFileIdFromInteractionId(const QString& interactionId)
    {
        return pimpl_->interactionToFileId[interactionId];
    }
    
    QString
    DataTransferModel::createDefaultDirectory()
    {
        auto defaultDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)
                                + "/Jami";
        QDir dir(defaultDirectory);
        if (!dir.exists())
            dir.mkpath(".");
        return defaultDirectory;
    }
    
    } // namespace api
    } // namespace lrc
    
    #include "api/moc_datatransfermodel.cpp"
    #include "datatransfermodel.moc"