Add signature info to verify category
[gpgol.git] / src / cpphelp.cpp
1 /* @file cpphelp.h
2  * @brief Common cpp helper stuff
3  *
4  * Copyright (C) 2018 Intevation GmbH
5  *
6  * This file is part of GpgOL.
7  *
8  * GpgOL is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * GpgOL is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "config.h"
23
24 #include "cpphelp.h"
25
26 #include <algorithm>
27 #include <sstream>
28 #include <vector>
29 #include <iterator>
30
31 #include "common.h"
32
33 #include <gpgme++/context.h>
34 #include <gpgme++/error.h>
35 #include <gpgme++/configuration.h>
36
37 #include <windows.h>
38
39 void
40 release_cArray (char **carray)
41 {
42   if (carray)
43     {
44       for (int idx = 0; carray[idx]; idx++)
45         {
46           xfree (carray[idx]);
47         }
48       xfree (carray);
49     }
50 }
51
52 void
53 rtrim(std::string &s)
54 {
55   s.erase (std::find_if (s.rbegin(), s.rend(), [] (int ch) {
56       return !std::isspace(ch);
57   }).base(), s.end());
58 }
59
60 void
61 ltrim(std::string &s)
62 {
63   s.erase (s.begin(), std::find_if (s.begin(), s.end(), [] (int ch) {
64       return !std::isspace(ch);
65   }));
66 }
67
68 void
69 trim(std::string &s)
70 {
71   ltrim (s);
72   rtrim (s);
73 }
74
75 void
76 join(const std::vector<std::string>& v, const char *c, std::string& s)
77 {
78   s.clear();
79   for (auto p = v.begin(); p != v.end(); ++p)
80     {
81       s += *p;
82       if (p != v.end() - 1)
83         {
84           s += c;
85         }
86     }
87 }
88
89 char **
90 vector_to_cArray(const std::vector<std::string> &vec)
91 {
92   char ** ret = (char**) xmalloc (sizeof (char*) * (vec.size() + 1));
93   for (size_t i = 0; i < vec.size(); i++)
94     {
95       ret[i] = xstrdup (vec[i].c_str());
96     }
97   ret[vec.size()] = NULL;
98   return ret;
99 }
100
101 std::vector <std::string>
102 cArray_to_vector(const char **cArray)
103 {
104   std::vector<std::string> ret;
105
106   if (!cArray)
107     {
108       return ret;
109     }
110
111   for (int i = 0; cArray[i]; i++)
112     {
113       ret.push_back (std::string (cArray[i]));
114     }
115   return ret;
116 }
117
118 bool
119 in_de_vs_mode()
120 {
121 /* We cache the values only once. A change requires restart.
122      This is because checking this is very expensive as gpgconf
123      spawns each process to query the settings. */
124   static bool checked;
125   static bool vs_mode;
126
127   if (checked)
128     {
129       return vs_mode;
130     }
131   checked = true;
132   GpgME::Error err;
133   const auto components = GpgME::Configuration::Component::load (err);
134   log_debug ("%s:%s: Checking for de-vs mode.",
135              SRCNAME, __func__);
136   if (err)
137     {
138       log_error ("%s:%s: Failed to get gpgconf components: %s",
139                  SRCNAME, __func__, err.asString ());
140       vs_mode = false;
141       return vs_mode;
142     }
143   for (const auto &component: components)
144     {
145       if (component.name () && !strcmp (component.name (), "gpg"))
146         {
147           for (const auto &option: component.options ())
148             {
149               if (option.name () && !strcmp (option.name (), "compliance") &&
150                   option.currentValue ().stringValue () &&
151                   !stricmp (option.currentValue ().stringValue (), "de-vs"))
152                 {
153                   log_debug ("%s:%s: Detected de-vs mode",
154                              SRCNAME, __func__);
155                   vs_mode = true;
156                   return vs_mode;
157                 }
158             }
159           vs_mode = false;
160           return vs_mode;
161         }
162     }
163   vs_mode = false;
164   return false;
165 }
166
167 std::map<std::string, std::string>
168 get_registry_subkeys (const char *path)
169 {
170   HKEY theKey;
171   std::map<std::string, std::string> ret;
172
173   std::string regPath = GPGOL_REGPATH;
174   regPath += "\\";
175   regPath += path;
176
177   if (RegOpenKeyEx (HKEY_CURRENT_USER,
178                     regPath.c_str (),
179                     0, KEY_ENUMERATE_SUB_KEYS | KEY_READ,
180                     &theKey) != ERROR_SUCCESS)
181     {
182       TRACEPOINT;
183       return ret;
184     }
185
186   DWORD values = 0,
187         maxValueName = 0,
188         maxValueLen = 0;
189
190   DWORD err = RegQueryInfoKey (theKey,
191                                nullptr,
192                                nullptr,
193                                nullptr,
194                                nullptr,
195                                nullptr,
196                                nullptr,
197                                &values,
198                                &maxValueName,
199                                &maxValueLen,
200                                nullptr,
201                                nullptr);
202
203   if (err != ERROR_SUCCESS)
204     {
205       TRACEPOINT;
206       RegCloseKey (theKey);
207       return ret;
208     }
209
210   /* Add space for NULL */
211   maxValueName++;
212   maxValueLen++;
213
214   char name[maxValueName + 1];
215   char value[maxValueLen + 1];
216   for (int i = 0; i < values; i++)
217     {
218       DWORD nameLen = maxValueName;
219       err = RegEnumValue (theKey, i,
220                           name,
221                           &nameLen,
222                           nullptr,
223                           nullptr,
224                           nullptr,
225                           nullptr);
226
227       if (err != ERROR_SUCCESS)
228         {
229           TRACEPOINT;
230           continue;
231         }
232
233       DWORD type;
234       DWORD valueLen = maxValueLen;
235       err = RegQueryValueEx (theKey, name,
236                              NULL, &type,
237                              (BYTE*)value, &valueLen);
238
239       if (err != ERROR_SUCCESS)
240         {
241           TRACEPOINT;
242           continue;
243         }
244       if (type != REG_SZ)
245         {
246           TRACEPOINT;
247           continue;
248         }
249       ret.insert (std::make_pair (std::string (name, nameLen),
250                                   std::string (value, valueLen)));
251     }
252   RegCloseKey (theKey);
253   return ret;
254 }
255
256 template<typename Out> void
257 internal_split (const std::string &s, char delim, Out result) {
258   std::stringstream ss(s);
259   std::string item;
260   while (std::getline (ss, item, delim))
261     {
262       *(result++) = item;
263     }
264 }
265
266 std::vector<std::string>
267 gpgol_split (const std::string &s, char delim)
268 {
269   std::vector<std::string> elems;
270   internal_split (s, delim, std::back_inserter (elems));
271   return elems;
272 }
273
274 std::string
275 string_to_hex(const std::string& input)
276 {
277     static const char* const lut = "0123456789ABCDEF";
278     size_t len = input.length();
279
280     std::string output;
281     output.reserve (3 * len + (len * 3 / 26));
282     for (size_t i = 0; i < len; ++i)
283     {
284         const unsigned char c = input[i];
285         output.push_back (lut[c >> 4]);
286         output.push_back (lut[c & 15]);
287         output.push_back (' ');
288         if (i % 26 == 0)
289           {
290             output.push_back ('\n');
291           }
292     }
293     return output;
294 }
295
296 bool
297 is_binary (const std::string &input)
298 {
299   for (int i = 0; i < input.size() - 1; ++i)
300     {
301       const unsigned char c = input[i];
302       if (c < 32 && c != 0x0d && c != 0x0a)
303         {
304           return true;
305         }
306     }
307   return false;
308 }
309
310 const char *
311 to_cstr (const GpgME::Protocol &prot)
312 {
313   return prot == GpgME::CMS ? "S/MIME" :
314          prot == GpgME::OpenPGP ? "OpenPGP" :
315          "Unknown Protocol";
316 }