Imported Upstream version 1.2.99~20120606~SE~ff65aef~SYSYNC~2728cb4
[platform/upstream/syncevolution.git] / src / syncevo / util.h
1 /*
2  * Copyright (C) 2008-2009 Patrick Ohly <patrick.ohly@gmx.de>
3  * Copyright (C) 2009 Intel Corporation
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) version 3.
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 Street, Fifth Floor, Boston, MA
18  * 02110-1301  USA
19  */
20
21 #ifndef INCL_SYNCEVOLUTION_UTIL
22 # define INCL_SYNCEVOLUTION_UTIL
23
24 #include <syncevo/SyncML.h>
25
26 #include <boost/algorithm/string/case_conv.hpp>
27 #include <boost/algorithm/string/predicate.hpp>
28 #include <boost/function.hpp>
29 #include <boost/utility/value_init.hpp>
30
31 #include <stdarg.h>
32
33 #include <vector>
34 #include <sstream>
35 #include <string>
36 #include <utility>
37 #include <exception>
38 #include <list>
39
40 #include <syncevo/Timespec.h>    // definitions used to be included in util.h,
41                                  // include it to avoid changing code using the time things
42 #include <syncevo/Logging.h>
43
44 #include <syncevo/declarations.h>
45 SE_BEGIN_CXX
46
47 class Logger;
48
49 /** case-insensitive less than for assoziative containers */
50 template <class T> class Nocase : public std::binary_function<T, T, bool> {
51 public:
52     bool operator()(const T &x, const T &y) const { return boost::ilexicographical_compare(x, y); }
53 };
54
55 /** case-insensitive equals */
56 template <class T> class Iequals : public std::binary_function<T, T, bool> {
57 public:
58     bool operator()(const T &x, const T &y) const { return boost::iequals(x, y); }
59 };
60
61 /** shorthand, primarily useful for BOOST_FOREACH macro */
62 typedef std::pair<std::string, std::string> StringPair;
63 typedef std::map<std::string, std::string> StringMap;
64
65 /**
66  * remove multiple slashes in a row and dots directly after a slash if not followed by filename,
67  * remove trailing /
68  */
69 std::string normalizePath(const std::string &path);
70
71 /**
72  * Returns last component of path. Trailing slash is ignored.
73  * Empty if path is empty.
74  */
75 std::string getBasename(const std::string &path);
76
77 /**
78  * Returns path without the last component. Empty if nothing left.
79  */
80 std::string getDirname(const std::string &path);
81
82 /**
83  * Splits path into directory and file part. Trailing slashes
84  * are stripped first.
85  */
86 void splitPath(const std::string &path, std::string &dir, std::string &file);
87
88 /**
89  * convert relative path to canonicalized absolute path
90  * @param path will be turned into absolute path if possible, otherwise left unchanged
91  * @return true if conversion is successful, false otherwise(errno will be set)
92  */
93 bool relToAbs(std::string &path);
94
95 /** ensure that m_path is writable, otherwise throw error */
96 void mkdir_p(const std::string &path);
97
98 inline bool rm_r_all(const std::string &path, bool isDir) { return true; }
99
100 /**
101  * remove a complete directory hierarchy; invoking on non-existant directory is okay
102  * @param path     relative or absolute path to be removed
103  * @param filter   an optional callback which determines whether an entry really is
104  *                 to be deleted (return true in that case); called with full path
105  *                 to entry and true if known to be a directory
106  */
107 void rm_r(const std::string &path, boost::function<bool (const std::string &,
108                                                     bool)> filter = rm_r_all);
109
110 /**
111  * copy complete directory hierarchy
112  *
113  * If the source is a directory, then the target
114  * also has to be a directory name. It will be
115  * created if necessary.
116  *
117  * Alternatively, both names may refer to files.
118  * In that case the directory which is going to
119  * contain the target file must exist.
120  *
121  * @param from     source directory or file
122  * @param to       target directory or file (must have same type as from)
123  */
124 void cp_r(const std::string &from, const std::string &to);
125
126 /** true if the path refers to a directory */
127 bool isDir(const std::string &path);
128
129 /**
130  * try to read a file into the given string, throw exception if fails
131  *
132  * @param filename     absolute or relative file name
133  * @retval content     filled with file content
134  * @return true if file could be read
135  */
136 bool ReadFile(const std::string &filename, std::string &content);
137 bool ReadFile(std::istream &in, std::string &content);
138
139 enum ExecuteFlags {
140     EXECUTE_NO_STDERR = 1<<0,       /**< suppress stderr of command */
141     EXECUTE_NO_STDOUT = 1<<1        /**< suppress stdout of command */
142 };
143
144 /**
145  * system() replacement
146  *
147  * If called without output redirection active (see LogRedirect),
148  * then it will simply call system(). If output redirection is
149  * active, the command is executed in a forked process without
150  * blocking the parent process and the parent reads the output,
151  * passing it through LogRedirect for processing.
152  *
153  * This is necessary to capture all output reliably: LogRedirect
154  * ensures that we don't deadlock, but to achieve that, it drops
155  * data when the child prints too much of it.
156  *
157  * @param cmd      command including parameters, without output redirection
158  * @param flags    see ExecuteFlags
159  * @return same as in system(): use WEXITSTATUS() et.al. to decode it
160  */
161 int Execute(const std::string &cmd, ExecuteFlags flags) throw();
162
163 /**
164  * Simple string hash function, derived from Dan Bernstein's algorithm.
165  */
166 unsigned long Hash(const char *str);
167 unsigned long Hash(const std::string &str);
168
169 /**
170  * SHA-256 implementation, returning hash as lowercase hex string (like sha256sum).
171  * Might not be available, in which case it raises an exception.
172  */
173 std::string SHA_256(const std::string &in);
174
175 /**
176  * escape/unescape code
177  *
178  * Escaping is done URL-like, with a configurable escape
179  * character. The exact set of characters to replace (besides the
180  * special escape character) is configurable, too.
181  *
182  * The code used to be in SafeConfigNode, but is of general value.
183  */
184 class StringEscape
185 {
186  public:
187     enum Mode {
188         SET,               /**< explicit list of characters to be escaped */
189         INI_VALUE,         /**< right hand side of .ini assignment:
190                               escape all spaces at start and end (but not in the middle) and the equal sign */
191         INI_WORD,          /**< same as before, but keep it one word:
192                               escape all spaces and the equal sign = */
193         STRICT             /**< general purpose:
194                               escape all characters besides alphanumeric and -_ */
195     };
196
197  private:
198     char m_escapeChar;
199     Mode m_mode;
200     std::set<char> m_forbidden;
201
202  public:
203     /**
204      * default constructor, using % as escape character, escaping all spaces (including
205      * leading and trailing ones), and all characters besides alphanumeric and -_
206      */
207     StringEscape(char escapeChar = '%', Mode mode = STRICT) :
208         m_escapeChar(escapeChar),
209         m_mode(mode)
210     {}
211
212     /**
213      * @param escapeChar        character used to introduce escape sequence
214      * @param forbidden         explicit list of characters which are to be escaped
215      */
216     StringEscape(char escapeChar, const char *forbidden);
217
218     /** special character which introduces two-char hex encoded original character */
219     char getEscapeChar() const { return m_escapeChar; }
220     void setEscapeChar(char escapeChar) { m_escapeChar = escapeChar; }
221
222     Mode getMode() const { return m_mode; }
223     void setMode(Mode mode) { m_mode = mode; }
224
225     /**
226      * escape string according to current settings
227      */
228     std::string escape(const std::string &str) const;
229
230     /** escape string with the given settings */
231     static std::string escape(const std::string &str, char escapeChar, Mode mode);
232
233     /**
234      * unescape string, with escape character as currently set
235      */
236     std::string unescape(const std::string &str) const { return unescape(str, m_escapeChar); }
237
238     /**
239      * unescape string, with escape character as given
240      */
241     static std::string unescape(const std::string &str, char escapeChar);
242 };
243
244 /**
245  * This is a simplified implementation of a class representing and calculating
246  * UUIDs v4 inspired from RFC 4122. We do not use cryptographic pseudo-random
247  * numbers, instead we rely on rand/srand.
248  *
249  * We initialize the random generation with the system time given by time(), but
250  * only once.
251  *
252  * Instantiating this class will generate a new unique UUID, available afterwards
253  * in the base string class.
254  */
255 class UUID : public std::string {
256  public:
257     UUID();
258 };
259
260 /**
261  * Safety check for string pointer.
262  * Returns pointer if valid, otherwise the default string.
263  */
264 inline const char *NullPtrCheck(const char *ptr, const char *def = "(null)")
265 {
266     return ptr ? ptr : def;
267 }
268
269 /**
270  * A C++ wrapper around readir() which provides the names of all
271  * directory entries, excluding . and ..
272  *
273  */
274 class ReadDir {
275  public:
276     ReadDir(const std::string &path, bool throwError = true);
277
278     typedef std::vector<std::string>::const_iterator const_iterator;
279     typedef std::vector<std::string>::iterator iterator;
280     iterator begin() { return m_entries.begin(); }
281     iterator end() { return m_entries.end(); }
282     const_iterator begin() const { return m_entries.begin(); }
283     const_iterator end() const { return m_entries.end(); }
284
285     /**
286      * check whether directory contains entry, returns full path
287      * @param caseInsensitive    ignore case, pick first entry which matches randomly
288      */
289     std::string find(const std::string &entry, bool caseSensitive);
290
291  private:
292     std::string m_path;
293     std::vector<std::string> m_entries;
294 };
295
296 /**
297  * Using this macro ensures that tests, even if defined in
298  * object files which are not normally linked into the test
299  * binary, are included in the test suite under the group
300  * "SyncEvolution".
301  *
302  * Use it like this:
303  * @verbatim
304    #include "config.h"
305    #ifdef ENABLE_UNIT_TESTS
306    # include "test.h"
307    class Foo : public CppUnit::TestFixture {
308        CPPUNIT_TEST_SUITE(foo);
309        CPPUNIT_TEST(testBar);
310        CPPUNIT_TEST_SUITE_END();
311
312      public:
313        void testBar();
314    };
315    # SYNCEVOLUTION_TEST_SUITE_REGISTRATION(classname)
316    #endif
317    @endverbatim
318  */
319 #define SYNCEVOLUTION_TEST_SUITE_REGISTRATION( ATestFixtureType ) \
320     CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ATestFixtureType, "SyncEvolution" ); \
321     extern "C" { int funambolAutoRegisterRegistry ## ATestFixtureType = 12345; }
322
323 std::string StringPrintf(const char *format, ...)
324 #ifdef __GNUC__
325         __attribute__((format(printf, 1, 2)))
326 #endif
327 ;
328 std::string StringPrintfV(const char *format, va_list ap);
329
330 /**
331  * strncpy() which inserts adds 0 byte
332  */
333 char *Strncpy(char *dest, const char *src, size_t n);
334
335 /**
336  * sleep() with sub-second resolution. Might be interrupted by signals
337  * before the time has elapsed.
338  */
339 void Sleep(double seconds);
340
341 /**
342  * Acts like the underlying type. In addition ensures that plain types
343  * are not left uninitialized.
344  */
345 template<class T> class Init {
346  public:
347     Init(const T &val) : m_value(val) {}
348     Init() : m_value(boost::value_initialized<T>()) {}
349     Init(const Init &other) : m_value(other.m_value) {}
350     Init & operator = (const T &val) { m_value = val; return *this; }
351     operator const T & () const { return m_value; }
352     operator T & () { return m_value; }
353  private:
354     T m_value;
355 };
356
357
358 /**
359  * Version of InitState for scalar values (can't derive from them):
360  * acts like the underlying type. In addition ensures that plain types
361  * are not left uninitialized and tracks whether a value was every
362  * assigned explicitly.
363  */
364 template<class T> class InitState {
365  public:
366     typedef T value_type;
367
368     InitState(const T &val, bool wasSet) : m_value(val), m_wasSet(wasSet) {}
369     InitState() : m_value(boost::value_initialized<T>()), m_wasSet(false) {}
370     InitState(const InitState &other) : m_value(other.m_value), m_wasSet(other.m_wasSet) {}
371     InitState & operator = (const T &val) { m_value = val; m_wasSet = true; return *this; }
372     operator const T & () const { return m_value; }
373     operator T & () { return m_value; }
374     const T & get() const { return m_value; }
375     T & get() { return m_value; }
376     bool wasSet() const { return m_wasSet; }
377  private:
378     T m_value;
379     bool m_wasSet;
380 };
381
382 /** version of InitState for classes */
383 template<class T> class InitStateClass : public T {
384  public:
385     typedef T value_type;
386
387     InitStateClass(const T &val, bool wasSet) : T(val), m_wasSet(wasSet) {}
388     InitStateClass() : m_wasSet(false) {}
389     InitStateClass(const char *val) : T(val), m_wasSet(false) {}
390     InitStateClass(const InitStateClass &other) : T(other), m_wasSet(other.m_wasSet) {}
391     InitStateClass & operator = (const T &val) { T::operator = (val); m_wasSet = true; return *this; }
392     const T & get() const { return *this; }
393     T & get() { return *this; }
394     bool wasSet() const { return m_wasSet; }
395  private:
396     bool m_wasSet;
397 };
398
399 /**
400  * a nop destructor which doesn't do anything, for boost::shared_ptr
401  */
402 struct NopDestructor
403 {
404     template <class T> void operator () (T *) {}
405 };
406
407 /**
408  * Acts like a boolean, but in addition, can also tell whether the
409  * value was explicitly set. Defaults to false for both.
410  */
411 typedef InitState<bool> Bool;
412
413 /**
414  * Acts like a string, but in addition, can also tell whether the
415  * value was explicitly set.
416  */
417 typedef InitStateClass<std::string> InitStateString;
418
419 /**
420  * Version of InitState where the value can true, false, or a string.
421  * Recognizes 0/1/false/true/no/yes case-insensitively as special
422  * booleans, everything else is considered a string.
423  */
424 class InitStateTri : public InitStateString
425 {
426  public:
427     InitStateTri(const std::string &val, bool wasSet) : InitStateString(val, wasSet) {}
428     InitStateTri() {}
429     InitStateTri(const char *val) : InitStateString(val, false) {}
430     InitStateTri(const InitStateTri &other) : InitStateString(other) {}
431     InitStateTri(const InitStateString &other) : InitStateString(other) {}
432
433     enum Value {
434         VALUE_TRUE,
435         VALUE_FALSE,
436         VALUE_STRING
437     };
438
439     // quick check for true/false, use get() for string case
440     Value getValue() const;
441 };
442
443 enum HandleExceptionFlags {
444     HANDLE_EXCEPTION_FLAGS_NONE = 0,
445
446     /**
447      * a 404 status error is possible and must not be logged as ERROR
448      */
449     HANDLE_EXCEPTION_404_IS_OKAY = 1 << 0,
450     HANDLE_EXCEPTION_FATAL = 1 << 1,
451     /**
452      * don't log exception as ERROR
453      */
454     HANDLE_EXCEPTION_NO_ERROR = 1 << 2,
455     HANDLE_EXCEPTION_MAX = 1 << 3,
456 };
457
458 /**
459  * an exception which records the source file and line
460  * where it was thrown
461  *
462  * @TODO add function name
463  */
464 class Exception : public std::runtime_error
465 {
466  public:
467     Exception(const std::string &file,
468                            int line,
469                            const std::string &what) :
470     std::runtime_error(what),
471         m_file(file),
472         m_line(line)
473         {}
474     ~Exception() throw() {}
475     const std::string m_file;
476     const int m_line;
477
478     /**
479      * Convenience function, to be called inside a catch(..) block.
480      *
481      * Rethrows the exception to determine what it is, then logs it
482      * at the chosen level (error by default).
483      *
484      * Turns certain known exceptions into the corresponding
485      * status code if status still was STATUS_OK when called.
486      * Returns updated status code.
487      *
488      * @param logger    the class which does the logging
489      * @retval explanation   set to explanation for problem, if non-NULL
490      * @param level     level to be used for logging
491      */
492     static SyncMLStatus handle(SyncMLStatus *status = NULL, Logger *logger = NULL, std::string *explanation = NULL, Logger::Level = Logger::ERROR, HandleExceptionFlags flags = HANDLE_EXCEPTION_FLAGS_NONE);
493     static SyncMLStatus handle(Logger *logger, HandleExceptionFlags flags = HANDLE_EXCEPTION_FLAGS_NONE) { return handle(NULL, logger, NULL, Logger::ERROR, flags); }
494     static SyncMLStatus handle(std::string &explanation, HandleExceptionFlags flags = HANDLE_EXCEPTION_FLAGS_NONE) { return handle(NULL, NULL, &explanation, Logger::ERROR, flags); }
495     static void handle(HandleExceptionFlags flags) { handle(NULL, NULL, NULL, Logger::ERROR, flags); }
496     static void log() { handle(NULL, NULL, NULL, Logger::DEBUG); }
497
498     /**
499      * Tries to identify exception class based on explanation string created by
500      * handle(). If successful, that exception is throw with the same
501      * attributes as in the original exception. Otherwise parse() returns.
502      */
503     static void tryRethrow(const std::string &explanation);
504
505     /**
506      * Same as tryRethrow() for strings with a 'org.syncevolution.xxxx:' prefix,
507      * as passed as D-Bus error strings.
508      */
509     static void tryRethrowDBus(const std::string &error);
510 };
511
512 /**
513  * StatusException by wrapping a SyncML status
514  */
515 class StatusException : public Exception
516 {
517 public:
518     StatusException(const std::string &file,
519                     int line,
520                     const std::string &what,
521                     SyncMLStatus status)
522         : Exception(file, line, what), m_status(status)
523     {}
524
525     SyncMLStatus syncMLStatus() const { return m_status; }
526 protected:
527     SyncMLStatus m_status;
528 };
529
530 class TransportException : public Exception
531 {
532  public:
533     TransportException(const std::string &file,
534                        int line,
535                        const std::string &what) :
536     Exception(file, line, what) {}
537     ~TransportException() throw() {}
538 };
539
540 class TransportStatusException : public StatusException
541 {
542  public:
543     TransportStatusException(const std::string &file,
544                              int line,
545                              const std::string &what,
546                              SyncMLStatus status) :
547     StatusException(file, line, what, status) {}
548     ~TransportStatusException() throw() {}
549 };
550
551 /**
552  * replace ${} with environment variables, with
553  * XDG_DATA_HOME, XDG_CACHE_HOME and XDG_CONFIG_HOME having their normal
554  * defaults
555  */
556 std::string SubstEnvironment(const std::string &str);
557
558 /** getenv() with default value */
559 inline const char *getEnv(const char *var, const char *def)
560 {
561     const char *res = getenv(var);
562     return res ? res : def;
563 }
564
565 inline std::string getHome() { return getEnv("HOME", "."); }
566
567 /**
568  * Parse a separator splitted set of strings src, the separator itself is
569  * escaped by a backslash. Spaces around the separator is also stripped.
570  * */
571 std::vector<std::string> unescapeJoinedString (const std::string &src, char separator);
572
573 /**
574  * mapping from int flag to explanation
575  */
576 struct Flag {
577     int m_flag;
578     const char *m_description;
579 };
580
581 /**
582  * turn flags into comma separated list of explanations
583  *
584  * @param flags     bit mask
585  * @param descr     array with zero m_flag as end marker
586  * @param sep       used to join m_description strings
587  */
588 std::string Flags2String(int flags, const Flag *descr, const std::string &sep = ", ");
589
590 /**
591  * Returns the path to the data directory. This is generally
592  * /usr/share/syncevolution/ but can be overridden by setting the
593  * SYNCEVOLUTION_DATA_DIR environment variable.
594  *
595  * @retval dataDir the path to the data directory
596  */
597 std::string SyncEvolutionDataDir();
598
599 /**
600  * Temporarily set env variable, restore old value on destruction.
601  * Useful for unit tests which depend on the environment.
602  */
603 class ScopedEnvChange
604 {
605  public:
606     ScopedEnvChange(const std::string &var, const std::string &value);
607     ~ScopedEnvChange();
608  private:
609     std::string m_var, m_oldval;
610     bool m_oldvalset;
611 };
612
613 std::string getCurrentTime();
614
615 /** throw a normal SyncEvolution Exception, including source information */
616 #define SE_THROW(_what) \
617     SE_THROW_EXCEPTION(Exception, _what)
618
619 /** throw a class which accepts file, line, what parameters */
620 #define SE_THROW_EXCEPTION(_class,  _what) \
621     throw _class(__FILE__, __LINE__, _what)
622
623 /** throw a class which accepts file, line, what plus 1 additional parameter */
624 #define SE_THROW_EXCEPTION_1(_class,  _what, _x1)   \
625     throw _class(__FILE__, __LINE__, (_what), (_x1))
626
627 /** throw a class which accepts file, line, what plus 2 additional parameters */
628 #define SE_THROW_EXCEPTION_2(_class,  _what, _x1, _x2) \
629     throw _class(__FILE__, __LINE__, (_what), (_x1), (_x2))
630
631 /** throw a class which accepts file, line, what plus 2 additional parameters */
632 #define SE_THROW_EXCEPTION_3(_class,  _what, _x1, _x2, _x3) \
633     throw _class(__FILE__, __LINE__, (_what), (_x1), (_x2), (_x3))
634
635 /** throw a class which accepts file, line, what plus 2 additional parameters */
636 #define SE_THROW_EXCEPTION_4(_class,  _what, _x1, _x2, _x3, _x4) \
637     throw _class(__FILE__, __LINE__, (_what), (_x1), (_x2), (_x3), (_x4))
638
639 /** throw a class which accepts file, line, what parameters and status parameters*/
640 #define SE_THROW_EXCEPTION_STATUS(_class,  _what, _status) \
641     throw _class(__FILE__, __LINE__, _what, _status)
642
643 SE_END_CXX
644 #endif // INCL_SYNCEVOLUTION_UTIL