44598163469bd901f069eb0e43c366205f4806ae
[platform/upstream/syncevolution.git] / src / syncevo / SyncConfig.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 #ifndef INCL_SYNC_EVOLUTION_CONFIG
21 # define INCL_SYNC_EVOLUTION_CONFIG
22
23 #include <syncevo/FilterConfigNode.h>
24 #include <syncevo/SafeConfigNode.h>
25 #include <syncevo/FileConfigNode.h>
26
27 #include <boost/shared_ptr.hpp>
28 #include <boost/algorithm/string/predicate.hpp>
29 #include <boost/algorithm/string/trim.hpp>
30 #include <boost/foreach.hpp>
31 #include <list>
32 #include <string>
33 #include <sstream>
34 #include <set>
35
36 #include <stdlib.h>
37 #include <limits.h>
38 #include <errno.h>
39
40 #include <syncevo/declarations.h>
41 SE_BEGIN_CXX
42 using namespace std;
43
44 /**
45  * @defgroup ConfigHandling Configuration Handling
46  * @{
47  */
48
49 class SyncSourceConfig;
50 typedef SyncSourceConfig PersistentSyncSourceConfig;
51 class ConfigTree;
52 class ConfigUserInterface;
53 class SyncSourceNodes;
54 class ConstSyncSourceNodes;
55
56 /** name of the per-source admin data property */
57 extern const char *const SourceAdminDataName;
58
59 /**
60  * A property has a name and a comment. Derived classes might have
61  * additional code to read and write the property from/to a
62  * ConfigNode. They might also one or more  of the properties
63  * on the fly, therefore the virtual get methods which return a
64  * string value and not just a reference.
65  *
66  * A default value is returned if the ConfigNode doesn't have
67  * a value set (= empty string). Invalid values in the configuration
68  * trigger an exception. Setting invalid values does not because
69  * it is not known where the value comes from - the caller should
70  * check it himself.
71  *
72  * Properties are either registered as source properties or
73  * source-independent sync properties. In each of these two sets of
74  * properties, the names must be unique.
75  *
76  * Properties can be either user-visible (and editable) or
77  * internal. Internal properties are used to cache some information
78  * and may get lost when copying configurations. Therefore it
79  * must be possible to recreate them somehow, if necessary with
80  * an expensive operation like a slow sync.
81  *
82  * Starting with SyncEvolution 1.0, the internal storage of
83  * property values was reorganized so that some properties
84  * can be shared between peers. The concept of two property
85  * sets (source and sync properties) was preserved because of
86  * the simplicity that it brings to the APIs. Now this concept
87  * is implemented by mapping properties into "views" that
88  * contain the properties relevant for a particular peer.
89  * Setting a shared value in one view updates the value in
90  * another. For details, see:
91  * http://syncevolution.org/development/configuration-handling
92  *
93  * As in the migration from the Sync4j config layout (internal and
94  * user-visible properties in the same file), the code is written so
95  * that properties are mapped to config nodes according to the most
96  * recent layout. Older layouts are accessed by using the same config
97  * node instance multiple times.
98  */
99 class ConfigProperty {
100  public:
101     ConfigProperty(const string &name, const string &comment,
102                    const string &def = string(""), const string &descr = string("")) :
103         m_obligatory(false),
104         m_hidden(false),
105         m_sharing(NO_SHARING),
106         m_flags(0),
107         m_name(name),
108         m_comment(boost::trim_right_copy(comment)),
109             m_defValue(def),
110         m_descr(descr)
111         {}
112     virtual ~ConfigProperty() {}
113     
114     virtual string getName() const { return m_name; }
115     virtual string getComment() const { return m_comment; }
116     virtual string getDefValue() const { return m_defValue; }
117     virtual string getDescr() const { return m_descr; }
118
119     /**
120      * Check whether the given value is okay.
121      * If not, then set an error string (one line, no punctuation).
122      *
123      * @return true if value is okay
124      */
125     virtual bool checkValue(const string &value, string &error) const { return true; }
126
127     /**
128      * Only useful when a config property wants to check itself whether to retrieve password
129      * Check the password and cache the result in the filter node on the fly if a property needs.
130      * sourceName and sourceConfigNode might be not set by caller. They only affect
131      * when checking password for syncsourceconfig 
132      * @param ui user interface
133      * @param serverName server name
134      * @param globalConfigNode the sync global config node for a server
135      * @param sourceName the source name used for source config properties
136      * @param sourceConfigNode the config node for the source
137      */
138     virtual void checkPassword(ConfigUserInterface &ui,
139                                const string &serverName,
140                                FilterConfigNode &globalConfigNode,
141                                const string &sourceName = string(),
142                                const boost::shared_ptr<FilterConfigNode> &sourceConfigNode = boost::shared_ptr<FilterConfigNode>()) const {}
143
144     /**
145      * Try to save password if a config property wants.
146      * It firstly check password and then invoke ui's savePassword
147      * function to save the password if necessary
148      */
149     virtual void savePassword(ConfigUserInterface &ui,
150                               const string &serverName,
151                               FilterConfigNode &globalConfigNode,
152                               const string &sourceName = string(),
153                               const boost::shared_ptr<FilterConfigNode> &sourceConfigNode = boost::shared_ptr<FilterConfigNode>()) const {}
154
155     /**
156      * This is used to generate description dynamically according to the context information
157      * Defalut implmenentation is to return value set in the constructor.
158      * Derived classes can override this function. Used by 'checkPassword' and 'savePassword'
159      * to generate description for user interface.
160      */
161     virtual const string getDescr(const string &serverName,
162                                   FilterConfigNode &globalConfigNode,
163                                   const string &sourceName = string(),
164                                   const boost::shared_ptr<FilterConfigNode> &sourceConfigNode=boost::shared_ptr<FilterConfigNode>()) const { return m_descr; }
165
166
167     /** split \n separated comment into lines without \n, appending them to commentLines */
168     static void splitComment(const string &comment, list<string> &commentLines);
169
170     /** internal property? */
171     bool isHidden() const { return m_hidden; }
172     void setHidden(bool hidden) { m_hidden = hidden; }
173
174     /** config is invalid without setting this property? */
175     bool isObligatory() const { return m_obligatory; }
176     void setObligatory(bool obligatory) { m_obligatory = obligatory; }
177
178     /**
179      * determines how a property is shared between different views
180      */
181     enum Sharing {
182         GLOBAL_SHARING,         /**< shared between all views,
183                                    for example the "default peer" property */
184         SOURCE_SET_SHARING,     /**< shared between all peers accessing
185                                    the same source set, for example the
186                                    logdir property */
187         NO_SHARING              /**< each peer has his own values */
188     };
189     Sharing getSharing() const { return m_sharing; }
190     void setSharing(Sharing sharing) { m_sharing = sharing; }
191
192     /**
193      * special hacks for certain properties
194      */
195     enum Flags {
196         SHARED_AND_UNSHARED = 1<<0   /**< value is stored with
197                                         SOURCE_SET_SHARING and
198                                         NO_SHARING, the later taking
199                                         precedency when reading
200                                         ("type"!) */
201     };
202     void setFlags(int flags) { m_flags = flags; }
203     int getFlags(void) const { return m_flags; }
204
205     /** set value unconditionally, even if it is not valid */
206     void setProperty(ConfigNode &node, const string &value) const { node.setProperty(getName(), value, getComment()); }
207     void setProperty(FilterConfigNode &node, const string &value, bool temporarily = false) const {
208         if (temporarily) {
209             node.addFilter(m_name, value);
210         } else {
211             node.setProperty(m_name, value, getComment());
212         }
213     }
214
215     /** set default value of a property, marked as default unless forced setting */
216     void setDefaultProperty(ConfigNode &node, bool force) const {
217         string defValue = getDefValue();
218         node.setProperty(m_name, defValue, getComment(), force ? NULL : &defValue);
219     }
220
221     /**
222      * String representation of property value. getPropertyValue() in
223      * some derived classes returns the value in some other, class specific
224      * representation.
225      *
226      * @retval isDefault    return true if the node had no value set and
227      *                      the default was returned instead
228      */
229     virtual string getProperty(const ConfigNode &node, bool *isDefault = NULL) const {
230         string name = getName();
231         string value = node.readProperty(name);
232         if (!value.empty()) {
233             string error;
234             if (!checkValue(value, error)) {
235                 throwValueError(node, name, value, error);
236             }
237             if (isDefault) {
238                 *isDefault = false;
239             }
240             return value;
241         } else {
242             if (isDefault) {
243                 *isDefault = true;
244             }
245             return getDefValue();
246         }
247     }
248
249     // true if property is set to non-empty value
250     bool isSet(const ConfigNode &node) const {
251         string name = getName();
252         string value = node.readProperty(name);
253         return !value.empty();
254     }
255
256  protected:
257     void throwValueError(const ConfigNode &node, const string &name, const string &value, const string &error) const;
258
259  private:
260     bool m_obligatory;
261     bool m_hidden;
262     Sharing m_sharing;
263     int m_flags;
264     const string m_name, m_comment, m_defValue, m_descr;
265 };
266
267 template<class T> class InitList : public list<T> {
268  public:
269     InitList() {}
270     InitList(const T &initialValue) {
271         push_back(initialValue);
272     }
273     InitList &operator + (const T &rhs) {
274         push_back(rhs);
275         return *this;
276     }
277     InitList &operator += (const T &rhs) {
278         push_back(rhs);
279         return *this;
280     }
281 };
282 typedef InitList<string> Aliases;
283 typedef InitList<Aliases> Values;
284
285
286 /**
287  * A string property which maps multiple different possible value
288  * strings to one generic value, ignoring the case. Values not listed
289  * are passed through unchanged. The first value in the list of
290  * aliases is the generic one.
291  *
292  * The addition operator is defined for the aliases so that they
293  * can be constructed more easily.
294  */
295 class StringConfigProperty : public ConfigProperty {
296  public:
297     StringConfigProperty(const string &name, const string &comment,
298                          const string &def = string(""),
299                          const string &descr = string(""),
300                          const Values &values = Values()) :
301     ConfigProperty(name, comment, def, descr),
302         m_values(values)
303         {}
304
305     /**
306      * @return false if aliases are defined and the string is not one of them
307      */
308     bool normalizeValue(string &res) const {
309         Values values = getValues();
310         BOOST_FOREACH(const Values::value_type &value, values) {
311             BOOST_FOREACH(const string &alias, value) {
312                 if (boost::iequals(res, alias)) {
313                     res = *value.begin();
314                     return true;
315                 }
316             }
317         }
318         return values.empty();
319     }
320
321     /**
322      * This implementation accepts all values if no aliases
323      * are given, otherwise the value must be part of the aliases.
324      */
325     virtual bool checkValue(const string &propValue, string &error) const {
326         Values values = getValues();
327         if (values.empty()) {
328             return true;
329         }
330
331         ostringstream err;
332         err << "not one of the valid values (";
333         bool firstval = true;
334         BOOST_FOREACH(const Values::value_type &value, values) {
335             if (!firstval) {
336                 err << ", ";
337             } else {
338                 firstval = false;
339             }
340             bool firstalias = true;
341             BOOST_FOREACH(const string &alias, value) {
342                 if (!firstalias) {
343                     err << " = ";
344                 } else {
345                     firstalias = false;
346                 }
347                 if (alias.empty()) {
348                     err << "\"\"";
349                 } else {
350                     err << alias;
351                 }
352                 
353                 if (boost::iequals(propValue, alias)) {
354                     return true;
355                 }
356             }
357         }
358         err << ")";
359         error = err.str();
360         return false;
361     }
362
363     virtual string getProperty(const ConfigNode &node, bool *isDefault = NULL) const {
364         string res = ConfigProperty::getProperty(node, isDefault);
365         normalizeValue(res);
366         return res;
367     }
368
369  protected:
370     virtual Values getValues() const { return m_values; }
371
372  private:
373     const Values m_values;
374 };
375
376
377 /**
378  * Instead of reading and writing strings, this class interprets the content
379  * as a specific type.
380  */
381 template<class T> class TypedConfigProperty : public ConfigProperty {
382  public:
383     TypedConfigProperty(const string &name, const string &comment, const string &defValue = string("0"), const string &descr = string("")) :
384     ConfigProperty(name, comment, defValue, descr)
385         {}
386
387     /**
388      * This implementation accepts all values that can be converted
389      * to the required type.
390      */
391     virtual bool checkValue(const string &value, string &error) const {
392         istringstream in(value);
393         T res;
394         if (in >> res) {
395             return true;
396         } else {
397             error = "cannot parse value";
398             return false;
399         }
400     }
401
402     void setProperty(ConfigNode &node, const T &value) const {
403         ostringstream out;
404
405         out << value;
406         node.setProperty(getName(), out.str(), getComment());
407     }
408     void setProperty(FilterConfigNode &node, const T &value, bool temporarily = false) const {
409         ostringstream out;
410
411         out << value;
412         if (temporarily) {
413             node.addFilter(getName(), out.str());
414         } else {
415             node.setProperty(getName(), out.str(), getComment());
416         }
417     }
418
419     T getPropertyValue(const ConfigNode &node, bool *isDefault = NULL) const {
420         string name = getName();
421         string value = node.readProperty(name);
422         istringstream in(value);
423         T res;
424         if (value.empty()) {
425             istringstream defStream(getDefValue());
426             defStream >> res;
427             if (isDefault) {
428                 *isDefault = true;
429             }
430             return res;
431         } else {
432             if (!(in >> res)) {
433                 throwValueError(node, name, value, "cannot parse value");
434             }
435             if (isDefault) {
436                 *isDefault = false;
437             }
438             return res;
439         }
440     }
441 };
442
443 /**
444  * The "in >> res" check in TypedConfigProperty::checkValue
445  * is to loose. For example, the standard library accepts
446  * -1 for an unsigned type.
447  *
448  * This class accepts a function pointer to strtoul() or
449  * strtol() and uses that function to do strict value checking.
450  *
451  * @param T       type to be converted to and from (like int)
452  * @param Tmin    minimum value of T for range checking
453  * @param Tmax    maximum value of T for range checking
454  * @param C       intermediate type for conversion  (like long)
455  * @param Cmin    minimum value of C for range checking
456  * @param Cmax    maximum value of C for range checking
457  * @param strto   conversion function
458  */
459 template <class T, T Tmin, T Tmax,
460     class C, C Cmin, C Cmax,
461     C (*strto)(const char *, char **, int)>
462 class ScalarConfigProperty : public TypedConfigProperty<T>
463 {
464  public:
465     ScalarConfigProperty(const string &name, const string &comment, const string &defValue = string("0"), const string &descr = string("")) :
466     TypedConfigProperty<T>(name, comment, defValue, descr)
467         {}
468
469     virtual bool checkValue(const string &value, string &error) const {
470         errno = 0;
471         const char *nptr = value.c_str();
472         char *endptr;
473         // use base 10 because not specifying a base 
474         // would interpret 077 as octal value, which
475         // could be confusing for users
476         C val = strto(nptr, &endptr, 10);
477         if ((errno == ERANGE && (val == Cmin || val == Cmax))) {
478             error = "range error";
479             return false;
480         }
481         if (errno != 0 && val == 0) {
482             error = "cannot parse";
483             return false;
484         }
485         if (endptr == nptr) {
486             error = "decimal value expected";
487             return false;
488         }
489         while (isspace(*endptr)) {
490             endptr++;
491         }
492         if (*endptr != '\0') {
493             error = "unexpected trailing non-whitespace characters: ";
494             error += endptr;
495             return false;
496         }
497         if (val > Tmax || val < Tmin) {
498             error = "range error";
499             return false;
500         }
501         if (Tmin == 0) {
502             // check that we didn't accidentally accept a negative value,
503             // strtoul() does that
504             const char *start = nptr;
505             while (*start && isspace(*start)) {
506                 start++;
507             }
508             if (*start == '-') {
509                 error = "range error";
510                 return false;
511             }
512         }
513
514         return true;
515     }
516 };
517
518 typedef ScalarConfigProperty<int, INT_MIN, INT_MAX, long, LONG_MIN, LONG_MAX, strtol> IntConfigProperty;
519 typedef ScalarConfigProperty<unsigned int, 0, UINT_MAX, unsigned long, 0, ULONG_MAX, strtoul> UIntConfigProperty;
520 typedef ScalarConfigProperty<long, LONG_MIN, LONG_MAX, long, LONG_MIN, LONG_MAX, strtol> LongConfigProperty;
521 typedef ScalarConfigProperty<unsigned long, 0, ULONG_MAX, unsigned long, 0, ULONG_MAX, strtoul> ULongConfigProperty;
522
523 /**
524  * This struct wraps keys for storing passwords
525  * in configuration system. Some fields might be empty
526  * for some passwords. Each field might have different 
527  * meaning for each password. Fields using depends on
528  * what user actually wants.
529  */
530 struct ConfigPasswordKey {
531  public:
532     ConfigPasswordKey() : port(0) {}
533
534     /** the user for the password */
535     string user;
536     /** the server for the password */
537     string server;
538     /** the domain name */
539     string domain;
540     /** the remote object */
541     string object;
542     /** the network protocol */
543     string protocol;
544     /** the authentication type */
545     string authtype;
546     /** the network port */
547     unsigned int port;
548 };
549
550 /**
551  * This interface has to be provided by the user of the config
552  * to let the config code interact with the user.
553  */
554 class ConfigUserInterface {
555  public:
556     virtual ~ConfigUserInterface() {}
557
558     /**
559      * A helper function which interactively asks the user for
560      * a certain password. May throw errors.
561      *
562      * @param passwordName the name of the password in the config file, such as 'proxyPassword'
563      * @param descr        A simple string explaining what the password is needed for,
564      *                     e.g. "SyncML server". This string alone has to be enough
565      *                     for the user to know what the password is for, i.e. the
566      *                     string has to be unique.
567      * @param key          the key used to retrieve password. Using this instead of ConfigNode is
568      *                     to make user interface independent on Configuration Tree
569      * @return entered password
570      */
571     virtual string askPassword(const string &passwordName, const string &descr, const ConfigPasswordKey &key) = 0;
572
573     /**
574      * A helper function which is used for user interface to save
575      * a certain password. Currently possibly syncml server. May
576      * throw errors.
577      * @param passwordName the name of the password in the config file, such as 'proxyPassword'
578      * @param password     password to be saved
579      * @param key          the key used to store password
580      * @return true if ui saves the password and false if not
581      */
582     virtual bool savePassword(const string &passwordName, const string &password, const ConfigPasswordKey &key) = 0;
583 };
584
585 class PasswordConfigProperty : public ConfigProperty {
586  public:
587     PasswordConfigProperty(const string &name, const string &comment, const string &def = string(""),const string &descr = string("")) :
588        ConfigProperty(name, comment, def, descr)
589            {}
590
591     /**
592      * Check the password and cache the result.
593      */
594     virtual void checkPassword(ConfigUserInterface &ui,
595                                const string &serverName,
596                                FilterConfigNode &globalConfigNode,
597                                const string &sourceName = "",
598                                const boost::shared_ptr<FilterConfigNode> &sourceConfigNode =
599                                boost::shared_ptr<FilterConfigNode>()) const;
600
601     /**
602      * It firstly check password and then invoke ui's savePassword
603      * function to save the password if necessary
604      */
605     virtual void savePassword(ConfigUserInterface &ui,
606                               const string &serverName,
607                               FilterConfigNode &globalConfigNode,
608                               const string &sourceName = "",
609                               const boost::shared_ptr<FilterConfigNode> &sourceConfigNode =
610                               boost::shared_ptr<FilterConfigNode>()) const;
611
612     /**
613      * Get password key for storing or retrieving passwords
614      * The default implemention is for 'password' in global config.
615      * @param descr decription for password
616      * @param globalConfigNode the global config node 
617      * @param sourceConfigNode the source config node. It might be empty
618      */
619     virtual ConfigPasswordKey getPasswordKey(const string &descr,
620                                              const string &serverName,
621                                              FilterConfigNode &globalConfigNode,
622                                              const string &sourceName = string(),
623                                              const boost::shared_ptr<FilterConfigNode> &sourceConfigNode =
624                                              boost::shared_ptr<FilterConfigNode>()) const; 
625
626     /**
627      * return the cached value if necessary and possible
628      */
629     virtual string getCachedProperty(const ConfigNode &node,
630                                      const string &cachedPassword);
631 };
632
633 /**
634  * A derived ConfigProperty class for the property "proxyPassword"
635  */
636 class ProxyPasswordConfigProperty : public PasswordConfigProperty {
637  public:
638     ProxyPasswordConfigProperty(const string &name, const string &comment, const string &def = string(""), const string &descr = string("")) :
639         PasswordConfigProperty(name,comment,def,descr)
640     {}
641     /**
642      * re-implement this function for it is necessary to do a check 
643      * before retrieving proxy password
644      */
645     virtual void checkPassword(ConfigUserInterface &ui,
646                                const string &serverName,
647                                FilterConfigNode &globalConfigNode,
648                                const string &sourceName,
649                                const boost::shared_ptr<FilterConfigNode> &sourceConfigNode) const;
650     virtual ConfigPasswordKey getPasswordKey(const string &descr,
651                                              const string &serverName,
652                                              FilterConfigNode &globalConfigNode,
653                                              const string &sourceName = string(),
654                                              const boost::shared_ptr<FilterConfigNode> &sourceConfigNode=boost::shared_ptr<FilterConfigNode>()) const; 
655 };
656
657 /**
658  * A derived ConfigProperty class for the property "evolutionpassword"
659  */
660 class EvolutionPasswordConfigProperty : public PasswordConfigProperty {
661  public:
662     EvolutionPasswordConfigProperty(const string &name, 
663                                     const string &comment, 
664                                     const string &def = string(""),
665                                     const string &descr = string("")): 
666                                     PasswordConfigProperty(name,comment,def,descr)
667     {}
668     virtual ConfigPasswordKey getPasswordKey(const string &descr,
669                                              const string &serverName,
670                                              FilterConfigNode &globalConfigNode,
671                                              const string &sourceName = string(),
672                                              const boost::shared_ptr<FilterConfigNode> &sourceConfigNode=boost::shared_ptr<FilterConfigNode>()) const; 
673     virtual const string getDescr(const string &serverName,
674                                   FilterConfigNode &globalConfigNode,
675                                   const string &sourceName,
676                                   const boost::shared_ptr<FilterConfigNode> &sourceConfigNode) const {
677         string descr = sourceName;
678         descr += " ";
679         descr += ConfigProperty::getDescr();
680         return descr;
681     }
682 };
683
684 /**
685  * Instead of reading and writing strings, this class interprets the content
686  * as boolean with T/F or 1/0 (default format).
687  */
688 class BoolConfigProperty : public StringConfigProperty {
689  public:
690     BoolConfigProperty(const string &name, const string &comment, const string &defValue = string("F"),const string &descr = string("")) :
691     StringConfigProperty(name, comment, defValue,descr,
692                          Values() + (Aliases("1") + "T" + "TRUE") + (Aliases("0") + "F" + "FALSE"))
693         {}
694
695     void setProperty(ConfigNode &node, bool value) {
696         StringConfigProperty::setProperty(node, value ? "1" : "0");
697     }
698     void setProperty(FilterConfigNode &node, bool value, bool temporarily = false) {
699         StringConfigProperty::setProperty(node, value ? "1" : "0", temporarily);
700     }
701     int getPropertyValue(const ConfigNode &node, bool *isDefault = NULL) const {
702         string res = ConfigProperty::getProperty(node, isDefault);
703
704         return boost::iequals(res, "T") ||
705             boost::iequals(res, "TRUE") ||
706             atoi(res.c_str()) != 0;
707     }
708 };
709
710 /**
711  * A property for arbitrary strings.
712  */
713 class SafeConfigProperty : public ConfigProperty {
714  public:
715     SafeConfigProperty(const string &name, const string &comment) :
716     ConfigProperty(name, comment)
717     {}
718
719     void setProperty(ConfigNode &node, const string &value) {
720         ConfigProperty::setProperty(node, SafeConfigNode::escape(value, true, false));
721     }
722     virtual string getProperty(const ConfigNode &node, bool *isDefault = NULL) const {
723         string res = ConfigProperty::getProperty(node, isDefault);
724         res = SafeConfigNode::unescape(res);
725         return res;
726     }
727 };
728
729 /**
730  * A registry for all properties which might be saved in the same ConfigNode.
731  * Currently the same as a simple list. Someone else owns the instances.
732  */
733 class ConfigPropertyRegistry : public list<const ConfigProperty *> {
734  public:
735     /** case-insensitive search for property */
736     const ConfigProperty *find(const string &propName) const {
737         BOOST_FOREACH(const ConfigProperty *prop, *this) {
738             if (boost::iequals(prop->getName(), propName)) {
739                 return prop;
740             }
741         }
742         return NULL;
743     }
744 };
745
746 /**
747  * Store the current string value of a property in a cache
748  * and return the "const char *" pointer that is expected by
749  * the client library.
750  */
751 class ConfigStringCache {
752  public:
753     const char *getProperty(const ConfigNode &node, const ConfigProperty &prop) {
754         string value = prop.getProperty(node);
755         return storeString(prop.getName(), value);
756     }
757
758     const char *storeString(const string &key, const string &value) {
759         const string &entry = m_cache[key] = value;
760         return entry.c_str();
761     }
762
763  private:
764     map<string, string> m_cache;
765 };
766
767 /**
768  * This class implements the client library configuration interface
769  * by mapping values to properties to entries in a ConfigTree. The
770  * mapping is either the traditional one used by SyncEvolution <= 0.7
771  * and client library <= 6.5 or the new layout introduced with
772  * SyncEvolution >= 0.8. If for a given server name the old config
773  * exists, then it is used. Otherwise the new layout is used.
774  *
775  * This class can be instantiated on its own and then provides access
776  * to properties actually stored in files. SyncContext
777  * inherits from this class so that a derived client has the chance to
778  * override every single property (although it doesn't have to).
779  * Likewise SyncSource is derived from
780  * SyncSourceConfig.
781  *
782  * Properties can be set permanently (this changes the underlying
783  * ConfigNode) and temporarily (this modifies the FilterConfigNode
784  * which wraps the ConfigNode).
785  *
786  * The old layout is:
787  * - $HOME/.sync4j/evolution/<server>/spds/syncml/config.txt
788  * -- spds/sources/<source>/config.txt
789  * ---                      changes_<changeid>/config.txt
790  *
791  * The new layout is:
792  * - ${XDG_CONFIG:-${HOME}/.config}/syncevolution/foo - base directory for server foo
793  * -- config.ini - constant per-server settings
794  * -- .internal.ini - read/write server properties - hidden from users because of the leading dot
795  * -- sources/bar - base directory for source bar
796  * --- config.ini - constant per-source settings
797  * --- .internal.ini - read/write source properties
798  * --- .changes_<changeid>.ini - change tracking node (content under control of sync source)
799  *
800  * Because this class needs to handle different file layouts it always
801  * uses a FileConfigTree instance. Other implementations would be
802  * possible.
803  */
804 class SyncConfig {
805  public:
806     /**
807      * Opens the configuration for a specific server,
808      * searching for the config files in the usual
809      * places. Will succeed even if config does not
810      * yet exist: flushing such a config creates it.
811      *
812      * @param peer   string that identifies the peer,
813      *               matching regex (.*)(@([^@]*))? 
814      *               where the $1 (the first part) is 
815      *               the peer name and the optional $2
816      *               (the part after the last @) is the
817      *               context, "default" if not given.
818      *               For example "scheduleworld" =
819      *               "ScheduleWorld" =
820      *               "scheduleworld@default", but not the same as
821      *               "scheduleworld@other_context"
822      *
823      * @param tree   if non-NULL, then this is used
824      *               as configuration tree instead of
825      *               searching for it; always uses the
826      *               current layout in that tree
827      */
828     SyncConfig(const string &peer,
829                boost::shared_ptr<ConfigTree> tree = boost::shared_ptr<ConfigTree>());
830
831     /**
832      * Creates a temporary configuration.
833      * Can be copied around, but not flushed.
834      */
835     SyncConfig();
836
837    /** absolute directory name of the configuration root */
838     string getRootPath() const;
839
840     typedef list< std::pair<std::string, std::string> > ConfigList;
841
842     /** A simple description of the template or the configuration based on a
843      * template. The rank field is used to indicate how good it matches the
844      * user input <MacAddress, DeviceName> */
845     struct TemplateDescription {
846         // The name of the template
847         std::string m_name;
848         // The description of the template (eg. the web server URL for a
849         // SyncML server. This is not used for UI, only CMD line used this.
850         std::string m_description;
851         // The matched percentage of the template, larger the better.
852         int m_rank;
853
854         //a unique identity of the device that the template is for, used by caller
855         std::string m_id;
856
857         // A string identify which fingerprint the template is matched with.
858         std::string m_fingerprint;
859
860         // A unique string identify the template path, so that a later operation
861         // fetching this config will be much easier
862         std::string m_path;
863
864         // A string indicates the original fingerprint in the matched template, this
865         // will not necessarily the same with m_fingerprint
866         std::string m_matchedModel;
867
868         TemplateDescription (const std::string &name, const std::string &description, 
869                 const int rank, const std::string id, const std::string &fingerprint, const std::string &path, const std::string &model)
870             :   m_name (name),
871                 m_description (description),
872                 m_rank (rank),
873                 m_id (id),
874                 m_fingerprint (fingerprint),
875                 m_path (path),
876                 m_matchedModel(model)
877         {
878         }
879
880         TemplateDescription (const std::string &name, const std::string &description);
881
882         static bool compare_op (boost::shared_ptr<TemplateDescription> &left, boost::shared_ptr<TemplateDescription> &right);
883     };
884
885     enum MatchMode {
886         /*Match templates when we work as SyncML server, i.e. the peer is the client*/
887         MATCH_FOR_SERVER_MODE,
888         /*Match templates when work as SyncML client, i.e. the peer is the server*/
889         MATCH_FOR_CLIENT_MODE,
890         /*Match templates for both SyncML server and SyncML client*/
891         MATCH_ALL,
892         INVALID
893     };
894
895     typedef list<boost::shared_ptr <TemplateDescription> > TemplateList;
896
897     struct DeviceDescription {
898         /** the id of the device */
899         std::string m_deviceId;
900         /** the finger print of the device used for matching templates */
901         std::string m_fingerprint;
902         /** match mode used for matching templates */
903         MatchMode m_matchMode;
904         DeviceDescription(const std::string &deviceId,
905                           const std::string &fingerprint,
906                           MatchMode mode)
907             :m_deviceId(deviceId), m_fingerprint(fingerprint), m_matchMode(mode)
908         {}
909         DeviceDescription() : m_matchMode(INVALID)
910         {}
911     };
912
913     typedef list<DeviceDescription> DeviceList;
914
915     /**
916      * returns list of servers in either the old (.sync4j) or
917      * new config directory (.config), given as server name
918      * and absolute root of config
919      */
920     static ConfigList getConfigs();
921
922     /**
923      * returns list of available config templates:
924      * for each peer listed in @peers, matching against the fingerprint information
925      * from the peer (deviceName likely), sorted by the matching score,
926      * templates failed to match(as long as it's for SyncML server) will also
927      * be returned as a fallback mechanism so that user can select a configuration
928      * template manually.
929      * Any templates for SyncMl Client is also returned, with a default rank.
930      * The assumption currently is only work for SyncML client peers.
931      * DeviceList is a list of matching tuples <fingerprint, SyncConfig::MatchMode>.
932      */
933     static TemplateList getPeerTemplates(const DeviceList &peers);
934
935     /**
936      * match the built-in templates against @param fingerprint, return a list of
937      * servers sorted by the matching rank.
938      * */
939     static TemplateList matchPeerTemplates(const DeviceList &peers, bool fuzzyMatch = true);
940
941     /**
942      * get the built-in default templates
943      */
944     static TemplateList getBuiltInTemplates ();
945
946     /**
947      * Creates a new instance of a configuration template.
948      * The result can be modified to set filters, but it
949      * cannot be flushed.
950      *
951      * @param peer   a configuration name, *without* a context (scheduleworld, not scheduleworld@default),
952      * or a configuration path in the system directory which can avoid another fuzzy match process.
953      * @return NULL if no such template
954      */
955     static boost::shared_ptr<SyncConfig> createPeerTemplate(const string &peer);
956
957     /** true if the main configuration file already exists */
958     bool exists() const;
959
960     /**
961      * The normalized, unique config name used by this instance.
962      * Empty if not backed up by a real config.
963      */
964     string getConfigName() const { return m_peer; }
965
966     /**
967      * Do something before doing flush to files. This is particularly
968      * useful when user interface wants to do preparation jobs, such
969      * as savePassword and others.
970      */
971     virtual void preFlush(ConfigUserInterface &ui); 
972
973     void flush();
974
975     /**
976      * Remove the configuration. Config directories are removed if
977      * empty.
978      *
979      * When the configuration is peer-specific, only the peer's
980      * properties and config nodes are removed. Otherwise the complete
981      * configuration is removed, including all peers.
982      *
983      * Does *not* remove logs associated with the configuration.
984      * For that use the logdir handling in SyncContext
985      * before removing the configuration.
986      */
987     void remove();
988
989     /**
990      * A list of all properties. Can be extended by derived clients.
991      */
992     static ConfigPropertyRegistry &getRegistry();
993
994     /**
995      * Normalize a config string:
996      * - lower case
997      * - non-printable and unsafe characters (colon, slash, backslash)
998      *   replaced by underscore
999      * - when no context specified: search for peer config first in @default,
1000      *   then also in other contexts in alphabetical order
1001      * - @default stripped
1002      * - empty string replaced with "@default"
1003      */
1004     static string normalizeConfigString(const string &config);
1005
1006     /**
1007      * Split a config string (normalized or not) into the peer part
1008      * (before final @) and the context (after that @, not including
1009      * it), return "default" as context if not specified otherwise.
1010      */
1011     static void splitConfigString(const string &config, string &peer, string &context);
1012
1013     /**
1014      * Replaces the property filter of either the sync properties or
1015      * all sources. This can be used to e.g. temporarily override
1016      * the active sync mode.
1017      *
1018      * @param sync     true if the filter applies to sync properties,
1019      *                 false if it applies to sources
1020      * @param source   empty string if filter applies to all sources,
1021      *                 otherwise the source name to which it applies
1022      * @param filter   key (case insensitive)/value pairs of properties
1023      *                 which are to be overridden
1024      */
1025     void setConfigFilter(bool sync,
1026                          const std::string &source,
1027                          const FilterConfigNode::ConfigFilter &filter);
1028
1029     /**
1030      * Read-write access to all configurable properties of the server.
1031      * The visible properties are passed through the config filter,
1032      * which can be modified.
1033      */
1034     boost::shared_ptr<FilterConfigNode> getProperties(bool hidden = false) { return m_props[hidden]; }
1035     boost::shared_ptr<const FilterConfigNode> getProperties(bool hidden = false) const { return const_cast<SyncConfig *>(this)->getProperties(hidden); }
1036
1037     /**
1038      * Returns the right config node for a certain property,
1039      * depending on visibility and sharing.
1040      */
1041     boost::shared_ptr<FilterConfigNode> getNode(const ConfigProperty &prop);
1042     boost::shared_ptr<const FilterConfigNode> getNode(const ConfigProperty &prop) const 
1043     {
1044         return const_cast<SyncConfig *>(this)->getNode(prop);
1045     }
1046
1047     /**
1048      * Returns a wrapper around all properties of the given source
1049      * which are saved in the config tree. Note that this is different
1050      * from the set of sync source configs used by the SyncManager:
1051      * the SyncManger uses the AbstractSyncSourceConfig. In
1052      * SyncEvolution those are implemented by the
1053      * SyncSource's actually instantiated by
1054      * SyncContext. Those are complete whereas
1055      * PersistentSyncSourceConfig only provides access to a
1056      * subset of the properties.
1057      *
1058      * Can be called for sources which do not exist yet.
1059      */
1060     virtual boost::shared_ptr<PersistentSyncSourceConfig> getSyncSourceConfig(const string &name);
1061     virtual boost::shared_ptr<const PersistentSyncSourceConfig> getSyncSourceConfig(const string &name) const {
1062         return const_cast<SyncConfig *>(this)->getSyncSourceConfig(name);
1063     }
1064
1065     /**
1066      * Returns list of all configured (not active!) sync sources.
1067      */
1068     virtual list<string> getSyncSources() const;
1069
1070     /**
1071      * Creates config nodes for a certain node. The nodes are not
1072      * yet created in the backend if they do not yet exist.
1073      *
1074      * @param name       the name of the sync source
1075      * @param trackName  additional part of the tracking node name (used for unit testing)
1076      */
1077     SyncSourceNodes getSyncSourceNodes(const string &name,
1078                                        const string &trackName = "");
1079     ConstSyncSourceNodes getSyncSourceNodes(const string &name,
1080                                             const string &trackName = "") const;
1081
1082     /**
1083      * initialize all properties with their default value
1084      */
1085     void setDefaults(bool force = true);
1086
1087     /**
1088      * create a new sync source configuration with default values
1089      */
1090     void setSourceDefaults(const string &name, bool force = true);
1091
1092     /**
1093      * Remove sync source configuration. And remove the directory
1094      * if it has no other files.
1095      *
1096      * When the configuration is peer-specific, only the peer's
1097      * properties are removed. Otherwise the complete source
1098      * configuration is removed, including properties stored
1099      * for in any of the peers.
1100      */
1101     void removeSyncSource(const string &name);
1102
1103     /**
1104      * clear existing visible source properties selected by the
1105      * configuration: with or without peer-specific properties,
1106      * depending on the current view
1107      */
1108     void clearSyncSourceProperties(const string &name);
1109
1110     /**
1111      * clear all global sync properties, with or without
1112      * peer-specific properties, depending on the current view
1113      */
1114     void clearSyncProperties();
1115
1116     /**
1117      * Copy all registered properties (hidden and visible) and the
1118      * tracking node into the current config. This is done by reading
1119      * all properties from the source config, which implies the unset
1120      * properties will be set to their default values.  The current
1121      * config is not cleared so additional, unregistered properties
1122      * (should they exist) will continue to exist unchanged.
1123      *
1124      * The current config still needs to be flushed to make the
1125      * changes permanent.
1126      *
1127      * @param sources   if NULL, then copy all sources; if not NULL,
1128      *                  then copy exactly the sources listed here
1129      *                  (regardless whether they exist or not)
1130      */
1131     void copy(const SyncConfig &other,
1132               const set<string> *sources);
1133
1134     /**
1135      * @name Settings specific to SyncEvolution
1136      *
1137      * See the property definitions in SyncConfig.cpp
1138      * for the user-visible explanations of
1139      * these settings.
1140      */
1141     /**@{*/
1142
1143     virtual string getDefaultPeer() const;
1144     virtual void setDefaultPeer(const string &value);
1145
1146     virtual const char *getLogDir() const;
1147     virtual void setLogDir(const string &value, bool temporarily = false);
1148
1149     virtual int getMaxLogDirs() const;
1150     virtual void setMaxLogDirs(int value, bool temporarily = false);
1151
1152     virtual int getLogLevel() const;
1153     virtual void setLogLevel(int value, bool temporarily = false);
1154
1155     virtual bool getPrintChanges() const;
1156     virtual void setPrintChanges(bool value, bool temporarily = false);
1157
1158     virtual std::string getWebURL() const;
1159     virtual void setWebURL(const std::string &url, bool temporarily = false);
1160
1161     virtual std::string getIconURI() const;
1162     virtual void setIconURI(const std::string &uri, bool temporarily = false);
1163
1164     /**
1165      * A property of server template configs. True if the server is
1166      * ready for use by "normal" users (everyone can get an account
1167      * and some kind of support, we have tested the server well
1168      * enough, ...).
1169      */
1170     virtual bool getConsumerReady() const;
1171     virtual void setConsumerReady(bool ready);
1172
1173     virtual unsigned long getHashCode() const;
1174     virtual void setHashCode(unsigned long hashCode);
1175
1176     virtual std::string getConfigDate() const;
1177     virtual void setConfigDate(); /* set current time always */
1178
1179     /**@}*/
1180
1181     /**
1182      * @name Settings inherited from Funambol
1183      *
1184      * These settings are required by the Funambol C++ client library.
1185      * Some of them are hard-coded in this class. A derived class could
1186      * make them configurable again, should that be desired.
1187      */
1188     /**@{*/
1189
1190     virtual const char*  getUsername() const;
1191     virtual void setUsername(const string &value, bool temporarily = false);
1192     virtual const char*  getPassword() const;
1193     virtual void setPassword(const string &value, bool temporarily = false);
1194
1195     /**
1196      * Look at the password setting and if it requires user interaction,
1197      * get it from the user. Then store it for later usage in getPassword().
1198      * Without this call, getPassword() returns the original, unmodified
1199      * config string.
1200      */
1201     virtual void checkPassword(ConfigUserInterface &ui);
1202
1203     /**
1204      * Look at the password setting and if it needs special mechanism to
1205      * save password, this function is used to store specified password
1206      * in the config tree.
1207      * @param ui the ui pointer
1208      */
1209     virtual void savePassword(ConfigUserInterface &ui); 
1210
1211     virtual bool getPreventSlowSync() const;
1212     virtual void setPreventSlowSync(bool value, bool temporarily = false);
1213     virtual bool getUseProxy() const;
1214     virtual void setUseProxy(bool value, bool temporarily = false);
1215     virtual const char*  getProxyHost() const;
1216     virtual void setProxyHost(const string &value, bool temporarily = false);
1217     virtual int getProxyPort() const { return 0; }
1218     virtual const char* getProxyUsername() const;
1219     virtual void setProxyUsername(const string &value, bool temporarily = false);
1220     virtual const char* getProxyPassword() const;
1221     virtual void checkProxyPassword(ConfigUserInterface &ui);
1222     virtual void saveProxyPassword(ConfigUserInterface &ui);
1223     virtual void setProxyPassword(const string &value, bool temporarily = false);
1224     virtual vector<string>  getSyncURL() const;
1225     virtual void setSyncURL(const string &value, bool temporarily = false);
1226     virtual void setSyncURL(const vector<string> &value, bool temporarily = false);
1227     virtual const char*  getClientAuthType() const;
1228     virtual void setClientAuthType(const string &value, bool temporarily = false);
1229     virtual unsigned long getMaxMsgSize() const;
1230     virtual void setMaxMsgSize(unsigned long value, bool temporarily = false);
1231     virtual unsigned int getMaxObjSize() const;
1232     virtual void setMaxObjSize(unsigned int value, bool temporarily = false);
1233     virtual unsigned long getReadBufferSize() const { return 0; }
1234     virtual const char* getSSLServerCertificates() const;
1235
1236     /**
1237      * iterate over files mentioned in getSSLServerCertificates()
1238      * and return name of first one which is found, empty string
1239      * if none
1240      */
1241     std::string findSSLServerCertificate();
1242
1243     virtual void setSSLServerCertificates(const string &value, bool temporarily = false);
1244     virtual bool getSSLVerifyServer() const;
1245     virtual void setSSLVerifyServer(bool value, bool temporarily = false);
1246     virtual bool getSSLVerifyHost() const;
1247     virtual void setSSLVerifyHost(bool value, bool temporarily = false);
1248     virtual int getRetryInterval() const;
1249     virtual void setRetryInterval(int value, bool temporarily = false);
1250     virtual int getRetryDuration() const;
1251     virtual void setRetryDuration(int value, bool temporarily = false);
1252     virtual bool  getCompression() const;
1253     virtual void setCompression(bool value, bool temporarily = false);
1254     virtual unsigned int getResponseTimeout() const { return 0; }
1255     virtual const char*  getDevID() const;
1256     virtual void setDevID(const string &value, bool temporarily = false);
1257
1258     /*Used for Server Alerted Sync*/
1259     virtual const char*  getRemoteIdentifier() const;
1260     virtual void setRemoteIdentifier (const string &value, bool temporaritly = false);
1261     virtual bool getPeerIsClient () const;
1262     virtual void setPeerIsClient (bool value, bool temporarily = false);
1263
1264     /**
1265      * An arbitrary name assigned to the peer configuration,
1266      * not necessarily unique. Can be used by a GUI instead
1267      * of the config name.
1268      */
1269     virtual string getPeerName() const;
1270     virtual void setPeerName(const string &name);
1271
1272     /**
1273      * The Device ID of our peer. Typically only relevant when the
1274      * peer is a client. Servers don't have a Device ID, just some
1275      * unique way of contacting them.
1276      */
1277     virtual string getRemoteDevID() const;
1278     virtual void setRemoteDevID(const string &value);
1279
1280     /**
1281      * The opaque nonce value stored for a peer, required for MD5
1282      * authentication. Only used when acting as server.
1283      */
1284     virtual string getNonce() const;
1285     virtual void setNonce(const string &value);
1286
1287     /**
1288      * The opaque per-peer admin data managed by the Synthesis
1289      * engine. Only used when acting as server.
1290      */
1291     virtual string getDeviceData() const;
1292     virtual void setDeviceData(const string &value);
1293
1294     /**
1295      * Specifies whether WBXML is to be used (default).
1296      * Otherwise XML is used.
1297      */
1298     virtual bool getWBXML() const;
1299     virtual void setWBXML(bool isWBXML, bool temporarily = false);
1300
1301     virtual const char*  getUserAgent() const { return "SyncEvolution"; }
1302     virtual const char*  getMan() const { return "Patrick Ohly"; }
1303     virtual const char*  getMod() const { return "SyncEvolution"; }
1304     virtual const char*  getOem() const { return "Open Source"; }
1305     virtual const char*  getHwv() const { return "unknown"; }
1306     virtual const char*  getSwv() const;
1307     virtual const char*  getDevType() const;
1308     /**@}*/
1309
1310 private:
1311     enum Layout {
1312         SYNC4J_LAYOUT,        /**< .syncj4/evolution/<server>, SyncEvolution <= 0.7.x */
1313         HTTP_SERVER_LAYOUT,   /**< .config/syncevolution/<server> with sources
1314                                  underneath, SyncEvolution <= 0.9.x */
1315         SHARED_LAYOUT         /**< .config/syncevolution/<context> containing sources 
1316                                  and peers, with source settings shared by peers,
1317                                  SyncEvolution >= 1.0 */
1318     };
1319
1320     /**
1321      * scans for peer configurations
1322      * @param root         absolute directory path
1323      * @param configname   expected name of config files (config.ini or config.txt)
1324      * @retval res         filled with new peer configurations found
1325      */
1326     static void addPeers(const string &root,
1327                          const std::string &configname,
1328                          SyncConfig::ConfigList &res);
1329
1330     /**
1331      * set tree and nodes to VolatileConfigTree/Node
1332      */
1333     void makeVolatile();
1334
1335     /**
1336      * String that identifies the peer, see constructor.
1337      * This is a normalized string (normalizePeerString()).
1338      * The name is a bit of a misnomer, because the config
1339      * might also reference just a context without any
1340      * peer-specific properties ("@some-context", or "@default").
1341      */
1342     string m_peer;
1343
1344     /**
1345      * Lower case path to peer configuration,
1346      * relative to configuration tree root.
1347      * For example "scheduleworld" for "ScheduleWorld" when
1348      * using the old config layouts, "default/peers/scheduleworld"
1349      * in the new layout.
1350      *
1351      * Empty if configuration view has no peer-specific properties.
1352      */
1353     string m_peerPath;
1354
1355     /**
1356      * lower case path to source set properties,
1357      * unused for old layouts, else something like
1358      * "default" or "other_context"
1359      */
1360     string m_contextPath;
1361
1362     Layout m_layout;
1363     string m_cachedPassword;
1364     string m_cachedProxyPassword;
1365
1366     /** holds all config nodes relative to the root that we found */
1367     boost::shared_ptr<ConfigTree> m_tree;
1368
1369     /** access to global sync properties, independent of
1370         the context (for example, "defaultPeer") */
1371     boost::shared_ptr<FilterConfigNode> m_globalNode;
1372         
1373     /** access to properties shared between peers */
1374     boost::shared_ptr<FilterConfigNode> m_contextNode;
1375     boost::shared_ptr<ConfigNode> m_contextHiddenNode;
1376
1377     /** access to properties specific to a peer */
1378     boost::shared_ptr<FilterConfigNode> m_peerNode;
1379     boost::shared_ptr<ConfigNode> m_hiddenPeerNode;
1380
1381     /** multiplexer for the other config nodes */
1382     boost::shared_ptr<FilterConfigNode> m_props[2];
1383
1384     /**
1385      * temporary override for all sync source settings
1386      */
1387     FilterConfigNode::ConfigFilter m_sourceFilter;
1388
1389     /** temporary override for settings of specific sources */
1390     typedef std::map<std::string, FilterConfigNode::ConfigFilter> SourceFilters_t;
1391     SourceFilters_t m_sourceFilters;
1392
1393     mutable ConfigStringCache m_stringCache;
1394
1395     static string getOldRoot() {
1396         return getHome() + "/.sync4j/evolution";
1397     }
1398
1399     static string getNewRoot() {
1400         const char *xdg_root_str = getenv("XDG_CONFIG_HOME");
1401         return xdg_root_str ? string(xdg_root_str) + "/syncevolution" :
1402             getHome() + "/.config/syncevolution";
1403     }
1404  
1405 };
1406
1407 /**
1408  * This set of config nodes is to be used by SyncSourceConfig
1409  * to accesss properties. Note that "const SyncSourceNodes"
1410  * only implies that the nodes cannot be changed; the properties
1411  * are still read- and writable. ConstSyncSourceNodes grants
1412  * only read access to properties.
1413  */
1414 class SyncSourceNodes {
1415  public:
1416     SyncSourceNodes() {}
1417
1418     /**
1419      * @param sharedNode      node for user-visible properties, shared between peers
1420      * @param peerNode        node for user-visible, per-peer properties (the same
1421      *                        as sharedNode in SYNC4J_LAYOUT and HTTP_SERVER_LAYOUT)
1422      * @param hiddenPeerNode  node for internal, per-peer properties (the same as
1423      *                        sharedNode in SYNC4J_LAYOUT)
1424      * @param trackingNode    node for tracking changes (always different than the
1425      *                        other nodes)
1426      * @param serverNode      node for tracking items in a server (always different
1427      *                        than the other nodes)
1428      */
1429     SyncSourceNodes(const boost::shared_ptr<FilterConfigNode> &sharedNode,
1430                     const boost::shared_ptr<FilterConfigNode> &peerNode,
1431                     const boost::shared_ptr<ConfigNode> &hiddenPeerNode,
1432                     const boost::shared_ptr<ConfigNode> &trackingNode,
1433                     const boost::shared_ptr<ConfigNode> &serverNode);
1434
1435     /** true if the peer-specific config node exists */
1436     bool exists() const { return m_peerNode->exists(); }
1437
1438     /**
1439      * Returns the right config node for a certain property,
1440      * depending on visibility and sharing.
1441      */
1442     boost::shared_ptr<FilterConfigNode> getNode(const ConfigProperty &prop) const;
1443
1444     /**
1445      * Read-write access to all configurable properties of the source.
1446      * The visible properties are passed through the config filter,
1447      * which can be modified.
1448      */
1449     boost::shared_ptr<FilterConfigNode> getProperties(bool hidden = false) const { return m_props[hidden]; }
1450
1451     /** read-write access to SyncML server specific config node */
1452     boost::shared_ptr<ConfigNode> getServerNode() const { return m_serverNode; }
1453
1454     /** read-write access to backend specific tracking node */
1455     boost::shared_ptr<ConfigNode> getTrackingNode() const { return m_trackingNode; }
1456
1457  protected:
1458     const boost::shared_ptr<FilterConfigNode> m_sharedNode;
1459     const boost::shared_ptr<FilterConfigNode> m_peerNode;
1460     const boost::shared_ptr<ConfigNode> m_hiddenPeerNode;
1461     const boost::shared_ptr<ConfigNode> m_trackingNode;
1462     const boost::shared_ptr<ConfigNode> m_serverNode;
1463
1464     /** multiplexer for the other nodes */
1465     boost::shared_ptr<FilterConfigNode> m_props[2];
1466 };
1467
1468 /**
1469  * same as SyncSourceNodes, but with only read access to properties
1470  */
1471 class ConstSyncSourceNodes : private SyncSourceNodes
1472 {
1473  public:
1474     ConstSyncSourceNodes(const SyncSourceNodes &other) :
1475        SyncSourceNodes(other)
1476     {}
1477
1478     boost::shared_ptr<const FilterConfigNode> getProperties(bool hidden = false) const {
1479         return const_cast<SyncSourceNodes *>(static_cast<const SyncSourceNodes *>(this))->getProperties(hidden);
1480     }
1481     boost::shared_ptr<const ConfigNode> getServerNode() const { return m_serverNode; }
1482     boost::shared_ptr<const ConfigNode> getTrackingNode() const { return m_trackingNode; } 
1483 };
1484
1485 struct SourceType {
1486     SourceType():m_forceFormat(false)
1487     {}
1488     string m_backend; /**< identifies the SyncEvolution backend (either via a generic term like "addressbook" or a specific one like "Evolution Contacts") */
1489     string m_format; /**< the format to be used (typically a MIME type) */
1490     bool   m_forceFormat; /**< force to use the client's preferred format instead giving the engine and server a choice */
1491 };
1492
1493 /**
1494  * This class maps per-source properties to ConfigNode properties.
1495  * Some properties are not configurable and have to be provided
1496  * by derived classes.
1497  */
1498 class SyncSourceConfig {
1499  public:
1500     SyncSourceConfig(const string &name, const SyncSourceNodes &nodes);
1501
1502     static ConfigPropertyRegistry &getRegistry();
1503
1504     /**
1505      * Read-write access to all configurable properties of the source.
1506      * The visible properties are passed through the config filter,
1507      * which can be modified.
1508      */
1509     boost::shared_ptr<FilterConfigNode> getProperties(bool hidden = false) {
1510         return m_nodes.getProperties(hidden);
1511     }
1512     boost::shared_ptr<const FilterConfigNode> getProperties(bool hidden = false) const { return const_cast<SyncSourceConfig *>(this)->getProperties(hidden); }
1513
1514     virtual const char*  getName() const { return m_name.c_str(); }
1515
1516     /**
1517      * Returns the right config node for a certain property,
1518      * depending on visibility and sharing.
1519      */
1520     boost::shared_ptr<FilterConfigNode> getNode(const ConfigProperty &prop) {
1521         return m_nodes.getNode(prop);
1522     }
1523     boost::shared_ptr<const FilterConfigNode> getNode(const ConfigProperty &prop) const {
1524         return m_nodes.getNode(prop);
1525     }
1526
1527     /** access to SyncML server specific config node */
1528     boost::shared_ptr<ConfigNode> getServerNode() { return m_nodes.getServerNode(); }
1529     boost::shared_ptr<const ConfigNode> getServerNode() const { return m_nodes.getServerNode(); }
1530
1531     /** access to backend specific tracking node */
1532     boost::shared_ptr<ConfigNode> getTrackingNode() { return m_nodes.getTrackingNode(); }
1533     boost::shared_ptr<const ConfigNode> getTrackingNode() const { return m_nodes.getTrackingNode(); }
1534
1535     /** sync mode for sync sources */
1536     static StringConfigProperty m_sourcePropSync;
1537
1538     /** true if the source config exists with view-specific properties (not just default or shared ones) */
1539     bool exists() const { return m_nodes.exists(); }
1540
1541     /** checks if a certain property is set to a non-empty value */
1542     bool isSet(ConfigProperty &prop) {
1543         return prop.isSet(*getProperties(prop.isHidden()));
1544     }
1545
1546     virtual const char *getUser() const;
1547     virtual void setUser(const string &value, bool temporarily = false);
1548
1549     const char *getPassword() const;
1550     virtual void setPassword(const string &value, bool temporarily = false);
1551
1552     /** same as SyncConfig::checkPassword() but with
1553      * an extra argument globalConfigNode for source config property
1554      * may need global config node to check password */
1555     virtual void checkPassword(ConfigUserInterface &ui, const string &serverName, FilterConfigNode& globalConfigNode);
1556
1557     /** same as SyncConfig::savePassword() */
1558     virtual void savePassword(ConfigUserInterface &ui, const string &serverName, FilterConfigNode& globalConfigNode);
1559
1560     /** selects the backend database to use */
1561     virtual const char *getDatabaseID() const;
1562     virtual void setDatabaseID(const string &value, bool temporarily = false);
1563
1564     /**
1565      * internal property: unique integer ID for the source, needed by Synthesis XML <dbtypeid>,
1566      * zero if unset
1567      */
1568     virtual const int getSynthesisID() const;
1569     virtual void setSynthesisID(int value, bool temporarily = false);
1570
1571     /**
1572      * Returns the data source type configured as part of the given
1573      * configuration; different SyncSources then check whether
1574      * they support that type. This call has to work before instantiating
1575      * a source and thus gets passed a node to read from.
1576      *
1577      * @return the pair of <backend> and the (possibly empty)
1578      *         <format> specified in the "type" property; see
1579      *         sourcePropSourceType in SyncConfig.cpp
1580      *         for details
1581      */
1582     static SourceType getSourceType(const SyncSourceNodes &nodes);
1583     static string getSourceTypeString(const SyncSourceNodes &nodes);
1584     virtual SourceType getSourceType() const;
1585
1586     /** set the source type in <backend>[:format] style */
1587     virtual void setSourceType(const string &value, bool temporarily = false);
1588
1589     /**
1590      * Returns the SyncSource URI: used in SyncML to address the data
1591      * on the server.
1592      *
1593      * Each URI has to be unique during a sync session, i.e.
1594      * two different sync sources cannot access the same data at
1595      * the same time.
1596      */
1597     virtual const char*  getURI() const;
1598     virtual void setURI(const string &value, bool temporarily = false);
1599
1600     /**
1601      * Gets the default syncMode.
1602      *
1603      * Sync modes can be one of:
1604      * - disabled
1605      * - slow
1606      * - two-way
1607      * - one-way-from-server
1608      * - one-way-from-client
1609      * - refresh-from-server
1610      * - refresh-from-client
1611      */
1612     virtual const char*  getSync() const;
1613     virtual void setSync(const string &value, bool temporarily = false);
1614
1615  private:
1616     string m_name;
1617     SyncSourceNodes m_nodes;
1618     mutable ConfigStringCache m_stringCache;
1619     string m_cachedPassword;
1620 };
1621
1622 /**
1623  * Representing a configuration template node used for fuzzy matching.
1624  */
1625 class TemplateConfig
1626 {
1627     boost::shared_ptr<FileConfigNode> m_metaNode;
1628     ConfigProps m_metaProps;
1629     string m_name;
1630 public:
1631     TemplateConfig (const string &path);
1632     enum {
1633         NO_MATCH = 0,
1634         LEVEL1_MATCH = 1,
1635         LEVEL2_MATCH = 2,
1636         LEVEL3_MATCH = 3,
1637         LEVEL4_MATCH = 4,
1638         BEST_MATCH=5
1639     };
1640     static bool isTemplateConfig (const string &path);
1641     virtual int metaMatch (const string &fingerprint, SyncConfig::MatchMode mode);
1642     virtual int serverModeMatch (SyncConfig::MatchMode mode);
1643     virtual int fingerprintMatch (const string &fingerprint);
1644     virtual string getName();
1645     virtual string getDescription();
1646     virtual string getFingerprint();
1647 };
1648
1649
1650 /**@}*/
1651
1652
1653 SE_END_CXX
1654 #endif