File indexing completed on 2024-05-26 05:27:55

0001 /*
0002  * Copyright (C) 2014 Aaron Seigo <aseigo@kde.org>
0003  *
0004  *   This program is free software; you can redistribute it and/or modify
0005  *   it under the terms of the GNU General Public License as published by
0006  *   the Free Software Foundation; either version 2 of the License, or
0007  *   (at your option) any later version.
0008  *
0009  *   This program is distributed in the hope that it will be useful,
0010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *   GNU General Public License for more details.
0013  *
0014  *   You should have received a copy of the GNU General Public License
0015  *   along with this program; if not, write to the
0016  *   Free Software Foundation, Inc.,
0017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
0018  */
0019 
0020 #include <QDebug>
0021 #include <QObject> // tr()
0022 #include <QModelIndex>
0023 #include <QTime>
0024 #include <iostream>
0025 
0026 #include "common/resource.h"
0027 #include "common/storage.h"
0028 #include "common/resourceconfig.h"
0029 #include "common/log.h"
0030 #include "common/storage.h"
0031 #include "common/definitions.h"
0032 #include "common/store.h"
0033 #include "common/propertyparser.h"
0034 
0035 #include "sinksh_utils.h"
0036 #include "state.h"
0037 #include "syntaxtree.h"
0038 
0039 namespace SinkList
0040 {
0041 
0042 Syntax::List syntax();
0043 
0044 static QByteArray compressId(bool compress, const QByteArray &id)
0045 {
0046     if (!compress) {
0047         if (id.startsWith('{')) {
0048             return id.mid(1, id.length() - 2);
0049         }
0050         return id;
0051     }
0052     auto compactId = id.mid(1, id.length() - 2).split('-');
0053     if (compactId.isEmpty()) {
0054         //Failed to compress id
0055         return id;
0056     }
0057     return compactId.first();
0058 }
0059 
0060 QByteArray baIfAvailable(const QStringList &list)
0061 {
0062     if (list.isEmpty()) {
0063         return QByteArray{};
0064     }
0065     return list.first().toUtf8();
0066 }
0067 
0068 template <typename T>
0069 static QString qDebugToString(const T &c)
0070 {
0071     QString s;
0072     {
0073         QDebug debug{&s};
0074         debug << c;
0075     }
0076     return s;
0077 }
0078 
0079 QStringList printToList(const Sink::ApplicationDomain::ApplicationDomainType &o, bool compact, const QByteArrayList &toPrint, bool limitPropertySize)
0080 {
0081     QStringList line;
0082     line << compressId(compact, o.resourceInstanceIdentifier());
0083     line << compressId(compact, o.identifier());
0084     for (const auto &prop: toPrint) {
0085         const auto value = o.getProperty(prop);
0086         if (value.isValid()) {
0087             if (value.canConvert<Sink::ApplicationDomain::Reference>()) {
0088                 line << compressId(compact, value.toByteArray());
0089             } else if (value.canConvert<QString>()) {
0090                 if (limitPropertySize) {
0091                     line << value.toString().mid(0, 75);
0092                 } else {
0093                     line << value.toString();
0094                 }
0095             } else if (value.canConvert<QByteArray>()) {
0096                 if (limitPropertySize) {
0097                     line << value.toByteArray().mid(0, 75);
0098                 } else {
0099                     line << value.toByteArray();
0100                 }
0101             } else if (value.canConvert<QByteArrayList>()) {
0102                 line << value.value<QByteArrayList>().join(", ");
0103             } else if (value.canConvert<Sink::ApplicationDomain::Mail::Contact>()) {
0104                 line << qDebugToString(value.value<Sink::ApplicationDomain::Mail::Contact>());
0105             } else if (value.canConvert<QList<Sink::ApplicationDomain::Mail::Contact>>()) {
0106                 line << qDebugToString(value.value<QList<Sink::ApplicationDomain::Mail::Contact>>());
0107             } else if (value.canConvert<QList<Sink::ApplicationDomain::Contact::Email>>()) {
0108                 line << qDebugToString(value.value<QList<Sink::ApplicationDomain::Contact::Email>>());
0109             } else {
0110                 line << QString("Unprintable type: %1").arg(value.typeName());
0111             }
0112         } else {
0113             line << QString{};
0114         }
0115     }
0116     return line;
0117 }
0118 
0119 bool list(const QStringList &args_, State &state)
0120 {
0121     if (args_.isEmpty()) {
0122         state.printError(syntax()[0].usage());
0123         return false;
0124     }
0125 
0126     auto options = SyntaxTree::parseOptions(args_);
0127     bool asLine = true;
0128 
0129     Sink::Query query;
0130     query.setId("list");
0131     if (!SinkshUtils::applyFilter(query, options)) {
0132         state.printError(syntax()[0].usage());
0133         return false;
0134     }
0135 
0136     if (options.options.contains("limit")) {
0137         query.limit(options.options.value("limit").first().toInt());
0138     }
0139 
0140     if (options.options.contains("sort")) {
0141         query.setSortProperty(options.options.value("sort").first().toUtf8());
0142     }
0143 
0144     if (options.options.contains("reduce")) {
0145         auto value = options.options.value("reduce").first().toUtf8();
0146         query.reduce(value.split(':').value(0), Sink::Query::Reduce::Selector(value.split(':').value(1), Sink::Query::Reduce::Selector::Max));
0147     }
0148 
0149     const auto compact = options.options.contains("compact");
0150     const auto exportProperties = options.options.contains("export");
0151     bool limitPropertySize = true;
0152     if (!options.options.contains("showall")) {
0153         if (options.options.contains("show")) {
0154             auto list = options.options.value("show");
0155             std::transform(list.constBegin(), list.constEnd(), std::back_inserter(query.requestedProperties), [] (const QString &s) { return s.toLatin1(); });
0156             //Print the full property if we explicitly list properties
0157             limitPropertySize = false;
0158         } else {
0159             query.requestedProperties = SinkshUtils::requestedProperties(query.type());
0160         }
0161     } else {
0162         asLine = false;
0163     }
0164 
0165     QByteArrayList toPrint = query.requestedProperties;
0166     std::sort(toPrint.begin(), toPrint.end());
0167     QStringList tableLine;
0168 
0169     for (const auto &o : SinkshUtils::getStore(query.type()).read(query)) {
0170         if (exportProperties) {
0171             for (const auto &prop: toPrint) {
0172                 const auto value = o.getProperty(prop);
0173                 if (value.isValid()) {
0174                     if (value.canConvert<QString>()) {
0175                         std::cout << value.toString().toStdString() << std::endl;
0176                     } else if (value.canConvert<QByteArray>()) {
0177                         std::cout << value.toByteArray().toStdString() << std::endl;
0178                     }
0179                 }
0180             }
0181             continue;
0182         }
0183         if (tableLine.isEmpty()) {
0184             tableLine << QObject::tr("Resource") << QObject::tr("Identifier");
0185             if (toPrint.isEmpty()) {
0186                 toPrint = o.availableProperties();
0187                 std::sort(toPrint.begin(), toPrint.end());
0188             }
0189             if (asLine) {
0190                 std::transform(toPrint.constBegin(), toPrint.constEnd(), std::back_inserter(tableLine), [] (const QByteArray &s) -> QString { return s; });
0191                 state.stageTableLine(tableLine);
0192             }
0193         }
0194         if (asLine) {
0195             state.stageTableLine(printToList(o, compact, toPrint, limitPropertySize));
0196         } else {
0197             state.stageTableLine(QStringList());
0198             auto list = printToList(o, compact, toPrint, limitPropertySize);
0199             state.stageTableLine(QStringList() << "Resource: " << list.value(0));
0200             state.stageTableLine(QStringList() << "Identifier: " << list.value(1));
0201             for (int i = 0; i < (list.size() - 2); i++) {
0202                 state.stageTableLine(QStringList() << toPrint.value(i) << list.value(i + 2));
0203             }
0204             state.flushTable();
0205         }
0206     }
0207     state.flushTable();
0208     return true;
0209 }
0210 
0211 Syntax::List syntax()
0212 {
0213     Syntax list("list", QObject::tr("List all resources, or the contents of one or more resources."), &SinkList::list, Syntax::NotInteractive);
0214 
0215     list.addPositionalArgument({"type", "The type of content to list (resource, identity, account, mail, etc.)"});
0216     list.addParameter("resource", {"resource", "List only the content of the given resource" });
0217     list.addFlag("compact", "Use a compact view (reduces the size of IDs)");
0218     list.addParameter("filter", {"property=$value", "Filter the results" });
0219     list.addParameter("fulltext", {"query", "Filter the results" });
0220     list.addParameter("id", {"id", "List only the content with the given ID" });
0221     list.addFlag("showall", "Show all properties");
0222     list.addParameter("show", {"property", "Only show the given property" });
0223     list.addParameter("reduce", {"property:$selectorProperty", "Combine the result with the same $property, sorted by $selectorProperty" });
0224     list.addParameter("sort", {"property", "Sort the results according to the given property" });
0225     list.addParameter("limit", {"count", "Limit the results" });
0226 
0227     list.completer = &SinkshUtils::resourceOrTypeCompleter;
0228     return Syntax::List() << list;
0229 }
0230 
0231 REGISTER_SYNTAX(SinkList)
0232 
0233 }