/* * Copyright (c) 2021 Belledonne Communications SARL. * * This file is part of linphone-desktop * (see https://www.linphone.org). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 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 . */ #include "ContentModel.hpp" #include #include #include #include #include "app/App.hpp" #include "app/providers/ThumbnailProvider.hpp" #include "components/chat-events/ChatMessageModel.hpp" #include "components/conferenceInfo/ConferenceInfoModel.hpp" #include "components/core/CoreManager.hpp" #include "components/settings/SettingsModel.hpp" #include "utils/Utils.hpp" // ============================================================================= ContentModel::ContentModel(ChatMessageModel* chatModel) : mAppData(chatModel ? QString::fromStdString(chatModel->getChatMessage()->getAppdata()) : ""){ App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE mChatMessageModel = chatModel; mWasDownloaded = false; mFileOffset = 0; } ContentModel::ContentModel(std::shared_ptr content, ChatMessageModel* chatModel) : mAppData(chatModel ? QString::fromStdString(chatModel->getChatMessage()->getAppdata()) : ""){ App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE mChatMessageModel = chatModel; mWasDownloaded = false; mFileOffset = 0; setContent(content); } std::shared_ptr ContentModel::getContent()const{ return mContent; } ChatMessageModel * ContentModel::getChatMessageModel()const{ return mChatMessageModel; } quint64 ContentModel::getFileSize() const{ auto s = mContent->getFileSize(); return (quint64)s; } QString ContentModel::getName() const{ QString name = QString::fromStdString(mContent->getName()); if( name == "") { // Try to find the name from file Path QString fileName = QString::fromStdString(mContent->getFilePath()); if(fileName != ""){ name = QFileInfo(fileName).baseName(); } } return name; } QString ContentModel::getThumbnail() const{ return mThumbnail; } QString ContentModel::getFilePath() const{ return Utils::coreStringToAppString(mContent->getFilePath()); } QString ContentModel::getUtf8Text() const{ return QString::fromStdString(mContent->getUtf8Text()); } ConferenceInfoModel * ContentModel::getConferenceInfoModel(){ if( !mConferenceInfoModel && isIcalendar()){ auto conferenceInfo = linphone::Factory::get()->createConferenceInfoFromIcalendarContent(mContent); if(conferenceInfo) mConferenceInfoModel = ConferenceInfoModel::create(conferenceInfo); } return mConferenceInfoModel.get(); } void ContentModel::setFileOffset(quint64 fileOffset){ if( mFileOffset != fileOffset) { mFileOffset = fileOffset; emit fileOffsetChanged(); } } void ContentModel::setThumbnail(const QString& data){ if( mThumbnail != data) { mThumbnail = data; emit thumbnailChanged(); } } void ContentModel::setWasDownloaded(bool wasDownloaded){ if( mWasDownloaded != wasDownloaded) { mWasDownloaded = wasDownloaded; emit wasDownloadedChanged(); } } void ContentModel::setContent(std::shared_ptr content){ mContent = content; emit nameChanged(); mConferenceInfoModel = nullptr; if(isFile() || isFileEncrypted() || isFileTransfer() ){ QString path = Utils::coreStringToAppString(mContent->getFilePath()); if (!path.isEmpty()) createThumbnail(); } } bool ContentModel::isFile() const{ return mContent->isFile(); } bool ContentModel::isFileEncrypted() const{ return mContent->isFileEncrypted(); } bool ContentModel::isFileTransfer() const{ return mContent->isFileTransfer(); } bool ContentModel::isIcalendar() const{ return mContent->isIcalendar(); } bool ContentModel::isMultipart() const{ return mContent->isMultipart(); } bool ContentModel::isText() const{ return mContent->isText(); } bool ContentModel::isVoiceRecording()const{ return mContent->isVoiceRecording(); } int ContentModel::getFileDuration() const { return mContent->getFileDuration(); } // Create a thumbnail from the first content that have a file and store it in Appdata void ContentModel::createThumbnail (const bool& force) { if(force || isFile() || isFileEncrypted() || isFileTransfer()){ QString id; QString path = getFilePath(); if( path != ""){ setWasDownloaded( !path.isEmpty() && QFileInfo(path).isFile()); setThumbnail(QStringLiteral("image://%1/%2").arg(ThumbnailProvider::ProviderId).arg(path)); } } } void ContentModel::removeDownloadedFile(){ QString path = getFilePath(); if( path != ""){ QFile(path).remove(); } } void ContentModel::downloadFile(){ switch (mChatMessageModel->getState()) { case LinphoneEnums::ChatMessageStateDelivered: case LinphoneEnums::ChatMessageStateDeliveredToUser: case LinphoneEnums::ChatMessageStateDisplayed: case LinphoneEnums::ChatMessageStateFileTransferDone: break; case LinphoneEnums::ChatMessageStateFileTransferInProgress: return; default: qWarning() << QStringLiteral("Wrong message state when requesting downloading, state=%1.").arg(mChatMessageModel->getState()); } bool soFarSoGood; QString filename = getName();//mFileTransfertContent->getName(); const QString safeFilePath = Utils::getSafeFilePath( QStringLiteral("%1%2") .arg(CoreManager::getInstance()->getSettingsModel()->getDownloadFolder()) .arg(filename), &soFarSoGood ); if (!soFarSoGood) { qWarning() << QStringLiteral("Unable to create safe file path for: %1.").arg(filename); return; } mContent->setFilePath(Utils::appStringToCoreString(safeFilePath)); if( !mContent->isFileTransfer()){ QMessageBox::warning(nullptr, "Download File", "This file was already downloaded and is no more on the server. Your peer have to resend it if you want to get it"); }else { if (!mChatMessageModel->getChatMessage()->downloadContent(mContent)) qWarning() << QStringLiteral("Unable to download file of entry %1.").arg(filename); } } void ContentModel::cancelDownloadFile(){ if(mChatMessageModel && mChatMessageModel->getChatMessage()) { mChatMessageModel->getChatMessage()->cancelFileTransfer(); } } void ContentModel::openFile (bool showDirectory) { if (mChatMessageModel && ((!mWasDownloaded && !mChatMessageModel->isOutgoing()) || mContent->getFilePath() == "")) { downloadFile(); }else{ QFileInfo info( Utils::coreStringToAppString(mContent->getFilePath())); showDirectory = showDirectory || !info.exists(); if(!QDesktopServices::openUrl( QUrl(QStringLiteral("file:///%1").arg(showDirectory ? info.absolutePath() : info.absoluteFilePath())) ) && !showDirectory){ QDesktopServices::openUrl( QUrl(QStringLiteral("file:///%1").arg(info.absolutePath())) ); } } } bool ContentModel::saveAs (const QString& path){ QString cachePath = Utils::coreStringToAppString(mContent->exportPlainFile()); bool toDelete = true; bool result = false; if(cachePath.isEmpty()) { cachePath = Utils::coreStringToAppString(mContent->getFilePath()); toDelete = false; } if(!cachePath.isEmpty()) { QString decodedPath = QUrl::fromPercentEncoding(path.toUtf8()); QFile file(cachePath); QFile newFile(decodedPath); if(newFile.exists()) newFile.remove(); result = file.copy(decodedPath); if(toDelete) file.remove(); if(result) QDesktopServices::openUrl(QUrl(QStringLiteral("file:///%1").arg(decodedPath))); } return result; } void ContentModel::updateTransferData(){ }