a7a57adccfd022a3c53e42cb765b4ae02fc60dd2
[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 char **
76 vector_to_cArray(const std::vector<std::string> &vec)
77 {
78   char ** ret = (char**) xmalloc (sizeof (char*) * (vec.size() + 1));
79   for (size_t i = 0; i < vec.size(); i++)
80     {
81       ret[i] = xstrdup (vec[i].c_str());
82     }
83   ret[vec.size()] = NULL;
84   return ret;
85 }
86
87 std::vector <std::string>
88 cArray_to_vector(const char **cArray)
89 {
90   std::vector<std::string> ret;
91
92   if (!cArray)
93     {
94       return ret;
95     }
96
97   for (int i = 0; cArray[i]; i++)
98     {
99       ret.push_back (std::string (cArray[i]));
100     }
101   return ret;
102 }
103
104 bool
105 in_de_vs_mode()
106 {
107 /* We cache the values only once. A change requires restart.
108      This is because checking this is very expensive as gpgconf
109      spawns each process to query the settings. */
110   static bool checked;
111   static bool vs_mode;
112
113   if (checked)
114     {
115       return vs_mode;
116     }
117   checked = true;
118   GpgME::Error err;
119   const auto components = GpgME::Configuration::Component::load (err);
120   log_debug ("%s:%s: Checking for de-vs mode.",
121              SRCNAME, __func__);
122   if (err)
123     {
124       log_error ("%s:%s: Failed to get gpgconf components: %s",
125                  SRCNAME, __func__, err.asString ());
126       vs_mode = false;
127       return vs_mode;
128     }
129   for (const auto &component: components)
130     {
131       if (component.name () && !strcmp (component.name (), "gpg"))
132         {
133           for (const auto &option: component.options ())
134             {
135               if (option.name () && !strcmp (option.name (), "compliance") &&
136                   option.currentValue ().stringValue () &&
137                   !stricmp (option.currentValue ().stringValue (), "de-vs"))
138                 {
139                   log_debug ("%s:%s: Detected de-vs mode",
140                              SRCNAME, __func__);
141                   vs_mode = true;
142                   return vs_mode;
143                 }
144             }
145           vs_mode = false;
146           return vs_mode;
147         }
148     }
149   vs_mode = false;
150   return false;
151 }
152
153 std::map<std::string, std::string>
154 get_registry_subkeys (const char *path)
155 {
156   HKEY theKey;
157   std::map<std::string, std::string> ret;
158
159   std::string regPath = GPGOL_REGPATH;
160   regPath += "\\";
161   regPath += path;
162
163   if (RegOpenKeyEx (HKEY_CURRENT_USER,
164                     regPath.c_str (),
165                     0, KEY_ENUMERATE_SUB_KEYS | KEY_READ,
166                     &theKey) != ERROR_SUCCESS)
167     {
168       TRACEPOINT;
169       return ret;
170     }
171
172   DWORD values = 0,
173         maxValueName = 0,
174         maxValueLen = 0;
175
176   DWORD err = RegQueryInfoKey (theKey,
177                                nullptr,
178                                nullptr,
179                                nullptr,
180                                nullptr,
181                                nullptr,
182                                nullptr,
183                                &values,
184                                &maxValueName,
185                                &maxValueLen,
186                                nullptr,
187                                nullptr);
188
189   if (err != ERROR_SUCCESS)
190     {
191       TRACEPOINT;
192       RegCloseKey (theKey);
193       return ret;
194     }
195
196   /* Add space for NULL */
197   maxValueName++;
198   maxValueLen++;
199
200   char name[maxValueName + 1];
201   char value[maxValueLen + 1];
202   for (int i = 0; i < values; i++)
203     {
204       DWORD nameLen = maxValueName;
205       err = RegEnumValue (theKey, i,
206                           name,
207                           &nameLen,
208                           nullptr,
209                           nullptr,
210                           nullptr,
211                           nullptr);
212
213       if (err != ERROR_SUCCESS)
214         {
215           TRACEPOINT;
216           continue;
217         }
218
219       DWORD type;
220       DWORD valueLen = maxValueLen;
221       err = RegQueryValueEx (theKey, name,
222                              NULL, &type,
223                              (BYTE*)value, &valueLen);
224
225       if (err != ERROR_SUCCESS)
226         {
227           TRACEPOINT;
228           continue;
229         }
230       if (type != REG_SZ)
231         {
232           TRACEPOINT;
233           continue;
234         }
235       ret.insert (std::make_pair (std::string (name, nameLen),
236                                   std::string (value, valueLen)));
237     }
238   RegCloseKey (theKey);
239   return ret;
240 }
241
242 template<typename Out> void
243 internal_split (const std::string &s, char delim, Out result) {
244   std::stringstream ss(s);
245   std::string item;
246   while (std::getline (ss, item, delim))
247     {
248       *(result++) = item;
249     }
250 }
251
252 std::vector<std::string>
253 gpgol_split (const std::string &s, char delim)
254 {
255   std::vector<std::string> elems;
256   internal_split (s, delim, std::back_inserter (elems));
257   return elems;
258 }
259
260 std::string
261 string_to_hex(const std::string& input)
262 {
263     static const char* const lut = "0123456789ABCDEF";
264     size_t len = input.length();
265
266     std::string output;
267     output.reserve (3 * len + (len * 3 / 26));
268     for (size_t i = 0; i < len; ++i)
269     {
270         const unsigned char c = input[i];
271         output.push_back (lut[c >> 4]);
272         output.push_back (lut[c & 15]);
273         output.push_back (' ');
274         if (i % 26 == 0)
275           {
276             output.push_back ('\n');
277           }
278     }
279     return output;
280 }
281
282 bool
283 is_binary (const std::string &input)
284 {
285   for (int i = 0; i < input.size() - 1; ++i)
286     {
287       const unsigned char c = input[i];
288       if (c < 32 && c != 0x0d && c != 0x0a)
289         {
290           return true;
291         }
292     }
293   return false;
294 }