File indexing completed on 2024-05-05 04:45:06

0001 /*
0002  * Copyright (C) 2003-2008  Justin Karneges <justin@affinix.com>
0003  * Copyright (C) 2014  Ivan Romanov <drizt@land.ru>
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Lesser General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2.1 of the License, or (at your option) any later version.
0009  *
0010  * This library 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 GNU
0013  * Lesser General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Lesser General Public
0016  * License along with this library; if not, write to the Free Software
0017  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
0018  */
0019 
0020 #include "utils.h"
0021 #include "mykeystorelist.h"
0022 #include <QCoreApplication>
0023 #include <QFileInfo>
0024 #include <QStringList>
0025 #ifdef Q_OS_WIN
0026 #include <windows.h>
0027 #endif
0028 
0029 using namespace QCA;
0030 
0031 namespace gpgQCAPlugin {
0032 
0033 void gpg_waitForFinished(GpgOp *gpg)
0034 {
0035     while (true) {
0036         GpgOp::Event e = gpg->waitForEvent(-1);
0037         if (e.type == GpgOp::Event::Finished)
0038             break;
0039     }
0040 }
0041 
0042 void gpg_keyStoreLog(const QString &str)
0043 {
0044     MyKeyStoreList *ksl = MyKeyStoreList::instance();
0045     if (ksl)
0046         ksl->ext_keyStoreLog(str);
0047 }
0048 
0049 inline bool check_bin(const QString &bin)
0050 {
0051     QFileInfo fi(bin);
0052     return fi.exists();
0053 }
0054 
0055 #ifdef Q_OS_WIN
0056 static bool get_reg_key(HKEY root, const char *path, QString &value)
0057 {
0058     HKEY hkey = 0;
0059 
0060     char  szValue[256];
0061     DWORD dwLen = 256;
0062 
0063     bool res = false;
0064 
0065     if (RegOpenKeyExA(root, path, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) {
0066         if (RegQueryValueExA(hkey, "Install Directory", NULL, NULL, (LPBYTE)szValue, &dwLen) == ERROR_SUCCESS) {
0067             value = QString::fromLocal8Bit(szValue);
0068             res   = true;
0069         }
0070         RegCloseKey(hkey);
0071     }
0072     return res;
0073 }
0074 
0075 static QString find_reg_gpgProgram()
0076 {
0077     const QStringList bins = {QStringLiteral("gpg.exe"), QStringLiteral("gpg2.exe")};
0078 
0079     HKEY root;
0080     root = HKEY_CURRENT_USER;
0081 
0082     const char *path  = "Software\\GNU\\GnuPG";
0083     const char *path2 = "Software\\Wow6432Node\\GNU\\GnuPG";
0084 
0085     QString dir;
0086     // check list of possible places in registry
0087     get_reg_key(HKEY_CURRENT_USER, path, dir) || get_reg_key(HKEY_CURRENT_USER, path2, dir) ||
0088         get_reg_key(HKEY_LOCAL_MACHINE, path, dir) || get_reg_key(HKEY_LOCAL_MACHINE, path2, dir);
0089 
0090     if (!dir.isEmpty()) {
0091         foreach (const QString &bin, bins) {
0092             if (check_bin(dir + QStringLiteral("\\") + bin)) {
0093                 return dir + QStringLiteral("\\") + bin;
0094             }
0095         }
0096     }
0097     return QString();
0098 }
0099 #endif
0100 
0101 QString find_bin()
0102 {
0103     // gpg and gpg2 has identical semantics
0104     // so any from them can be used
0105     QStringList bins;
0106 #ifdef Q_OS_WIN
0107     bins << QStringLiteral("gpg.exe") << QStringLiteral("gpg2.exe");
0108 #else
0109     bins << QStringLiteral("gpg") << QStringLiteral("gpg2");
0110 #endif
0111 
0112     // Prefer bundled gpg
0113     foreach (const QString &bin, bins) {
0114         if (check_bin(QCoreApplication::applicationDirPath() + QLatin1Char('/') + bin)) {
0115             return QCoreApplication::applicationDirPath() + QLatin1Char('/') + bin;
0116         }
0117     }
0118 
0119 #ifdef Q_OS_WIN
0120     // On Windows look up at registry
0121     QString bin = find_reg_gpgProgram();
0122     if (!bin.isEmpty())
0123         return bin;
0124 #endif
0125 
0126         // Look up at PATH environment
0127 #ifdef Q_OS_WIN
0128     const QString pathSep = QStringLiteral(";");
0129 #else
0130     const QString pathSep = QStringLiteral(":");
0131 #endif
0132 
0133     QStringList paths = QString::fromLocal8Bit(qgetenv("PATH")).split(pathSep, Qt::SkipEmptyParts);
0134 
0135 #ifdef Q_OS_MAC
0136     // On Mac OS bundled always uses system default PATH
0137     // so it need explicity add extra paths which can
0138     // contain gpg
0139     // Mac GPG and brew use /usr/local/bin
0140     // MacPorts uses /opt/local/bin
0141     paths << QStringLiteral("/usr/local/bin") << QStringLiteral("/opt/local/bin");
0142 #endif
0143     paths.removeDuplicates();
0144 
0145     foreach (const QString &path, paths) {
0146         foreach (const QString &bin, bins) {
0147             if (check_bin(path + QLatin1Char('/') + bin)) {
0148                 return path + QLatin1Char('/') + bin;
0149             }
0150         }
0151     }
0152 
0153     // Return nothing if gpg not found
0154     return QString();
0155 }
0156 
0157 QString escape_string(const QString &in)
0158 {
0159     QString out;
0160     for (const QChar &c : in) {
0161         if (c == QLatin1Char('\\'))
0162             out += QStringLiteral("\\\\");
0163         else if (c == QLatin1Char(':'))
0164             out += QStringLiteral("\\c");
0165         else
0166             out += c;
0167     }
0168     return out;
0169 }
0170 
0171 QString unescape_string(const QString &in)
0172 {
0173     QString out;
0174     for (int n = 0; n < in.length(); ++n) {
0175         if (in[n] == QLatin1Char('\\')) {
0176             if (n + 1 < in.length()) {
0177                 if (in[n + 1] == QLatin1Char('\\'))
0178                     out += QLatin1Char('\\');
0179                 else if (in[n + 1] == QLatin1Char('c'))
0180                     out += QLatin1Char(':');
0181                 ++n;
0182             }
0183         } else
0184             out += in[n];
0185     }
0186     return out;
0187 }
0188 
0189 PGPKey publicKeyFromId(const QString &id)
0190 {
0191     MyKeyStoreList *ksl = MyKeyStoreList::instance();
0192     if (!ksl)
0193         return PGPKey();
0194 
0195     return ksl->publicKeyFromId(id);
0196 }
0197 
0198 PGPKey secretKeyFromId(const QString &id)
0199 {
0200     MyKeyStoreList *ksl = MyKeyStoreList::instance();
0201     if (!ksl)
0202         return PGPKey();
0203 
0204     return ksl->secretKeyFromId(id);
0205 }
0206 
0207 } // end namespace gpgQCAPlugin