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