Imported Upstream version 1.0beta3
[platform/upstream/syncevolution.git] / src / synthesis / src / sysync_SDK / Sources / san.cpp
1 /*
2  *  File:         san.cpp
3  *
4  *  Author:                       Beat Forster (bfo@synthesis.ch)
5  *
6  *  Server Alerted Notification
7  *    for OMA DS 1.2
8  *
9  *  Copyright (c) 2005-2009 by Synthesis AG (www.synthesis.ch)
10  *
11  *
12  */
13
14 /*
15                       128 bit     64 bit + n char
16                   +------------+--------------------+--------------------+
17                   |            |                    |                    |
18                   |  digest    |  notification-hdr  |  notification-body |
19                   |            |                    |                    |
20                   +------------+--------------------+--------------------+
21                               /                      \                    \
22                             /                          \ ---------          \
23                           /                              \         \          \
24      --------------------                                  ------    \          \
25    /                                                              \    \          \
26  /                                                                  \    \          \
27 +---------+---------+-----------+--------+---------+--------+--------+    +----------+
28 | version | ui-mode | initiator | future | session | server | server |    |  usage   |
29 |         |         |           |   use  |   id    | ident  | ident  |    | specific |
30 |         |         |           |        |         | length |        |    |          |
31 +---------+---------+-----------+--------+---------+--------+--------+    +----------+
32   10 bit     2 bit      1 bit     27 bit   16 bit     8 bit   n char
33
34
35 H     = MD5 hashing function
36 B64   = Base64 encoding
37 digest= H(B64(H(server-identifier:password)):nonce:B64(H(notification)))
38
39
40
41                 notification body:
42   +-------+--------+--------+--------+----------+
43   |  num  | future | sync 1 | sync N | vendor   |
44   | syncs |   use  |        |        | specific |
45   |       |        |        |        |          |
46   +-------+--------+--------+--------+----------+
47     4 bit  4 bit  /          \          n char
48                 /              \
49      ----------                  -------
50    /                                     \
51  /                                         \
52 +------+--------+---------+--------+--------+
53 | sync | future | content | server | server |
54 | type | use    | type    | URI    | URI    |
55 |      |        |         | length |        |
56 +------+--------+---------+--------+--------+
57  4 bit   4 bit    24 bit    8 bit    n char
58
59 */
60
61
62 #ifdef HAVE_CONFIG_H
63 # include <config.h>
64 #endif
65
66 #include "prefix_file.h"
67 #include "sync_include.h"
68 #include "san.h"
69 #include "sysync_md5.h"
70 #include "sysync_b64.h"
71
72 #ifndef WITHOUT_SAN_1_1
73 #include "sysync_utils.h"
74 #endif
75
76
77 const uInt16 SyncML12 = 12;   // currently supported SyncML version
78 const uInt16 SyncML11 = 11;   // currently supported SyncML version
79 const uInt16 SyncML10 = 10;   // currently supported SyncML version
80
81 #pragma options align= packed // allow direct mapping of the structure
82
83
84 using namespace sysync;
85
86 namespace sysync {
87
88 // ---- structure definition ---------------------------------------------
89 #define BpB        8 // bits per byte
90 #define NBits      7 // bytes of the notification-hdr  bits
91 #define BBits      4 // bytes of the notification-body bits
92
93 #define DB_Full  420 // memory full error
94 #define DB_Error 510 // general DB error
95
96 struct TPackage {
97   TDigestField digest;
98
99   uInt8  bitField[ NBits ]; // version, ui-mode, initiator, future use, sesion id
100   uInt8  serverID_len;
101 }; // TPackage
102
103
104 struct TBody {
105   uInt8  bitField[ BBits ]; // sync type, future use, content type
106   uInt8  serverURI_len;
107 }; // TBody
108
109
110
111 // ---- defined locally for the moment to avoid dependencies ----
112 //
113 // MD5 and B64 given string
114 static void MD5B64_Local(const char *aString, sInt32 aLen, string &aMD5B64)
115 {
116   // determine input length
117   if (aLen<=0) aLen=strlen(aString);
118   // calc MD5
119   md5::SYSYNC_MD5_CTX context;
120   uInt8 digest[16];
121   md5::Init (&context);
122   md5::Update (&context, (const uInt8 *)aString,aLen);
123   md5::Final (digest, &context);
124   // b64 encode the MD5 digest
125   uInt32 b64md5len;
126   char *b64md5=b64::encode(digest,16,&b64md5len);
127   // assign result
128   aMD5B64.assign(b64md5,b64md5len);
129   // done
130   b64::free(b64md5); // return buffer allocated by b64::encode
131 } // MD5B64_Local
132
133
134
135 // ---- constructor/destructor -------------------------------------------
136 SanPackage::SanPackage() // constructor
137 {
138   fBody= NULL;
139   CreateEmptyNotificationBody();
140
141   memset( &fDigest, 0, DigestSize );
142   fProtocolVersion= 0;
143   fUI_Mode        = UI_not_specified;
144   fInitiator      = Initiator_Server;
145   fSessionID      = 0;
146
147   fSan            = NULL;
148   fSanSize        = 0;
149 } // constructor
150
151
152 SanPackage::~SanPackage() // destructor
153 {
154   ReleasePackage();
155   ReleaseNotificationBody();
156 } // destructor
157
158
159
160 // ---- digest creation --------------------------------------------------
161 TDigestField SanPackage::H( string s )
162 {
163   TDigestField df;
164
165   // calc MD5
166   md5::SYSYNC_MD5_CTX context;
167   md5::Init        ( &context );
168   md5::Update      ( &context, (const uInt8 *)s.c_str(), s.length() );
169   md5::Final( df.b,  &context );
170   return      df;
171 } // DigestField
172
173
174 string SanPackage::B64_H( string s1, string s2 )
175 {
176   if          (!s2.empty()) s1+= ":" + s2;
177   MD5B64_Local( s1.c_str(), s1.size(), s1 );
178   return        s1;
179 } // B64_H
180
181
182 string SanPackage::B64_H_Notification( void* san, size_t sanSize )
183 {
184   string                    s;
185   const char*   v= (const char*)san + DigestSize;
186   size_t           nfySize= sanSize - DigestSize;
187   MD5B64_Local( v, nfySize, s );
188   return                    s;
189 } // B64_H
190
191
192
193 /*! Prepare the SAN record */
194 void SanPackage::PreparePackage( string    aB64_H_srvID_pwd,
195                                  string    aNonce,
196                                  uInt16    aProtocolVersion,
197                                  UI_Mode   aUI_Mode,
198                                  Initiator aInitiator,
199                                  uInt16    aSessionID,
200                                  string    aSrvID )
201 {
202   fB64_H_srvID_pwd= aB64_H_srvID_pwd;
203   fNonce          = aNonce;
204   fProtocolVersion= aProtocolVersion;
205   fUI_Mode        = aUI_Mode;
206   fInitiator      = aInitiator;
207   fSessionID      = aSessionID;
208   fServerID       = aSrvID;
209 } // PreparePackage
210
211
212 // if only hashes are available
213 TSyError SanPackage::CreateDigest( const char* b64_h_serverID_password,
214                                    const char* aNonce,
215                                    void* san, size_t sanSize )
216 {
217   string s= b64_h_serverID_password;
218   if   ( s.empty()) {
219     for (int i= 0; i<DigestSize; i++) { // special case for empty digest
220       fDigest.b[ i ]= 0x00;
221     } // for
222   }
223   else {                    s+= ":";
224                 s+= aNonce; s+= ":";
225                 s+= B64_H_Notification( san,sanSize );
226     fDigest= H( s );
227   } // if
228
229   return LOCERR_OK;
230 } // CreateDigest
231
232
233 TSyError SanPackage::CreateDigest( const char* aServerID,
234                                    const char* aPassword,
235                                    const char* aNonce,
236                                    void* san, size_t sanSize )
237 {
238   return CreateDigest( B64_H( aServerID,aPassword ).c_str(),
239                        aNonce,
240                        san,sanSize );
241 } // CreateDigest
242
243
244
245 bool SanPackage::DigestOK( void* san )
246 {
247   TDigestField* sanD= (TDigestField*)san;
248
249   for (int i= 0; i<DigestSize; i++) {
250     if (fDigest.b[ i ]!=sanD->b[ i ]) return false;
251   } // for
252
253   return true;
254 } // DigestOK
255
256
257
258 // ---- bit operations ---------------------------------------------------
259 void SanPackage::AddBits( void* ptr, int pos, int n, uInt32 value )
260 {
261   byte* b= (byte*)ptr;
262   int    lim= pos+n;
263   if    (lim>BpB*NBits) return; // check if within the field
264   while (lim>BpB) { b++; lim-= BpB; }
265
266   int  i;
267   for (i=0; i<n; i++) {
268     uInt8 db= 1<<(BpB-lim);
269
270     if   ((value % 2)==1) *b|=  db; // add    bit
271     else                  *b&= ~db; // remove bit
272     value= value / 2;
273
274         lim--;
275     if (lim==0) { lim= BpB; b--; }
276   } // for
277 } // AddBits
278
279
280 uInt32 SanPackage::GetBits( void* ptr, int pos, int n )
281 {
282   uInt32 value= 0;
283
284   byte* b= (byte*)ptr;
285   int    lim= pos+n;
286   if    (lim>BpB*NBits) return 0; // check if within the field
287   while (lim>BpB) { b++; lim-= BpB; }
288
289   int  i;
290   for (i=0; i<n; i++) {
291     uInt8 db= 1<<(BpB-lim);
292
293     if ((*b & db)!=0) value|= (1<<n); // check bit and add it to <value>
294     value= value / 2;
295
296         lim--;
297     if (lim==0) { lim= BpB; b--; }
298   } // for
299
300   return value;
301 } // GetBits
302
303
304
305 // ---- notification body generation -------------------------------------
306 void SanPackage::CreateEmptyNotificationBody()
307 {
308   ReleaseNotificationBody();
309
310                     fEmpty= 0x00; // no sync fields = ALL data stores concerned
311   fBody=           &fEmpty;
312   fBodySize= sizeof(fEmpty);
313   fNSync= 0;
314 } // CreateEmptyNotificationBody
315
316
317
318 TSyError SanPackage::AddSync( int syncType, uInt32 contentType,
319                               const char* serverURI )
320 {
321   int    len= strlen(serverURI);
322   int   nLen= BBits + 1 +  len;  // length of the new part
323   int newLen= fBodySize + nLen;  // total length of the new block
324
325   void*   fb=  malloc( newLen ); // allocate it
326   memcpy( fb, fBody,fBodySize ); // copy existing structure to beginning
327
328   byte*   b = (byte*)fb;
329           b+= fBodySize;         // get a pointer to the new part
330
331   ReleaseNotificationBody();     // release the old structure
332   fNSync++;                      // adapt number of available parts
333   fBody    = fb;                 // now the new bigger structure is assigned
334   fBodySize= newLen;
335
336   // fill in new counter value
337   AddBits( fBody,         0, 4, fNSync       ); // number of sync datastores
338   AddBits( fBody,         4, 4, 0            ); // future use
339
340   // fill in contents of the nth structure
341   TBody*   tb= (TBody*)b;
342   AddBits( tb->bitField,  0, 4, syncType-200 ); // the sync type 206..210
343   AddBits( tb->bitField,  4, 4, 0            ); // future use
344   AddBits( tb->bitField,  8,24, contentType  ); // the content tye
345            tb->serverURI_len=   len;
346
347   byte*           pp= (byte*)(tb+1); // = right after TBody
348   memcpy( (void*) pp, (void*)serverURI, len );
349   return LOCERR_OK;
350 } // AddSync
351
352
353
354 void SanPackage::ReleaseNotificationBody()
355 {
356   if (fBody!=NULL &&
357       fBody!=&fEmpty) { free( fBody ); fBody= NULL; }
358 } // ReleaseNotificationBody
359
360
361 #ifndef WITHOUT_SAN_1_1
362 // general callback entry for all others
363 static Ret_t univ( ... )
364 {
365 //printf( "callback\n" );
366   return 0;
367 } // univ
368
369
370 static Ret_t startM( InstanceID_t id, VoidPtr_t userData, SmlSyncHdrPtr_t pContent )
371 {
372   cAppCharP Sy= "SyncML/";
373   size_t n = strlen(Sy);
374
375   SanPackage* a= (SanPackage*)userData;
376   string mup  = "";
377   string nonce= "";
378
379   uInt16 major=0,minor=0;
380
381   cAppCharP verP = smlPCDataToCharP(pContent->proto);
382   if (strucmp(verP,Sy,n)==0) {
383     n+=StrToUShort(verP+n,major);
384     if (verP[n]=='.') {
385       n++;
386       StrToUShort(verP+n,minor);
387     }
388   }
389
390   sInt32                                sessionID;
391   smlPCDataToLong( pContent->sessionID, sessionID );
392
393   string srvID= smlSrcTargLocURIToCharP(pContent->source);
394
395   a->PreparePackage( mup, nonce, 10*major+minor, UI_not_specified, Initiator_Server, sessionID, srvID );
396   a->CreateEmptyNotificationBody();
397   return 0;
398 } // startM
399
400
401 static Ret_t alertM( InstanceID_t id, VoidPtr_t userData, SmlAlertPtr_t pContent )
402 {
403   SanPackage* a= (SanPackage*)userData;
404
405   sInt32                           syncType;
406   smlPCDataToLong( pContent->data, syncType );
407   uInt32 contentType= 0; // always 0
408
409   SmlItemListPtr_t el= pContent->itemList;
410
411   while (true) { // can be a chained list of elements
412     string locURI= smlSrcTargLocURIToCharP(el->item->source);
413     a->AddSync( syncType, contentType, locURI.c_str() ); // for each element add one
414
415     if (el->next==NULL) break;
416     el= el->next;
417   } // while
418
419 //printf( "alert\n" );
420   return 0;
421 } // alert
422
423
424 static Ret_t endM( InstanceID_t id, VoidPtr_t userData, Boolean_t final )
425 {
426 //printf( "end\n" );
427   return 0;
428 } // endM
429
430
431 // Callback record, most of the routines are not used
432 static const SmlCallbacks_t mySmlCallbacks = {
433   /* message callbacks */
434   startM,                    // smlStartMessageCallback,
435   endM,                      // smlEndMessageCallback,
436   /* grouping commands */
437   (smlStartSyncFunc)   univ, // smlStartSyncCallback,
438   (smlEndSyncFunc)     univ, // smlEndSyncCallback,
439   #ifdef ATOMIC_RECEIVE  /* these callbacks are NOT included in the Toolkit lite version */
440     univ, // smlStartAtomicCallback,
441     univ, // smlEndAtomicCallback,
442   #endif
443   #ifdef SEQUENCE_RECEIVE
444     univ, // smlStartSequenceCallback,
445     univ, // smlEndSequenceCallback,
446   #endif
447   /* Sync Commands */
448   (smlAddCmdFunc)   univ, // smlAddCmdCallback,
449   alertM,                 // smlAlertCmdCallback,
450   (smlDeleteCmdFunc)univ, // smlDeleteCmdCallback,
451   (smlGetCmdFunc)   univ, // smlGetCmdCallback,
452   (smlPutCmdFunc)   univ, // smlPutCmdCallback,
453   #ifdef MAP_RECEIVE
454     (smlMapCmdFunc) univ, // smlMapCmdCallback,
455   #endif
456   #ifdef RESULT_RECEIVE
457     (smlResultsCmdFunc)univ, // smlResultsCmdCallback,
458   #endif
459   (smlStatusCmdFunc) univ, // smlStatusCmdCallback,
460   (smlReplaceCmdFunc)univ, // smlReplaceCmdCallback,
461   /* other commands */
462   #ifdef COPY_RECEIVE  /* these callbacks are NOT included in the Toolkit lite version */
463     univ, // smlCopyCmdCallback,
464   #endif
465   #ifdef EXEC_RECEIVE
466     univ, // smlExecCmdCallback,
467   #endif
468   #ifdef SEARCH_RECEIVE
469     univ, // smlSearchCmdCallback,
470   #endif
471   smlMoveCmdFunc(univ), // smlMoveCmdCallback,
472   /* Other Callbacks */
473   smlHandleErrorFunc  (univ), // smlHandleErrorCallback,
474   smlTransmitChunkFunc(univ)  // smlTransmitChunkCallback
475 }; /* sml_callbacks struct */
476
477
478
479 // Try to convert a 1.1 message
480 // - if successful, fill in values into 1.2 fields
481 // - if not successful, interpret it as 1.2 structure
482 TSyError SanPackage::Check_11( void* san, size_t sanSize )
483 {
484   TSyError             err;
485   SmlCallbacks_t       scb= mySmlCallbacks;
486   SmlInstanceOptions_t sIOpts;
487   InstanceID_t         id;
488   Ret_t                cer;
489   MemPtr_t             wPos;
490   MemSize_t            freeSize;
491
492   // struct assignment / 1k buffer
493   sIOpts.encoding       = SML_WBXML; // it is always WBXML
494   sIOpts.workspaceSize  = 1024*30;      // should be always sufficient
495   sIOpts.maxOutgoingSize=    0;      // disabled for now
496
497   err=   smlInitInstance( &scb, &sIOpts, this, &id );  if (err) return err;
498
499   do {
500     err= smlLockWriteBuffer  ( id, &wPos, &freeSize ); if (err) break;
501
502     memcpy( wPos, san,sanSize ); // now we have a new internal copy
503     err= smlUnlockWriteBuffer( id, sanSize );          if (err) break;
504     err= smlProcessData      ( id, SML_ALL_COMMANDS ); if (err) break;
505   } while (false);
506
507   cer= smlTerminateInstance( id ); if (!err) err= cer;
508
509   return err;
510 } // Check_11
511 #endif // WITHOUT_SAN_1_1
512
513
514 TSyError SanPackage::PassSan( void* san, size_t sanSize, int mode)
515 {
516   TSyError err = LOCERR_OK;
517   bool     use_as_12= true;
518
519   ReleasePackage();
520 //printf( "here we will have the potential 1.1 -> 1.2 conversion\n" );
521
522   #ifndef WITHOUT_SAN_1_1
523   if (mode == 0 || mode == 1) {
524       err= Check_11  ( san,sanSize );
525       if (!err)  err= GetPackage( san,sanSize );
526       //use_as_12= err==SML_ERR_XLT_INCOMP_WBXML_VERS;
527       use_as_12= err!=0;
528       //printf( "err=%d\n", err );
529   }
530 #endif
531
532   if (use_as_12 && mode !=1) {
533     err= DB_Full;
534
535         fSan=   malloc( sanSize );
536     if (fSan) {
537       fSanSize=         sanSize;
538       memcpy( fSan, san,sanSize ); // now we have a new internal copy
539       err= LOCERR_OK;
540     } // if
541   } // if
542
543   return err;
544 } // PassSan
545
546
547 TSyError SanPackage::GetSanSize( void* san, size_t &sanSize )
548 {
549   TPackage* tp= (TPackage*)san;
550   TBody*    tb = NULL;
551
552   byte* b= (byte*)(tp+1);
553   byte* v;
554
555   b+= tp->serverID_len;
556
557   int nth= GetBits( b, 0,4 ); // first not valid = the end
558
559   b++; // start of 1st element
560   int    n= nth;
561   while (n>0) {
562     n--;
563     tb= (TBody*)b;
564     b = (byte*)(tb+1);
565
566     if (b > (byte*)san+sanSize && sanSize>0) return DB_Forbidden;
567     v=  b + tb->serverURI_len;
568     if (b > (byte*)san+sanSize && sanSize>0) return DB_Forbidden;
569
570     if (n==0) break;
571     b=  v;
572   } // while
573
574   b+= tb->serverURI_len; // finally the serverURI length
575
576   size_t   rslt= b - (byte*)san;
577   if (sanSize>0 && sanSize<rslt) return DB_Forbidden;
578
579   sanSize= rslt;
580   return LOCERR_OK;
581 } // GetSanSize
582
583
584 // ---- notification body parsing ----------------------------------------
585 TSyError SanPackage::GetNthSync( int    nth,
586                                  int    &syncType,
587                                  uInt32 &contentType,
588                                  string &serverURI )
589 {
590   syncType   =  0; // set default values
591   contentType=  0;
592   serverURI  = "";
593
594   TPackage* tp= (TPackage*)fSan;
595   TBody*    tb;
596
597   fDigest         =                     tp->digest;
598   fProtocolVersion=            GetBits( tp->bitField,  0,10 );
599   fUI_Mode        =   (UI_Mode)GetBits( tp->bitField, 10, 2 );
600   fInitiator      = (Initiator)GetBits( tp->bitField, 12, 1 );
601   fSessionID      =            GetBits( tp->bitField, 40,16 );
602
603   /*If the version does not match, this should be an invalid SAN message*/
604   if (fProtocolVersion!=SyncML12 &&
605       fProtocolVersion!=SyncML11 &&
606       fProtocolVersion!=SyncML10) return DB_Forbidden;
607
608   byte* b= (byte*)(tp+1);
609   byte* v;
610
611   fServerID.assign( (const char*)b,(unsigned int)tp->serverID_len );
612   b+= tp->serverID_len;
613
614   fNSync= GetBits( b, 0,4 );
615
616   if (nth==0)               return LOCERR_OK;
617   if (nth<1 || nth>fNSync ) return DB_NotFound;
618
619   b++; // start of 1st element
620   int    n= nth;
621   while (n>0) {
622     n--;
623     tb= (TBody*)b;
624     b = (byte*)(tb+1);
625
626     if (b > (byte*)fSan+fSanSize) return DB_Forbidden; // no access behind the message
627     v=  b + tb->serverURI_len;
628     if (v > (byte*)fSan+fSanSize) return DB_Forbidden; // no access behind the message
629
630     if (n==0) break;
631     b=  v;
632   } // while
633
634   syncType   = 200 + GetBits( tb->bitField,  0, 4 );
635   contentType=       GetBits( tb->bitField,  8,24 );
636
637   serverURI.assign( (const char*)b,(unsigned int)tb->serverURI_len );
638
639   return LOCERR_OK;
640 } // GetNthSync
641
642
643 TSyError SanPackage::GetHeader()
644 {
645   int    syncType; // these 3 variables are not really used
646   uInt32 contentType;
647   string serverURI;
648
649   return GetNthSync( 0, syncType,contentType,serverURI );
650 } // GetHeader
651
652
653
654 // ---- package generation -----------------------------------------------
655 TSyError SanPackage::GetPackage( void* &san, size_t &sanSize,
656                                  void*  vendorSpecific,
657                                  size_t vendorSpecificSize )
658 {
659   ReleasePackage(); // remove a previous one
660
661   byte   len    = (byte)fServerID.length();     // calulate the full size
662          sanSize= sizeof(TPackage) + len + fBodySize + vendorSpecificSize;
663   //size_t nfySize= sanSize - DigestSize;
664   fSan          = malloc( sanSize );
665   san           =            fSan;
666   TPackage*   tp= (TPackage*)fSan;
667
668   // -------------------
669   AddBits( tp->bitField,  0,10, fProtocolVersion );
670   AddBits( tp->bitField, 10, 2, fUI_Mode         );
671   AddBits( tp->bitField, 12, 1, fInitiator       );
672   AddBits( tp->bitField, 13,27, 0                ); // future use, must be "0"
673   AddBits( tp->bitField, 40,16, fSessionID       );
674            tp->serverID_len=    len;
675
676   // copy <fServerID> string at the end of TPackage struct
677   byte*           pp= (byte*)(tp+1); // = right after TPackage
678   memcpy( (void*) pp,      (void*)fServerID.c_str(), len );
679   memcpy( (void*)(pp+len),        fBody,       fBodySize );
680
681   if (vendorSpecific!=NULL &&
682       vendorSpecificSize>0)
683     memcpy( (void*)(pp+len+fBodySize), vendorSpecific,vendorSpecificSize );
684
685   CreateDigest( fB64_H_srvID_pwd.c_str(), fNonce.c_str(), san,sanSize );
686   tp->digest= fDigest;
687
688   fSanSize= sanSize;
689   return LOCERR_OK;
690 } // GetPackage
691
692
693 void SanPackage::ReleasePackage() {
694   if (fSan!=NULL) { free( fSan ); fSan= NULL; }
695 } // ReleasePackage
696
697 #ifndef WITHOUT_SAN_1_1
698
699 const char * const SyncMLVerProtoNames[] = 
700 {
701     "undefined",
702     "SyncML/1.0",
703     "SyncML/1.1",
704     "SyncML/1.2"
705 };
706
707 const char *const SyncMLVerDTDNames[] =
708 {
709     "???",
710     "1.0",
711     "1.1",
712     "1.2"
713 };
714
715 const SmlVersion_t SmlVersionCodes[] =
716 {
717     SML_VERS_UNDEF,
718     SML_VERS_1_0,
719     SML_VERS_1_1,
720     SML_VERS_1_1
721 };
722
723 TSyError SanPackage::GetPackageLegacy( void* &san,
724                                        size_t &sanSize,
725                                        const vector<pair <string, string> >& sources,
726                                        int alertCode,
727                                        bool wbxml)
728 {
729   ReleasePackage(); // remove a previous one
730   TSyError err;
731   SmlCallbacks_t       scb= mySmlCallbacks;
732   SmlInstanceOptions_t sIOpts;
733   InstanceID_t         id;
734
735
736   // struct assignment / 1k buffer
737   sIOpts.encoding       = wbxml ? SML_WBXML : SML_XML;
738   sIOpts.workspaceSize  = 1024;      // should be always sufficient
739   sIOpts.maxOutgoingSize=    0;      // disabled for now
740
741   err=   smlInitInstance( &scb, &sIOpts, this, &id );  if (err) return err;
742
743   SmlSyncHdrPtr_t headerP = NULL;
744   SmlAlertPtr_t alertP = NULL;
745
746   do {
747     SYSYNC_TRY{
748       //create SyncHdr
749       headerP = SML_NEW (SmlSyncHdr_t);
750       headerP->elementType = SML_PE_HEADER;
751       if (fProtocolVersion != 10 && fProtocolVersion != 11){
752           //wrong version!
753           err = DB_Error;
754           break;
755       }
756       int version = fProtocolVersion - 10 + 1;
757       headerP->version = newPCDataString (SyncMLVerDTDNames[version]);
758       headerP->proto = newPCDataString (SyncMLVerProtoNames[version]);
759       headerP->sessionID = newPCDataLong (fSessionID);
760       headerP->msgID = newPCDataString ("1");
761       headerP->target = newLocation ("/", "");
762       headerP->source = newLocation (fServerID.c_str(), "");
763       headerP->respURI = NULL;
764       headerP->meta = NULL;
765       headerP->flags = 0;
766       //TODO generate the cred element for authentication
767       headerP->cred = NULL;
768
769       //create SyncMessage
770       err = smlStartMessageExt (id, headerP, SmlVersionCodes[version]); if (err) break;
771       //create Alert Commands
772       //internal Alert element 
773       alertP = SML_NEW (SmlAlert_t);
774       alertP->elementType = SML_PE_ALERT;
775       alertP->cmdID = newPCDataLong(1);
776       alertP->flags = 0;
777       alertP->data = newPCDataLong (alertCode);
778       alertP->cred = NULL;
779       alertP->itemList = NULL;
780       alertP->flags = 0;
781
782       //for each source, add a item
783       for (unsigned int num =0; num < sources.size(); num++) {
784           SmlItemPtr_t alertItemP = newItem();
785           alertItemP->source = newOptLocation (sources[num].second.c_str());
786           alertItemP->meta = newMetaType (sources[num].first.c_str());
787           addItemToList (alertItemP, &alertP->itemList);
788       }
789
790       err = smlAlertCmd (id, alertP); if (err) break;
791       err = smlEndMessage (id, true); if (err) break;
792
793       MemPtr_t buf = NULL;
794       err = smlLockReadBuffer (id, (MemPtr_t *) &buf, (MemSize_t *)&sanSize); if (err) break;
795       fSan          = malloc( sanSize ); if (!fSan) {err = DB_Full; break;}
796       san = fSan;
797       memcpy (san, buf, sanSize);
798       err = smlUnlockReadBuffer (id, sanSize); if (err) break;
799       } SYSYNC_CATCH (...)
800       if  (headerP) {
801           smlFreeProtoElement (headerP);
802           headerP = NULL;
803       }
804       if (alertP) {
805           smlFreeProtoElement (alertP);
806           alertP = NULL;
807       }
808       err = DB_Full;
809       SYSYNC_ENDCATCH
810   } while (false);
811   if  (headerP) {
812       smlFreeProtoElement (headerP);
813   }
814   if (alertP) {
815       smlFreeProtoElement (alertP);
816   }
817   if (err) return err;
818
819   err = smlTerminateInstance( id );
820   return err;
821 }
822 #endif
823
824 } // namespace sysync
825
826 // eof