Imported Upstream version 0.8~alpha1
[platform/upstream/syncevolution.git] / src / SyncEvolutionConfig.h
1 /*
2  * Copyright (C) 2008 Patrick Ohly
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY, TITLE, NONINFRINGEMENT or FITNESS FOR A PARTICULAR
11  * PURPOSE.  See the GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
16  * 02111-1307  USA
17  */
18 #ifndef INCL_SYNC_EVOLUTION_CONFIG
19 # define INCL_SYNC_EVOLUTION_CONFIG
20
21 #include "FilterConfigNode.h"
22
23 #include "spds/AbstractSyncConfig.h"
24 #include "spds/AbstractSyncSourceConfig.h"
25 #include <boost/shared_ptr.hpp>
26 #include <boost/algorithm/string/predicate.hpp>
27 #include <boost/algorithm/string/trim.hpp>
28 #include <list>
29 #include <string>
30 #include <sstream>
31 #include <set>
32 using namespace std;
33
34 class EvolutionSyncSourceConfig;
35 class PersistentEvolutionSyncSourceConfig;
36 class ConfigTree;
37 struct SyncSourceNodes;
38 struct ConstSyncSourceNodes;
39
40 /**
41  * A property has a name and a comment. Derived classes might have
42  * additional code to read and write the property from/to a
43  * ConfigNode. They might also one or more  of the properties
44  * on the fly, therefore the virtual get methods which return a
45  * string value and not just a reference.
46  *
47  * A default value is returned if the ConfigNode doesn't have
48  * a value set (= empty string). Invalid values in the configuration
49  * trigger an exception. Setting invalid values does not because
50  * it is not known where the value comes from - the caller should
51  * check it himself.
52  */
53 class ConfigProperty {
54  public:
55     ConfigProperty(const string &name, const string &comment, const string &def = string("")) :
56         m_obligatory(false),
57         m_hidden(false),
58         m_name(name),
59         m_comment(boost::trim_right_copy(comment)),
60         m_defValue(def)
61         {}
62     virtual ~ConfigProperty() {}
63     
64     virtual string getName() const { return m_name; }
65     virtual string getComment() const { return m_comment; }
66     virtual string getDefValue() const { return m_defValue; }
67
68     /**
69      * Check whether the given value is okay.
70      * If not, then set an error string (one line, no punctuation).
71      *
72      * @return true if value is okay
73      */
74     virtual bool checkValue(const string &value, string &error) const { return true; }
75
76     /** split \n separated comment into lines without \n, appending them to commentLines */
77     static void splitComment(const string &comment, list<string> &commentLines);
78
79     bool isHidden() const { return m_hidden; }
80     void setHidden(bool hidden) { m_hidden = hidden; }
81
82     bool isObligatory() const { return m_obligatory; }
83     void setObligatory(bool obligatory) { m_obligatory = obligatory; }
84
85     /** set value unconditionally, even if it is not valid */
86     void setProperty(ConfigNode &node, const string &value) const { node.setProperty(getName(), value, getComment()); }
87     void setProperty(FilterConfigNode &node, const string &value, bool temporarily = false) const {
88         if (temporarily) {
89             node.addFilter(m_name, value);
90         } else {
91             node.setProperty(m_name, value, getComment());
92         }
93     }
94
95     /** set default value of a property, marked as default unless forced setting */
96     void setDefaultProperty(ConfigNode &node, bool force) const {
97         string defValue = getDefValue();
98         node.setProperty(m_name, defValue, getComment(), force ? NULL : &defValue);
99     }
100
101     /**
102      * @retval isDefault    return true if the node had no value set and
103      *                      the default was returned instead
104      */
105     virtual string getProperty(const ConfigNode &node, bool *isDefault = NULL) const {
106         string name = getName();
107         string value = node.readProperty(name);
108         if (value.size()) {
109             string error;
110             if (!checkValue(value, error)) {
111                 throwValueError(node, name, value, error);
112             }
113             if (isDefault) {
114                 *isDefault = false;
115             }
116             return value;
117         } else {
118             if (isDefault) {
119                 *isDefault = true;
120             }
121             return getDefValue();
122         }
123     }
124
125  protected:
126     void throwValueError(const ConfigNode &node, const string &name, const string &value, const string &error) const;
127
128  private:
129     bool m_obligatory;
130     bool m_hidden;
131     const string m_name, m_comment, m_defValue;
132 };
133
134 template<class T> class InitList : public list<T> {
135  public:
136     InitList() {}
137     InitList(const T &initialValue) {
138         push_back(initialValue);
139     }
140     InitList &operator + (const T &rhs) {
141         push_back(rhs);
142         return *this;
143     }
144     InitList &operator += (const T &rhs) {
145         push_back(rhs);
146         return *this;
147     }
148 };
149 typedef InitList<string> Aliases;
150 typedef InitList<Aliases> Values;
151
152
153 /**
154  * A string property which maps multiple different possible value
155  * strings to one generic value, ignoring the case. Values not listed
156  * are passed through unchanged. The first value in the list of
157  * aliases is the generic one.
158  *
159  * The addition operator is defined for the aliases so that they
160  * can be constructed more easily.
161  */
162 class StringConfigProperty : public ConfigProperty {
163  public:
164     StringConfigProperty(const string &name, const string &comment,
165                          const string &def = string(""),
166                          const Values &values = Values()) :
167     ConfigProperty(name, comment, def),
168         m_values(values)
169         {}
170
171     /**
172      * @return false if aliases are defined and the string is not one of them
173      */
174     bool normalizeValue(string &res) const {
175         Values values = getValues();
176         for (Values::const_iterator value = values.begin();
177              value != values.end();
178              ++value) {
179             for (Aliases::const_iterator alias = value->begin();
180                  alias != value->end();
181                  ++alias) {
182                 if (boost::iequals(res, *alias)) {
183                     res = *value->begin();
184                     return true;
185                 }
186             }
187         }
188         return values.empty();
189     }
190
191     /**
192      * This implementation accepts all values if no aliases
193      * are given, otherwise the value must be part of the aliases.
194      */
195     virtual bool checkValue(const string &propValue, string &error) const {
196         Values values = getValues();
197         if (values.empty()) {
198             return true;
199         }
200
201         ostringstream err;
202         err << "not one of the valid values (";
203         for (Values::const_iterator value = values.begin();
204              value != values.end();
205              ++value) {
206             if (value != values.begin()) {
207                 err << ", ";
208             }
209             for (Aliases::const_iterator alias = value->begin();
210                  alias != value->end();
211                  ++alias) {
212                 if (alias != value->begin()) {
213                     err << " = ";
214                 }
215                 if (alias->empty()) {
216                     err << "\"\"";
217                 } else {
218                     err << *alias;
219                 }
220                 
221                 if (boost::iequals(propValue, *alias)) {
222                     return true;
223                 }
224             }
225         }
226         err << ")";
227         error = err.str();
228         return false;
229     }
230
231     virtual string getProperty(const ConfigNode &node, bool *isDefault = NULL) const {
232         string res = ConfigProperty::getProperty(node, isDefault);
233         normalizeValue(res);
234         return res;
235     }
236
237  protected:
238     virtual Values getValues() const { return m_values; }
239
240  private:
241     const Values m_values;
242 };
243
244
245 /**
246  * Instead of reading and writing strings, this class interprets the content
247  * as a specific type.
248  */
249 template<class T> class TypedConfigProperty : public ConfigProperty {
250  public:
251     TypedConfigProperty(const string &name, const string &comment, const string &defValue = string("0")) :
252     ConfigProperty(name, comment, defValue)
253         {}
254
255     /**
256      * This implementation accepts all values that can be converted
257      * to the required type.
258      */
259     virtual bool checkValue(const string &value, string &error) const {
260         istringstream in(value);
261         T res;
262         if (in >> res) {
263             return true;
264         } else {
265             error = "cannot parse value";
266             return false;
267         }
268     }
269
270     void setProperty(ConfigNode &node, const T &value) const {
271         ostringstream out;
272
273         out << value;
274         node.setProperty(getName(), out.str(), getComment());
275     }
276     void setProperty(FilterConfigNode &node, const T &value, bool temporarily = false) const {
277         ostringstream out;
278
279         out << value;
280         if (temporarily) {
281             node.addFilter(getName(), out.str());
282         } else {
283             node.setProperty(getName(), out.str(), getComment());
284         }
285     }
286
287     T getProperty(ConfigNode &node, bool *isDefault = NULL) {
288         string name = getName();
289         string value = node.readProperty(name);
290         istringstream in(value);
291         T res;
292         if (value.empty()) {
293             istringstream defStream(getDefValue());
294             defStream >> res;
295             if (isDefault) {
296                 *isDefault = true;
297             }
298             return res;
299         } else {
300             if (!(in >> res)) {
301                 throwValueError(node, name, value, "cannot parse value");
302             }
303             if (isDefault) {
304                 *isDefault = false;
305             }
306             return res;
307         }
308     }
309 };
310
311 typedef TypedConfigProperty<int> IntConfigProperty;
312 typedef TypedConfigProperty<unsigned int> UIntConfigProperty;
313 typedef TypedConfigProperty<long> LongConfigProperty;
314 typedef TypedConfigProperty<unsigned long> ULongConfigProperty;
315
316 /**
317  * This interface has to be provided by the user of the config
318  * to let the config code interact with the user.
319  */
320 class ConfigUserInterface {
321  public:
322     virtual ~ConfigUserInterface() {}
323
324     /**
325      * A helper function which interactively asks the user for
326      * a certain password. May throw errors.
327      *
328      * @param descr     A simple string explaining what the password is needed for,
329      *                  e.g. "SyncML server". This string alone has to be enough
330      *                  for the user to know what the password is for, i.e. the
331      *                  string has to be unique.
332      * @return entered password
333      */
334     virtual string askPassword(const string &descr) = 0;
335 };
336
337 class PasswordConfigProperty : public ConfigProperty {
338  public:
339     PasswordConfigProperty(const string &name, const string &comment, const string &def = string("")) :
340        ConfigProperty(name, comment, def)
341            {}
342
343     /**
344      * Check the password and cache the result.
345      */
346     virtual void checkPassword(ConfigNode &node,
347                                ConfigUserInterface &ui,
348                                const string &descr,
349                                string &cachedPassword);
350
351     /**
352      * return the cached value if necessary and possible
353      */
354     virtual string getCachedProperty(ConfigNode &node,
355                                      const string &cachedPassword);
356 };
357
358 /**
359  * Instead of reading and writing strings, this class interprets the content
360  * as boolean with T/F or 1/0 (default format).
361  */
362 class BoolConfigProperty : public StringConfigProperty {
363  public:
364     BoolConfigProperty(const string &name, const string &comment, const string &defValue = string("F")) :
365     StringConfigProperty(name, comment, defValue,
366                          Values() + (Aliases("1") + "T" + "TRUE") + (Aliases("0") + "F" + "FALSE"))
367         {}
368
369     void setProperty(ConfigNode &node, bool value) {
370         StringConfigProperty::setProperty(node, value ? "1" : "0");
371     }
372     void setProperty(FilterConfigNode &node, bool value, bool temporarily = false) {
373         StringConfigProperty::setProperty(node, value ? "1" : "0", temporarily);
374     }
375     int getProperty(ConfigNode &node, bool *isDefault = NULL) {
376         string res = ConfigProperty::getProperty(node, isDefault);
377
378         return boost::iequals(res, "T") ||
379             boost::iequals(res, "TRUE") ||
380             atoi(res.c_str()) != 0;
381     }
382 };
383
384 /**
385  * A registry for all properties which might be saved in the same ConfigNode.
386  * Currently the same as a simple list. Someone else owns the instances.
387  */
388 class ConfigPropertyRegistry : public list<const ConfigProperty *> {
389  public:
390     /** case-insensitive search for property */
391     const ConfigProperty *find(const string &propName) const {
392         for (const_iterator it = begin();
393              it != end();
394              ++it) {
395             if (boost::iequals((*it)->getName(), propName)) {
396                 return *it;
397             }
398         }
399         return NULL;
400     }
401 };
402
403 /**
404  * Store the current string value of a property in a cache
405  * and return the "const char *" pointer that is expected by
406  * the client library.
407  */
408 class ConfigStringCache {
409  public:
410     const char *getProperty(const ConfigNode &node, const ConfigProperty &prop) {
411         string value = prop.getProperty(node);
412         return storeString(prop.getName(), value);
413     }
414
415     const char *storeString(const string &key, const string &value) {
416         pair< map<string, string>::iterator, bool > res = m_cache.insert(pair<string,string>(key, value));
417         if (!res.second) {
418             res.first->second = value;
419         }
420         return res.first->second.c_str();
421     }
422
423  private:
424     map<string, string> m_cache;
425 };
426
427 /**
428  * This class implements the client library configuration interface
429  * by mapping values to properties to entries in a ConfigTree. The
430  * mapping is either the traditional one used by SyncEvolution <= 0.7
431  * and client library <= 6.5 or the new layout introduced with
432  * SyncEvolution >= 0.8. If for a given server name the old config
433  * exists, then it is used. Otherwise the new layout is used.
434  *
435  * This class can be instantiated on its own and then provides access
436  * to properties actually stored in files. EvolutionSyncClient
437  * inherits from this class so that a derived client has the chance to
438  * override every single property (although it doesn't have to).
439  * Likewise EvolutionSyncSource is derived from
440  * EvolutionSyncSourceConfig.
441  *
442  * Properties can be set permanently (this changes the underlying
443  * ConfigNode) and temporarily (this modifies the FilterConfigNode
444  * which wraps the ConfigNode).
445  *
446  * The old layout is:
447  * - $HOME/.sync4j/evolution/<server>/spds/syncml/config.txt
448  * -- spds/sources/<source>/config.txt
449  * ---                      changes_<changeid>/config.txt
450  *
451  * The new layout is:
452  * - ${XDG_CONFIG:-${HOME}/.config}/syncevolution/foo - base directory for server foo
453  * -- config.ini - constant per-server settings
454  * -- .internal.ini - read/write server properties - hidden from users because of the leading dot
455  * -- sources/bar - base directory for source bar
456  * --- config.ini - constant per-source settings
457  * --- .internal.ini - read/write source properties
458  * --- .changes_<changeid>.ini - change tracking node (content under control of sync source)
459  *
460  * Because this class needs to handle different file layouts it always
461  * uses a FileConfigTree instance. Other implementations would be
462  * possible.
463  */
464 class EvolutionSyncConfig : public AbstractSyncConfig {
465  public:
466     /**
467      * Opens the configuration for a specific server,
468      * searching for the config files in the usual
469      * places. Will succeed even if config does not
470      * yet exist: flushing such a config creates it.
471      *
472      * @param tree   if non-NULL, then this is used
473      *               as configuration tree instead of
474      *               searching for it; always uses the
475      *               current layout in that tree
476      */
477     EvolutionSyncConfig(const string &server,
478                         boost::shared_ptr<ConfigTree> tree = boost::shared_ptr<ConfigTree>());
479
480     /**
481      * Creates a temporary configuration.
482      * Can be copied around, but not flushed.
483      */
484     EvolutionSyncConfig();
485
486    /** absolute directory name of the configuration root */
487     string getRootPath() const;
488
489     typedef list< pair<string, string> > ServerList;
490
491     /**
492      * returns list of servers in either the old (.sync4j) or
493      * new config directory (.config), given as server name
494      * and absolute root of config
495      */
496     static ServerList getServers();
497
498     /**
499      * returns list of available config templates, given as
500      * server name and comment
501      */
502     static ServerList getServerTemplates();
503
504     /**
505      * Creates a new instance of a configuration template.
506      * The result can be modified to set filters, but it
507      * cannot be flushed.
508      *
509      * @return NULL if no such template
510      */
511     static boost::shared_ptr<EvolutionSyncConfig> createServerTemplate(const string &server);
512
513     /** true if the main configuration file already exists */
514     bool exists() const;
515
516     /** write changes */
517     void flush();
518
519     /**
520      * A list of all properties. Can be extended by derived clients.
521      */
522     static ConfigPropertyRegistry &getRegistry();
523
524     /**
525      * Replaces the property filter of either the sync properties or
526      * all sources. This can be used to e.g. temporarily override
527      * the active sync mode.
528      */
529     void setConfigFilter(bool sync, const FilterConfigNode::ConfigFilter &filter) {
530         if (sync) {
531             m_configNode->setFilter(filter);
532         } else {
533             m_sourceFilter = filter;
534         }
535     }
536
537     /**
538      * Read-write access to all configurable properties of the server.
539      * The visible properties are passed through the config filter,
540      * which can be modified.
541      */
542     virtual boost::shared_ptr<FilterConfigNode> getProperties(bool hidden = false) {
543         if (hidden) {
544             return boost::shared_ptr<FilterConfigNode>(new FilterConfigNode(m_hiddenNode));
545         } else {
546             return m_configNode;
547         }
548     }
549     virtual boost::shared_ptr<const FilterConfigNode> getProperties(bool hidden = false) const { return const_cast<EvolutionSyncConfig *>(this)->getProperties(hidden); }
550
551
552     /**
553      * Returns a wrapper around all properties of the given source
554      * which are saved in the config tree. Note that this is different
555      * from the set of sync source configs used by the SyncManager:
556      * the SyncManger uses the AbstractSyncSourceConfig. In
557      * SyncEvolution those are implemented by the
558      * EvolutionSyncSource's actually instantiated by
559      * EvolutionSyncClient. Those are complete whereas
560      * PersistentEvolutionSyncSourceConfig only provides access to a
561      * subset of the properties.
562      *
563      * Can be called for sources which do not exist yet.
564      */
565     virtual boost::shared_ptr<PersistentEvolutionSyncSourceConfig> getSyncSourceConfig(const string &name);
566     virtual boost::shared_ptr<const PersistentEvolutionSyncSourceConfig> getSyncSourceConfig(const string &name) const {
567         return const_cast<EvolutionSyncConfig *>(this)->getSyncSourceConfig(name);
568     }
569
570     /**
571      * Returns list of all configured (not active!) sync sources.
572      */
573     virtual list<string> getSyncSources() const;
574
575     /**
576      * Creates config nodes for a certain node. The nodes are not
577      * yet created in the backend if they do not yet exist.
578      *
579      * @param name       the name of the sync source
580      * @param trackName  additional part of the tracking node name (used for unit testing)
581      */
582     SyncSourceNodes getSyncSourceNodes(const string &name,
583                                        const string &trackName = "");
584     ConstSyncSourceNodes getSyncSourceNodes(const string &name,
585                                             const string &trackName = "") const;
586
587     /**
588      * initialize all properties with their default value
589      */
590     void setDefaults();
591
592     /**
593      * create a new sync source configuration with default values
594      */
595     void setSourceDefaults(const string &name);
596
597     /**
598      * Copy all registered properties (hidden and visible) and the
599      * tracking node into the current config. This is done by reading
600      * all properties from the source config, which implies the unset
601      * properties will be set to their default values.  The current
602      * config is not cleared so additional, unregistered properties
603      * (should they exist) will continue to exist unchanged.
604      *
605      * The current config still needs to be flushed to make the
606      * changes permanent.
607      *
608      * @param sourceFilter   if NULL, then copy all sources; if not NULL,
609      *                       then only copy sources listed here
610      */
611     void copy(const EvolutionSyncConfig &other,
612               const set<string> *sourceFilter);
613
614     /**
615      * @defgroup SyncEvolutionSettings
616      *
617      * See etc/syncml-config.txt and the property definitions in
618      * SyncEvolutionConfig.cpp for the user-visible explanations of
619      * these settings.
620      *
621      * @{
622      */
623
624     virtual const char *getLogDir() const;
625     virtual void setLogDir(const string &value, bool temporarily = false);
626
627     virtual int getMaxLogDirs() const;
628     virtual void setMaxLogDirs(int value, bool temporarily = false);
629
630     virtual int getLogLevel() const;
631     virtual void setLogLevel(int value, bool temporarily = false);
632
633     /**@}*/
634
635     /**
636      * @defgroup AbstractSyncConfig
637      *
638      * These settings are required by the Funambol C++ client library.
639      * Some of them are hard-coded in this class. A derived class could
640      * make them configurable again, should that be desired.
641      *
642      * @{
643      */
644
645     /**
646      * @defgroup ActiveSyncSources
647      *
648      * This group of calls grants access to all active sources. In
649      * SyncEvolution the EvolutionSyncClient class decides which
650      * sources are active and thus fully configured and reimplements
651      * these calls.
652      *
653      * @{
654      */
655     virtual AbstractSyncSourceConfig* getAbstractSyncSourceConfig(const char* name) const { return NULL; }
656     virtual AbstractSyncSourceConfig* getAbstractSyncSourceConfig(unsigned int i) const { return NULL; }
657     virtual unsigned int getAbstractSyncSourceConfigsCount() const { return 0; }
658     /**@}*/
659
660     virtual const char*  getUsername() const;
661     virtual void setUsername(const string &value, bool temporarily = false);
662     virtual const char*  getPassword() const;
663     virtual void setPassword(const string &value, bool temporarily = false);
664
665     /**
666      * Look at the password setting and if it requires user interaction,
667      * get it from the user. Then store it for later usage in getPassword().
668      * Without this call, getPassword() returns the original, unmodified
669      * config string.
670      */
671     virtual void checkPassword(ConfigUserInterface &ui);
672
673     virtual bool getUseProxy() const;
674     virtual void setUseProxy(bool value, bool temporarily = false);
675     virtual const char*  getProxyHost() const;
676     virtual void setProxyHost(const string &value, bool temporarily = false);
677     virtual int getProxyPort() const { return 0; }
678     virtual const char* getProxyUsername() const;
679     virtual void setProxyUsername(const string &value, bool temporarily = false);
680     virtual const char* getProxyPassword() const;
681     virtual void checkProxyPassword(ConfigUserInterface &ui);
682     virtual void setProxyPassword(const string &value, bool temporarily = false);
683     virtual const char*  getSyncURL() const;
684     virtual void setSyncURL(const string &value, bool temporarily = false);
685     virtual const char*  getClientAuthType() const;
686     virtual void setClientAuthType(const string &value, bool temporarily = false);
687     virtual bool getLoSupport() const;
688     virtual void setLoSupport(bool value, bool temporarily = false);
689     virtual unsigned long getMaxMsgSize() const;
690     virtual void setMaxMsgSize(unsigned long value, bool temporarily = false);
691     virtual unsigned int getMaxObjSize() const;
692     virtual void setMaxObjSize(unsigned int value, bool temporarily = false);
693     virtual unsigned long getReadBufferSize() const { return 0; }
694     virtual const char* getSSLServerCertificates() const;
695     virtual void setSSLServerCertificates(const string &value, bool temporarily = false);
696     virtual bool getSSLVerifyServer() const;
697     virtual void setSSLVerifyServer(bool value, bool temporarily = false);
698     virtual bool getSSLVerifyHost() const;
699     virtual void setSSLVerifyHost(bool value, bool temporarily = false);
700     virtual bool  getCompression() const;
701     virtual void setCompression(bool value, bool temporarily = false);
702     virtual unsigned int getResponseTimeout() const { return 0; }
703     virtual const char*  getDevID() const;
704     virtual void setDevID(const string &value, bool temporarily = false);
705
706     virtual bool getServerAuthRequired() const { return false; }
707     virtual const char*  getServerAuthType() const { return ""; }
708     virtual const char*  getServerPWD() const { return ""; }
709     virtual const char*  getServerID() const { return ""; }
710
711     virtual const char*  getUserAgent() const { return "SyncEvolution"; }
712     virtual const char*  getVerDTD() const { return "1.1"; }
713     virtual const char*  getMan() const { return "Patrick Ohly"; }
714     virtual const char*  getMod() const { return "SyncEvolution"; }
715     virtual const char*  getOem() const { return "Open Source"; }
716     virtual const char*  getFwv() const { return ""; }
717     virtual const char*  getHwv() const { return ""; }
718     virtual const char*  getDsV() const { return ""; }
719     virtual const char*  getSwv() const;
720     virtual const char*  getDevType() const;
721
722     virtual bool getUtc() const { return true; }
723     virtual bool getNocSupport() const { return false; }
724
725     virtual const char*  getServerNonce() const;
726     virtual void setServerNonce(const char *value);
727     virtual const char*  getClientNonce() const;
728     virtual void setClientNonce(const char *value);
729     virtual const char*  getDevInfHash() const;
730     virtual void setDevInfHash(const char *value);
731
732     /**@}*/
733
734 private:
735     string m_server;
736     bool m_oldLayout;
737     string m_cachedPassword;
738     string m_cachedProxyPassword;
739
740     /** holds all config nodes relative to the root that we found */
741     boost::shared_ptr<ConfigTree> m_tree;
742
743     /** access to global sync properties */
744     boost::shared_ptr<FilterConfigNode> m_configNode;
745     boost::shared_ptr<ConfigNode> m_hiddenNode;
746
747     /** temporary overrides for sync or sync source settings */
748     FilterConfigNode::ConfigFilter m_sourceFilter;
749
750     mutable ConfigStringCache m_stringCache;
751
752     static string getHome() {
753         const char *homestr = getenv("HOME");
754         return homestr ? homestr : ".";
755     }
756     
757     static string getOldRoot() {
758         return getHome() + "/.sync4j/evolution";
759     }
760
761     static string getNewRoot() {
762         const char *xdg_root_str = getenv("XDG_CONFIG_HOME");
763         return xdg_root_str ? string(xdg_root_str) + "/syncevolution" :
764             getHome() + "/.config/syncevolution";
765     }
766 };
767
768 /**
769  * This set of config nodes is to be used by EvolutionSyncSourceConfig
770  * to accesss properties.
771  */
772 struct SyncSourceNodes {
773     /**
774      * @param configNode    node for user-visible properties
775      * @param hiddenNode    node for internal properties (may be the same as
776      *                      configNode in old config layouts!)
777      * @param trackingNode  node for tracking changes (always different than the
778      *                      other two nodes)
779      */
780     SyncSourceNodes(const boost::shared_ptr<FilterConfigNode> &configNode,
781                     const boost::shared_ptr<ConfigNode> &hiddenNode,
782                     const boost::shared_ptr<ConfigNode> &trackingNode) : 
783     m_configNode(configNode),
784         m_hiddenNode(hiddenNode),
785         m_trackingNode(trackingNode)
786     {}
787
788     const boost::shared_ptr<FilterConfigNode> m_configNode;
789     const boost::shared_ptr<ConfigNode> m_hiddenNode;
790     const boost::shared_ptr<ConfigNode> m_trackingNode;
791 };
792
793 struct ConstSyncSourceNodes {
794     ConstSyncSourceNodes(const boost::shared_ptr<const FilterConfigNode> &configNode,
795                          const boost::shared_ptr<const ConfigNode> &hiddenNode,
796                          const boost::shared_ptr<const ConfigNode> &trackingNode) : 
797     m_configNode(configNode),
798         m_hiddenNode(hiddenNode),
799         m_trackingNode(trackingNode)
800     {}
801
802     ConstSyncSourceNodes(const SyncSourceNodes &other) :
803     m_configNode(other.m_configNode),
804         m_hiddenNode(other.m_hiddenNode),
805         m_trackingNode(other.m_trackingNode)
806     {}
807
808     const boost::shared_ptr<const FilterConfigNode> m_configNode;
809     const boost::shared_ptr<const ConfigNode> m_hiddenNode;
810     const boost::shared_ptr<const ConfigNode> m_trackingNode;
811 };
812
813
814 /**
815  * This class maps per-source properties to ConfigNode properties.
816  * Some properties are not configurable and have to be provided
817  * by derived classes.
818  */
819 class EvolutionSyncSourceConfig : public AbstractSyncSourceConfig {
820  public:
821     EvolutionSyncSourceConfig(const string &name, const SyncSourceNodes &nodes);
822
823     static ConfigPropertyRegistry &getRegistry();
824     bool exists() const { return m_nodes.m_configNode->exists(); }
825
826     /**
827      * @defgroup EvolutionSyncSourceConfigExtensions
828      *
829      * @{
830      */
831     virtual const char *getUser() const;
832     virtual void setUser(const string &value, bool temporarily = false);
833
834     const char *getPassword() const;
835     virtual void setPassword(const string &value, bool temporarily = false);
836
837     /** same as EvolutionSyncConfig::checkPassword() */
838     virtual void checkPassword(ConfigUserInterface &ui);
839
840     virtual const char *getDatabaseID() const;
841     virtual void setDatabaseID(const string &value, bool temporarily = false);
842     /**@}*/
843
844     /**
845      * Returns the data source type configured as part of the given
846      * configuration; different EvolutionSyncSources then check whether
847      * they support that type. This call has to work before instantiating
848      * a source and thus gets passed a node to read from.
849      *
850      * @return the pair of <backend> and the (possibly empty)
851      *         <format> specified in the "type" property; see
852      *         sourcePropSourceType in SyncEvolutionConfig.cpp
853      *         for details
854      */
855     static pair<string, string> getSourceType(const SyncSourceNodes &nodes);
856     static string getSourceTypeString(const SyncSourceNodes &nodes);
857     virtual pair<string, string> getSourceType() const;
858
859     /** set the source type in <backend>[:format] style */
860     virtual void setSourceType(const string &value, bool temporarily = false);
861
862
863     /**@}*/
864
865     /**
866      * @defgroup AbstractSyncSourceConfigAPI_not_yet_implemented
867      *
868      * These calls have to be implemented by EvolutionSyncSource
869      * instances. Some sources support more than one type. The
870      * configuration then selects the preferred format in
871      * the getSourceType() string.
872      * 
873      * @{
874      */
875
876     /**
877      * Returns the preferred mime type of the items handled by the sync source.
878      * Example: "text/x-vcard"
879      */
880     virtual const char *getMimeType() const = 0;
881
882     /**
883      * Returns the version of the mime type used by client.
884      * Example: "2.1"
885      */
886     virtual const char *getMimeVersion() const = 0;
887
888     /**
889      * A string representing the source types (with versions) supported by the SyncSource.
890      * The string must be formatted as a sequence of "type:version" separated by commas ','.
891      * For example: "text/x-vcard:2.1,text/vcard:3.0".
892      * The version can be left empty, for example: "text/x-s4j-sifc:".
893      * Supported types will be sent as part of the DevInf.
894      */
895     virtual const char* getSupportedTypes() const = 0;
896
897     /**@}*/
898
899     /**
900      * @defgroup AbstractSyncSourceConfigAPI_implemented
901      * @{
902      */
903     virtual const char *getType() const { return getMimeType(); }
904     virtual const char *getVersion() const { return getMimeVersion(); }
905     virtual const char*  getName() const { return m_name.c_str(); }
906     /**@}*/
907
908     /**
909      * Returns the SyncSource URI: used in SyncML to address the data
910      * on the server.
911      *
912      * Each URI has to be unique during a sync session, i.e.
913      * two different sync sources cannot access the same data at
914      * the same time.
915      */
916     virtual const char*  getURI() const;
917     virtual void setURI(const string &value, bool temporarily = false);
918
919     /**
920      * Returns a comma separated list of the possible syncModes for the
921      * SyncSource. Sync modes can be one of
922      * - slow
923      * - two-way
924      * - one-way-from-server
925      * - one-way-from-client
926      * - refresh-from-server
927      * - refresh-from-client
928      * - one-way-from-server
929      * - one-way-from-client
930      * - addrchange (Funambol extension)
931      *
932      * This is hard-coded in SyncEvolution because changing it
933      * wouldn't have any effect (IMHO).
934      */
935     virtual const char*  getSyncModes() const { return "slow,two-way,one-way-from-server,one-way-from-client,refresh-from-server,refresh-from-client"; }
936
937     /**
938      * Gets the default syncMode as one of the strings listed in setSyncModes.
939      */
940     virtual const char*  getSync() const;
941     virtual void setSync(const string &value, bool temporarily = false);
942     
943     /**
944      * Specifies how the content of an outgoing item should be
945      * encoded by the client library if the sync source does not
946      * set an encoding on the item that it created. Valid values
947      * are listed in SyncItem::encodings.
948      */
949     virtual const char*  getEncoding() const;
950     virtual void setEncoding(const string &value, bool temporarily = false);
951
952     /**
953      * Sets the last sync timestamp. Called by the sync engine at
954      * the end of a sync. The client must save that modified
955      * value; it is needed to decide during the next sync whether
956      * an incremental sync is possible.
957      *
958      * SyncEvolution will reset this value when a SyncSource fails
959      * and thus force a slow sync during the next sync.
960      *
961      * @param timestamp the last sync timestamp
962      */
963     virtual unsigned long getLast() const;
964     virtual void setLast(unsigned long timestamp);
965
966     /**
967      * "des" enables an encryption mode which only the Funambol server
968      * understands. Not configurable in SyncEvolution unless a derived
969      * SyncSource decides otherwise.
970      */
971     virtual const char* getEncryption() const { return ""; }
972
973     /**
974      * Returns an array of CtCap with all the capabilities for this
975      * source.  The capabilities specify which parts of e.g. a vCard
976      * the sync source supports. Not specifying this in detail by
977      * returning an empty array implies that it supports all aspects.
978      * This is the default implementation of this call.
979      *
980      * @return an ArrayList of CTCap
981      */
982     virtual const ArrayList& getCtCaps() const { static const ArrayList dummy; return dummy; }
983
984     /**@}*/
985
986  private:
987     string m_name;
988     SyncSourceNodes m_nodes;
989     mutable ConfigStringCache m_stringCache;
990     string m_cachedPassword;
991 };
992
993 /**
994  * Adds dummy implementations of the missing calls to
995  * EvolutionSyncSourceConfig so that the other properties can be read.
996  */
997 class PersistentEvolutionSyncSourceConfig : public EvolutionSyncSourceConfig {
998  public:
999     PersistentEvolutionSyncSourceConfig(const string &name, const SyncSourceNodes &nodes) :
1000     EvolutionSyncSourceConfig(name, nodes) {}
1001
1002     virtual const char* getMimeType() const { return ""; }
1003     virtual const char* getMimeVersion() const { return ""; }
1004     virtual const char* getSupportedTypes() const { return ""; }
1005 };
1006
1007 #endif