3 * Base class for SySync applications, is supposed to exist
4 * as singular object only, manages "global" things such
5 * as config reading and session dispatching
7 * Copyright (c) 2002-2009 by Synthesis AG (www.synthesis.ch)
9 * 2002-03-06 : luz : Created
12 #include "prefix_file.h"
15 #include "syncappbase.h"
16 #include "scriptcontext.h"
18 #include "syncagent.h"
19 #include "multifielditem.h" // in case we have no scripts...
21 #ifdef SYSER_REGISTRATION
25 #ifdef DIRECT_APPBASE_GLOBALACCESS
26 #include "sysync_glob_vars.h"
31 #include "global_progress.h" // globally accessible progress event posting
33 #ifndef ENGINE_LIBRARY
35 // can be called globally to post progress events
36 extern "C" int GlobalNotifyProgressEvent (
37 TProgressEventType aEventType,
43 #ifdef PROGRESS_EVENTS
44 TSyncAppBase *baseP = getExistingSyncAppBase();
46 return baseP->NotifyProgressEvent(aEventType,NULL,aExtra1,aExtra2,aExtra3);
49 return true; // not aborted
50 } // GlobalNotifyProgressEvent
52 #endif // not ENGINE_LIBRARY
57 #ifndef HARDCODED_CONFIG
59 // SyncML encoding names for end user config
60 const char * const SyncMLEncodingNames[numSyncMLEncodings] = {
68 // SyncML encoding names for MIME type
69 const char * const SyncMLEncodingMIMENames[numSyncMLEncodings] = {
71 SYNCML_ENCODING_WBXML,
76 #if !defined(HARDCODED_CONFIG) || defined(ENGINEINTERFACE_SUPPORT)
78 // platform string names for accessing them as config variables
79 const char * const PlatformStringNames[numPlatformStrings] = {
80 "platformvers", // version string of the current platform
81 "globcfg_path", // global system-wide config path (such as C:\Windows or /etc)
82 "loccfg_path", // local config path (such as exedir or user's dir)
83 "defout_path", // default path to writable directory to write logs and other output by default
84 "temp_path", // path where we can write temp files
85 "exedir_path", // path to directory where executable resides
86 "userdir_path", // path to the user's home directory for user-visible documents and files
87 "appdata_path", // path to the user's preference directory for this application
88 "prefs_path", // path to directory where all application prefs reside (not just mine)
89 "device_uri", // URI of the device (as from getDeviceInfo)
90 "device_name", // Name of the device (as from getDeviceInfo)
91 "user_name", // Name of the currently logged in user
97 #ifdef ENGINEINTERFACE_SUPPORT
99 #ifdef DIRECT_APPBASE_GLOBALACCESS
100 // Only for old-style targets that still use a global anchor
102 #ifdef ENGINE_LIBRARY
103 #error "Engine Library may NOT access appBase via global anchor any more!"
107 // With enginemodulebase support, the global anchor is the enginebase module,
108 // not syncappbase itself.
110 #define GET_SYNCAPPBASE (((TEngineInterface *)sysync_glob_anchor())->getSyncAppBase())
112 // get access to existing Sync app base object, NULL if none (i.e. if no TEngineInterface)
113 TSyncAppBase *getExistingSyncAppBase(void)
115 TEngineInterface *eng = (TEngineInterface *)sysync_glob_anchor();
116 return eng ? eng->getSyncAppBase() : NULL;
117 } // getExistingSyncAppBase
119 // global function, returns pointer to (singular) app base
120 // object. With EngineInterface, this is ALWAYS a member of
121 // TEngineInterface, so we create the global engineinterface if we don't have it
123 TSyncAppBase *getSyncAppBase(void)
125 TSyncAppBase *appBase = getExistingSyncAppBase();
126 if (appBase) return appBase;
127 // no appBase yet, we must create and anchor the TEngineInterface
129 ENGINE_IF_CLASS *engine = sysync::newClientEngine();
131 ENGINE_IF_CLASS *engine = sysync::newServerEngine();
133 // we must init the engine to trigger creation of the appbase!
134 if (engine) engine->Init();
135 return GET_SYNCAPPBASE;
138 TEngineInterface *getEngineInterface(void)
140 return (TEngineInterface *)sysync_glob_anchor();
141 } // getEngineInterface
143 // free Sync Session Dispatcher
144 void freeSyncAppBase(void)
146 TEngineInterface *eng = getEngineInterface();
148 // kills interface, and also kills syncappbase in the process
153 #endif // DIRECT_APPBASE_GLOBALACCESS
156 #else // ENGINEINTERFACE_SUPPORT
158 // Old style without enginemodulebase: the global anchor is syncappbase
160 #define GET_SYNCAPPBASE ((TSyncAppBase *)sysync_glob_anchor())
163 // global function, returns pointer to (singular) app base
164 // object. If not yet existing, a new app base is created
165 TSyncAppBase *getSyncAppBase(void)
167 if (!sysync_glob_anchor()) {
168 // no dispatcher exists, create new one
169 // (using function which will create derived app
170 // specific dispatcher)
171 sysync_glob_setanchor(newSyncAppBase());
173 // dispatcher now exists, use it
174 return GET_SYNCAPPBASE;
178 // get access to existing Sync app base object, NULL if none
179 TSyncAppBase *getExistingSyncAppBase(void)
181 return GET_SYNCAPPBASE;
182 } // getExistingSyncAppBase
185 // free Sync Session Dispatcher
186 void freeSyncAppBase(void)
188 if (sysync_glob_anchor()) {
189 // object exists, kill it now
190 delete GET_SYNCAPPBASE;
191 sysync_glob_setanchor(NULL);
195 #endif // not ENGINEINTERFACE_SUPPORT
200 // static routines for accessing appbase logs from UI_Call_In/DB_Callback
202 extern "C" void AppBaseLogDebugPuts(void *aCallbackRef, const char *aText)
205 POBJDEBUGPUTSX(static_cast<TSyncAppBase *>(aCallbackRef),DBG_DBAPI+DBG_PLUGIN,aText);
207 } // AppBaseLogDebugPuts
210 extern "C" void AppBaseLogDebugExotic(void *aCallbackRef, const char *aText)
213 POBJDEBUGPUTSX(static_cast<TSyncAppBase *>(aCallbackRef),DBG_DBAPI+DBG_PLUGIN+DBG_EXOTIC,aText);
215 } // AppBaseLogDebugExotic
218 extern "C" void AppBaseLogDebugBlock(void *aCallbackRef, const char *aTag, const char *aDesc, const char *aAttrText )
221 bool collapsed=false;
222 if (aTag && aTag[0]=='-') { aTag++; collapsed=true; }
223 static_cast<TSyncAppBase *>(aCallbackRef)->getDbgLogger()->DebugOpenBlock(aTag,aDesc,collapsed,"%s",aAttrText);
225 } // AppBaseLogDebugBlock
228 extern "C" void AppBaseLogDebugEndBlock(void *aCallbackRef, const char *aTag)
231 if (aTag && aTag[0]=='-') aTag++;
232 static_cast<TSyncAppBase *>(aCallbackRef)->getDbgLogger()->DebugCloseBlock(aTag);
234 } // AppBaseLogDebugEndBlock
237 extern "C" void AppBaseLogDebugEndThread(void *aCallbackRef)
240 static_cast<TSyncAppBase *>(aCallbackRef)->getDbgLogger()->DebugThreadOutputDone(true); // remove thread record for global threads
242 } // AppBaseLogDebugEndThread
247 // root config constructor
248 TRootConfig::TRootConfig(TSyncAppBase *aSyncAppBaseP) :
249 TRootConfigElement(aSyncAppBaseP),
252 fDatatypesConfigP(NULL)
253 #ifdef SCRIPT_SUPPORT
254 , fScriptConfigP(NULL)
257 , fDebugConfig("debug",this) // init static debug config member
260 // config date is unknown so far
262 #ifndef HARDCODED_CONFIG
263 // string for identifying config file in logs
264 fConfigIDString="<none>";
266 } // TRootConfig::TRootConfig
269 TRootConfig::~TRootConfig()
272 if (fAgentConfigP) delete fAgentConfigP;
273 if (fDatatypesConfigP) delete fDatatypesConfigP;
274 if (fCommConfigP) delete fCommConfigP;
275 #ifdef SCRIPT_SUPPORT
276 if (fScriptConfigP) delete fScriptConfigP;
278 } // TRootConfig::~TRootConfig
281 void TRootConfig::clear(void)
283 // root config variables
284 // - init PUT suppression
285 fNeverPutDevinf=false;
286 // - init message size
287 fLocalMaxMsgSize=DEFAULT_MAXMSGSIZE;
288 fLocalMaxObjSize=DEFAULT_MAXOBJSIZE;
289 // - system time zone
290 fSystemTimeContext=TCTX_SYSTEM; // default to automatic detection
291 #ifdef ENGINEINTERFACE_SUPPORT
292 // - default identification
296 // - init device limit
297 #ifdef CUSTOMIZABLE_DEVICES_LIMIT
298 fConcurrentDeviceLimit=CONCURRENT_DEVICES_LIMIT;
300 // remove, (re-)create and clear linked config branches (debug last to allow dbg output while clearing)
301 // - global scripting config
302 #ifdef SCRIPT_SUPPORT
303 if (fScriptConfigP) delete fScriptConfigP;
304 fScriptConfigP= new TScriptConfig(this);
305 if (fScriptConfigP) fScriptConfigP->clear();
307 // - communication config
308 if (fCommConfigP) delete fCommConfigP;
310 if (fCommConfigP) fCommConfigP->clear();
311 // - datatypes registry config
312 if (fDatatypesConfigP) delete fDatatypesConfigP;
313 installDatatypesConfig();
314 if (fDatatypesConfigP) fDatatypesConfigP->clear();
316 if (fAgentConfigP) delete fAgentConfigP;
317 installAgentConfig();
318 if (fAgentConfigP) fAgentConfigP->clear();
319 // clear embedded debug config (as the last action)
321 fDebugConfig.clear();
325 } // TRootConfig::clear
328 // save app state (such as settings in datastore configs etc.)
329 void TRootConfig::saveAppState(void)
331 if (fAgentConfigP) fAgentConfigP->saveAppState();
332 if (fDatatypesConfigP) fDatatypesConfigP->saveAppState();
333 if (fCommConfigP) fCommConfigP->saveAppState();
334 } // TRootConfig::saveAppState
337 // MUST be called after creating config to load (or pre-load) variable parts of config
338 // such as binfile profiles. If aDoLoose==false, situations, where existing config
339 // is detected but cannot be re-used will return an error. With aDoLoose==true, config
340 // files etc. are created even if it means a loss of data.
341 localstatus TRootConfig::loadVarConfig(bool aDoLoose)
343 // only agent may load variable config
345 return fAgentConfigP->loadVarConfig(aDoLoose);
347 return LOCERR_NOCFG; // no config yet
348 } // TRootConfig::loadVarConfig
353 #ifndef HARDCODED_CONFIG
355 // root config element parsing
356 bool TRootConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine)
359 if (strucmp(aElementName,"debug")==0) {
361 // let static TDebugConfig member handle it
362 expectChildParsing(fDebugConfig);
364 ReportError(false,"No debugging features available in this version");
365 expectAll(); // no debug code, simply ignore settings
369 else if (strucmp(aElementName,"configdate")==0)
370 expectTimestamp(fConfigDate);
371 else if (strucmp(aElementName,"configidstring")==0)
372 expectMacroString(fConfigIDString);
374 #ifdef ENGINEINTERFACE_SUPPORT
375 // - product identification (in devInf)
376 if (strucmp(aElementName,"manufacturer")==0)
377 expectMacroString(fMan);
378 else if (strucmp(aElementName,"model")==0)
379 expectMacroString(fMod);
380 else if (strucmp(aElementName,"HardwareVersion")==0)
381 expectMacroString(fHwV);
382 else if (strucmp(aElementName,"FirmwareVersion")==0)
383 expectMacroString(fFwV);
384 else if (strucmp(aElementName,"DeviceType")==0)
385 expectMacroString(fDevTyp);
389 if (strucmp(aElementName,"configvar")==0) {
390 const char *nam = getAttr(aAttributes,"name");
392 return fail("Missing 'name' attribute in 'configvar'");
394 if (!getAttrExpanded(aAttributes,"value",val,false))
395 return fail("Missing 'value' attribute in 'configvar'");
396 getSyncAppBase()->setConfigVar(nam,val.c_str());
400 else if (strucmp(aElementName,"neverputdevinf")==0)
401 expectBool(fNeverPutDevinf);
402 else if (strucmp(aElementName,"maxmsgsize")==0)
403 expectUInt32(fLocalMaxMsgSize);
404 else if (strucmp(aElementName,"maxobjsize")==0)
405 expectUInt32(fLocalMaxObjSize);
406 else if (strucmp(aElementName,"maxconcurrentsessions")==0) {
407 #ifdef CUSTOMIZABLE_DEVICES_LIMIT
408 expectInt32(fConcurrentDeviceLimit);
410 expectAll(); // no configurable limit, simply ignore contents
414 else if (strucmp(aElementName,"definetimezone")==0)
415 expectVTimezone(getSyncAppBase()->getAppZones()); // definition of custom time zone
416 else if (strucmp(aElementName,"systemtimezone")==0)
417 expectTimezone(fSystemTimeContext);
419 else if (strucmp(aElementName,"licensename")==0) {
420 #ifdef SYSER_REGISTRATION
421 expectString(fLicenseName);
423 expectAll(); // simply ignore contents for versions w/o registration
426 else if (strucmp(aElementName,"licensecode")==0) {
427 #ifdef SYSER_REGISTRATION
428 expectString(fLicenseCode);
430 expectAll(); // simply ignore contents for versions w/o registration
433 #ifdef SCRIPT_SUPPORT
434 else if (strucmp(aElementName,"scripting")==0) {
435 // let linked TScriptConfig handle it
436 expectChildParsing(*fScriptConfigP);
440 // Agent: Server or client
442 (IS_CLIENT && strucmp(aElementName,"client")==0) ||
443 (IS_SERVER && strucmp(aElementName,"server")==0)
446 if (!fAgentConfigP) return false;
447 return parseAgentConfig(aAttributes, aLine);
450 else if (strucmp(aElementName,"transport")==0) {
452 if (!fCommConfigP) return false;
453 if (!parseCommConfig(aAttributes, aLine)) {
454 // not a transport we can understand, simply ignore
458 else if (strucmp(aElementName,"datatypes")==0) {
459 // datatypes (type registry) config
460 if (!fDatatypesConfigP) return false;
461 return parseDatatypesConfig(aAttributes, aLine);
469 } // TRootConfig::localStartElement
473 // resolve (finish after all data is parsed)
474 void TRootConfig::localResolve(bool aLastPass)
476 // make sure static debug element is resolved so
477 // eventual debug information created by resolving other
478 // elements go to the correct locations/files
479 // Note: in XML configs, the debug element is resolved immediately
480 // after parsing (has fResolveImmediately set) and will
481 // not be re-resolved here unless the element was not parsed at all.
482 #if defined(SYDEBUG) && !defined(SYSYNC_TOOL)
483 // - for SysyTool, do not resolve here as we don't want to see all of the
484 // DBG blurb on the screen created by resolving the config
485 fDebugConfig.Resolve(aLastPass);
487 // set zone for system if one was defined explicitly
488 if (!TCTX_IS_SYSTEM(fSystemTimeContext) && !TCTX_IS_UNKNOWN(fSystemTimeContext)) {
489 getSyncAppBase()->getAppZones()->predefinedSysTZ = fSystemTimeContext;
490 getSyncAppBase()->getAppZones()->ResetCache(); // make sure next query for SYSTEM tz will get new set zone
493 // MaxMessagesize must have a reasonable size
494 if (fLocalMaxMsgSize<512) {
495 SYSYNC_THROW(TConfigParseException("<maxmsgsize> must be at least 512 bytes"));
497 // make sure we have the registration info vars updated
498 #ifdef APP_CAN_EXPIRE
499 getSyncAppBase()->updateAppExpiry();
500 #elif defined(SYSER_REGISTRATION)
501 getSyncAppBase()->isRegistered();
503 // make sure linked elements are resolved
504 #ifdef SCRIPT_SUPPORT
505 if (fScriptConfigP) fScriptConfigP->Resolve(aLastPass);
507 if (fAgentConfigP) fAgentConfigP->Resolve(aLastPass);
508 if (fDatatypesConfigP) fDatatypesConfigP->Resolve(aLastPass);
509 if (fCommConfigP) fCommConfigP->Resolve(aLastPass);
510 // finally, get rid of macros (all scripts are now read)
511 #ifdef SCRIPT_SUPPORT
512 if (fScriptConfigP && aLastPass) fScriptConfigP->clearmacros();
514 #if defined(SYDEBUG) && defined(SYSYNC_TOOL)
515 // - for SysyTool, resolve now, where resolving dbg output has gone /dev/null already
516 fDebugConfig.Resolve(aLastPass);
518 // try to resolve variable config here, but without forcing new one
520 loadVarConfig(false);
522 } // TRootConfig::localResolve
525 // Base datatype config
528 void TDataTypeConfig::clear(void)
531 fTypeName.erase(); // no type
532 fTypeVersion.erase(); // no version
533 #ifdef ZIPPED_BINDATA_SUPPORT
534 fZippedBindata=false;
535 fZipCompressionLevel=-1; // valid range is 0-9, invalid value will select Z_DEFAULT_COMPRESSION
537 fBinaryParts=false; // no binary parts
538 fUseUTF16=false; // no UTF-16/Unicode translation
539 fMSBFirst=false; // default to Intel byte order for UTF16
542 } // TMIMEDirTypeConfig::clear
545 #ifdef CONFIGURABLE_TYPE_SUPPORT
547 // config element parsing
548 bool TDataTypeConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine)
550 // checking the elements
551 if (strucmp(aElementName,"typestring")==0)
552 expectString(fTypeName);
553 else if (strucmp(aElementName,"versionstring")==0)
554 expectString(fTypeVersion);
555 else if (strucmp(aElementName,"binaryparts")==0)
556 expectBool(fBinaryParts);
557 #ifdef ZIPPED_BINDATA_SUPPORT
558 else if (strucmp(aElementName,"zippedbindata")==0)
559 expectBool(fZippedBindata);
560 else if (strucmp(aElementName,"zipcompressionlevel")==0)
561 expectInt16(fZipCompressionLevel);
563 else if (strucmp(aElementName,"unicodedata")==0)
564 expectBool(fUseUTF16);
565 else if (strucmp(aElementName,"bigendian")==0)
566 expectBool(fMSBFirst);
569 return false; // base class is TConfigElement
572 } // TDataTypeConfig::localStartElement
576 void TDataTypeConfig::localResolve(bool aLastPass)
580 // Note: type strings might be set explicitly or implicitly by derived classes
581 // Note2: all types must have a version (SCTS will fail without). For example
582 // Starfish's text/plain notes have Version "1.0"
583 if (fTypeName.empty() || fTypeVersion.empty() )
584 SYSYNC_THROW(TConfigParseException("datatype must have non-empty 'typestring' and 'versionstring'"));
586 } // TDataTypeConfig::localResolve
594 TDatatypesConfig::TDatatypesConfig(const char* aName, TConfigElement *aParentElement) :
595 TConfigElement(aName,aParentElement)
598 } // TDatatypesConfig::TDatatypesConfig
601 TDatatypesConfig::~TDatatypesConfig()
604 } // TDatatypesConfig::~TDatatypesConfig
608 void TDatatypesConfig::clear(void)
611 TDataTypesList::iterator pos;
612 for(pos=fDataTypesList.begin();pos!=fDataTypesList.end();pos++)
614 fDataTypesList.clear();
617 } // TDatatypesConfig::clear
620 TDataTypeConfig *TDatatypesConfig::getDataType(const char *aName)
622 TDataTypesList::iterator pos;
623 for(pos=fDataTypesList.begin();pos!=fDataTypesList.end();pos++) {
624 if (strucmp((*pos)->getName(),aName)==0) {
629 return NULL; // not found
630 } // TDatatypesConfig::getDataType
633 #ifdef CONFIGURABLE_TYPE_SUPPORT
635 // config element parsing
636 bool TDatatypesConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine)
638 // checking the elements
639 if (strucmp(aElementName,"datatype")==0) {
640 // definition of a new data type
642 const char *nam = getAttr(aAttributes,"name");
644 return fail("Missing 'name' attribute in 'datatype'");
646 const char *basetype = getAttr(aAttributes,"basetype");
648 return fail("Missing 'basetype' attribute in 'datatype'");
649 // - call global function to get correct TDataTypeConfig derived object
650 TDataTypeConfig *datatypeP = getSyncAppBase()->getRootConfig()->newDataTypeConfig(nam,basetype,this);
652 return fail("Unknown basetype '%s'",basetype);
654 fDataTypesList.push_back(datatypeP);
655 // - let element handle parsing
656 expectChildParsing(*datatypeP);
660 return inherited::localStartElement(aElementName,aAttributes,aLine);
663 } // TDatatypesConfig::localStartElement
669 void TDatatypesConfig::localResolve(bool aLastPass)
671 // resolve all types in list
672 TDataTypesList::iterator pos;
673 for(pos=fDataTypesList.begin();pos!=fDataTypesList.end();pos++)
674 (*pos)->Resolve(aLastPass);
676 inherited::localResolve(aLastPass);
677 } // TDatatypesConfig::localResolve
683 // debug config constructor
684 TDebugConfig::TDebugConfig(const char *aElementName, TConfigElement *aParentElementP) :
685 TConfigElement(aElementName,aParentElementP)
687 // do not call clear(), because this is virtual!
688 } // TDebugConfig::TDebugConfig
691 void TDebugConfig::clear(void)
694 fGlobalDbgLoggerOptions.clear(); // set logger options to defaults
695 fSessionDbgLoggerOptions.clear(); // set logger options to defaults
696 fDebug = DEFAULT_DEBUG; // if <>0 (and #defined SYDEBUG), debug output is generated, value is used as mask
697 fMsgDump = DEFAULT_MSGDUMP; // if set (and #defined MSGDUMP), messages sent and received are logged;
698 fSingleGlobLog = false; // create a separate global log per app start
699 fSingleSessionLog = false; // create separate session logs
700 fTimedSessionLogNames = true; // add session start time into file name
701 fLogSessionsToGlobal = false; // use separate file(s) for session log
702 fXMLtranslate = DEFAULT_XMLTRANSLATE; // if set, communication will be translated to XML and logged
703 fSimMsgRead = DEFAULT_SIMMSGREAD; // if set (and #defined SIMMSGREAD), simulated input with "i_" prefixed incoming messages are supported
704 fGlobalDebugLogs = DEFAULT_GLOBALDEBUGLOGS;
705 fSessionDebugLogs = DEFAULT_SESSIONDEBUGLOGS;
706 if (getPlatformString(pfs_defout_path,fDebugInfoPath))
707 makeOSDirPath(fDebugInfoPath);
709 fDebugInfoPath.erase(); // none
710 // make sure that defaults are applied a first time NOW, BEFORE reading first config
713 // and make sure final resolve takes place early when <debug> element finishes parsing
714 // (but not for SYSYNC_TOOL, where we want no debug output at all during config read & resolve!)
715 fResolveImmediately = true;
719 } // TDebugConfig::clear
722 // resolve (finish after all data is parsed)
723 void TDebugConfig::localResolve(bool aLastPass)
728 #ifndef HARDCODED_CONFIG
729 // XML config - user options settings are parsed into fSessionDbgLoggerOptions
730 // - by default, global logging has same options as configured for session...
731 fGlobalDbgLoggerOptions = fSessionDbgLoggerOptions;
732 // ...but we have a few hard-coded things for global logging:
733 #ifdef MULTITHREAD_PIPESERVER
734 // - for pipe server, global logs should be per-thread
735 fGlobalDbgLoggerOptions.fFlushMode=dbgflush_flush; // flush every log line
736 fGlobalDbgLoggerOptions.fSubThreadMode=dbgsubthread_separate; // separate per thread
737 fGlobalDbgLoggerOptions.fTimestampForAll=true; // timestamp for every message
740 // - global log for ISAPI/XPT *Servers* is always in openclose mode (possibly multiple processes accessing it)
741 fGlobalDbgLoggerOptions.fFlushMode=dbgflush_openclose; // open and close for every log line
743 fGlobalDbgLoggerOptions.fSubThreadMode=dbgsubthread_linemix; // mix in one file
744 #ifdef MULTI_THREAD_SUPPORT
745 fGlobalDbgLoggerOptions.fThreadIDForAll=true; // thread ID for each message
749 // initialize global debug logging options
750 getSyncAppBase()->fAppLogger.setMask(fDebug); // set initial debug mask from config
751 getSyncAppBase()->fAppLogger.setEnabled(fGlobalDebugLogs); // init from config
752 getSyncAppBase()->fAppLogger.setOptions(&fGlobalDbgLoggerOptions);
753 // install outputter, but only if not yet installed in an earlier invocation. We only want ONE log per engine instantiation!
754 if (!getSyncAppBase()->fAppLogger.outputEstablished()) {
755 getSyncAppBase()->fAppLogger.installOutput(getSyncAppBase()->newDbgOutputter(true)); // install the output object (and pass ownership!)
756 getSyncAppBase()->fAppLogger.setDebugPath(fDebugInfoPath.c_str()); // global log all in one file
757 getSyncAppBase()->fAppLogger.appendToDebugPath(fGlobalDbgLoggerOptions.fBasename.empty() ?
759 fGlobalDbgLoggerOptions.fBasename.c_str());
760 if (fSingleGlobLog) {
761 // One single log - in this case, we MUST append to current log
762 fGlobalDbgLoggerOptions.fAppend=true;
765 // create a new global log for each app start
766 getSyncAppBase()->fAppLogger.appendToDebugPath("_");
768 TimestampToISO8601Str(t, getSyncAppBase()->getSystemNowAs(TCTX_UTC), TCTX_UTC, false, false);
769 getSyncAppBase()->fAppLogger.appendToDebugPath(t.c_str());
770 getSyncAppBase()->fAppLogger.appendToDebugPath("_global");
773 // define this as the main thread
774 getSyncAppBase()->fAppLogger.DebugDefineMainThread();
777 }; // TDebugConfig::localResolve
780 #ifndef HARDCODED_CONFIG
782 // debug option (combination) names
783 const char * const debugOptionNames[numDebugOptions] = {
784 // current categories
803 // flags mostly (not always) used in combination with some of the basic categories
830 const uInt32 debugOptionMasks[numDebugOptions] = {
831 // current categories
850 // flags mostly (not always) used in combination with some of the basic categories
868 DBG_RTK_SML+DBG_RTK_XPT,
870 // old names that are mapped to new masks
871 DBG_DATA, // formerly: DBG_ITEMS
872 DBG_PROTO, // formerly: DBG_CMD
873 DBG_REMOTEINFO, // formerly: DBG_DEVINF
874 DBG_PARSE+DBG_GEN // formerly: DBG_DATACONV
879 uInt32 TDebugConfig::str2DebugMask(const char **aAttributes)
881 expectEmpty(); // enable may not have content
883 const char* dbgopt = getAttr(aAttributes,"option");
885 ReportError(false,"debug enable/disable, missing 'option' attribute");
888 if (StrToEnum(debugOptionNames,numDebugOptions,k,dbgopt)) {
889 return debugOptionMasks[k];
891 ReportError(false,"unknown debug option '%s'",dbgopt);
893 } // TDebugConfig::str2DebugMask
896 // debug config element parsing
897 bool TDebugConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine)
899 // checking the elements
900 if (strucmp(aElementName,"mask")==0)
901 expectUInt32(fDebug);
902 else if (strucmp(aElementName,"enable")==0)
903 fDebug = fDebug | str2DebugMask(aAttributes);
904 else if (strucmp(aElementName,"disable")==0)
905 fDebug = fDebug & ~str2DebugMask(aAttributes);
906 else if (strucmp(aElementName,"logpath")==0)
907 expectPath(fDebugInfoPath);
908 else if (strucmp(aElementName,"msgdump")==0)
909 expectBool(fMsgDump);
910 else if (strucmp(aElementName,"xmltranslate")==0)
911 expectBool(fXMLtranslate);
912 else if (strucmp(aElementName,"simmsgread")==0)
913 expectBool(fSimMsgRead);
914 else if (strucmp(aElementName,"sessionlogs")==0)
915 expectBool(fSessionDebugLogs);
916 else if (strucmp(aElementName,"globallogs")==0)
917 expectBool(fGlobalDebugLogs);
918 // options for TDebugLogger
919 else if (strucmp(aElementName,"logformat")==0)
920 expectEnum(sizeof(fSessionDbgLoggerOptions.fOutputFormat),&fSessionDbgLoggerOptions.fOutputFormat,DbgOutFormatNames,numDbgOutFormats);
921 else if (strucmp(aElementName,"folding")==0)
922 expectEnum(sizeof(fSessionDbgLoggerOptions.fFoldingMode),&fSessionDbgLoggerOptions.fFoldingMode,DbgFoldingModeNames,numDbgFoldingModes);
923 else if (strucmp(aElementName,"indentstring")==0)
924 expectCString(fSessionDbgLoggerOptions.fIndentString);
925 else if (strucmp(aElementName,"fileprefix")==0)
926 expectRawString(fSessionDbgLoggerOptions.fCustomPrefix);
927 else if (strucmp(aElementName,"filesuffix")==0)
928 expectRawString(fSessionDbgLoggerOptions.fCustomSuffix);
929 else if (strucmp(aElementName,"filename")==0)
930 expectRawString(fSessionDbgLoggerOptions.fBasename);
931 else if (strucmp(aElementName,"logflushmode")==0)
932 expectEnum(sizeof(fSessionDbgLoggerOptions.fFlushMode),&fSessionDbgLoggerOptions.fFlushMode,DbgFlushModeNames,numDbgFlushModes);
933 else if (strucmp(aElementName,"appendtoexisting")==0)
934 expectBool(fSessionDbgLoggerOptions.fAppend);
935 else if (strucmp(aElementName,"timestamp")==0)
936 expectBool(fSessionDbgLoggerOptions.fTimestampStructure);
937 else if (strucmp(aElementName,"timestampall")==0)
938 expectBool(fSessionDbgLoggerOptions.fTimestampForAll);
939 else if (strucmp(aElementName,"showthreadid")==0)
940 expectBool(fSessionDbgLoggerOptions.fThreadIDForAll);
941 else if (strucmp(aElementName,"subthreadmode")==0)
942 expectEnum(sizeof(fSessionDbgLoggerOptions.fSubThreadMode),&fSessionDbgLoggerOptions.fSubThreadMode,DbgSubthreadModeNames,numDbgSubthreadModes);
943 else if (strucmp(aElementName,"subthreadbuffersize")==0)
944 expectUInt32(fSessionDbgLoggerOptions.fSubThreadBufferMax);
945 else if (strucmp(aElementName,"singlegloballog")==0)
946 expectBool(fSingleGlobLog);
947 else if (strucmp(aElementName,"singlesessionlog")==0)
948 expectBool(fSingleSessionLog);
949 else if (strucmp(aElementName,"timedsessionlognames")==0)
950 expectBool(fTimedSessionLogNames);
951 else if (strucmp(aElementName,"logsessionstoglobal")==0)
952 expectBool(fLogSessionsToGlobal);
954 return false; // invalid element
956 } // TDebugConfig::localStartElement
962 #ifndef ENGINE_LIBRARY
964 // in engine library, all output must be in context of an engineInterface/appBase
966 // Debug output routines
968 // If a fDebugLogOutputFunc callback is defined,
969 // it will be used for output, otherwise global gDebugLogPath
970 // file will be written
972 uInt32 getDbgMask(void)
975 TSyncAppBase *appBase = getExistingSyncAppBase();
976 if (!appBase) return 0; // no appbase -> no debug
977 return appBase->getDbgMask();
984 TDebugLogger *getDbgLogger(void)
987 TSyncAppBase *appBase = getExistingSyncAppBase();
988 if (!appBase) return NULL; // no appbase -> no debuglogger
989 return appBase->getDbgLogger();
996 // non-class DebugPuts
997 void DebugPuts(uInt32 mask, const char *text)
1000 // use global debug channel of appBase for non-object-context output
1001 TSyncAppBase *appBase = getExistingSyncAppBase();
1002 if (!appBase || appBase->getDbgMask()==0) return; // no appbase or debug off -> no output
1003 TDebugLogger *dbgLogger = appBase->getDbgLogger();
1004 if (!dbgLogger) return;
1005 dbgLogger->DebugPuts(mask,text,0,false);
1010 // non-class print to debug channel
1011 void DebugVPrintf(uInt32 mask, const char *format, va_list args)
1014 // use global debug channel of appBase for non-object-context output
1015 TSyncAppBase *appBase = getExistingSyncAppBase();
1016 if (!appBase || appBase->getDbgMask()==0) return; // no appbase or debug off -> no output
1017 TDebugLogger *dbgLogger = appBase->getDbgLogger();
1018 if (!dbgLogger) return;
1019 dbgLogger->DebugVPrintf(mask,format,args);
1024 // non-class print to debug channel
1025 void DebugPrintf(const char *text, ...)
1030 va_start(args, text);
1031 DebugVPrintf(DBG_TRANSP, text,args);
1033 } // if (PDEBUGMASK)
1038 void smlLibPrint(const char *text, ...)
1042 va_start(args, text);
1043 DebugVPrintf(DBG_RTK_SML,text,args);
1049 void smlLibVprintf(const char *format, va_list va)
1052 DebugVPrintf(DBG_RTK_SML,format,va);
1057 // entry point for SyncML-Toolkit with
1058 // #define TRACE_TO_STDOUT
1059 void localOutput(const char *aFormat, va_list aArgs)
1062 NCDEBUGVPRINTFX(DBG_RTK_SML,aFormat,aArgs);
1067 #endif // not ENGINE_LIBRARY
1070 // Console printout. Only enabled when defined(CONSOLEINFO)
1072 // non-class print to console
1073 void ConsolePrintf(const char *text, ...)
1076 const sInt16 maxmsglen=1024;
1077 char msg[maxmsglen];
1081 va_start(args, text);
1082 // assemble the message string
1083 vsnprintf(msg, maxmsglen, text, args);
1088 } // sysyncConsolePrintf
1091 // non-class Console output
1092 void ConsolePuts(const char *text)
1095 // show on app's console equivalent
1096 AppConsolePuts(text);
1097 #endif // console enabled
1098 } // sysyncConsolePuts
1106 /* SyncML toolkit callback function declarations */
1109 /* message callbacks */
1110 static Ret_t smlStartMessageCallback(InstanceID_t id, VoidPtr_t userData, SmlSyncHdrPtr_t pContent);
1111 static Ret_t smlEndMessageCallback(InstanceID_t id, VoidPtr_t userData, Boolean_t final);
1112 /* grouping commands */
1113 static Ret_t smlStartSyncCallback(InstanceID_t id, VoidPtr_t userData, SmlSyncPtr_t pContent);
1114 static Ret_t smlEndSyncCallback(InstanceID_t id, VoidPtr_t userData);
1115 #ifdef ATOMIC_RECEIVE /* these callbacks are NOT included in the Toolkit lite version */
1116 static Ret_t smlStartAtomicCallback(InstanceID_t id, VoidPtr_t userData, SmlAtomicPtr_t pContent);
1117 static Ret_t smlEndAtomicCallback(InstanceID_t id, VoidPtr_t userData);
1119 #ifdef SEQUENCE_RECEIVE
1120 static Ret_t smlStartSequenceCallback(InstanceID_t id, VoidPtr_t userData, SmlSequencePtr_t pContent);
1121 static Ret_t smlEndSequenceCallback(InstanceID_t id, VoidPtr_t userData);
1124 static Ret_t smlAddCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlAddPtr_t pContent);
1125 static Ret_t smlAlertCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlAlertPtr_t pContent);
1126 static Ret_t smlDeleteCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlDeletePtr_t pContent);
1127 static Ret_t smlGetCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlGetPtr_t pContent);
1128 static Ret_t smlPutCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlPutPtr_t pContent);
1130 static Ret_t smlMapCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlMapPtr_t pContent);
1132 #ifdef RESULT_RECEIVE
1133 static Ret_t smlResultsCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlResultsPtr_t pContent);
1135 static Ret_t smlStatusCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlStatusPtr_t pContent);
1136 static Ret_t smlReplaceCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlReplacePtr_t pContent);
1138 #ifdef COPY_RECEIVE /* these callbacks are NOT included in the Toolkit lite version */
1139 static Ret_t smlCopyCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlCopyPtr_t param);
1141 static Ret_t smlMoveCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlMovePtr_t param);
1143 static Ret_t smlExecCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlExecPtr_t pContent);
1145 #ifdef SEARCH_RECEIVE
1146 static Ret_t smlSearchCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlSearchPtr_t pContent);
1148 /* Other Callbacks */
1149 static Ret_t smlHandleErrorCallback(InstanceID_t id, VoidPtr_t userData);
1150 static Ret_t smlTransmitChunkCallback(InstanceID_t id, VoidPtr_t userData);
1152 /* print callback */
1153 void smlPrintCallback(String_t outputString);
1154 } // extern "C" declaration
1158 TSyncAppBase::TSyncAppBase() :
1163 #ifdef PROGRESS_EVENTS
1164 fProgressEventFunc(NULL),
1166 #ifdef ENGINEINTERFACE_SUPPORT
1167 fEngineInterfaceP(NULL),
1169 fMasterPointer(NULL),
1171 fApiInterModuleContext(0)
1172 // reset all callbacks
1175 ,fAppLogger(&fAppZones)
1178 // at the moment of creation, this is now the SyncAppBase
1179 // (set it here already to allow getSyncAppBase() from derived constructors)
1180 #ifdef ENGINEINTERFACE_SUPPORT
1181 #ifdef DIRECT_APPBASE_GLOBALACCESS
1182 getEngineInterface()->setSyncAppBase(this); // set the link so getSyncAppBase() via EngineInterface works immediately
1185 #ifdef ENGINE_LIBRARY
1186 #error "DIRECT_APPBASE_GLOBALACCESS is not allowed with ENGINE_LIBRARY"
1188 sysync_glob_setanchor(this);
1190 #ifdef MD5_TEST_FUNCS
1195 TP_START(fTPInfo,TP_general);
1196 #ifdef EXPIRES_AFTER_DATE
1197 // - get current time
1199 lineartime2date(getSystemNowAs(TCTX_UTC),&y,&m,&d);
1200 // - calculate scrambled version thereof
1202 ((sInt32)y-1720l)*12l*42l+
1206 #define SCRAMBLED_EXPIRY_VALUE \
1208 (EXPIRY_MONTH-1)*42+ \
1209 (EXPIRY_YEAR-1720)*12*42
1212 #ifdef APP_CAN_EXPIRE
1213 fAppExpiryStatus=LOCERR_OK; // do not compare here, would be too easy
1215 #if defined(SYDEBUG) && defined(HARDCODED_CONFIG)
1216 fConfigFilePath="<hardcoded config>";
1218 #ifdef SYSER_REGISTRATION
1219 // make sure that license is standard (no phone home, no expiry) in case there is NO license at all
1225 // TODO: put this somewhere where the return code can be checked and
1226 // reported to the user of TSyncAppBase
1227 fAppZones.initialize();
1233 lineartime_t stdStart;
1234 lineartime_t dstStart;
1235 bool ok = getSystemTimeZone(zoneName, stdBias, dstBias, stdStart, dstStart);
1236 printf("getSystemTimeZone: name=%s, stdBias=%hd, dstBias=%hd, stdStart=%lld, dstStart=%lld\n", zoneName.c_str(), stdBias, dstBias, stdStart, dstStart);
1239 } // TSyncAppBase::TSyncAppBase
1243 TSyncAppBase::~TSyncAppBase()
1245 fDeleting=true; // flag deletion to block calling critical (virtual) methods
1246 #if !defined(ENGINEINTERFACE_SUPPORT) || defined(DIRECT_APPBASE_GLOBALACCESS)
1247 sysync_glob_setanchor(NULL);
1249 // stop and show profiling info
1251 #ifdef TIME_PROFILING
1252 if (PDEBUGMASK & DBG_PROFILE) {
1254 PDEBUGPRINTFX(DBG_PROFILE,("Non-Session CPU usage statistics: (system/user)"));
1256 for (i=0; i<numTPTypes; i++) {
1257 PNCDEBUGPRINTFX(DBG_PROFILE,(
1258 "- %-20s : (%10ld/%10ld) ms",
1260 TP_GETSYSTEMMS(fTPInfo,(TTP_Types)i),
1261 TP_GETUSERMS(fTPInfo,(TTP_Types)i)
1265 PNCDEBUGPRINTFX(DBG_PROFILE,(
1266 "- %-20s : (%10ld/%10ld) ms",
1268 TP_GETTOTALSYSTEMMS(fTPInfo),
1269 TP_GETTOTALUSERMS(fTPInfo)
1273 // delete the config now
1275 // - but first make sure applogger does not refer to it any more
1276 fAppLogger.setOptions(NULL);
1279 if (fConfigP) delete fConfigP;
1280 } // TSyncAppBase::~TSyncAppBase
1284 #ifndef HARDCODED_CONFIG
1286 // get config variables
1287 bool TSyncAppBase::getConfigVar(cAppCharP aVarName, string &aValue)
1289 // look up in user-defined variables first
1290 TStringToStringMap::iterator pos = fConfigVars.find(aVarName);
1291 if (pos!=fConfigVars.end()) {
1292 aValue = (*pos).second;
1293 return true; // found in user defined vars
1295 // check some globals
1296 if (strucmp(aVarName,"version")==0) {
1298 aValue = SYSYNC_FULL_VERSION_STRING;
1301 if (strucmp(aVarName,"hexversion")==0) {
1302 // string-comparable version as 8-digit hex MMmmrrbb (Major, minor, rev, build)
1303 StringObjPrintf(aValue,"%02X%02X%02X%02X",SYSYNC_VERSION_MAJOR,SYSYNC_VERSION_MINOR,SYSYNC_SUBVERSION,SYSYNC_BUILDNUMBER);
1306 if (strucmp(aVarName,"manufacturer")==0) {
1307 aValue = getManufacturer();
1310 if (strucmp(aVarName,"model")==0) {
1311 aValue = getModel();
1314 if (strucmp(aVarName,"variant")==0) {
1316 #if SYSER_VARIANT_CODE==SYSER_VARIANT_STD
1318 #elif SYSER_VARIANT_CODE==SYSER_VARIANT_PRO
1320 #elif SYSER_VARIANT_CODE==SYSER_VARIANT_CUSTOM
1322 #elif SYSER_VARIANT_CODE==SYSER_VARIANT_DEMO
1329 if (strucmp(aVarName,"productcode")==0) {
1330 #ifdef SYSER_PRODUCT_CODE
1331 StringObjPrintf(aValue,"%d",SYSER_PRODUCT_CODE);
1337 if (strucmp(aVarName,"extraid")==0) {
1338 #ifdef SYSER_PRODUCT_CODE
1339 StringObjPrintf(aValue,"%d",SYSER_EXTRA_ID);
1345 if (strucmp(aVarName,"platformname")==0) {
1346 aValue = SYSYNC_PLATFORM_NAME;
1349 // look up in platform strings
1351 for (plsId=0; plsId<numPlatformStrings; plsId++) {
1352 if (strucmp(aVarName,PlatformStringNames[plsId])==0) {
1353 // get platform string
1354 return getPlatformString((TPlatformStringID)plsId,aValue);
1359 } // TSyncAppBase::getConfigVar
1362 // set config variable
1363 bool TSyncAppBase::setConfigVar(cAppCharP aVarName, cAppCharP aNewValue)
1365 // set user-defined config variable
1366 fConfigVars[aVarName] = aNewValue;
1368 } // TSyncAppBase::setConfigVar
1371 // expand config vars in string
1372 bool TSyncAppBase::expandConfigVars(string &aString, sInt8 aCfgVarExp, TConfigElement *aCfgElement, cAppCharP aElementName)
1374 string::size_type n,n2;
1376 if (aCfgVarExp<=0 || aString.empty()) return true; // no expansion
1377 if (aCfgElement && !aElementName) aElementName="*Unknown*";
1380 n = aString.find("$(",n);
1381 if (n==string::npos)
1382 break; // no more macros
1383 // found macro name start - now search end
1384 n+=2; // position after $( lead-in
1385 n2 = aString.find(")",n);
1386 if (n2!=string::npos) {
1389 vn.assign(aString,n,n2-n); // name
1390 if (getConfigVar(vn.c_str(),vv)) {
1391 if (aCfgVarExp==2) {
1392 // check for recursion loop
1393 vn.insert(0,"$("); vn.append(")");
1394 if (vv.find(vn,0)!=string::npos) {
1395 if (aCfgElement) aCfgElement->ReportError(true,"Recursive config variable $(%s) in <%s>",vn.c_str(),aElementName);
1396 n=n2+1; // do not expand
1400 // found value - substitute
1401 n-=2; // substitute beginning with leadin
1402 n2+=1; // include closing paranthesis
1403 aString.replace(n,n2-n,vv);
1405 // do not allow recursive macro expansion
1406 n+=vv.size(); // continue searching past substituted chars
1410 // not found - leave macro as-is
1411 if (aCfgElement) aCfgElement->ReportError(false,"Undefined config variable $(%s) in <%s>",vn.c_str(),aElementName);
1412 n=n2+1; // continue search after closing paranthesis
1416 if (aCfgElement) aCfgElement->ReportError(false,"Unterminated $(xxx)-style config variable in <%s>",aElementName);
1420 } // TSyncAppBase::expandConfigVars
1422 #endif // not HARDCODED_CONFIG
1426 #ifdef HARDCODED_CONFIG
1429 localstatus TSyncAppBase::initHardcodedConfig(void)
1433 // initialize for receiving new config
1435 // now call initializer in derived root config
1436 err=fConfigP->createHardcodedConfig();
1437 if (err!=LOCERR_OK) return err;
1438 // make sure it gets all resolved
1439 fConfigP->ResolveAll();
1442 } // TSyncAppBase::initHardcodedConfig
1448 // report config errors
1449 void TSyncAppBase::ConferrPrintf(const char *text, ...)
1451 const sInt16 maxmsglen=1024;
1452 char msg[maxmsglen];
1456 va_start(args, text);
1457 // assemble the message string
1458 vsnprintf(msg, maxmsglen, text, args);
1460 // output config errors
1462 } // TSyncAppBase::ConferrPrintf
1465 // report config errors to appropriate channel
1466 void TSyncAppBase::ConferrPuts(const char *msg)
1468 #ifdef ENGINE_LIBRARY
1471 // - get config var to see where we should put config errors
1472 if (!getConfigVar("conferrpath", filename))
1473 return; // no output defined for config errors
1474 // a config error path is defined
1475 if (strucmp(filename.c_str(),"console")==0) {
1476 // put message directly to what is supposed to be the console
1477 AppConsolePuts(msg);
1480 #else // ENGINE_LIBRARY
1481 // old variant - output to predefined path
1485 #elif defined(__PALM_OS__)
1486 return; // PalmOS has no file output
1488 // prepare file name
1490 if (!getPlatformString(pfs_defout_path,filename)) return;
1491 makeOSDirPath(filename);
1492 filename+=CONFERRPREFIX;
1494 filename+=CONFERRSUFFIX;
1495 #endif // not ENGINE_LIBRARY
1497 // now write to file
1498 FILE * logfile=fopen(filename.c_str(),"a");
1501 StringObjTimestamp(ts,getSystemNowAs(TCTX_SYSTEM));
1503 fputs(ts.c_str(),logfile);
1505 fputs("\n",logfile);
1508 #endif // __PALM_OS__
1509 } // TSyncAppBase::ConferrPuts
1512 /* config reading */
1514 // XML parser's "userdata"
1517 TRootConfigElement *rootconfig;
1523 static void startElement(void *userData, const char *name, const char **atts);
1524 static void charData(void *userData, const XML_Char *s, int len);
1525 static void endElement(void *userData, const char *name);
1528 static localstatus checkErrors(TRootConfigElement *aRootConfigP,XML_Parser aParser)
1530 const char *errmsg = aRootConfigP->getErrorMsg();
1532 aRootConfigP->getSyncAppBase()->ConferrPrintf(
1533 "%s at line %ld col %ld",
1535 (sInt32)XML_GetCurrentLineNumber(aParser),
1536 (sInt32)XML_GetCurrentColumnNumber(aParser)
1538 aRootConfigP->resetError();
1539 return aRootConfigP->getFatalError(); // return when fatal
1542 return LOCERR_OK; // no (fatal) error
1546 // callback for expat
1547 static void startElement(void *userData, const char *name, const char **atts)
1549 TRootConfigElement *cfgP = static_cast<TXMLUserData *>(userData)->rootconfig;
1550 XML_Parser parser = static_cast<TXMLUserData *>(userData)->parser;
1552 cfgP->startElement(name,atts,XML_GetCurrentLineNumber(parser));
1554 SYSYNC_CATCH (exception &e)
1555 cfgP->ReportError(true,"Exception in StartElement: %s",e.what());
1558 checkErrors(cfgP,parser);
1562 // callback for expat
1563 static void charData(void *userData, const XML_Char *s, int len)
1565 TRootConfigElement *cfgP = static_cast<TXMLUserData *>(userData)->rootconfig;
1566 XML_Parser parser = static_cast<TXMLUserData *>(userData)->parser;
1568 cfgP->charData(s,len);
1570 SYSYNC_CATCH (exception &e)
1571 cfgP->ReportError(true,"Exception in charData: %s",e.what());
1574 checkErrors(cfgP,parser);
1579 // callback for expat
1580 static void endElement(void *userData, const char *name)
1582 TRootConfigElement *cfgP = static_cast<TXMLUserData *>(userData)->rootconfig;
1583 XML_Parser parser = static_cast<TXMLUserData *>(userData)->parser;
1585 cfgP->endElement(name);
1587 SYSYNC_CATCH (exception &e)
1588 cfgP->ReportError(true,"Exception in endElement: %s",e.what());
1591 checkErrors(cfgP,parser);
1595 // config stream reading
1596 localstatus TSyncAppBase::readXMLConfigStream(TXMLConfigReadFunc aReaderFunc, void *aContext)
1598 localstatus fatalerr;
1600 // clear (reset to default) all config
1602 TP_SWITCH(last,fTPInfo,TP_configread);
1603 MP_SHOWCURRENT(DBG_HOT,"start reading config");
1605 // initialize for new config
1607 fConfigP->ResetParsing();
1609 appChar buf[CONFIG_READ_BUFSIZ];
1612 XML_Parser parser = XML_ParserCreate(NULL);
1614 // init user data struct
1615 TXMLUserData userdata;
1616 userdata.parser=parser;
1617 userdata.rootconfig=fConfigP;
1618 // pass pointer to root config here
1619 XML_SetUserData(parser, &userdata);
1620 XML_SetElementHandler(parser, startElement, endElement);
1621 XML_SetCharacterDataHandler(parser, charData);
1624 // callback reader func
1625 if (!(aReaderFunc)(buf,CONFIG_READ_BUFSIZ,&len,aContext)) {
1626 fConfigP->setFatalError(LOCERR_CFGREAD); // this is also fatal
1628 "Error reading from config"
1632 // %%% changed stop criterium to smooth EngineInterface API
1633 //done = len < CONFIG_READ_BUFSIZ;
1635 if (!XML_Parse(parser, buf, len, done)) {
1636 fConfigP->setFatalError(LOCERR_CFGPARSE); // this is also fatal
1638 "%s at line %ld col %ld",
1639 XML_ErrorString(XML_GetErrorCode(parser)),
1640 (sInt32)XML_GetCurrentLineNumber(parser),
1641 (sInt32)XML_GetCurrentColumnNumber(parser)
1646 if (fConfigP->getFatalError()) break;
1648 XML_ParserFree(parser);
1649 if (!fConfigP->getFatalError()) {
1651 fConfigP->ResolveAll();
1652 // display resolve error, if any
1653 const char *msg = fConfigP->getErrorMsg();
1655 // this is fatal only if error was thrown in Resolve.
1656 // Some warnings might be set with ReportError and
1657 // will not cause abort.
1661 // check if ok or not
1662 if ((fatalerr=fConfigP->getFatalError())!=LOCERR_OK) {
1663 // config failed, reset
1664 // %%% do not clear the config here
1665 //fConfigP->clear();
1667 "Fatal error %hd, no valid configuration could be read from XML file",
1670 TP_START(fTPInfo,last);
1675 XML_ParserFree(parser);
1677 fConfigP->setFatalError(LOCERR_CFGPARSE); // this is also fatal
1679 "Exception while parsing XML, no valid configuration"
1681 TP_START(fTPInfo,last);
1682 return LOCERR_CFGPARSE;
1684 TP_START(fTPInfo,last);
1685 #if defined(APP_CAN_EXPIRE) && defined(RELEASE_YEAR) && defined(SYSER_REGISTRATION)
1686 if (fAppExpiryStatus==LOCERR_TOONEW) {
1688 "License is invalid for software released on or after %04d-%02d-01",
1689 (fRelDuration / 12) + 2000,
1690 (fRelDuration) % 12 + 1
1694 #ifdef APP_CAN_EXPIRE
1695 if (fAppExpiryStatus!=LOCERR_OK) {
1696 if (fAppExpiryStatus==LOCERR_EXPIRED) {
1697 ConferrPrintf("Time-limited License expired");
1699 ConferrPrintf("Missing or bad License Information");
1701 ConferrPrintf("Please contact Synthesis AG to obtain new license information");
1702 fConfigP->setFatalError(fAppExpiryStatus); // this is also fatal
1703 return fAppExpiryStatus;
1706 #ifdef SYSER_REGISTRATION
1707 // check if config should have locked sections with a certain CRC value
1712 // - get restriction string from licensed info
1713 ok = getAppEnableInfo(daysleft, NULL, &s)==LOCERR_OK;
1714 string restrid,restrval;
1715 const char *p = s.c_str(); // start of license info string
1716 while (ok && (p=getLicenseRestriction(p,restrid,restrval))!=NULL) {
1717 if (restrid=="l") { // lock CRC
1718 StrToULong(restrval.c_str(),shouldcrc);
1719 ok=shouldcrc==fConfigP->getConfigLockCRC();
1723 ConferrPrintf("Locked config sections are not valid");
1724 fConfigP->setFatalError(LOCERR_BADREG); // this is also fatal
1725 return LOCERR_BADREG;
1729 MP_SHOWCURRENT(DBG_HOT,"finished reading config");
1731 } // TSyncAppBase::readXMLConfigStream
1734 #ifdef CONSTANTXML_CONFIG
1736 // stream reader for reading from compiled-in text constant
1737 static int _CALLING_ ConstantReader(
1738 sysync::appCharP aBuffer,
1739 sysync::bufferIndex aMaxSize,
1740 sysync::bufferIndex *aReadCharsP,
1741 void *aContext // const char **
1745 const char *readptr = *((const char **)aContext);
1746 // read from constant
1747 if (!readptr) return false;
1748 size_t len = strlen(readptr);
1749 if (len>aMaxSize) len=aMaxSize;
1751 if (len>0) strncpy(aBuffer,readptr,len);
1753 *((const char **)aContext)=readptr+len;
1754 *aReadCharsP=len; // return number of chars actually read
1755 return true; // successful
1759 // config file reading from hard-wired Constant
1760 localstatus TSyncAppBase::readXMLConfigConstant(const char *aConstantXML)
1762 const char *aCursor = aConstantXML;
1763 return readXMLConfigStream(&ConstantReader, &aCursor);
1765 // signal where config came from
1766 fConfigFilePath="<XML read from string constant>";
1768 } // TSyncAppBase::readXMLConfigConstant
1774 // stream reader for cfile
1775 static int _CALLING_ CFileReader(
1777 bufferIndex aMaxSize,
1778 bufferIndex *aReadCharsP,
1779 void *aContext // FILE *
1782 FILE *cfgfile = (FILE *)aContext;
1784 size_t len = fread(aBuffer, 1, aMaxSize, cfgfile);
1787 return appFalse; // not EOF, other error: failed
1788 len=0; // nothing read, end of file
1790 *aReadCharsP=len; // return number of chars actually read
1791 return appTrue; // successful
1795 // config file reading from C file
1796 localstatus TSyncAppBase::readXMLConfigCFile(FILE *aCfgFile)
1798 return readXMLConfigStream(&CFileReader, (void *)aCfgFile);
1799 } // TSyncAppBase::readXMLConfigCFile
1802 // read config from file path
1803 localstatus TSyncAppBase::readXMLConfigFile(cAppCharP aFilePath)
1805 localstatus fatalerr;
1808 FILE* cfgfile=fopen(aFilePath,"r");
1810 // yes, there is a config file. Get its date
1811 getRootConfig()->fConfigDate = getFileModificationDate(aFilePath);
1812 // now read the config file (and possibly override fConfigDate)
1813 if ((fatalerr=readXMLConfigCFile(cfgfile))!=LOCERR_OK) {
1815 PDEBUGPRINTFX(DBG_ERROR,(
1816 "==== Fatal Error %hd reading config file '%s'",
1820 return fatalerr; // config file with fatal errors
1823 #if defined(SYDEBUG) && !defined(SYSYNC_TOOL)
1825 StringObjTimestamp(t,getRootConfig()->fConfigDate);
1826 // now write settings to log
1827 PDEBUGPRINTFX(DBG_HOT,(
1828 "==== Config file '%s' read: Last Config Change=%s, Debug=0x%08lX, Lock=%ld",
1832 (long)fConfigP->getConfigLockCRC()
1834 PDEBUGPRINTFX(DBG_HOT,(
1835 "==== Config file ID = '%s'",
1836 getRootConfig()->fConfigIDString.c_str()
1839 CONSOLEPRINTF(("- Config file read from '%s'",aFilePath));
1841 if (getRootConfig()->fDebugConfig.fSessionDebugLogs || getRootConfig()->fDebugConfig.fGlobalDebugLogs)
1842 CONSOLEPRINTF(("- Debug log path: %s",getRootConfig()->fDebugConfig.fDebugInfoPath.c_str()));
1843 // signal where config came from
1844 fConfigFilePath=aFilePath;
1850 DEBUGPRINTFX(DBG_ERROR,("==== No Config file found under '%s'",aFilePath));
1851 // reset config to defaults
1853 return LOCERR_NOCFGFILE;
1855 } // TSyncAppBase::readXMLConfigFile
1858 #ifndef ENGINE_LIBRARY
1860 // standard reading of config on predefined paths
1861 localstatus TSyncAppBase::readXMLConfigStandard(const char *aConfigFileName, bool aOnlyGlobal, bool aAbsolute)
1863 localstatus fatalerr;
1866 // - get path where config file should be
1868 sInt16 attempt= aOnlyGlobal ? 1 : 0; // if only global, don't look in exe dir (e.g. for ISAPI modules)
1874 // no config file found
1875 return LOCERR_NOCFGFILE;
1877 // just use path as it is
1878 cfgfilename=aConfigFileName;
1883 // first check if there's a local copy
1884 if (!getPlatformString(pfs_loccfg_path,cfgfilename))
1885 continue; // none found, try next
1887 else if (attempt==2) {
1888 // if no local config file, look for a global one
1889 if (!getPlatformString(pfs_globcfg_path,cfgfilename))
1890 continue; // none found, try next
1893 CONSOLEPRINTF(("- No config file found, using default settings"));
1894 // reset config to defaults
1896 return LOCERR_NOCFGFILE; // no config
1899 makeOSDirPath(cfgfilename,false);
1900 cfgfilename+=aConfigFileName;
1902 fatalerr=readXMLConfigFile(cfgfilename.c_str());
1903 if (fatalerr==LOCERR_OK)
1904 break; // config found, ok
1908 ConferrPrintf("Fatal Error (exception) while reading config file");
1909 return LOCERR_CFGREAD;
1911 return LOCERR_OK; // ok
1912 } // TSyncAppBase::readXMLConfigStandard
1914 #endif // ENGINE_LIBRARY
1916 #endif // HARDCODED_CONFIG
1919 /* progress sevent notification */
1921 #ifdef PROGRESS_EVENTS
1924 bool TSyncAppBase::NotifyProgressEvent(
1925 TProgressEventType aEventType,
1926 TLocalDSConfig *aDatastoreID,
1932 TProgressEvent theevent;
1934 if (fProgressEventFunc) {
1935 // there is a progress event callback
1937 theevent.eventtype=aEventType;
1938 theevent.datastoreID=aDatastoreID;
1939 theevent.extra=aExtra1;
1940 theevent.extra2=aExtra2;
1941 theevent.extra3=aExtra3;
1942 // - invoke callback (returns false if aborted)
1943 return fProgressEventFunc(
1945 fProgressEventContext
1948 // if no callback, never abort
1949 return true; // ok, no abort
1950 } // TSyncAppBase::NotifyProgressEvent
1956 /* logfile outputs */
1959 /* SyncML toolkit callback handlers */
1962 Ret_t TSyncAppBase::EndMessage(VoidPtr_t userData, Boolean_t aFinal)
1964 if (!userData) return SML_ERR_WRONG_PARAM;
1967 return ((TSyncSession *) userData)->EndMessage(aFinal);
1969 SYSYNC_CATCH (exception &e)
1970 return HandleDecodingException((TSyncSession *)userData,"EndMessage",&e);
1973 return HandleDecodingException((TSyncSession *)userData,"EndMessage",NULL);
1975 } // TSyncAppBase::EndMessage
1978 Ret_t TSyncAppBase::StartSync(VoidPtr_t userData, SmlSyncPtr_t aContentP)
1980 if (!userData) return SML_ERR_WRONG_PARAM;
1983 return ((TSyncSession *) userData)->StartSync(aContentP);
1985 SYSYNC_CATCH (exception &e)
1986 return HandleDecodingException((TSyncSession *)userData,"StartSync",&e);
1989 return HandleDecodingException((TSyncSession *)userData,"StartSync",NULL);
1991 } // TSyncAppBase::StartSync
1994 Ret_t TSyncAppBase::EndSync(VoidPtr_t userData)
1996 if (!userData) return SML_ERR_WRONG_PARAM;
1999 return ((TSyncSession *) userData)->EndSync();
2001 SYSYNC_CATCH (exception &e)
2002 return HandleDecodingException((TSyncSession *)userData,"EndSync",&e);
2005 return HandleDecodingException((TSyncSession *)userData,"EndSync",NULL);
2007 } // TSyncAppBase::EndSync
2010 #ifdef SEQUENCE_RECEIVE
2011 Ret_t TSyncAppBase::StartSequence(VoidPtr_t userData, SmlSequencePtr_t aContentP)
2013 if (!userData) return SML_ERR_WRONG_PARAM;
2016 return ((TSyncSession *) userData)->StartSequence(aContentP);
2018 SYSYNC_CATCH (exception &e)
2019 return HandleDecodingException((TSyncSession *)userData,"StartSequence",&e);
2022 return HandleDecodingException((TSyncSession *)userData,"StartSequence",NULL);
2024 } // TSyncAppBase::StartSequence
2027 Ret_t TSyncAppBase::EndSequence(VoidPtr_t userData)
2029 if (!userData) return SML_ERR_WRONG_PARAM;
2032 return ((TSyncSession *) userData)->EndSequence();
2034 SYSYNC_CATCH (exception &e)
2035 return HandleDecodingException((TSyncSession *)userData,"EndSequence",&e);
2038 return HandleDecodingException((TSyncSession *)userData,"EndSequence",NULL);
2040 } // TSyncAppBase::EndSequence
2044 #ifdef ATOMIC_RECEIVE
2045 Ret_t TSyncAppBase::StartAtomic(VoidPtr_t userData, SmlAtomicPtr_t aContentP)
2047 if (!userData) return SML_ERR_WRONG_PARAM;
2050 return ((TSyncSession *) userData)->StartAtomic(aContentP);
2052 SYSYNC_CATCH (exception &e)
2053 return HandleDecodingException((TSyncSession *)userData,"StartAtomic",&e);
2056 return HandleDecodingException((TSyncSession *)userData,"StartAtomic",NULL);
2058 } // TSyncAppBase::StartAtomic
2061 Ret_t TSyncAppBase::EndAtomic(VoidPtr_t userData)
2063 if (!userData) return SML_ERR_WRONG_PARAM;
2066 return ((TSyncSession *) userData)->EndAtomic();
2068 SYSYNC_CATCH (exception &e)
2069 return HandleDecodingException((TSyncSession *)userData,"EndAtomic",&e);
2072 return HandleDecodingException((TSyncSession *)userData,"EndAtomic",NULL);
2074 } // TSyncAppBase::EndAtomic
2078 Ret_t TSyncAppBase::AddCmd(VoidPtr_t userData, SmlAddPtr_t aContentP)
2080 if (!userData) return SML_ERR_WRONG_PARAM;
2083 return ((TSyncSession *) userData)->AddCmd(aContentP);
2085 SYSYNC_CATCH (exception &e)
2086 return HandleDecodingException((TSyncSession *)userData,"AddCmd",&e);
2089 return HandleDecodingException((TSyncSession *)userData,"AddCmd",NULL);
2091 } // TSyncAppBase::AddCmd
2094 Ret_t TSyncAppBase::AlertCmd(VoidPtr_t userData, SmlAlertPtr_t aContentP)
2096 if (!userData) return SML_ERR_WRONG_PARAM;
2099 return ((TSyncSession *) userData)->AlertCmd(aContentP);
2101 SYSYNC_CATCH (exception &e)
2102 return HandleDecodingException((TSyncSession *)userData,"AlertCmd",&e);
2105 return HandleDecodingException((TSyncSession *)userData,"AlertCmd",NULL);
2107 } // TSyncAppBase::AlertCmd
2110 Ret_t TSyncAppBase::DeleteCmd(VoidPtr_t userData, SmlDeletePtr_t aContentP)
2112 if (!userData) return SML_ERR_WRONG_PARAM;
2115 return ((TSyncSession *) userData)->DeleteCmd(aContentP);
2117 SYSYNC_CATCH (exception &e)
2118 return HandleDecodingException((TSyncSession *)userData,"DeleteCmd",&e);
2121 return HandleDecodingException((TSyncSession *)userData,"DeleteCmd",NULL);
2123 } // TSyncAppBase::DeleteCmd
2126 Ret_t TSyncAppBase::GetCmd(VoidPtr_t userData, SmlGetPtr_t aContentP)
2128 if (!userData) return SML_ERR_WRONG_PARAM;
2131 return ((TSyncSession *) userData)->GetCmd(aContentP);
2133 SYSYNC_CATCH (exception &e)
2134 return HandleDecodingException((TSyncSession *)userData,"GetCmd",&e);
2137 return HandleDecodingException((TSyncSession *)userData,"GetCmd",NULL);
2139 } // TSyncAppBase::GetCmd
2142 Ret_t TSyncAppBase::PutCmd(VoidPtr_t userData, SmlPutPtr_t aContentP)
2144 if (!userData) return SML_ERR_WRONG_PARAM;
2147 return ((TSyncSession *) userData)->PutCmd(aContentP);
2149 SYSYNC_CATCH (exception &e)
2150 return HandleDecodingException((TSyncSession *)userData,"PutCmd",&e);
2153 return HandleDecodingException((TSyncSession *)userData,"PutCmd",NULL);
2155 } // TSyncAppBase::PutCmd
2159 Ret_t TSyncAppBase::MapCmd(VoidPtr_t userData, SmlMapPtr_t aContentP)
2161 if (!userData) return SML_ERR_WRONG_PARAM;
2164 return ((TSyncSession *) userData)->MapCmd(aContentP);
2166 SYSYNC_CATCH (exception &e)
2167 return HandleDecodingException((TSyncSession *)userData,"MapCmd",&e);
2170 return HandleDecodingException((TSyncSession *)userData,"MapCmd",NULL);
2172 } // TSyncAppBase::MapCmd
2176 #ifdef RESULT_RECEIVE
2177 Ret_t TSyncAppBase::ResultsCmd(VoidPtr_t userData, SmlResultsPtr_t aContentP)
2179 if (!userData) return SML_ERR_WRONG_PARAM;
2182 return ((TSyncSession *) userData)->ResultsCmd(aContentP);
2184 SYSYNC_CATCH (exception &e)
2185 return HandleDecodingException((TSyncSession *)userData,"ResultsCmd",&e);
2188 return HandleDecodingException((TSyncSession *)userData,"ResultsCmd",NULL);
2190 } // TSyncAppBase::ResultsCmd
2194 Ret_t TSyncAppBase::StatusCmd(VoidPtr_t userData, SmlStatusPtr_t aContentP)
2196 if (!userData) return SML_ERR_WRONG_PARAM;
2199 return ((TSyncSession *) userData)->StatusCmd(aContentP);
2201 SYSYNC_CATCH (exception &e)
2202 return HandleDecodingException((TSyncSession *)userData,"StatusCmd",&e);
2205 return HandleDecodingException((TSyncSession *)userData,"StatusCmd",NULL);
2207 } // TSyncAppBase::StatusCmd
2210 Ret_t TSyncAppBase::ReplaceCmd(VoidPtr_t userData, SmlReplacePtr_t aContentP)
2212 if (!userData) return SML_ERR_WRONG_PARAM;
2215 return ((TSyncSession *) userData)->ReplaceCmd(aContentP);
2217 SYSYNC_CATCH (exception &e)
2218 return HandleDecodingException((TSyncSession *)userData,"ReplaceCmd",&e);
2221 return HandleDecodingException((TSyncSession *)userData,"ReplaceCmd",NULL);
2223 } // TSyncAppBase::ReplaceCmd
2227 Ret_t TSyncAppBase::CopyCmd(VoidPtr_t userData, SmlCopyPtr_t aContentP)
2229 if (!userData) return SML_ERR_WRONG_PARAM;
2232 return ((TSyncSession *) userData)->CopyCmd(aContentP);
2234 SYSYNC_CATCH (exception &e)
2235 return HandleDecodingException((TSyncSession *)userData,"CopyCmd",&e);
2238 return HandleDecodingException((TSyncSession *)userData,"CopyCmd",NULL);
2240 } // TSyncAppBase::CopyCmd
2244 Ret_t TSyncAppBase::MoveCmd(VoidPtr_t userData, SmlMovePtr_t aContentP)
2246 if (!userData) return SML_ERR_WRONG_PARAM;
2249 return ((TSyncSession *) userData)->MoveCmd(aContentP);
2251 SYSYNC_CATCH (exception &e)
2252 return HandleDecodingException((TSyncSession *)userData,"MoveCmd",&e);
2255 return HandleDecodingException((TSyncSession *)userData,"MoveCmd",NULL);
2257 } // TSyncAppBase::MoveCmd
2260 /* Other Callbacks */
2261 Ret_t TSyncAppBase::HandleError(VoidPtr_t userData)
2263 if (!userData) return SML_ERR_WRONG_PARAM;
2266 return ((TSyncSession *) userData)->HandleError();
2268 SYSYNC_CATCH (exception &e)
2269 return HandleDecodingException((TSyncSession *)userData,"HandleError",&e);
2272 return HandleDecodingException((TSyncSession *)userData,"HandleError",NULL);
2274 } // TSyncAppBase::HandleError
2279 Ret_t TSyncAppBase::DummyHandler(VoidPtr_t userData, const char* msg)
2281 if (!userData) return SML_ERR_WRONG_PARAM;
2283 // session is attached
2285 return ((TSyncSession *) userData)->DummyHandler(msg);
2287 SYSYNC_CATCH (exception &e)
2288 return HandleDecodingException((TSyncSession *)userData,"DummyHandler",&e);
2291 return HandleDecodingException((TSyncSession *)userData,"DummyHandler",NULL);
2295 DEBUGPRINTFX(DBG_HOT,("DummyHandler (without session attached): msg=%s",msg));
2298 } // TSyncAppBase::DummyHandler
2301 /* SyncML toolkit callback address table */
2303 static const SmlCallbacks_t mySmlCallbacks = {
2304 /* message callbacks */
2305 smlStartMessageCallback,
2306 smlEndMessageCallback,
2307 /* grouping commands */
2308 smlStartSyncCallback,
2310 #ifdef ATOMIC_RECEIVE /* these callbacks are NOT included in the Toolkit lite version */
2311 smlStartAtomicCallback,
2312 smlEndAtomicCallback,
2314 #ifdef SEQUENCE_RECEIVE
2315 smlStartSequenceCallback,
2316 smlEndSequenceCallback,
2320 smlAlertCmdCallback,
2321 smlDeleteCmdCallback,
2327 #ifdef RESULT_RECEIVE
2328 smlResultsCmdCallback,
2330 smlStatusCmdCallback,
2331 smlReplaceCmdCallback,
2332 /* other commands */
2333 #ifdef COPY_RECEIVE /* these callbacks are NOT included in the Toolkit lite version */
2339 #ifdef SEARCH_RECEIVE
2340 smlSearchCmdCallback,
2343 /* Other Callbacks */
2344 smlHandleErrorCallback,
2345 smlTransmitChunkCallback
2346 }; /* sml_callbacks struct */
2349 /* Context record to find back to appbase and store userData */
2352 TSyncAppBase *appBaseP;
2354 } TSmlContextDataRec;
2357 /* SyncML toolkit callback implementations */
2359 // macros to simplify access to contex
2360 #define GET_APPBASE(x) (((TSmlContextDataRec *)x)->appBaseP)
2361 #define GET_USERDATA(x) (((TSmlContextDataRec *)x)->userDataP)
2363 /* message callbacks */
2364 static Ret_t smlStartMessageCallback(InstanceID_t id, VoidPtr_t userData, SmlSyncHdrPtr_t pContent) { return GET_APPBASE(userData)->StartMessage(id,GET_USERDATA(userData),pContent); }
2365 static Ret_t smlEndMessageCallback(InstanceID_t id, VoidPtr_t userData, Boolean_t final) { return GET_APPBASE(userData)->EndMessage(GET_USERDATA(userData),final); }
2366 /* grouping commands */
2367 static Ret_t smlStartSyncCallback(InstanceID_t id, VoidPtr_t userData, SmlSyncPtr_t pContent) { return GET_APPBASE(userData)->StartSync(GET_USERDATA(userData),pContent); }
2368 static Ret_t smlEndSyncCallback(InstanceID_t id, VoidPtr_t userData) { return GET_APPBASE(userData)->EndSync(GET_USERDATA(userData)); }
2369 #ifdef ATOMIC_RECEIVE /* these callbacks are NOT included in the Toolkit lite version */
2370 static Ret_t smlStartAtomicCallback(InstanceID_t id, VoidPtr_t userData, SmlAtomicPtr_t pContent) { return GET_APPBASE(userData)->StartAtomic(GET_USERDATA(userData),pContent); }
2371 static Ret_t smlEndAtomicCallback(InstanceID_t id, VoidPtr_t userData) { return GET_APPBASE(userData)->EndAtomic(GET_USERDATA(userData)); }
2373 #ifdef SEQUENCE_RECEIVE
2374 static Ret_t smlStartSequenceCallback(InstanceID_t id, VoidPtr_t userData, SmlSequencePtr_t pContent) { return GET_APPBASE(userData)->StartSequence(GET_USERDATA(userData),pContent); }
2375 static Ret_t smlEndSequenceCallback(InstanceID_t id, VoidPtr_t userData) { return GET_APPBASE(userData)->EndSequence(GET_USERDATA(userData)); }
2378 static Ret_t smlAddCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlAddPtr_t pContent) { return GET_APPBASE(userData)->AddCmd(GET_USERDATA(userData),pContent); }
2379 static Ret_t smlAlertCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlAlertPtr_t pContent) { return GET_APPBASE(userData)->AlertCmd(GET_USERDATA(userData),pContent); }
2380 static Ret_t smlDeleteCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlDeletePtr_t pContent) { return GET_APPBASE(userData)->DeleteCmd(GET_USERDATA(userData),pContent); }
2381 static Ret_t smlGetCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlGetPtr_t pContent) { return GET_APPBASE(userData)->GetCmd(GET_USERDATA(userData),pContent); }
2382 static Ret_t smlPutCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlPutPtr_t pContent) { return GET_APPBASE(userData)->PutCmd(GET_USERDATA(userData),pContent); }
2384 static Ret_t smlMapCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlMapPtr_t pContent) { return GET_APPBASE(userData)->MapCmd(GET_USERDATA(userData),pContent); }
2386 #ifdef RESULT_RECEIVE
2387 static Ret_t smlResultsCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlResultsPtr_t pContent) { return GET_APPBASE(userData)->ResultsCmd(GET_USERDATA(userData),pContent); }
2389 static Ret_t smlStatusCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlStatusPtr_t pContent) { return GET_APPBASE(userData)->StatusCmd(GET_USERDATA(userData),pContent); }
2390 static Ret_t smlReplaceCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlReplacePtr_t pContent) { return GET_APPBASE(userData)->ReplaceCmd(GET_USERDATA(userData),pContent); }
2391 /* other commands */
2392 #ifdef COPY_RECEIVE /* these callbacks are NOT included in the Toolkit lite version */
2393 static Ret_t smlCopyCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlCopyPtr_t pContent) { return GET_APPBASE(userData)->CopyCmd(GET_USERDATA(userData),pContent); }
2395 static Ret_t smlMoveCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlMovePtr_t pContent) { return GET_APPBASE(userData)->MoveCmd(GET_USERDATA(userData),pContent); }
2397 static Ret_t smlExecCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlExecPtr_t pContent) { /*%%%tbd return GET_APPBASE(userData)->ExecCmd(GET_USERDATA(userData),pContent); */ return SML_ERR_INVALID_OPTIONS; }
2399 #ifdef SEARCH_RECEIVE
2400 static Ret_t smlSearchCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlSearchPtr_t pContent) { /*%%%tbd return GET_APPBASE(userData)->SearchCmd(GET_USERDATA(userData),pContent); */ return SML_ERR_INVALID_OPTIONS; }
2402 /* Other Callbacks */
2403 static Ret_t smlHandleErrorCallback(InstanceID_t id, VoidPtr_t userData) { return GET_APPBASE(userData)->DummyHandler(GET_USERDATA(userData),"ErrorCallback"); }
2404 static Ret_t smlTransmitChunkCallback(InstanceID_t id, VoidPtr_t userData) { /*%%%tdb return GET_APPBASE(userData)->TransmitChunk(GET_USERDATA(userData),pContent); */ return SML_ERR_INVALID_OPTIONS; }
2407 /* end callback implementations */
2410 /* RTK interfacing */
2413 Ret_t TSyncAppBase::setSmlInstanceUserData(
2414 InstanceID_t aInstanceID,
2419 if (smlGetUserData(aInstanceID,&ctxP)==SML_ERR_OK && ctxP) {
2420 static_cast<TSmlContextDataRec *>(ctxP)->userDataP=aUserDataP;
2423 return SML_ERR_MGR_INVALID_INSTANCE_INFO; // invalid instance (has no TSmlContextDataRec in userData)
2424 } // TSyncAppBase::setSmlInstanceUserData
2427 Ret_t TSyncAppBase::getSmlInstanceUserData(
2428 InstanceID_t aInstanceID,
2433 if (smlGetUserData(aInstanceID,&ctxP)==SML_ERR_OK && ctxP) {
2434 *aUserDataPP = static_cast<TSmlContextDataRec *>(ctxP)->userDataP;
2437 return SML_ERR_MGR_INVALID_INSTANCE_INFO; // invalid instance (has no TSmlContextDataRec in userData)
2438 } // TSyncAppBase::setSmlInstanceUserData
2443 // create new SyncML toolkit instance
2444 bool TSyncAppBase::newSmlInstance(
2445 SmlEncoding_t aEncoding,
2446 sInt32 aWorkspaceMem,
2447 InstanceID_t &aInstanceID
2450 SmlInstanceOptions_t myInstanceOptions;
2454 #error "Only NOWSM version is supported any more"
2458 myInstanceOptions.encoding=aEncoding;
2459 // - total size of instance buffer
2460 // (must have room for both incoming and outgoing message if instance
2461 // is used for both)
2462 myInstanceOptions.workspaceSize=aWorkspaceMem;
2463 // - maximum outgoing message size
2464 myInstanceOptions.maxOutgoingSize=0; // %%% disabled for now, can be set later with setMaxOutgoingSize()
2465 // - create user data record
2466 TSmlContextDataRec *smlContextRecP = new TSmlContextDataRec;
2467 if (!smlContextRecP) return false;
2468 smlContextRecP->appBaseP=this; // pointer to find back to this syncappbase w/o the help of global vars
2469 smlContextRecP->userDataP=NULL; // userData will be SySyncSession pointer, but now session is not yet determined
2470 // - now instantiate (thread-safe!)
2471 err=smlInitInstance(
2472 &mySmlCallbacks, // callbacks
2475 &aInstanceID // where to store the instance ID
2477 // - return instance or NULL if failed
2478 if (err==SML_ERR_OK) {
2479 DEBUGPRINTFX(DBG_RTK_SML,("////////////// sml Instance created, id(=instanceInfoPtr)=0x%08lX",(long)aInstanceID));
2480 return true; // success
2483 DEBUGPRINTFX(DBG_ERROR,("************ smlInitInstance returned 0x%hX",(sInt16)err));
2484 aInstanceID=NULL; // none
2485 return false; // failed
2487 } // TSyncAppBase::newSmlInstance
2490 void TSyncAppBase::freeSmlInstance(InstanceID_t aInstance)
2492 // forget instance now
2493 // - accept no-instance
2494 if (aInstance==NULL) return;
2495 // - there is an instance
2496 // - free context record
2498 if (smlGetUserData(aInstance,&ctxP)==SML_ERR_OK && ctxP)
2499 delete static_cast<TSmlContextDataRec *>(ctxP);
2500 // - free instance itself
2501 Ret_t err=smlTerminateInstance(aInstance);
2502 DEBUGPRINTFX(DBG_RTK_SML,("////////////// sml Instance freed, id(=instanceInfoPtr)=0x%08lX, err=0x%hX",(long)aInstance,(sInt16)err));
2504 if (err!=SML_ERR_OK) {
2505 DEBUGPRINTFX(DBG_ERROR,("smlTerminateInstance returned 0x%hX",(sInt16)err));
2508 } // TSyncAppBase::freeSmlInstance
2511 // determine encoding from beginning of SyncML message data
2512 SmlEncoding_t TSyncAppBase::encodingFromData(cAppPointer aData, memSize aDataSize)
2514 SmlEncoding_t enc = SML_UNDEF;
2515 if (aData && aDataSize>=5) {
2516 // check for WBXML intro sequences
2518 (memcmp((cAppCharP)aData,"\x02\x00\x00",3)==0) || // WBXML V2 + Public identifier as string
2519 (memcmp((cAppCharP)aData,"\x02\xA4\x01",3)==0) || // WBXML V2 + Public identifier 0x1201 for SyncML 1.2
2520 (memcmp((cAppCharP)aData,"\x02\x9F\x53",3)==0) || // WBXML V2 + Public identifier 0x0FD3 for SyncML 1.1
2521 (memcmp((cAppCharP)aData,"\x02\x9F\x51",3)==0) // WBXML V2 + Public identifier 0x0FD1 for SyncML 1.0
2526 // - skip UTF-8 BOM if there is one
2527 cUInt8P p = (cUInt8P)aData;
2528 if (p[0]==0xEF && p[1]==0xBB && p[2]==0xBF)
2529 p+=3; // skip the BOM
2530 // now check for XML
2531 if (strnncmp((cAppCharP)p,"<?xml",5)==0 ||
2532 strnncmp((cAppCharP)p,"<SyncML",7)==0)
2537 } // TSyncAppBase::encodingFromData
2540 // determine encoding from Content-Type: header value
2541 SmlEncoding_t TSyncAppBase::encodingFromContentType(cAppCharP aTypeString)
2543 sInt16 enc = SML_UNDEF;
2545 stringSize l=strlen(SYNCML_MIME_TYPE SYNCML_ENCODING_SEPARATOR);
2546 if (strucmp(aTypeString,SYNCML_MIME_TYPE SYNCML_ENCODING_SEPARATOR,l)==0) {
2547 // is SyncML, check encoding
2548 cAppCharP p = strchr(aTypeString,';');
2549 sInt16 cl = p ? p-aTypeString-l : 0; // length of encoding string (charset could be appended here)
2550 StrToEnum(SyncMLEncodingMIMENames,numSyncMLEncodings,enc,aTypeString+l,cl);
2553 return static_cast<SmlEncoding_t>(enc);
2554 } // TSyncAppBase::encodingFromContentType
2559 // save app state (such as settings in datastore configs etc.)
2560 void TSyncAppBase::saveAppState(void)
2562 if (fConfigP) fConfigP->saveAppState();
2563 } // TSyncAppBase::saveAppState
2566 // manufacturer of overall solution (can be configured, while OEM is fixed to Synthesis)
2567 string TSyncAppBase::getManufacturer(void)
2569 #ifdef ENGINEINTERFACE_SUPPORT
2570 if (fConfigP && !(fConfigP->fMan.empty()))
2571 return fConfigP->fMan;
2573 // if no string configured, return default
2574 return CUST_SYNC_MAN;
2575 } // TSyncAppBase::getManufacturer
2578 // model (application name) of overall solution
2579 string TSyncAppBase::getModel(void) {
2580 #ifdef ENGINEINTERFACE_SUPPORT
2581 if (fConfigP && !(fConfigP->fMod.empty()))
2582 return fConfigP->fMod;
2584 // if no string configured, return default
2585 return CUST_SYNC_MODEL;
2586 } // TSyncAppBase::getModel
2590 string TSyncAppBase::getHardwareVersion(void) {
2591 #ifdef ENGINEINTERFACE_SUPPORT
2592 if (fConfigP && !(fConfigP->fHwV.empty())) {
2593 return fConfigP->fHwV;
2597 // if no string configured, return default
2598 getPlatformString(pfs_device_name, s);
2600 } // TSyncAppBase::getHardwareVersion
2603 // firmware version (depends a lot on the context - OS version?)
2604 string TSyncAppBase::getFirmwareVersion(void) {
2605 #ifdef ENGINEINTERFACE_SUPPORT
2606 if (fConfigP && !(fConfigP->fFwV.empty())) {
2607 return fConfigP->fFwV;
2611 // if no string configured, return default
2612 getPlatformString(pfs_platformvers, s);
2614 } // TSyncAppBase::getHardwareVersion
2617 // hardware type (PDA, PC, ...)
2618 string TSyncAppBase::getDevTyp() {
2619 #ifdef ENGINEINTERFACE_SUPPORT
2620 if (fConfigP && !(fConfigP->fDevTyp.empty())) {
2621 return fConfigP->fDevTyp;
2624 // if no string configured, return default
2626 return SYNCML_SERVER_DEVTYP;
2628 return SYNCML_CLIENT_DEVTYP;
2629 } // TSyncAppBase::getDevTyp
2632 #ifdef APP_CAN_EXPIRE
2634 void TSyncAppBase::updateAppExpiry(void)
2636 // this is the basic check. Some other checks
2637 // are spread in various files to disguise checking a little
2638 #if defined(EXPIRES_AFTER_DAYS) || defined(SYSER_REGISTRATION)
2639 // check soft expiry
2640 fAppExpiryStatus = appEnableStatus();
2641 // check hard expiry only if demo, that is, if no valid license is installed
2642 if (fAppExpiryStatus==LOCERR_OK && fDaysLeft>=0 && !fRegOK)
2646 #ifdef EXPIRES_AFTER_DATE
2647 // check hard expiry date
2648 fScrambledNow>SCRAMBLED_EXPIRY_VALUE ?
2649 LOCERR_EXPIRED : LOCERR_OK;
2651 // no hard expiry, just ok if enabled
2655 } // TSyncAppBase::updateAppExpiry
2661 #ifdef SYSER_REGISTRATION
2663 // checks if registered (must be implemented in base class)
2664 // returns LOCERR_EXPIRED, LOCERR_TOONEW or LOCERR_BADREG if not registered correctly
2665 localstatus TSyncAppBase::isRegistered(void)
2667 #if !defined(HARDCODED_CONFIG) || defined(ENGINEINTERFACE_SUPPORT)
2668 // we have licensing in the config file or using engine interface, check it
2669 return fConfigP ? checkRegInfo(fConfigP->fLicenseName.c_str(),fConfigP->fLicenseCode.c_str(),false) : LOCERR_BADREG;
2671 // no license checking at this level (maybe overriden method provides check)
2672 return LOCERR_EXPIRED;
2674 } // TSyncAppBase::isRegistered
2677 // get (entire) registration string
2678 void TSyncAppBase::getRegString(string &aString)
2680 #if !defined(HARDCODED_CONFIG) || defined(ENGINEINTERFACE_SUPPORT)
2681 // we have licensing in the config file or set via engine interface, use it
2683 aString=fConfigP->fLicenseName;
2689 } // TSyncAppBase::getRegString
2696 #if !defined(APP_CAN_EXPIRE) && defined(RELEASE_VERSION) && !defined(NEVER_EXPIRES_IS_OK)
2697 #error "Warning: Release version that never expires!"
2701 #ifdef APP_CAN_EXPIRE
2703 // make sure we have a valid variant code for the target
2704 #ifndef SYSER_VARIANT_CODE
2705 #error "SYSER_VARIANT_CODE must be defined in target_options.h"
2708 // check enable status of application
2709 localstatus TSyncAppBase::appEnableStatus(void)
2711 // safety check - app w/o initialized config is NOT enabled
2712 // Note: agentconfig tested here, but all other config sections are created in clear() at the same time
2713 if (!fConfigP || !(fConfigP->fAgentConfigP)) {
2714 return LOCERR_WRONGUSAGE;
2716 // check registration (which will disable normal expiry)
2717 #ifdef SYSER_REGISTRATION
2718 localstatus regsta = isRegistered(); // ok if registered
2720 #ifndef APP_CAN_EXPIRE
2721 localstatus regsta = LOCERR_OK; // not registerable, not exprining - just run forever
2722 #ifdef RELEASE_VERSION
2723 #error "WARNING: Completely unlimited operation w/o license or expiry - is this intended??"
2726 localstatus regsta = LOCERR_BADREG; // not registerable, assume no license, must be eval which expires
2729 localstatus sta = regsta;
2730 // check expiry (only if registration has not already defined one)
2731 #ifdef APP_CAN_EXPIRE
2732 #ifdef NO_LICENSE_UNTIL_HARDEXPIRY
2733 // we don't need a valid license code until hard expiry date hits
2734 // so if we have a failure now, let the hard expiry decide
2735 if (regsta!=LOCERR_OK) {
2736 #ifdef SYSER_REGISTRATION
2737 fDaysLeft=1; // simulate expiring tomorrow
2739 sta = LOCERR_OK; // ok if we find no hard expiry later
2740 // then let hard expiry decide
2741 #ifndef EXPIRES_AFTER_DATE
2742 #error "WARNING: NO_LICENSE_UNTIL_HARDEXPIRY without EXPIRES_AFTER_DATE - running forever w/o license - indended that way?"
2746 sInt32 td = lineartime2dateonly(getSystemNowAs(TCTX_UTC));
2747 #if defined(EXPIRES_AFTER_DAYS) || defined(NO_LICENSE_UNTIL_HARDEXPIRY)
2748 if (regsta==LOCERR_BADREG || regsta==LOCERR_WRONGPROD) {
2749 // not registered (for this product), check if we are in evaluation period
2750 #ifdef EXPIRES_AFTER_DATE
2751 // check hard expiry first
2752 if (fScrambledNow>SCRAMBLED_EXPIRY_VALUE) {
2753 #ifdef SYSER_REGISTRATION
2754 fDaysLeft=0; // hard-expired
2756 sta = LOCERR_EXPIRED;
2761 #ifdef EXPIRES_AFTER_DAYS
2762 // (bfo found that we need to chec for > demo days too, as
2763 // otherwise some clever guys could install with the
2764 // clock 20 years in the future and then set the clock back)
2766 lineardate_t firstuse;
2767 getFirstUseInfo(SYSER_VARIANT_CODE,firstuse,vers);
2768 sInt32 d = firstuse+EXPIRES_AFTER_DAYS - td;
2769 fDaysLeft = d>0 && d<=EXPIRES_AFTER_DAYS ? d : 0;
2770 sta = d>0 ? LOCERR_OK : LOCERR_EXPIRED;
2772 // Do NOT change the status to expired! - just pass on the license error status
2773 // which might be ok here in case we have a NO_LICENSE_UNTIL_HARDEXPIRY
2774 //sta = LOCERR_EXPIRED;
2780 fDaysLeft=-1; // App cannot expire, no limit
2783 } // TSyncAppBase::appEnableStatus
2786 // get registration information to display (and check internally)
2787 localstatus TSyncAppBase::getAppEnableInfo(sInt16 &aDaysLeft, string *aRegnameP, string *aRegInternalsP)
2789 #ifndef SYSER_REGISTRATION
2791 if (aRegnameP) aRegnameP->erase();
2792 if (aRegInternalsP) aRegInternalsP->erase();
2793 aDaysLeft = -1; // no expiring license (altough hardexpiry might still apply
2794 return appEnableStatus();
2796 // we have registration
2797 localstatus sta = appEnableStatus();
2798 if (sta!=LOCERR_OK) {
2799 if (aRegnameP) aRegnameP->erase();
2800 if (aRegInternalsP) aRegInternalsP->erase();
2801 return sta; // not enabled
2803 // do an extra check here
2804 aDaysLeft = fDaysLeft;
2805 if (fDaysLeft==0) SYSYNC_THROW(exception()); // exit app, as fDaysLeft must be > 0 or -1 here
2806 // get strings if requested
2807 if (aRegnameP || aRegInternalsP) {
2809 // get entire string
2811 // check for separation into a visible (name) and and invisible (email or license restriction) part
2814 // - first priority: license restrictions in form ::x=something
2816 if (n!=string::npos) {
2817 // found a license restriction
2818 m=n; // everthing before special separator belongs to name, rest to internals
2821 // - second priority: a simple email address at the end of the string
2823 if (n==string::npos) {
2824 n=l; m=l; // no email, entire string is name
2828 if (n==string::npos) {
2829 n=l; m=l; // no email, entire string is name
2832 m=n+1; // do not return separating space in either name nor internals
2837 // now remove spaces at the beginning to avoid
2838 // invisible registration info
2839 int i = s.find_first_not_of(' ');
2840 if (i==string::npos) i=0; // no non-space -> start at beginning
2843 for (i= 0; i<n; i++) {
2844 if (s.find( ' ',i )!=i) break; // search for the first char, which is not ' '
2849 if (aRegnameP) aRegnameP->assign(s, i,n);
2850 if (aRegInternalsP) {
2851 if (m<l) aRegInternalsP->assign(s,m,l-m);
2852 else aRegInternalsP->erase();
2857 } // TSyncAppBase::getAppEnableInfo
2859 #endif // APP_CAN_EXPIRE
2863 #ifdef EXPIRES_AFTER_DAYS
2865 // make sure we have a valid variant code for the target
2866 #ifndef SYSER_VERSCHECK_MASK
2867 #error "SYSER_VERSCHECK_MASK must be defined in target_options.h"
2870 /// @brief update first use info to allow for repeated eval when user installs an all-new version
2871 /// @return true if update was needed
2872 /// @param[in] aVariant variant context to perform update
2873 /// @param[in,out] aFirstUseDate date when this variant and version was used first.
2875 /// @param[in,out] aFirstUseVers version that relates to aFirstUseDate.
2876 /// Will be updated to current version if version check allows re-starting demo period.
2877 bool TSyncAppBase::updateFirstUseInfo(lineardate_t &aFirstUseDate, uInt32 &aFirstUseVers)
2879 // update if current version is significantly newer than what we used last time
2882 ((aFirstUseVers & SYSER_VERSCHECK_MASK) <
2883 (SYSYNC_VERSION_UINT32 & SYSER_VERSCHECK_MASK))
2885 // current version is different in a relevant part of the version number, so reset first use
2886 aFirstUseDate = getSystemNowAs(TCTX_UTC) / linearDateToTimeFactor;
2887 aFirstUseVers = SYSYNC_VERSION_UINT32;
2892 } // TSyncAppBase::updateFirstUseInfo
2897 #ifdef SYSER_REGISTRATION
2899 // helper to get next restriction out of license string
2900 const char * TSyncAppBase::getLicenseRestriction(const char *aInfo, string &aID, string &aVal)
2904 bool quotedval=false;
2906 // if no info or at end of string, return NULL
2907 if (!aInfo || *aInfo==0) return NULL;
2908 // find next restriction
2909 aInfo=strstr(aInfo,"::");
2910 if (!aInfo) return NULL; // no more restrictions found
2911 // get ID of restriction
2912 aInfo+=2; // skip ::
2913 p=strchr(aInfo,'=');
2914 if (!p) return NULL; // no more restrictions found
2916 aID.assign(aInfo,p-aInfo);
2917 aInfo=p+1; // skip =
2918 // get value of restriction
2921 // starts with doublequote -> treat as quoted value
2925 while ((c=*aInfo)) {
2928 // quoted string ends with " and can contain backslash escapes
2929 if (c==0x22) break; // done after closing quote
2931 if (*aInfo==0) break; // quote without char following, stop here
2932 c=*aInfo++; // get next char
2936 // unquoted string ends with next space
2937 if (isspace(c)) break;
2942 // return where to continue scanning for next item
2944 } // TSyncAppBase::getLicenseRestriction
2947 // checks registration code for CRC ok and compare with
2948 // predefined constants for product code etc.
2949 localstatus TSyncAppBase::checkRegInfo(const char *aRegKey, const char *aRegCode, bool aMangled)
2953 // extract information from registration code
2954 localstatus regSta = LOCERR_OK;
2956 // do not allow registration text less than 12 chars
2957 if (strlen(aRegKey)<12)
2958 regSta=LOCERR_BADREG; // too short code is a bad code
2959 else if (!getSySerialInfo(
2966 fLicCRC, // CRC as included in the license code
2970 regSta=LOCERR_BADREG; // no code is a bad code
2971 if (regSta==LOCERR_OK) {
2972 // code is basically ok, check standard info
2976 (fRegProductCode == SYSER_PRODUCT_CODE_MAIN)
2977 #ifdef SYSER_PRODUCT_CODE_ALT1
2978 || (fRegProductCode == SYSER_PRODUCT_CODE_ALT1)
2980 #ifdef SYSER_PRODUCT_CODE_ALT2
2981 || (fRegProductCode == SYSER_PRODUCT_CODE_ALT2)
2983 #ifdef SYSER_PRODUCT_CODE_ALT3
2984 || (fRegProductCode == SYSER_PRODUCT_CODE_ALT3)
2986 #ifdef SYSER_PRODUCT_CODE_ALT4
2987 || (fRegProductCode == SYSER_PRODUCT_CODE_ALT4)
2989 #ifdef SYSER_PRODUCT_CODE_ALT5
2990 || (fRegProductCode == SYSER_PRODUCT_CODE_ALT5)
2992 #ifdef SYSER_PRODUCT_CODE_ALT6
2993 || (fRegProductCode == SYSER_PRODUCT_CODE_ALT6)
2995 #ifdef SYSER_PRODUCT_CODE_ALT7
2996 || (fRegProductCode == SYSER_PRODUCT_CODE_ALT7)
2998 #ifdef SYSER_PRODUCT_CODE_ALT8
2999 || (fRegProductCode == SYSER_PRODUCT_CODE_ALT8)
3001 #ifdef SYSER_PRODUCT_CODE_ALT9
3002 || (fRegProductCode == SYSER_PRODUCT_CODE_ALT9)
3005 // special SYSER_PRODFLAG_MAXRELDATE product flag
3007 ((SYSER_NEEDED_PRODUCT_FLAGS & SYSER_PRODFLAG_MAXRELDATE)==0) || // either maxreldate flag is not required...
3008 (fRegProductFlags & SYSER_PRODFLAG_MAXRELDATE) || // ..or it is present..
3009 (fRegDuration!=0) // ..or there is a time limit, which means that the even if the flag is required, product can run with a timed license without the flag
3011 // test other product flags (all except SYSER_PRODFLAG_MAXRELDATE)
3012 && ((fRegProductFlags & (SYSER_NEEDED_PRODUCT_FLAGS & ~SYSER_PRODFLAG_MAXRELDATE)) == (SYSER_NEEDED_PRODUCT_FLAGS & ~SYSER_PRODFLAG_MAXRELDATE))
3013 && ((fRegProductFlags & SYSER_FORBIDDEN_PRODUCT_FLAGS) == 0)
3015 regSta=LOCERR_WRONGPROD;
3016 // anyway, check if CRC is ok
3017 if (!(fLicCRC == addNameToCRC(infocrc,aRegKey,aMangled))) {
3018 regSta=LOCERR_BADREG; // bad CRC is bad registration (and has precedence over wrong product)
3019 // make sure we do not enable exotic functionality
3027 // Now if we have OK, app is registered, but maybe limited
3028 // by time or max release date.
3029 if (regSta==LOCERR_OK) {
3030 // - check max release date limit first
3031 if (fRegProductFlags & SYSER_PRODFLAG_MAXRELDATE) {
3032 // duration is a release duration
3033 // - in case this is a max release date limited license, this
3034 // excludes time limited - max release date licenses are always permanent
3035 fRelDuration = fRegDuration;
3037 // Now check if this build has a hard-coded release date
3039 // license valid only up to release date specified, check that
3040 // if (fRegDuration > (RELEASE_YEAR-2000)*12+RELEASE_MONTH-1) // plain
3043 (fRelDuration*3+48 <= 3*((RELEASE_YEAR-2000)*12+RELEASE_MONTH-1)+48)
3044 ) { // a bit disguised
3045 // license is not valid any more for a build as new as this one
3047 return LOCERR_TOONEW;
3051 // - check for expired license now
3052 // Note: we don't check demo period (days after first use) here
3053 if (fRegDuration!=0) {
3054 lineardate_t ending = date2lineardate(fRegDuration/12+2000,fRegDuration%12+1,1);
3055 sInt32 d=ending-lineartime2dateonly(getSystemNowAs(TCTX_UTC));
3056 fDaysLeft = d>0 ? d : 0;
3058 // license has expired
3060 return LOCERR_EXPIRED;
3064 fDaysLeft=-1; // unlimited by registration
3066 // if it is not ok here, registration code is bad
3067 fRegOK=regSta==LOCERR_OK; // save for further reference
3068 return regSta; // return status
3069 } // TSyncAppBase::checkRegInfo
3072 // checks if current license is properly activated
3073 // - note: must be called at a time when internet connection is available
3074 localstatus TSyncAppBase::checkLicenseActivation(lineardate_t &aLastcheck, uInt32 &aLastcrc)
3078 // - check if already activated
3080 fRegLicenseType && (
3081 (aLastcrc != fLicCRC) || // different license than at last activation
3082 (aLastcheck==0) || // never checked at all
3083 (aLastcheck+180 < lineartime2dateonly(getSystemNowAs(TCTX_UTC))) // not checked in the last half year
3087 ok = checkLicenseType(fRegLicenseType);
3088 // update check date even if we fail (but only if we checked once before)
3089 // to prevent failed sync sessions when reg server has a problem
3090 if (ok || aLastcheck) {
3091 aLastcheck = lineartime2dateonly(getSystemNowAs(TCTX_UTC));
3093 // update CRC only if we could validate the new CRC
3100 OBJ_PROGRESS_EVENT(this,pev_error,NULL,LOCERR_BADREG,0,0);
3103 return ok ? LOCERR_OK : LOCERR_BADREG;
3104 } // TSyncAppBase::checkLicenseActivation
3109 #ifdef CONCURRENT_DEVICES_LIMIT
3111 // check if session count is exceeded
3112 void TSyncAppBase::checkSessionCount(sInt32 aSessionCount, TSyncSession *aSessionP)
3114 // Check if session must be busy (due to licensing restrictions)
3115 // - some minor arithmetic to hide actual comparison with limit
3116 #ifdef SYSER_REGISTRATION
3117 // number of users from license or hardcoded limit, whichever is lower
3118 sInt32 scrambledlimit = 3*(CONCURRENT_DEVICES_LIMIT!=0 && CONCURRENT_DEVICES_LIMIT<fRegQuantity ? CONCURRENT_DEVICES_LIMIT : fRegQuantity)+42;
3120 // only hardcoded limit
3121 sInt32 scrambledlimit = 3*CONCURRENT_DEVICES_LIMIT+42;
3124 // compare with hard limit (if zero, count is unlimited)
3125 ((aSessionCount<<1)+aSessionCount+42>=scrambledlimit && scrambledlimit!=42)
3126 #ifdef CUSTOMIZABLE_DEVICES_LIMIT
3127 // compare with configurable limit, if not set to zero (=unlimited)
3128 || (((aSessionCount<<2) > fConfigP->fConcurrentDeviceLimit*4) && fConfigP->fConcurrentDeviceLimit)
3131 // make session busy (not really responding)
3132 aSessionP->setSessionBusy(true);
3133 PDEBUGPRINTFX(DBG_HOT,("***** Limit of concurrent sessions reached, server response is 'busy'"));
3135 CONSOLEPRINTF(("- concurrent session limit reached, rejecting session with BUSY status"));
3137 } // TSyncAppBase::checkSessionCount
3142 // factory methods of Rootconfig
3143 // =============================
3146 // Create datatypes registry - default to Multifield-capable version
3147 void TRootConfig::installDatatypesConfig(void)
3149 fDatatypesConfigP = new TMultiFieldDatatypesConfig(this); // default
3150 } // TSyncAppBase::newDatatypesConfig
3153 #ifndef HARDCODED_CONFIG
3155 bool TRootConfig::parseDatatypesConfig(const char **aAttributes, sInt32 aLine)
3157 // currently, only one type of datatype registry exists per app, so we do not
3158 // need to check attributes
3159 expectChildParsing(*fDatatypesConfigP);
3161 } // TRootConfig::parseDatatypesConfig
3166 } // namespace sysync
3170 #ifdef CONFIGURABLE_TYPE_SUPPORT
3172 #ifdef MIMEDIR_SUPPORT
3173 #include "vcarditemtype.h"
3174 #include "vcalendaritemtype.h"
3176 #ifdef TEXTTYPE_SUPPORT
3177 #include "textitemtype.h"
3179 #ifdef DATAOBJ_SUPPORT
3180 #include "dataobjtype.h"
3186 // create new datatype config by name
3187 // returns NULL if none found
3188 TDataTypeConfig *TRootConfig::newDataTypeConfig(const char *aName, const char *aBaseType, TConfigElement *aParentP)
3190 #ifdef MIMEDIR_SUPPORT
3191 if (strucmp(aBaseType,"mimedir")==0)
3192 return new TMIMEDirTypeConfig(aName,aParentP);
3193 else if (strucmp(aBaseType,"vcard")==0)
3194 return new TVCardTypeConfig(aName,aParentP);
3195 else if (strucmp(aBaseType,"vcalendar")==0)
3196 return new TVCalendarTypeConfig(aName,aParentP);
3199 #ifdef TEXTTYPE_SUPPORT
3200 if (strucmp(aBaseType,"text")==0)
3201 return new TTextTypeConfig(aName,aParentP);
3204 #ifdef DATAOBJ_SUPPORT
3205 if (strucmp(aBaseType,"dataobj")==0)
3206 return new TDataObjConfig(aName,aParentP);
3209 return NULL; // unknown basetype
3210 } // TRootConfig::newDataTypeConfig
3213 // create new profile config by name
3214 // returns NULL if none found
3215 TProfileConfig *TRootConfig::newProfileConfig(const char *aName, const char *aTypeName, TConfigElement *aParentP)
3217 // create profiles by name
3218 #ifdef MIMEDIR_SUPPORT
3219 if (strucmp(aTypeName,"mimeprofile")==0)
3220 return new TMIMEProfileConfig(aName,aParentP);
3223 #ifdef TEXTTYPE_SUPPORT
3224 if (strucmp(aTypeName,"textprofile")==0)
3225 return new TTextProfileConfig(aName,aParentP);
3228 return NULL; // unknown profile
3229 } // TRootConfig::newProfileConfig
3231 } // namespace sysync
3238 // only one of XML2GO or SDK/Plugin can be on top of customagent
3239 #ifdef XML2GO_SUPPORT
3240 #include "xml2goapiagent.h"
3241 #elif defined(SDK_SUPPORT)
3242 #include "pluginapiagent.h"
3244 // ODBC can be in-between if selected
3246 #include "odbcapiagent.h"
3252 // Create agent config - default to customImpl based agent
3253 void TRootConfig::installAgentConfig(void)
3255 #if defined(XML2GO_SUPPORT)
3256 fAgentConfigP = new TXml2goAgentConfig(this); // xml2go (eventually on top of ODBC)
3257 #elif defined(SDK_SUPPORT)
3258 fAgentConfigP = new TPluginAgentConfig(this); // plugin/SDK (eventually on top of ODBC)
3259 #elif defined(SQL_SUPPORT)
3260 fAgentConfigP = new TOdbcAgentConfig(this); // ODBC only
3262 fAgentConfigP = NULL; // none
3264 } // TSyncAppBase::installAgentConfig
3267 #ifndef HARDCODED_CONFIG
3269 bool TRootConfig::parseAgentConfig(const char **aAttributes, sInt32 aLine)
3271 const char *typenam = getAttr(aAttributes,"type");
3274 #ifdef XML2GO_SUPPORT
3275 if (strucmp(typenam,"xml2go")==0) parseit=true;
3278 if (strucmp(typenam,"plugin")==0) parseit=true;
3281 if (strucmp(typenam,"odbc")==0 || strucmp(typenam,"sql")==0) parseit=true;
3284 expectChildParsing(*fAgentConfigP);
3287 } // TRootConfig::parseAgentConfig
3292 // Support for SySync Diagnostic Tool
3297 // special RTK instance just for translating WBXML to XML
3300 #define GET_XMLOUTINSTANCE(u) ((InstanceID_t)GET_USERDATA(u))
3302 // SyncML toolkit callback implementations for sysytool debug decoder
3304 // userData must be instance_id of XML instance to generate XML message into
3306 static Ret_t sysytoolStartMessageCallback(InstanceID_t id, VoidPtr_t userData, SmlSyncHdrPtr_t pContent)
3308 // Note: we must find the SyncML version in advance, as fSyncMLVersion is not yet valid here
3310 StrToEnum(SyncMLVerDTDNames,numSyncMLVersions,hdrVers,smlPCDataToCharP(pContent->version));
3311 smlStartMessageExt(GET_XMLOUTINSTANCE(userData),pContent,SmlVersionCodes[hdrVers]);
3315 static Ret_t sysytoolEndMessageCallback(InstanceID_t id, VoidPtr_t userData, Boolean_t final)
3317 smlEndMessage(GET_XMLOUTINSTANCE(userData),final);
3321 static Ret_t sysytoolStartSyncCallback(InstanceID_t id, VoidPtr_t userData, SmlSyncPtr_t pContent)
3323 smlStartSync(GET_XMLOUTINSTANCE(userData),pContent);
3327 static Ret_t sysytoolEndSyncCallback(InstanceID_t id, VoidPtr_t userData)
3329 smlEndSync(GET_XMLOUTINSTANCE(userData));
3334 #ifdef ATOMIC_RECEIVE /* these callbacks are NOT included in the Toolkit lite version */
3336 static Ret_t sysytoolStartAtomicCallback(InstanceID_t id, VoidPtr_t userData, SmlAtomicPtr_t pContent)
3338 smlStartAtomic(GET_XMLOUTINSTANCE(userData),pContent);
3342 static Ret_t sysytoolEndAtomicCallback(InstanceID_t id, VoidPtr_t userData)
3344 smlEndAtomic(GET_XMLOUTINSTANCE(userData));
3350 #ifdef SEQUENCE_RECEIVE
3352 static Ret_t sysytoolStartSequenceCallback(InstanceID_t id, VoidPtr_t userData, SmlSequencePtr_t pContent)
3354 smlStartSequence(GET_XMLOUTINSTANCE(userData),pContent);
3358 static Ret_t sysytoolEndSequenceCallback(InstanceID_t id, VoidPtr_t userData)
3360 smlEndSequence(GET_XMLOUTINSTANCE(userData));
3366 static Ret_t sysytoolAddCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlAddPtr_t pContent)
3368 smlAddCmd(GET_XMLOUTINSTANCE(userData),pContent);
3372 static Ret_t sysytoolAlertCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlAlertPtr_t pContent)
3374 smlAlertCmd(GET_XMLOUTINSTANCE(userData),pContent);
3379 static Ret_t sysytoolDeleteCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlDeletePtr_t pContent)
3381 smlDeleteCmd(GET_XMLOUTINSTANCE(userData),pContent);
3385 static Ret_t sysytoolGetCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlGetPtr_t pContent)
3387 smlGetCmd(GET_XMLOUTINSTANCE(userData),pContent);
3391 static Ret_t sysytoolPutCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlPutPtr_t pContent)
3393 smlPutCmd(GET_XMLOUTINSTANCE(userData),pContent);
3398 static Ret_t sysytoolMapCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlMapPtr_t pContent)
3400 smlMapCmd(GET_XMLOUTINSTANCE(userData),pContent);
3405 #ifdef RESULT_RECEIVE
3406 static Ret_t sysytoolResultsCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlResultsPtr_t pContent)
3408 smlResultsCmd(GET_XMLOUTINSTANCE(userData),pContent);
3413 static Ret_t sysytoolStatusCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlStatusPtr_t pContent)
3415 smlStatusCmd(GET_XMLOUTINSTANCE(userData),pContent);
3419 static Ret_t sysytoolReplaceCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlReplacePtr_t pContent)
3421 smlReplaceCmd(GET_XMLOUTINSTANCE(userData),pContent);
3426 static Ret_t sysytoolCopyCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlCopyPtr_t pContent)
3428 smlCopyCmd(GET_XMLOUTINSTANCE(userData),pContent);
3433 static Ret_t sysytoolMoveCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlMovePtr_t pContent)
3435 smlMoveCmd(GET_XMLOUTINSTANCE(userData),pContent);
3440 static Ret_t sysytoolExecCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlExecPtr_t pContent)
3442 smlExecCmd(GET_XMLOUTINSTANCE(userData),pContent);
3448 #ifdef SEARCH_RECEIVE
3449 static Ret_t sysytoolSearchCmdCallback(InstanceID_t id, VoidPtr_t userData, SmlSearchPtr_t pContent)
3451 smlSearchCmd(GET_XMLOUTINSTANCE(userData),pContent);
3457 static Ret_t sysytoolHandleErrorCallback(InstanceID_t id, VoidPtr_t userData)
3462 static Ret_t sysytoolTransmitChunkCallback(InstanceID_t id, VoidPtr_t userData)
3464 return SML_ERR_INVALID_OPTIONS;
3468 static const SmlCallbacks_t sysyncToolCallbacks = {
3469 /* message callbacks */
3470 sysytoolStartMessageCallback,
3471 sysytoolEndMessageCallback,
3472 /* grouping commands */
3473 sysytoolStartSyncCallback,
3474 sysytoolEndSyncCallback,
3475 #ifdef ATOMIC_RECEIVE /* these callbacks are NOT included in the Toolkit lite version */
3476 sysytoolStartAtomicCallback,
3477 sysytoolEndAtomicCallback,
3479 #ifdef SEQUENCE_RECEIVE
3480 sysytoolStartSequenceCallback,
3481 sysytoolEndSequenceCallback,
3484 sysytoolAddCmdCallback,
3485 sysytoolAlertCmdCallback,
3486 sysytoolDeleteCmdCallback,
3487 sysytoolGetCmdCallback,
3488 sysytoolPutCmdCallback,
3490 sysytoolMapCmdCallback,
3492 #ifdef RESULT_RECEIVE
3493 sysytoolResultsCmdCallback,
3495 sysytoolStatusCmdCallback,
3496 sysytoolReplaceCmdCallback,
3497 /* other commands */
3498 #ifdef COPY_RECEIVE /* these callbacks are NOT included in the Toolkit lite version */
3499 sysytoolCopyCmdCallback,
3502 sysytoolExecCmdCallback,
3504 #ifdef SEARCH_RECEIVE
3505 sysytoolSearchCmdCallback,
3507 sysytoolMoveCmdCallback,
3508 /* Other Callbacks */
3509 sysytoolHandleErrorCallback,
3510 sysytoolTransmitChunkCallback
3511 }; /* sml_callbacks struct */
3515 // WBXML to XML conversion
3516 int wbxmlConv(int argc, const char *argv[])
3520 CONSOLEPRINTF((" wbxml2xml <wbxml binary message file> [<xml output file>]"));
3521 CONSOLEPRINTF((" Converts to XML using SyncML-Toolkit"));
3522 CONSOLEPRINTF((" If no output file is specified, input file name with suffix '.xml' is used"));
3523 return EXIT_SUCCESS;
3526 // check for argument
3527 if (argc<1 || argc>2) {
3528 CONSOLEPRINTF(("1 or 2 arguments required"));
3529 return EXIT_FAILURE;
3533 FILE *inFile = fopen(argv[0],"rb");
3535 CONSOLEPRINTF(("Error opening input file '%s', error=%d",argv[0],errno));
3536 return EXIT_FAILURE;
3539 // prepare a instance for decoding the WBXML
3540 InstanceID_t wbxmlInInstance;
3541 if (!getSyncAppBase()->newSmlInstance(
3543 500*1024, // 500k should be waaaaay enough
3546 CONSOLEPRINTF(("Error creating WBXML parser"));
3547 return EXIT_FAILURE;
3549 // install the sysytool callbacks (default are the normal appbase ones)
3550 smlSetCallbacks(wbxmlInInstance, &sysyncToolCallbacks);
3552 // prepare instance for generating XML output
3553 InstanceID_t xmlOutInstance;
3554 if (!getSyncAppBase()->newSmlInstance(
3556 500*1024, // 500k should be waaaaay enough
3559 CONSOLEPRINTF(("Error creating XML generator"));
3560 return EXIT_FAILURE;
3562 // link output instance as userdata into input instance
3563 getSyncAppBase()->setSmlInstanceUserData(wbxmlInInstance, xmlOutInstance);
3565 // read WBXML original file into workspace
3567 MemSize_t wbxmlBufSiz, wbxmlDataSiz;
3569 rc = smlLockWriteBuffer(wbxmlInInstance, &wbxmlBufP, &wbxmlBufSiz);
3570 if (rc!=SML_ERR_OK) {
3571 CONSOLEPRINTF(("Error getting WBXML buffer, err=%d",rc));
3572 return EXIT_FAILURE;
3574 wbxmlDataSiz = fread(wbxmlBufP,1,wbxmlBufSiz,inFile);
3575 if (wbxmlDataSiz==0) {
3576 CONSOLEPRINTF(("No data in WBXML input file or error, err=%d",errno));
3577 return EXIT_FAILURE;
3580 CONSOLEPRINTF(("Read %ld bytes from WBXML input file '%s'",wbxmlDataSiz,argv[0]));
3581 smlUnlockWriteBuffer(wbxmlInInstance,wbxmlDataSiz);
3585 rc = smlProcessData(wbxmlInInstance, SML_NEXT_COMMAND);
3586 } while (rc==SML_ERR_CONTINUE);
3587 if (rc!=SML_ERR_OK) {
3588 CONSOLEPRINTF(("Error while decoding WBXML document, rc=%d",rc));
3591 CONSOLEPRINTF(("Successfully completed decoding WBXML document"));
3594 // write to output file
3597 outFileName = argv[0];
3599 outFileName = argv[1];
3601 outFileName += ".xml";
3603 FILE *outFile = fopen(outFileName.c_str(),"w");
3605 CONSOLEPRINTF(("Error opening output file '%s', error=%d",outFileName.c_str(),errno));
3606 return EXIT_FAILURE;
3609 MemSize_t xmlDataSiz;
3610 rc = smlLockReadBuffer(xmlOutInstance,&xmlBufP,&xmlDataSiz);
3611 if (rc!=SML_ERR_OK) {
3612 CONSOLEPRINTF(("Error reading decoded XML from converter WBXML document, rc=%d",rc));
3613 return EXIT_FAILURE;
3615 CONSOLEPRINTF(("Writing %ld bytes of XML translation to '%s'",xmlDataSiz,outFileName.c_str()));
3616 fwrite(xmlBufP,1,xmlDataSiz,outFile);
3619 return EXIT_SUCCESS;
3622 #endif // SYSYNC_TOOL
3626 } // namespace sysync