Overview

Packages

  • ActiveSync
  • None

Classes

  • Horde_ActiveSync
  • Horde_ActiveSync_Connector_Exporter
  • Horde_ActiveSync_Connector_Importer
  • Horde_ActiveSync_Driver_Base
  • Horde_ActiveSync_Exception
  • Horde_ActiveSync_Exception_InvalidRequest
  • Horde_ActiveSync_Exception_StateGone
  • Horde_ActiveSync_Message_Base
  • Horde_ActiveSync_Request_Base
  • Horde_ActiveSync_Request_FolderCreate
  • Horde_ActiveSync_Request_FolderSync
  • Horde_ActiveSync_Request_GetHierarchy
  • Horde_ActiveSync_Request_GetItemEstimate
  • Horde_ActiveSync_Request_MeetingResponse
  • Horde_ActiveSync_Request_MoveItems
  • Horde_ActiveSync_Request_Notify
  • Horde_ActiveSync_Request_Ping
  • Horde_ActiveSync_Request_Provision
  • Horde_ActiveSync_Request_Search
  • Horde_ActiveSync_Request_SendMail
  • Horde_ActiveSync_Request_SmartForward
  • Horde_ActiveSync_Request_SmartReply
  • Horde_ActiveSync_Request_Sync
  • Horde_ActiveSync_State_File
  • Horde_ActiveSync_Sync
  • Horde_ActiveSync_Wbxml
  • Horde_ActiveSync_Wbxml_Decoder
  • Horde_ActiveSync_Wbxml_Encoder
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * ActiveSync Handler for SYNC requests
  4:  *
  5:  * Copyright 2009-2012 Horde LLC (http://www.horde.org/)
  6:  *
  7:  * @author Michael J. Rubinsky <mrubinsk@horde.org>
  8:  * @package ActiveSync
  9:  */
 10: /**
 11:  * Zarafa Deutschland GmbH, www.zarafaserver.de
 12:  * This file is distributed under GPL-2.0.
 13:  * Consult COPYING file for details
 14:  */
 15: class Horde_ActiveSync_Request_Sync extends Horde_ActiveSync_Request_Base
 16: {
 17:     /* Status */
 18:     const STATUS_SUCCESS     = 1;
 19:     const STATUS_VERSIONMISM = 2;
 20:     const STATUS_KEYMISM     = 3;
 21:     const STATUS_PROTERROR   = 4;
 22:     const STATUS_SERVERERROR = 5;
 23: 
 24:     /* Maximum window size */
 25:     const MAX_WINDOW_SIZE    = 512;
 26: 
 27:     /**
 28:      * Handle the sync request
 29:      *
 30:      * @return boolean
 31:      * @throws Horde_ActiveSync_Exception
 32:      */
 33:     public function handle()
 34:     {
 35:         parent::handle();
 36:         $this->_logger->info('[' . $this->_device->id . '] Handling SYNC command.');
 37: 
 38:         // Check policy
 39:         if (!$this->checkPolicyKey($this->_activeSync->getPolicyKey())) {
 40:             return false;
 41:         }
 42: 
 43:         $this->_statusCode = self::STATUS_SUCCESS;
 44:         $collections = array();
 45: 
 46:         // Start decoding request
 47:         if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_SYNCHRONIZE)) {
 48:             throw new Horde_ActiveSync_Exception('Protocol error');
 49:         }
 50:         if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_FOLDERS)) {
 51:             throw new Horde_ActiveSync_Exception('Protocol error');
 52:         }
 53: 
 54:         while ($this->_statusCode == self::STATUS_SUCCESS &&
 55:                $this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_FOLDER)) {
 56: 
 57:             // Defaults
 58:             $collection = array();
 59:             $collection['truncation'] = Horde_ActiveSync::TRUNCATION_ALL;
 60:             $collection['clientids'] = array();
 61:             $collection['fetchids'] = array();
 62:             $collection['windowsize'] = 100;
 63:             $collection['conflict'] = Horde_ActiveSync::CONFLICT_OVERWRITE_PIM;
 64: 
 65:             if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_FOLDERTYPE)) {
 66:                 throw new Horde_ActiveSync_Exception('Protocol error');
 67:             }
 68: 
 69:             $collection['class'] = $this->_decoder->getElementContent();
 70:             $this->_logger->info('[' . $this->_device->id . '] Syncing folder class: ' . $collection['class']);
 71:             if (!$this->_decoder->getElementEndTag()) {
 72:                 throw new Horde_ActiveSync_Exception('Protocol error');
 73:             }
 74: 
 75:             if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_SYNCKEY)) {
 76:                 throw new Horde_ActiveSync_Exception('Protocol error');
 77:             }
 78:             $collection['synckey'] = $this->_decoder->getElementContent();
 79:             if (!$this->_decoder->getElementEndTag()) {
 80:                 throw new Horde_ActiveSync_Exception('Protocol error');
 81:             }
 82: 
 83:             if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_FOLDERID)) {
 84:                 $collection['id'] = $this->_decoder->getElementContent();
 85:                 $this->_logger->info('[' . $this->_device->id . '] Folder server id: ' . $collection['id']);
 86:                 if (!$this->_decoder->getElementEndTag()) {
 87:                     throw new Horde_ActiveSync_Exception('Protocol error');
 88:                 }
 89:             }
 90: 
 91:             // SYNC_SUPPORTED
 92:             if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_SUPPORTED)) {
 93:                 // Only allowed on initial sync request
 94:                 if ($collection['synckey'] != 0) {
 95:                     $this->_statusCode = self::STATUS_PROTERROR;
 96:                     $this->_handleError($collection);
 97:                     exit;
 98:                 }
 99:                 while (1) {
100:                     $el = $this->_decoder->getElement();
101:                     if ($el[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_ENDTAG) {
102:                         break;
103:                     }
104:                     $collection['supported'][] = $el[2];
105:                 }
106:             }
107: 
108:             if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_DELETESASMOVES)) {
109:                 $collection['deletesasmoves'] = true;
110:             }
111: 
112:             if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_GETCHANGES)) {
113:                 $collection['getchanges'] = true;
114:             }
115: 
116:             if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_WINDOWSIZE)) {
117:                 $collection['windowsize'] = $this->_decoder->getElementContent();
118:                 if (!$this->_decoder->getElementEndTag()) {
119:                     $this->_statusCode = self::STATUS_PROTERROR;
120:                     $this->_handleError($collection);
121:                     exit;
122:                 }
123: 
124:                 // Ensure appropriate window size
125:                 if ($collection['windowsize'] < 1 || $collection['windowsize'] > self::MAX_WINDOW_SIZE) {
126:                     $this->_logger->debug('[' . $this->_device->id . '] Bad windowsize sent, defaulting to 512');
127:                     $collection['windowsize'] = self::MAX_WINDOW_SIZE;
128:                 }
129:             }
130: 
131:             if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_OPTIONS)) {
132:                 while(1) {
133:                     if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_FILTERTYPE)) {
134:                         $collection['filtertype'] = $this->_decoder->getElementContent();
135:                         if (!$this->_decoder->getElementEndTag()) {
136:                             $this->_statusCode = self::STATUS_PROTERROR;
137:                             $this->_handleError($collection);
138:                             exit;
139:                         }
140:                     }
141:                     if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_TRUNCATION)) {
142:                         $collection['truncation'] = $this->_decoder->getElementContent();
143:                         if (!$this->_decoder->getElementEndTag()) {
144:                             $this->_statusCode = self::STATUS_PROTERROR;
145:                             $this->_handleError($collection);
146:                             exit;
147:                         }
148:                     }
149:                     if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_RTFTRUNCATION)) {
150:                         $collection['rtftruncation'] = $this->_decoder->getElementContent();
151:                         if (!$this->_decoder->getElementEndTag()) {
152:                             $this->_statusCode = self::STATUS_PROTERROR;
153:                             $this->_handleError($collection);
154:                             exit;
155:                         }
156:                     }
157: 
158:                     if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_MIMESUPPORT)) {
159:                         $collection['mimesupport'] = $this->_decoder->getElementContent();
160:                         if (!$this->_decoder->getElementEndTag()) {
161:                             $this->_statusCode = self::STATUS_PROTERROR;
162:                             $this->_handleError($collection);
163:                             exit;
164:                         }
165:                     }
166: 
167:                     if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_MIMETRUNCATION)) {
168:                         $collection['mimetruncation'] = $this->_decoder->getElementContent();
169:                         if (!$this->_decoder->getElementEndTag()) {
170:                             $this->_statusCode = self::STATUS_PROTERROR;
171:                             $this->_handleError($collection);
172:                             exit;
173:                         }
174:                     }
175: 
176:                     if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_CONFLICT)) {
177:                         $collection['conflict'] = $this->_decoder->getElementContent();
178:                         if (!$this->_decoder->getElementEndTag()) {
179:                             $this->_statusCode = self::STATUS_PROTERROR;
180:                             $this->_handleError;
181:                             exit;
182:                         }
183:                     }
184:                     $e = $this->_decoder->peek();
185:                     if ($e[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_ENDTAG) {
186:                         $this->_decoder->getElementEndTag();
187:                         break;
188:                     }
189:                 }
190:             }
191: 
192:             if ($this->_statusCode == self::STATUS_SUCCESS) {
193:                 // Initialize the state
194:                 $this->_state->init($collection);
195:                 if (!empty($collection['supported'])) {
196:                     // Initial sync and we have SUPPORTED data - save it
197:                     if (empty($this->_device->supported)) {
198:                         $this->_device->supported = array();
199:                     }
200:                     $this->_device->supported[$collection['class']] = $collection['supported'];
201:                     $this->_state->setDeviceInfo($this->_device);
202:                 }
203: 
204:                 // Compatibility mode - get folderid from the state
205:                 if (!isset($collection['id'])) {
206:                     $collection['id'] = $this->_state->getFolderData($this->_device->id, $collection['class']);
207:                 }
208: 
209:                 try {
210:                     $this->_state->loadState($collection['synckey'], 'sync', $collection['id']);
211:                 } catch (Horde_ActiveSync_Exception $e) {
212:                     $this->_statusCode = self::STATUS_KEYMISM;
213:                     $this->_handleError($collection);
214:                     exit;
215:                 }
216:             }
217: 
218:             if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_COMMANDS)) {
219:                 // Some broken clients send SYNC_COMMANDS with a synckey of 0.
220:                 // This is a violation of the spec, and could lead to all kinds
221:                 // of data integrity issues.
222:                 if (empty($collection['synckey'])) {
223:                     $this->_statusCode = self::STATUS_PROTERROR;
224:                     $this->_handleError($collection);
225:                     exit;
226:                 }
227: 
228:                 // Configure importer with last state
229:                 $importer = $this->_driver->getImporter();
230:                 $importer->init($this->_state, $collection['id'], $collection['conflict']);
231:                 $nchanges = 0;
232:                 while (1) {
233:                     // MODIFY or REMOVE or ADD or FETCH
234:                     $element = $this->_decoder->getElement();
235:                     if ($element[Horde_ActiveSync_Wbxml::EN_TYPE] != Horde_ActiveSync_Wbxml::EN_TYPE_STARTTAG) {
236:                         $this->_decoder->_ungetElement($element);
237:                         break;
238:                     }
239: 
240:                     $nchanges++;
241: 
242:                     if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_SERVERENTRYID)) {
243:                         $serverid = $this->_decoder->getElementContent();
244: 
245:                         if (!$this->_decoder->getElementEndTag()) {// end serverid
246:                             $this->_statusCode = self::STATUS_PROTERROR;
247:                             $this->_handleError($collection);
248:                             exit;
249:                         }
250:                     } else {
251:                         $serverid = false;
252:                     }
253: 
254:                     if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_CLIENTENTRYID)) {
255:                         $clientid = $this->_decoder->getElementContent();
256: 
257:                         if (!$this->_decoder->getElementEndTag()) { // end clientid
258:                             $this->_statusCode = self::STATUS_PROTERROR;
259:                             $this->_handleError($collection);
260:                             exit;
261:                         }
262:                     } else {
263:                         $clientid = false;
264:                     }
265: 
266:                     // Create Message object from messages passed from PIM
267:                     if ($this->_decoder->getElementStartTag(Horde_ActiveSync::SYNC_DATA)) {
268:                         switch ($collection['class']) {
269:                         case 'Email':
270:                             //@TODO
271:                             //$appdata = new SyncMail();
272:                             //$appdata->decode($decoder);
273:                             // Remove error code when implemented.
274:                             $this->_statusCode = self::STATUS_SERVERERROR;
275:                             break;
276:                         case 'Contacts':
277:                             $appdata = new Horde_ActiveSync_Message_Contact(
278:                                 array('logger' => $this->_logger,
279:                                       'protocolversion' => $this->_version));
280:                             $appdata->decodeStream($this->_decoder);
281:                             break;
282:                         case 'Calendar':
283:                             $appdata = new Horde_ActiveSync_Message_Appointment(array('logger' => $this->_logger));
284:                             $appdata->decodeStream($this->_decoder);
285:                             break;
286:                         case 'Tasks':
287:                             $appdata = new Horde_ActiveSync_Message_Task(array('logger' => $this->_logger));
288:                             $appdata->decodeStream($this->_decoder);
289:                             break;
290:                         }
291:                         if (!$this->_decoder->getElementEndTag()) {
292:                             // End application data
293:                             $this->_statusCode = self::STATUS_PROTERROR;
294:                             break;
295:                         }
296:                     }
297: 
298:                     switch ($element[Horde_ActiveSync_Wbxml::EN_TAG]) {
299:                     case Horde_ActiveSync::SYNC_MODIFY:
300:                         if (isset($appdata)) {
301:                             // Currently, 'read' is only sent by the PDA when it
302:                             // is ONLY setting the read flag.
303:                             if (isset($appdata->read)) {
304:                                 $importer->importMessageReadFlag($serverid, $appdata->read);
305:                             } else {
306:                                 $importer->importMessageChange($serverid, $appdata, $this->_device, false);
307:                             }
308:                             $collection['importedchanges'] = true;
309:                         }
310:                         break;
311:                     case Horde_ActiveSync::SYNC_ADD:
312:                         if (isset($appdata)) {
313:                             $id = $importer->importMessageChange(false, $appdata, $this->_device, $clientid);
314:                             if ($clientid && $id) {
315:                                 $collection['clientids'][$clientid] = $id;
316:                                 $collection['importedchanges'] = true;
317:                             }
318:                         }
319:                         break;
320:                     case Horde_ActiveSync::SYNC_REMOVE:
321:                         if (isset($collection['deletesasmoves'])) {
322:                             $folderid = $this->_driver->getWasteBasket();
323:                             if ($folderid) {
324:                                 $importer->importMessageMove($serverid, $folderid);
325:                                 $collection['importedchanges'] = true;
326:                                 break;
327:                             }
328:                         }
329: 
330:                         $importer->importMessageDeletion($serverid);
331:                         $collection['importedchanges'] = true;
332:                         break;
333:                     case Horde_ActiveSync::SYNC_FETCH:
334:                         array_push($collection['fetchids'], $serverid);
335:                         break;
336:                     }
337: 
338:                     if (!$this->_decoder->getElementEndTag()) {
339:                         // end change/delete/move
340:                         $this->_statusCode = self::STATUS_PROTERROR;
341:                         $this->_handleError($collection);
342:                         exit;
343:                     }
344:                 }
345: 
346:                 $this->_logger->debug(sprintf('[%s] Processed %d incoming changes', $this->_device->id, $nchanges));
347: 
348:                 if (!$this->_decoder->getElementEndTag()) {
349:                     // end commands
350:                     $this->_statusCode = self::STATUS_PROTERROR;
351:                     $this->_handleError($collection);
352:                     exit;
353:                 }
354:             }
355: 
356:             if (!$this->_decoder->getElementEndTag()) {
357:                 // end collection
358:                 $this->_statusCode = self::STATUS_PROTERROR;
359:                 $this->_handleError($collection);
360:                 exit;
361:             }
362: 
363:             array_push($collections, $collection);
364:         }
365: 
366:         if (!$this->_decoder->getElementEndTag()) {
367:             // end collections
368:             return false;
369:         }
370: 
371:         if (!$this->_decoder->getElementEndTag()) {
372:             // end sync
373:             return false;
374:         }
375: 
376:         // Start output to PIM
377:         $this->_logger->info('[' . $this->_device->id . '] Beginning SYNC Response.');
378:         $this->_encoder->startWBXML();
379:         $this->_encoder->startTag(Horde_ActiveSync::SYNC_SYNCHRONIZE);
380:         $this->_encoder->startTag(Horde_ActiveSync::SYNC_FOLDERS);
381:         foreach ($collections as $collection) {
382:             $changecount = 0;
383:             if (isset($collection['getchanges'])) {
384:                 $filtertype = isset($collection['filtertype']) ? $collection['filtertype'] : false;
385:                 $exporter = new Horde_ActiveSync_Connector_Exporter($this->_encoder, $collection['class']);
386:                 $sync = $this->_driver->getSyncObject();
387:                 $sync->init($this->_state, $exporter, $collection);
388:                 $changecount = $sync->getChangeCount();
389:             }
390: 
391:             $counter = Horde_ActiveSync_State_Base::getSyncKeyCounter($collection['synckey']);
392:             // Get new synckey if needed
393:             if (isset($collection['importedchanges']) ||
394:                 $changecount > 0 ||
395:                 $collection['synckey'] == '0' ||
396:                 $counter == '1') {
397:                 try {
398:                     $this->_logger->debug('Generating new synckey. Old synckey: ' . $collection['synckey']);
399:                     $collection['newsynckey'] = $this->_state->getNewSyncKey($collection['synckey']);
400:                     $this->_logger->debug('New synckey generated: ' . $collection['newsynckey']);
401:                 } catch (Horde_ActiveSync_Exception $e) {
402:                     $this->_statusCode = self::STATUS_KEYMISM;
403:                 }
404:             }
405: 
406:             $this->_encoder->startTag(Horde_ActiveSync::SYNC_FOLDER);
407:             $this->_encoder->startTag(Horde_ActiveSync::SYNC_FOLDERTYPE);
408:             $this->_encoder->content($collection['class']);
409:             $this->_encoder->endTag();
410: 
411:             $this->_encoder->startTag(Horde_ActiveSync::SYNC_SYNCKEY);
412:             if (isset($collection['newsynckey'])) {
413:                 $this->_encoder->content($collection['newsynckey']);
414:             } else {
415:                 $this->_encoder->content($collection['synckey']);
416:             }
417:             $this->_encoder->endTag();
418: 
419:             $this->_encoder->startTag(Horde_ActiveSync::SYNC_FOLDERID);
420:             $this->_encoder->content($collection['id']);
421:             $this->_encoder->endTag();
422: 
423:             $this->_encoder->startTag(Horde_ActiveSync::SYNC_STATUS);
424:             $this->_encoder->content($this->_statusCode);
425:             $this->_encoder->endTag();
426: 
427:             // Check the mimesupport because we need it for advanced emails
428:             $mimesupport = isset($collection['mimesupport']) ? $collection['mimesupport'] : 0;
429: 
430:             // Output server IDs for new items we received and added from PIM
431:             if (isset($collection['clientids']) || count($collection['fetchids']) > 0) {
432:                 $this->_encoder->startTag(Horde_ActiveSync::SYNC_REPLIES);
433:                 foreach ($collection['clientids'] as $clientid => $serverid) {
434:                     $this->_encoder->startTag(Horde_ActiveSync::SYNC_ADD);
435:                     $this->_encoder->startTag(Horde_ActiveSync::SYNC_CLIENTENTRYID);
436:                     $this->_encoder->content($clientid);
437:                     $this->_encoder->endTag();
438:                     $this->_encoder->startTag(Horde_ActiveSync::SYNC_SERVERENTRYID);
439:                     $this->_encoder->content($serverid);
440:                     $this->_encoder->endTag();
441:                     $this->_encoder->startTag(Horde_ActiveSync::SYNC_STATUS);
442:                     $this->_encoder->content(1);
443:                     $this->_encoder->endTag();
444:                     $this->_encoder->endTag();
445:                 }
446: 
447:                 // Output any FETCH requests
448:                 foreach ($collection['fetchids'] as $id) {
449:                     $data = $this->_driver->fetch($collection['id'], $id, $mimesupport);
450:                     if ($data !== false) {
451:                         $this->_encoder->startTag(Horde_ActiveSync::SYNC_FETCH);
452:                         $this->_encoder->startTag(Horde_ActiveSync::SYNC_SERVERENTRYID);
453:                         $this->_encoder->content($id);
454:                         $this->_encoder->endTag();
455:                         $this->_encoder->startTag(Horde_ActiveSync::SYNC_STATUS);
456:                         $this->_encoder->content(1);
457:                         $this->_encoder->endTag();
458:                         $this->_encoder->startTag(Horde_ActiveSync::SYNC_DATA);
459:                         $data->encodeStream($this->_encoder);
460:                         $this->_encoder->endTag();
461:                         $this->_encoder->endTag();
462:                     } else {
463:                         $this->_logger->err(sprintf('[Horde_ActiveSync::handleSync] Unable to fetch %s', $id));
464:                     }
465:                 }
466:                 $this->_encoder->endTag();
467:             }
468: 
469:             // Send server changes to PIM
470:             if (isset($collection['getchanges'])) {
471:                 // Changecount and exporter initialized above
472:                 if (!empty($collection['windowsize']) && $changecount > $collection['windowsize']) {
473:                     $this->_encoder->startTag(Horde_ActiveSync::SYNC_MOREAVAILABLE, false, true);
474:                 }
475: 
476:                 // Output message changes per folder
477:                 $this->_encoder->startTag(Horde_ActiveSync::SYNC_COMMANDS);
478: 
479:                 // Stream the changes to the PDA
480:                 $n = 0;
481:                 while (1) {
482:                     $progress = $sync->syncronize();
483:                     if (!is_array($progress)) {
484:                         break;
485:                     }
486:                     $n++;
487: 
488:                     if (!empty($collection['windowsize']) && $n >= $collection['windowsize']) {
489:                         $this->_logger->info(sprintf('[%s] Exported maxItems of messages: %d - more available.', $this->_device->id, $collection['windowsize']));
490:                         break;
491:                     }
492:                 }
493:                 $this->_encoder->endTag();
494:             }
495: 
496:             $this->_encoder->endTag();
497: 
498:             // Save the sync state for the next time
499:             if (isset($collection['newsynckey'])) {
500:                 if (!empty($sync) || !empty($importer) || !empty($exporter) || $collection['synckey'] == 0)  {
501:                     $this->_state->setNewSyncKey($collection['newsynckey']);
502:                     $this->_state->save();
503:                 } else {
504:                     $this->_logger->err(sprintf('[%s] Error saving %s - no state information available.', $this->_device->id, $collection['newsynckey']));
505:                 }
506:             }
507:         }
508: 
509:         $this->_encoder->endTag();
510: 
511:         $this->_encoder->endTag();
512: 
513:         return true;
514:     }
515: 
516:     /**
517:      * Helper for handling sync errors
518:      *
519:      * @param <type> $collection
520:      */
521:     private function _handleError($collection)
522:     {
523:         $this->_encoder->startWBXML();
524:         $this->_encoder->startTag(Horde_ActiveSync::SYNC_SYNCHRONIZE);
525: 
526:         $this->_encoder->startTag(Horde_ActiveSync::SYNC_FOLDERS);
527: 
528:         // Get new synckey if needed
529:         if ($this->_statusCode == self::STATUS_KEYMISM ||
530:             isset($collection['importedchanges']) ||
531:             isset($collection['getchanges']) ||
532:             $collection['synckey'] == '0') {
533: 
534:             $collection['newsynckey'] = Horde_ActiveSync_State_Base::getNewSyncKey(($this->_statusCode == self::STATUS_KEYMISM) ? 0 : $collection['synckey']);
535:             if ($collection['synckey'] != 0) {
536:                 $this->_state->init($collection);
537:                 $this->_state->removeState($collection['synckey']);
538:             }
539:         }
540: 
541:         $this->_encoder->startTag(Horde_ActiveSync::SYNC_FOLDER);
542: 
543:         $this->_encoder->startTag(Horde_ActiveSync::SYNC_FOLDERTYPE);
544:         $this->_encoder->content($collection['class']);
545:         $this->_encoder->endTag();
546: 
547:         $this->_encoder->startTag(Horde_ActiveSync::SYNC_SYNCKEY);
548:         if (isset($collection['newsynckey'])) {
549:             $this->_encoder->content($collection['newsynckey']);
550:         } else {
551:             $this->_encoder->content($collection['synckey']);
552:         }
553:         $this->_encoder->endTag();
554: 
555:         $this->_encoder->startTag(Horde_ActiveSync::SYNC_FOLDERID);
556:         $this->_encoder->content($collection['id']);
557:         $this->_encoder->endTag();
558: 
559:         $this->_encoder->startTag(Horde_ActiveSync::SYNC_STATUS);
560:         $this->_encoder->content($this->_statusCode);
561:         $this->_encoder->endTag();
562: 
563:         $this->_encoder->endTag(); // Horde_ActiveSync::SYNC_FOLDER
564:         $this->_encoder->endTag();
565:         $this->_encoder->endTag();
566:     }
567: 
568: }
569: 
API documentation generated by ApiGen