File indexing completed on 2024-03-24 17:26:05
0001 /* 0002 SPDX-FileCopyrightText: 2002 Shie Erlich <erlich@users.sourceforge.net> 0003 SPDX-FileCopyrightText: 2002 Rafi Yanai <yanai@users.sourceforge.net> 0004 SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "krservices.h" 0010 0011 // QtCore 0012 #include <QDir> 0013 #include <QSet> 0014 #include <QTextStream> 0015 #include <QtGlobal> 0016 0017 #include <KConfigCore/KSharedConfig> 0018 #include <KIOCore/KProtocolManager> 0019 #include <utility> 0020 0021 #include "defaults.h" 0022 #include "krglobal.h" 0023 0024 QString KrServices::GLOBAL_MESSAGE_PATTERN = "%{time hh:mm:ss.zzz}-%{type} %{category} %{function}@%{line} # %{message}"; 0025 0026 bool KrServices::cmdExist(const QString &cmdName) 0027 { 0028 // Reminder: If that function is modified, it's important to research if the 0029 // changes must also be applied to `KrServices::fullPathName()` 0030 // and `kio_krarcProtocol::fullPathName()` 0031 0032 KConfigGroup dependGrp(krConfig, "Dependencies"); 0033 QString supposedName = dependGrp.readEntry(cmdName, QString()); 0034 if (QFileInfo::exists(supposedName)) 0035 return true; 0036 0037 if ((supposedName = QStandardPaths::findExecutable(cmdName)).isEmpty()) 0038 return false; 0039 0040 // Because an executable file has been found, its path is remembered 0041 // in order to avoid some future searches 0042 dependGrp.writeEntry(cmdName, supposedName); 0043 0044 return true; 0045 } 0046 0047 QString KrServices::fullPathName(const QString &name, QString confName) 0048 { 0049 // Reminder: If that function is modified, it's important to research if the 0050 // changes must also be applied to `kio_krarcProtocol::fullPathName()` 0051 // and `KrServices::cmdExist()` 0052 0053 if (confName.isNull()) 0054 confName = name; 0055 0056 KConfigGroup dependGrp(krConfig, "Dependencies"); 0057 QString supposedName = dependGrp.readEntry(confName, QString()); 0058 if (QFileInfo::exists(supposedName)) 0059 return supposedName; 0060 0061 if ((supposedName = QStandardPaths::findExecutable(name)).isEmpty()) 0062 return QString(); 0063 0064 // Because an executable file has been found, its path is remembered 0065 // in order to avoid some future searches 0066 dependGrp.writeEntry(confName, supposedName); 0067 0068 return supposedName; 0069 } 0070 0071 QString KrServices::chooseFullPathName(QStringList names, const QString &confName) 0072 { 0073 foreach (const QString &name, names) { 0074 QString foundTool = KrServices::fullPathName(name, confName); 0075 if (!foundTool.isEmpty()) { 0076 return foundTool; 0077 } 0078 } 0079 0080 return ""; 0081 } 0082 0083 bool KrServices::isExecutable(const QString &path) 0084 { 0085 QFileInfo info(path); 0086 return info.isFile() && info.isExecutable(); 0087 } 0088 0089 bool KrServices::isoSupported(const QString &mimetype) 0090 { 0091 #ifdef KRARC_QUERY_ENABLED 0092 return KProtocolInfo::archiveMimetypes("iso").contains(mimetype); 0093 #else 0094 return false; 0095 #endif 0096 } 0097 0098 bool KrServices::fileToStringList(QTextStream *stream, QStringList &target, bool keepEmptyLines) 0099 { 0100 if (!stream) 0101 return false; 0102 QString line; 0103 while (!stream->atEnd()) { 0104 line = stream->readLine().trimmed(); 0105 if (keepEmptyLines || !line.isEmpty()) 0106 target.append(line); 0107 } 0108 return true; 0109 } 0110 0111 bool KrServices::fileToStringList(QFile *file, QStringList &target, bool keepEmptyLines) 0112 { 0113 QTextStream stream(file); 0114 return fileToStringList(&stream, target, keepEmptyLines); 0115 } 0116 0117 QString KrServices::quote(const QString &name) 0118 { 0119 if (!name.contains('\'')) 0120 return '\'' + name + '\''; 0121 if (!name.contains('"') && !name.contains('$')) 0122 return '\"' + name + '\"'; 0123 return escape(name); 0124 } 0125 0126 QStringList KrServices::quote(const QStringList &names) 0127 { 0128 QStringList result; 0129 for (int i = 0; i < names.size(); ++i) 0130 result.append(quote(names[i])); 0131 return result; 0132 } 0133 0134 QList<QUrl> KrServices::toUrlList(const QStringList &list) 0135 { 0136 QList<QUrl> result; 0137 for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) { 0138 result.append(QUrl::fromUserInput(*it, QDir::currentPath(), QUrl::AssumeLocalFile)); 0139 } 0140 return result; 0141 } 0142 0143 QStringList KrServices::toStringList(const QList<QUrl> &list) 0144 { 0145 QStringList result; 0146 for (QList<QUrl>::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) { 0147 result.append(it->toString()); 0148 } 0149 return result; 0150 } 0151 0152 // Adds one tool to the list in the supportedTools method 0153 void supportedTool(QStringList &tools, const QString &toolType, QStringList names, QString confName) 0154 { 0155 QString foundTool = KrServices::chooseFullPathName(std::move(names), std::move(confName)); 0156 if (!foundTool.isEmpty()) { 0157 tools.append(toolType); 0158 tools.append(foundTool); 0159 } 0160 } 0161 0162 // return a list in the format of TOOLS,PATH. for example 0163 // DIFF,kdiff,TERMINAL,konsole,... 0164 // 0165 // currently supported tools: DIFF, MAIL, RENAME 0166 // 0167 // to use it: QStringList lst = supportedTools(); 0168 // int i = lst.indexOf("DIFF"); 0169 // if (i!=-1) pathToDiff=lst[i+1]; 0170 QStringList KrServices::supportedTools() 0171 { 0172 QStringList tools; 0173 0174 // first, a diff program: kdiff 0175 supportedTool(tools, 0176 "DIFF", 0177 QStringList() << "kdiff3" 0178 << "kompare" 0179 << "xxdiff", 0180 "diff utility"); 0181 0182 // a mailer: kmail or thunderbird 0183 supportedTool(tools, 0184 "MAIL", 0185 QStringList() << "thunderbird" 0186 << "kmail", 0187 "mailer"); 0188 0189 // rename tool: krename 0190 supportedTool(tools, "RENAME", QStringList() << "krename", "krename"); 0191 0192 // checksum utility 0193 supportedTool(tools, "MD5", QStringList() << "md5sum", "checksum utility"); 0194 0195 return tools; 0196 } 0197 0198 QString KrServices::escape(QString name) 0199 { 0200 const QString evilstuff = "\\\"'`()[]{}!?;$&<>| \t\r\n"; // stuff that should get escaped 0201 0202 for (auto i : evilstuff) 0203 name.replace(i, ('\\' + i)); 0204 0205 return name; 0206 } 0207 0208 QString KrServices::escapeFileUrl(QString urlString) 0209 { 0210 // Avoid that if a path contains a '#' then what follows the '#' be interpreted as the fragment identifier of 0211 // the URL and not a part of the file path; for more information https://bugs.kde.org/show_bug.cgi?id=270150 can be seen 0212 return urlString.replace('#', "%23").replace('?', "%3F"); 0213 } 0214 0215 QUrl KrServices::escapeFileUrl(const QUrl &url) 0216 { 0217 return QUrl(KrServices::escapeFileUrl(url.toString())); 0218 } 0219 0220 QString KrServices::urlToLocalPath(const QUrl &url) 0221 { 0222 QUrl fileUrl = QUrl(url); 0223 // QUrl::toLocalFile() does not work if the protocol is "file" e.g. when opening an archive 0224 fileUrl.setScheme("file"); 0225 QString path = fileUrl.toLocalFile(); 0226 REPLACE_DIR_SEP2(path); 0227 0228 #ifdef Q_OS_WIN 0229 if (path.startsWith(DIR_SEPARATOR)) { 0230 int p = 1; 0231 while (p < path.length() && path[p] == DIR_SEPARATOR_CHAR) 0232 p++; 0233 /* /C:/Folder */ 0234 if (p + 2 <= path.length() && path[p].isLetter() && path[p + 1] == ':') { 0235 path = path.mid(p); 0236 } 0237 } 0238 #endif 0239 return path; 0240 } 0241 0242 static bool s_withDebugMessages; 0243 static QtMessageHandler s_defaultMessageHandler; 0244 0245 void KrServices::setGlobalKrMessageHandler(bool withDebugMessages) 0246 { 0247 s_withDebugMessages = withDebugMessages; 0248 s_defaultMessageHandler = qInstallMessageHandler(nullptr); 0249 qInstallMessageHandler(&krMessageHandler); 0250 } 0251 0252 void KrServices::krMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) 0253 { 0254 // filter debug if not enabled 0255 if (type != QtDebugMsg || s_withDebugMessages) { 0256 s_defaultMessageHandler(type, context, msg); 0257 } 0258 }