File indexing completed on 2024-05-12 05:12:41
0001 /* 0002 * Copyright (C) 2014 Bhaskar Kandiyal <bkandiyal@gmail.com> 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 along 0015 * with this program; if not, write to the Free Software Foundation, Inc., 0016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 0017 * 0018 */ 0019 0020 #include "editcommand.h" 0021 0022 #include <Akonadi/Item> 0023 #include <Akonadi/ItemFetchJob> 0024 #include <Akonadi/ItemFetchScope> 0025 #include <Akonadi/ItemModifyJob> 0026 0027 #include <qprocess.h> 0028 #include <qtemporaryfile.h> 0029 0030 #include <iostream> 0031 0032 #include "commandfactory.h" 0033 #include "collectionresolvejob.h" 0034 0035 using namespace Akonadi; 0036 0037 DEFINE_COMMAND("edit", EditCommand, I18N_NOOP("Edit the raw payload for the specified item using $EDITOR")); 0038 0039 EditCommand::EditCommand(QObject *parent) 0040 : AbstractCommand(parent), 0041 mTempFile(nullptr) 0042 { 0043 } 0044 0045 EditCommand::~EditCommand() 0046 { 0047 delete mTempFile; 0048 } 0049 0050 void EditCommand::setupCommandOptions(QCommandLineParser *parser) 0051 { 0052 addOptionsOption(parser); 0053 addDryRunOption(parser); 0054 0055 parser->addPositionalArgument("item", i18nc("@info:shell", "The item to edit")); 0056 } 0057 0058 int EditCommand::initCommand(QCommandLineParser *parser) 0059 { 0060 const QStringList args = parser->positionalArguments(); 0061 if (!checkArgCount(args, 1, i18nc("@info:shell", "No item specified"))) return InvalidUsage; 0062 0063 if (!getCommonOptions(parser)) return InvalidUsage; 0064 0065 mItemArg = args.first(); 0066 0067 return NoError; 0068 } 0069 0070 void EditCommand::start() 0071 { 0072 Item item = CollectionResolveJob::parseItem(mItemArg, true); 0073 if (!item.isValid()) { 0074 emit finished(InvalidUsage); 0075 } 0076 0077 ItemFetchJob *job = new ItemFetchJob(item, this); 0078 job->fetchScope().setFetchModificationTime(false); 0079 job->fetchScope().fetchAllAttributes(false); 0080 job->fetchScope().fetchFullPayload(true); 0081 connect(job, &ItemFetchJob::result, this, &EditCommand::onItemFetched); 0082 } 0083 0084 void EditCommand::onItemFetched(KJob *job) 0085 { 0086 if (!checkJobResult(job)) return; 0087 ItemFetchJob *fetchJob = qobject_cast<ItemFetchJob *>(job); 0088 Q_ASSERT(fetchJob != nullptr); 0089 0090 Item::List items = fetchJob->items(); 0091 0092 if (items.count() < 1) { 0093 emit error(i18nc("@info:shell", "No result found for item '%1'", job->property("arg").toString())); 0094 emit finished(RuntimeError); 0095 return; 0096 } 0097 0098 Akonadi::Item item = items.first(); 0099 0100 if (!item.hasPayload()) { 0101 emit error(i18nc("@info:shell", "Item '%1' has no payload", job->property("arg").toString())); 0102 emit finished(RuntimeError); 0103 return; 0104 } 0105 0106 QString editor = QString::fromLocal8Bit(qgetenv("EDITOR")); 0107 if (editor.isEmpty()) { 0108 emit error(i18nc("@info:shell", "EDITOR environment variable needs to be set")); 0109 emit finished(RuntimeError); 0110 return; 0111 } 0112 0113 mTempFile = new QTemporaryFile(this); 0114 mTempFile->open(); 0115 mTempFile->write(item.payloadData()); 0116 mTempFile->flush(); // Make sure the data is written to the file before opening up the editor 0117 mTempFile->close(); 0118 0119 /* Using system() because KProcess / QProcess does not behave properly with console commands that expect input from stdin */ 0120 int ret = system(QString(editor + " " + mTempFile->fileName()).toLocal8Bit().data()); 0121 if (ret != 0) { 0122 emit error(i18nc("@info:shell", "Cannot launch text editor '%1'", editor)); 0123 emit finished(RuntimeError); 0124 return; 0125 } 0126 0127 if (!isDryRun()) { 0128 mTempFile->open(); 0129 mTempFile->seek(0); // Seek to the beginning of the file 0130 item.setPayloadFromData(mTempFile->readAll()); 0131 ItemModifyJob *modifyJob = new ItemModifyJob(item); 0132 connect(modifyJob, &ItemModifyJob::result, this, &EditCommand::onItemModified); 0133 } else { 0134 onItemModified(job); 0135 } 0136 } 0137 0138 void EditCommand::onItemModified(KJob *job) 0139 { 0140 if (!checkJobResult(job)) return; 0141 std::cout << i18nc("@info:shell", "Changes to item '%1' have been saved", mItemArg).toLocal8Bit().constData() << std::endl; 0142 emit finished(NoError); 0143 }