File: | libsynthesis/src/sysync/synccommand.cpp |
Warning: | line 2532, column 9 Value stored to 'processitem' is never read |
1 | /* |
2 | * File: SyncCommand.cpp |
3 | * |
4 | * Author: Lukas Zeller (luz@plan44.ch) |
5 | * |
6 | * TSmlCommand, TXXXCmd.... |
7 | * Wrapper classes for SyncML Commands and the associated SyncML |
8 | * Toolkit mechanics. |
9 | * |
10 | * Copyright (c) 2001-2011 by Synthesis AG + plan44.ch |
11 | * |
12 | * 2001-05-30 : luz : created |
13 | * |
14 | */ |
15 | |
16 | // includes |
17 | #include "prefix_file.h" |
18 | |
19 | #include "synccommand.h" |
20 | #include "syncsession.h" |
21 | |
22 | // %%%% debug hack switch |
23 | //#define DEBUG_XMLRESPONSE_FOR_WBXML 1 |
24 | //#undef DEBUG_XMLRESPONSE_FOR_WBXML |
25 | |
26 | // Status for Results is not needed according to SyncML 1.0.1 |
27 | // specs but 9210 seems to need it. |
28 | // Note: future versions of the standard will require |
29 | // status for all commands, so this is going to be the default |
30 | #define RESULTS_SENDS_STATUS1 1 |
31 | |
32 | // Map statuses are sent immediately, even if they will be part |
33 | // of sync-updates-to-client package (instead of map-acknowledge) |
34 | // This seems to be the normal case |
35 | #define MAP_STATUS_IMMEDIATE1 1 |
36 | |
37 | |
38 | #ifndef SYNCCOMMAND_PART1_EXCLUDE |
39 | |
40 | using namespace sysync; |
41 | |
42 | namespace sysync { |
43 | void TSmlCommandPContainerClear(TSmlCommandPContainer &aContainer) |
44 | { |
45 | while (!aContainer.empty()) { |
46 | delete aContainer.front(); |
47 | aContainer.pop_front(); |
48 | } |
49 | } |
50 | } |
51 | |
52 | /* command name list, used for cmdRef */ |
53 | |
54 | const char * const SyncCommandNames[numSmlCommandTypes] = { |
55 | "SyncHdr", |
56 | "Sync", |
57 | "Sync", // note this is actually SyncEnd, but as we send this as cmdRef, it MUST be named "Sync" as well |
58 | "Add", |
59 | "Alert", |
60 | "Delete", |
61 | "Get", |
62 | "Put", |
63 | "Map", |
64 | "Results", |
65 | "Status", |
66 | "Replace", |
67 | "Copy", |
68 | "Move", |
69 | "Sequence", |
70 | "Atomic", |
71 | "[unknown]" |
72 | }; |
73 | |
74 | |
75 | /* |
76 | * Implementation of TSmlCommand |
77 | */ |
78 | |
79 | /* public TSmlCommand members */ |
80 | |
81 | |
82 | // base constructor (to be called by all derived constructors) |
83 | TSmlCommand::TSmlCommand( |
84 | TSmlCommandTypes aCmdType, // the command type |
85 | bool aOutgoing, // set if this is a outgoing command (to avoid confusion) |
86 | TSyncSession *aSessionP, // associated session (for callbacks) |
87 | uInt32 aMsgID // (optional, for receiving only) the Message ID of the command |
88 | ) |
89 | { |
90 | // save info |
91 | fCmdType=aCmdType; |
92 | fMsgID=aMsgID; |
93 | fSessionP=aSessionP; |
94 | fOutgoing=aOutgoing; |
95 | // init |
96 | fWaitingForStatus=0; // not yet waiting for any statuses |
97 | fCmdID=0; // no ID yet, will be either set at issue() or read at StartProcessing() |
98 | fNoResp=false; // respond by default |
99 | fDontSend=false; // send by default |
100 | fEvalMode=false; // no eval |
101 | fPrepared=false; |
102 | fAllowFailure=false; |
103 | // debug |
104 | DEBUGPRINTFX(DBG_PROTO,("Created command '%s' (%s)", getName(), fOutgoing ? "outgoing" : "incoming")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Created command '%s' (%s)" , getName(), fOutgoing ? "outgoing" : "incoming"); }; |
105 | } // TSmlCommand::TSmlCommand |
106 | |
107 | |
108 | // get name of command |
109 | const char *TSmlCommand::getName(void) |
110 | { |
111 | return SyncCommandNames[fCmdType]; |
112 | } // TSmlCommand::getName |
113 | |
114 | |
115 | #ifdef SYDEBUG2 |
116 | TDebugLogger *TSmlCommand::getDbgLogger(void) |
117 | { |
118 | // commands log to session's logger |
119 | return fSessionP ? fSessionP->getDbgLogger() : NULL__null; |
120 | } // TSmlCommand::getDbgLogger |
121 | |
122 | uInt32 TSmlCommand::getDbgMask(void) |
123 | { |
124 | if (!fSessionP) return 0; // no session, no debug |
125 | return fSessionP->getDbgMask(); |
126 | } // TSmlCommand::getDbgMask |
127 | #endif |
128 | |
129 | |
130 | TSyncAppBase *TSmlCommand::getSyncAppBase(void) |
131 | { |
132 | return fSessionP ? fSessionP->getSyncAppBase() : NULL__null; |
133 | } // TSmlCommand::getSyncAppBase |
134 | |
135 | |
136 | // get name of certain command |
137 | const char *TSmlCommand::getNameOf(TSmlCommandTypes aCmdType) |
138 | { |
139 | return SyncCommandNames[aCmdType]; |
140 | } // TSmlCommand::getNameOf |
141 | |
142 | |
143 | // start processing a command |
144 | void TSmlCommand::StartProcessing( |
145 | SmlPcdataPtr_t aCmdID, // ID of command |
146 | Flag_t aFlags // flags of command |
147 | ) |
148 | { |
149 | // get command ID |
150 | StrToULong(smlPCDataToCharP(aCmdID),fCmdID); |
151 | // get noResp state |
152 | fNoResp=(aFlags & SmlNoResp_f0x0100)!=0; |
153 | PDEBUGPRINTFX(DBG_HOT,("Started processing Command '%s' (incoming MsgID=%ld, CmdID=%ld)%s",getName(),(long)fMsgID,(long)fCmdID,fNoResp ? ", noResp" : "")){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Started processing Command '%s' (incoming MsgID=%ld, CmdID=%ld)%s" ,getName(),(long)fMsgID,(long)fCmdID,fNoResp ? ", noResp" : "" ); }; |
154 | } // TSmlCommand::StartProcessing |
155 | |
156 | |
157 | |
158 | // - Prepare for issuing, evaluate size of command |
159 | sInt32 TSmlCommand::evalIssue( |
160 | uInt32 aAsCmdID, // command ID to be used |
161 | uInt32 aInMsgID, // message ID in which command is being issued |
162 | bool aNoResp // issue without wanting response |
163 | ) |
164 | { |
165 | MemSize_t res; |
166 | bool ok; |
167 | |
168 | fPrepared=false; // force re-prepare |
169 | |
170 | // start evaluation run |
171 | smlStartEvaluation(fSessionP->getSmlWorkspaceID()); |
172 | |
173 | fEvalMode=true; |
174 | SYSYNC_TRYtry { |
175 | // - call issue to get size |
176 | ok=issue(aAsCmdID,aInMsgID,aNoResp); |
177 | // - back to normal mode |
178 | fEvalMode=false; |
179 | smlEndEvaluation(fSessionP->getSmlWorkspaceID(),&res); |
180 | if (!ok) res=-1; // no room, error |
181 | /* %%% hack to force unsendable-sized syncop commands: |
182 | #ifdef RELEASE_VERSION |
183 | #error "%%%%remove this debuh hack!!!" |
184 | #endif |
185 | if (dynamic_cast<TSyncOpCommand *>(this)!=NULL) { |
186 | // always oversized |
187 | res=0; |
188 | } |
189 | */ |
190 | } |
191 | SYSYNC_CATCH (...)catch(...) { |
192 | fEvalMode=false; |
193 | smlEndEvaluation(fSessionP->getSmlWorkspaceID(),&res); |
194 | SYSYNC_RETHROWthrow; |
195 | SYSYNC_ENDCATCH} |
196 | |
197 | // return available space after sending this command |
198 | return res; |
199 | } // TSmlCommand::evalIssue |
200 | |
201 | |
202 | |
203 | void TSmlCommand::PrepareIssue( |
204 | SmlPcdataPtr_t *aCmdID, // ID of command |
205 | Flag_t *aFlags // flags of command |
206 | ) |
207 | { |
208 | if (!fPrepared) { |
209 | fPrepared=true; |
210 | // set Command ID |
211 | if (aCmdID) { |
212 | // remove old |
213 | if (*aCmdID) smlFreePcdata(*aCmdID); |
214 | // create new |
215 | *aCmdID=newPCDataLong(fCmdID); |
216 | } |
217 | // add NoResp flag if requested |
218 | if (aFlags) |
219 | *aFlags |= fNoResp ? SmlNoResp_f0x0100 : 0; |
220 | } |
221 | if (!fEvalMode) { |
222 | #ifdef SYDEBUG2 |
223 | if (aCmdID) { |
224 | if (*aCmdID==NULL__null) |
225 | SYSYNC_THROW(TSyncException("No Command ID set at evalIssue() but requested one at issue()"))throw TSyncException("No Command ID set at evalIssue() but requested one at issue()" ); |
226 | } |
227 | #endif |
228 | // save workspace size immediately before sending to calc message size |
229 | fBytesbefore=fSessionP->getSmlWorkspaceFreeBytes(); |
230 | #ifdef DEBUG_XMLRESPONSE_FOR_WBXML |
231 | // %%% debug hack %%% force output to be XML |
232 | smlSetEncoding(fSessionP->getSmlWorkspaceID(),SML_XML); |
233 | #endif |
234 | } |
235 | } // TSmlCommand::PrepareIssue |
236 | |
237 | |
238 | #ifndef USE_SML_EVALUATION1 |
239 | |
240 | // get (approximated) message size required for sending it |
241 | uInt32 TSmlCommand::messageSize(void) |
242 | { |
243 | // default, should be enough for most commands |
244 | return DEFAULTCOMMANDSIZE200;; |
245 | } |
246 | |
247 | #endif |
248 | |
249 | // finalizes issuing a command (updates message size) |
250 | void TSmlCommand::FinalizeIssue(void) |
251 | { |
252 | fSessionP->incOutgoingMessageSize(fBytesbefore-fSessionP->getSmlWorkspaceFreeBytes()); // update msg size |
253 | #ifdef DEBUG_XMLRESPONSE_FOR_WBXML |
254 | // %%% debug hack %%% force input to be WBXML again |
255 | smlSetEncoding(fSessionP->getSmlWorkspaceID(),SML_WBXML); |
256 | #endif |
257 | } // TSmlCommand::FinalizeIssue |
258 | |
259 | |
260 | // finalizes issuing a command (updates message size) |
261 | bool TSmlCommand::queueForResponse(void) |
262 | { |
263 | return (!fNoResp && !fSessionP->fOutgoingNoResp); |
264 | } // TSmlCommand::queueForStatus |
265 | |
266 | |
267 | // returns true if command must be put to the waiting-for-status queue. |
268 | // If false, command can be deleted |
269 | bool TSmlCommand::issue( |
270 | uInt32 aAsCmdID, // command ID to be used |
271 | uInt32 aInMsgID, // message ID in which command is being issued |
272 | bool aNoResp |
273 | ) |
274 | { |
275 | // set command ID and Message ID (for further compare with incoming statuses) |
276 | fCmdID=aAsCmdID; |
277 | fMsgID=aInMsgID; |
278 | fNoResp=aNoResp; |
279 | return fEvalMode; // evaluation ok, but base class commands cannot be issued |
280 | } // TSmlCommand::issue |
281 | |
282 | |
283 | // execute command (perform real actions, generate status) |
284 | // returns true if command has executed and can be deleted |
285 | bool TSmlCommand::execute(void) |
286 | { |
287 | // non-derived execute (such as map received by client): protocol error |
288 | TStatusCommand *statusCmdP=newStatusCommand(400); |
289 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
290 | // done |
291 | return false; |
292 | } // TSmlCommand::execute |
293 | |
294 | |
295 | // - test if command matches status |
296 | bool TSmlCommand::matchStatus(TStatusCommand *aStatusCmdP) |
297 | { |
298 | // match if cmdID and msgID are the same |
299 | return ( |
300 | (fMsgID==aStatusCmdP->fRefMsgID) && |
301 | (fCmdID==aStatusCmdP->fRefCmdID) |
302 | ); |
303 | } // TSmlCommand::matchStatus |
304 | |
305 | |
306 | // handle status received for previously issued command |
307 | // returns true if done, false if command must be kept in the status queue |
308 | bool TSmlCommand::handleStatus(TStatusCommand *aStatusCmdP) |
309 | { |
310 | // base class just handles common cases |
311 | TSyError statuscode = aStatusCmdP->getStatusCode(); |
312 | if (statuscode<200) { |
313 | // informational |
314 | switch (statuscode) { |
315 | case 101: |
316 | // in progress, wait for final status |
317 | POBJDEBUGPRINTFX(fSessionP,DBG_HOT,("Status: 101: In progress, keep waiting for final status")){ if ((fSessionP) && (((0x00000001) & (fSessionP) ->getDbgMask()) == (0x00000001))) (fSessionP)->getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Status: 101: In progress, keep waiting for final status" ); }; |
318 | return false; // keep in queue |
319 | //break; |
320 | default: |
321 | // unknown |
322 | POBJDEBUGPRINTFX(fSessionP,DBG_ERROR,("Status: %hd: unknown informational status -> accepted",statuscode)){ if ((fSessionP) && (((0x00000002) & (fSessionP) ->getDbgMask()) == (0x00000002))) (fSessionP)->getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Status: %hd: unknown informational status -> accepted" ,statuscode); }; |
323 | return true; |
324 | } |
325 | } |
326 | else if (statuscode<300) { |
327 | if (statuscode==202) { |
328 | // accepted for processing |
329 | POBJDEBUGPRINTFX(fSessionP,DBG_PROTO,("Status: 202: accepted for processing, keep waiting for final status")){ if ((fSessionP) && (((0x00000010) & (fSessionP) ->getDbgMask()) == (0x00000010))) (fSessionP)->getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Status: 202: accepted for processing, keep waiting for final status" ); }; |
330 | return false; // keep in queue |
331 | } |
332 | // successful |
333 | POBJDEBUGPRINTFX(fSessionP,DBG_PROTO,("Status: %hd: successful --> accept as ok",statuscode)){ if ((fSessionP) && (((0x00000010) & (fSessionP) ->getDbgMask()) == (0x00000010))) (fSessionP)->getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Status: %hd: successful --> accept as ok" ,statuscode); }; |
334 | return true; // done with command |
335 | } |
336 | else if (statuscode<400) { |
337 | // redirection |
338 | // %%% - we cannot handle them, abort for now |
339 | POBJDEBUGPRINTFX(fSessionP,DBG_ERROR,("Status: %hd: redirected --> we cannot handle this, abort session",statuscode)){ if ((fSessionP) && (((0x00000002) & (fSessionP) ->getDbgMask()) == (0x00000002))) (fSessionP)->getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Status: %hd: redirected --> we cannot handle this, abort session" ,statuscode); }; |
340 | fSessionP->AbortSession(412,false,statuscode); // other party's fault: incomplete command |
341 | return true; // done with command |
342 | } |
343 | else if (statuscode==418) { |
344 | POBJDEBUGPRINTFX(fSessionP,DBG_PROTO,("Status: 418: already existed on peer --> accept as ok")){ if ((fSessionP) && (((0x00000010) & (fSessionP) ->getDbgMask()) == (0x00000010))) (fSessionP)->getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Status: 418: already existed on peer --> accept as ok" ); }; |
345 | return true; // done with command |
346 | } |
347 | else if (statuscode<500) { |
348 | // originator exception (we sent some bad stuff) |
349 | POBJDEBUGPRINTFX(fSessionP,DBG_ERROR,("Status: %hd: originator exception",statuscode)){ if ((fSessionP) && (((0x00000002) & (fSessionP) ->getDbgMask()) == (0x00000002))) (fSessionP)->getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Status: %hd: originator exception" ,statuscode); }; |
350 | if (!fAllowFailure) fSessionP->AbortSession(500,false,statuscode); // our fault |
351 | return true; // done with command |
352 | } |
353 | else { |
354 | // must be recipient exception |
355 | POBJDEBUGPRINTFX(fSessionP,DBG_ERROR,("Status: %hd: recipient exception",statuscode)){ if ((fSessionP) && (((0x00000002) & (fSessionP) ->getDbgMask()) == (0x00000002))) (fSessionP)->getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Status: %hd: recipient exception" ,statuscode); }; |
356 | if (!fAllowFailure) fSessionP->AbortSession(statuscode,false,statuscode); // show other party's reason for error |
357 | return true; // done with command |
358 | } |
359 | // just to make sure |
360 | return true; // done with command |
361 | } // TSmlCommand::handleStatus |
362 | |
363 | |
364 | |
365 | // generate status depending on fNoResp and session's fMsgNoResp |
366 | TStatusCommand *TSmlCommand::newStatusCommand(TSyError aStatusCode, const char *aStringItem) |
367 | { |
368 | TStatusCommand *statusCmdP = new TStatusCommand(fSessionP,this,aStatusCode); |
369 | if (aStringItem) |
370 | statusCmdP->addItemString(aStringItem); |
371 | return statusCmdP; |
372 | } // TSmlCommand::newStatusCommand |
373 | |
374 | |
375 | // generate and send status depending on fNoResp and session's fMsgNoResp |
376 | void TSmlCommand::issueStatusCommand(TSyError aStatusCode) |
377 | { |
378 | // issuePtr can handle NULL in case no status was generated... |
379 | fSessionP->issueRootPtr(newStatusCommand(aStatusCode)); |
380 | } // TSmlCommand::issueStatusCommand |
381 | |
382 | |
383 | |
384 | TSmlCommand::~TSmlCommand() |
385 | { |
386 | TSmlCommandPContainerClear(fPendingStatusReplies); |
387 | PDEBUGPRINTFX(DBG_PROTO,("Deleted command '%s' (%s MsgID=%ld, CmdID=%ld)",getName(),fOutgoing ? "outgoing" : "incoming", (long)fMsgID,(long)fCmdID)){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Deleted command '%s' (%s MsgID=%ld, CmdID=%ld)" ,getName(),fOutgoing ? "outgoing" : "incoming", (long)fMsgID, (long)fCmdID); }; |
388 | } // TSmlCommand::~TSmlCommand |
389 | |
390 | void TSmlCommand::queueStatusCmd(TSmlCommand *aSyncCommandP) |
391 | { |
392 | fPendingStatusReplies.push_back(aSyncCommandP); |
393 | } |
394 | |
395 | bool TSmlCommand::hasQueuedStatusCmds() const |
396 | { |
397 | return !fPendingStatusReplies.empty(); |
398 | } |
399 | |
400 | void TSmlCommand::transferQueuedStatusCmds(TSmlCommandPContainer &commands) |
401 | { |
402 | while (!fPendingStatusReplies.empty()) { |
403 | commands.push_back(fPendingStatusReplies.front()); |
404 | fPendingStatusReplies.pop_front(); |
405 | } |
406 | } |
407 | |
408 | /* end of TSmlCommand implementation */ |
409 | |
410 | |
411 | |
412 | /* |
413 | * Implementation of TSyncHeader |
414 | */ |
415 | |
416 | /* public TSyncHeader members */ |
417 | |
418 | |
419 | // constructor for receiving Sync header |
420 | TSyncHeader::TSyncHeader( |
421 | TSyncSession *aSessionP, // associated session (for callbacks) |
422 | SmlSyncHdrPtr_t aSyncHdrElementP // associated SyncHdr content element |
423 | ) : |
424 | TSmlCommand(scmd_synchdr,false,aSessionP) |
425 | { |
426 | // save element |
427 | fSyncHdrElementP = aSyncHdrElementP; |
428 | } // TSyncHeader::TSyncHeader |
429 | |
430 | |
431 | // constructor for sending SyncHdr |
432 | TSyncHeader::TSyncHeader( |
433 | TSyncSession *aSessionP, // associated session (for callbacks) |
434 | bool aOutgoingNoResp // if true, entire message will request no responses |
435 | ) : |
436 | TSmlCommand(scmd_synchdr,true,aSessionP) |
437 | { |
438 | // prevent two simultaneous messages |
439 | if (fSessionP->fOutgoingStarted) |
440 | SYSYNC_THROW(TSyncException("Tried to start new message before finishing previous"))throw TSyncException("Tried to start new message before finishing previous" ); |
441 | // let session create the structure (using session vars for info) |
442 | fSyncHdrElementP=fSessionP->NewOutgoingSyncHdr(aOutgoingNoResp); |
443 | // now outgoing message IS started |
444 | fSessionP->fOutgoingStarted=true; |
445 | } // TSyncHeader::TSyncHeader |
446 | |
447 | |
448 | // returns true if command must be put to the waiting-for-status queue. |
449 | // If false, command can be deleted |
450 | bool TSyncHeader::issue( |
451 | uInt32 aAsCmdID, // command ID to be used |
452 | uInt32 aInMsgID, // message ID in which command is being issued |
453 | bool aNoResp |
454 | ) |
455 | { |
456 | // prepare basic stuff |
457 | TSmlCommand::issue(0,aInMsgID,false); |
458 | // now issue |
459 | if (fSyncHdrElementP) { |
460 | // issue command with SyncML toolkit, no CmdID or flags to set here |
461 | PrepareIssue(NULL__null,NULL__null); |
462 | if (!fEvalMode) { |
463 | Ret_t err; |
464 | #ifdef SYDEBUG2 |
465 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance) { |
466 | err=smlStartMessageExt(fSessionP->fOutgoingXMLInstance,fSyncHdrElementP,SmlVersionCodes[fSessionP->fSyncMLVersion]); |
467 | if (err!=SML_ERR_OK0x00) { |
468 | // problem with XML translation |
469 | PDEBUGPRINTFX(DBG_ERROR,("XML translation disabled due to sml error=%04hX",err)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("XML translation disabled due to sml error=%04hX" ,err); }; |
470 | fSessionP->fXMLtranslate=false; |
471 | } |
472 | } |
473 | #endif |
474 | if ((err=smlStartMessageExt(fSessionP->getSmlWorkspaceID(),fSyncHdrElementP,SmlVersionCodes[fSessionP->fSyncMLVersion]))!=SML_ERR_OK0x00) { |
475 | SYSYNC_THROW(TSmlException("smlStartMessage",err))throw TSmlException("smlStartMessage",err); |
476 | } |
477 | FinalizeIssue(); |
478 | // we don't need the status structure any more, free (and NULL ptr) now |
479 | FreeSmlElement(); |
480 | } |
481 | else |
482 | // just evaluate size |
483 | return smlStartMessageExt(fSessionP->getSmlWorkspaceID(),fSyncHdrElementP,SmlVersionCodes[fSessionP->fSyncMLVersion])==SML_ERR_OK0x00; |
484 | } |
485 | else { |
486 | DEBUGPRINTFX(DBG_ERROR,("*** Tried to issue NULL synchdr")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("*** Tried to issue NULL synchdr" ); }; |
487 | } |
488 | // header will normally receive status |
489 | return queueForResponse(); |
490 | } // TSyncHeader::issue |
491 | |
492 | |
493 | // handle status received for previously issued command |
494 | // returns true if done, false if command must be kept in the status queue |
495 | bool TSyncHeader::handleStatus(TStatusCommand *aStatusCmdP) |
496 | { |
497 | // status for SyncHdr |
498 | if (!fSessionP->handleHeaderStatus(aStatusCmdP)) { |
499 | // session could not handle item |
500 | return TSmlCommand::handleStatus(aStatusCmdP); |
501 | } |
502 | // status handled |
503 | return true; // done with command |
504 | } // TSyncHeader::handleStatus |
505 | |
506 | |
507 | // execute command (perform real actions, generate status) |
508 | // returns true if command has executed and can be deleted |
509 | // NOTE: synchdr is a special case: if it returns FALSE, |
510 | // session must be reset and synchdr must be re-excecuted |
511 | bool TSyncHeader::execute(void) |
512 | { |
513 | const char *verDTD; |
514 | const char *verProto; |
515 | TStatusCommand *statusCmdP=NULL__null; |
516 | sInt16 statuscode=400; |
517 | bool hdrok=true; |
518 | |
519 | if (!fSyncHdrElementP) SYSYNC_THROW(TSyncException("empty header"))throw TSyncException("empty header"); |
520 | if (!fSessionP) SYSYNC_THROW(TSyncException("missing fSessionP"))throw TSyncException("missing fSessionP"); |
521 | // first get message ID to be able to generate statuses |
522 | fMsgID=0; // none by default |
523 | if (StrToULong(smlPCDataToCharP(fSyncHdrElementP->msgID),fMsgID)) { |
524 | // got msgID, check if ok |
525 | if ( |
526 | fMsgID==uInt32(fSessionP->fIncomingMsgID-1) && |
527 | fSessionP->fAllowMessageRetries // check if we want to allow this (7250 for example seems to retry messages) |
528 | ) { |
529 | // this seems to be a transport-level retry of the previous message |
530 | PDEBUGPRINTFX(DBG_ERROR,("*********** WARNING: Remote resent MsgID %ld",(long)fMsgID)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("*********** WARNING: Remote resent MsgID %ld" ,(long)fMsgID); }; |
531 | // set back incoming ID |
532 | fSessionP->fIncomingMsgID = fMsgID; |
533 | // -> we should resend the previous answer again. |
534 | if ( |
535 | fSessionP->getSyncAppBase()->canBufferRetryAnswer() |
536 | ) { |
537 | // we can resend answers |
538 | PDEBUGPRINTFX(DBG_ERROR,("last answer buffered -> sending it again")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("last answer buffered -> sending it again" ); }; |
539 | fSessionP->fMessageRetried=true; |
540 | return false; |
541 | } |
542 | else { |
543 | // use not foolproof poor man's method |
544 | // %%% This will fail if the previous message received has |
545 | // changed datastore/session/package states, but will work if |
546 | // the retry is within a phase (probable case for long sessions) |
547 | PDEBUGPRINTFX(DBG_ERROR,("No buffered answer to resend -> just process msg again (WARNING: possibly messes up session state)")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("No buffered answer to resend -> just process msg again (WARNING: possibly messes up session state)" ); }; |
548 | } |
549 | } |
550 | if (fMsgID<uInt32(fSessionP->fIncomingMsgID)) { |
551 | // bad Message ID (lower than previous): forget previous session, start new one |
552 | PDEBUGPRINTFX(DBG_ERROR,("Bad incoming MsgID %ld, expected >=%ld -> Aborting previous Session, starting new",(long)fMsgID,(long)fSessionP->fIncomingMsgID)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Bad incoming MsgID %ld, expected >=%ld -> Aborting previous Session, starting new" ,(long)fMsgID,(long)fSessionP->fIncomingMsgID); }; |
553 | return false; // session must be restarted, this command re-executed |
554 | } |
555 | } |
556 | else { |
557 | // header without session ID is bad |
558 | statuscode=500; |
559 | statusCmdP=newStatusCommand(statuscode); |
560 | // log file entry |
561 | PDEBUGPRINTFX(DBG_ERROR,("Missing incoming MsgID -> Aborting Session")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Missing incoming MsgID -> Aborting Session" ); }; |
562 | hdrok=false; // cannot start |
563 | } |
564 | // Assign session-var anyway |
565 | fSessionP->fIncomingMsgID=fMsgID; |
566 | // now check header for conformance |
567 | SYSYNC_TRYtry { |
568 | // get info out of SyncHdr |
569 | if (hdrok) { |
570 | // get noResp flag (which is valid for the entire message) |
571 | fNoResp=(fSyncHdrElementP->flags & SmlNoResp_f0x0100)!=0; |
572 | fSessionP->fMsgNoResp=fNoResp; // copy to session flag |
573 | // test SyncML version compatibility |
574 | verProto=smlPCDataToCharP(fSyncHdrElementP->proto); |
575 | verDTD=smlPCDataToCharP(fSyncHdrElementP->version); |
576 | sInt16 ver; |
577 | // find version |
578 | for (ver=1; ver<numSyncMLVersions; ver++) { |
579 | if (strcmp(verProto,SyncMLVerProtoNames[ver])==0) { |
580 | // known version found |
581 | // - set it only for server, client keeps preset version (will change it when |
582 | // a 513 is detected) |
583 | if (IS_SERVER(getSyncAppBase()->isServer())) fSessionP->fSyncMLVersion=(TSyncMLVersions)ver; |
584 | break; |
585 | } |
586 | } |
587 | // - Protocol Version |
588 | TSyncMLVersions maxver = fSessionP->getSessionConfig()->fMaxSyncMLVersionSupported; |
589 | TSyncMLVersions minver = fSessionP->getSessionConfig()->fMinSyncMLVersionSupported; |
590 | if ( |
591 | ver<minver || |
592 | ver>=numSyncMLVersions || |
593 | ver>maxver || |
594 | (IS_SERVER(getSyncAppBase()->isServer()) && fSessionP->fSyncMLVersion!=syncml_vers_unknown && fSessionP->fSyncMLVersion!=ver) |
595 | ) { |
596 | // unsupported protocol version (or different than in first message): Status 513 |
597 | // - Make sure we have a valid SyncML version |
598 | if ( |
599 | fSessionP->fSyncMLVersion==syncml_vers_unknown || |
600 | fSessionP->fSyncMLVersion>maxver |
601 | ) { |
602 | // use highest version we know for the answering message |
603 | fSessionP->fSyncMLVersion = maxver; |
604 | } |
605 | else if (fSessionP->fSyncMLVersion<minver) { |
606 | // use lowest enabled version for answering message |
607 | fSessionP->fSyncMLVersion = minver; |
608 | } |
609 | // - Set status |
610 | statuscode=513; |
611 | statusCmdP=newStatusCommand(statuscode); |
612 | // - add version(s) we support in data item |
613 | string vs; |
614 | for (sInt16 v=minver; v<=maxver; v++) { |
615 | if (!vs.empty()) vs+=", "; |
616 | vs+=SyncMLVerProtoNames[v]; |
617 | } |
618 | statusCmdP->addItemString(vs.c_str()); |
619 | // - log file entry |
620 | PDEBUGPRINTFX(DBG_ERROR,("Unsupported or changing verProto %s -> Aborting Session",verProto)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Unsupported or changing verProto %s -> Aborting Session" ,verProto); }; |
621 | hdrok=false; // bad header |
622 | } |
623 | // protocol version known, check if DTD matches |
624 | else if (strcmp(verDTD,SyncMLVerDTDNames[ver])!=0) { |
625 | // wrong DTD version for this protocol version: Status 505 |
626 | statuscode=505; |
627 | statusCmdP=newStatusCommand(statuscode); |
628 | statusCmdP->addItemString(SyncMLVerDTDNames[ver]); |
629 | // log file entry |
630 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Wrong verDTD %s, expected %s -> Aborting Session" , verDTD, SyncMLVerDTDNames[ver] ); } |
631 | "Wrong verDTD %s, expected %s -> Aborting Session",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Wrong verDTD %s, expected %s -> Aborting Session" , verDTD, SyncMLVerDTDNames[ver] ); } |
632 | verDTD,{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Wrong verDTD %s, expected %s -> Aborting Session" , verDTD, SyncMLVerDTDNames[ver] ); } |
633 | SyncMLVerDTDNames[ver]{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Wrong verDTD %s, expected %s -> Aborting Session" , verDTD, SyncMLVerDTDNames[ver] ); } |
634 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Wrong verDTD %s, expected %s -> Aborting Session" , verDTD, SyncMLVerDTDNames[ver] ); }; |
635 | hdrok=false; // bad header |
636 | } |
637 | // if ok so far, continue header processing |
638 | if (hdrok) { |
639 | PDEBUGPRINTFX(DBG_HOT,("Started Processing of message #%ld (%s)",(long)fSessionP->fIncomingMsgID,SyncMLVerProtoNames[ver])){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Started Processing of message #%ld (%s)" ,(long)fSessionP->fIncomingMsgID,SyncMLVerProtoNames[ver]) ; }; |
640 | // take a look at SyncHdr Meta |
641 | SmlMetInfMetInfPtr_t metaP=smlPCDataToMetInfP(fSyncHdrElementP->meta); |
642 | if (metaP) { |
643 | // max (outgoing) message size |
644 | if (metaP->maxmsgsize) { |
645 | smlPCDataToLong(metaP->maxmsgsize,fSessionP->fMaxOutgoingMsgSize); |
646 | PDEBUGPRINTFX(DBG_REMOTEINFO,("MaxMsgSize found in SyncHdr: %ld -> set for outgoing msgs",(long)fSessionP->fMaxOutgoingMsgSize)){ if (((0x00000100) & getDbgMask()) == (0x00000100)) getDbgLogger ()->setNextMask(0x00000100).DebugPrintfLastMask ("MaxMsgSize found in SyncHdr: %ld -> set for outgoing msgs" ,(long)fSessionP->fMaxOutgoingMsgSize); }; |
647 | } |
648 | // max (outgoing) object size (SyncML 1.1 only) |
649 | if (metaP->maxobjsize) { |
650 | smlPCDataToLong(metaP->maxobjsize,fSessionP->fMaxOutgoingObjSize); |
651 | PDEBUGPRINTFX(DBG_REMOTEINFO,("MaxObjSize found in SyncHdr: %ld",(long)fSessionP->fMaxOutgoingObjSize)){ if (((0x00000100) & getDbgMask()) == (0x00000100)) getDbgLogger ()->setNextMask(0x00000100).DebugPrintfLastMask ("MaxObjSize found in SyncHdr: %ld" ,(long)fSessionP->fMaxOutgoingObjSize); }; |
652 | } |
653 | } |
654 | // call server/client specific message start in derived classes |
655 | statusCmdP=newStatusCommand(200); // prepare OK default status (will possibly be modified by MessageStarted()) |
656 | hdrok=fSessionP->MessageStarted(fSyncHdrElementP,*statusCmdP); |
657 | } |
658 | else { |
659 | //#warning "comment the next line to have server respond like pre-1.0.8.29" |
660 | // call client/server specific message start routine, but with error flag |
661 | // Note: we already have a status command (containing an error) |
662 | fSessionP->MessageStarted(fSyncHdrElementP,*statusCmdP,true); |
663 | } |
664 | } |
665 | // complete and send status, if any |
666 | if (statusCmdP) { |
667 | statusCmdP->addTargetRef(fSessionP->fLocalURI.c_str()); |
668 | statusCmdP->addSourceRef(fSessionP->fRemoteURI.c_str()); |
669 | // issue as SyncHdr status (if successful status) |
670 | TStatusCommand *cmdP = statusCmdP; statusCmdP=NULL__null; |
671 | statuscode=cmdP->getStatusCode(); // get actual status code |
672 | fSessionP->issueRootPtr(cmdP,false,statuscode==200); |
673 | } |
674 | // set session vars according to header success or failure |
675 | // - ignore all further incoming commands when header is not ok |
676 | // NOTE: bad cred will NOT (any longer, SyncFest #5) be flagged as bad header |
677 | // but instead MessageStarted may have aborted command processing |
678 | if (!hdrok) fSessionP->AbortSession(400,true); // bad request |
679 | // free this one now, is not needed any more |
680 | FreeSmlElement(); |
681 | } |
682 | SYSYNC_CATCH (...)catch(...) { |
683 | // make sure owned objects in local scope are deleted |
684 | if (statusCmdP) delete statusCmdP; |
685 | // re-throw |
686 | SYSYNC_RETHROWthrow; |
687 | SYSYNC_ENDCATCH} |
688 | // done with command, delete it now: return true |
689 | return true; |
690 | } // TSyncHeader::execute |
691 | |
692 | |
693 | |
694 | void TSyncHeader::FreeSmlElement(void) |
695 | { |
696 | // remove SyncML toolkit element(s) |
697 | FREEPROTOELEMENT(fSyncHdrElementP); |
698 | } // TSyncHeader::FreeSmlElement |
699 | |
700 | |
701 | TSyncHeader::~TSyncHeader() |
702 | { |
703 | // free command elements, if any (use explicit invocation as this is a destructor) |
704 | TSyncHeader::FreeSmlElement(); |
705 | } // TSyncHeader::~TSyncHeader |
706 | |
707 | |
708 | /* end of TSyncHeader implementation */ |
709 | |
710 | |
711 | |
712 | /* |
713 | * Implementation of TSyncCommand |
714 | */ |
715 | |
716 | |
717 | // constructor for sending Sync Command |
718 | TSyncCommand::TSyncCommand( |
719 | TSyncSession *aSessionP, // associated session (for callbacks) |
720 | TLocalEngineDS *aLocalDataStoreP, // local datastore |
721 | TRemoteDataStore *aRemoteDataStoreP // remote datastore |
722 | ) : |
723 | TSmlCommand(scmd_sync,true,aSessionP), |
724 | fInterruptedCommandP(NULL__null) |
725 | { |
726 | // save params |
727 | fLocalDataStoreP=aLocalDataStoreP; |
728 | fRemoteDataStoreP=aRemoteDataStoreP; |
729 | // create internal sync element |
730 | fSyncElementP = SML_NEW(SmlSync_t)((SmlSync_t*) _smlMalloc(sizeof(SmlSync_t))); |
731 | // set proto element type to make it auto-disposable |
732 | fSyncElementP->elementType=SML_PE_SYNC_START; |
733 | // Cmd ID is now empty (will be set when issued) |
734 | fSyncElementP->cmdID=NULL__null; |
735 | // default to no flags (noResp is set at issue, if at all) |
736 | fSyncElementP->flags=0; |
737 | // set source and target |
738 | fSyncElementP->target=newLocation(fRemoteDataStoreP->getFullName()); // remote is target for Sync command |
739 | fSyncElementP->source=newLocation(fLocalDataStoreP->getRemoteViewOfLocalURI()); // local is source of Sync command |
740 | // no optional elements for now |
741 | fSyncElementP->cred=NULL__null; // %%% no database level auth yet at all |
742 | fSyncElementP->meta=NULL__null; // %%% no search grammar for now |
743 | // add number of changes for SyncML 1.1 if remote supports it |
744 | fSyncElementP->noc=NULL__null; // default to none |
745 | fRemoteWantsNOC=aSessionP->fRemoteWantsNOC; |
746 | if (fRemoteWantsNOC) { |
747 | sInt32 noc = fLocalDataStoreP->getNumberOfChanges(); |
748 | if (noc>=0) { |
749 | // we have a valid NOC value, add it |
750 | fSyncElementP->noc=newPCDataLong(noc); |
751 | } |
752 | } |
753 | // not yet in progress (as not yet issued) |
754 | fInProgress=false; |
755 | } // TSyncCommand::TSyncCommand |
756 | |
757 | |
758 | // constructor for receiving Sync Command |
759 | TSyncCommand::TSyncCommand( |
760 | TSyncSession *aSessionP, // associated session (for callbacks) |
761 | uInt32 aMsgID, // the Message ID of the command |
762 | SmlSyncPtr_t aSyncElementP // associated Sync content element |
763 | ) : |
764 | TSmlCommand(scmd_sync,false,aSessionP,aMsgID), |
765 | fInterruptedCommandP(NULL__null) |
766 | { |
767 | // save sync element |
768 | fSyncElementP = aSyncElementP; |
769 | fInProgress=false; // just in case... |
770 | // no params |
771 | fLocalDataStoreP=NULL__null; |
772 | fRemoteDataStoreP=NULL__null; |
773 | } // TSyncCommand::TSyncCommand |
774 | |
775 | |
776 | // handle status received for previously issued command |
777 | // returns true if done, false if command must be kept in the status queue |
778 | bool TSyncCommand::handleStatus(TStatusCommand *aStatusCmdP) |
779 | { |
780 | // catch those codes that do not abort entire session |
781 | TSyError statuscode = aStatusCmdP->getStatusCode(); |
782 | bool handled=false; |
783 | switch (statuscode) { |
784 | case 404: // datastore not found |
785 | case 403: // forbidden |
786 | case 406: // bad mode |
787 | case 415: // type(s) not supported |
788 | case 422: // bad CGI |
789 | case 510: // datastore error |
790 | case 512: // sync failed |
791 | case 514: // cancelled |
792 | if (fLocalDataStoreP) { |
793 | // there is a local datastore to abort |
794 | fLocalDataStoreP->engAbortDataStoreSync(statuscode,false); // remote problem |
795 | } |
796 | if (fInProgress) { |
797 | // make sure sync command is finished now |
798 | fInProgress=false; |
799 | // Note that setting fInProgress to false |
800 | // is only completely safe in issue(). |
801 | // Here it is allowed as we KNOW that syncCommand |
802 | // is root level, so session's handleStatus() |
803 | // will properly clear the fInterruptedCommandP |
804 | // (this would not work if this command was nested) |
805 | } |
806 | handled = true; |
807 | break; |
808 | default: |
809 | handled=TSmlCommand::handleStatus(aStatusCmdP); |
810 | break; |
811 | } |
812 | return handled; |
813 | } // TSyncCommand::handleStatus |
814 | |
815 | |
816 | // mark any syncitems (or other data) for resume. Called for pending commands |
817 | // when a Suspend alert is received or whenever a resumable state must be saved |
818 | void TSyncCommand::markPendingForResume(TLocalEngineDS *aForDatastoreP, bool aUnsent) |
819 | { |
820 | // only act if this is for our local datastore and unsent |
821 | // (sent ones will be in the status wait queue, and will be found there) |
822 | if (aUnsent && fLocalDataStoreP==aForDatastoreP) { |
823 | fSessionP->markPendingForResume( |
824 | fNextMessageCommands, |
825 | fInterruptedCommandP, |
826 | fLocalDataStoreP |
827 | ); |
828 | } |
829 | } // TSyncCommand::markPendingForResume |
830 | |
831 | |
832 | // analyze command (but do not yet execute) |
833 | bool TSyncCommand::analyze(TPackageStates aPackageState) |
834 | { |
835 | TSmlCommand::analyze(aPackageState); |
836 | // get Command ID and flags |
837 | if (fSyncElementP) { |
838 | StartProcessing(fSyncElementP->cmdID,fSyncElementP->flags); |
839 | return true; |
840 | } |
841 | else return false; // no proto element, bad command |
842 | } // TSyncCommand::analyze |
843 | |
844 | |
845 | // execute command (perform real actions, generate status) |
846 | // returns true if command has executed and can be deleted |
847 | bool TSyncCommand::execute(void) |
848 | { |
849 | TStatusCommand *statusCmdP=NULL__null; |
850 | bool queueforlater = false; |
851 | |
852 | if (fSyncElementP) |
853 | SYSYNC_TRYtry { |
854 | // determine database to be synced (target LocURI) |
855 | // - generate default OK status |
856 | statusCmdP = newStatusCommand(200); |
857 | // - add source and target refs from item |
858 | statusCmdP->addSourceRef(smlSrcTargLocURIToCharP(fSyncElementP->source)); |
859 | statusCmdP->addTargetRef(smlSrcTargLocURIToCharP(fSyncElementP->target)); |
860 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Processing Sync, Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(fSyncElementP->source), smlSrcTargLocURIToCharP (fSyncElementP->target) ); } |
861 | "Processing Sync, Source='%s', Target='%s'",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Processing Sync, Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(fSyncElementP->source), smlSrcTargLocURIToCharP (fSyncElementP->target) ); } |
862 | smlSrcTargLocURIToCharP(fSyncElementP->source),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Processing Sync, Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(fSyncElementP->source), smlSrcTargLocURIToCharP (fSyncElementP->target) ); } |
863 | smlSrcTargLocURIToCharP(fSyncElementP->target){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Processing Sync, Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(fSyncElementP->source), smlSrcTargLocURIToCharP (fSyncElementP->target) ); } |
864 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Processing Sync, Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(fSyncElementP->source), smlSrcTargLocURIToCharP (fSyncElementP->target) ); }; |
865 | // - check for MaxObjSize here |
866 | SmlMetInfMetInfPtr_t metaP=smlPCDataToMetInfP(fSyncElementP->meta); |
867 | if (metaP && metaP->maxobjsize) { |
868 | smlPCDataToLong(metaP->maxobjsize,fSessionP->fMaxOutgoingObjSize); |
869 | PDEBUGPRINTFX(DBG_REMOTEINFO,("MaxObjSize found in Sync command: %ld",(long)fSessionP->fMaxOutgoingObjSize)){ if (((0x00000100) & getDbgMask()) == (0x00000100)) getDbgLogger ()->setNextMask(0x00000100).DebugPrintfLastMask ("MaxObjSize found in Sync command: %ld" ,(long)fSessionP->fMaxOutgoingObjSize); }; |
870 | } |
871 | // - let session do the processing |
872 | queueforlater=false; |
873 | fSessionP->processSyncStart( |
874 | fSyncElementP, |
875 | *statusCmdP, |
876 | queueforlater // will be set if command must be queued for later re-execution |
877 | ); |
878 | if (queueforlater) { |
879 | // we don't need the status now |
880 | delete statusCmdP; |
881 | } |
882 | else { |
883 | // Sync command execution completed, send (or save) status now |
884 | #ifdef SYNCSTATUS_AT_SYNC_CLOSE |
885 | // %%% don't send, just save for being sent at </Sync> |
886 | fSessionP->fSyncCloseStatusCommandP=statusCmdP; |
887 | #else |
888 | // - issue status for item |
889 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
890 | #endif |
891 | /* %%% no need to abort session, failing sync command stops sync with this |
892 | datastore anyway |
893 | // make sure session gets aborted when Sync is not successful |
894 | if (!ok) { |
895 | fSessionP->AbortSession(500,true); |
896 | } |
897 | */ |
898 | // free element |
899 | FreeSmlElement(); |
900 | } |
901 | } |
902 | SYSYNC_CATCH (...)catch(...) { |
903 | // make sure owned objects in local scope are deleted |
904 | if (statusCmdP) delete statusCmdP; |
905 | // re-throw |
906 | SYSYNC_RETHROWthrow; |
907 | SYSYNC_ENDCATCH} |
908 | // return true if command has fully executed |
909 | return !queueforlater; |
910 | } // TSyncCommand::execute |
911 | |
912 | |
913 | // returns true if command must be put to the waiting-for-status queue. |
914 | // If false, command can be deleted |
915 | bool TSyncCommand::issue( |
916 | uInt32 aAsCmdID, // command ID to be used |
917 | uInt32 aInMsgID, // message ID in which command is being issued |
918 | bool aNoResp |
919 | ) |
920 | { |
921 | // prepare basic stuff |
922 | TSmlCommand::issue(aAsCmdID,aInMsgID,aNoResp); |
923 | // now issue |
924 | if (fSyncElementP) { |
925 | // generate (first) opening (or evaluate) |
926 | if (fEvalMode) return generateOpen(); |
927 | generateOpen(); |
928 | // generate commands, update fInProgress |
929 | generateCommandsAndClose(); |
930 | // Make sure this is not counted as command (will be counted in issuePtr(), so |
931 | // decrement here). Note that this must be done AFTER calling generateCommandsAndClose(), |
932 | // because generating needs the correct count (and this <sync> is not yet included by now!) |
933 | fSessionP->fOutgoingCmds--; // we're now one below the real count, but that will be compensated when returning to issuePtr |
934 | } |
935 | else { |
936 | DEBUGPRINTFX(DBG_ERROR,("*** Tried to issue NULL sync")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("*** Tried to issue NULL sync" ); }; |
937 | } |
938 | // return true if command must be queued for status/result response reception |
939 | return queueForResponse(); |
940 | } // TSyncCommand::issue |
941 | |
942 | |
943 | // - test if completely issued (must be called after issue() and continueIssue()) |
944 | bool TSyncCommand::finished(void) |
945 | { |
946 | // not finished as long there are more syncOps to send; |
947 | // incoming are always finished after executing |
948 | return (!fInProgress || !fOutgoing); |
949 | } // TSyncCommand::finished |
950 | |
951 | |
952 | // generate opening <Sync> bracket |
953 | bool TSyncCommand::generateOpen(void) |
954 | { |
955 | // issue command Start <Sync> with SyncML toolkit |
956 | fPrepared=false; // force re-preparing in all cases (as this might be continuing a command) |
957 | PrepareIssue(&fSyncElementP->cmdID,&fSyncElementP->flags); |
958 | |
959 | // (re-)check NumberOfChanges, because in a SyncML client that number might not |
960 | // have been available right away when constructing the TSyncCommand. |
961 | if (!fSyncElementP->noc && |
962 | fRemoteWantsNOC) { |
963 | sInt32 noc = fLocalDataStoreP->getNumberOfChanges(); |
964 | if (noc>=0) { |
965 | fSyncElementP->noc=newPCDataLong(noc); |
966 | } |
967 | } |
968 | |
969 | if (!fEvalMode) { |
970 | #ifdef SYDEBUG2 |
971 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance) |
972 | smlStartSync(fSessionP->fOutgoingXMLInstance,fSyncElementP); |
973 | #endif |
974 | Ret_t err; |
975 | if ((err=smlStartSync(fSessionP->getSmlWorkspaceID(),fSyncElementP))!=SML_ERR_OK0x00) { |
976 | SYSYNC_THROW(TSmlException("smlStartSync",err))throw TSmlException("smlStartSync",err); |
977 | } |
978 | FinalizeIssue(); |
979 | // show debug |
980 | PDEBUGBLOCKFMT(("sync","Opened Sync command bracket",getDbgLogger()->DebugOpenBlockExpanded ("sync","Opened Sync command bracket" , "Reopen=%s|SourceURI=%s|TargetURI=%s|IncomingMsgID=%ld|CmdID=%ld" , fInProgress ? "yes" : "no", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ) |
981 | "Reopen=%s|SourceURI=%s|TargetURI=%s|IncomingMsgID=%ld|CmdID=%ld",getDbgLogger()->DebugOpenBlockExpanded ("sync","Opened Sync command bracket" , "Reopen=%s|SourceURI=%s|TargetURI=%s|IncomingMsgID=%ld|CmdID=%ld" , fInProgress ? "yes" : "no", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ) |
982 | fInProgress ? "yes" : "no",getDbgLogger()->DebugOpenBlockExpanded ("sync","Opened Sync command bracket" , "Reopen=%s|SourceURI=%s|TargetURI=%s|IncomingMsgID=%ld|CmdID=%ld" , fInProgress ? "yes" : "no", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ) |
983 | smlSrcTargLocURIToCharP(fSyncElementP->source),getDbgLogger()->DebugOpenBlockExpanded ("sync","Opened Sync command bracket" , "Reopen=%s|SourceURI=%s|TargetURI=%s|IncomingMsgID=%ld|CmdID=%ld" , fInProgress ? "yes" : "no", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ) |
984 | smlSrcTargLocURIToCharP(fSyncElementP->target),getDbgLogger()->DebugOpenBlockExpanded ("sync","Opened Sync command bracket" , "Reopen=%s|SourceURI=%s|TargetURI=%s|IncomingMsgID=%ld|CmdID=%ld" , fInProgress ? "yes" : "no", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ) |
985 | (long)fMsgID,getDbgLogger()->DebugOpenBlockExpanded ("sync","Opened Sync command bracket" , "Reopen=%s|SourceURI=%s|TargetURI=%s|IncomingMsgID=%ld|CmdID=%ld" , fInProgress ? "yes" : "no", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ) |
986 | (long)fCmdIDgetDbgLogger()->DebugOpenBlockExpanded ("sync","Opened Sync command bracket" , "Reopen=%s|SourceURI=%s|TargetURI=%s|IncomingMsgID=%ld|CmdID=%ld" , fInProgress ? "yes" : "no", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ) |
987 | ))getDbgLogger()->DebugOpenBlockExpanded ("sync","Opened Sync command bracket" , "Reopen=%s|SourceURI=%s|TargetURI=%s|IncomingMsgID=%ld|CmdID=%ld" , fInProgress ? "yes" : "no", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ); |
988 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "%sOpened <Sync> bracket, Source='%s', Target='%s' as (outgoing MsgID=%ld, CmdID=%ld)" , fInProgress ? "Re-" : "", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ); } |
989 | "%sOpened <Sync> bracket, Source='%s', Target='%s' as (outgoing MsgID=%ld, CmdID=%ld)",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "%sOpened <Sync> bracket, Source='%s', Target='%s' as (outgoing MsgID=%ld, CmdID=%ld)" , fInProgress ? "Re-" : "", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ); } |
990 | fInProgress ? "Re-" : "",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "%sOpened <Sync> bracket, Source='%s', Target='%s' as (outgoing MsgID=%ld, CmdID=%ld)" , fInProgress ? "Re-" : "", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ); } |
991 | smlSrcTargLocURIToCharP(fSyncElementP->source),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "%sOpened <Sync> bracket, Source='%s', Target='%s' as (outgoing MsgID=%ld, CmdID=%ld)" , fInProgress ? "Re-" : "", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ); } |
992 | smlSrcTargLocURIToCharP(fSyncElementP->target),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "%sOpened <Sync> bracket, Source='%s', Target='%s' as (outgoing MsgID=%ld, CmdID=%ld)" , fInProgress ? "Re-" : "", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ); } |
993 | (long)fMsgID,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "%sOpened <Sync> bracket, Source='%s', Target='%s' as (outgoing MsgID=%ld, CmdID=%ld)" , fInProgress ? "Re-" : "", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ); } |
994 | (long)fCmdID{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "%sOpened <Sync> bracket, Source='%s', Target='%s' as (outgoing MsgID=%ld, CmdID=%ld)" , fInProgress ? "Re-" : "", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ); } |
995 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "%sOpened <Sync> bracket, Source='%s', Target='%s' as (outgoing MsgID=%ld, CmdID=%ld)" , fInProgress ? "Re-" : "", smlSrcTargLocURIToCharP(fSyncElementP ->source), smlSrcTargLocURIToCharP(fSyncElementP->target ), (long)fMsgID, (long)fCmdID ); }; |
996 | // calculate (approx) max free space for data |
997 | fSessionP->fMaxRoomForData = |
998 | fSessionP->getSmlWorkspaceFreeBytes()-fSessionP->getNotUsableBufferBytes()- // what is free |
999 | DEFAULTCOMMANDSIZE200;; // minus a standard command size |
1000 | // now we are in progress |
1001 | fInProgress=true; |
1002 | return true; |
1003 | } |
1004 | else |
1005 | return smlStartSync(fSessionP->getSmlWorkspaceID(),fSyncElementP)==SML_ERR_OK0x00; |
1006 | } // TSyncCommand::generateOpen |
1007 | |
1008 | |
1009 | // generate commands for inside of the <Sync> bracket |
1010 | void TSyncCommand::generateCommandsAndClose(void) |
1011 | { |
1012 | // generate new commands only if message is not full already |
1013 | if (!fSessionP->outgoingMessageFull()) { |
1014 | // check for unassigned fLocalDataStoreP as this seems to happen sometimes in the cmdline client |
1015 | PPOINTERTEST(fLocalDataStoreP,("Warning: fLocalDataStoreP==NULL, cannot generate commands -> empty <sync> command"))if (!fLocalDataStoreP) getDbgLogger()->setNextMask(0x00000002 ).DebugPrintfLastMask ("Warning: fLocalDataStoreP==NULL, cannot generate commands -> empty <sync> command" ); |
1016 | if (fLocalDataStoreP) { |
1017 | fInProgress = !( |
1018 | fLocalDataStoreP->engGenerateSyncCommands |
1019 | ( |
1020 | fNextMessageCommands, |
1021 | fInterruptedCommandP |
1022 | ) |
1023 | ); |
1024 | } |
1025 | } |
1026 | // issue command End </Sync> with SyncML toolkit |
1027 | // - save workspace size immediately before sending to calc message size |
1028 | fBytesbefore=fSessionP->getSmlWorkspaceFreeBytes(); |
1029 | #ifdef SYDEBUG2 |
1030 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance) |
1031 | smlEndSync(fSessionP->fOutgoingXMLInstance); |
1032 | #endif |
1033 | Ret_t err; |
1034 | if ((err=smlEndSync(fSessionP->getSmlWorkspaceID()))!=SML_ERR_OK0x00) { |
1035 | SYSYNC_THROW(TSmlException("smlEndSync",err))throw TSmlException("smlEndSync",err); |
1036 | } |
1037 | FinalizeIssue(); |
1038 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Closed </Sync> bracket, %sfinal" , fInProgress ? "NOT " : "" ); } |
1039 | "Closed </Sync> bracket, %sfinal",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Closed </Sync> bracket, %sfinal" , fInProgress ? "NOT " : "" ); } |
1040 | fInProgress ? "NOT " : ""{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Closed </Sync> bracket, %sfinal" , fInProgress ? "NOT " : "" ); } |
1041 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Closed </Sync> bracket, %sfinal" , fInProgress ? "NOT " : "" ); }; |
1042 | PDEBUGENDBLOCK("sync")getDbgLogger()->DebugCloseBlock( "sync"); |
1043 | } // TSyncCommand::generateCommandsAndClose |
1044 | |
1045 | |
1046 | // - continue issuing command. This is called by session at start of new message |
1047 | // when finished() returned false after issue()/continueIssue() |
1048 | // (which causes caller of finished() to put command into fInteruptedCommands queue) |
1049 | // returns true if command should be queued for status (again?) |
1050 | // NOTE: continueIssue must make sure that it gets a new CmdID/MsgID because |
1051 | // the command itself is issued multiple times |
1052 | bool TSyncCommand::continueIssue(bool &aNewIssue) |
1053 | { |
1054 | aNewIssue=false; // never issue anew! |
1055 | if (!fInProgress) return false; // done, don't queue for status again |
1056 | // command is in progress, re-open a <sync> bracket in this message |
1057 | // - get new CmdID/MsgID |
1058 | fCmdID = fSessionP->getNextOutgoingCmdID(); |
1059 | fMsgID = fSessionP->getOutgoingMsgID(); |
1060 | // - now issue open |
1061 | generateOpen(); |
1062 | // first try to execute queued sub-commands that could not be sent in last message |
1063 | fSessionP->ContinuePackage( |
1064 | fNextMessageCommands, |
1065 | fInterruptedCommandP |
1066 | ); |
1067 | // then generate more commands if needed (updates fInProgress) |
1068 | generateCommandsAndClose(); |
1069 | // new sync command must be queued for status again |
1070 | return true; |
1071 | } // TSyncCommand::continueIssue |
1072 | |
1073 | |
1074 | void TSyncCommand::FreeSmlElement(void) |
1075 | { |
1076 | // remove SyncML toolkit element(s) |
1077 | FREEPROTOELEMENT(fSyncElementP); |
1078 | } // TResultsCommand::FreeSmlElement |
1079 | |
1080 | |
1081 | TSyncCommand::~TSyncCommand() |
1082 | { |
1083 | // free command elements, if any (use explicit invocation as this is a destructor) |
1084 | TSyncCommand::FreeSmlElement(); |
1085 | // forget any queued sub commands |
1086 | TSmlCommandPContainer::iterator pos; |
1087 | for (pos=fNextMessageCommands.begin(); pos!=fNextMessageCommands.end(); ++pos) { |
1088 | // show that command was not sent |
1089 | DEBUGPRINTFX(DBG_ERROR,("Never sent prepared Sub-Command '%s', (outgoing MsgID=%ld, CmdID=%ld)",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Never sent prepared Sub-Command '%s', (outgoing MsgID=%ld, CmdID=%ld)" , (*pos)->getName(), (long)(*pos)->getMsgID(), (long)(* pos)->getCmdID() ); } |
1090 | (*pos)->getName(),{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Never sent prepared Sub-Command '%s', (outgoing MsgID=%ld, CmdID=%ld)" , (*pos)->getName(), (long)(*pos)->getMsgID(), (long)(* pos)->getCmdID() ); } |
1091 | (long)(*pos)->getMsgID(),{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Never sent prepared Sub-Command '%s', (outgoing MsgID=%ld, CmdID=%ld)" , (*pos)->getName(), (long)(*pos)->getMsgID(), (long)(* pos)->getCmdID() ); } |
1092 | (long)(*pos)->getCmdID(){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Never sent prepared Sub-Command '%s', (outgoing MsgID=%ld, CmdID=%ld)" , (*pos)->getName(), (long)(*pos)->getMsgID(), (long)(* pos)->getCmdID() ); } |
1093 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Never sent prepared Sub-Command '%s', (outgoing MsgID=%ld, CmdID=%ld)" , (*pos)->getName(), (long)(*pos)->getMsgID(), (long)(* pos)->getCmdID() ); }; |
1094 | // delete |
1095 | delete *pos; |
1096 | } |
1097 | fNextMessageCommands.clear(); // clear list |
1098 | // - interrupted command |
1099 | // NOTE: interrupted subcommands may NOT exist in any of the main command |
1100 | // queues, because these OWN the commands and will delete them |
1101 | // at ResetSession(). |
1102 | if (fInterruptedCommandP) { |
1103 | // show that command was not sent |
1104 | DEBUGPRINTFX(DBG_ERROR,("Never finished interrupted sub-command '%s', (outgoing MsgID=%ld, CmdID=%ld)",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Never finished interrupted sub-command '%s', (outgoing MsgID=%ld, CmdID=%ld)" , fInterruptedCommandP->getName(), (long)fInterruptedCommandP ->getMsgID(), (long)fInterruptedCommandP->getCmdID() ); } |
1105 | fInterruptedCommandP->getName(),{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Never finished interrupted sub-command '%s', (outgoing MsgID=%ld, CmdID=%ld)" , fInterruptedCommandP->getName(), (long)fInterruptedCommandP ->getMsgID(), (long)fInterruptedCommandP->getCmdID() ); } |
1106 | (long)fInterruptedCommandP->getMsgID(),{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Never finished interrupted sub-command '%s', (outgoing MsgID=%ld, CmdID=%ld)" , fInterruptedCommandP->getName(), (long)fInterruptedCommandP ->getMsgID(), (long)fInterruptedCommandP->getCmdID() ); } |
1107 | (long)fInterruptedCommandP->getCmdID(){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Never finished interrupted sub-command '%s', (outgoing MsgID=%ld, CmdID=%ld)" , fInterruptedCommandP->getName(), (long)fInterruptedCommandP ->getMsgID(), (long)fInterruptedCommandP->getCmdID() ); } |
1108 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Never finished interrupted sub-command '%s', (outgoing MsgID=%ld, CmdID=%ld)" , fInterruptedCommandP->getName(), (long)fInterruptedCommandP ->getMsgID(), (long)fInterruptedCommandP->getCmdID() ); }; |
1109 | delete fInterruptedCommandP; |
1110 | fInterruptedCommandP=NULL__null; |
1111 | } |
1112 | } // TSyncCommand::~TSyncCommand |
1113 | |
1114 | |
1115 | /* end of TSyncCommand implementation */ |
1116 | |
1117 | |
1118 | /* |
1119 | * Implementation of TSyncEndCommand |
1120 | */ |
1121 | |
1122 | |
1123 | // constructor for receiving Sync Command |
1124 | TSyncEndCommand::TSyncEndCommand( |
1125 | TSyncSession *aSessionP, // associated session (for callbacks) |
1126 | uInt32 aMsgID // the Message ID of the command |
1127 | ) : |
1128 | TSmlCommand(scmd_syncend,false,aSessionP,aMsgID) |
1129 | { |
1130 | // nop so far |
1131 | } // TSyncEndCommand::TSyncEndCommand |
1132 | |
1133 | |
1134 | // execute command (perform real actions, generate status) |
1135 | // returns true if command has executed and can be deleted |
1136 | bool TSyncEndCommand::execute(void) |
1137 | { |
1138 | bool queueforlater=false; |
1139 | |
1140 | // let session do the appropriate processing |
1141 | fSessionP->processSyncEnd(queueforlater); |
1142 | // return true if command has fully executed |
1143 | return !queueforlater; |
1144 | } // TSyncEndCommand::execute |
1145 | |
1146 | |
1147 | TSyncEndCommand::~TSyncEndCommand() |
1148 | { |
1149 | } // TSyncEndCommand::~TSyncEndCommand |
1150 | |
1151 | |
1152 | /* end of TSyncEndCommand implementation */ |
1153 | |
1154 | |
1155 | |
1156 | /* |
1157 | * Implementation of TAlertCommand |
1158 | */ |
1159 | |
1160 | |
1161 | // constructor for sending Alert |
1162 | TAlertCommand::TAlertCommand( |
1163 | TSyncSession *aSessionP, // associated session (for callbacks) |
1164 | TLocalEngineDS *aLocalDataStoreP, // local datastore |
1165 | uInt16 aAlertCode // Alert code to send |
1166 | ) : |
1167 | TSmlCommand(scmd_alert,true,aSessionP) |
1168 | { |
1169 | // save datastore |
1170 | fLocalDataStoreP = aLocalDataStoreP; |
1171 | // save Alert Code |
1172 | fAlertCode = aAlertCode; |
1173 | // create internal alert element |
1174 | fAlertElementP = SML_NEW(SmlAlert_t)((SmlAlert_t*) _smlMalloc(sizeof(SmlAlert_t))); |
1175 | // set proto element type to make it auto-disposable |
1176 | fAlertElementP->elementType=SML_PE_ALERT; |
1177 | // Cmd ID is now empty (will be set when issued) |
1178 | fAlertElementP->cmdID=NULL__null; |
1179 | // default to no flags (noResp is set at issue, if at all) |
1180 | fAlertElementP->flags=0; |
1181 | // data is alert code |
1182 | fAlertElementP->data=newPCDataLong(fAlertCode); |
1183 | // no optional elements for now |
1184 | fAlertElementP->cred=NULL__null; |
1185 | fAlertElementP->itemList=NULL__null; |
1186 | } // TAlertCommand::TAlertCommand |
1187 | |
1188 | |
1189 | // constructor for receiving Alert |
1190 | TAlertCommand::TAlertCommand( |
1191 | TSyncSession *aSessionP, // associated session (for callbacks) |
1192 | uInt32 aMsgID, // the Message ID of the command |
1193 | SmlAlertPtr_t aAlertElementP // associated Alert content element |
1194 | ) : |
1195 | TSmlCommand(scmd_alert,false,aSessionP,aMsgID) |
1196 | { |
1197 | // save alert element |
1198 | fAlertElementP = aAlertElementP; |
1199 | // no params |
1200 | fLocalDataStoreP=NULL__null; |
1201 | } // TAlertCommand::TAlertCommand |
1202 | |
1203 | |
1204 | // analyze command (but do not yet execute) |
1205 | bool TAlertCommand::analyze(TPackageStates aPackageState) |
1206 | { |
1207 | TSmlCommand::analyze(aPackageState); |
1208 | // get Command ID and flags |
1209 | if (fAlertElementP) { |
1210 | StartProcessing(fAlertElementP->cmdID,fAlertElementP->flags); |
1211 | return true; |
1212 | } |
1213 | else return false; // no proto element, bad command |
1214 | } // TAlertCommand::analyze |
1215 | |
1216 | |
1217 | // execute command (perform real actions, generate status) |
1218 | // returns true if command has executed and can be deleted |
1219 | bool TAlertCommand::execute(void) |
1220 | { |
1221 | TStatusCommand *statusCmdP=NULL__null; |
1222 | TSmlCommand *alertresponsecmdP=NULL__null; |
1223 | |
1224 | SYSYNC_TRYtry { |
1225 | // get alert code |
1226 | sInt32 temp; |
1227 | if (!smlPCDataToLong(fAlertElementP->data,temp)) { |
1228 | // non-numeric alert |
1229 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Non-Integer Alert Data: '%s', cannot handle" , smlPCDataToCharP(fAlertElementP->data) ); } |
1230 | "Non-Integer Alert Data: '%s', cannot handle",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Non-Integer Alert Data: '%s', cannot handle" , smlPCDataToCharP(fAlertElementP->data) ); } |
1231 | smlPCDataToCharP(fAlertElementP->data){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Non-Integer Alert Data: '%s', cannot handle" , smlPCDataToCharP(fAlertElementP->data) ); } |
1232 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Non-Integer Alert Data: '%s', cannot handle" , smlPCDataToCharP(fAlertElementP->data) ); }; |
1233 | statusCmdP = newStatusCommand(400,"Alert Data not understood"); |
1234 | } |
1235 | else { |
1236 | fAlertCode=temp; |
1237 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Code=%hd. %s Cred. Analyzing Items" , fAlertCode, fAlertElementP->cred ? "has" : "No" ); } |
1238 | "Code=%hd. %s Cred. Analyzing Items",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Code=%hd. %s Cred. Analyzing Items" , fAlertCode, fAlertElementP->cred ? "has" : "No" ); } |
1239 | fAlertCode,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Code=%hd. %s Cred. Analyzing Items" , fAlertCode, fAlertElementP->cred ? "has" : "No" ); } |
1240 | fAlertElementP->cred ? "has" : "No"{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Code=%hd. %s Cred. Analyzing Items" , fAlertCode, fAlertElementP->cred ? "has" : "No" ); } |
1241 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Code=%hd. %s Cred. Analyzing Items" , fAlertCode, fAlertElementP->cred ? "has" : "No" ); }; |
1242 | // intercept special codes |
1243 | if (fAlertCode==221) { |
1244 | // %%% tdb |
1245 | PDEBUGPRINTFX(DBG_ERROR,("*********** RESULT ALERT 221 received in bad context")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("*********** RESULT ALERT 221 received in bad context" ); }; |
1246 | statusCmdP = newStatusCommand(400,"221 Alert in bad context received"); |
1247 | } else if (fAlertCode==222) { |
1248 | // request next message in packet |
1249 | PDEBUGPRINTFX(DBG_HOT,("Next Message in Packet Alert (222): flag sending waiting commands")){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Next Message in Packet Alert (222): flag sending waiting commands" ); }; |
1250 | // - acknowledge 222 alert |
1251 | statusCmdP = newStatusCommand(200); |
1252 | // - add source and target refs |
1253 | statusCmdP->addTargetRef(fSessionP->getLocalURI()); |
1254 | statusCmdP->addSourceRef(fSessionP->getRemoteURI()); |
1255 | // - issue status for item (but not being sent alone with SyncHdr status) |
1256 | // (treat it like ok-synchdr-status = NOT to be sent if there's no real command following) |
1257 | { TSmlCommand* p=statusCmdP; statusCmdP=NULL__null; fSessionP->issueRootPtr(p,false,true); } |
1258 | // - signal occurrence of 222 alert to session |
1259 | fSessionP->nextMessageRequest(); |
1260 | } else { |
1261 | // normal alert, walk through items |
1262 | SmlItemListPtr_t nextitemP = fAlertElementP->itemList; |
1263 | while (nextitemP) { |
1264 | if (nextitemP->item) { |
1265 | // - check for MaxObjSize here |
1266 | SmlMetInfMetInfPtr_t metaP=smlPCDataToMetInfP(nextitemP->item->meta); |
1267 | if (metaP && metaP->maxobjsize) { |
1268 | smlPCDataToLong(metaP->maxobjsize,fSessionP->fMaxOutgoingObjSize); |
1269 | PDEBUGPRINTFX(DBG_REMOTEINFO,("MaxObjSize found in Alert command: %ld",(long)fSessionP->fMaxOutgoingObjSize)){ if (((0x00000100) & getDbgMask()) == (0x00000100)) getDbgLogger ()->setNextMask(0x00000100).DebugPrintfLastMask ("MaxObjSize found in Alert command: %ld" ,(long)fSessionP->fMaxOutgoingObjSize); }; |
1270 | } |
1271 | // process alert item with common code |
1272 | // - generate default OK status |
1273 | statusCmdP = newStatusCommand(200); |
1274 | // - add source and target refs from item |
1275 | statusCmdP->addSourceRef(smlSrcTargLocURIToCharP(nextitemP->item->source)); |
1276 | statusCmdP->addTargetRef(smlSrcTargLocURIToCharP(nextitemP->item->target)); |
1277 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "- Processing Alert Item (code=%hd), Source='%s', Target='%s'" , fAlertCode, smlSrcTargLocURIToCharP(nextitemP->item-> source), smlSrcTargLocURIToCharP(nextitemP->item->target ) ); } |
1278 | "- Processing Alert Item (code=%hd), Source='%s', Target='%s'",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "- Processing Alert Item (code=%hd), Source='%s', Target='%s'" , fAlertCode, smlSrcTargLocURIToCharP(nextitemP->item-> source), smlSrcTargLocURIToCharP(nextitemP->item->target ) ); } |
1279 | fAlertCode,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "- Processing Alert Item (code=%hd), Source='%s', Target='%s'" , fAlertCode, smlSrcTargLocURIToCharP(nextitemP->item-> source), smlSrcTargLocURIToCharP(nextitemP->item->target ) ); } |
1280 | smlSrcTargLocURIToCharP(nextitemP->item->source),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "- Processing Alert Item (code=%hd), Source='%s', Target='%s'" , fAlertCode, smlSrcTargLocURIToCharP(nextitemP->item-> source), smlSrcTargLocURIToCharP(nextitemP->item->target ) ); } |
1281 | smlSrcTargLocURIToCharP(nextitemP->item->target){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "- Processing Alert Item (code=%hd), Source='%s', Target='%s'" , fAlertCode, smlSrcTargLocURIToCharP(nextitemP->item-> source), smlSrcTargLocURIToCharP(nextitemP->item->target ) ); } |
1282 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "- Processing Alert Item (code=%hd), Source='%s', Target='%s'" , fAlertCode, smlSrcTargLocURIToCharP(nextitemP->item-> source), smlSrcTargLocURIToCharP(nextitemP->item->target ) ); }; |
1283 | // - let session process the alert item |
1284 | alertresponsecmdP = |
1285 | fSessionP->processAlertItem( |
1286 | fAlertCode, |
1287 | nextitemP->item, |
1288 | fAlertElementP->cred, |
1289 | *statusCmdP, |
1290 | fLocalDataStoreP // receives involved datastore (Note: if Alert cmd has multiple items, this will finally contain only the datastore of the last item, others might differ) |
1291 | ); |
1292 | // - issue status for item |
1293 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
1294 | // - issue result (e.g. acknowledge alert) for item, if any |
1295 | if (alertresponsecmdP) { |
1296 | fSessionP->queueForIssueRoot(alertresponsecmdP); |
1297 | } |
1298 | } |
1299 | // next |
1300 | nextitemP=nextitemP->next; |
1301 | } // while |
1302 | } // normal alert code with item |
1303 | } // numeric alert code |
1304 | // free element |
1305 | FreeSmlElement(); |
1306 | } |
1307 | SYSYNC_CATCH (...)catch(...) { |
1308 | // make sure owned objects in local scope are deleted |
1309 | if (statusCmdP) delete statusCmdP; |
1310 | if (alertresponsecmdP) delete alertresponsecmdP; |
1311 | // re-throw |
1312 | SYSYNC_RETHROWthrow; |
1313 | SYSYNC_ENDCATCH} |
1314 | // done with command, delete it now: return true |
1315 | return true; |
1316 | } // TAlertCommand::execute |
1317 | |
1318 | |
1319 | // returns true if command must be put to the waiting-for-status queue. |
1320 | // If false, command can be deleted |
1321 | bool TAlertCommand::issue( |
1322 | uInt32 aAsCmdID, // command ID to be used |
1323 | uInt32 aInMsgID, // message ID in which command is being issued |
1324 | bool aNoResp |
1325 | ) |
1326 | { |
1327 | // prepare basic stuff |
1328 | TSmlCommand::issue(aAsCmdID,aInMsgID,aNoResp); |
1329 | // now issue |
1330 | if (fAlertElementP) { |
1331 | // issue command with SyncML toolkit |
1332 | PrepareIssue(&fAlertElementP->cmdID,&fAlertElementP->flags); |
1333 | if (!fEvalMode) { |
1334 | #ifdef SYDEBUG2 |
1335 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance) |
1336 | smlAlertCmd(fSessionP->fOutgoingXMLInstance,fAlertElementP); |
1337 | #endif |
1338 | Ret_t err; |
1339 | if ((err=smlAlertCmd(fSessionP->getSmlWorkspaceID(),fAlertElementP))!=SML_ERR_OK0x00) { |
1340 | SYSYNC_THROW(TSmlException("smlAlertCmd",err))throw TSmlException("smlAlertCmd",err); |
1341 | } |
1342 | FinalizeIssue(); |
1343 | // show debug |
1344 | #ifdef SYDEBUG2 |
1345 | PDEBUGPRINTFX(DBG_HOT,("Alert Code %s sent",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Alert Code %s sent" , smlPCDataToCharP(fAlertElementP->data) ); } |
1346 | smlPCDataToCharP(fAlertElementP->data){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Alert Code %s sent" , smlPCDataToCharP(fAlertElementP->data) ); } |
1347 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Alert Code %s sent" , smlPCDataToCharP(fAlertElementP->data) ); }; |
1348 | // normal alert, walk through items |
1349 | SmlItemListPtr_t nextitemP = fAlertElementP->itemList; |
1350 | while (nextitemP) { |
1351 | if (nextitemP->item) { |
1352 | // show alert item |
1353 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "- Alert Item: Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(nextitemP->item->source), smlSrcTargLocURIToCharP (nextitemP->item->target) ); } |
1354 | "- Alert Item: Source='%s', Target='%s'",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "- Alert Item: Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(nextitemP->item->source), smlSrcTargLocURIToCharP (nextitemP->item->target) ); } |
1355 | smlSrcTargLocURIToCharP(nextitemP->item->source),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "- Alert Item: Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(nextitemP->item->source), smlSrcTargLocURIToCharP (nextitemP->item->target) ); } |
1356 | smlSrcTargLocURIToCharP(nextitemP->item->target){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "- Alert Item: Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(nextitemP->item->source), smlSrcTargLocURIToCharP (nextitemP->item->target) ); } |
1357 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "- Alert Item: Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(nextitemP->item->source), smlSrcTargLocURIToCharP (nextitemP->item->target) ); }; |
1358 | } |
1359 | // next |
1360 | nextitemP=nextitemP->next; |
1361 | /// @note %%% we should not send more than one item for now! |
1362 | if (nextitemP) |
1363 | DEBUGPRINTFX(DBG_ERROR,("More than one item - handleStatus is not prepared for that!")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("More than one item - handleStatus is not prepared for that!" ); }; |
1364 | } // while |
1365 | #endif |
1366 | // we don't need the status structure any more, free (and NULL ptr) now |
1367 | FreeSmlElement(); |
1368 | } |
1369 | else |
1370 | return smlAlertCmd(fSessionP->getSmlWorkspaceID(),fAlertElementP)==SML_ERR_OK0x00; |
1371 | } |
1372 | else { |
1373 | DEBUGPRINTFX(DBG_ERROR,("*** Tried to issue NULL alert")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("*** Tried to issue NULL alert" ); }; |
1374 | } |
1375 | // return true if command must be queued for status/result response reception |
1376 | return queueForResponse(); |
1377 | } // TAlertCommand::issue |
1378 | |
1379 | |
1380 | bool TAlertCommand::statusEssential(void) |
1381 | { |
1382 | // Alert 222 status is not essential |
1383 | return !(fAlertCode==222); |
1384 | } // TAlertCommand::statusEssential |
1385 | |
1386 | |
1387 | // handle status received for previously issued command |
1388 | // returns true if done, false if command must be kept in the status queue |
1389 | bool TAlertCommand::handleStatus(TStatusCommand *aStatusCmdP) |
1390 | { |
1391 | /// @note: This is a simplified implementation which KNOWS that |
1392 | /// we do not send Alerts with more than one item. If we did one |
1393 | /// day, we'd have to extend this implementation. |
1394 | // if this alert command was created by a datastore, let it handle it |
1395 | if (fLocalDataStoreP) { |
1396 | // pass to local datastore |
1397 | if (fLocalDataStoreP->engHandleAlertStatus(aStatusCmdP->getStatusCode())) |
1398 | return true; // datastore handled it |
1399 | } |
1400 | // let SmlCommand handle it |
1401 | return TSmlCommand::handleStatus(aStatusCmdP); |
1402 | } // TAlertCommand::handleStatus |
1403 | |
1404 | |
1405 | // add a String Item to the alert |
1406 | void TAlertCommand::addItemString( |
1407 | const char *aItemString // item string to be added |
1408 | ) |
1409 | { |
1410 | if (fAlertElementP && aItemString) { |
1411 | addItem(newStringDataItem(aItemString)); |
1412 | } |
1413 | } // TAlertCommand::addItemString |
1414 | |
1415 | |
1416 | // add an Item to the alert |
1417 | void TAlertCommand::addItem( |
1418 | SmlItemPtr_t aItemP // existing item data structure, ownership is passed to Alert |
1419 | ) |
1420 | { |
1421 | if (fAlertElementP) |
1422 | addItemToList(aItemP,&(fAlertElementP->itemList)); |
1423 | } // TAlertCommand::addItem |
1424 | |
1425 | |
1426 | void TAlertCommand::FreeSmlElement(void) |
1427 | { |
1428 | // remove SyncML toolkit element(s) |
1429 | FREEPROTOELEMENT(fAlertElementP); |
1430 | } // TResultsCommand::FreeSmlElement |
1431 | |
1432 | |
1433 | TAlertCommand::~TAlertCommand() |
1434 | { |
1435 | // free command elements, if any (use explicit invocation as this is a destructor) |
1436 | TAlertCommand::FreeSmlElement(); |
1437 | } // TAlertCommand::~TAlertCommand |
1438 | |
1439 | |
1440 | /* end of TAlertCommand implementation */ |
1441 | |
1442 | |
1443 | |
1444 | |
1445 | |
1446 | /* |
1447 | * Implementation of TUnimplementedCommand |
1448 | */ |
1449 | |
1450 | |
1451 | // constructor for receiving command |
1452 | TUnimplementedCommand::TUnimplementedCommand( |
1453 | TSyncSession *aSessionP, // associated session (for callbacks) |
1454 | uInt32 aMsgID, // the Message ID of the command |
1455 | SmlPcdataPtr_t aCmdID, // command ID (as contents are unknown an cannot be analyzed) |
1456 | Flag_t aFlags, // flags to get fNoResp |
1457 | TSmlCommandTypes aCmdType, // command type (for name) |
1458 | void *aContentP, // associated command content element |
1459 | TSyError aStatusCode // status code to be returned on execution |
1460 | ) : |
1461 | TSmlCommand(aCmdType,false,aSessionP,aMsgID) |
1462 | { |
1463 | // get command ID |
1464 | StrToULong(smlPCDataToCharP(aCmdID),fCmdID); |
1465 | // save noResp |
1466 | fNoResp=(aFlags & SmlNoResp_f0x0100)!=0; |
1467 | // forget element |
1468 | smlFreeProtoElement(aContentP); |
1469 | // save status type |
1470 | fStatusCode=aStatusCode; |
1471 | } // TUnimplementedCommand::TUnimplementedCommand |
1472 | |
1473 | |
1474 | // execute command (perform real actions, generate status) |
1475 | // returns true if command has executed and can be deleted |
1476 | bool TUnimplementedCommand::execute(void) |
1477 | { |
1478 | TStatusCommand *statusCmdP=NULL__null; |
1479 | |
1480 | DEBUGPRINTFX(DBG_HOT,("UNIMPLEMENTED, started dummy processing, (incoming MsgID=%ld, CmdID=%ld)",(long)fMsgID,(long)fCmdID)){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("UNIMPLEMENTED, started dummy processing, (incoming MsgID=%ld, CmdID=%ld)" ,(long)fMsgID,(long)fCmdID); }; |
1481 | SYSYNC_TRYtry { |
1482 | statusCmdP = newStatusCommand(fStatusCode); |
1483 | statusCmdP->addItemString("Unimplemented Command"); |
1484 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
1485 | } |
1486 | SYSYNC_CATCH (...)catch(...) { |
1487 | // make sure owned objects in local scope are deleted |
1488 | if (statusCmdP) delete statusCmdP; |
1489 | // re-throw |
1490 | SYSYNC_RETHROWthrow; |
1491 | SYSYNC_ENDCATCH} |
1492 | // done with command, delete it now: return true |
1493 | return true; |
1494 | } // TUnimplementedCommand::execute |
1495 | |
1496 | |
1497 | /* end of TUnimplementedCommand implementation */ |
1498 | |
1499 | |
1500 | |
1501 | /* |
1502 | * Implementation of TSyncOpCommand |
1503 | */ |
1504 | |
1505 | // constructor for receiving command |
1506 | TSyncOpCommand::TSyncOpCommand( |
1507 | TSyncSession *aSessionP, // associated session (for callbacks) |
1508 | TLocalEngineDS *aDataStoreP, // the local datastore this syncop belongs to |
1509 | uInt32 aMsgID, // the Message ID of the command |
1510 | TSyncOperation aSyncOp, // the Sync operation (sop_xxx) |
1511 | TSmlCommandTypes aCmdType, // the command type (scmd_xxx) |
1512 | SmlGenericCmdPtr_t aSyncOpElementP // associated syncml protocol element |
1513 | ) : |
1514 | TSmlCommand(aCmdType,false,aSessionP,aMsgID) |
1515 | { |
1516 | // save datastore |
1517 | fDataStoreP=aDataStoreP; |
1518 | // save operation type |
1519 | fSyncOp=aSyncOp; |
1520 | // save element |
1521 | fSyncOpElementP = aSyncOpElementP; |
1522 | // no remainder to be sent as next chunk |
1523 | fChunkedItemSize = 0; |
1524 | fIncompleteData = false; |
1525 | // no suspended part of item |
1526 | fStoredSize=0; |
1527 | fUnconfirmedSize=0; |
1528 | fLastChunkSize=0; |
1529 | } // TSyncOpCommand::TSyncOpCommand |
1530 | |
1531 | |
1532 | // constructor for sending command |
1533 | TSyncOpCommand::TSyncOpCommand( |
1534 | TSyncSession *aSessionP, // associated session (for callbacks) |
1535 | TLocalEngineDS *aDataStoreP, // datastore from which command originates |
1536 | TSyncOperation aSyncOp, // sync operation (=command type) |
1537 | SmlPcdataPtr_t aMetaP // meta for entire command (passing owner) |
1538 | ) : |
1539 | TSmlCommand(scmd_unknown,true,aSessionP) |
1540 | { |
1541 | // save datastore |
1542 | fDataStoreP=aDataStoreP; |
1543 | #ifndef USE_SML_EVALUATION1 |
1544 | // no items yet |
1545 | fItemSizes=0; |
1546 | #endif |
1547 | // no remainder to be sent as next chunk |
1548 | fChunkedItemSize = 0; |
1549 | fIncompleteData = false; |
1550 | // no suspended part of item |
1551 | fStoredSize=0; |
1552 | fUnconfirmedSize=0; |
1553 | fLastChunkSize=0; |
1554 | // command type not yet determined |
1555 | fSyncOp=aSyncOp; |
1556 | // create internal alert element |
1557 | fSyncOpElementP = SML_NEW(SmlGenericCmd_t)((SmlGenericCmd_t*) _smlMalloc(sizeof(SmlGenericCmd_t))); |
1558 | // set default to make sure it is disposable (will be adjusted when items are added) |
1559 | fSyncOpElementP->elementType=SML_PE_GENERIC; |
1560 | // Cmd ID is now empty (will be set when issued) |
1561 | fSyncOpElementP->cmdID=NULL__null; |
1562 | // default to no flags (noResp is set at issue, if at all) |
1563 | fSyncOpElementP->flags=0; |
1564 | // insert meta, if any |
1565 | fSyncOpElementP->meta=aMetaP; |
1566 | // no optional elements for now |
1567 | fSyncOpElementP->cred=NULL__null; |
1568 | fSyncOpElementP->itemList=NULL__null; |
1569 | // determine command type |
1570 | switch (fSyncOp) { |
1571 | case sop_wants_add: |
1572 | case sop_add: |
1573 | fSyncOpElementP->elementType=SML_PE_ADD; |
1574 | fCmdType=scmd_add; |
1575 | break; |
1576 | case sop_copy: |
1577 | fSyncOpElementP->elementType=SML_PE_COPY; |
1578 | fCmdType=scmd_copy; |
1579 | break; |
1580 | case sop_move: |
1581 | fSyncOpElementP->elementType=SML_PE_MOVE; |
1582 | fCmdType=scmd_move; |
1583 | break; |
1584 | case sop_wants_replace: |
1585 | case sop_replace: |
1586 | fSyncOpElementP->elementType=SML_PE_REPLACE; |
1587 | fCmdType=scmd_replace; |
1588 | break; |
1589 | case sop_archive_delete: |
1590 | fSyncOpElementP->flags |= SmlArchive_f0x8000; |
1591 | goto dodelete; |
1592 | case sop_soft_delete: |
1593 | fSyncOpElementP->flags |= SmlSftDel_f0x4000; |
1594 | case sop_delete: |
1595 | dodelete: |
1596 | fSyncOpElementP->elementType=SML_PE_DELETE; |
1597 | fCmdType=scmd_delete; |
1598 | break; |
1599 | default: |
1600 | SYSYNC_THROW(TSyncException("Invalid SyncOp in TSyncOpCommand"))throw TSyncException("Invalid SyncOp in TSyncOpCommand"); |
1601 | //break; |
1602 | } // switch |
1603 | } // TSyncOpCommand::TSyncOpCommand |
1604 | |
1605 | |
1606 | #ifndef USE_SML_EVALUATION1 |
1607 | |
1608 | // get (approximated) message size required for sending it |
1609 | uInt32 TSyncOpCommand::messageSize(void) |
1610 | { |
1611 | // default, should be enough for most commands |
1612 | return TSmlCommand::messageSize()+fItemSizes; |
1613 | } |
1614 | |
1615 | #endif |
1616 | |
1617 | |
1618 | // handle status received for previously issued command |
1619 | // returns true if done, false if command must be kept in the status queue |
1620 | bool TSyncOpCommand::handleStatus(TStatusCommand *aStatusCmdP) |
1621 | { |
1622 | // check if this is a split command |
1623 | if (fIncompleteData) { |
1624 | // must be 213 |
1625 | if (aStatusCmdP->getStatusCode()==213) return true; |
1626 | // something wrong, we did not get a 213 |
1627 | PDEBUGPRINTFX(DBG_ERROR,("chunked object received status %hd instead of 213 --> aborting session",aStatusCmdP->getStatusCode())){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("chunked object received status %hd instead of 213 --> aborting session" ,aStatusCmdP->getStatusCode()); }; |
1628 | // reason for aborting is incomplete command (reception) |
1629 | fSessionP->AbortSession(412,true); // local problem |
1630 | } |
1631 | else { |
1632 | // end of non-split SyncOp means that possibly saved |
1633 | // parts of partial outgoing item are now obsolete |
1634 | if (fDataStoreP->fPartialItemState==pi_state_save_outgoing) { |
1635 | fDataStoreP->fPartialItemState=pi_state_none; // not any more |
1636 | PDEBUGPRINTFX(DBG_PROTO+DBG_EXOTIC,("chunked object received final status %hd --> forget partial item data now",aStatusCmdP->getStatusCode())){ if (((0x00000010 +0x80000000) & getDbgMask()) == (0x00000010 +0x80000000)) getDbgLogger()->setNextMask(0x00000010 +0x80000000 ).DebugPrintfLastMask ("chunked object received final status %hd --> forget partial item data now" ,aStatusCmdP->getStatusCode()); }; |
1637 | // - forget stored data in case we have any |
1638 | if (fDataStoreP->fPIStoredDataP) { |
1639 | if (fDataStoreP->fPIStoredDataAllocated) |
1640 | smlLibFree(fDataStoreP->fPIStoredDataP); |
1641 | fDataStoreP->fPIStoredDataP=NULL__null; |
1642 | fDataStoreP->fPIStoredDataAllocated=false; // not any more |
1643 | } |
1644 | // - clear URIs |
1645 | fDataStoreP->fLastSourceURI.erase(); |
1646 | fDataStoreP->fLastTargetURI.erase(); |
1647 | // - clear other flags |
1648 | fDataStoreP->fLastItemStatus=0; // none left to send |
1649 | fDataStoreP->fPITotalSize=0; |
1650 | fDataStoreP->fPIUnconfirmedSize=0; |
1651 | fDataStoreP->fPIStoredSize=0; |
1652 | } |
1653 | } |
1654 | // let datastore handle this |
1655 | // Note: as fDataStoreP is linked to the generating datastore, this will never be |
1656 | // a superdatastore. engHandleSyncOpStatus() is prepared to convert |
1657 | // superID prefixed localIDs back to subDS's localID |
1658 | bool handled=false; |
1659 | if (fDataStoreP) { |
1660 | handled=fDataStoreP->engHandleSyncOpStatus(aStatusCmdP,this); |
1661 | } |
1662 | if (!handled) { |
1663 | // let base class handle it |
1664 | handled=TSmlCommand::handleStatus(aStatusCmdP); |
1665 | } |
1666 | return handled; |
1667 | } // TSyncOpCommand::handleStatus |
1668 | |
1669 | |
1670 | // mark any syncitems (or other data) for resume. Called for pending commands |
1671 | // when a Suspend alert is received or whenever a resumable state must be saved |
1672 | void TSyncOpCommand::markPendingForResume(TLocalEngineDS *aForDatastoreP, bool aUnsent) |
1673 | { |
1674 | // only act if this is for our local datastore, and only outgoing ones! |
1675 | if (fOutgoing && fDataStoreP==aForDatastoreP && fSyncOpElementP) { |
1676 | // go through all of my items |
1677 | SmlItemListPtr_t itemListP = fSyncOpElementP->itemList; |
1678 | SmlItemPtr_t itemP; |
1679 | while (itemListP) { |
1680 | itemP=itemListP->item; |
1681 | if (itemP) { |
1682 | // call datastore to mark this one for resume |
1683 | fDataStoreP->engMarkItemForResume( |
1684 | smlSrcTargLocURIToCharP(itemP->source), // source for outgoing items is localID |
1685 | smlSrcTargLocURIToCharP(itemP->target), // target for outgoing items is remoteID |
1686 | fIncompleteData ? true : aUnsent // if not completely sent yet, always treat it as unsent! |
1687 | ); |
1688 | } |
1689 | itemListP=itemListP->next; |
1690 | } |
1691 | } |
1692 | } // TSyncOpCommand::markPendingForResume |
1693 | |
1694 | |
1695 | |
1696 | // mark item for resend in next sync session (if possible) |
1697 | void TSyncOpCommand::markForResend(void) |
1698 | { |
1699 | if (fOutgoing && fDataStoreP) { |
1700 | // go through all of my items |
1701 | SmlItemListPtr_t itemListP = fSyncOpElementP->itemList; |
1702 | SmlItemPtr_t itemP; |
1703 | while (itemListP) { |
1704 | itemP=itemListP->item; |
1705 | if (itemP) { |
1706 | // call datastore to mark this one for resume |
1707 | fDataStoreP->engMarkItemForResend( |
1708 | smlSrcTargLocURIToCharP(itemP->source), // source for outgoing items is localID |
1709 | smlSrcTargLocURIToCharP(itemP->target) // target for outgoing items is remoteID |
1710 | ); |
1711 | } |
1712 | itemListP=itemListP->next; |
1713 | } |
1714 | } |
1715 | } // TSyncOpCommand::markForResend |
1716 | |
1717 | |
1718 | |
1719 | // let item update the partial item state for suspend |
1720 | // Note: this may only be called for an item that is actually the partial item |
1721 | void TSyncOpCommand::updatePartialItemState(TLocalEngineDS *aForDatastoreP) |
1722 | { |
1723 | if (!fOutgoing && fDataStoreP==aForDatastoreP && fDataStoreP->dsResumeChunkedSupportedInDB()) { |
1724 | // save info for only partially received item |
1725 | fDataStoreP->fLastItemStatus = 0; // no status sent yet |
1726 | // pass current item data |
1727 | // - get last item data |
1728 | SmlItemListPtr_t itemnodeP=fSyncOpElementP->itemList; |
1729 | while (itemnodeP) { |
1730 | if (!itemnodeP->next) { |
1731 | // this is the last item |
1732 | fDataStoreP->fPartialItemState=pi_state_save_incoming; |
1733 | // - get total expected size |
1734 | fDataStoreP->fPITotalSize=0; |
1735 | SmlMetInfMetInfPtr_t metaP = smlPCDataToMetInfP(itemnodeP->item->meta); |
1736 | if (!metaP || !metaP->size) { |
1737 | // item has no meta or no meta-size, so size must be in meta of command |
1738 | metaP = smlPCDataToMetInfP(fSyncOpElementP->meta); |
1739 | } |
1740 | if (metaP) smlPCDataToULong(metaP->size, fDataStoreP->fPITotalSize); |
1741 | // - get data |
1742 | if (itemnodeP->item && itemnodeP->item->data) { |
1743 | // dispose current contents if these were separately allocated |
1744 | // (otherwise, we can just overwrite the pointer) |
1745 | if (fDataStoreP->fPIStoredDataP && fDataStoreP->fPIStoredDataAllocated) |
1746 | smlLibFree(fDataStoreP->fPIStoredDataP); |
1747 | // datastore does NOT get owner of the data! |
1748 | fDataStoreP->fPIStoredDataAllocated=false; // we still own that data, session must NOT try to dispose! |
1749 | fDataStoreP->fPIStoredSize=itemnodeP->item->data->length; |
1750 | fDataStoreP->fPIStoredDataP=itemnodeP->item->data->content; |
1751 | } |
1752 | // - get amount of stored data that is unconfirmed |
1753 | // (=the size of the most recently received chunk. This is unconfirmed |
1754 | // until the next chunk arrives, because we don't know before that if the |
1755 | // status 213 has reached the sender) |
1756 | fDataStoreP->fPIUnconfirmedSize=fLastChunkSize; |
1757 | // summarize |
1758 | PDEBUGPRINTFX(DBG_ADMIN,({ if (((0x00000040) & getDbgMask()) == (0x00000040)) getDbgLogger ()->setNextMask(0x00000040).DebugPrintfLastMask ( "State of partially received item: total size=%ld, received=%ld, unconfirmed=%ld" , (long)fDataStoreP->fPITotalSize, (long)fDataStoreP->fPIStoredSize , (long)fDataStoreP->fPIUnconfirmedSize ); } |
1759 | "State of partially received item: total size=%ld, received=%ld, unconfirmed=%ld",{ if (((0x00000040) & getDbgMask()) == (0x00000040)) getDbgLogger ()->setNextMask(0x00000040).DebugPrintfLastMask ( "State of partially received item: total size=%ld, received=%ld, unconfirmed=%ld" , (long)fDataStoreP->fPITotalSize, (long)fDataStoreP->fPIStoredSize , (long)fDataStoreP->fPIUnconfirmedSize ); } |
1760 | (long)fDataStoreP->fPITotalSize,{ if (((0x00000040) & getDbgMask()) == (0x00000040)) getDbgLogger ()->setNextMask(0x00000040).DebugPrintfLastMask ( "State of partially received item: total size=%ld, received=%ld, unconfirmed=%ld" , (long)fDataStoreP->fPITotalSize, (long)fDataStoreP->fPIStoredSize , (long)fDataStoreP->fPIUnconfirmedSize ); } |
1761 | (long)fDataStoreP->fPIStoredSize,{ if (((0x00000040) & getDbgMask()) == (0x00000040)) getDbgLogger ()->setNextMask(0x00000040).DebugPrintfLastMask ( "State of partially received item: total size=%ld, received=%ld, unconfirmed=%ld" , (long)fDataStoreP->fPITotalSize, (long)fDataStoreP->fPIStoredSize , (long)fDataStoreP->fPIUnconfirmedSize ); } |
1762 | (long)fDataStoreP->fPIUnconfirmedSize{ if (((0x00000040) & getDbgMask()) == (0x00000040)) getDbgLogger ()->setNextMask(0x00000040).DebugPrintfLastMask ( "State of partially received item: total size=%ld, received=%ld, unconfirmed=%ld" , (long)fDataStoreP->fPITotalSize, (long)fDataStoreP->fPIStoredSize , (long)fDataStoreP->fPIUnconfirmedSize ); } |
1763 | )){ if (((0x00000040) & getDbgMask()) == (0x00000040)) getDbgLogger ()->setNextMask(0x00000040).DebugPrintfLastMask ( "State of partially received item: total size=%ld, received=%ld, unconfirmed=%ld" , (long)fDataStoreP->fPITotalSize, (long)fDataStoreP->fPIStoredSize , (long)fDataStoreP->fPIUnconfirmedSize ); }; |
1764 | // done |
1765 | break; |
1766 | } |
1767 | itemnodeP=itemnodeP->next; |
1768 | } // while |
1769 | } |
1770 | } // TSyncOpCommand::updatePartialItemState |
1771 | |
1772 | |
1773 | // get source (localID) of sent command |
1774 | cAppCharP TSyncOpCommand::getSourceLocalID(void) |
1775 | { |
1776 | if (!fSyncOpElementP) return NULL__null; |
1777 | if (!fSyncOpElementP->itemList) return NULL__null; |
1778 | if (!fSyncOpElementP->itemList->item) return NULL__null; |
1779 | return smlSrcTargLocURIToCharP(fSyncOpElementP->itemList->item->source); |
1780 | } // TSyncOpCommand::getSourceLocalID |
1781 | |
1782 | |
1783 | // get target (remoteID) of sent command |
1784 | cAppCharP TSyncOpCommand::getTargetRemoteID(void) |
1785 | { |
1786 | if (!fSyncOpElementP) return NULL__null; |
1787 | if (!fSyncOpElementP->itemList) return NULL__null; |
1788 | if (!fSyncOpElementP->itemList->item) return NULL__null; |
1789 | return smlSrcTargLocURIToCharP(fSyncOpElementP->itemList->item->target); |
1790 | } // TSyncOpCommand::getTargetRemoteID |
1791 | |
1792 | |
1793 | // add an Item to the sync op command |
1794 | void TSyncOpCommand::addItem( |
1795 | SmlItemPtr_t aItemP // existing item data structure, ownership is passed to SyncOp command |
1796 | ) |
1797 | { |
1798 | // add item |
1799 | if (fSyncOpElementP) { |
1800 | addItemToList(aItemP,&(fSyncOpElementP->itemList)); |
1801 | #ifndef USE_SML_EVALUATION1 |
1802 | fItemSizes += |
1803 | ITEMOVERHEADSIZE90 + |
1804 | strlen(smlSrcTargLocURIToCharP(aItemP->target)) + |
1805 | strlen(smlSrcTargLocNameToCharP(aItemP->target)) + |
1806 | strlen(smlSrcTargLocURIToCharP(aItemP->source)) + |
1807 | strlen(smlSrcTargLocNameToCharP(aItemP->source)); |
1808 | SmlMetInfMetInfPtr_t metaP = smlPCDataToMetInfP(aItemP->meta); |
1809 | if (metaP) fItemSizes+=strlen(smlPCDataToCharP(metaP->type)); |
1810 | if (aItemP->data) fItemSizes+=aItemP->data->length; |
1811 | #endif |
1812 | } |
1813 | } // TSyncOpCommand::addItem |
1814 | |
1815 | |
1816 | |
1817 | // helper: add dataPos EMI to meta |
1818 | static void addDataPos(SmlMetInfMetInfPtr_t aMetaP, uInt32 aDataPos) |
1819 | { |
1820 | // - find end of emi list or existing datapos |
1821 | SmlPcdataListPtr_t *emiPP = &(aMetaP->emi); |
1822 | /* version that searches for existing datapos and will replace it |
1823 | while (*emiPP!=NULL) { |
1824 | if (strucmp(smlPCDataToCharP((*emiPP)->data),"datapos=",8)==0) { |
1825 | // found existing datapos |
1826 | break; |
1827 | } |
1828 | emiPP = &((*emiPP)->next); |
1829 | } |
1830 | if (*emiPP==NULL) { |
1831 | // - add new EMI |
1832 | *emiPP=(SmlPcdataListPtr_t)smlLibMalloc(sizeof(SmlPcdataList_t)); |
1833 | (*emiPP)->next=NULL; |
1834 | } |
1835 | else { |
1836 | // - replace existing |
1837 | smlFreePcdata((*emiPP)->data); |
1838 | } |
1839 | */ |
1840 | while (*emiPP!=NULL__null) emiPP = &((*emiPP)->next); |
1841 | // - add new EMI list element |
1842 | *emiPP=(SmlPcdataListPtr_t)smlLibMalloc(sizeof(SmlPcdataList_t)); |
1843 | (*emiPP)->next=NULL__null; |
1844 | // - set new data |
1845 | string s; |
1846 | StringObjPrintf(s,"datapos=%ld",(long)aDataPos); |
1847 | (*emiPP)->data = newPCDataString(s.c_str(),s.size()); |
1848 | } // addDataPos |
1849 | |
1850 | |
1851 | |
1852 | void TSyncOpCommand::saveAsPartialItem(SmlItemPtr_t aItemP) |
1853 | { |
1854 | // - forget stored data in case we have any |
1855 | if (fDataStoreP->fPIStoredDataP) { |
1856 | if (fDataStoreP->fPIStoredDataAllocated) |
1857 | smlLibFree(fDataStoreP->fPIStoredDataP); |
1858 | fDataStoreP->fPIStoredDataP=NULL__null; |
1859 | fDataStoreP->fPIStoredDataAllocated=false; // not any more |
1860 | } |
1861 | // save only when we can actually store chunk resume data |
1862 | if (fDataStoreP->dsResumeChunkedSupportedInDB()) { |
1863 | // - save URIs |
1864 | fDataStoreP->fLastSourceURI=smlSrcTargLocURIToCharP(aItemP->source); |
1865 | fDataStoreP->fLastTargetURI=smlSrcTargLocURIToCharP(aItemP->target); |
1866 | // - copy current item's data now (before the split!) |
1867 | fDataStoreP->fPIStoredDataAllocated=true; // separately allocated buffer, not connected with item any more |
1868 | fDataStoreP->fPIStoredSize=aItemP->data->length; // length of unsplitted item's buffer |
1869 | fDataStoreP->fPIStoredDataP=smlLibMalloc(aItemP->data->length); |
1870 | smlLibMemcpy((uInt8 *)fDataStoreP->fPIStoredDataP,aItemP->data->content,aItemP->data->length); |
1871 | // - set other flags |
1872 | fDataStoreP->fLastItemStatus=0; // none left to send |
1873 | fDataStoreP->fPartialItemState=pi_state_save_outgoing; |
1874 | fDataStoreP->fPITotalSize=fChunkedItemSize; |
1875 | fDataStoreP->fPIUnconfirmedSize=fDataStoreP->fPIStoredSize; // just a copy |
1876 | } |
1877 | } // TSyncOpCommand::saveAsPartialItem |
1878 | |
1879 | |
1880 | // - possibly substitute data with previous session's buffered left-overs from a chunked transfer |
1881 | // for resuming a chunked item transfer. |
1882 | bool TSyncOpCommand::checkChunkContinuation(void) |
1883 | { |
1884 | if (fChunkedItemSize==0 && fDataStoreP && fDataStoreP->fPartialItemState==pi_state_loaded_outgoing) { |
1885 | // this is a so far unchunked item, and there is |
1886 | // to-be-resent data from the previously suspended session |
1887 | // - check if the command contains the partially sent item |
1888 | SmlItemListPtr_t itemListP = fSyncOpElementP->itemList; |
1889 | while (itemListP) { |
1890 | if ( |
1891 | itemListP->item && |
1892 | strcmp(smlSrcTargLocURIToCharP(itemListP->item->source),fDataStoreP->fLastSourceURI.c_str())==0 && |
1893 | strcmp(smlSrcTargLocURIToCharP(itemListP->item->target),fDataStoreP->fLastTargetURI.c_str())==0 |
1894 | ) { |
1895 | // detected to-be-continued chunked item |
1896 | PDEBUGPRINTFX(DBG_PROTO+DBG_HOT,({ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Resuming sending chunked item Source='%s', Target='%s' -> replacing data with rest from suspended session" , fDataStoreP->fLastSourceURI.c_str(), fDataStoreP->fLastTargetURI .c_str() ); } |
1897 | "Resuming sending chunked item Source='%s', Target='%s' -> replacing data with rest from suspended session",{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Resuming sending chunked item Source='%s', Target='%s' -> replacing data with rest from suspended session" , fDataStoreP->fLastSourceURI.c_str(), fDataStoreP->fLastTargetURI .c_str() ); } |
1898 | fDataStoreP->fLastSourceURI.c_str(),{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Resuming sending chunked item Source='%s', Target='%s' -> replacing data with rest from suspended session" , fDataStoreP->fLastSourceURI.c_str(), fDataStoreP->fLastTargetURI .c_str() ); } |
1899 | fDataStoreP->fLastTargetURI.c_str(){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Resuming sending chunked item Source='%s', Target='%s' -> replacing data with rest from suspended session" , fDataStoreP->fLastSourceURI.c_str(), fDataStoreP->fLastTargetURI .c_str() ); } |
1900 | )){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Resuming sending chunked item Source='%s', Target='%s' -> replacing data with rest from suspended session" , fDataStoreP->fLastSourceURI.c_str(), fDataStoreP->fLastTargetURI .c_str() ); }; |
1901 | // Do not send meta size on all but first chunk |
1902 | SmlMetInfMetInfPtr_t metinfP = itemListP->item->meta ? (SmlMetInfMetInfPtr_t)(itemListP->item->meta->content) : NULL__null; |
1903 | if (metinfP && metinfP->size) { |
1904 | smlFreePcdata(metinfP->size); |
1905 | metinfP->size=NULL__null; |
1906 | } |
1907 | // But make sure item knows the original total size (prevents splitCommand to add meta size again) |
1908 | fChunkedItemSize = fDataStoreP->fPITotalSize; |
1909 | // now add dataPos as <meta><EMI>: fPITotalSize-fPIStoredSize |
1910 | // - make sure we have meta |
1911 | if (!metinfP) { |
1912 | itemListP->item->meta=newMeta(); |
1913 | metinfP=(SmlMetInfMetInfPtr_t)(itemListP->item->meta->content); |
1914 | } |
1915 | // - add it (total - what remains to be sent) |
1916 | addDataPos(metinfP,fDataStoreP->fPITotalSize-fDataStoreP->fPIStoredSize); |
1917 | // update buffered data info |
1918 | if (itemListP->item->data) { |
1919 | // substitute original data with buffered rest of data from last session |
1920 | // (so in case the item has changed in the local DB, we'll still send the original data of |
1921 | // which the receiver already has seen a part) |
1922 | PDEBUGPRINTFX(DBG_PROTO+DBG_DETAILS,({ if (((0x00000010 +0x40000000) & getDbgMask()) == (0x00000010 +0x40000000)) getDbgLogger()->setNextMask(0x00000010 +0x40000000 ).DebugPrintfLastMask ( "original data size of item=%ld, total size at time of suspend=%ld, rest being sent now=%ld" , (long)itemListP->item->data->length, (long)fDataStoreP ->fPITotalSize, (long)fDataStoreP->fPIStoredSize ); } |
1923 | "original data size of item=%ld, total size at time of suspend=%ld, rest being sent now=%ld",{ if (((0x00000010 +0x40000000) & getDbgMask()) == (0x00000010 +0x40000000)) getDbgLogger()->setNextMask(0x00000010 +0x40000000 ).DebugPrintfLastMask ( "original data size of item=%ld, total size at time of suspend=%ld, rest being sent now=%ld" , (long)itemListP->item->data->length, (long)fDataStoreP ->fPITotalSize, (long)fDataStoreP->fPIStoredSize ); } |
1924 | (long)itemListP->item->data->length, // current total size{ if (((0x00000010 +0x40000000) & getDbgMask()) == (0x00000010 +0x40000000)) getDbgLogger()->setNextMask(0x00000010 +0x40000000 ).DebugPrintfLastMask ( "original data size of item=%ld, total size at time of suspend=%ld, rest being sent now=%ld" , (long)itemListP->item->data->length, (long)fDataStoreP ->fPITotalSize, (long)fDataStoreP->fPIStoredSize ); } |
1925 | (long)fDataStoreP->fPITotalSize, // total size at time of suspend{ if (((0x00000010 +0x40000000) & getDbgMask()) == (0x00000010 +0x40000000)) getDbgLogger()->setNextMask(0x00000010 +0x40000000 ).DebugPrintfLastMask ( "original data size of item=%ld, total size at time of suspend=%ld, rest being sent now=%ld" , (long)itemListP->item->data->length, (long)fDataStoreP ->fPITotalSize, (long)fDataStoreP->fPIStoredSize ); } |
1926 | (long)fDataStoreP->fPIStoredSize // what we will send now{ if (((0x00000010 +0x40000000) & getDbgMask()) == (0x00000010 +0x40000000)) getDbgLogger()->setNextMask(0x00000010 +0x40000000 ).DebugPrintfLastMask ( "original data size of item=%ld, total size at time of suspend=%ld, rest being sent now=%ld" , (long)itemListP->item->data->length, (long)fDataStoreP ->fPITotalSize, (long)fDataStoreP->fPIStoredSize ); } |
1927 | )){ if (((0x00000010 +0x40000000) & getDbgMask()) == (0x00000010 +0x40000000)) getDbgLogger()->setNextMask(0x00000010 +0x40000000 ).DebugPrintfLastMask ( "original data size of item=%ld, total size at time of suspend=%ld, rest being sent now=%ld" , (long)itemListP->item->data->length, (long)fDataStoreP ->fPITotalSize, (long)fDataStoreP->fPIStoredSize ); }; |
1928 | // dispose current data |
1929 | smlLibFree(itemListP->item->data->content); |
1930 | // set new data from last session |
1931 | itemListP->item->data->length=fDataStoreP->fPIStoredSize; |
1932 | itemListP->item->data->content=fDataStoreP->fPIStoredDataP; |
1933 | // data is now owned by item |
1934 | fDataStoreP->fPIStoredDataP=NULL__null; |
1935 | fDataStoreP->fPIStoredSize=0; |
1936 | fDataStoreP->fPIStoredDataAllocated=false; |
1937 | } |
1938 | else { |
1939 | PDEBUGPRINTFX(DBG_ERROR,("WARNING: internal error: to-be-resumed item contains no data?")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("WARNING: internal error: to-be-resumed item contains no data?" ); }; |
1940 | } |
1941 | fDataStoreP->fPartialItemState=pi_state_none; // consumed now |
1942 | fDataStoreP->fPITotalSize=0; |
1943 | fDataStoreP->fPIUnconfirmedSize=0; |
1944 | // substitution of item data done |
1945 | // (don't check other items - we have ONE item only, anyway in the current implementation) |
1946 | return true; |
1947 | } |
1948 | // next item |
1949 | itemListP=itemListP->next; |
1950 | } |
1951 | } |
1952 | // no chunk continuation |
1953 | return false; |
1954 | } // TSyncOpCommand::checkChunkContinuation |
1955 | |
1956 | |
1957 | // check if split is possible at all |
1958 | bool TSyncOpCommand::canSplit(void) |
1959 | { |
1960 | // Sync Op commands can be split when remote supports <moredata/> mechanism |
1961 | return fSessionP->fRemoteSupportsLargeObjects; |
1962 | } |
1963 | |
1964 | |
1965 | // - try to split (e.g. by SyncML 1.1 moredata mechanism) command by reducing |
1966 | // original command by at least aReduceByBytes and generating a second |
1967 | // command containing the rest of the data |
1968 | // Returns NULL if split is not possible or not worth trying in the current situation |
1969 | // (e.g.: only ridiculously small part would remain) |
1970 | TSmlCommand *TSyncOpCommand::splitCommand(sInt32 aReduceByBytes) |
1971 | { |
1972 | SmlItemListPtr_t *itemListPP; |
1973 | TSyncOpCommand *remainingDataCmdP=NULL__null; |
1974 | |
1975 | // nothing remaining so far |
1976 | SmlItemListPtr_t remainingItems=NULL__null; |
1977 | // check other conditions |
1978 | if (!fSyncOpElementP) return NULL__null; |
1979 | // now find where we should split |
1980 | do { |
1981 | // start of list |
1982 | itemListPP = &(fSyncOpElementP->itemList); |
1983 | // check if any items |
1984 | if (*itemListPP==NULL__null) break; // no more items |
1985 | // find last item |
1986 | while ((*itemListPP)->next) itemListPP = &((*itemListPP)->next); |
1987 | // get it's data |
1988 | SmlItemPtr_t itemP = (*itemListPP)->item; |
1989 | SmlPcdataPtr_t dataP = itemP->data; |
1990 | // check if we should split this item |
1991 | if ( |
1992 | canSplit() && // remote can handle large objects (that is: chunked transfers) |
1993 | dataP && // there is data |
1994 | dataP->contentType!=SML_PCDATA_EXTENSION && // it's not an extension |
1995 | dataP->length > (MemSize_t)aReduceByBytes+MIN_SPLIT_DATA200 // remaining length of first part is large enough to make splitting worth doing now |
1996 | ) { |
1997 | // split within this item |
1998 | // Prepare original item |
1999 | // - make sure we have meta |
2000 | if (!itemP->meta) |
2001 | itemP->meta = newMeta(); // create meta as we haven't got one yet |
2002 | SmlMetInfMetInfPtr_t metinfP = (SmlMetInfMetInfPtr_t)(itemP->meta->content); |
2003 | // - set size if this is the first chunk |
2004 | if (metinfP->size) smlFreePcdata(metinfP->size); |
2005 | if (fChunkedItemSize==0) { |
2006 | // first chunk |
2007 | // - set dataPos to 0 |
2008 | addDataPos(metinfP,0); |
2009 | // Note: we don't need to buffer when sending the first chunk. |
2010 | // If we get suspended before the second chunk is being generated, the item will |
2011 | // start over from beginning anyway (and we can use data from the DB). |
2012 | fChunkedItemSize=dataP->length; |
2013 | metinfP->size=newPCDataLong(fChunkedItemSize); |
2014 | PDEBUGPRINTFX(DBG_PROTO+DBG_HOT,({ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Item data too big (%ld) - must be chunked using <MoreData/>, %ld bytes to be sent later" , (long)fChunkedItemSize, (long)aReduceByBytes ); } |
2015 | "Item data too big (%ld) - must be chunked using <MoreData/>, %ld bytes to be sent later",{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Item data too big (%ld) - must be chunked using <MoreData/>, %ld bytes to be sent later" , (long)fChunkedItemSize, (long)aReduceByBytes ); } |
2016 | (long)fChunkedItemSize,{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Item data too big (%ld) - must be chunked using <MoreData/>, %ld bytes to be sent later" , (long)fChunkedItemSize, (long)aReduceByBytes ); } |
2017 | (long)aReduceByBytes{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Item data too big (%ld) - must be chunked using <MoreData/>, %ld bytes to be sent later" , (long)fChunkedItemSize, (long)aReduceByBytes ); } |
2018 | )){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Item data too big (%ld) - must be chunked using <MoreData/>, %ld bytes to be sent later" , (long)fChunkedItemSize, (long)aReduceByBytes ); }; |
2019 | #ifdef SYDEBUG2 |
2020 | // %%% should not happen, but I'm not sure it really won't |
2021 | if (fDataStoreP->fPartialItemState==pi_state_loaded_outgoing) { |
2022 | PDEBUGPRINTFX(DBG_ERROR,("WARNING - internal error: Splitting new item apparently before previous session's item has been resent")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("WARNING - internal error: Splitting new item apparently before previous session's item has been resent" ); }; |
2023 | } |
2024 | #endif |
2025 | } |
2026 | else { |
2027 | // this item is NOT the first chunk -> save stuff we need to |
2028 | PDEBUGPRINTFX(DBG_PROTO+DBG_HOT,({ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Remaining data still too big (%ld/%ld) - must be chunked again, %ld bytes to be sent later" , (long)dataP->length, (long)fChunkedItemSize, (long)aReduceByBytes ); } |
2029 | "Remaining data still too big (%ld/%ld) - must be chunked again, %ld bytes to be sent later",{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Remaining data still too big (%ld/%ld) - must be chunked again, %ld bytes to be sent later" , (long)dataP->length, (long)fChunkedItemSize, (long)aReduceByBytes ); } |
2030 | (long)dataP->length,{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Remaining data still too big (%ld/%ld) - must be chunked again, %ld bytes to be sent later" , (long)dataP->length, (long)fChunkedItemSize, (long)aReduceByBytes ); } |
2031 | (long)fChunkedItemSize,{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Remaining data still too big (%ld/%ld) - must be chunked again, %ld bytes to be sent later" , (long)dataP->length, (long)fChunkedItemSize, (long)aReduceByBytes ); } |
2032 | (long)aReduceByBytes{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Remaining data still too big (%ld/%ld) - must be chunked again, %ld bytes to be sent later" , (long)dataP->length, (long)fChunkedItemSize, (long)aReduceByBytes ); } |
2033 | )){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Remaining data still too big (%ld/%ld) - must be chunked again, %ld bytes to be sent later" , (long)dataP->length, (long)fChunkedItemSize, (long)aReduceByBytes ); }; |
2034 | // Note: in this case, the item already has a dataPos - no need to add one here! |
2035 | // Resume the item in the middle rather than resending it in full. |
2036 | // IMPORTANT: It is essential not to store the fLastSourceURI/fLastTargetURI |
2037 | // on the first chunk, as it then probably still contains info from |
2038 | // the previous session. |
2039 | saveAsPartialItem(itemP); |
2040 | } |
2041 | // - set <moredata> |
2042 | itemP->flags |= SmlMoreData_f0x0400; |
2043 | // - create new data for original item (original data is in dataP) |
2044 | itemP->data = newPCDataStringX( |
2045 | (uInt8 *)dataP->content, // original data |
2046 | dataP->contentType==SML_PCDATA_OPAQUE, // opaque if original was opaque |
2047 | dataP->length-aReduceByBytes // reduced length |
2048 | ); |
2049 | // Create additional item for next message |
2050 | // - new item |
2051 | SmlItemPtr_t nextItemP = newItem(); |
2052 | // - with meta |
2053 | nextItemP->meta = newMeta(); |
2054 | SmlMetInfMetInfPtr_t nextMetinfP = (SmlMetInfMetInfPtr_t)(nextItemP->meta->content); |
2055 | // - SyncML 1.1.1: The <Size> element MUST only be specified in the first chunk of the item. |
2056 | nextMetinfP->size=NULL__null; // no size in remaining items |
2057 | // - copy other meta |
2058 | if (metinfP->maxobjsize) nextMetinfP->format=newPCDataString(smlPCDataToCharP(metinfP->maxobjsize)); // We NEED this one of ZIPPED_BINDATA_SUPPORT! |
2059 | if (metinfP->format) nextMetinfP->format=newPCDataString(smlPCDataToCharP(metinfP->format)); |
2060 | if (metinfP->type) nextMetinfP->type=newPCDataString(smlPCDataToCharP(metinfP->type)); |
2061 | if (metinfP->mark) nextMetinfP->mark=newPCDataString(smlPCDataToCharP(metinfP->mark)); |
2062 | //%%% if we ever decide to carry over EMI here, make sure we don't copy <EMI>dataPos=x</EMI>, as |
2063 | // addDataPos() code relies on no dataPos being present when called. |
2064 | //if (metinfP->emi) nextMetinfP->emi=newPCDataString(smlPCDataToCharP(metinfP->emi)); // %%% not needed yet |
2065 | if (metinfP->version) nextMetinfP->version=newPCDataString(smlPCDataToCharP(metinfP->version)); |
2066 | // - copy source and target |
2067 | nextItemP->target=newOptLocation(smlSrcTargLocURIToCharP(itemP->target),smlSrcTargLocNameToCharP(itemP->target)); |
2068 | nextItemP->source=newOptLocation(smlSrcTargLocURIToCharP(itemP->source),smlSrcTargLocNameToCharP(itemP->source)); |
2069 | // - copy flags except <moredata> |
2070 | nextItemP->flags = itemP->flags & ~SmlMoreData_f0x0400; |
2071 | // - now copy rest of data |
2072 | nextItemP->data = newPCDataStringX( |
2073 | (uInt8 *)dataP->content + dataP->length-aReduceByBytes, // original data minus what we have in original item |
2074 | dataP->contentType==SML_PCDATA_OPAQUE, // opaque if original was opaque |
2075 | aReduceByBytes // reduced length = remaining bytes |
2076 | ); |
2077 | // - original data can now be disposed |
2078 | smlFreePcdata(dataP); |
2079 | // Add correct data position to the next item now. |
2080 | addDataPos(nextMetinfP,fChunkedItemSize-aReduceByBytes); |
2081 | // Now insert new item containing remaining data to beginning of list for next chunk |
2082 | SmlItemListPtr_t ilP = SML_NEW(SmlItemList_t)((SmlItemList_t*) _smlMalloc(sizeof(SmlItemList_t))); |
2083 | ilP->next=remainingItems; |
2084 | ilP->item=nextItemP; |
2085 | remainingItems=ilP; |
2086 | // count reduction |
2087 | aReduceByBytes=0; |
2088 | // done |
2089 | break; |
2090 | } |
2091 | else { |
2092 | // Split between items |
2093 | fChunkedItemSize=0; // no chunking in progress now |
2094 | // - get last itemlist element |
2095 | SmlItemListPtr_t ilP = *itemListPP; |
2096 | // - cut it out of original list |
2097 | *itemListPP=NULL__null; |
2098 | // - put it at the BEGINNING of the remaining items list |
2099 | ilP->next=remainingItems; |
2100 | remainingItems=ilP; |
2101 | // - count reduction |
2102 | aReduceByBytes -= dataP ? dataP->length : 0; |
2103 | // loop to check second-last item |
2104 | } |
2105 | // repeat as long as reduction goal is not met |
2106 | } while (aReduceByBytes>0); |
2107 | // check if any items left in original command |
2108 | if (fSyncOpElementP->itemList == NULL__null) { |
2109 | // none left in original list, can't split |
2110 | // - put back remaining list to original item |
2111 | fSyncOpElementP->itemList = remainingItems; |
2112 | // - cannot split |
2113 | return NULL__null; |
2114 | } |
2115 | // now create new command containing the remaining items |
2116 | if (remainingItems) { |
2117 | if (aReduceByBytes<=0) { |
2118 | // duplicate meta |
2119 | SmlPcdataPtr_t splitMetaP = copyMeta(fSyncOpElementP->meta); |
2120 | // make new command |
2121 | remainingDataCmdP = new TSyncOpCommand( |
2122 | fSessionP, // associated session (for callbacks) |
2123 | fDataStoreP, // datastore from which command originates |
2124 | fSyncOp, // sync operation (=command type) |
2125 | splitMetaP // meta for entire command (passing owner) |
2126 | ); |
2127 | // now pass remaining items to new command |
2128 | remainingDataCmdP->fSyncOpElementP->itemList = remainingItems; |
2129 | // next command must know that it part of a chunked transfer |
2130 | remainingDataCmdP->fChunkedItemSize = fChunkedItemSize; |
2131 | // original command must know that it must expect a 213 status |
2132 | fIncompleteData = true; |
2133 | } |
2134 | else { |
2135 | // remaining items not used, delete them |
2136 | smlFreeItemList(remainingItems); |
2137 | } |
2138 | } |
2139 | // return split-off command |
2140 | return remainingDataCmdP; |
2141 | } // TSyncOpCommand::splitCommand |
2142 | |
2143 | |
2144 | // - test if completely issued (must be called after issue() and continueIssue()) |
2145 | bool TSyncOpCommand::finished(void) |
2146 | { |
2147 | return |
2148 | (fOutgoing) || // outgoing commands are always finished (new split mechanism actually splits the command in two separate commands) |
2149 | (!fOutgoing && fSessionP->fIncompleteDataCommandP!=this); // not part of an incoming chunked data transfer |
2150 | } // TSyncOpCommand::finished |
2151 | |
2152 | |
2153 | // analyze command (but do not yet execute) |
2154 | bool TSyncOpCommand::analyze(TPackageStates aPackageState) |
2155 | { |
2156 | TSmlCommand::analyze(aPackageState); |
2157 | // get Command ID and flags |
2158 | if (fSyncOpElementP) { |
2159 | StartProcessing(fSyncOpElementP->cmdID,fSyncOpElementP->flags); |
2160 | return true; |
2161 | } |
2162 | else return false; // no proto element, bad command |
2163 | } // TSyncOpCommand::analyze |
2164 | |
2165 | |
2166 | // Adds data chunk from specified command to this (incomplete) command |
2167 | // includes checking if sync op and item source/target match and |
2168 | // checks for size match |
2169 | #define MISSING_END_OF_CHUNK_ERROR223 223 // End of Data for chunked object not received |
2170 | |
2171 | localstatus TSyncOpCommand::AddNextChunk(SmlItemPtr_t aNextChunkItem, TSyncOpCommand *aCmdP) |
2172 | { |
2173 | |
2174 | SmlItemListPtr_t incompletenode; |
2175 | SmlItemPtr_t incompleteitem; |
2176 | SmlPcdataPtr_t newdata; |
2177 | localstatus sta; |
2178 | |
2179 | // find last item in this command |
2180 | incompletenode = fSyncOpElementP->itemList; |
2181 | if (!incompletenode) return 412; // incomplete command |
2182 | while (incompletenode && incompletenode->next) incompletenode=incompletenode->next; |
2183 | incompleteitem = incompletenode->item; |
2184 | // check for data integrity |
2185 | if (!incompleteitem) return 412; |
2186 | if (!incompleteitem->data) return 412; |
2187 | if (!aNextChunkItem) return 412; |
2188 | if (!aNextChunkItem->data) return 412; |
2189 | // check for item compatibility |
2190 | // - commands must have same sync op |
2191 | if (getSyncOp() != aCmdP->getSyncOp()) |
2192 | goto missingeoc; // not a status - will be converted to alert |
2193 | // - must have same source and target URI |
2194 | if ( |
2195 | strcmp(smlSrcTargLocURIToCharP(incompleteitem->source),smlSrcTargLocURIToCharP(aNextChunkItem->source))!=0 || |
2196 | strcmp(smlSrcTargLocURIToCharP(incompleteitem->target),smlSrcTargLocURIToCharP(aNextChunkItem->target))!=0 |
2197 | ) |
2198 | goto missingeoc; // not a status - will be converted to alert |
2199 | // - must have same PCData type and not extension |
2200 | if ( |
2201 | incompleteitem->data->contentType != aNextChunkItem->data->contentType || |
2202 | aNextChunkItem->data->contentType == SML_PCDATA_EXTENSION |
2203 | ) |
2204 | return 400; // originator error, bad request |
2205 | // append data from next chunk to incomplete item |
2206 | newdata = SML_NEW(SmlPcdata_t)((SmlPcdata_t*) _smlMalloc(sizeof(SmlPcdata_t))); |
2207 | // - same content type as previous data had |
2208 | newdata->contentType = incompleteitem->data->contentType; |
2209 | newdata->contentType = incompleteitem->data->contentType; |
2210 | // - set new size |
2211 | newdata->length = incompleteitem->data->length + aNextChunkItem->data->length; |
2212 | // - remember size of chunk we're adding now in the incomplete command |
2213 | aCmdP->fLastChunkSize = aNextChunkItem->data->length; |
2214 | // - allocate new data for updated item (including an extra NUL terminator) |
2215 | newdata->content=smlLibMalloc(newdata->length+1); |
2216 | if (newdata->content==NULL__null) |
2217 | return 413; // request entity too large |
2218 | // - copy existing content |
2219 | smlLibMemcpy(newdata->content,incompleteitem->data->content,incompleteitem->data->length); |
2220 | // - add new chunk |
2221 | smlLibMemcpy((uInt8 *)newdata->content+incompleteitem->data->length,aNextChunkItem->data->content,aNextChunkItem->data->length); |
2222 | // - set the NUL terminator in case item is parsed as C string |
2223 | *(((uInt8 *)newdata->content)+newdata->length)=0; |
2224 | // - free old data in item |
2225 | smlFreePcdata(incompleteitem->data); |
2226 | // - insert updated data |
2227 | incompleteitem->data = newdata; |
2228 | // Now check if we are complete |
2229 | if ((aNextChunkItem->flags & SmlMoreData_f0x0400) == 0) { |
2230 | // end of chunk, verify size |
2231 | // - get total size from meta (of original item) |
2232 | SmlMetInfMetInfPtr_t metaP = smlPCDataToMetInfP(incompleteitem->meta); |
2233 | if (!metaP || !metaP->size) { |
2234 | // item has no meta or no meta-size, so size must be in meta of command |
2235 | metaP = smlPCDataToMetInfP(fSyncOpElementP->meta); |
2236 | if (!metaP) { |
2237 | PDEBUGPRINTFX(DBG_ERROR,("Chunked item has no meta -> no size found")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Chunked item has no meta -> no size found" ); }; |
2238 | return 424; // no meta: Size mismatch |
2239 | } |
2240 | } |
2241 | sInt32 expectedSize; |
2242 | if (!smlPCDataToLong(metaP->size, expectedSize)) { |
2243 | PDEBUGPRINTFX(DBG_ERROR,("Chunked item had no or invalid meta <size> in first chunk")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Chunked item had no or invalid meta <size> in first chunk" ); }; |
2244 | return 424; // bad size string: size mismatch |
2245 | } |
2246 | // - check for size match |
2247 | if (incompleteitem->data->length != (MemSize_t)expectedSize) { |
2248 | // check if size mismatch could be due to duplicate transmit of unconfirmed data |
2249 | if (fUnconfirmedSize == uInt32(incompleteitem->data->length - expectedSize)) { |
2250 | // size mismatch is exactly what could be caused by duplicate transmit |
2251 | PDEBUGPRINTFX(DBG_PROTO+DBG_HOT,({ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Detected duplicate chunk in reassembled item due to resume without dataPos (%ld bytes at %ld) -> adjusting" , (long)fUnconfirmedSize, (long)fStoredSize-fUnconfirmedSize ) ; } |
2252 | "Detected duplicate chunk in reassembled item due to resume without dataPos (%ld bytes at %ld) -> adjusting",{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Detected duplicate chunk in reassembled item due to resume without dataPos (%ld bytes at %ld) -> adjusting" , (long)fUnconfirmedSize, (long)fStoredSize-fUnconfirmedSize ) ; } |
2253 | (long)fUnconfirmedSize,{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Detected duplicate chunk in reassembled item due to resume without dataPos (%ld bytes at %ld) -> adjusting" , (long)fUnconfirmedSize, (long)fStoredSize-fUnconfirmedSize ) ; } |
2254 | (long)fStoredSize-fUnconfirmedSize{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Detected duplicate chunk in reassembled item due to resume without dataPos (%ld bytes at %ld) -> adjusting" , (long)fUnconfirmedSize, (long)fStoredSize-fUnconfirmedSize ) ; } |
2255 | )){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Detected duplicate chunk in reassembled item due to resume without dataPos (%ld bytes at %ld) -> adjusting" , (long)fUnconfirmedSize, (long)fStoredSize-fUnconfirmedSize ) ; }; |
2256 | // - cut out duplicate |
2257 | smlLibMemmove( |
2258 | ((uInt8 *)incompleteitem->data->content+fStoredSize-fUnconfirmedSize), // to end of confirmed data |
2259 | ((uInt8 *)incompleteitem->data->content+fStoredSize), // from end of stored data |
2260 | incompleteitem->data->length-fStoredSize // everything between end of stored data and end of item |
2261 | ); |
2262 | incompleteitem->data->length = expectedSize; // adjust length |
2263 | *((uInt8 *)incompleteitem->data->content+expectedSize)=0; // add new safety terminator |
2264 | fUnconfirmedSize=0; // no data unconfirmed any more |
2265 | } |
2266 | else { |
2267 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Chunked item has wrong size (%ld, expected=%ld) after reassembly" , (long)incompleteitem->data->length, (long)expectedSize ); } |
2268 | "Chunked item has wrong size (%ld, expected=%ld) after reassembly",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Chunked item has wrong size (%ld, expected=%ld) after reassembly" , (long)incompleteitem->data->length, (long)expectedSize ); } |
2269 | (long)incompleteitem->data->length,{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Chunked item has wrong size (%ld, expected=%ld) after reassembly" , (long)incompleteitem->data->length, (long)expectedSize ); } |
2270 | (long)expectedSize{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Chunked item has wrong size (%ld, expected=%ld) after reassembly" , (long)incompleteitem->data->length, (long)expectedSize ); } |
2271 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Chunked item has wrong size (%ld, expected=%ld) after reassembly" , (long)incompleteitem->data->length, (long)expectedSize ); }; |
2272 | return 424; // size mismatch |
2273 | } |
2274 | } |
2275 | // successfully reassembled |
2276 | sta=0; |
2277 | } |
2278 | else { |
2279 | // not yet completely reassembled |
2280 | sta=213; |
2281 | } |
2282 | // get MsgID and CmdID from added chunk's commnd |
2283 | fCmdID = aCmdP->getCmdID(); |
2284 | fMsgID = aCmdP->getMsgID(); |
2285 | // copy actual cmdID tag (to make sure we don't get the wrong CmdID when re-processing the command later) |
2286 | smlFreePcdata(fSyncOpElementP->cmdID); // ged rid of current ID |
2287 | fSyncOpElementP->cmdID = smlPcdataDup(aCmdP->fSyncOpElementP->cmdID); // copy ID from last added chunk |
2288 | // return status code |
2289 | return sta; |
2290 | missingeoc: |
2291 | // missing end of chunk |
2292 | TAlertCommand *alertCmdP = new TAlertCommand(fSessionP, NULL__null, (uInt16)223); |
2293 | SmlItemPtr_t alertItemP = newItem(); |
2294 | alertItemP->target=newOptLocation(smlSrcTargLocURIToCharP(incompleteitem->source)); |
2295 | alertItemP->source=newOptLocation(smlSrcTargLocURIToCharP(incompleteitem->target)); |
2296 | alertCmdP->addItem(alertItemP); |
2297 | // issue the alert |
2298 | fSessionP->issueRootPtr(alertCmdP); |
2299 | // signal failure of reassembling chunked item |
2300 | return MISSING_END_OF_CHUNK_ERROR223; |
2301 | } // TSyncOpCommand::AddNextChunk |
2302 | |
2303 | |
2304 | // SyncOp commands can execute out of order except when they |
2305 | // contain chunked items, because then we would have to issue |
2306 | // a 213 Status immediately, which would violate the ordering |
2307 | // of Status replies. |
2308 | bool TSyncOpCommand::canExecuteOutOfOrder() |
2309 | { |
2310 | SmlItemListPtr_t *itemnodePP=&(fSyncOpElementP->itemList); |
2311 | while (*itemnodePP) { |
2312 | SmlItemListPtr_t thisitemnode = *itemnodePP; |
2313 | if (thisitemnode->item && |
2314 | thisitemnode->item->flags & SmlMoreData_f0x0400) { |
2315 | return false; |
2316 | } |
2317 | itemnodePP = &(thisitemnode->next); |
2318 | } |
2319 | return true; |
2320 | } |
2321 | |
2322 | // execute command (perform real actions, generate status) |
2323 | // returns true if command has executed and can be deleted |
2324 | bool TSyncOpCommand::execute(void) |
2325 | { |
2326 | TStatusCommand *statusCmdP=NULL__null; |
2327 | SmlItemListPtr_t *itemnodePP, thisitemnode; |
2328 | localstatus sta; |
2329 | TSyncOpCommand *incompleteCmdP; |
2330 | bool queueforlater,processitem; |
2331 | bool nostatus; |
2332 | SmlItemListPtr_t tobequeueditems=NULL__null; |
2333 | |
2334 | SYSYNC_TRYtry { |
2335 | // get datastore pointer if we do not have one yet |
2336 | if (fDataStoreP==NULL__null) { |
2337 | // in case we did not get the pointer at creation - that is, when the enclosing |
2338 | // <sync> was delayed - we must now get datastore as set by the current <sync> command |
2339 | fDataStoreP = fSessionP->fLocalSyncDatastoreP; |
2340 | if (fDataStoreP==NULL__null) { |
2341 | statusCmdP=newStatusCommand(404); // no datastore, we can't process items for it |
2342 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
2343 | return true; // command executed |
2344 | } |
2345 | } |
2346 | // get command meta if any |
2347 | SmlMetInfMetInfPtr_t cmdmetaP=smlPCDataToMetInfP(fSyncOpElementP->meta); |
2348 | // process items |
2349 | DEBUGPRINTFX(DBG_HOT,("command started processing")){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("command started processing" ); }; |
2350 | itemnodePP=&(fSyncOpElementP->itemList); |
2351 | while (*itemnodePP) { |
2352 | queueforlater=false; // do no queue by default |
2353 | processitem=true; // process by default |
2354 | nostatus=false; // set to true if someone else is responsible for updating fLastItemStatus |
2355 | thisitemnode = *itemnodePP; |
2356 | // no result nor status so far |
2357 | statusCmdP=NULL__null; |
2358 | // check for NULL item |
2359 | if (!thisitemnode->item) { |
2360 | PDEBUGPRINTFX(DBG_ERROR,("command with NULL item")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("command with NULL item" ); }; |
2361 | statusCmdP=newStatusCommand(400); // protocol error |
2362 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
2363 | return true; // command executed |
2364 | } |
2365 | // check if we are resuming a partially transmitted item (but MUST have data) |
2366 | if ( |
2367 | fSessionP->fIncompleteDataCommandP==NULL__null && |
2368 | thisitemnode->item->data && // item must have data |
2369 | fDataStoreP->fPartialItemState==pi_state_loaded_incoming && |
2370 | strcmp(smlSrcTargLocURIToCharP(thisitemnode->item->source),fDataStoreP->fLastSourceURI.c_str())==0 && |
2371 | strcmp(smlSrcTargLocURIToCharP(thisitemnode->item->target),fDataStoreP->fLastTargetURI.c_str())==0 |
2372 | ) { |
2373 | // this is the last item sent in the previously suspended session |
2374 | if (fDataStoreP->fPIStoredSize==0) { |
2375 | // No item was left only partially received from the suspended session. |
2376 | // But we must handle the special case where the final status of the last item sent |
2377 | // in the suspended session did not reach the recipient, so we now see the last chunk again. |
2378 | // In this case, simply re-issue the status and ignore the contents |
2379 | if (fDataStoreP->fLastItemStatus) { |
2380 | // item already processed, just repeat sending the status |
2381 | PDEBUGPRINTFX(DBG_PROTO,("Received last chunk for already processed item -> just resending status %hd",fDataStoreP->fLastItemStatus)){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Received last chunk for already processed item -> just resending status %hd" ,fDataStoreP->fLastItemStatus); }; |
2382 | statusCmdP = newStatusCommand(fDataStoreP->fLastItemStatus); |
2383 | processitem=false; // do not further process the item, just status |
2384 | fDataStoreP->fPartialItemState=pi_state_none; // chunked transfer from last session finally done |
2385 | } |
2386 | } |
2387 | else { |
2388 | // we have a partially received item left from the suspended session |
2389 | // continue it |
2390 | PDEBUGPRINTFX(DBG_PROTO+DBG_HOT,({ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Resuming receiving chunked item Source='%s', Target='%s'" , fDataStoreP->fLastSourceURI.c_str(), fDataStoreP->fLastTargetURI .c_str() ); } |
2391 | "Resuming receiving chunked item Source='%s', Target='%s'",{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Resuming receiving chunked item Source='%s', Target='%s'" , fDataStoreP->fLastSourceURI.c_str(), fDataStoreP->fLastTargetURI .c_str() ); } |
2392 | fDataStoreP->fLastSourceURI.c_str(),{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Resuming receiving chunked item Source='%s', Target='%s'" , fDataStoreP->fLastSourceURI.c_str(), fDataStoreP->fLastTargetURI .c_str() ); } |
2393 | fDataStoreP->fLastTargetURI.c_str(){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Resuming receiving chunked item Source='%s', Target='%s'" , fDataStoreP->fLastSourceURI.c_str(), fDataStoreP->fLastTargetURI .c_str() ); } |
2394 | )){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Resuming receiving chunked item Source='%s', Target='%s'" , fDataStoreP->fLastSourceURI.c_str(), fDataStoreP->fLastTargetURI .c_str() ); }; |
2395 | // simulate a meta size from suspended session's saved item size |
2396 | // - create meta if none there |
2397 | if (!thisitemnode->item->meta) |
2398 | thisitemnode->item->meta = newMeta(); |
2399 | // - now check/generate meta size |
2400 | SmlMetInfMetInfPtr_t metinfP = (SmlMetInfMetInfPtr_t)(thisitemnode->item->meta->content); |
2401 | if (metinfP->size) { |
2402 | #ifdef __MWERKS__ |
2403 | #warning "%%% maybe use presence of meta size to know that this is NOT resuming, that is as an implicit dataPos=0" |
2404 | #endif |
2405 | /* if I understand correctly, size MUST NOT be present on any but the first chunk. |
2406 | If that's correct, we could discard the saved partial item from a previous session |
2407 | in case we see a size (because this would mean the item is retransmitted as a whole |
2408 | and sender does not support resuming a partial item */ |
2409 | // item has meta size, check if correct |
2410 | uInt32 thissize; |
2411 | if ( |
2412 | !smlPCDataToULong(metinfP->size, thissize) || |
2413 | thissize!=fDataStoreP->fPITotalSize |
2414 | ) |
2415 | { |
2416 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Resumed item size does not match (expected=%ld, found=%ld)" , (long)fDataStoreP->fPITotalSize, (long)thissize ); } |
2417 | "Resumed item size does not match (expected=%ld, found=%ld)",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Resumed item size does not match (expected=%ld, found=%ld)" , (long)fDataStoreP->fPITotalSize, (long)thissize ); } |
2418 | (long)fDataStoreP->fPITotalSize,{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Resumed item size does not match (expected=%ld, found=%ld)" , (long)fDataStoreP->fPITotalSize, (long)thissize ); } |
2419 | (long)thissize{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Resumed item size does not match (expected=%ld, found=%ld)" , (long)fDataStoreP->fPITotalSize, (long)thissize ); } |
2420 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Resumed item size does not match (expected=%ld, found=%ld)" , (long)fDataStoreP->fPITotalSize, (long)thissize ); }; |
2421 | statusCmdP = newStatusCommand(424); |
2422 | processitem=false; // do not further process the item |
2423 | } |
2424 | } |
2425 | else { |
2426 | // item has no meta size, create it now |
2427 | metinfP->size=newPCDataLong(fDataStoreP->fPITotalSize); |
2428 | } |
2429 | SmlPcdataPtr_t newdata=NULL__null; |
2430 | uInt32 dataPos=0; |
2431 | if (processitem) { |
2432 | // save sizes confirmed/unconfirmed data in this command object |
2433 | // (for possible reassembly adjustment when command is complete) |
2434 | fUnconfirmedSize=fDataStoreP->fPIUnconfirmedSize; |
2435 | fStoredSize=fDataStoreP->fPIStoredSize; |
2436 | // Determine Data position |
2437 | // - check if we have it in EMI (Synthesis-Oracle enhancement) |
2438 | // <EMI xmlns='syncml:metinf'>datapos=NUM</EMI> |
2439 | SmlPcdataListPtr_t emiP = metinfP->emi; // start with item meta EMI |
2440 | bool foundDataPos=false; |
2441 | for (uInt16 i=0; i<2; i++) { |
2442 | while (emiP) { |
2443 | if (emiP->data) { |
2444 | const char *p = smlPCDataToCharP(emiP->data); |
2445 | if (strucmp(p,"datapos=",8)==0) { |
2446 | // correct lead-in, get number now |
2447 | if (StrToULong(p+8,dataPos)>0) { |
2448 | PDEBUGPRINTFX(DBG_PROTO+DBG_DETAILS,("found <meta><EMI>datapos=%ld",(long)dataPos)){ if (((0x00000010 +0x40000000) & getDbgMask()) == (0x00000010 +0x40000000)) getDbgLogger()->setNextMask(0x00000010 +0x40000000 ).DebugPrintfLastMask ("found <meta><EMI>datapos=%ld" ,(long)dataPos); }; |
2449 | foundDataPos=true; // found dataPos |
2450 | break; |
2451 | } |
2452 | else { |
2453 | PDEBUGPRINTFX(DBG_ERROR,("invalid number in <meta><EMI>datapos, ignoring it")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("invalid number in <meta><EMI>datapos, ignoring it" ); }; |
2454 | } |
2455 | } |
2456 | } |
2457 | // check next |
2458 | emiP=emiP->next; |
2459 | } |
2460 | // done if found |
2461 | if (foundDataPos) break; |
2462 | // try with cmd meta |
2463 | if (!cmdmetaP) break; // we don't have a command meta, no point to search |
2464 | emiP = cmdmetaP->emi; // cmd meta EMI |
2465 | } |
2466 | if (foundDataPos) { |
2467 | // we have a dataPos value |
2468 | // - no unconfirmed size any more for this item (but we still need the datastore-level vars |
2469 | // below to do the copying |
2470 | fUnconfirmedSize=0; |
2471 | // - confirmed size is the data position now |
2472 | fStoredSize=dataPos; |
2473 | } |
2474 | else { |
2475 | // without known dataPos, we assume all received data confirmed for now |
2476 | // and will adjust at end of item if needed |
2477 | dataPos = fDataStoreP->fPIStoredSize; |
2478 | } |
2479 | // - check integrity |
2480 | if (dataPos>fDataStoreP->fPIStoredSize) { |
2481 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Data position invalid (max allowed=%ld, found=%ld)" , (long)fDataStoreP->fPIStoredSize, (long)dataPos ); } |
2482 | "Data position invalid (max allowed=%ld, found=%ld)",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Data position invalid (max allowed=%ld, found=%ld)" , (long)fDataStoreP->fPIStoredSize, (long)dataPos ); } |
2483 | (long)fDataStoreP->fPIStoredSize,{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Data position invalid (max allowed=%ld, found=%ld)" , (long)fDataStoreP->fPIStoredSize, (long)dataPos ); } |
2484 | (long)dataPos{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Data position invalid (max allowed=%ld, found=%ld)" , (long)fDataStoreP->fPIStoredSize, (long)dataPos ); } |
2485 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "Data position invalid (max allowed=%ld, found=%ld)" , (long)fDataStoreP->fPIStoredSize, (long)dataPos ); }; |
2486 | statusCmdP = newStatusCommand(412); |
2487 | processitem=false; // do not further process the item |
2488 | } |
2489 | if (processitem) { |
2490 | // - combine new and old data |
2491 | newdata = SML_NEW(SmlPcdata_t)((SmlPcdata_t*) _smlMalloc(sizeof(SmlPcdata_t))); |
2492 | // - same content type |
2493 | newdata->contentType = thisitemnode->item->data->contentType; |
2494 | // - set new size |
2495 | newdata->length = dataPos + thisitemnode->item->data->length; |
2496 | // - allocate new data for updated item (including an extra NUL terminator) |
2497 | newdata->content=smlLibMalloc(newdata->length+1); |
2498 | if (newdata->content==NULL__null) { |
2499 | statusCmdP = newStatusCommand(413); |
2500 | processitem=false; // do not further process the item |
2501 | } |
2502 | } |
2503 | } |
2504 | if (processitem) { |
2505 | // copy already received content up to dataPos |
2506 | smlLibMemcpy(newdata->content,fDataStoreP->fPIStoredDataP,dataPos); |
2507 | // forget data stored at DS level |
2508 | fDataStoreP->fPIStoredSize=0; |
2509 | if (fDataStoreP->fPIStoredDataP) { |
2510 | // only free if not owned by an item |
2511 | if (fDataStoreP->fPIStoredDataAllocated) |
2512 | smlLibFree(fDataStoreP->fPIStoredDataP); |
2513 | } |
2514 | fDataStoreP->fPIStoredDataP=NULL__null; |
2515 | // append content just received in this item |
2516 | smlLibMemcpy((uInt8 *)newdata->content+dataPos,thisitemnode->item->data->content,thisitemnode->item->data->length); |
2517 | // - set the NUL terminator in case item is parsed as C string |
2518 | *(((uInt8 *)newdata->content)+newdata->length)=0; |
2519 | // - free old data in item |
2520 | smlFreePcdata(thisitemnode->item->data); |
2521 | // - insert new data |
2522 | thisitemnode->item->data = newdata; |
2523 | } |
2524 | /* No, we need to keep pi_state_loaded_incoming until we get |
2525 | // Finished processing left-overs from last session |
2526 | fDataStoreP->fPartialItemState=pi_state_none; |
2527 | */ |
2528 | // Now we can treat this as if it was the first (or only) chunk of a non-resumed item |
2529 | } // if we have partial data received in last session |
2530 | } // if item is the same as last item in suspended session |
2531 | if (processitem) { |
2532 | processitem=false; // only process further if we detect complete data |
Value stored to 'processitem' is never read | |
2533 | // check if this item is complete (not chunked by <moredata>) |
2534 | if (thisitemnode->item->flags & SmlMoreData_f0x0400) { |
2535 | // no, it's only a chunk |
2536 | if (thisitemnode->item->data==NULL__null) { |
2537 | PDEBUGPRINTFX(DBG_ERROR,("Chunked item has no <data>")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Chunked item has no <data>" ); }; |
2538 | statusCmdP->setStatusCode(412); |
2539 | // do not further process the command, issue status and exit |
2540 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
2541 | return true; // processed (with error) |
2542 | } |
2543 | // - return appropriate status |
2544 | statusCmdP = newStatusCommand(213); // chunked item accepted and buffered |
2545 | // - no items may follow the chunked one |
2546 | if (thisitemnode->next) { |
2547 | PDEBUGPRINTFX(DBG_ERROR,("Chunked item had additional items after the chunked one")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Chunked item had additional items after the chunked one" ); }; |
2548 | statusCmdP->setStatusCode(400); |
2549 | // do not further process the command, issue status and exit |
2550 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
2551 | return true; // processed (with error) |
2552 | } |
2553 | if (fSessionP->fIncompleteDataCommandP==NULL__null) { |
2554 | // This is the first chunk, save this as the original command (as it contains all meta) |
2555 | fSessionP->fIncompleteDataCommandP = this; |
2556 | // make sure that already executed items will not get saved |
2557 | *itemnodePP=NULL__null; // disconnect not-yet-executed items from executed ones |
2558 | smlFreeItemList(fSyncOpElementP->itemList); // free executed items |
2559 | fSyncOpElementP->itemList = thisitemnode; // put not-yet-executed, partial item into command |
2560 | // make sure moredata flag is not set on reassembled item |
2561 | thisitemnode->item->flags &= ~SmlMoreData_f0x0400; |
2562 | // save size of the chunk |
2563 | fLastChunkSize=thisitemnode->item->data->length; |
2564 | } |
2565 | else { |
2566 | // this is a chunk in the middle, combine its data |
2567 | // with the already buffered incomplete command |
2568 | // and update MsgID/CmdID. If source and target do not match, |
2569 | // statusCmdP will set to appropriate error code |
2570 | sta=fSessionP->fIncompleteDataCommandP->AddNextChunk(thisitemnode->item,this); |
2571 | if (sta) statusCmdP->setStatusCode(sta); // set error if any |
2572 | } |
2573 | PDEBUGPRINTFX(DBG_PROTO+DBG_HOT,("<Moredata/> set: Chunk (%ld bytes) received (plus possible carry over from suspend) and buffered",(long)fLastChunkSize)){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ("<Moredata/> set: Chunk (%ld bytes) received (plus possible carry over from suspend) and buffered" ,(long)fLastChunkSize); }; |
2574 | } |
2575 | else { |
2576 | // Complete item or end of chunked item |
2577 | processitem=true; |
2578 | incompleteCmdP = fSessionP->fIncompleteDataCommandP; |
2579 | if (incompleteCmdP) { |
2580 | // end of chunked item, add final chunk and check for errors |
2581 | sta=incompleteCmdP->AddNextChunk(thisitemnode->item,this); |
2582 | if (sta==MISSING_END_OF_CHUNK_ERROR223) { |
2583 | // command should have been end of chunked data, but wasn't. |
2584 | // Alert 223 is already issued. |
2585 | // - dispose of failed incomplete command |
2586 | delete incompleteCmdP; |
2587 | fSessionP->fIncompleteDataCommandP=NULL__null; |
2588 | // - process item as new command |
2589 | } |
2590 | else if (sta==0) { |
2591 | // successfully reassembled command, execute it now |
2592 | PDEBUGPRINTFX(DBG_PROTO+DBG_HOT,("Last Chunk received (%ld bytes), item is reassembled",(long)fLastChunkSize)){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ("Last Chunk received (%ld bytes), item is reassembled" ,(long)fLastChunkSize); }; |
2593 | // - first remove global link to it to avoid recursion |
2594 | fSessionP->fIncompleteDataCommandP=NULL__null; |
2595 | // - execute now (and pass ownership) |
2596 | // issues appropriate statuses, so we don't need to deal with it; |
2597 | // in fact, we must not touch fLastItemStatus because we don't |
2598 | // know the status |
2599 | nostatus=true; |
2600 | fSessionP->process(incompleteCmdP); |
2601 | // - this item is processed now, continue in loop if there are more items |
2602 | processitem=false; // do not process the item normally |
2603 | // Note: statusCmdP is NULL here, so no extra status will be issued for the |
2604 | // item (process() should have already caused appropriate statuses to |
2605 | // be generated. |
2606 | } |
2607 | else { |
2608 | // some error with this item, generate status |
2609 | statusCmdP = newStatusCommand(sta); |
2610 | PDEBUGPRINTFX(DBG_ERROR,("Adding next chunk to item failed with status=%hd",sta)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Adding next chunk to item failed with status=%hd" ,sta); }; |
2611 | // - dispose of failed incomplete command |
2612 | delete incompleteCmdP; |
2613 | fSessionP->fIncompleteDataCommandP=NULL__null; |
2614 | // do not process anything any further |
2615 | processitem=false; // do not process the item normally |
2616 | fDataStoreP->fLocalItemsError++; // count this as an error |
2617 | } |
2618 | } |
2619 | else { |
2620 | // save size of the chunk (if item has ANY data at all) |
2621 | fLastChunkSize=thisitemnode->item->data ? thisitemnode->item->data->length : 0; |
2622 | } |
2623 | if (processitem) { |
2624 | // - get remote and local IDs of item |
2625 | const char *remoteID=smlSrcTargLocURIToCharP(thisitemnode->item->source); |
2626 | const char *localID=smlSrcTargLocURIToCharP(thisitemnode->item->target); |
2627 | // prepare OK status for item |
2628 | statusCmdP = newStatusCommand(200); |
2629 | // let session process the item |
2630 | PDEBUGPRINTFX(DBG_PROTO+DBG_HOT,({ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Item (syncop: %s) started processing, remoteID='%s', localID='%s'" , SyncOpNames[(sInt16)fSyncOp], remoteID, localID ); } |
2631 | "Item (syncop: %s) started processing, remoteID='%s', localID='%s'",{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Item (syncop: %s) started processing, remoteID='%s', localID='%s'" , SyncOpNames[(sInt16)fSyncOp], remoteID, localID ); } |
2632 | SyncOpNames[(sInt16)fSyncOp],{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Item (syncop: %s) started processing, remoteID='%s', localID='%s'" , SyncOpNames[(sInt16)fSyncOp], remoteID, localID ); } |
2633 | remoteID,{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Item (syncop: %s) started processing, remoteID='%s', localID='%s'" , SyncOpNames[(sInt16)fSyncOp], remoteID, localID ); } |
2634 | localID{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Item (syncop: %s) started processing, remoteID='%s', localID='%s'" , SyncOpNames[(sInt16)fSyncOp], remoteID, localID ); } |
2635 | )){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Item (syncop: %s) started processing, remoteID='%s', localID='%s'" , SyncOpNames[(sInt16)fSyncOp], remoteID, localID ); }; |
2636 | queueforlater=false; |
2637 | if (fSessionP->processSyncOpItem( |
2638 | fSyncOp, // the operation |
2639 | thisitemnode->item, // the item to be processed |
2640 | cmdmetaP, // command-wide meta, if any |
2641 | fDataStoreP, // related datastore pointer |
2642 | *statusCmdP, // pre-set 200 status, can be modified in case of errors |
2643 | queueforlater // set if processing of item must be done later |
2644 | )) { |
2645 | // fully ok (no internal change of requested operations or |
2646 | // silent acceptance of deleting non-existant item) |
2647 | } |
2648 | else { |
2649 | // Internal processing of items showed some irregularity, but |
2650 | // status to remote peer can still be ok (for example when trying |
2651 | // to delete non-existant item in datastore with incomplete rollbacks, |
2652 | // processSyncOpItem() will return false, but Status=200. |
2653 | PDEBUGPRINTFX(DBG_PROTO,({ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Irregularity in execution of item, status=%hd" , statusCmdP->getStatusCode() ); } |
2654 | "Irregularity in execution of item, status=%hd",{ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Irregularity in execution of item, status=%hd" , statusCmdP->getStatusCode() ); } |
2655 | statusCmdP->getStatusCode(){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Irregularity in execution of item, status=%hd" , statusCmdP->getStatusCode() ); } |
2656 | )){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Irregularity in execution of item, status=%hd" , statusCmdP->getStatusCode() ); }; |
2657 | } |
2658 | } // if processitem |
2659 | } // if complete item |
2660 | } // if processitem |
2661 | // now generate status or queue for later |
2662 | // - remember as last item for possible suspend and resume |
2663 | fDataStoreP->fLastSourceURI = smlSrcTargLocURIToCharP(thisitemnode->item->source); |
2664 | fDataStoreP->fLastTargetURI = smlSrcTargLocURIToCharP(thisitemnode->item->target); |
2665 | if (queueforlater) { |
2666 | PDEBUGPRINTFX(DBG_PROTO,({ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Item could not be processed completely now -> will be queued for later processing" ); } |
2667 | "Item could not be processed completely now -> will be queued for later processing"{ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Item could not be processed completely now -> will be queued for later processing" ); } |
2668 | )){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Item could not be processed completely now -> will be queued for later processing" ); }; |
2669 | // item processing could not complete, we must queue this and all other items |
2670 | // in this command for later processing. However, re-assembling chunked |
2671 | // items must proceed as normal. |
2672 | fDataStoreP->fLastItemStatus = 0; // no status sent yet |
2673 | // Therefore, we move this item from the original list to a list of to-be-queued items |
2674 | addItemToList( |
2675 | thisitemnode->item, // the item |
2676 | &tobequeueditems // place pointer to next node here |
2677 | ); |
2678 | // cut item out of original list to make sure it does not get disposed with it |
2679 | // - itemnodePP points to pointer to list start or a "next" pointer in a node |
2680 | // (which in turn points to thisitemnode). Now let it point to the next item node. |
2681 | // - this also advance processing to the next item |
2682 | *itemnodePP = thisitemnode->next; |
2683 | // - dispose of the item node itself |
2684 | thisitemnode->next=NULL__null; // disconnect subsequent nodes |
2685 | thisitemnode->item=NULL__null; // disconnect item (which is now in tobequeueditems list) |
2686 | smlFreeItemList(thisitemnode); // dispose of node |
2687 | // - and the status command |
2688 | delete statusCmdP; |
2689 | statusCmdP = NULL__null; |
2690 | } |
2691 | else { |
2692 | // count incoming net data |
2693 | if (thisitemnode->item->data) { |
2694 | fDataStoreP->fIncomingDataBytes+=thisitemnode->item->data->length; |
2695 | } |
2696 | // item processed |
2697 | // - remember status (final only) for possible suspend and resume |
2698 | sta= statusCmdP ? statusCmdP->getStatusCode() : 0; |
2699 | if (!nostatus && sta!=213) { |
2700 | // final status received, save it for possible resend |
2701 | fDataStoreP->fLastItemStatus = sta; |
2702 | // but forget data stored at DS level |
2703 | fDataStoreP->fPIStoredSize=0; |
2704 | if (fDataStoreP->fPIStoredDataP) { |
2705 | // only free if not owned by an item |
2706 | if (fDataStoreP->fPIStoredDataAllocated) |
2707 | smlLibFree(fDataStoreP->fPIStoredDataP); |
2708 | } |
2709 | fDataStoreP->fPIStoredDataP=NULL__null; |
2710 | // make sure it gets saved |
2711 | fDataStoreP->fPartialItemState = pi_state_save_incoming; |
2712 | } |
2713 | // - issue status for it |
2714 | if (statusCmdP) { |
2715 | // add source and target refs of item |
2716 | statusCmdP->addTargetRef(smlSrcTargLocURIToCharP(thisitemnode->item->target)); // add target ref |
2717 | statusCmdP->addSourceRef(smlSrcTargLocURIToCharP(thisitemnode->item->source)); // add source ref |
2718 | // issue |
2719 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
2720 | } |
2721 | // advance to next item in list |
2722 | itemnodePP = &(thisitemnode->next); |
2723 | } |
2724 | } // item loop |
2725 | // free this one in advance (only if command is finished) |
2726 | if (finished() && !tobequeueditems) FreeSmlElement(); |
2727 | // update item list in command for queuing if needed |
2728 | if (tobequeueditems) { |
2729 | // there are to-be-queued items, insert them instead of the original item list |
2730 | // - delete current item list (only contains already processed and statused items) |
2731 | smlFreeItemList(fSyncOpElementP->itemList); |
2732 | // - insert to be queued items instead |
2733 | fSyncOpElementP->itemList=tobequeueditems; |
2734 | } |
2735 | } |
2736 | SYSYNC_CATCH (...)catch(...) { |
2737 | // make sure owned objects in local scope are deleted |
2738 | if (statusCmdP) delete statusCmdP; |
2739 | // re-throw |
2740 | SYSYNC_RETHROWthrow; |
2741 | SYSYNC_ENDCATCH} |
2742 | // if not all items could be executed, command must be queued for later re-execution. |
2743 | // (all successfully executed items are already deleted from the item list) |
2744 | return !tobequeueditems; |
2745 | } // TSyncOpCommand::execute |
2746 | |
2747 | |
2748 | // returns true if command must be put to the waiting-for-status queue. |
2749 | // If false, command does not need to be put into waiting-for-status queue |
2750 | // and can be deleted if finished() returns true |
2751 | bool TSyncOpCommand::issue( |
2752 | uInt32 aAsCmdID, // command ID to be used |
2753 | uInt32 aInMsgID, // message ID in which command is being issued |
2754 | bool aNoResp // dummy here, because Status has always no response |
2755 | ) |
2756 | { |
2757 | // prepare basic stuff |
2758 | TSmlCommand::issue(aAsCmdID,aInMsgID,aNoResp); |
2759 | // now issue |
2760 | if (fSyncOpElementP) { |
2761 | // issue command with SyncML toolkit (no flags) |
2762 | PrepareIssue(&fSyncOpElementP->cmdID,&fSyncOpElementP->flags); // CmdID and flags |
2763 | Ret_t err; |
2764 | InstanceID_t wspid = fSessionP->getSmlWorkspaceID(); |
2765 | switch (fCmdType) { |
2766 | case scmd_add: |
2767 | #ifdef SYDEBUG2 |
2768 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance && !fEvalMode) |
2769 | smlAddCmd(fSessionP->fOutgoingXMLInstance,fSyncOpElementP); |
2770 | #endif |
2771 | err=smlAddCmd(wspid,fSyncOpElementP); |
2772 | break; |
2773 | #ifdef COPY_SEND |
2774 | case scmd_copy: |
2775 | #ifdef SYDEBUG2 |
2776 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance && !fEvalMode) |
2777 | smlCopyCmd(fSessionP->fOutgoingXMLInstance,fSyncOpElementP); |
2778 | #endif |
2779 | err=smlCopyCmd(wspid,fSyncOpElementP); |
2780 | break; |
2781 | #endif |
2782 | case scmd_move: |
2783 | #ifdef SYDEBUG2 |
2784 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance && !fEvalMode) |
2785 | smlMoveCmd(fSessionP->fOutgoingXMLInstance,fSyncOpElementP); |
2786 | #endif |
2787 | err=smlMoveCmd(wspid,fSyncOpElementP); |
2788 | break; |
2789 | case scmd_replace: |
2790 | #ifdef SYDEBUG2 |
2791 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance && !fEvalMode) |
2792 | smlReplaceCmd(fSessionP->fOutgoingXMLInstance,fSyncOpElementP); |
2793 | #endif |
2794 | err=smlReplaceCmd(wspid,fSyncOpElementP); |
2795 | break; |
2796 | case scmd_delete: |
2797 | #ifdef SYDEBUG2 |
2798 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance && !fEvalMode) |
2799 | smlDeleteCmd(fSessionP->fOutgoingXMLInstance,fSyncOpElementP); |
2800 | #endif |
2801 | err=smlDeleteCmd(wspid,fSyncOpElementP); |
2802 | break; |
2803 | default: |
2804 | SYSYNC_THROW(TSyncException("TSyncOpCommand:issue, bad command type"))throw TSyncException("TSyncOpCommand:issue, bad command type" ); |
2805 | } |
2806 | if (!fEvalMode) { |
2807 | if (err!=SML_ERR_OK0x00) { |
2808 | SYSYNC_THROW(TSmlException("smlAdd/Copy/Replace/DeleteCmd",err))throw TSmlException("smlAdd/Copy/Replace/DeleteCmd",err); |
2809 | } |
2810 | FinalizeIssue(); |
2811 | // show items |
2812 | SmlItemListPtr_t itemP = fSyncOpElementP->itemList; |
2813 | while (itemP) { |
2814 | // count net data sent |
2815 | sInt32 itemlen=0; |
2816 | if (itemP->item && itemP->item->data) { |
2817 | itemlen=itemP->item->data->length; |
2818 | fDataStoreP->fOutgoingDataBytes+=itemlen; |
2819 | } |
2820 | // show item source and target |
2821 | PDEBUGPRINTFX(DBG_PROTO,({ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Item remoteID='%s', localID='%s', datasize=%ld" , smlSrcTargLocURIToCharP(itemP->item->target), smlSrcTargLocURIToCharP (itemP->item->source), (long)itemlen ); } |
2822 | "Item remoteID='%s', localID='%s', datasize=%ld",{ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Item remoteID='%s', localID='%s', datasize=%ld" , smlSrcTargLocURIToCharP(itemP->item->target), smlSrcTargLocURIToCharP (itemP->item->source), (long)itemlen ); } |
2823 | smlSrcTargLocURIToCharP(itemP->item->target),{ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Item remoteID='%s', localID='%s', datasize=%ld" , smlSrcTargLocURIToCharP(itemP->item->target), smlSrcTargLocURIToCharP (itemP->item->source), (long)itemlen ); } |
2824 | smlSrcTargLocURIToCharP(itemP->item->source),{ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Item remoteID='%s', localID='%s', datasize=%ld" , smlSrcTargLocURIToCharP(itemP->item->target), smlSrcTargLocURIToCharP (itemP->item->source), (long)itemlen ); } |
2825 | (long)itemlen{ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Item remoteID='%s', localID='%s', datasize=%ld" , smlSrcTargLocURIToCharP(itemP->item->target), smlSrcTargLocURIToCharP (itemP->item->source), (long)itemlen ); } |
2826 | )){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ( "Item remoteID='%s', localID='%s', datasize=%ld" , smlSrcTargLocURIToCharP(itemP->item->target), smlSrcTargLocURIToCharP (itemP->item->source), (long)itemlen ); }; |
2827 | if (fChunkedItemSize>0 && !fIncompleteData) { |
2828 | #ifdef SYDEBUG2 |
2829 | PDEBUGPRINTFX(DBG_PROTO+DBG_HOT,({ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Last Chunk (%ld bytes) of large object (%ld total) sent now - retaining it in case of implicit suspend" , (long)itemlen, (long)fChunkedItemSize ); } |
2830 | "Last Chunk (%ld bytes) of large object (%ld total) sent now - retaining it in case of implicit suspend",{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Last Chunk (%ld bytes) of large object (%ld total) sent now - retaining it in case of implicit suspend" , (long)itemlen, (long)fChunkedItemSize ); } |
2831 | (long)itemlen,{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Last Chunk (%ld bytes) of large object (%ld total) sent now - retaining it in case of implicit suspend" , (long)itemlen, (long)fChunkedItemSize ); } |
2832 | (long)fChunkedItemSize{ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Last Chunk (%ld bytes) of large object (%ld total) sent now - retaining it in case of implicit suspend" , (long)itemlen, (long)fChunkedItemSize ); } |
2833 | )){ if (((0x00000010 +0x00000001) & getDbgMask()) == (0x00000010 +0x00000001)) getDbgLogger()->setNextMask(0x00000010 +0x00000001 ).DebugPrintfLastMask ( "Last Chunk (%ld bytes) of large object (%ld total) sent now - retaining it in case of implicit suspend" , (long)itemlen, (long)fChunkedItemSize ); }; |
2834 | #endif |
2835 | if (itemlen>0) |
2836 | saveAsPartialItem(itemP->item); |
2837 | } |
2838 | // next |
2839 | itemP=itemP->next; |
2840 | } |
2841 | // we don't need the data any more, but we should keep the source and target IDs until we have the status |
2842 | // - get rid of data |
2843 | if (fSyncOpElementP->itemList) { |
2844 | // - free possible extra items (shouldn't be any - we always send single item per command) |
2845 | smlFreeItemList(fSyncOpElementP->itemList->next); |
2846 | fSyncOpElementP->itemList->next=NULL__null; |
2847 | // - free data and meta part of this item, but not target and source info |
2848 | if (fSyncOpElementP->itemList->item) { |
2849 | smlFreePcdata(fSyncOpElementP->itemList->item->meta); |
2850 | fSyncOpElementP->itemList->item->meta=NULL__null; |
2851 | smlFreePcdata(fSyncOpElementP->itemList->item->data); |
2852 | fSyncOpElementP->itemList->item->data=NULL__null; |
2853 | } |
2854 | } |
2855 | } |
2856 | else |
2857 | return err==SML_ERR_OK0x00; // ok if evaluation had no error |
2858 | } |
2859 | else { |
2860 | DEBUGPRINTFX(DBG_ERROR,("*** Tried to issue NULL status")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("*** Tried to issue NULL status" ); }; |
2861 | } |
2862 | // sync op commands do need status |
2863 | return true; // queue for status |
2864 | } // TSyncOpCommand::issue |
2865 | |
2866 | |
2867 | void TSyncOpCommand::FreeSmlElement(void) |
2868 | { |
2869 | // remove SyncML toolkit element(s) |
2870 | FREEPROTOELEMENT(fSyncOpElementP); |
2871 | } // TSyncOpCommand::FreeSmlElement |
2872 | |
2873 | |
2874 | TSyncOpCommand::~TSyncOpCommand() |
2875 | { |
2876 | // free command elements, if any (use explicit invocation as this is a destructor) |
2877 | TSyncOpCommand::FreeSmlElement(); |
2878 | } // TSyncOpCommand::~TSyncOpCommand |
2879 | |
2880 | |
2881 | /* end of TSyncOpCommand implementation */ |
2882 | |
2883 | |
2884 | #endif // SYNCCOMMAND_PART1_EXCLUDE |
2885 | #ifndef SYNCCOMMAND_PART2_EXCLUDE |
2886 | |
2887 | /* |
2888 | * Implementation of TMapCommand |
2889 | */ |
2890 | |
2891 | |
2892 | // constructor for receiving Map command |
2893 | TMapCommand::TMapCommand( |
2894 | TSyncSession *aSessionP, // associated session (for callbacks) |
2895 | uInt32 aMsgID, // the Message ID of the command |
2896 | SmlMapPtr_t aMapElementP // associated syncml protocol element |
2897 | ) : |
2898 | TSmlCommand(scmd_map,false,aSessionP,aMsgID) |
2899 | { |
2900 | // save element |
2901 | fMapElementP = aMapElementP; |
2902 | fInProgress=false; // just in case... |
2903 | // no params |
2904 | fLocalDataStoreP=NULL__null; |
2905 | fRemoteDataStoreP=NULL__null; |
2906 | } // TMapCommand::TMapCommand |
2907 | |
2908 | |
2909 | #ifdef SYSYNC_SERVER1 |
2910 | // Server only receives Maps |
2911 | |
2912 | // analyze command (but do not yet execute) |
2913 | bool TMapCommand::analyze(TPackageStates aPackageState) |
2914 | { |
2915 | TSmlCommand::analyze(aPackageState); |
2916 | // get Command ID and flags |
2917 | if (fMapElementP) { |
2918 | StartProcessing(fMapElementP->cmdID,0); |
2919 | return true; |
2920 | } |
2921 | else return false; // no proto element, bad command |
2922 | } // TMapCommand::analyze |
2923 | |
2924 | |
2925 | // execute command (perform real actions, generate status) |
2926 | // returns true if command has executed and can be deleted |
2927 | bool TMapCommand::execute(void) |
2928 | { |
2929 | TStatusCommand *statusCmdP=NULL__null; |
2930 | bool queueforlater; |
2931 | |
2932 | SYSYNC_TRYtry { |
2933 | // prepare a status |
2934 | statusCmdP = newStatusCommand(200); |
2935 | // let session actually process the command |
2936 | queueforlater=false; |
2937 | fSessionP->processMapCommand(fMapElementP,*statusCmdP,queueforlater); |
2938 | // check if done or queued for later |
2939 | if (queueforlater) { |
2940 | delete statusCmdP; |
2941 | } |
2942 | else { |
2943 | // now issue status, if any |
2944 | if (statusCmdP) { |
2945 | statusCmdP->addTargetRef(smlSrcTargLocURIToCharP(fMapElementP->target)); // add target ref |
2946 | statusCmdP->addSourceRef(smlSrcTargLocURIToCharP(fMapElementP->source)); // add source ref |
2947 | #ifdef MAP_STATUS_IMMEDIATE1 |
2948 | // issue status right now (might cause map statuses |
2949 | // returned in sync-updates-to-client package #4 instead of map-confirm #6 |
2950 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
2951 | #else |
2952 | // issue status only if outgoing package is map-response |
2953 | fSessionP->issueNotBeforePackage(psta_map,statusCmdP); |
2954 | #endif |
2955 | } |
2956 | // free this one in advance |
2957 | FreeSmlElement(); |
2958 | } |
2959 | } |
2960 | SYSYNC_CATCH (...)catch(...) { |
2961 | // make sure owned objects in local scope are deleted |
2962 | if (statusCmdP) delete statusCmdP; |
2963 | // re-throw |
2964 | SYSYNC_RETHROWthrow; |
2965 | SYSYNC_ENDCATCH} |
2966 | // return true if command has fully executed |
2967 | return !queueforlater; |
2968 | } // TMapCommand::execute |
2969 | |
2970 | #endif |
2971 | |
2972 | #ifdef SYSYNC_CLIENT1 |
2973 | |
2974 | // Client only sends maps |
2975 | |
2976 | // constructor for sending MAP Command |
2977 | TMapCommand::TMapCommand( |
2978 | TSyncSession *aSessionP, // associated session (for callbacks) |
2979 | TLocalEngineDS *aLocalDataStoreP, // local datastore |
2980 | TRemoteDataStore *aRemoteDataStoreP // remote datastore |
2981 | ) : |
2982 | TSmlCommand(scmd_map,true,aSessionP) |
2983 | { |
2984 | // save params |
2985 | fLocalDataStoreP=aLocalDataStoreP; |
2986 | fRemoteDataStoreP=aRemoteDataStoreP; |
2987 | // create new internal map element |
2988 | fMapElementP=NULL__null; // none yet |
2989 | generateEmptyMapElement(); |
2990 | // not yet in progress (as not yet issued) |
2991 | fInProgress=false; |
2992 | } // TMapCommand::TMapCommand |
2993 | |
2994 | |
2995 | // generate empty map element |
2996 | void TMapCommand::generateEmptyMapElement(void) |
2997 | { |
2998 | // free possibly still existing map element |
2999 | if (fMapElementP) FreeSmlElement(); |
3000 | // create internal map element |
3001 | fMapElementP = SML_NEW(SmlMap_t)((SmlMap_t*) _smlMalloc(sizeof(SmlMap_t))); |
3002 | // set proto element type to make it auto-disposable |
3003 | fMapElementP->elementType=SML_PE_MAP; |
3004 | // Cmd ID is now empty (will be set when issued) |
3005 | fMapElementP->cmdID=NULL__null; |
3006 | // set source and target |
3007 | fMapElementP->target=newLocation(fRemoteDataStoreP->getFullName()); // remote is target for Map command |
3008 | fMapElementP->source=newLocation(fLocalDataStoreP->getRemoteViewOfLocalURI()); // local is source of Map command |
3009 | // no optional elements for now |
3010 | fMapElementP->cred=NULL__null; // %%% no database level auth yet at all |
3011 | fMapElementP->meta=NULL__null; // %%% no meta for now |
3012 | // map itemlist is empty |
3013 | fMapElementP->mapItemList=NULL__null; |
3014 | #ifndef USE_SML_EVALUATION1 |
3015 | // no item sizes |
3016 | fItemSizes=0; |
3017 | #endif |
3018 | } // TMapCommand::generateEmptyMapElement |
3019 | |
3020 | |
3021 | // returns true if command must be put to the waiting-for-status queue. |
3022 | // If false, command can be deleted (except if it is not finished() ) |
3023 | bool TMapCommand::issue( |
3024 | uInt32 aAsCmdID, // command ID to be used |
3025 | uInt32 aInMsgID, // message ID in which command is being issued |
3026 | bool aNoResp |
3027 | ) |
3028 | { |
3029 | // prepare basic stuff |
3030 | TSmlCommand::issue(aAsCmdID,aInMsgID,aNoResp); |
3031 | // now issue |
3032 | if (fMapElementP) { |
3033 | // add as many Map items as possible, update fInProgress |
3034 | // BUT DONT DO THAT IN EVAL MODE (would be recursive, as generateMapItems() |
3035 | // will call evalIssue() which will call this routine....) |
3036 | if (!fEvalMode) generateMapItems(); |
3037 | // issue command, but only if there are any items at all |
3038 | if (fMapElementP->mapItemList) { |
3039 | // now issue map command |
3040 | PrepareIssue(&fMapElementP->cmdID); |
3041 | if (!fEvalMode) { |
3042 | #ifdef SYDEBUG2 |
3043 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance) |
3044 | smlMapCmd(fSessionP->fOutgoingXMLInstance,fMapElementP); |
3045 | #endif |
3046 | Ret_t err; |
3047 | if ((err=smlMapCmd(fSessionP->getSmlWorkspaceID(),fMapElementP))!=SML_ERR_OK0x00) { |
3048 | SYSYNC_THROW(TSmlException("smlMapCmd",err))throw TSmlException("smlMapCmd",err); |
3049 | } |
3050 | FinalizeIssue(); |
3051 | // show debug |
3052 | DEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Generated Map command, Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(fMapElementP->source), smlSrcTargLocURIToCharP (fMapElementP->target) ); } |
3053 | "Generated Map command, Source='%s', Target='%s'",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Generated Map command, Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(fMapElementP->source), smlSrcTargLocURIToCharP (fMapElementP->target) ); } |
3054 | smlSrcTargLocURIToCharP(fMapElementP->source),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Generated Map command, Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(fMapElementP->source), smlSrcTargLocURIToCharP (fMapElementP->target) ); } |
3055 | smlSrcTargLocURIToCharP(fMapElementP->target){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Generated Map command, Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(fMapElementP->source), smlSrcTargLocURIToCharP (fMapElementP->target) ); } |
3056 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "Generated Map command, Source='%s', Target='%s'" , smlSrcTargLocURIToCharP(fMapElementP->source), smlSrcTargLocURIToCharP (fMapElementP->target) ); }; |
3057 | } |
3058 | else |
3059 | return smlMapCmd(fSessionP->getSmlWorkspaceID(),fMapElementP)==SML_ERR_OK0x00; |
3060 | } |
3061 | else { |
3062 | if (fEvalMode) return true; // evaluated nothing, is ok! |
3063 | DEBUGPRINTFX(DBG_PROTO,("Suppressed generating empty map command")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("Suppressed generating empty map command" ); }; |
3064 | return false; // do not queue, delete command now |
3065 | } |
3066 | // keep smlElement, as we need it to mark confirmed map items |
3067 | // at handleStatus(). |
3068 | } |
3069 | else { |
3070 | DEBUGPRINTFX(DBG_ERROR,("*** Tried to issue NULL sync")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("*** Tried to issue NULL sync" ); }; |
3071 | } |
3072 | // return true if command must be queued for status/result response reception |
3073 | return queueForResponse(); |
3074 | } // TMapCommand::issue |
3075 | |
3076 | |
3077 | |
3078 | // - test if completely issued (must be called after issue() and continueIssue()) |
3079 | bool TMapCommand::finished(void) |
3080 | { |
3081 | // not finished as long there are more syncOps to send |
3082 | return (!fInProgress || !fOutgoing); |
3083 | } // TMapCommand::finished |
3084 | |
3085 | |
3086 | // - continue issuing command. This is called by session at start of new message |
3087 | // when finished() returned false after issue()/continueIssue() |
3088 | // (which causes caller of finished() to put command into fInteruptedCommands queue) |
3089 | // returns true if command should be queued for status (again?) |
3090 | // NOTE: continueIssue must make sure that it gets a new CmdID/MsgID because |
3091 | // the command itself is issued multiple times |
3092 | bool TMapCommand::continueIssue(bool &aNewIssue) |
3093 | { |
3094 | aNewIssue=false; // never issue anew! |
3095 | if (!fInProgress) return false; // done, don't queue for status again |
3096 | // we can generate next map command only after we have received status for this one |
3097 | if (isWaitingForStatus()) return true; // still in progress, still waiting for status |
3098 | // command is in progress, continue with another <Map> command in this message |
3099 | // - create new Map command |
3100 | generateEmptyMapElement(); |
3101 | // - issue again with new command ID |
3102 | fCmdID = fSessionP->getNextOutgoingCmdID(); |
3103 | fMsgID = fSessionP->getOutgoingMsgID(); |
3104 | // new map command must be queued for status again |
3105 | // but only if something was actually issued (map command issue can |
3106 | // be nop if there are no map items present) |
3107 | return issue(fCmdID,fMsgID,fNoResp); |
3108 | } // TMapCommand::continueIssue |
3109 | |
3110 | |
3111 | // add as many Map items as possible, update fInProgress |
3112 | void TMapCommand::generateMapItems(void) |
3113 | { |
3114 | // let datastore add Map items (possibly none) |
3115 | fInProgress = !( |
3116 | fLocalDataStoreP->engGenerateMapItems(this,NULL__null) |
3117 | ); |
3118 | } // TMapCommand::generateMapItems |
3119 | |
3120 | |
3121 | // add a Map Item to the map command |
3122 | void TMapCommand::addMapItem(const char *aLocalID, const char *aRemoteID) |
3123 | { |
3124 | // make item |
3125 | SmlMapItemPtr_t mapitemP = SML_NEW(SmlMapItem_t)((SmlMapItem_t*) _smlMalloc(sizeof(SmlMapItem_t))); |
3126 | mapitemP->target=newLocation(aRemoteID); |
3127 | mapitemP->source=newLocation(aLocalID); |
3128 | #ifndef USE_SML_EVALUATION1 |
3129 | // update size |
3130 | fItemSizes += |
3131 | ITEMOVERHEADSIZE90 + |
3132 | strlen(aLocalID) + |
3133 | strlen(aRemoteID); |
3134 | #endif |
3135 | // add item to item list |
3136 | SmlMapItemListPtr_t *mapItemListPP = &(fMapElementP->mapItemList); |
3137 | // find last itemlist pointer |
3138 | while (*mapItemListPP) { |
3139 | mapItemListPP=&((*mapItemListPP)->next); |
3140 | } |
3141 | // aItemListPP now points to a NULL pointer which must be replaced by addr of new ItemList entry |
3142 | *mapItemListPP = SML_NEW(SmlMapItemList_t)((SmlMapItemList_t*) _smlMalloc(sizeof(SmlMapItemList_t))); |
3143 | (*mapItemListPP)->next=NULL__null; |
3144 | (*mapItemListPP)->mapItem=mapitemP; // insert new item |
3145 | } // TMapCommand::addItem |
3146 | |
3147 | |
3148 | // remove last added map item from the command |
3149 | void TMapCommand::deleteLastMapItem(void) |
3150 | { |
3151 | // make item |
3152 | #ifndef USE_SML_EVALUATION1 |
3153 | #error "Not implemented for old non-eval method any more" |
3154 | #endif |
3155 | // kill last item in item list |
3156 | SmlMapItemListPtr_t *mapItemListPP = &(fMapElementP->mapItemList); |
3157 | // find last itemlist pointer pointing to an item |
3158 | while (*mapItemListPP && (*mapItemListPP)->next) { |
3159 | mapItemListPP=&((*mapItemListPP)->next); |
3160 | } |
3161 | // aItemListPP now points to the pointer which points to the last item list element (or is NULL if no items there) |
3162 | if (*mapItemListPP) { |
3163 | // delete rest of list, which consists of one item only |
3164 | smlFreeMapItemList(*mapItemListPP); |
3165 | // NULL link in previous item or beginning of list |
3166 | *mapItemListPP=NULL__null; |
3167 | } |
3168 | } // TMapCommand::deleteLastMapItem |
3169 | |
3170 | |
3171 | |
3172 | // handle status received for previously issued command |
3173 | // returns true if done, false if command must be kept in the status queue |
3174 | bool TMapCommand::handleStatus(TStatusCommand *aStatusCmdP) |
3175 | { |
3176 | bool handled=false; |
3177 | if (aStatusCmdP->getStatusCode()==200) { |
3178 | handled=true; // is ok |
3179 | // mark maps confirmed |
3180 | if (fLocalDataStoreP) { |
3181 | // go through all of my items |
3182 | SmlMapItemListPtr_t mapItemListP = fMapElementP->mapItemList; |
3183 | SmlMapItemPtr_t mapItemP; |
3184 | while (mapItemListP) { |
3185 | mapItemP=mapItemListP->mapItem; |
3186 | if (mapItemP) { |
3187 | // call datastore to mark this map confirmed (no need to be sent again in next session / resume) |
3188 | fLocalDataStoreP->engMarkMapConfirmed( |
3189 | smlSrcTargLocURIToCharP(mapItemP->source), // source for outgoing mapitem is localID |
3190 | smlSrcTargLocURIToCharP(mapItemP->target) // target for outgoing mapitem is remoteID |
3191 | ); |
3192 | } |
3193 | mapItemListP=mapItemListP->next; |
3194 | } |
3195 | } |
3196 | } |
3197 | // anyway, we can now get rid of the map items in the command |
3198 | if (fMapElementP) FreeSmlElement(); |
3199 | // check if base class must handle it |
3200 | if(!handled) { |
3201 | // let base class handle it |
3202 | handled=TSmlCommand::handleStatus(aStatusCmdP); |
3203 | } |
3204 | return handled; |
3205 | } // TMapCommand::handleStatus |
3206 | |
3207 | #endif // client-only map implementation |
3208 | |
3209 | |
3210 | // Common for Client and Server |
3211 | |
3212 | #ifndef USE_SML_EVALUATION1 |
3213 | |
3214 | // get (approximated) message size required for sending it |
3215 | uInt32 TMapCommand::messageSize(void) |
3216 | { |
3217 | // return size of command so far |
3218 | return TSmlCommand::messageSize()+fItemSizes; |
3219 | } // TMapCommand::messageSize |
3220 | |
3221 | #endif |
3222 | |
3223 | |
3224 | void TMapCommand::FreeSmlElement(void) |
3225 | { |
3226 | // remove SyncML toolkit element(s) |
3227 | FREEPROTOELEMENT(fMapElementP); |
3228 | } // TMapCommand::FreeSmlElement |
3229 | |
3230 | |
3231 | TMapCommand::~TMapCommand() |
3232 | { |
3233 | // free command elements, if any (use explicit invocation as this is a destructor) |
3234 | TMapCommand::FreeSmlElement(); |
3235 | } // TMapCommand::TMapCommand |
3236 | |
3237 | |
3238 | /* end of TMapCommand implementation */ |
3239 | |
3240 | /* |
3241 | * Implementation of TGetCommand |
3242 | */ |
3243 | |
3244 | // constructor for receiving command |
3245 | TGetCommand::TGetCommand( |
3246 | TSyncSession *aSessionP, // associated session (for callbacks) |
3247 | uInt32 aMsgID, // the Message ID of the command |
3248 | SmlGetPtr_t aGetElementP // associated syncml protocol element |
3249 | ) : |
3250 | TSmlCommand(scmd_get,false,aSessionP,aMsgID) |
3251 | { |
3252 | // save element |
3253 | fGetElementP = aGetElementP; |
3254 | } // TGetCommand::TGetCommand |
3255 | |
3256 | |
3257 | // constructor for sending command |
3258 | TGetCommand::TGetCommand( |
3259 | TSyncSession *aSessionP // associated session (for callbacks) |
3260 | ) : |
3261 | TSmlCommand(scmd_get,true,aSessionP) |
3262 | { |
3263 | // create internal get element |
3264 | fGetElementP = SML_NEW(SmlGet_t)((SmlGet_t*) _smlMalloc(sizeof(SmlGet_t))); |
3265 | // set proto element type to make it auto-disposable |
3266 | fGetElementP->elementType=SML_PE_GET; |
3267 | // Cmd ID is now empty (will be set when issued) |
3268 | fGetElementP->cmdID=NULL__null; |
3269 | // default to no flags (noResp is set at issue, if at all) |
3270 | fGetElementP->flags=0; |
3271 | // no optional elements for now |
3272 | fGetElementP->cred=NULL__null; |
3273 | fGetElementP->lang=NULL__null; |
3274 | fGetElementP->meta=NULL__null; |
3275 | fGetElementP->itemList=NULL__null; |
3276 | } // TGetCommand::TGetCommand |
3277 | |
3278 | |
3279 | // set Meta of the get command |
3280 | void TGetCommand::setMeta( |
3281 | SmlPcdataPtr_t aMetaP // existing meta data structure, ownership is passed to Get |
3282 | ) |
3283 | { |
3284 | if (fGetElementP) |
3285 | fGetElementP->meta=aMetaP; |
3286 | } // TGetCommand::setMeta |
3287 | |
3288 | |
3289 | // add an Item to the get command |
3290 | void TGetCommand::addItem( |
3291 | SmlItemPtr_t aItemP // existing item data structure, ownership is passed to Get |
3292 | ) |
3293 | { |
3294 | if (fGetElementP) |
3295 | addItemToList(aItemP,&(fGetElementP->itemList)); |
3296 | } // TGetCommand::addItem |
3297 | |
3298 | |
3299 | // add a target specification Item to the get command |
3300 | void TGetCommand::addTargetLocItem( |
3301 | const char *aTargetURI, |
3302 | const char *aTargetName |
3303 | ) |
3304 | { |
3305 | SmlItemPtr_t itemP = newItem(); |
3306 | |
3307 | itemP->target = newLocation(aTargetURI,aTargetName); |
3308 | addItem(itemP); |
3309 | } // TGetCommand::addTargetLocItem |
3310 | |
3311 | |
3312 | |
3313 | // analyze command (but do not yet execute) |
3314 | bool TGetCommand::analyze(TPackageStates aPackageState) |
3315 | { |
3316 | TSmlCommand::analyze(aPackageState); |
3317 | // get Command ID and flags |
3318 | if (fGetElementP) { |
3319 | StartProcessing(fGetElementP->cmdID,fGetElementP->flags); |
3320 | return true; |
3321 | } |
3322 | else return false; // no proto element, bad command |
3323 | } // TGetCommand::analyze |
3324 | |
3325 | |
3326 | // execute command (perform real actions, generate status) |
3327 | // returns true if command has executed and can be deleted |
3328 | bool TGetCommand::execute(void) |
3329 | { |
3330 | TStatusCommand *statusCmdP=NULL__null; |
3331 | TResultsCommand *resultsCmdP=NULL__null; |
3332 | SmlItemListPtr_t thisitemnode,nextitemnode; |
3333 | |
3334 | SYSYNC_TRYtry { |
3335 | // process items |
3336 | thisitemnode=fGetElementP->itemList; |
3337 | while (thisitemnode) { |
3338 | nextitemnode = thisitemnode->next; |
3339 | // no result nor status so far |
3340 | statusCmdP=NULL__null; |
3341 | resultsCmdP=NULL__null; |
3342 | // get Target LocURI |
3343 | if (!thisitemnode->item) SYSYNC_THROW(TSyncException("Get with NULL item"))throw TSyncException("Get with NULL item"); |
3344 | string locURI=smlSrcTargLocURIToCharP(thisitemnode->item->target); |
3345 | DEBUGPRINTFX(DBG_HOT,("processing item with locURI=%s",locURI.c_str())){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("processing item with locURI=%s" ,locURI.c_str()); }; |
3346 | // let session (and descendants) process it |
3347 | // - default to "not found" status |
3348 | statusCmdP = newStatusCommand(404); |
3349 | resultsCmdP=fSessionP->processGetItem(locURI.c_str(),this,thisitemnode->item,*statusCmdP); |
3350 | // now complete and issue status |
3351 | statusCmdP->addTargetRef(locURI.c_str()); // add target ref |
3352 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
3353 | // issue results, if any |
3354 | if (resultsCmdP) { |
3355 | ISSUE_COMMAND_ROOT(fSessionP,resultsCmdP){ TSmlCommand* p=resultsCmdP; resultsCmdP=__null; fSessionP-> issueRootPtr(p); }; |
3356 | } |
3357 | // next item |
3358 | thisitemnode=nextitemnode; |
3359 | } |
3360 | // free this one in advance |
3361 | FreeSmlElement(); |
3362 | } |
3363 | SYSYNC_CATCH (...)catch(...) { |
3364 | // make sure owned objects in local scope are deleted |
3365 | if (statusCmdP) delete statusCmdP; |
3366 | if (resultsCmdP) delete resultsCmdP; |
3367 | // re-throw |
3368 | SYSYNC_RETHROWthrow; |
3369 | SYSYNC_ENDCATCH} |
3370 | // done with command, delete it now: return true |
3371 | return true; |
3372 | } // TGetCommand::execute |
3373 | |
3374 | |
3375 | // returns true if command must be put to the waiting-for-status queue. |
3376 | // If false, command can be deleted |
3377 | bool TGetCommand::issue( |
3378 | uInt32 aAsCmdID, // command ID to be used |
3379 | uInt32 aInMsgID, // message ID in which command is being issued |
3380 | bool aNoResp |
3381 | ) |
3382 | { |
3383 | // prepare basic stuff |
3384 | TSmlCommand::issue(aAsCmdID,aInMsgID,aNoResp); |
3385 | // now issue |
3386 | if (fGetElementP) { |
3387 | // issue command with SyncML toolkit |
3388 | PrepareIssue(&fGetElementP->cmdID,&fGetElementP->flags); |
3389 | if (!fEvalMode) { |
3390 | #ifdef SYDEBUG2 |
3391 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance) |
3392 | smlGetCmd(fSessionP->fOutgoingXMLInstance,fGetElementP); |
3393 | #endif |
3394 | Ret_t err; |
3395 | if ((err=smlGetCmd(fSessionP->getSmlWorkspaceID(),fGetElementP))!=SML_ERR_OK0x00) { |
3396 | SYSYNC_THROW(TSmlException("smlGetCmd",err))throw TSmlException("smlGetCmd",err); |
3397 | } |
3398 | FinalizeIssue(); |
3399 | // we don't need the status structure any more, free (and NULL ptr) now |
3400 | FreeSmlElement(); |
3401 | } |
3402 | else |
3403 | return smlGetCmd(fSessionP->getSmlWorkspaceID(),fGetElementP)==SML_ERR_OK0x00; |
3404 | } |
3405 | else { |
3406 | DEBUGPRINTFX(DBG_ERROR,("*** Tried to issue NULL get")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("*** Tried to issue NULL get" ); }; |
3407 | } |
3408 | // return true if command must be queued for status/result response reception |
3409 | return queueForResponse(); |
3410 | } // TGetCommand::issue |
3411 | |
3412 | |
3413 | bool TGetCommand::statusEssential(void) |
3414 | { |
3415 | // get status is not essential in lenient mode |
3416 | return !(fSessionP->fLenientMode); |
3417 | } // TGetCommand::statusEssential |
3418 | |
3419 | |
3420 | // handle status received for previously issued command |
3421 | // returns true if done, false if command must be kept in the status queue |
3422 | bool TGetCommand::handleStatus(TStatusCommand *aStatusCmdP) |
3423 | { |
3424 | // base class just handles common cases |
3425 | TSyError statuscode = aStatusCmdP->getStatusCode(); |
3426 | if (statuscode>=500) { |
3427 | // %%% for SCTS, which rejects GET with status 500 in some cases |
3428 | POBJDEBUGPRINTFX(fSessionP,DBG_ERROR,("Status: %hd: 5xx for get is passed w/o error",statuscode)){ if ((fSessionP) && (((0x00000002) & (fSessionP) ->getDbgMask()) == (0x00000002))) (fSessionP)->getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Status: %hd: 5xx for get is passed w/o error" ,statuscode); }; |
3429 | return true; |
3430 | } |
3431 | // let ancestor analyze |
3432 | return TSmlCommand::handleStatus(aStatusCmdP); |
3433 | } // TGetCommand::handleStatus |
3434 | |
3435 | |
3436 | |
3437 | |
3438 | void TGetCommand::FreeSmlElement(void) |
3439 | { |
3440 | // remove SyncML toolkit element(s) |
3441 | FREEPROTOELEMENT(fGetElementP); |
3442 | } // TGetCommand::FreeSmlElement |
3443 | |
3444 | |
3445 | TGetCommand::~TGetCommand() |
3446 | { |
3447 | // free command elements, if any (use explicit invocation as this is a destructor) |
3448 | TGetCommand::FreeSmlElement(); |
3449 | } // TGetCommand::~TGetCommand |
3450 | |
3451 | |
3452 | /* end of TGetCommand implementation */ |
3453 | |
3454 | /* |
3455 | * Implementation of TPutCommand |
3456 | */ |
3457 | |
3458 | |
3459 | // constructor for receiving command |
3460 | TPutCommand::TPutCommand( |
3461 | TSyncSession *aSessionP, // associated session (for callbacks) |
3462 | uInt32 aMsgID, // the Message ID of the command |
3463 | SmlGetPtr_t aPutElementP // associated syncml protocol element |
3464 | ) : |
3465 | TSmlCommand(scmd_put,false,aSessionP,aMsgID) |
3466 | { |
3467 | // save element |
3468 | fPutElementP = aPutElementP; |
3469 | } // TPutCommand::TPutCommand |
3470 | |
3471 | |
3472 | // constructor for sending command |
3473 | TPutCommand::TPutCommand( |
3474 | TSyncSession *aSessionP // associated session (for callbacks) |
3475 | ) : |
3476 | TSmlCommand(scmd_put,true,aSessionP) |
3477 | { |
3478 | // create internal get element |
3479 | fPutElementP = SML_NEW(SmlPut_t)((SmlPut_t*) _smlMalloc(sizeof(SmlPut_t))); |
3480 | // set proto element type to make it auto-disposable |
3481 | fPutElementP->elementType=SML_PE_PUT; |
3482 | // Cmd ID is now empty (will be set when issued) |
3483 | fPutElementP->cmdID=NULL__null; |
3484 | // default to no flags (noResp is set at issue, if at all) |
3485 | fPutElementP->flags=0; |
3486 | // no optional elements for now |
3487 | fPutElementP->cred=NULL__null; |
3488 | fPutElementP->lang=NULL__null; |
3489 | fPutElementP->meta=NULL__null; |
3490 | fPutElementP->itemList=NULL__null; |
3491 | } // TPutCommand::TPutCommand |
3492 | |
3493 | |
3494 | // add Meta to the get command |
3495 | void TPutCommand::setMeta( |
3496 | SmlPcdataPtr_t aMetaP // existing meta data structure, ownership is passed to Get |
3497 | ) |
3498 | { |
3499 | if (fPutElementP) |
3500 | fPutElementP->meta=aMetaP; |
3501 | } // TPutCommand::setMeta |
3502 | |
3503 | |
3504 | // add an Item to the get command |
3505 | void TPutCommand::addItem( |
3506 | SmlItemPtr_t aItemP // existing item data structure, ownership is passed to Get |
3507 | ) |
3508 | { |
3509 | if (fPutElementP) |
3510 | addItemToList(aItemP,&(fPutElementP->itemList)); |
3511 | } // TPutCommand::addItem |
3512 | |
3513 | |
3514 | // add a source specification Item to the put command and return a pointer |
3515 | // to add data to it |
3516 | SmlItemPtr_t TPutCommand::addSourceLocItem( |
3517 | const char *aTargetURI, |
3518 | const char *aTargetName |
3519 | ) |
3520 | { |
3521 | SmlItemPtr_t itemP = newItem(); |
3522 | |
3523 | itemP->source = newLocation(aTargetURI,aTargetName); |
3524 | addItem(itemP); |
3525 | return itemP; |
3526 | } // TPutCommand::addSourceLocItem |
3527 | |
3528 | |
3529 | // analyze command (but do not yet execute) |
3530 | bool TPutCommand::analyze(TPackageStates aPackageState) |
3531 | { |
3532 | TSmlCommand::analyze(aPackageState); |
3533 | // get Command ID and flags |
3534 | if (fPutElementP) { |
3535 | StartProcessing(fPutElementP->cmdID,fPutElementP->flags); |
3536 | return true; |
3537 | } |
3538 | else return false; // no proto element, bad command |
3539 | } // TPutCommand::analyze |
3540 | |
3541 | |
3542 | // execute command (perform real actions, generate status) |
3543 | // returns true if command has executed and can be deleted |
3544 | bool TPutCommand::execute(void) |
3545 | { |
3546 | TStatusCommand *statusCmdP=NULL__null; |
3547 | SmlItemListPtr_t thisitemnode,nextitemnode; |
3548 | |
3549 | SYSYNC_TRYtry { |
3550 | // process items |
3551 | thisitemnode=fPutElementP->itemList; |
3552 | while (thisitemnode) { |
3553 | nextitemnode = thisitemnode->next; |
3554 | // no result nor status so far |
3555 | statusCmdP=NULL__null; |
3556 | if (!thisitemnode->item) SYSYNC_THROW(TSyncException("Put with NULL item"))throw TSyncException("Put with NULL item"); |
3557 | // get Source LocURI |
3558 | string locURI=smlSrcTargLocURIToCharP(thisitemnode->item->source); |
3559 | DEBUGPRINTFX(DBG_HOT,("processing item with locURI=%s",locURI.c_str())){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("processing item with locURI=%s" ,locURI.c_str()); }; |
3560 | // let session (and descendants) process it |
3561 | // - default to not allowed to put status |
3562 | statusCmdP = newStatusCommand(403); |
3563 | fSessionP->processPutResultItem(true,locURI.c_str(),this,thisitemnode->item,*statusCmdP); |
3564 | // now complete and issue status |
3565 | statusCmdP->addSourceRef(locURI.c_str()); // add source ref |
3566 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
3567 | // next item |
3568 | thisitemnode=nextitemnode; |
3569 | } |
3570 | // free element |
3571 | FreeSmlElement(); |
3572 | } |
3573 | SYSYNC_CATCH (...)catch(...) { |
3574 | // make sure owned objects in local scope are deleted |
3575 | if (statusCmdP) delete statusCmdP; |
3576 | // re-throw |
3577 | SYSYNC_RETHROWthrow; |
3578 | SYSYNC_ENDCATCH} |
3579 | // done with command, delete it now: return true |
3580 | return true; |
3581 | } // TPutCommand::execute |
3582 | |
3583 | |
3584 | // returns true if command must be put to the waiting-for-status queue. |
3585 | // If false, command can be deleted |
3586 | bool TPutCommand::issue( |
3587 | uInt32 aAsCmdID, // command ID to be used |
3588 | uInt32 aInMsgID, // message ID in which command is being issued |
3589 | bool aNoResp |
3590 | ) |
3591 | { |
3592 | // prepare basic stuff |
3593 | TSmlCommand::issue(aAsCmdID,aInMsgID,aNoResp); |
3594 | // now issue |
3595 | if (fPutElementP) { |
3596 | // issue command with SyncML toolkit |
3597 | PrepareIssue(&fPutElementP->cmdID,&fPutElementP->flags); |
3598 | if (!fEvalMode) { |
3599 | #ifdef SYDEBUG2 |
3600 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance) |
3601 | smlPutCmd(fSessionP->fOutgoingXMLInstance,fPutElementP); |
3602 | #endif |
3603 | Ret_t err; |
3604 | if ((err=smlPutCmd(fSessionP->getSmlWorkspaceID(),fPutElementP))!=SML_ERR_OK0x00) { |
3605 | SYSYNC_THROW(TSmlException("smlPutCmd",err))throw TSmlException("smlPutCmd",err); |
3606 | } |
3607 | FinalizeIssue(); |
3608 | // we don't need the status structure any more, free (and NULL ptr) now |
3609 | FreeSmlElement(); |
3610 | } |
3611 | else |
3612 | return smlPutCmd(fSessionP->getSmlWorkspaceID(),fPutElementP)==SML_ERR_OK0x00; |
3613 | } |
3614 | else { |
3615 | DEBUGPRINTFX(DBG_ERROR,("*** Tried to issue NULL put")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("*** Tried to issue NULL put" ); }; |
3616 | } |
3617 | // return true if command must be queued for status/result response reception |
3618 | return queueForResponse(); |
3619 | } // TPutCommand::issue |
3620 | |
3621 | |
3622 | void TPutCommand::FreeSmlElement(void) |
3623 | { |
3624 | // remove SyncML toolkit element(s) |
3625 | FREEPROTOELEMENT(fPutElementP); |
3626 | } // TPutCommand::FreeSmlElement |
3627 | |
3628 | |
3629 | TPutCommand::~TPutCommand() |
3630 | { |
3631 | // free command elements, if any (use explicit invocation as this is a destructor) |
3632 | TPutCommand::FreeSmlElement(); |
3633 | } // TPutCommand::~TPutCommand |
3634 | |
3635 | |
3636 | /* end of TPutCommand implementation */ |
3637 | |
3638 | |
3639 | /* |
3640 | * Implementation of TStatusCommand |
3641 | */ |
3642 | |
3643 | |
3644 | // constructor for generating status |
3645 | TStatusCommand::TStatusCommand( |
3646 | TSyncSession *aSessionP, // associated session (for callbacks) |
3647 | TSmlCommand *aCommandP, // command this status refers to |
3648 | TSyError aStatusCode // status code |
3649 | ) : |
3650 | TSmlCommand(scmd_status,true,aSessionP) |
3651 | { |
3652 | // save status code |
3653 | fStatusCode=aStatusCode; |
3654 | // get reference info |
3655 | if (aCommandP) { |
3656 | // referring to a command |
3657 | fRefMsgID=aCommandP->getMsgID(); |
3658 | fRefCmdID=aCommandP->getCmdID(); |
3659 | fRefCmdType=aCommandP->getCmdType(); |
3660 | // - set flag to suppress sending this status when NoResp is set |
3661 | fDontSend= aCommandP->getNoResp() || fSessionP->getMsgNoResp(); |
3662 | } |
3663 | else { |
3664 | // referring to SyncHdr of current message |
3665 | fRefMsgID=fSessionP->fIncomingMsgID; |
3666 | fRefCmdID=0; // "command" ID of SyncHdr is 0 |
3667 | fRefCmdType=scmd_synchdr; // is SyncHdr |
3668 | // - set flag to suppress sending this status when NoResp is set |
3669 | fDontSend=fSessionP->getMsgNoResp(); |
3670 | } |
3671 | // create internal status element |
3672 | fStatusElementP = SML_NEW(SmlStatus_t)((SmlStatus_t*) _smlMalloc(sizeof(SmlStatus_t))); |
3673 | // set proto element type to make it auto-disposable |
3674 | fStatusElementP->elementType=SML_PE_STATUS; |
3675 | // Cmd ID is now empty (will be set at Issue to ensure correct sequential ordering in case this status is not immediately sent) |
3676 | fStatusElementP->cmdID=NULL__null; |
3677 | // status refers to message of specified command |
3678 | fStatusElementP->msgRef=newPCDataLong(fRefMsgID); |
3679 | // status refers to ID of specified command |
3680 | fStatusElementP->cmdRef=newPCDataLong(fRefCmdID); |
3681 | // add name |
3682 | fStatusElementP->cmd=newPCDataString(getNameOf(fRefCmdType)); |
3683 | // no status code yet (will be added at issue()) |
3684 | fStatusElementP->data=NULL__null; |
3685 | // no optional elements for now |
3686 | fStatusElementP->targetRefList=NULL__null; |
3687 | fStatusElementP->sourceRefList=NULL__null; |
3688 | fStatusElementP->cred=NULL__null; |
3689 | fStatusElementP->chal=NULL__null; |
3690 | fStatusElementP->itemList=NULL__null; |
3691 | } // TStatusCommand::TStatusCommand |
3692 | |
3693 | |
3694 | // %%%% (later obsolete) constructor for generating status w/o having a command object |
3695 | TStatusCommand::TStatusCommand( |
3696 | TSyncSession *aSessionP, // associated session (for callbacks) |
3697 | uInt32 aRefCmdID, // referred-to command ID |
3698 | TSmlCommandTypes aRefCmdType, // referred-to command type (scmd_xxx) |
3699 | bool aNoResp, // set if no-Resp |
3700 | TSyError aStatusCode // status code |
3701 | ) : |
3702 | TSmlCommand(scmd_status,true,aSessionP) |
3703 | { |
3704 | // save status code |
3705 | fStatusCode=aStatusCode; |
3706 | // get reference info |
3707 | fRefMsgID=fSessionP->fIncomingMsgID; |
3708 | fRefCmdID=aRefCmdID; |
3709 | fRefCmdType=aRefCmdType; |
3710 | // - set flag to suppress sending this status when NoResp is set |
3711 | fDontSend=aNoResp; |
3712 | // create internal status element |
3713 | fStatusElementP = SML_NEW(SmlStatus_t)((SmlStatus_t*) _smlMalloc(sizeof(SmlStatus_t))); |
3714 | // set proto element type to make it auto-disposable |
3715 | fStatusElementP->elementType=SML_PE_STATUS; |
3716 | // Cmd ID is now empty (will be set at Issue to ensure correct sequential ordering in case this status is not immediately sent) |
3717 | fStatusElementP->cmdID=NULL__null; |
3718 | // status refers to message of specified command |
3719 | fStatusElementP->msgRef=newPCDataLong(fRefMsgID); |
3720 | // status refers to ID of specified command |
3721 | fStatusElementP->cmdRef=newPCDataLong(fRefCmdID); |
3722 | // add name |
3723 | fStatusElementP->cmd=newPCDataString(getNameOf(fRefCmdType)); |
3724 | // no status code yet (will be added at issue()) |
3725 | fStatusElementP->data=NULL__null; |
3726 | // no optional elements for now |
3727 | fStatusElementP->targetRefList=NULL__null; |
3728 | fStatusElementP->sourceRefList=NULL__null; |
3729 | fStatusElementP->cred=NULL__null; |
3730 | fStatusElementP->chal=NULL__null; |
3731 | fStatusElementP->itemList=NULL__null; |
3732 | } // TStatusCommand::TStatusCommand |
3733 | |
3734 | |
3735 | // constructor for receiving status |
3736 | TStatusCommand::TStatusCommand( |
3737 | TSyncSession *aSessionP, // associated session (for callbacks) |
3738 | uInt32 aMsgID, // the Message ID of the command |
3739 | SmlStatusPtr_t aStatusElementP // associated STATUS command content element |
3740 | ) : |
3741 | TSmlCommand(scmd_status,false,aSessionP,aMsgID) |
3742 | { |
3743 | // save element |
3744 | fStatusElementP = aStatusElementP; |
3745 | } // TStatusCommand::TStatusCommand |
3746 | |
3747 | |
3748 | // analyze status |
3749 | bool TStatusCommand::analyze(TPackageStates aPackageState) |
3750 | { |
3751 | TSmlCommand::analyze(aPackageState); |
3752 | // get Command ID and flags |
3753 | if (fStatusElementP) { |
3754 | StartProcessing(fStatusElementP->cmdID,0); |
3755 | // get status code |
3756 | sInt32 temp; |
3757 | if (smlPCDataToLong(fStatusElementP->data,temp)) fStatusCode=temp; |
3758 | else { |
3759 | PDEBUGPRINTFX(DBG_ERROR,("Malformed status code: '%s'",smlPCDataToCharP(fStatusElementP->data))){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Malformed status code: '%s'" ,smlPCDataToCharP(fStatusElementP->data)); }; |
3760 | return false; // bad status |
3761 | } |
3762 | // get message reference |
3763 | if (!fStatusElementP->msgRef) { |
3764 | // no MsgRef -> must assume 1 (according to SyncML specs) |
3765 | fRefMsgID=1; |
3766 | DEBUGPRINTFX(DBG_PROTO,("No MsgRef in Status, assumed 1")){ if (((0x00000010) & getDbgMask()) == (0x00000010)) getDbgLogger ()->setNextMask(0x00000010).DebugPrintfLastMask ("No MsgRef in Status, assumed 1" ); }; |
3767 | } |
3768 | else if (!smlPCDataToULong(fStatusElementP->msgRef,fRefMsgID)) { |
3769 | PDEBUGPRINTFX(DBG_ERROR,("Malformed message reference: '%s'",smlPCDataToCharP(fStatusElementP->msgRef))){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Malformed message reference: '%s'" ,smlPCDataToCharP(fStatusElementP->msgRef)); }; |
3770 | return false; // bad status |
3771 | } |
3772 | // get command reference |
3773 | if (!smlPCDataToULong(fStatusElementP->cmdRef,fRefCmdID)) { |
3774 | PDEBUGPRINTFX(DBG_ERROR,("Malformed command reference: '%s'",smlPCDataToCharP(fStatusElementP->msgRef))){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("Malformed command reference: '%s'" ,smlPCDataToCharP(fStatusElementP->msgRef)); }; |
3775 | return false; // bad status |
3776 | } |
3777 | #ifdef SYDEBUG2 |
3778 | // warn if error (don't treat slow sync status or conflict indication as errors) |
3779 | // - 418 = item already exits: sent by Funambol server when both client and |
3780 | // and server have a new item which is considered identical by the server |
3781 | // (must be really identical, minor difference will lead to a merged item |
3782 | // which is sent back to the client without the 418). See Moblin Bugzilla #4599. |
3783 | if (fStatusCode>=300 && fStatusCode!=508 && fStatusCode!=419 && fStatusCode!=418) { |
3784 | PDEBUGPRINTFX(DBG_ERROR,({ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3785 | "WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)",{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3786 | fStatusCode,{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3787 | (long)fRefMsgID,{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3788 | (long)fRefCmdID,{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3789 | (long)fRefMsgID,{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3790 | (long)fRefCmdID,{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3791 | smlPCDataToCharP(fStatusElementP->cmd),{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3792 | (long)fRefMsgID,{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3793 | (long)fRefCmdID{ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3794 | )){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ( "WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); }; |
3795 | } |
3796 | else { |
3797 | // show what we have received |
3798 | PDEBUGPRINTFX(DBG_HOT,({ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "RECEIVED STATUS %hd for for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3799 | "RECEIVED STATUS %hd for for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "RECEIVED STATUS %hd for for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3800 | fStatusCode,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "RECEIVED STATUS %hd for for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3801 | (long)fRefMsgID,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "RECEIVED STATUS %hd for for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3802 | (long)fRefCmdID,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "RECEIVED STATUS %hd for for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3803 | (long)fRefMsgID,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "RECEIVED STATUS %hd for for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3804 | (long)fRefCmdID,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "RECEIVED STATUS %hd for for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3805 | smlPCDataToCharP(fStatusElementP->cmd),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "RECEIVED STATUS %hd for for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3806 | (long)fRefMsgID,{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "RECEIVED STATUS %hd for for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3807 | (long)fRefCmdID{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "RECEIVED STATUS %hd for for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); } |
3808 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ( "RECEIVED STATUS %hd for for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)" , fStatusCode, (long)fRefMsgID, (long)fRefCmdID, (long)fRefMsgID , (long)fRefCmdID, smlPCDataToCharP(fStatusElementP->cmd), (long)fRefMsgID, (long)fRefCmdID ); }; |
3809 | } |
3810 | // - source and target refs |
3811 | if (PDEBUGMASKgetDbgMask() & DBG_HOT0x00000001) { |
3812 | SmlTargetRefListPtr_t targetrefP = fStatusElementP->targetRefList; |
3813 | while (targetrefP) { |
3814 | // target ref available |
3815 | PDEBUGPRINTFX(DBG_HOT,("- TargetRef (remoteID) = '%s'",smlPCDataToCharP(targetrefP->targetRef))){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("- TargetRef (remoteID) = '%s'" ,smlPCDataToCharP(targetrefP->targetRef)); }; |
3816 | // next |
3817 | targetrefP=targetrefP->next; |
3818 | } |
3819 | SmlSourceRefListPtr_t sourcerefP = fStatusElementP->sourceRefList; |
3820 | while (sourcerefP) { |
3821 | // target ref available |
3822 | PDEBUGPRINTFX(DBG_HOT,("- SourceRef (localID) = '%s'",smlPCDataToCharP(sourcerefP->sourceRef))){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("- SourceRef (localID) = '%s'" ,smlPCDataToCharP(sourcerefP->sourceRef)); }; |
3823 | // next |
3824 | sourcerefP=sourcerefP->next; |
3825 | } |
3826 | } |
3827 | // - optional items |
3828 | if (PDEBUGMASKgetDbgMask() & DBG_ERROR0x00000002) { |
3829 | SmlItemListPtr_t itemlistP = fStatusElementP->itemList; |
3830 | while (itemlistP) { |
3831 | // item available |
3832 | PDEBUGPRINTFX(DBG_HOT,("- Item data = %s",smlItemDataToCharP(itemlistP->item))){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("- Item data = %s" ,smlItemDataToCharP(itemlistP->item)); }; |
3833 | // next |
3834 | itemlistP=itemlistP->next; |
3835 | } |
3836 | } |
3837 | #endif |
3838 | return true; // good status |
3839 | } |
3840 | else return false; // no proto element, bad command |
3841 | } // TStatusCommand::analyze |
3842 | |
3843 | |
3844 | |
3845 | // returns true if command must be put to the waiting-for-status queue. |
3846 | // If false, command can be deleted |
3847 | bool TStatusCommand::issue( |
3848 | uInt32 aAsCmdID, // command ID to be used |
3849 | uInt32 aInMsgID, // message ID in which command is being issued |
3850 | bool aNoResp // dummy here, because Status has always no response |
3851 | ) |
3852 | { |
3853 | // now issue |
3854 | if (fStatusElementP) { |
3855 | // prepare basic stuff |
3856 | TSmlCommand::issue(aAsCmdID,aInMsgID,true); |
3857 | // set status code in structure (but only once, in case we are evaluating before issuing) |
3858 | if (fStatusElementP->data==NULL__null) fStatusElementP->data=newPCDataLong(fStatusCode); |
3859 | // Status is meant to have a CmdID. SyncML 1.0 docs say no, but this was corrected in 1.0.1 |
3860 | // issue command with SyncML toolkit (no flags) |
3861 | PrepareIssue(&fStatusElementP->cmdID,NULL__null); // CmdID (SyncML 1.0.1 conformant) |
3862 | if (!fEvalMode) { |
3863 | // PrepareIssue(NULL,NULL); // no CmdID, no flags |
3864 | #ifdef SYDEBUG2 |
3865 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance) |
3866 | smlStatusCmd(fSessionP->fOutgoingXMLInstance,fStatusElementP); |
3867 | #endif |
3868 | Ret_t err; |
3869 | if ((err=smlStatusCmd(fSessionP->getSmlWorkspaceID(),fStatusElementP))!=SML_ERR_OK0x00) { |
3870 | SYSYNC_THROW(TSmlException("smlStatusCmd",err))throw TSmlException("smlStatusCmd",err); |
3871 | } |
3872 | FinalizeIssue(); |
3873 | // show debug |
3874 | #ifdef SYDEBUG2 |
3875 | // - warning for non-ok (don't treat slow sync status as error) |
3876 | if (fStatusCode>=300 && fStatusCode!=508) { |
3877 | PDEBUGPRINTFX(DBG_ERROR,("WARNING: Non-OK Status %hd returned to remote!",fStatusCode)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("WARNING: Non-OK Status %hd returned to remote!" ,fStatusCode); }; |
3878 | } |
3879 | // - what was issued |
3880 | PDEBUGPRINTFX(DBG_HOT,("Status Code %s issued for Cmd=%s, (incoming MsgID=%s, CmdID=%s)",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Status Code %s issued for Cmd=%s, (incoming MsgID=%s, CmdID=%s)" , smlPCDataToCharP(fStatusElementP->data), smlPCDataToCharP (fStatusElementP->cmd), smlPCDataToCharP(fStatusElementP-> msgRef), smlPCDataToCharP(fStatusElementP->cmdRef) ); } |
3881 | smlPCDataToCharP(fStatusElementP->data),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Status Code %s issued for Cmd=%s, (incoming MsgID=%s, CmdID=%s)" , smlPCDataToCharP(fStatusElementP->data), smlPCDataToCharP (fStatusElementP->cmd), smlPCDataToCharP(fStatusElementP-> msgRef), smlPCDataToCharP(fStatusElementP->cmdRef) ); } |
3882 | smlPCDataToCharP(fStatusElementP->cmd),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Status Code %s issued for Cmd=%s, (incoming MsgID=%s, CmdID=%s)" , smlPCDataToCharP(fStatusElementP->data), smlPCDataToCharP (fStatusElementP->cmd), smlPCDataToCharP(fStatusElementP-> msgRef), smlPCDataToCharP(fStatusElementP->cmdRef) ); } |
3883 | smlPCDataToCharP(fStatusElementP->msgRef),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Status Code %s issued for Cmd=%s, (incoming MsgID=%s, CmdID=%s)" , smlPCDataToCharP(fStatusElementP->data), smlPCDataToCharP (fStatusElementP->cmd), smlPCDataToCharP(fStatusElementP-> msgRef), smlPCDataToCharP(fStatusElementP->cmdRef) ); } |
3884 | smlPCDataToCharP(fStatusElementP->cmdRef){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Status Code %s issued for Cmd=%s, (incoming MsgID=%s, CmdID=%s)" , smlPCDataToCharP(fStatusElementP->data), smlPCDataToCharP (fStatusElementP->cmd), smlPCDataToCharP(fStatusElementP-> msgRef), smlPCDataToCharP(fStatusElementP->cmdRef) ); } |
3885 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("Status Code %s issued for Cmd=%s, (incoming MsgID=%s, CmdID=%s)" , smlPCDataToCharP(fStatusElementP->data), smlPCDataToCharP (fStatusElementP->cmd), smlPCDataToCharP(fStatusElementP-> msgRef), smlPCDataToCharP(fStatusElementP->cmdRef) ); }; |
3886 | // - source and target refs |
3887 | if (PDEBUGTEST(DBG_HOT)(((0x00000001) & getDbgMask()) == (0x00000001))) { |
3888 | SmlTargetRefListPtr_t targetrefP = fStatusElementP->targetRefList; |
3889 | while (targetrefP) { |
3890 | // target ref available |
3891 | PDEBUGPRINTFX(DBG_HOT,("- TargetRef (localID) = '%s'",smlPCDataToCharP(targetrefP->targetRef))){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("- TargetRef (localID) = '%s'" ,smlPCDataToCharP(targetrefP->targetRef)); } |
3892 | // next |
3893 | targetrefP=targetrefP->next; |
3894 | } |
3895 | SmlSourceRefListPtr_t sourcerefP = fStatusElementP->sourceRefList; |
3896 | while (sourcerefP) { |
3897 | // target ref available |
3898 | PDEBUGPRINTFX(DBG_HOT,("- SourceRef (remoteID) = '%s'",smlPCDataToCharP(sourcerefP->sourceRef))){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("- SourceRef (remoteID) = '%s'" ,smlPCDataToCharP(sourcerefP->sourceRef)); } |
3899 | // next |
3900 | sourcerefP=sourcerefP->next; |
3901 | } |
3902 | } |
3903 | #endif |
3904 | // we don't need the status structure any more, free (and NULL ptr) now |
3905 | FreeSmlElement(); |
3906 | } |
3907 | else |
3908 | return smlStatusCmd(fSessionP->getSmlWorkspaceID(),fStatusElementP)==SML_ERR_OK0x00; |
3909 | } |
3910 | else { |
3911 | DEBUGPRINTFX(DBG_ERROR,("*** Tried to issue NULL status")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("*** Tried to issue NULL status" ); }; |
3912 | } |
3913 | // status does NOT await any answer, and can be deleted after issuing |
3914 | return false; // don't queue for status |
3915 | } // TStatusCommand::issue |
3916 | |
3917 | |
3918 | // add a target Ref to the status (no op if ref is NULL) |
3919 | void TStatusCommand::addTargetRef( |
3920 | const char *aTargetRef // Target LocURI of an item this status applies to |
3921 | ) |
3922 | { |
3923 | SmlTargetRefListPtr_t *targetreflistPP; |
3924 | if (fStatusElementP && aTargetRef && *aTargetRef) { |
3925 | // Note: empty refs will not be added |
3926 | targetreflistPP=&(fStatusElementP->targetRefList); |
3927 | // find last targetreflist pointer |
3928 | while (*targetreflistPP) { |
3929 | targetreflistPP=&((*targetreflistPP)->next); |
3930 | } |
3931 | // targetreflistPP now points to a NULL pointer which must be replaced by addr of new targetreflist entry |
3932 | *targetreflistPP = SML_NEW(SmlTargetRefList_t)((SmlTargetRefList_t*) _smlMalloc(sizeof(SmlTargetRefList_t)) ); |
3933 | (*targetreflistPP)->next=NULL__null; |
3934 | (*targetreflistPP)->targetRef= |
3935 | newPCDataString(aTargetRef); |
3936 | } |
3937 | } // TStatusCommand::addTargetRef |
3938 | |
3939 | |
3940 | // add a source Ref to the status (no op if ref is NULL) |
3941 | void TStatusCommand::addSourceRef( |
3942 | const char *aSourceRef // Target LocURI of an item this status applies to |
3943 | ) |
3944 | { |
3945 | SmlSourceRefListPtr_t *sourcereflistPP; |
3946 | if (fStatusElementP && aSourceRef && *aSourceRef) { |
3947 | // Note: empty refs will not be added |
3948 | sourcereflistPP=&(fStatusElementP->sourceRefList); |
3949 | // find last sourcereflist pointer |
3950 | while (*sourcereflistPP) { |
3951 | sourcereflistPP=&((*sourcereflistPP)->next); |
3952 | } |
3953 | // sourcereflistPP now points to a NULL pointer which must be replaced by addr of new sourcereflist entry |
3954 | *sourcereflistPP = SML_NEW(SmlSourceRefList_t)((SmlSourceRefList_t*) _smlMalloc(sizeof(SmlSourceRefList_t)) ); |
3955 | (*sourcereflistPP)->next=NULL__null; |
3956 | (*sourcereflistPP)->sourceRef= |
3957 | newPCDataString(aSourceRef); |
3958 | } |
3959 | } // TStatusCommand::addSourceRef |
3960 | |
3961 | |
3962 | // add a String Item to the status (only if not empty) |
3963 | void TStatusCommand::addItemString( |
3964 | const char *aItemString // item string to be added |
3965 | ) |
3966 | { |
3967 | if (fStatusElementP && aItemString && *aItemString) { |
3968 | addItem(newStringDataItem(aItemString)); |
3969 | } |
3970 | } // TStatusCommand::addItemString |
3971 | |
3972 | |
3973 | // add an Item to the status |
3974 | void TStatusCommand::addItem( |
3975 | SmlItemPtr_t aItemP // existing item data structure, ownership is passed to Status |
3976 | ) |
3977 | { |
3978 | if (fStatusElementP) |
3979 | addItemToList(aItemP,&(fStatusElementP->itemList)); |
3980 | } // TStatusCommand::addItem |
3981 | |
3982 | |
3983 | // move items from another status to this one (passes ownership of items and deletes them from original) |
3984 | void TStatusCommand::moveItemsFrom(TStatusCommand *aStatusCommandP) |
3985 | { |
3986 | if (fStatusElementP && aStatusCommandP) { |
3987 | // pass item list to new owner |
3988 | fStatusElementP->itemList = aStatusCommandP->fStatusElementP->itemList; |
3989 | // remove items from original |
3990 | aStatusCommandP->fStatusElementP->itemList = NULL__null; |
3991 | } |
3992 | } // TStatusCommand::moveItemsFrom |
3993 | |
3994 | |
3995 | |
3996 | // add Challenge to status |
3997 | // challenge data structure ownership is passed to Status |
3998 | void TStatusCommand::setChallenge(SmlChalPtr_t aChallengeP) |
3999 | { |
4000 | if (fStatusElementP) { |
4001 | if (fStatusElementP->chal) { |
4002 | // get rid of old challenge |
4003 | smlFreeChalPtr(fStatusElementP->chal); |
4004 | fStatusElementP->chal=NULL__null; |
4005 | } |
4006 | // set new |
4007 | fStatusElementP->chal=aChallengeP; |
4008 | } |
4009 | } // TStatusCommand::setChallenge |
4010 | |
4011 | |
4012 | // set Status code |
4013 | void TStatusCommand::setStatusCode(TSyError aStatusCode) |
4014 | { |
4015 | fStatusCode = aStatusCode; |
4016 | } // TStatusCommand::setStatusCode |
4017 | |
4018 | |
4019 | void TStatusCommand::FreeSmlElement(void) |
4020 | { |
4021 | // remove SyncML toolkit element(s) |
4022 | FREEPROTOELEMENT(fStatusElementP); |
4023 | } // TResultsCommand::FreeSmlElement |
4024 | |
4025 | |
4026 | TStatusCommand::~TStatusCommand() |
4027 | { |
4028 | // free command elements, if any (use explicit invocation as this is a destructor) |
4029 | TStatusCommand::FreeSmlElement(); |
4030 | } // TStatusCommand::TStatusCommand |
4031 | |
4032 | |
4033 | /* end of TStatusCommand implementation */ |
4034 | |
4035 | |
4036 | /* |
4037 | * Implementation of TResultsCommand |
4038 | */ |
4039 | |
4040 | // constructor for receiving command |
4041 | TResultsCommand::TResultsCommand( |
4042 | TSyncSession *aSessionP, // associated session (for callbacks) |
4043 | uInt32 aMsgID, // the Message ID of the command |
4044 | SmlResultsPtr_t aResultsElementP // associated syncml protocol element |
4045 | ) : |
4046 | TSmlCommand(scmd_results,false,aSessionP,aMsgID) |
4047 | { |
4048 | // save element |
4049 | fResultsElementP = aResultsElementP; |
4050 | } // TResultsCommand::TResultsCommand |
4051 | |
4052 | |
4053 | // constructor for generating results |
4054 | TResultsCommand::TResultsCommand( |
4055 | TSyncSession *aSessionP, // associated session (for callbacks) |
4056 | TSmlCommand *aCommandP, // command these results refer to |
4057 | const char *aTargetRef, // target reference |
4058 | const char *aSourceRef // source reference |
4059 | ) : |
4060 | TSmlCommand(scmd_results,true,aSessionP) |
4061 | { |
4062 | // create internal results element |
4063 | fResultsElementP = SML_NEW(SmlResults_t)((SmlResults_t*) _smlMalloc(sizeof(SmlResults_t))); |
4064 | // set proto element type to make it auto-disposable |
4065 | fResultsElementP->elementType=SML_PE_RESULTS; |
4066 | // Cmd ID is now empty (will be set when issued) |
4067 | fResultsElementP->cmdID=NULL__null; |
4068 | // results refer to message of specified command |
4069 | fResultsElementP->msgRef=newPCDataLong(aCommandP->getMsgID()); |
4070 | // results refer to ID of specified command |
4071 | fResultsElementP->cmdRef=newPCDataLong(aCommandP->getCmdID()); |
4072 | // no meta for now |
4073 | fResultsElementP->meta=NULL__null; |
4074 | // target reference if specified |
4075 | if (aTargetRef) fResultsElementP->targetRef=newPCDataString(aTargetRef); |
4076 | else fResultsElementP->targetRef=NULL__null; |
4077 | // source reference if specified |
4078 | if (aSourceRef) fResultsElementP->sourceRef=newPCDataString(aSourceRef); |
4079 | else fResultsElementP->sourceRef=NULL__null; |
4080 | // no items for now |
4081 | fResultsElementP->itemList=NULL__null; |
4082 | } // TResultsCommand::TResultsCommand |
4083 | |
4084 | |
4085 | |
4086 | // returns true if command must be put to the waiting-for-status queue. |
4087 | // If false, command can be deleted |
4088 | bool TResultsCommand::issue( |
4089 | uInt32 aAsCmdID, // command ID to be used |
4090 | uInt32 aInMsgID, // message ID in which command is being issued |
4091 | bool aNoResp // issue without wanting response |
4092 | ) |
4093 | { |
4094 | // prepare |
4095 | TSmlCommand::issue(aAsCmdID,aInMsgID,aNoResp); |
4096 | // now issue |
4097 | if (fResultsElementP) { |
4098 | // issue command with SyncML toolkit (no flags) |
4099 | PrepareIssue(&fResultsElementP->cmdID,NULL__null); |
4100 | if (!fEvalMode) { |
4101 | #ifdef SYDEBUG2 |
4102 | if (fSessionP->fXMLtranslate && fSessionP->fOutgoingXMLInstance) |
4103 | smlResultsCmd(fSessionP->fOutgoingXMLInstance,fResultsElementP); |
4104 | #endif |
4105 | Ret_t err; |
4106 | if ((err=smlResultsCmd(fSessionP->getSmlWorkspaceID(),fResultsElementP))!=SML_ERR_OK0x00) { |
4107 | SYSYNC_THROW(TSmlException("smlResultsCmd",err))throw TSmlException("smlResultsCmd",err); |
4108 | } |
4109 | FinalizeIssue(); |
4110 | // show debug |
4111 | DEBUGPRINTFX(DBG_HOT,("results issued for (incoming MsgID=%s, CmdID=%s)",{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("results issued for (incoming MsgID=%s, CmdID=%s)" , smlPCDataToCharP(fResultsElementP->msgRef), smlPCDataToCharP (fResultsElementP->cmdRef) ); } |
4112 | smlPCDataToCharP(fResultsElementP->msgRef),{ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("results issued for (incoming MsgID=%s, CmdID=%s)" , smlPCDataToCharP(fResultsElementP->msgRef), smlPCDataToCharP (fResultsElementP->cmdRef) ); } |
4113 | smlPCDataToCharP(fResultsElementP->cmdRef){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("results issued for (incoming MsgID=%s, CmdID=%s)" , smlPCDataToCharP(fResultsElementP->msgRef), smlPCDataToCharP (fResultsElementP->cmdRef) ); } |
4114 | )){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("results issued for (incoming MsgID=%s, CmdID=%s)" , smlPCDataToCharP(fResultsElementP->msgRef), smlPCDataToCharP (fResultsElementP->cmdRef) ); }; |
4115 | // we don't need the results structure any more, free (and NULL ptr) now |
4116 | FreeSmlElement(); |
4117 | } |
4118 | else |
4119 | return smlResultsCmd(fSessionP->getSmlWorkspaceID(),fResultsElementP)==SML_ERR_OK0x00; |
4120 | } |
4121 | else { |
4122 | DEBUGPRINTFX(DBG_ERROR,("*** Tried to issue NULL result")){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger ()->setNextMask(0x00000002).DebugPrintfLastMask ("*** Tried to issue NULL result" ); }; |
4123 | } |
4124 | // SyncML 1.0: result does NOT await any answer, and can be deleted after issuing |
4125 | // SyncML 1.0.1: all commands will receive a status (except Status) |
4126 | return true; // queue for status/result |
4127 | } // TResultsCommand::issue |
4128 | |
4129 | |
4130 | // add a String Item to the results |
4131 | void TResultsCommand::addItemString( |
4132 | const char *aItemString // item string to be added |
4133 | ) |
4134 | { |
4135 | if (fResultsElementP && aItemString) { |
4136 | addItem(newStringDataItem(aItemString)); |
4137 | } |
4138 | } // TResultsCommand::addItemString |
4139 | |
4140 | |
4141 | // add an Item to the results |
4142 | void TResultsCommand::addItem( |
4143 | SmlItemPtr_t aItemP // existing item data structure, ownership is passed to Results |
4144 | ) |
4145 | { |
4146 | if (fResultsElementP) |
4147 | addItemToList(aItemP,&(fResultsElementP->itemList)); |
4148 | } // TResultsCommand::addItem |
4149 | |
4150 | |
4151 | // set Meta of the results command |
4152 | void TResultsCommand::setMeta( |
4153 | SmlPcdataPtr_t aMetaP // existing meta data structure, ownership is passed to Get |
4154 | ) |
4155 | { |
4156 | if (fResultsElementP) |
4157 | fResultsElementP->meta=aMetaP; |
4158 | } // TResultsCommand::setMeta |
4159 | |
4160 | |
4161 | |
4162 | |
4163 | // analyze command (but do not yet execute) |
4164 | bool TResultsCommand::analyze(TPackageStates aPackageState) |
4165 | { |
4166 | TSmlCommand::analyze(aPackageState); |
4167 | // get Command ID and flags |
4168 | if (fResultsElementP) { |
4169 | StartProcessing(fResultsElementP->cmdID,0); |
4170 | return true; |
4171 | } |
4172 | else return false; // no proto element, bad command |
4173 | } // TResultsCommand::analyze |
4174 | |
4175 | |
4176 | // execute command (perform real actions, generate status) |
4177 | // returns true if command has executed and can be deleted |
4178 | bool TResultsCommand::execute(void) |
4179 | { |
4180 | TStatusCommand *statusCmdP=NULL__null; |
4181 | SmlItemListPtr_t thisitemnode,nextitemnode; |
4182 | |
4183 | // process items |
4184 | thisitemnode=fResultsElementP->itemList; |
4185 | while (thisitemnode) { |
4186 | nextitemnode = thisitemnode->next; |
4187 | if (!thisitemnode->item) SYSYNC_THROW(TSyncException("Results with NULL item"))throw TSyncException("Results with NULL item"); |
4188 | // get Source LocURI |
4189 | string locURI=smlSrcTargLocURIToCharP(thisitemnode->item->source); |
4190 | DEBUGPRINTFX(DBG_HOT,("processing item with locURI=%s",locURI.c_str())){ if (((0x00000001) & getDbgMask()) == (0x00000001)) getDbgLogger ()->setNextMask(0x00000001).DebugPrintfLastMask ("processing item with locURI=%s" ,locURI.c_str()); }; |
4191 | // let session (and descendants) process it |
4192 | // - default to ok status |
4193 | statusCmdP = newStatusCommand(200); |
4194 | fSessionP->processPutResultItem(false,locURI.c_str(),this,thisitemnode->item,*statusCmdP); |
4195 | #ifdef RESULTS_SENDS_STATUS1 |
4196 | // now complete and issue status |
4197 | statusCmdP->addSourceRef(locURI.c_str()); // add source ref |
4198 | ISSUE_COMMAND_ROOT(fSessionP,statusCmdP){ TSmlCommand* p=statusCmdP; statusCmdP=__null; fSessionP-> issueRootPtr(p); }; |
4199 | #else |
4200 | // suppress (forget) status |
4201 | delete statusCmdP; |
4202 | #endif |
4203 | // next item |
4204 | thisitemnode=nextitemnode; |
4205 | } |
4206 | // free element |
4207 | FreeSmlElement(); |
4208 | // done with command, delete it now: return true |
4209 | return true; |
4210 | } // TResultsCommand::execute |
4211 | |
4212 | |
4213 | void TResultsCommand::FreeSmlElement(void) |
4214 | { |
4215 | // remove SyncML toolkit element(s) |
4216 | FREEPROTOELEMENT(fResultsElementP); |
4217 | } // TResultsCommand::FreeSmlElement |
4218 | |
4219 | |
4220 | TResultsCommand::~TResultsCommand() |
4221 | { |
4222 | // free command elements, if any (use explicit invocation as this is a destructor) |
4223 | TResultsCommand::FreeSmlElement(); |
4224 | } // TResultsCommand::TResultsCommand |
4225 | |
4226 | |
4227 | /* end of TResultsCommand implementation */ |
4228 | |
4229 | |
4230 | /* |
4231 | * Implementation of TDevInfResultsCommand |
4232 | */ |
4233 | |
4234 | |
4235 | // constructor for generating devInf results |
4236 | TDevInfResultsCommand::TDevInfResultsCommand( |
4237 | TSyncSession *aSessionP, // associated session (for callbacks) |
4238 | TSmlCommand *aCommandP // command these results refer to |
4239 | ) : |
4240 | /* %%% if strictly following example in SyncML protocol specs |
4241 | * DevInf results don't have a source or target ref, only the item has |
4242 | TResultsCommand(aSessionP,aCommandP,SYNCML_DEVINF_LOCURI,NULL) |
4243 | */ |
4244 | TResultsCommand(aSessionP,aCommandP,NULL__null,NULL__null) |
4245 | { |
4246 | // standard result is now created |
4247 | // - create meta type |
4248 | /* %%% if strictly following example in SyncML protocol specs, meta |
4249 | * must be defined in the result/put command, not the individual item |
4250 | */ |
4251 | string metatype=SYNCML_DEVINF_META_TYPE"application/vnd.syncml-devinf"; |
4252 | fSessionP->addEncoding(metatype); |
4253 | fResultsElementP->meta=newMetaType(metatype.c_str()); |
4254 | // - add local DevInf item to result |
4255 | // Note: explicit GET always returns entire devInf (all datastores) |
4256 | addItem(fSessionP->getLocalDevInfItem(false,false)); |
4257 | } // TDevInfResultsCommand::TDevInfResultsCommand |
4258 | |
4259 | |
4260 | // - try to shrink command by at least aReduceByBytes |
4261 | // Returns false if shrink is not possible |
4262 | bool TDevInfResultsCommand::shrinkCommand(sInt32 aReduceByBytes) |
4263 | { |
4264 | // measure current size (with current CmdID/MsgID) |
4265 | sInt32 origfree = evalIssue(fCmdID,fMsgID,fNoResp); |
4266 | // extract original devInf |
4267 | SmlItemPtr_t origDevInf = fResultsElementP->itemList->item; |
4268 | // remove it from the item list |
4269 | fResultsElementP->itemList->item = NULL__null; |
4270 | smlFreeItemList(fResultsElementP->itemList); |
4271 | fResultsElementP->itemList = NULL__null; |
4272 | // create reduced version of the devInf |
4273 | // - only alerted datastores if initialisation is complete (i.e. we KNOW which datastores the sync is about) |
4274 | // - no CTCap property lists |
4275 | SmlItemPtr_t reducedDevInf = |
4276 | fSessionP->getLocalDevInfItem( |
4277 | fSessionP->getIncomingState()>psta_init, // alerted only if init complete |
4278 | true // no CTCap property lists |
4279 | ); |
4280 | // insert it into command |
4281 | addItem(reducedDevInf); |
4282 | // measure again |
4283 | sInt32 nowfree = evalIssue(fCmdID,fMsgID,fNoResp); |
4284 | // decide if we are successful |
4285 | if (nowfree-origfree>=aReduceByBytes) { |
4286 | // new devinf matches size requirement |
4287 | smlFreeItemPtr(origDevInf); // discard original devInf |
4288 | return true; // shrink successful |
4289 | } |
4290 | else { |
4291 | // new reduced devInf is still too big |
4292 | fResultsElementP->itemList->item = origDevInf; // restore oiginal devInf |
4293 | smlFreeItemPtr(reducedDevInf); // discard reduced one |
4294 | return false; // cannot shrink enough |
4295 | } |
4296 | } // TDevInfResultsCommand::shrinkCommand |
4297 | |
4298 | |
4299 | |
4300 | // mark devinf as sent when issuing command |
4301 | bool TDevInfResultsCommand::issue( |
4302 | uInt32 aAsCmdID, // command ID to be used |
4303 | uInt32 aInMsgID, // message ID in which command is being issued |
4304 | bool aNoResp |
4305 | ) |
4306 | { |
4307 | fSessionP->remoteGotDevinf(); |
4308 | return TResultsCommand::issue(aAsCmdID,aInMsgID,aNoResp); |
4309 | } // TDevInfResultsCommand::issue |
4310 | |
4311 | |
4312 | void TDevInfResultsCommand::FreeSmlElement(void) |
4313 | { |
4314 | // remove SyncML toolkit element(s) |
4315 | // - result might already be freed! |
4316 | if (fResultsElementP) { |
4317 | FREEPROTOELEMENT(fResultsElementP); |
4318 | } |
4319 | } // TDevInfResultsCommand::FreeSmlElement |
4320 | |
4321 | |
4322 | TDevInfResultsCommand::~TDevInfResultsCommand() |
4323 | { |
4324 | // free command elements, if any (use explicit invocation as this is a destructor) |
4325 | TDevInfResultsCommand::FreeSmlElement(); |
4326 | // NOTE: fResultsElementP is NULLed so invocation of base class destuctor does no harm |
4327 | } // TDevInfResultsCommand::TDevInfResultsCommand |
4328 | |
4329 | |
4330 | /* end of TDevInfResultsCommand implementation */ |
4331 | |
4332 | |
4333 | /* |
4334 | * Implementation of TDevInfResultsCommand |
4335 | */ |
4336 | |
4337 | |
4338 | // constructor for generating devinf Put command |
4339 | TDevInfPutCommand::TDevInfPutCommand( |
4340 | TSyncSession *aSessionP // associated session (for callbacks) |
4341 | ) : |
4342 | TPutCommand(aSessionP) |
4343 | { |
4344 | // standard put is now created |
4345 | // - create meta type |
4346 | /* %%% if strictly following example in SyncML protocol specs, meta |
4347 | * must be defined in the result/put command, not the individual item |
4348 | */ |
4349 | string metatype=SYNCML_DEVINF_META_TYPE"application/vnd.syncml-devinf"; |
4350 | fSessionP->addEncoding(metatype); |
4351 | fPutElementP->meta=newMetaType(metatype.c_str()); |
4352 | // - add local DevInf item to result |
4353 | // Note: PUT of server only returns alerted datastore's devInf |
4354 | addItem(fSessionP->getLocalDevInfItem(IS_SERVER(getSyncAppBase()->isServer()),false)); |
4355 | } // TDevInfPutCommand::TDevInfPutCommand |
4356 | |
4357 | |
4358 | // mark devinf as sent when issuing command |
4359 | bool TDevInfPutCommand::issue( |
4360 | uInt32 aAsCmdID, // command ID to be used |
4361 | uInt32 aInMsgID, // message ID in which command is being issued |
4362 | bool aNoResp |
4363 | ) |
4364 | { |
4365 | fSessionP->remoteGotDevinf(); |
4366 | return TPutCommand::issue(aAsCmdID,aInMsgID,aNoResp); |
4367 | } // TDevInfPutCommand::issue |
4368 | |
4369 | |
4370 | void TDevInfPutCommand::FreeSmlElement(void) |
4371 | { |
4372 | // remove SyncML toolkit element(s) |
4373 | // - result might already be freed! |
4374 | if (fPutElementP) { |
4375 | FREEPROTOELEMENT(fPutElementP); |
4376 | } |
4377 | } // TDevInfPutCommand::FreeSmlElement |
4378 | |
4379 | |
4380 | TDevInfPutCommand::~TDevInfPutCommand() |
4381 | { |
4382 | // free command elements, if any (use explicit invocation as this is a destructor) |
4383 | TDevInfPutCommand::FreeSmlElement(); |
4384 | // NOTE: fResultsElementP is NULLed so invocation of base class destuctor does not harm |
4385 | } // TDevInfPutCommand::~TDevInfPutCommand |
4386 | |
4387 | /* end of TDevInfPutCommand implementation */ |
4388 | |
4389 | #endif // SYNCCOMMAND_PART2_EXCLUDE |
4390 | |
4391 | // eof |