File indexing completed on 2024-05-12 05:20:58
0001 /* 0002 SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 #include "notesmanager.h" 0007 #include "akonadi/noteschangerecorder.h" 0008 #include "attributes/notealarmattribute.h" 0009 #include "attributes/notedisplayattribute.h" 0010 #include "attributes/notelockattribute.h" 0011 #include "job/createnewnotejob.h" 0012 #include "network/notesnetworkreceiver.h" 0013 #include "notesharedglobalconfig.h" 0014 0015 #include <Akonadi/ChangeRecorder> 0016 #include <Akonadi/Collection> 0017 #include <Akonadi/CollectionFetchJob> 0018 #include <Akonadi/CollectionFetchScope> 0019 #include <Akonadi/ItemFetchJob> 0020 #include <Akonadi/ItemFetchScope> 0021 #include <Akonadi/NoteUtils> 0022 #include <Akonadi/Session> 0023 0024 #include <KMime/KMimeMessage> 0025 0026 #include <KLocalizedString> 0027 #include <KNotification> 0028 0029 #include <QDateTime> 0030 #include <QTcpServer> 0031 #include <QTimer> 0032 0033 NotesManager::NotesManager(QObject *parent) 0034 : QObject(parent) 0035 , mSession(new Akonadi::Session("KNotes Session", this)) 0036 { 0037 mNoteRecorder = new NoteShared::NotesChangeRecorder(this); 0038 mNoteRecorder->changeRecorder()->setSession(mSession); 0039 connect(mNoteRecorder->changeRecorder(), &Akonadi::Monitor::itemAdded, this, &NotesManager::slotItemAdded); 0040 connect(mNoteRecorder->changeRecorder(), &Akonadi::Monitor::itemChanged, this, &NotesManager::slotItemChanged); 0041 connect(mNoteRecorder->changeRecorder(), &Akonadi::Monitor::itemRemoved, this, &NotesManager::slotItemRemoved); 0042 0043 auto job = new Akonadi::CollectionFetchJob(Akonadi::Collection::root(), Akonadi::CollectionFetchJob::Recursive, mSession); 0044 job->fetchScope().setContentMimeTypes({Akonadi::NoteUtils::noteMimeType()}); 0045 job->fetchScope().setFetchIdOnly(true); 0046 connect(job, &Akonadi::CollectionFetchJob::collectionsReceived, this, &NotesManager::slotCollectionsReceived); 0047 } 0048 0049 NotesManager::~NotesManager() 0050 { 0051 clear(); 0052 } 0053 0054 void NotesManager::clear() 0055 { 0056 delete mListener; 0057 mListener = nullptr; 0058 if (mCheckAlarm && mCheckAlarm->isActive()) { 0059 mCheckAlarm->stop(); 0060 } 0061 } 0062 0063 void NotesManager::slotCollectionsReceived(const Akonadi::Collection::List &collections) 0064 { 0065 for (const Akonadi::Collection &col : collections) { 0066 if (!col.contentMimeTypes().contains(Akonadi::NoteUtils::noteMimeType())) { 0067 continue; 0068 } 0069 auto job = new Akonadi::ItemFetchJob(col, mSession); 0070 job->setDeliveryOption(Akonadi::ItemFetchJob::EmitItemsInBatches); 0071 job->fetchScope().fetchAttribute<NoteShared::NoteAlarmAttribute>(); 0072 job->fetchScope().fetchAttribute<NoteShared::NoteLockAttribute>(); 0073 job->fetchScope().fetchAttribute<NoteShared::NoteDisplayAttribute>(); 0074 job->fetchScope().fetchAttribute<NoteShared::NoteAlarmAttribute>(); 0075 job->fetchScope().fetchFullPayload(true); 0076 connect(job, &Akonadi::ItemFetchJob::itemsReceived, this, [this](const Akonadi::Item::List &items) { 0077 for (const Akonadi::Item &item : items) { 0078 slotItemAdded(item); 0079 } 0080 }); 0081 } 0082 } 0083 0084 void NotesManager::slotItemAdded(const Akonadi::Item &item) 0085 { 0086 if (item.hasAttribute<NoteShared::NoteAlarmAttribute>()) { 0087 mListItem.append(item); 0088 } 0089 } 0090 0091 void NotesManager::slotItemRemoved(const Akonadi::Item &item) 0092 { 0093 mListItem.removeAll(item); 0094 } 0095 0096 void NotesManager::slotItemChanged(const Akonadi::Item &item, const QSet<QByteArray> &set) 0097 { 0098 if (set.contains("ATR:NoteAlarmAttribute")) { 0099 mListItem.removeAll(item); 0100 if (item.hasAttribute<NoteShared::NoteAlarmAttribute>()) { 0101 mListItem.append(item); 0102 } else { 0103 if (mAlarmDialog) { 0104 mAlarmDialog->removeAlarm(item); 0105 } 0106 } 0107 } 0108 } 0109 0110 void NotesManager::slotCheckAlarm() 0111 { 0112 QDateTime from = NoteShared::NoteSharedGlobalConfig::self()->alarmsLastChecked().addSecs(1); 0113 if (!from.isValid()) { 0114 from.setSecsSinceEpoch(0); 0115 } 0116 0117 const QDateTime now = QDateTime::currentDateTime(); 0118 NoteShared::NoteSharedGlobalConfig::self()->setAlarmsLastChecked(now); 0119 0120 Akonadi::Item::List lst; 0121 for (const Akonadi::Item &item : std::as_const(mListItem)) { 0122 const auto attrAlarm = item.attribute<NoteShared::NoteAlarmAttribute>(); 0123 if (attrAlarm) { 0124 if (attrAlarm->dateTime() < QDateTime::currentDateTime()) { 0125 lst.append(item); 0126 } 0127 } 0128 } 0129 if (!lst.isEmpty()) { 0130 if (!mAlarmDialog) { 0131 mAlarmDialog = new NotesAgentAlarmDialog; 0132 } 0133 mAlarmDialog->addListAlarm(lst); 0134 mAlarmDialog->show(); 0135 } 0136 mCheckAlarm->start(); 0137 } 0138 0139 void NotesManager::load() 0140 { 0141 updateNetworkListener(); 0142 if (!mCheckAlarm) { 0143 mCheckAlarm = new QTimer(this); 0144 } else if (mCheckAlarm->isActive()) { 0145 mCheckAlarm->stop(); 0146 } 0147 0148 mCheckAlarm->setInterval(1000 * 60 * NoteShared::NoteSharedGlobalConfig::checkInterval()); 0149 connect(mCheckAlarm, &QTimer::timeout, this, &NotesManager::slotCheckAlarm); 0150 slotCheckAlarm(); 0151 } 0152 0153 void NotesManager::stopAll() 0154 { 0155 clear(); 0156 } 0157 0158 void NotesManager::slotAcceptConnection() 0159 { 0160 // Accept the connection and make KNotesNetworkReceiver do the job 0161 QTcpSocket *s = mListener->nextPendingConnection(); 0162 0163 if (s) { 0164 auto recv = new NoteShared::NotesNetworkReceiver(s); 0165 connect(recv, &NoteShared::NotesNetworkReceiver::sigNoteReceived, this, &NotesManager::slotNewNote); 0166 } 0167 } 0168 0169 void NotesManager::slotNewNote(const QString &name, const QString &text) 0170 { 0171 KNotification::event(QStringLiteral("receivednotes"), 0172 QString(), 0173 i18n("Note Received"), 0174 QStringLiteral("knotes"), 0175 KNotification::CloseOnTimeout, 0176 QStringLiteral("akonadi_notes_agent")); 0177 auto job = new NoteShared::CreateNewNoteJob(this, nullptr); 0178 // For the moment it doesn't support richtext. 0179 job->setRichText(false); 0180 job->setNote(name, text); 0181 job->start(); 0182 } 0183 0184 void NotesManager::updateNetworkListener() 0185 { 0186 delete mListener; 0187 mListener = nullptr; 0188 0189 if (NoteShared::NoteSharedGlobalConfig::receiveNotes()) { 0190 // create the socket and start listening for connections 0191 mListener = new QTcpServer; 0192 mListener->listen(QHostAddress::Any, NoteShared::NoteSharedGlobalConfig::port()); 0193 connect(mListener, &QTcpServer::newConnection, this, &NotesManager::slotAcceptConnection); 0194 } 0195 } 0196 0197 #include "moc_notesmanager.cpp"