1 | /* |
2 | * Copyright (C) 2003-2008 Justin Karneges <justin@affinix.com> |
3 | * Copyright (C) 2014 Ivan Romanov <drizt@land.ru> |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2.1 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this library; if not, write to the Free Software |
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
18 | */ |
19 | |
20 | #include "utils.h" |
21 | #include "mykeystorelist.h" |
22 | #include <QCoreApplication> |
23 | #include <QFileInfo> |
24 | #include <QStringList> |
25 | #ifdef Q_OS_WIN |
26 | #include <windows.h> |
27 | #endif |
28 | |
29 | using namespace QCA; |
30 | |
31 | namespace gpgQCAPlugin { |
32 | |
33 | void gpg_waitForFinished(GpgOp *gpg) |
34 | { |
35 | while (true) { |
36 | GpgOp::Event e = gpg->waitForEvent(msecs: -1); |
37 | if (e.type == GpgOp::Event::Finished) |
38 | break; |
39 | } |
40 | } |
41 | |
42 | void gpg_keyStoreLog(const QString &str) |
43 | { |
44 | MyKeyStoreList *ksl = MyKeyStoreList::instance(); |
45 | if (ksl) |
46 | ksl->ext_keyStoreLog(str); |
47 | } |
48 | |
49 | inline bool check_bin(const QString &bin) |
50 | { |
51 | QFileInfo fi(bin); |
52 | return fi.exists(); |
53 | } |
54 | |
55 | #ifdef Q_OS_WIN |
56 | static bool get_reg_key(HKEY root, const char *path, QString &value) |
57 | { |
58 | HKEY hkey = 0; |
59 | |
60 | char szValue[256]; |
61 | DWORD dwLen = 256; |
62 | |
63 | bool res = false; |
64 | |
65 | if (RegOpenKeyExA(root, path, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) { |
66 | if (RegQueryValueExA(hkey, "Install Directory" , NULL, NULL, (LPBYTE)szValue, &dwLen) == ERROR_SUCCESS) { |
67 | value = QString::fromLocal8Bit(szValue); |
68 | res = true; |
69 | } |
70 | RegCloseKey(hkey); |
71 | } |
72 | return res; |
73 | } |
74 | |
75 | static QString find_reg_gpgProgram() |
76 | { |
77 | const QStringList bins = {QStringLiteral("gpg.exe" ), QStringLiteral("gpg2.exe" )}; |
78 | |
79 | HKEY root; |
80 | root = HKEY_CURRENT_USER; |
81 | |
82 | const char *path = "Software\\GNU\\GnuPG" ; |
83 | const char *path2 = "Software\\Wow6432Node\\GNU\\GnuPG" ; |
84 | |
85 | QString dir; |
86 | // check list of possible places in registry |
87 | get_reg_key(HKEY_CURRENT_USER, path, dir) || get_reg_key(HKEY_CURRENT_USER, path2, dir) || |
88 | get_reg_key(HKEY_LOCAL_MACHINE, path, dir) || get_reg_key(HKEY_LOCAL_MACHINE, path2, dir); |
89 | |
90 | if (!dir.isEmpty()) { |
91 | foreach (const QString &bin, bins) { |
92 | if (check_bin(dir + QStringLiteral("\\" ) + bin)) { |
93 | return dir + QStringLiteral("\\" ) + bin; |
94 | } |
95 | } |
96 | } |
97 | return QString(); |
98 | } |
99 | #endif |
100 | |
101 | QString find_bin() |
102 | { |
103 | // gpg and gpg2 has identical semantics |
104 | // so any from them can be used |
105 | QStringList bins; |
106 | #ifdef Q_OS_WIN |
107 | bins << QStringLiteral("gpg.exe" ) << QStringLiteral("gpg2.exe" ); |
108 | #else |
109 | bins << QStringLiteral("gpg" ) << QStringLiteral("gpg2" ); |
110 | #endif |
111 | |
112 | // Prefer bundled gpg |
113 | foreach (const QString &bin, bins) { |
114 | if (check_bin(bin: QCoreApplication::applicationDirPath() + QLatin1Char('/') + bin)) { |
115 | return QCoreApplication::applicationDirPath() + QLatin1Char('/') + bin; |
116 | } |
117 | } |
118 | |
119 | #ifdef Q_OS_WIN |
120 | // On Windows look up at registry |
121 | QString bin = find_reg_gpgProgram(); |
122 | if (!bin.isEmpty()) |
123 | return bin; |
124 | #endif |
125 | |
126 | // Look up at PATH environment |
127 | #ifdef Q_OS_WIN |
128 | const QString pathSep = QStringLiteral(";" ); |
129 | #else |
130 | const QString pathSep = QStringLiteral(":" ); |
131 | #endif |
132 | |
133 | QStringList paths = QString::fromLocal8Bit(ba: qgetenv(varName: "PATH" )).split(sep: pathSep, behavior: Qt::SkipEmptyParts); |
134 | |
135 | #ifdef Q_OS_MAC |
136 | // On Mac OS bundled always uses system default PATH |
137 | // so it need explicity add extra paths which can |
138 | // contain gpg |
139 | // Mac GPG and brew use /usr/local/bin |
140 | // MacPorts uses /opt/local/bin |
141 | paths << QStringLiteral("/usr/local/bin" ) << QStringLiteral("/opt/local/bin" ); |
142 | #endif |
143 | paths.removeDuplicates(); |
144 | |
145 | foreach (const QString &path, paths) { |
146 | foreach (const QString &bin, bins) { |
147 | if (check_bin(bin: path + QLatin1Char('/') + bin)) { |
148 | return path + QLatin1Char('/') + bin; |
149 | } |
150 | } |
151 | } |
152 | |
153 | // Return nothing if gpg not found |
154 | return QString(); |
155 | } |
156 | |
157 | QString escape_string(const QString &in) |
158 | { |
159 | QString out; |
160 | for (const QChar &c : in) { |
161 | if (c == QLatin1Char('\\')) |
162 | out += QStringLiteral("\\\\" ); |
163 | else if (c == QLatin1Char(':')) |
164 | out += QStringLiteral("\\c" ); |
165 | else |
166 | out += c; |
167 | } |
168 | return out; |
169 | } |
170 | |
171 | QString unescape_string(const QString &in) |
172 | { |
173 | QString out; |
174 | for (int n = 0; n < in.length(); ++n) { |
175 | if (in[n] == QLatin1Char('\\')) { |
176 | if (n + 1 < in.length()) { |
177 | if (in[n + 1] == QLatin1Char('\\')) |
178 | out += QLatin1Char('\\'); |
179 | else if (in[n + 1] == QLatin1Char('c')) |
180 | out += QLatin1Char(':'); |
181 | ++n; |
182 | } |
183 | } else |
184 | out += in[n]; |
185 | } |
186 | return out; |
187 | } |
188 | |
189 | PGPKey publicKeyFromId(const QString &id) |
190 | { |
191 | MyKeyStoreList *ksl = MyKeyStoreList::instance(); |
192 | if (!ksl) |
193 | return PGPKey(); |
194 | |
195 | return ksl->publicKeyFromId(keyId: id); |
196 | } |
197 | |
198 | PGPKey secretKeyFromId(const QString &id) |
199 | { |
200 | MyKeyStoreList *ksl = MyKeyStoreList::instance(); |
201 | if (!ksl) |
202 | return PGPKey(); |
203 | |
204 | return ksl->secretKeyFromId(keyId: id); |
205 | } |
206 | |
207 | } // end namespace gpgQCAPlugin |
208 | |