Imported Upstream version 1.3.99.4
[platform/upstream/syncevolution.git] / src / syncevo / SyncContext.h
1 /*
2  * Copyright (C) 2005-2009 Patrick Ohly <patrick.ohly@gmx.de>
3  * Copyright (C) 2009 Intel Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) version 3.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301  USA
19  */
20
21 #ifndef INCL_EVOLUTIONSYNCCLIENT
22 #define INCL_EVOLUTIONSYNCCLIENT
23
24 #include <syncevo/SmartPtr.h>
25 #include <syncevo/SyncConfig.h>
26 #include <syncevo/SyncML.h>
27 #include <syncevo/SynthesisEngine.h>
28 #include <syncevo/UserInterface.h>
29
30 #include <string>
31 #include <set>
32 #include <map>
33 #include <stdint.h>
34
35 #include <boost/smart_ptr.hpp>
36 #include <boost/signals2.hpp>
37
38 #include <syncevo/declarations.h>
39 SE_BEGIN_CXX
40
41 class TransportAgent;
42 class SourceList;
43 class SyncSource;
44 class SyncSourceEvent;
45
46 /**
47  * This is the main class inside SyncEvolution which
48  * looks at the configuration, activates all enabled
49  * sources and executes the synchronization.
50  *
51  * All interaction with the user (reporting progress, asking for
52  * passwords, ...) is done via virtual methods. The default
53  * implementation of those uses stdin/out.
54  *
55  */
56 class SyncContext : public SyncConfig {
57     /**
58      * the string used to request a config,
59      * *not* the normalized config name itself;
60      * for that use SyncConfig::getConfigName()
61      */
62     const string m_server;
63
64     bool m_doLogging;
65     bool m_quiet;
66     bool m_dryrun;
67
68     bool m_localSync;
69     string m_localPeerContext; /**< context name (including @) if doing local sync */
70     string m_localClientRootPath;
71     bool m_serverMode;
72     bool m_serverAlerted;      /**< sync was initiated by server (applies to client and server mode) */
73     bool m_configNeeded;
74     std::string m_sessionID;
75     SharedBuffer m_initialMessage;
76     string m_initialMessageType;
77     string m_syncDeviceID;
78
79     FullProps m_configFilters;
80     
81     boost::shared_ptr<TransportAgent> m_agent;
82     boost::shared_ptr<UserInterface> m_userInterface;
83
84     /**
85      * a pointer to the active SourceList instance for this context if one exists;
86      * used for error handling in throwError() on the iPhone
87      */
88     SourceList *m_sourceListPtr;
89
90     /**
91      * a pointer to the active SyncContext instance if one exists;
92      * set by sync() and/or SwapContext
93      */
94     static SyncContext *m_activeContext;
95     class SwapContext {
96         SyncContext *m_oldContext;
97     public:
98         SwapContext(SyncContext *newContext) :
99             m_oldContext(SyncContext::m_activeContext) {
100             SyncContext::m_activeContext = newContext;
101         }
102         ~SwapContext() {
103             SyncContext::m_activeContext = m_oldContext;
104         }
105     };
106
107     /**
108      * Connection to the Synthesis engine. Always valid in a
109      * constructed SyncContext. Use getEngine() to reference
110      * it.
111      */
112     SharedEngine m_engine;
113
114     /**
115      * Synthesis session handle. Only valid while sync is running.
116      */
117     SharedSession m_session;
118
119     /**
120      * installs session in SyncContext and removes it again
121      * when going out of scope
122      */
123     class SessionSentinel {
124         SyncContext &m_client;
125     public:
126         SessionSentinel(SyncContext &client, SharedSession &session) :
127         m_client(client) {
128             m_client.m_session = session;
129         }
130         ~SessionSentinel() {
131             m_client.m_session.reset();
132         }
133     };
134
135     /*
136      * The URL this SyncContext is actually using, since we may support multiple
137      * urls in the configuration.
138      * */
139     string m_usedSyncURL;
140
141     /* True iff current sync session was triggered by us
142      * (such as in server alerted sync).
143      */
144     bool m_remoteInitiated;
145   public:
146     /**
147      * Common initialization code which needs to be done once
148      * at the start of main() in any application using SyncEvolution.
149      * For example, initializes (if applicable) glib and EDS.
150      *
151      * @param appname     static string, must remain valid, defines name of executable (see g_set_prgname())
152      */
153     static void initMain(const char *appname);
154
155     /**
156      * A signal invoked as part of initMain().
157      * Backends can connect to it to extend initMain().
158      */
159     typedef boost::signals2::signal<void (const char *appname)> InitMainSignal;
160     static InitMainSignal &GetInitMainSignal();
161
162     /**
163      * A signal invoked each time a source has gone through a sync cycle.
164      */
165     typedef boost::signals2::signal<void (const std::string &name, const SyncSourceReport &source)> SourceSyncedSignal;
166     SourceSyncedSignal m_sourceSyncedSignal;
167
168     /**
169      * true if binary was compiled as stable release
170      * (see gen-autotools.sh)
171      */
172     static bool isStableRelease();
173
174     /**
175      * override stable release mode (for testing purposes)
176      */
177     static void setStableRelease(bool isStableRelease);
178
179     /**
180      * SyncContext using a volatile config
181      * and no logging.
182      */
183     SyncContext();
184
185     /**
186      * Constructor for syncing with a SyncML peer.
187      *
188      * @param peer       identifies the client or server config to be used
189      * @param doLogging  write additional log and datatbase files about the sync;
190      *                   true for regular syncs, false for debugging
191      */
192     SyncContext(const string &server,
193                 bool doLogging = false);
194
195     /**
196      * Constructor for client in a local sync.
197      *
198      * @param client     identifies the client context to be used (@foobar)
199      * @param server     identifies the server peer (foo@bar)
200      * @param rootPath   use this directory as config directory for the
201      *                   peer-specific files (located inside peer directory
202      *                   of server config)
203      * @param agent      transport agent, ready for communication with server
204      * @param doLogging  write additional log and datatbase files about the sync
205      */
206     SyncContext(const string &client,
207                 const string &server,
208                 const string &rootPath,
209                 const boost::shared_ptr<TransportAgent> &agent,
210                 bool doLogging = false);
211
212     virtual ~SyncContext();
213
214     bool getQuiet() { return m_quiet; }
215     void setQuiet(bool quiet) { m_quiet = quiet; }
216
217     bool getDryRun() { return m_dryrun; }
218     void setDryRun(bool dryrun) { m_dryrun = dryrun; }
219
220     bool isLocalSync() const { return m_localSync; }
221
222     bool isServerAlerted() const { return m_serverAlerted; }
223     void setServerAlerted(bool serverAlerted) { m_serverAlerted = serverAlerted; }
224
225     boost::shared_ptr<UserInterface> getUserInterface() { return m_userInterface; }
226     void setUserInterface(const boost::shared_ptr<UserInterface> &userInterface) { m_userInterface = userInterface; }
227
228     /** use config UI owned by caller, without reference counting */
229     void setUserInterface(UserInterface *userInterface) { m_userInterface = boost::shared_ptr<UserInterface>(userInterface, NopDestructor()); }
230
231     /**
232      * In contrast to getUserInterface(), this call here never returns NULL.
233      * If no UserInterface is currently set, then it returns
234      * a reference to a dummy instance which doesn't do anything.
235      */
236     UserInterface &getUserInterfaceNonNull();
237
238     /**
239      * Running operations typically checks that a config really exists
240      * on disk. Setting false disables the check.
241      */
242     bool isConfigNeeded() const { return m_configNeeded; }
243     void setConfigNeeded(bool configNeeded) { m_configNeeded = configNeeded; }
244
245     /**
246      * throws error if config is needed and not available
247      *
248      * @param operation   a noun describing what is to be done next ("proceed with %s", operation)
249      */
250     void checkConfig(const std::string &operation) const;
251
252     /**
253      * Sets configuration filters. Currently only used in local sync
254      * to configure the sync client.
255      */
256     void setConfigProps(const FullProps &props) { m_configFilters = props; }
257     const FullProps &getConfigProps() const { return m_configFilters; }
258
259     /** only for server: device ID of peer */
260     void setSyncDeviceID(const std::string &deviceID) { m_syncDeviceID = deviceID; }
261     std::string getSyncDeviceID() const { return m_syncDeviceID; }
262
263     /*
264      * Use sendSAN as the first step is sync() if this is a server alerted sync.
265      * Prepare the san package and send the SAN request to the peer.
266      * Returns false if failed to get a valid client sync request
267      * otherwise put the client sync request into m_initialMessage which will
268      * be used to initalze the server via initServer(), then continue sync() to
269      * start the real sync serssion.
270      * @version indicates the SAN protocal version used (1.2 or 1.1/1.0)
271      */
272     bool sendSAN(uint16_t version);
273
274     /**
275      * Initializes the session so that it runs as SyncML server once
276      * sync() is called. For this to work the first client message
277      * must be available already.
278      *
279      * @param sessionID    session ID to be used by server
280      * @param data         content of initial message sent by the client
281      * @param messageType  content type set by the client
282      */
283     void initServer(const std::string &sessionID,
284                     SharedBuffer data,
285                     const std::string &messageType);
286
287     /**
288      * Executes the sync, throws an exception in case of failure.
289      * Handles automatic backups and report generation.
290      *
291      * @retval complete sync report, skipped if NULL
292      * @return overall sync status, for individual sources see report
293      */
294     SyncMLStatus sync(SyncReport *report = NULL);
295
296     /** result of analyzeSyncMLMessage() */
297     struct SyncMLMessageInfo {
298         std::string m_deviceID;
299
300         /** a string representation of the whole structure for debugging */
301         std::string toString() { return std::string("deviceID ") + m_deviceID; }
302     };
303
304     /**
305      * Instead or executing a sync, analyze the initial message
306      * without changing any local data. Returns once the LocURI =
307      * device ID of the client is known.
308      *
309      * @return device ID, empty if not in data
310      */
311     static SyncMLMessageInfo
312         analyzeSyncMLMessage(const char *data, size_t len,
313                              const std::string &messageType);
314
315     /**
316      * Convenience function, to be called inside a catch() block of
317      * (or for) the sync.
318      *
319      * Rethrows the exception to determine what it is, then logs it
320      * as an error and returns a suitable error code (usually a general
321      * STATUS_DATASTORE_FAILURE).
322      */
323     SyncMLStatus handleException();
324
325     /**
326      * Determines the log directory of the previous sync (either in
327      * temp or logdir) and shows changes since then.
328      */
329     void status();
330
331     enum RestoreDatabase {
332         DATABASE_BEFORE_SYNC,
333         DATABASE_AFTER_SYNC
334     };
335
336     /**
337      * Restore data of selected sources from before or after the given
338      * sync session, identified by absolute path to the log dir.
339      */
340     void restore(const string &dirname, RestoreDatabase database);
341
342     /**
343      * fills vector with absolute path to information about previous
344      * sync sessions, oldest one first
345      */
346     void getSessions(vector<string> &dirs);
347
348     /**
349      * fills report with information about previous session
350      * @return the peer name from the dir.
351      */
352     string readSessionInfo(const string &dir, SyncReport &report);
353
354     /**
355      * fills report with information about local changes
356      *
357      * Only sync sources selected in the SyncContext
358      * constructor are checked. The local item changes will be set in
359      * the SyncReport's ITEM_LOCAL ITEM_ADDED/UPDATED/REMOVED.
360      *
361      * Some sync sources might not be able to report this
362      * information outside of a regular sync, in which case
363      * these fields are set to -1. 
364      *
365      * Start and end times of the check are also reported.
366      */
367     void checkStatus(SyncReport &report);
368
369     /**
370      * throws a StatusException with a local, fatal error with the given string
371      * or (on the iPhone, where exception handling is not
372      * supported by the toolchain) prints an error directly
373      * and aborts
374      *
375      * output format: <error>
376      *
377      * @param error     a string describing the error
378      */
379     static void throwError(const string &error);
380
381     /**
382      * throw an exception with a specific status code after an operation failed and
383      * remember that this instance has failed
384      *
385      * output format: <failure>
386      *
387      * @param status     a more specific status code; other throwError() variants
388      *                   use STATUS_FATAL + sysync::LOCAL_STATUS_CODE, which is interpreted
389      *                   as a fatal local error
390      * @param action     a string describing what was attempted *and* how it failed
391      */
392     static void throwError(SyncMLStatus status, const string &failure);
393
394     /**
395      * throw an exception after an operation failed and
396      * remember that this instance has failed
397      *
398      * output format: <action>: <error string>
399      *
400      * @Param action   a string describing the operation or object involved
401      * @param error    the errno error code for the failure
402      */
403     static void throwError(const string &action, int error);
404
405     /**
406      * An error handler which prints the error message and then
407      * stops the program. Never returns.
408      *
409      * The API was chosen so that it can be used as libebook/libecal
410      * "backend-dies" signal handler.
411      */
412     static void fatalError(void *object, const char *error);
413
414     /**
415      * When using Evolution this function starts a background thread
416      * which drives the default event loop. Without that loop
417      * "backend-died" signals are not delivered. The problem with
418      * the thread is that it seems to interfere with gconf startup
419      * when added to the main() function of syncevolution. Therefore
420      * it is started by SyncSource::beginSync() (for unit
421      * testing of sync sources) and SyncContext::sync() (for
422      * normal operation).
423      */
424     static void startLoopThread();
425
426     /**
427      * Finds activated sync source by name. May return  NULL
428      * if no such sync source was defined or is not currently
429      * instantiated. Pointer remains valid throughout the sync
430      * session. Called by Synthesis DB plugin to find active
431      * sources.
432      *
433      * @param name     can be both <SyncSource::getName()> as well as <prefix>_<SyncSource::getName()>
434      *                 (necessary when renaming sources in the Synthesis XML config)
435      *
436      * @TODO: roll SourceList into SyncContext and
437      * make this non-static
438      */
439     static SyncSource *findSource(const std::string &name);
440     static const char m_findSourceSeparator = '@';
441
442     /**
443      * Find the active sync context for the given session.
444      *
445      * @param sessionName      chosen by SyncEvolution and passed to
446      *                         Synthesis engine, which calls us back
447      *                         with it in SyncEvolution_Session_CreateContext()
448      * @return context or NULL if not found
449      */
450     static SyncContext *findContext(const char *sessionName);
451
452     SharedEngine getEngine() { return m_engine; }
453     const SharedEngine getEngine() const { return m_engine; }
454
455     bool getDoLogging() { return m_doLogging; }
456
457     /**
458      * Returns the string used to select the peer config
459      * used by this instance.
460      *
461      * Note that this is not the same as a valid configuration
462      * name. For example "foo" might be matched against a
463      * "foo@bar" config by SyncConfig. Use SyncConfig::getConfigName()
464      * to get the underlying config.
465      */
466     std::string getPeer() { return m_server; }
467
468     /**
469      * Handle for active session, may be NULL.
470      */
471     SharedSession getSession() { return m_session; }
472
473     bool getRemoteInitiated() {return m_remoteInitiated;}
474     void setRemoteInitiated(bool remote) {m_remoteInitiated = remote;}
475
476     /**
477      * If called while a sync session runs,
478      * the engine will finish the session and then
479      * immediately try to run another one with
480      * the same sources.
481      *
482      * Does nothing when called at the wrong time.
483      * There's no guarantee either that restarting is
484      * possible.
485      */
486     static void requestAnotherSync();
487
488     /**
489      * access to current set of sync sources, NULL if not instantiated yet
490      */
491     const std::vector<SyncSource *> *getSources() const;
492
493   protected:
494     /** exchange active Synthesis engine */
495     SharedEngine swapEngine(SharedEngine newengine) {
496         SharedEngine oldengine = m_engine;
497         m_engine = newengine;
498         return oldengine;
499     }
500
501     /** sentinel class which creates, installs and removes a new
502         Synthesis engine for the duration of its own life time */
503     class SwapEngine {
504         SyncContext &m_client;
505         SharedEngine m_oldengine;
506
507     public:
508         SwapEngine(SyncContext &client) :
509         m_client(client) {
510             SharedEngine syncengine(m_client.createEngine());
511             m_oldengine = m_client.swapEngine(syncengine);
512         }
513
514         ~SwapEngine() {
515             m_client.swapEngine(m_oldengine);
516         }
517     };
518
519     /**
520      * Create a Synthesis engine for the currently active
521      * sources (might be empty!) and settings.
522      */
523     SharedEngine createEngine();
524
525     /**
526      * Return skeleton Synthesis client XML configuration.
527      *
528      * The <scripting/>, <datatypes/>, <clientorserver/> elements (if
529      * present) are replaced by the caller with fragments found in the
530      * file system. When <datatypes> already has content, that content
531      * may contain <fieldlists/>, <profiles/>, <datatypedefs/>, which
532      * will be replaced by definitions gathered from backends.
533      *
534      * The default implementation of this function takes the configuration from
535      * (in this order):
536      * - $(XDG_CONFIG_HOME)/syncevolution-xml
537      * - $(datadir)/syncevolution/xml
538      * Files with identical names are read from the first location where they
539      * are found. If $(SYNCEVOLUTION_XML_CONFIG_DIR) is set, then it overrides
540      * the previous two locations.
541      *
542      * The syncevolution.xml file is read from the first place where it is found.
543      * In addition, further .xml files in sub-directories are gathered and get
544      * inserted into the syncevolution.xml template.
545      *
546      * If none of these locations has XML configs, then builtin strings are
547      * used as fallback. This only works for mode == "client". Otherwise an
548      * error is thrown.
549      *
550      * @param mode         "client" or "server"
551      * @retval xml         is filled with Synthesis client config which may hav <datastore/>
552      * @retval rules       remote rules which the caller needs for <clientorserver/>
553      * @retval configname  a string describing where the config came from
554      */
555     virtual void getConfigTemplateXML(const string &mode,
556                                       string &xml,
557                                       string &rules,
558                                       string &configname);
559                                       
560
561     /**
562      * Return complete Synthesis XML configuration.
563      *
564      * Calls getConfigTemplateXML(), then fills in
565      * sync source XML fragments if necessary.
566      *
567      * @retval xml         is filled with complete Synthesis client config
568      * @retval configname  a string describing where the config came from
569      */
570     virtual void getConfigXML(string &xml, string &configname);
571
572     /**
573      * Callback for derived classes: called after initializing the
574      * client, but before doing anything with its configuration.
575      * Can be used to override the client configuration.
576      */
577     virtual void prepare() {}
578
579     /**
580      * instantiate transport agent
581      *
582      * Called by engine when it needs to exchange messages.  The
583      * transport agent will be used throughout the sync session and
584      * unref'ed when no longer needed. At most one agent will be
585      * requested at a time. The transport agent is intentionally
586      * returned as a Boost shared pointer so that a pointer to a
587      * class with a different life cycle is possible, either by
588      * keeping a reference or by returning a shared_ptr where the
589      * destructor doesn't do anything.
590      *
591      * The agent must be ready for use:
592      * - HTTP specific settings must have been applied
593      * - the current SyncContext's timeout must have been
594      *   installed via TransportAgent::setTimeout()
595      *
596      * The default implementation instantiates one of the builtin
597      * transport agents, depending on how it was compiled.
598      *
599      * @param gmainloop    the GMainLoop to be used by transports, if not NULL;
600      *                     transports not supporting that should not be created;
601      *                     transports will increase the reference count for the loop
602      * @return transport agent
603      */
604     virtual boost::shared_ptr<TransportAgent> createTransportAgent(void *gmainloop);
605     virtual boost::shared_ptr<TransportAgent> createTransportAgent() { return createTransportAgent(NULL); }
606
607     /**
608      * display a text message from the server
609      *
610      * Not really used by SyncML servers. Could be displayed in a
611      * modal dialog.
612      *
613      * @param message     string with local encoding, possibly with line breaks
614      */
615     virtual void displayServerMessage(const string &message);
616
617     /**
618      * display general sync session progress
619      *
620      * @param type    PEV_*, see <synthesis/engine_defs.h>
621      * @param extra1  extra information depending on type
622      * @param extra2  extra information depending on type
623      * @param extra3  extra information depending on type
624      */
625     virtual void displaySyncProgress(sysync::TProgressEventEnum type,
626                                      int32_t extra1, int32_t extra2, int32_t extra3);
627
628     /**
629      * An event plus its parameters, see Synthesis engine.
630      */
631     class SyncSourceEvent
632     {
633       public:
634         sysync::TProgressEventEnum m_type;
635         int32_t m_extra1, m_extra2, m_extra3;
636
637         SyncSourceEvent() :
638             m_type(sysync::PEV_NOP)
639         {}
640
641         SyncSourceEvent(sysync::TProgressEventEnum type,
642                         int32_t extra1,
643                         int32_t extra2,
644                         int32_t extra3)
645         {
646             m_type = type;
647             m_extra1 = extra1;
648             m_extra2 = extra2;
649             m_extra3 = extra3;
650         }
651     };
652
653     /**
654      * display sync source specific progress
655      *
656      * @param source  source which is the target of the event
657      * @param event   contains PEV_* and extra parameters, see <synthesis/engine_defs.h>
658      * @param flush   if true, then bypass caching events and print directly
659      * @return true if the event was cached
660      */
661     virtual bool displaySourceProgress(SyncSource &source,
662                                        const SyncSourceEvent &event,
663                                        bool flush);
664
665     /**
666      * report step command info
667      *
668      * Will be called after each step in step loop in SyncContext::doSync().
669      * This reports step command info. 
670      * @param stepCmd step command enum value 
671      */
672     virtual void reportStepCmd(sysync::uInt16 stepCmd) {}
673
674  private:
675     /** initialize members as part of constructors */
676     void init();
677
678     /**
679      * generate XML configuration and (re)initialize engine with it
680      */
681     void initEngine(bool logXML);
682
683     /**
684      * the code common to init() and status():
685      * populate source list with active sources and open
686      */
687     void initSources(SourceList &sourceList);
688
689     /**
690      * set m_localSync and m_localPeerContext
691      * @param config    config name of peer
692      */
693     void initLocalSync(const string &config);
694
695     /**
696      * called via pre-signal of m_startDataRead
697      */
698     void startSourceAccess(SyncSource *source);
699
700     /**
701      * utility function for status() and getChanges():
702      * iterate over sources, check for changes and copy result
703      */
704     void checkSourceChanges(SourceList &sourceList, SyncReport &changes);
705
706     /**
707      * A method to report sync is really successfully started.
708      * It happens at the same time SynthesDBPlugin starts to access source.
709      * For each sync, it is only called at most one time.
710      * The default action is nothing.
711      */
712     virtual void syncSuccessStart() { }
713
714     /**
715      * sets up Synthesis session and executes it
716      */
717     SyncMLStatus doSync();
718
719     /**
720      * directory for Synthesis client binfiles or
721      * Synthesis server textdb files, unique for each
722      * peer
723      */
724     string getSynthesisDatadir();
725
726     /**
727      * return true if "delayedabort" session variable is true
728      */
729     bool checkForScriptAbort(SharedSession session);
730
731     // total retry duration
732     int m_retryDuration;
733     // message resend interval
734     int m_retryInterval;
735     // Current retry count
736     int m_retries;
737
738     //a flag indicating whether it is the first time to start source access.
739     //It can be used to report infomation about a sync is successfully started.
740     bool m_firstSourceAccess;
741
742     // Cache for use in displaySourceProgress().
743     SyncSource *m_sourceProgress;
744     SyncSourceEvent m_sourceEvent;
745
746 public:
747     /**
748      * Returns the URL in the getSyncURL() list which is to be used
749      * for sync.  The long term goal is to pick the first URL which
750      * uses a currently available transport; right now it simply picks
751      * the first supported one.
752      */
753     string getUsedSyncURL();
754 };
755
756 SE_END_CXX
757 #endif // INCL_EVOLUTIONSYNCCLIENT