[ Index ]
 

Code source de Horde 3.1.3

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/lib/SyncML/ -> Sync.php (source)

   1  <?php
   2  /**
   3   * $Horde: framework/SyncML/SyncML/Sync.php,v 1.8.4.9 2006/05/01 12:05:14 jan Exp $
   4   *
   5   * Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
   6   *
   7   * See the enclosed file COPYING for license information (LGPL). If you
   8   * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
   9   *
  10   * @author  Anthony Mills <amills@pyramid6.com>
  11   * @since   Horde 3.0
  12   * @package SyncML
  13   */
  14  class SyncML_Sync {
  15  
  16      /**
  17       * Target: contacts, notes, calendar, tasks,
  18       */
  19      var $_targetLocURI; // target means server here
  20  
  21      var $_sourceLocURI; // source means client here
  22  
  23      var $_alert;
  24  
  25      /**
  26       * True indicates that there are still sync elements that have not been
  27       * sent yet due to message size limitations and have to be sent in the next
  28       * message.
  29       *
  30       * @var boolean
  31       */
  32      var $_pendingElements;
  33  
  34      /**
  35       * Remember entries we have handled already: once we send a delete for an
  36       * entry, we don't want to send an add afterwards. This array is also used
  37       * if a sync is sent in multiple messages due to message size restrictions.
  38       *
  39       * @var array
  40       */
  41      var $_done;
  42  
  43      function SyncML_Sync($alert, $serverURI, $clientURI)
  44      {
  45          $this->_alert = $alert;
  46          $this->_pendingElements = false;
  47          $this->_done = array();
  48          $this->_targetLocURI = basename($serverURI);
  49          $this->_sourceLocURI = $clientURI;
  50          global $backend;
  51          $backend->logMessage("create for syncType=$serverURI", __FILE__, __LINE__, PEAR_LOG_DEBUG);
  52      }
  53  
  54      /**
  55       * Here's where the actual processing of a client-sent Sync
  56       * Item takes place. Entries are added, deleted or replaced
  57       * from the server database by using Horde API (Registry) calls.
  58       */
  59      function handleSyncItem($item)
  60      {
  61          global $backend;
  62  
  63          $state = &$_SESSION['SyncML.state'];
  64          $device = &$state->getDevice();
  65          $syncIdentifier = $state->getSyncIdentifier();
  66  
  67          $hordeType = $type = $this->_targetLocURI;
  68  
  69          // Use contentType explicitly specified in this sync command.
  70          $contentType = $item->getContentType();
  71  
  72          // If not provided, use default from device info.
  73          if (!$contentType) {
  74              $contentType = $device->getPreferredContentType($type);
  75          }
  76  
  77          list($content, $contentType) =
  78              $device->convertClient2Server($item->getContent(),
  79                                            $contentType);
  80          $cuid = $item->getCuid();
  81          $suid = false;
  82  
  83          // Handle client add requests.
  84          if ($item->getElementType() =='Add') {
  85              $suid = $backend->importEntry($syncIdentifier, $hordeType,
  86                                            $content, $contentType, $cuid);
  87              if (!is_a($suid, 'PEAR_Error')) {
  88                  $state->log("Client-Add");
  89                  $backend->logMessage('added client entry as ' . $suid,
  90                                       __FILE__, __LINE__, PEAR_LOG_DEBUG);
  91              } else {
  92                  $state->log("Client-AddFailure");
  93                  $backend->logMessage('Error in adding client entry:' . $suid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
  94              }
  95  
  96          // Handle client delete requests.
  97          } elseif ($item->getElementType() =='Delete') {
  98              $suid = $backend->deleteEntry($syncIdentifier, $type, $cuid);
  99              if ($type == 'calendar'
 100                  && $device->handleTasksInCalendar()) {
 101                  // deleteEntry does not need to return an error on
 102                  // deletion of nonexistent entries. So just to be sure
 103                  // we have to delete from the tasks database as well:
 104                  $backend->logMessage('special tasks delete ' . $suid . ' due to client request', __FILE__, __LINE__, PEAR_LOG_DEBUG);
 105                  $suid = $backend->deleteEntry($syncIdentifier, 'tasks', $cuid);
 106              }
 107              if (!is_a($suid, 'PEAR_Error')) {
 108                  $state->log("Client-Delete");
 109                  $backend->logMessage('deleted entry ' . $suid . ' due to client request', __FILE__, __LINE__, PEAR_LOG_DEBUG);
 110              } else {
 111                  $state->log("Client-DeleteFailure");
 112                  $this->logMessage('Failure deleting client entry, maybe gone already on server. msg:'. $suid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
 113              }
 114  
 115          // Handle client replace requests.
 116          } elseif ($item->getElementType() == 'Replace') {
 117              $suid = $backend->replaceEntry($syncIdentifier, $hordeType,
 118                                             $content, $contentType, $cuid);
 119  
 120              if (!is_a($suid, 'PEAR_Error')) {
 121                  $state->log("Client-Replace");
 122                  $backend->logMessage('replaced entry ' . $suid . ' due to client request', __FILE__, __LINE__, PEAR_LOG_DEBUG);
 123              } else {
 124                  $backend->logMessage($suid->message, __FILE__, __LINE__, PEAR_LOG_DEBUG);
 125                  $backend->logMessage($suid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
 126  
 127                  // Entry may have been deleted; try adding it.
 128                  $suid = $backend->importEntry($syncIdentifier, $hordeType,
 129                                                $content, $contentType, $cuid);
 130                  if (!is_a($suid, 'PEAR_Error')) {
 131                      $state->log("Client-AddReplace");
 132                      $backend->logMessage('added client entry due to replace request as ' . $suid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
 133                  } else {
 134                      $state->log("Client-AddFailure");
 135                      $backend->logMessage('Error in adding client entry due to replace request:' . $suid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
 136                  }
 137              }
 138          } else {
 139              $backend->logMessage('Unexpected elementType: ' . $item->getElementType(),
 140                                   __FILE__, __LINE__, PEAR_LOG_ERR);
 141          }
 142  
 143          return $suid;
 144      }
 145  
 146      /**
 147       * Creates a &lt;Sync&gt; output.
 148       */
 149      function createSyncOutput($currentCmdID, &$output)
 150      {
 151          $state = &$_SESSION['SyncML.state'];
 152          $attrs = array();
 153  
 154          $output->startElement($state->getURI(), 'Sync', $attrs);
 155          $output->startElement($state->getURI(), 'CmdID', $attrs);
 156          $output->characters($currentCmdID);
 157          $currentCmdID++;
 158          $output->endElement($state->getURI(), 'CmdID');
 159  
 160          $output->startElement($state->getURI(), 'Target', $attrs);
 161          $output->startElement($state->getURI(), 'LocURI', $attrs);
 162          $output->characters($this->_sourceLocURI);
 163          $output->endElement($state->getURI(), 'LocURI');
 164          $output->endElement($state->getURI(), 'Target');
 165  
 166          $output->startElement($state->getURI(), 'Source', $attrs);
 167          $output->startElement($state->getURI(), 'LocURI', $attrs);
 168          $output->characters($this->_targetLocURI);
 169          $output->endElement($state->getURI(), 'LocURI');
 170          $output->endElement($state->getURI(), 'Source');
 171  
 172          $syncType = $this->_targetLocURI;
 173  
 174          global $backend;
 175          $backend->logMessage("handleSync for syncType=$syncType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
 176  
 177          // Here's where server modifications are sent to the client:
 178          $refts = $state->getServerAnchorLast($syncType);
 179          $currentCmdID = $this->handleSync($currentCmdID, $syncType,
 180                                            $output, $refts);
 181  
 182          $output->endElement($state->getURI(), 'Sync');
 183  
 184          return $currentCmdID;
 185      }
 186  
 187      /**
 188       * Sends server changes to the client.
 189       */
 190      function handleSync($currentCmdID, $syncType, &$output, $refts, $end_ts = 0)
 191      {
 192          global $backend;
 193          global $messageFull;
 194  
 195          /* $messageFull will be set to true to indicate that there's no room
 196           * for other data in this message. If it's false (empty) and there
 197           * are pending Sync data, the final command will sent the pending data.
 198           * This global data should be moved to a global object, together
 199           * with currentCmdID and $output. */
 200          $messageFull = false;
 201  
 202          $state = &$_SESSION['SyncML.state'];
 203          $device = &$state->getDevice();
 204          $syncIdentifier = $state->getSyncIdentifier();
 205          $contentType = $device->getPreferredContentTypeClient($syncType, $this->_sourceLocURI);
 206  
 207          /* We faithfully expect to deal with all remaining elements. Will be
 208           * set to true if we run out of space for message creation. */
 209          $this->setPendingElements(false);
 210  
 211          // Handle deletions.
 212          $deletions = $backend->getServerDeletions($syncIdentifier, $syncType, $refts, $end_ts);
 213  
 214          if ($refts > 0) {
 215              // Don't send deletes on SlowSync.
 216              foreach ($deletions as $suid => $cuid) {
 217                  $this->_done[$suid] = true;
 218                  $backend->logMessage("delete: cuid=$cuid suid=$suid refts: $refts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
 219                  // Create a Delete request for client.
 220                  $currentCmdID = $this->outputCommand($currentCmdID, $output, 'Delete',
 221                                                       null, null, $cuid, null);
 222                  $state->log('Server-Delete');
 223              }
 224          }
 225          // Handle additions.
 226          $adds = $backend->getServerAdditions($syncIdentifier, $syncType, $refts, $end_ts);
 227          foreach ($adds as $suid => $cuid) {
 228              if (!empty($this->_done[$suid])) {
 229                  // Already sent delete, no need to add.
 230                  continue;
 231              }
 232              $backend->logMessage("add: $suid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
 233  
 234              $c = $backend->retrieveEntry($syncType, $suid, $contentType);
 235              if (!is_a($c, 'PEAR_Error')) {
 236                  // Item in history but not in database. Strange, but can happen.
 237                  list($clientContent, $clientContentType) =
 238                      $device->convertServer2Client($c, $contentType);
 239                  // Check if we have space left in the message.
 240                  if (($state->getMaxMsgSize()
 241                      - $output->getOutputSize()
 242                      - strlen($clientContent)) < 50) {
 243                      $backend->logMessage('max message size reached cursize='
 244                                           . $output->getOutputSize(),
 245                                           __FILE__, __LINE__, PEAR_LOG_DEBUG);
 246                      $messageFull = true;
 247                      $this->setPendingElements(true);
 248                      return $currentCmdID;
 249                  }
 250                  $this->_done[$suid] = true;
 251                  $currentCmdID = $this->outputCommand($currentCmdID, $output,
 252                                                       'Add',
 253                                                       $clientContent,
 254                                                       $clientContentType,
 255                                                       null,
 256                                                       $suid);
 257                  $state->log('Server-Add');
 258              } else {
 259                  $backend->logMessage('api export call for ' . $suid . ' failed:  ' . $c->getMessage(),
 260                                       __FILE__, __LINE__, PEAR_LOG_DEBUG);
 261              }
 262          }
 263  
 264          // Handle changes.
 265          if ($refts != 0) {
 266              // Don't send changes for SlowSync, confuses some clients.
 267              $end_ts = time();
 268              $changes = $backend->getServerModifications($syncIdentifier,
 269                                                          $syncType,
 270                                                          $refts, $end_ts);
 271              if (is_a($changes, 'PEAR_Error')) {
 272                  $backend->logMessage($changes, __FILE__, __LINE__, PEAR_LOG_ERR);
 273                  return $changes;
 274              }
 275  
 276              foreach ($changes as $suid => $cuid) {
 277                  if (!empty($this->_done[$suid])) {
 278                      // Already sent delete or add, no need to modify.
 279                      continue;
 280                  }
 281  
 282                  if (!$cuid) {
 283                      // TODO: create an "add" here instead?
 284                      continue;
 285                  }
 286  
 287                  $c = $backend->retrieveEntry($syncType, $suid, $contentType);
 288                  if (!is_a($c, 'PEAR_Error')) {
 289                      $backend->logMessage("change: $suid",
 290                                           __FILE__, __LINE__, PEAR_LOG_DEBUG);
 291                      list($clientContent, $clientContentType) =
 292                          $device->convertServer2Client($c, $contentType);
 293                      // Check if we have space left in the message.
 294                      if (($state->getMaxMsgSize()
 295                           - $output->getOutputSize()
 296                           - strlen($clientContent)) < 50) {
 297                          $backend->logMessage('max message size reached cursize='
 298                                               . $output->getOutputSize(),
 299                                               __FILE__, __LINE__, PEAR_LOG_DEBUG);
 300                          $messageFull = true;
 301                          $this->setPendingElements(true);
 302                          return $currentCmdID;
 303                      }
 304                      $this->_done[$suid] = true;
 305                      $currentCmdID = $this->outputCommand($currentCmdID, $output,
 306                                                           'Replace',
 307                                                           $clientContent,
 308                                                           $clientContentType,
 309                                                           $cuid,
 310                                                           null);
 311                      $state->log('Server-Replace');
 312                  } else {
 313                      // Item in history but not in database. Strange, but
 314                      // can happen.
 315                  }
 316              }
 317          }
 318  
 319          // If tasks are handled inside calendar, do the same again for
 320          // tasks.
 321          if ($syncType == 'calendar' && $device->handleTasksInCalendar()) {
 322              $backend->logMessage("handling tasks in calendar sync",
 323                                   __FILE__, __LINE__, PEAR_LOG_DEBUG);
 324  
 325              $currentCmdID = $this->handleSync($currentCmdID, 'tasks',
 326                                                $output, $refts, $end_ts);
 327          }
 328  
 329          return $currentCmdID;
 330      }
 331  
 332      /**
 333       * Output a single Sync command (Add, Delete, Replace).
 334       */
 335      function outputCommand($currentCmdID, &$output, $command,
 336                             $content, $contentType = null,
 337                             $cuid = null, $suid = null)
 338      {
 339          $state = &$_SESSION['SyncML.state'];
 340  
 341          $attrs = array();
 342          $output->startElement($state->getURI(), $command, $attrs);
 343  
 344          $output->startElement($state->getURI(), 'CmdID', $attrs);
 345          $chars = $currentCmdID;
 346          $output->characters($chars);
 347          $output->endElement($state->getURI(), 'CmdID');
 348  
 349          if (isset($contentType)) {
 350              $output->startElement($state->getURI(), 'Meta', $attrs);
 351              $output->startElement($state->getURIMeta(), 'Type', $attrs);
 352              $output->characters($contentType);
 353              $output->endElement($state->getURIMeta(), 'Type');
 354              $output->endElement($state->getURI(), 'Meta');
 355          }
 356  
 357          if (isset($content)
 358              || isset($cuid) || isset($suid)) {
 359              $output->startElement($state->getURI(), 'Item', $attrs);
 360              if ($suid != null) {
 361                  $output->startElement($state->getURI(), 'Source', $attrs);
 362                  $output->startElement($state->getURI(), 'LocURI', $attrs);
 363                  $output->characters($suid);
 364                  $output->endElement($state->getURI(), 'LocURI');
 365                  $output->endElement($state->getURI(), 'Source');
 366              }
 367  
 368              if ($cuid != null) {
 369                  $output->startElement($state->getURI(), 'Target', $attrs);
 370                  $output->startElement($state->getURI(), 'LocURI', $attrs);
 371                  $output->characters($cuid);
 372                  $output->endElement($state->getURI(), 'LocURI');
 373                  $output->endElement($state->getURI(), 'Target');
 374              }
 375              if (isset($content)) {
 376                  $output->startElement($state->getURI(), 'Data', $attrs);
 377                  $output->characters($content);
 378                  $output->endElement($state->getURI(), 'Data');
 379              }
 380              $output->endElement($state->getURI(), 'Item');
 381          }
 382  
 383          $output->endElement($state->getURI(), $command);
 384  
 385          $currentCmdID++;
 386  
 387          return $currentCmdID;
 388      }
 389  
 390      function setPendingElements($e)
 391      {
 392          $this->_pendingElements = $e;
 393      }
 394  
 395      function hasPendingElements()
 396      {
 397          return $this->_pendingElements;
 398      }
 399  
 400  }


Généré le : Sun Feb 25 18:01:28 2007 par Balluche grâce à PHPXref 0.7