File indexing completed on 2025-02-02 05:05:40
0001 /* 0002 SPDX-FileCopyrightText: 2008 Tobias Koenig <tokoe@kde.org> 0003 SPDX-FileCopyrightText: 2008 Bertjan Broeksema <broeksema@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "vcarddirresource.h" 0009 0010 #include "settingsadaptor.h" 0011 #include "vcarddirresource_debug.h" 0012 0013 #include <QDir> 0014 #include <QDirIterator> 0015 #include <QFile> 0016 0017 #include <Akonadi/ChangeRecorder> 0018 #include <Akonadi/EntityDisplayAttribute> 0019 #include <Akonadi/ItemFetchScope> 0020 0021 #include <KLocalizedString> 0022 0023 using namespace Akonadi; 0024 0025 VCardDirResource::VCardDirResource(const QString &id) 0026 : ResourceBase(id) 0027 { 0028 VcardDirResourceSettings::instance(KSharedConfig::openConfig()); 0029 // setup the resource 0030 new SettingsAdaptor(VcardDirResourceSettings::self()); 0031 QDBusConnection::sessionBus().registerObject(QStringLiteral("/Settings"), VcardDirResourceSettings::self(), QDBusConnection::ExportAdaptors); 0032 0033 changeRecorder()->itemFetchScope().fetchFullPayload(); 0034 connect(this, &VCardDirResource::reloadConfiguration, this, &VCardDirResource::slotReloadConfig); 0035 } 0036 0037 VCardDirResource::~VCardDirResource() 0038 { 0039 // clear cache 0040 mAddressees.clear(); 0041 } 0042 0043 void VCardDirResource::slotReloadConfig() 0044 { 0045 VcardDirResourceSettings::self()->load(); 0046 0047 initializeVCardDirectory(); 0048 loadAddressees(); 0049 0050 synchronize(); 0051 } 0052 0053 void VCardDirResource::aboutToQuit() 0054 { 0055 VcardDirResourceSettings::self()->save(); 0056 } 0057 0058 void VCardDirResource::loadAddressees() 0059 { 0060 mAddressees.clear(); 0061 0062 QDirIterator it(vCardDirectoryName()); 0063 while (it.hasNext()) { 0064 it.next(); 0065 const QString filename = it.fileName(); 0066 if (filename != QLatin1StringView(".") && filename != QLatin1StringView("..") && filename != QLatin1StringView("WARNING_README.txt")) { 0067 QFile file(it.filePath()); 0068 if (file.open(QIODevice::ReadOnly)) { 0069 const QByteArray data = file.readAll(); 0070 file.close(); 0071 0072 const KContacts::Addressee addr = mConverter.parseVCard(data); 0073 if (!addr.isEmpty()) { 0074 mAddressees.insert(addr.uid(), addr); 0075 } 0076 } else { 0077 qCCritical(VCARDDIRRESOURCE_LOG) << " file can't be load " << it.filePath(); 0078 } 0079 } 0080 } 0081 0082 Q_EMIT status(Idle); 0083 } 0084 0085 bool VCardDirResource::retrieveItems(const Akonadi::Item::List &items, const QSet<QByteArray> &parts) 0086 { 0087 Q_UNUSED(parts); 0088 0089 Akonadi::Item::List resultItems; 0090 resultItems.reserve(items.size()); 0091 0092 for (const Akonadi::Item &item : items) { 0093 Item newItem(item); 0094 if (!doRetrieveItem(newItem)) { 0095 return false; 0096 } 0097 resultItems.append(newItem); 0098 } 0099 0100 itemsRetrieved(resultItems); 0101 0102 return true; 0103 } 0104 0105 bool VCardDirResource::retrieveItem(const Akonadi::Item &item, const QSet<QByteArray> &) 0106 { 0107 Item newItem(item); 0108 0109 if (!doRetrieveItem(newItem)) { 0110 return false; 0111 } 0112 0113 itemRetrieved(newItem); 0114 0115 return true; 0116 } 0117 0118 bool VCardDirResource::doRetrieveItem(Akonadi::Item &item) 0119 { 0120 const QString remoteId = item.remoteId(); 0121 if (!mAddressees.contains(remoteId)) { 0122 Q_EMIT error(i18n("Contact with uid '%1' not found.", remoteId)); 0123 return false; 0124 } 0125 0126 item.setPayload<KContacts::Addressee>(mAddressees.value(remoteId)); 0127 0128 return true; 0129 } 0130 0131 void VCardDirResource::itemAdded(const Akonadi::Item &item, const Akonadi::Collection &) 0132 { 0133 if (VcardDirResourceSettings::self()->readOnly()) { 0134 Q_EMIT error(i18n("Trying to write to a read-only directory: '%1'", vCardDirectoryName())); 0135 cancelTask(); 0136 return; 0137 } 0138 0139 KContacts::Addressee addressee; 0140 if (item.hasPayload<KContacts::Addressee>()) { 0141 addressee = item.payload<KContacts::Addressee>(); 0142 } 0143 0144 if (!addressee.isEmpty()) { 0145 // add it to the cache... 0146 mAddressees.insert(addressee.uid(), addressee); 0147 0148 // ... and write it through to the file system 0149 const QByteArray data = mConverter.createVCard(addressee); 0150 0151 QFile file(vCardDirectoryFileName(addressee.uid())); 0152 file.open(QIODevice::WriteOnly); 0153 file.write(data); 0154 file.close(); 0155 0156 // report everything ok 0157 Item newItem(item); 0158 newItem.setRemoteId(addressee.uid()); 0159 changeCommitted(newItem); 0160 } else { 0161 changeProcessed(); 0162 } 0163 } 0164 0165 void VCardDirResource::itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &) 0166 { 0167 if (VcardDirResourceSettings::self()->readOnly()) { 0168 Q_EMIT error(i18n("Trying to write to a read-only directory: '%1'", vCardDirectoryName())); 0169 cancelTask(); 0170 return; 0171 } 0172 0173 KContacts::Addressee addressee; 0174 if (item.hasPayload<KContacts::Addressee>()) { 0175 addressee = item.payload<KContacts::Addressee>(); 0176 } 0177 0178 if (!addressee.isEmpty()) { 0179 // change it in the cache... 0180 mAddressees.insert(addressee.uid(), addressee); 0181 0182 // ... and write it through to the file system 0183 const QByteArray data = mConverter.createVCard(addressee); 0184 0185 QFile file(vCardDirectoryFileName(addressee.uid())); 0186 if (file.open(QIODevice::WriteOnly)) { 0187 file.write(data); 0188 file.close(); 0189 0190 Item newItem(item); 0191 newItem.setRemoteId(addressee.uid()); 0192 changeCommitted(newItem); 0193 } else { 0194 qCritical() << " We can't write in file " << file.fileName(); 0195 } 0196 } else { 0197 changeProcessed(); 0198 } 0199 } 0200 0201 void VCardDirResource::itemRemoved(const Akonadi::Item &item) 0202 { 0203 if (VcardDirResourceSettings::self()->readOnly()) { 0204 Q_EMIT error(i18n("Trying to write to a read-only directory: '%1'", vCardDirectoryName())); 0205 cancelTask(); 0206 return; 0207 } 0208 0209 // remove it from the cache... 0210 mAddressees.remove(item.remoteId()); 0211 0212 // ... and remove it from the file system 0213 QFile::remove(vCardDirectoryFileName(item.remoteId())); 0214 0215 changeProcessed(); 0216 } 0217 0218 void VCardDirResource::retrieveCollections() 0219 { 0220 Collection c; 0221 c.setParentCollection(Collection::root()); 0222 c.setRemoteId(vCardDirectoryName()); 0223 c.setName(name()); 0224 QStringList mimeTypes; 0225 mimeTypes << KContacts::Addressee::mimeType(); 0226 c.setContentMimeTypes(mimeTypes); 0227 if (VcardDirResourceSettings::self()->readOnly()) { 0228 c.setRights(Collection::ReadOnly); 0229 } else { 0230 Collection::Rights rights; 0231 rights |= Collection::CanChangeItem; 0232 rights |= Collection::CanCreateItem; 0233 rights |= Collection::CanDeleteItem; 0234 rights |= Collection::CanChangeCollection; 0235 c.setRights(rights); 0236 } 0237 0238 auto attr = c.attribute<EntityDisplayAttribute>(Collection::AddIfMissing); 0239 attr->setDisplayName(i18n("Contacts Folder")); 0240 attr->setIconName(QStringLiteral("x-office-address-book")); 0241 0242 Collection::List list; 0243 list << c; 0244 collectionsRetrieved(list); 0245 } 0246 0247 void VCardDirResource::retrieveItems(const Akonadi::Collection &) 0248 { 0249 Item::List items; 0250 items.reserve(mAddressees.count()); 0251 0252 for (const KContacts::Addressee &addressee : std::as_const(mAddressees)) { 0253 Item item; 0254 item.setRemoteId(addressee.uid()); 0255 item.setMimeType(KContacts::Addressee::mimeType()); 0256 items.append(item); 0257 } 0258 0259 itemsRetrieved(items); 0260 } 0261 0262 QString VCardDirResource::vCardDirectoryName() const 0263 { 0264 return VcardDirResourceSettings::self()->path(); 0265 } 0266 0267 QString VCardDirResource::vCardDirectoryFileName(const QString &file) const 0268 { 0269 return VcardDirResourceSettings::self()->path() + QLatin1Char('/') + file; 0270 } 0271 0272 void VCardDirResource::initializeVCardDirectory() const 0273 { 0274 QDir dir(vCardDirectoryName()); 0275 0276 // if folder does not exists, create it 0277 if (!dir.exists()) { 0278 if (!QDir::root().mkpath(dir.absolutePath())) { 0279 qCritical() << "Failed to create vCard directory" << dir.absolutePath(); 0280 } else { 0281 qDebug() << "vCard directory " << dir.absolutePath() << "successfuly created"; 0282 } 0283 } 0284 0285 // check whether warning file is in place... 0286 QFile file(dir.absolutePath() + QStringLiteral("/WARNING_README.txt")); 0287 if (!file.exists()) { 0288 // ... if not, create it 0289 file.open(QIODevice::WriteOnly); 0290 file.write( 0291 "Important Warning!!!\n\n" 0292 "Don't create or copy vCards inside this folder manually, they are managed by the Akonadi framework!\n"); 0293 file.close(); 0294 } 0295 } 0296 0297 AKONADI_RESOURCE_MAIN(VCardDirResource) 0298 0299 #include "moc_vcarddirresource.cpp"