File indexing completed on 2024-05-12 05:26:19
0001 /* 0002 * Copyright (C) 2015 Aaron Seigo <aseigo@kolabsystems.com> 0003 * Copyright (C) 2015 Christian Mollekopf <mollekopf@kolabsystems.com> 0004 * 0005 * This program is free software; you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation; either version 2 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program; if not, write to the 0017 * Free Software Foundation, Inc., 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 0019 */ 0020 0021 #include "sinksh_utils.h" 0022 0023 #include "common/store.h" 0024 #include "common/log.h" 0025 #include "common/propertyparser.h" 0026 0027 #include "utils.h" 0028 0029 namespace SinkshUtils { 0030 0031 bool isValidStoreType(const QString &type) 0032 { 0033 return Sink::ApplicationDomain::getTypeNames().contains(type.toLatin1()); 0034 } 0035 0036 StoreBase &getStore(const QString &type) 0037 { 0038 using namespace Sink::ApplicationDomain; 0039 0040 #define REGISTER_TYPE(TYPE) \ 0041 if (type == getTypeName<TYPE>()) { static Store<TYPE> store; return store; } else 0042 SINK_REGISTER_TYPES() 0043 #undef REGISTER_TYPE 0044 { 0045 SinkWarning_("", "") << "Trying to get a store that doesn't exist: " << type; 0046 Q_ASSERT(false); 0047 } 0048 0049 static DummyStore store; 0050 return store; 0051 } 0052 0053 QList<QByteArray> requestedProperties(const QString &type) 0054 { 0055 using namespace Sink::ApplicationDomain; 0056 if (type == getTypeName<Folder>()) { 0057 return QList<QByteArray>() << Folder::Name::name 0058 << Folder::Parent::name 0059 << Folder::SpecialPurpose::name; 0060 } else if (type == getTypeName<Mail>()) { 0061 return QList<QByteArray>() << Mail::Subject::name 0062 << Mail::Folder::name 0063 << Mail::Date::name; 0064 } else if (type == getTypeName<Event>()) { 0065 return QList<QByteArray>() << Event::Summary::name; 0066 } else if (type == getTypeName<Todo>()) { 0067 return QList<QByteArray>() << Todo::Summary::name << Todo::Status::name; 0068 } else if (type == getTypeName<Contact>()) { 0069 return QList<QByteArray>() << Contact::Fn::name << Contact::Emails::name << Contact::Addressbook::name; 0070 } else if (type == getTypeName<Addressbook>()) { 0071 return QList<QByteArray>() << Addressbook::Name::name << Addressbook::Parent::name; 0072 } else if (type == getTypeName<SinkResource>()) { 0073 return QList<QByteArray>() << SinkResource::ResourceType::name << SinkResource::Account::name << SinkResource::Server::name; 0074 } else if (type == getTypeName<SinkAccount>()) { 0075 return QList<QByteArray>() << SinkAccount::AccountType::name << SinkAccount::Name::name; 0076 } else if (type == getTypeName<Identity>()) { 0077 return QList<QByteArray>() << Identity::Name::name << Identity::Address::name << Identity::Account::name; 0078 } 0079 return QList<QByteArray>(); 0080 } 0081 0082 QSharedPointer<QAbstractItemModel> loadModel(const QString &type, Sink::Query query) 0083 { 0084 query.requestedProperties = requestedProperties(type); 0085 auto model = getStore(type).loadModel(query); 0086 Q_ASSERT(model); 0087 return model; 0088 } 0089 0090 QStringList resourceIds() 0091 { 0092 Sink::Query query; 0093 QStringList resources; 0094 for (const auto &r : getStore("resource").read(query)) { 0095 resources << r.identifier(); 0096 } 0097 return resources; 0098 } 0099 0100 QStringList debugareaCompleter(const QStringList &, const QString &fragment, State &state) 0101 { 0102 return Utils::filteredCompletions(Sink::Log::debugAreas().toList(), fragment); 0103 } 0104 0105 QStringList resourceCompleter(const QStringList &, const QString &fragment, State &state) 0106 { 0107 return Utils::filteredCompletions(resourceIds(), fragment); 0108 } 0109 0110 static QStringList toStringList(const QByteArrayList &l) 0111 { 0112 QStringList list; 0113 for (const auto &s : l) { 0114 list << s; 0115 } 0116 return list; 0117 } 0118 0119 QStringList resourceOrTypeCompleter(const QStringList &commands, const QString &fragment, State &state) 0120 { 0121 if (commands.count() == 1) { 0122 return Utils::filteredCompletions(toStringList(Sink::ApplicationDomain::getTypeNames()), fragment); 0123 } 0124 0125 return Utils::filteredCompletions(resourceIds(), fragment); 0126 } 0127 0128 QStringList typeCompleter(const QStringList &commands, const QString &fragment, State &state) 0129 { 0130 return Utils::filteredCompletions(toStringList(Sink::ApplicationDomain::getTypeNames()), fragment); 0131 } 0132 0133 QMap<QString, QString> keyValueMapFromArgs(const QStringList &args) 0134 { 0135 QMap<QString, QString> map; 0136 for (int i = 0; i + 2 <= args.size(); i += 2) { 0137 map.insert(args.at(i), args.at(i + 1)); 0138 } 0139 return map; 0140 } 0141 0142 bool isId(const QByteArray &value) 0143 { 0144 return value.startsWith("{"); 0145 } 0146 0147 bool applyFilter(Sink::Query &query, const QStringList &args_) 0148 { 0149 if (args_.isEmpty()) { 0150 return false; 0151 } 0152 auto args = args_; 0153 0154 auto type = args.takeFirst(); 0155 0156 if ((type.isEmpty() || !SinkshUtils::isValidStoreType(type)) && type != "*") { 0157 qWarning() << "Unknown type: " << type; 0158 return false; 0159 } 0160 if (type != "*") { 0161 query.setType(type.toUtf8()); 0162 } 0163 if (!args.isEmpty()) { 0164 auto resource = args.takeFirst().toLatin1(); 0165 0166 if (resource.contains('/')) { 0167 //The resource isn't an id but a path 0168 auto list = resource.split('/'); 0169 const auto resourceId = parseUid(list.takeFirst()); 0170 query.resourceFilter(resourceId); 0171 if (type == Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Mail>() && !list.isEmpty()) { 0172 auto value = list.takeFirst(); 0173 if (isId(value)) { 0174 query.filter<Sink::ApplicationDomain::Mail::Folder>(value); 0175 } else { 0176 Sink::Query folderQuery; 0177 folderQuery.resourceFilter(resourceId); 0178 folderQuery.filter<Sink::ApplicationDomain::Folder::Name>(value); 0179 folderQuery.filter<Sink::ApplicationDomain::Folder::Parent>(QVariant()); 0180 auto folders = Sink::Store::read<Sink::ApplicationDomain::Folder>(folderQuery); 0181 if (folders.size() == 1) { 0182 query.filter<Sink::ApplicationDomain::Mail::Folder>(folders.first()); 0183 } else { 0184 qWarning() << "Folder name did not match uniquely: " << folders.size(); 0185 for (const auto &f : folders) { 0186 qWarning() << f.getName(); 0187 } 0188 return false; 0189 } 0190 } 0191 } 0192 } else { 0193 query.resourceFilter(parseUid(resource)); 0194 } 0195 } 0196 return true; 0197 } 0198 0199 bool applyFilter(Sink::Query &query, const SyntaxTree::Options &options) 0200 { 0201 bool ret = applyFilter(query, options.positionalArguments); 0202 if (options.options.contains("resource")) { 0203 for (const auto &f : options.options.value("resource")) { 0204 query.resourceFilter(parseUid(f.toLatin1())); 0205 } 0206 } 0207 if (options.options.contains("filter")) { 0208 for (const auto &f : options.options.value("filter")) { 0209 auto filter = f.split("="); 0210 const auto property = filter.value(0).toLatin1(); 0211 const auto value = filter.value(1); 0212 query.filter(property, Sink::PropertyParser::parse(query.type(), property, QString::fromUtf8(parseUid(value.toUtf8())))); 0213 } 0214 } 0215 if (options.options.contains("fulltext")) { 0216 for (const auto &f : options.options.value("fulltext")) { 0217 query.filter({}, Sink::QueryBase::Comparator(f, Sink::QueryBase::Comparator::Fulltext)); 0218 } 0219 } 0220 if (options.options.contains("id")) { 0221 for (const auto &f : options.options.value("id")) { 0222 query.filter(parseUid(f.toUtf8())); 0223 } 0224 } 0225 return ret; 0226 } 0227 0228 QByteArray parseUid(const QByteArray &uid) 0229 { 0230 if (uid.size() == 36 && uid.contains('-') && !uid.startsWith('{')) { 0231 return '{' + uid + '}'; 0232 } 0233 return uid; 0234 } 0235 0236 }