Пример #1
0
 /**
  * Import a folder change from the wbxml stream
  *
  * @param string $uid          The folder uid
  * @param string $displayname  The folder display name
  * @param string $parent       The parent folder id.
  * @param integer $type        The EAS Folder type. @since 2.9.0
  *
  * @return Horde_ActiveSync_Message_Folder The new folder object.
  */
 public function importFolderChange($uid, $displayname, $parent = Horde_ActiveSync::FOLDER_ROOT, $type = null)
 {
     $this->_logger->info(sprintf('[%s] Horde_ActiveSync_Connector_Importer::importFolderChange(%s, %s, %s, %s)', $this->_procid, $uid, $displayname, $parent, $type));
     // Convert the uids to serverids.
     $collections = $this->_as->getCollectionsObject();
     $parent_sid = !empty($parent) ? $collections->getBackendIdForFolderUid($parent) : $parent;
     $folderid = !empty($uid) ? $collections->getBackendIdForFolderUid($uid) : false;
     // Perform the creation in the backend.
     try {
         $results = $this->_as->driver->changeFolder($folderid, $displayname, $parent_sid, $uid, $type);
     } catch (Horde_ActiveSync_Exception $e) {
         $this->_logger->err($e->getMessage());
         throw $e;
     }
     // @todo Horde 6 this should always return an object.
     if ($results instanceof Horde_ActiveSync_Message_Folder) {
         $folderid = $results->_serverid;
         $uid = $results->serverid;
     } else {
         // @TODO Remove for 3.0 Need to build a message folder object here
         // for BC reasons.
         $serverid = $results;
         $results = $this->_as->messageFactory('Folder');
         $results->serverid = $serverid;
         $results->_serverid = $folderid;
     }
     $change = array();
     $change['id'] = $uid;
     $change['folderid'] = $folderid;
     $change['mod'] = $displayname;
     $change['parent'] = $parent;
     $this->_state->updateState(Horde_ActiveSync::CHANGE_TYPE_CHANGE, $change, Horde_ActiveSync::CHANGE_ORIGIN_PIM);
     return $results;
 }
Пример #2
0
 /**
  * Get an activesync uid for the given backend serverid. If we've seen this
  * serverid before, return the previously created uid, otherwise return
  * a new one.
  *
  * @param string $id      The server's current folder name E.g., INBOX
  * @param string $type    The folder type, a Horde_ActiveSync::FOLDER_TYPE_*
  *                        constant. If empty, assumes FOLDER_TYPE_USER_MAIL
  * @param string $old_id  The previous folder name for this folder, if the
  *                        folder is being renamed. @since 2.15.0
  *                        @todo This is tempoarary until 3.0 (H6) when we
  *                        will have the collection manager take care of ALL
  *                        of the folder name <-> UID mapping management.
  *
  * @return string  A unique identifier for the specified backend folder id.
  *                 The first character indicates the foldertype as such:
  *                 'F' - Email
  *                 'C' - Contact
  *                 'A' - Appointment
  *                 'T' - Task
  *                 'N' - Note
  * @since 2.4.0
  */
 protected function _getFolderUidForBackendId($id, $type = null, $old_id = null)
 {
     // Always use 'RI' for Recipient cache.
     if ($id == 'RI') {
         return 'RI';
     }
     $map = $this->_state->getFolderUidToBackendIdMap();
     // Rename?
     if (!empty($old_id) && !empty($map[$old_id])) {
         $this->_tempMap[$id] = $map[$old_id];
     }
     if (!empty($map[$id])) {
         return $map[$id];
     } elseif (!empty($this->_tempMap[$id])) {
         return $this->_tempMap[$id];
     }
     // Convert TYPE to CLASS
     $type = $this->_getClassFromType($type);
     $rMap = array_flip($this->_typeMap);
     $prefix = $rMap[$type];
     // None found, generate a new UID.
     $this->_tempMap[$id] = sprintf('%s%04x%04x', $prefix, mt_rand(0, 0xffff), mt_rand(0, 0xffff));
     $this->_logger->info(sprintf('[%s] Creating new folder uuid for %s: %s', getmypid(), $id, $this->_tempMap[$id]));
     return $this->_tempMap[$id];
 }
Пример #3
0
 /**
  * Get all server changes for the specified collection
  *
  * @param string $collection  The collection type (a Horde interface name -
  *                            calendar, contacts, tasks)
  * @param integer $from_ts    Starting timestamp or modification sequence.
  * @param integer $to_ts      Ending timestamp or modification sequence.
  * @param string $server_id   The server id of the collection. If null, uses
  *                            multiplexed.
  *
  * @return array  A hash of add, modify, and delete uids
  * @throws InvalidArgumentException, Horde_Exception
  */
 public function getChanges($collection, $from_ts, $to_ts, $server_id)
 {
     if (!in_array($collection, array('calendar', 'contacts', 'tasks', 'notes'))) {
         throw new InvalidArgumentException('collection must be one of calendar, contacts, tasks or notes');
     }
     $app = $this->_registry->hasInterface($collection);
     if (!$app || $this->_registry->isInactive($app)) {
         throw new Horde_Exception(sprintf('The %s interface is not active in Horde.', $collection));
     }
     // We can use modification sequences.
     if ($this->hasFeature('modseq', $collection)) {
         $this->_logger->info(sprintf('[%s] Fetching changes for %s using MODSEQ.', getmypid(), $collection));
         try {
             return $this->_registry->{$collection}->getChangesByModSeq($from_ts, $to_ts, $server_id);
         } catch (Exception $e) {
             return array('add' => array(), 'modify' => array(), 'delete' => array());
         }
     }
     // Older API, use timestamps.
     $this->_logger->info(sprintf('[%s] Fetching changes for %s using TIMESTAMPS.', getmypid(), $collection));
     try {
         return $this->_registry->{$collection}->getChanges($from_ts, $to_ts, false, $server_id);
     } catch (Exception $e) {
         return array('add' => array(), 'modify' => array(), 'delete' => array());
     }
 }
Пример #4
0
 /**
  * Force reset all collection's PINGABLE flag. Used to force client
  * to issue a non-empty PING request.
  *
  */
 public function resetPingCache()
 {
     $collections = $this->_cache->getCollections(false);
     foreach ($collections as $id => $collection) {
         $this->_logger->info(sprintf('UNSETTING collection %s (%s) PINGABLE flag.', $collection['serverid'], $id));
         $this->_cache->removePingableCollection($id);
     }
 }
Пример #5
0
 protected function _buildBodyPart(Horde_ActiveSync_Imap_MessageBodyData $mbd, array $options, Horde_ActiveSync_Message_AirSyncBaseBodypart $message)
 {
     $this->_logger->info(sprintf('[%s] Preparing BODYPART data.', $this->_procid));
     $message->status = Horde_ActiveSync_Message_AirSyncBaseBodypart::STATUS_SUCCESS;
     if (!empty($options['bodypartprefs']['preview']) && $mbd->plain) {
         $mbd->plain['body']->rewind();
         $message->preview = $mbd->plain['body']->substring(0, $options['bodypartprefs']['preview']);
     }
     $message->data = $mbd->bodyPart['body']->stream;
     $message->truncated = $mbd->bodyPart['truncated'];
     return $message;
 }
Пример #6
0
 protected function _reorderChanges(array $ensure)
 {
     $changes = array();
     foreach ($this->_changes as $change) {
         if (array_search($change['id'], $ensure) !== false) {
             $this->_logger->info(sprintf('Placing %s at beginning of changes array.', $change['id']));
             array_unshift($changes, $change);
         } else {
             $changes[] = $change;
         }
     }
     return $changes;
 }
Пример #7
0
 /**
  * Opens a connection to the Kolab server.
  *
  * @param boolean $create_missing Create a preferences folder if it is
  *                                missing.
  *
  * @return Horde_Kolab_Storage_Data The storage backend.
  *
  * @throws Horde_Prefs_Exception
  */
 protected function _getStorage($create_missing = false)
 {
     $query = $this->_kolab->getList()->getQuery();
     if ($folder = $query->getDefault('h-prefs')) {
         return $this->_kolab->getData($folder);
     }
     $folders = $query->listByType('h-prefs');
     if (!empty($folders)) {
         return $this->_kolab->getData($folders[0]);
     }
     if (!$create_missing) {
         throw new Horde_Prefs_Exception('No Kolab storage backend available.');
     }
     $params = $this->getParams();
     $folder = $this->_kolab->getList()->getNamespace()->constructFolderName($params['user'], $this->_folder);
     $this->_kolab->getList()->getListManipulation()->createFolder($folder, 'h-prefs.default');
     if ($this->_logger !== null) {
         $this->_logger->info(sprintf(__CLASS__ . ': Created default Kolab preferences folder "%s".', $this->_folder));
     }
     return $this->_kolab->getData($folder);
 }
Пример #8
0
 /**
  * Builds a proper AS mail message object.
  *
  * @param Horde_Imap_Client_Mailbox    $mbox  The IMAP mailbox.
  * @param Horde_Imap_Client_Data_Fetch $data  The fetch results.
  * @param array $options                      Additional Options:
  *   - truncation:  (integer) Truncate the message body to this length.
  *                  DEFAULT: No truncation.
  *   - bodyprefs: (array)  Bodyprefs, if sent from device.
  *                DEFAULT: none (No body prefs sent or enforced).
  *   - mimesupport: (integer)  Indicates if MIME is supported or not.
  *                  Possible values: 0 - Not supported 1 - Only S/MIME or
  *                  2 - All MIME.
  *                  DEFAULT: 0 (No MIME support)
  *   - protocolversion: (float)  The EAS protocol version to support.
  *                      DEFAULT: 2.5
  *
  * @return Horde_ActiveSync_Message_Mail  The message object suitable for
  *                                        streaming to the device.
  */
 protected function _buildMailMessage(Horde_Imap_Client_Mailbox $mbox, Horde_Imap_Client_Data_Fetch $data, $options = array())
 {
     $imap = $this->_getImapOb();
     $version = empty($options['protocolversion']) ? Horde_ActiveSync::VERSION_TWOFIVE : $options['protocolversion'];
     $imap_message = new Horde_ActiveSync_Imap_Message($imap, $mbox, $data);
     $eas_message = Horde_ActiveSync::messageFactory('Mail');
     // Build To: data (POOMMAIL_TO has a max length of 1024).
     $to = $imap_message->getToAddresses();
     $eas_message->to = array_pop($to['to']);
     foreach ($to['to'] as $to_atom) {
         if (strlen($eas_message->to) + strlen($to_atom) > 1024) {
             break;
         }
         $eas_message->to .= ',' . $to_atom;
     }
     $eas_message->displayto = implode(';', $to['displayto']);
     if (empty($eas_message->displayto)) {
         $eas_message->displayto = $eas_message->to;
     }
     // Ensure we don't send broken UTF8 data to the client. It makes clients
     // angry. And we don't like angry clients.
     $hdr_charset = $imap_message->getStructure()->getHeaderCharset();
     // Fill in other header data
     $eas_message->from = $imap_message->getFromAddress();
     $eas_message->subject = Horde_ActiveSync_Utils::ensureUtf8($imap_message->getSubject(), $hdr_charset);
     $eas_message->threadtopic = $eas_message->subject;
     $eas_message->datereceived = $imap_message->getDate();
     $eas_message->read = $imap_message->getFlag(Horde_Imap_Client::FLAG_SEEN);
     $eas_message->cc = $imap_message->getCc();
     $eas_message->reply_to = $imap_message->getReplyTo();
     // Default to IPM.Note - may change below depending on message content.
     $eas_message->messageclass = 'IPM.Note';
     // Codepage id. MS recommends to always set to UTF-8 when possible.
     // See http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756%28v=vs.85%29.aspx
     $eas_message->cpid = Horde_ActiveSync_Message_Mail::INTERNET_CPID_UTF8;
     // Message importance. First try X-Priority, then Importance since
     // Outlook sends the later.
     if ($priority = $imap_message->getHeaders()->getValue('X-priority')) {
         $priorty = preg_replace('/\\D+/', '', $priority);
     } else {
         $priority = $imap_message->getHeaders()->getValue('Importance');
     }
     $eas_message->importance = $this->_getEASImportance($priority);
     // Get the body data and ensure we have something to send.
     $message_body_data = $this->_validateMessageBodyData($imap_message->getMessageBodyData($options));
     if ($version == Horde_ActiveSync::VERSION_TWOFIVE) {
         $eas_message->body = $message_body_data['plain']['body']->stream;
         $eas_message->bodysize = $message_body_data['plain']['body']->length(true);
         $eas_message->bodytruncated = $message_body_data['plain']['truncated'];
         $eas_message->attachments = $imap_message->getAttachments($version);
     } else {
         // Get the message body and determine original type.
         if (!empty($message_body_data['html'])) {
             $eas_message->airsyncbasenativebodytype = Horde_ActiveSync::BODYPREF_TYPE_HTML;
         } else {
             $eas_message->airsyncbasenativebodytype = Horde_ActiveSync::BODYPREF_TYPE_PLAIN;
         }
         $airsync_body = Horde_ActiveSync::messageFactory('AirSyncBaseBody');
         if (isset($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_MIME]) && ($options['mimesupport'] == Horde_ActiveSync::MIME_SUPPORT_ALL || $options['mimesupport'] == Horde_ActiveSync::MIME_SUPPORT_SMIME && $imap_message->isSigned())) {
             $this->_logger->info(sprintf('[%s] Sending MIME Message.', $this->_procid));
             // ActiveSync *REQUIRES* all data sent to be in UTF-8, so we
             // must convert the body parts to UTF-8. Unfortunately if the
             // email is signed (or encrypted for that matter) we can't
             // alter the data in anyway or the signature will not be
             // verified, so we fetch the entire message and hope for the best.
             if (!$imap_message->isSigned()) {
                 // Sending a non-signed MIME message, start building the
                 // UTF-8 converted structure.
                 $mime = new Horde_Mime_Part();
                 $mime->setType('multipart/alternative');
                 // Populate the text/plain part if we have one.
                 if (!empty($message_body_data['plain'])) {
                     $plain_mime = new Horde_Mime_Part();
                     $plain_mime->setType('text/plain');
                     $plain_mime->setContents($message_body_data['plain']['body']->stream, array('usestream' => true));
                     $plain_mime->setCharset('UTF-8');
                     $mime->addPart($plain_mime);
                 }
                 // Populate the text/html part if we have one.
                 if (!empty($message_body_data['html'])) {
                     $html_mime = new Horde_Mime_Part();
                     $html_mime->setType('text/html');
                     $html_mime->setContents($message_body_data['html']['body']->stream, array('usestream' => true));
                     $html_mime->setCharset('UTF-8');
                     $mime->addPart($html_mime);
                 }
                 // If we have attachments, create a multipart/mixed wrapper.
                 if ($imap_message->hasAttachments()) {
                     $base = new Horde_Mime_Part();
                     $base->setType('multipart/mixed');
                     $base->addPart($mime);
                     $atc = $imap_message->getAttachmentsMimeParts();
                     foreach ($atc as $atc_part) {
                         $base->addPart($atc_part);
                     }
                     $eas_message->airsyncbaseattachments = $imap_message->getAttachments($version);
                 } else {
                     $base = $mime;
                 }
                 // Populate the EAS body structure with the MIME data.
                 $airsync_body->data = $base->toString(array('headers' => $imap_message->getHeaders(), 'stream' => true));
                 $airsync_body->estimateddatasize = $base->getBytes();
             } else {
                 // Signed/Encrypted message - can't mess with it at all.
                 $raw = new Horde_ActiveSync_Rfc822($imap_message->getFullMsg(true), false);
                 $airsync_body->estimateddatasize = $raw->getBytes();
                 $airsync_body->data = $raw->getString();
                 $eas_message->messageclass = 'IPM.Note.SMIME.MultipartSigned';
                 // Might not know if we have attachments, but take a best
                 // guess.
                 $eas_message->airsyncbaseattachments = $imap_message->getAttachments($version);
             }
             // MIME Truncation
             $airsync_body->type = Horde_ActiveSync::BODYPREF_TYPE_MIME;
             $this->_logger->info(sprintf('[%s] Checking MIMETRUNCATION: %s, ServerData: %s', $this->_procid, $options['truncation'], $airsync_body->estimateddatasize));
             if (!empty($options['truncation']) && $airsync_body->estimateddatasize > $options['truncation']) {
                 ftruncate($airsync_body->data, $options['truncation']);
                 $airsync_body->truncated = '1';
             } else {
                 $airsync_body->truncated = '0';
             }
             $eas_message->airsyncbasebody = $airsync_body;
         } elseif (isset($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_HTML]) || isset($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_RTF])) {
             // Sending non MIME encoded HTML message text.
             $this->_logger->info(sprintf('[%s] Sending HTML Message.', $this->_procid));
             if (empty($message_body_data['html'])) {
                 $airsync_body->type = Horde_ActiveSync::BODYPREF_TYPE_PLAIN;
                 $message_body_data['html'] = array('body' => $message_body_data['plain']['body'], 'estimated_size' => $message_body_data['plain']['size'], 'truncated' => $message_body_data['plain']['truncated']);
             } else {
                 $airsync_body->type = Horde_ActiveSync::BODYPREF_TYPE_HTML;
             }
             if (!empty($message_body_data['html']['estimated_size'])) {
                 $airsync_body->estimateddatasize = $message_body_data['html']['estimated_size'];
                 $airsync_body->truncated = $message_body_data['html']['truncated'];
                 $airsync_body->data = $message_body_data['html']['body']->stream;
                 $eas_message->airsyncbasebody = $airsync_body;
             }
             $eas_message->airsyncbaseattachments = $imap_message->getAttachments($version);
         } elseif (isset($options['bodyprefs'][Horde_ActiveSync::BODYPREF_TYPE_PLAIN])) {
             // Non MIME encoded plaintext
             $this->_logger->info(sprintf('[%s] Sending PLAINTEXT Message.', $this->_procid));
             if (!empty($message_body_data['plain']['size'])) {
                 $airsync_body->estimateddatasize = $message_body_data['plain']['size'];
                 $airsync_body->truncated = $message_body_data['plain']['truncated'];
                 $airsync_body->data = $message_body_data['plain']['body']->stream;
                 $airsync_body->type = Horde_ActiveSync::BODYPREF_TYPE_PLAIN;
                 $eas_message->airsyncbasebody = $airsync_body;
             }
             $eas_message->airsyncbaseattachments = $imap_message->getAttachments($version);
         }
         if ($version > Horde_ActiveSync::VERSION_TWELVEONE) {
             $flags = array();
             $msgFlags = $this->_getMsgFlags();
             foreach ($imap_message->getFlags() as $flag) {
                 if (($key = array_search(strtolower($flag), array_map('strtolower', $msgFlags))) !== false) {
                     $flags[] = $msgFlags[$key];
                 }
             }
             $eas_message->categories = $flags;
         }
     }
     // Preview?
     if ($version >= Horde_ActiveSync::VERSION_FOURTEEN && !empty($options['bodyprefs']['preview'])) {
         $message_body_data['plain']['body']->rewind();
         $eas_message->airsyncbasebody->preview = $message_body_data['plain']['body']->substring(0, $options['bodyprefs']['preview']);
     }
     // Check for special message types.
     $part = $imap_message->getStructure();
     if ($part->getType() == 'multipart/report') {
         $ids = array_keys($imap_message->contentTypeMap());
         reset($ids);
         $part1_id = next($ids);
         $part2_id = Horde_Mime::mimeIdArithmetic($part1_id, 'next');
         $lines = explode(chr(13), $imap_message->getBodyPart($part2_id, array('decode' => true)));
         switch ($part->getContentTypeParameter('report-type')) {
             case 'delivery-status':
                 foreach ($lines as $line) {
                     if (strpos(trim($line), 'Action:') === 0) {
                         switch (trim(substr(trim($line), 7))) {
                             case 'failed':
                                 $eas_message->messageclass = 'REPORT.IPM.NOTE.NDR';
                                 break 2;
                             case 'delayed':
                                 $eas_message->messageclass = 'REPORT.IPM.NOTE.DELAYED';
                                 break 2;
                             case 'delivered':
                                 $eas_message->messageclass = 'REPORT.IPM.NOTE.DR';
                                 break 2;
                         }
                     }
                 }
                 break;
             case 'disposition-notification':
                 foreach ($lines as $line) {
                     if (strpos(trim($line), 'Disposition:') === 0) {
                         if (strpos($line, 'displayed') !== false) {
                             $eas_message->messageclass = 'REPORT.IPM.NOTE.IPNRN';
                         } elseif (strpos($line, 'deleted') !== false) {
                             $eas_message->messageclass = 'REPORT.IPM.NOTE.IPNNRN';
                         }
                         break;
                     }
                 }
         }
     }
     // Check for meeting requests and POOMMAIL_FLAG data
     if ($version >= Horde_ActiveSync::VERSION_TWELVE) {
         $eas_message->contentclass = 'urn:content-classes:message';
         if ($mime_part = $imap_message->hasiCalendar()) {
             $data = Horde_ActiveSync_Utils::ensureUtf8($mime_part->getContents(), $mime_part->getCharset());
             $vCal = new Horde_Icalendar();
             if ($vCal->parsevCalendar($data, 'VCALENDAR', $mime_part->getCharset())) {
                 try {
                     $method = $vCal->getAttribute('METHOD');
                     $eas_message->contentclass = 'urn:content-classes:calendarmessage';
                 } catch (Horde_Icalendar_Exception $e) {
                 }
                 switch ($method) {
                     case 'REQUEST':
                     case 'PUBLISH':
                         $eas_message->messageclass = 'IPM.Schedule.Meeting.Request';
                         $mtg = Horde_ActiveSync::messageFactory('MeetingRequest');
                         $mtg->fromvEvent($vCal);
                         $eas_message->meetingrequest = $mtg;
                         break;
                     case 'REPLY':
                         try {
                             $reply_status = $this->_getiTipStatus($vCal, $eas_message->from);
                             switch ($reply_status) {
                                 case 'ACCEPTED':
                                     $eas_message->messageclass = 'IPM.Schedule.Meeting.Resp.Pos';
                                     break;
                                 case 'DECLINED':
                                     $eas_message->messageclass = 'IPM.Schedule.Meeting.Resp.Neg';
                                     break;
                                 case 'TENTATIVE':
                                     $eas_message->messageclass = 'IPM.Schedule.Meeting.Resp.Tent';
                             }
                             $mtg = Horde_ActiveSync::messageFactory('MeetingRequest');
                             $mtg->fromvEvent($vCal);
                             $eas_message->meetingrequest = $mtg;
                         } catch (Horde_ActiveSync_Exception $e) {
                             $this->_logger->err($e->getMessage());
                         }
                 }
             }
         }
         if ($imap_message->getFlag(Horde_Imap_Client::FLAG_FLAGGED)) {
             $poommail_flag = Horde_ActiveSync::messageFactory('Flag');
             $poommail_flag->subject = $imap_message->getSubject();
             $poommail_flag->flagstatus = Horde_ActiveSync_Message_Flag::FLAG_STATUS_ACTIVE;
             $poommail_flag->flagtype = Horde_Imap_Client::FLAG_FLAGGED;
             $eas_message->flag = $poommail_flag;
         }
     }
     if ($version >= Horde_ActiveSync::VERSION_FOURTEEN) {
         $eas_message->messageid = $imap_message->getHeaders()->getValue('Message-ID');
         $eas_message->forwarded = $imap_message->getFlag(Horde_Imap_Client::FLAG_FORWARDED);
         $eas_message->answered = $imap_message->getFlag(Horde_Imap_Client::FLAG_ANSWERED);
     }
     return $eas_message;
 }
Пример #9
0
 /**
  * Log the message
  */
 protected function _logMessage()
 {
     $this->_logger->info("MAIL \n" . $this->_getFullMessage());
 }
Пример #10
0
 /**
  * Load and initialize the sync state
  *
  * @param array $collection  The collection array for the collection, if
  *                           a FOLDERSYNC, pass an empty array.
  * @param string $syncKey    The synckey of the state to load. If empty will
  *                           force a reset of the state for the class
  *                           specified in $id
  * @param string $type       The type of state a
  *                           Horde_ActiveSync::REQUEST_TYPE constant.
  * @param string $id         The folder id this state represents. If empty
  *                           assumed to be a foldersync state.
  *
  * @throws Horde_ActiveSync_Exception, Horde_ActiveSync_Exception_StateGone
  */
 public function loadState(array $collection, $syncKey, $type = null, $id = null)
 {
     // Initialize the local members.
     $this->_collection = $collection;
     $this->_changes = null;
     $this->_type = $type;
     // If this is a FOLDERSYNC, mock the device id.
     if ($type == Horde_ActiveSync::REQUEST_TYPE_FOLDERSYNC && empty($id)) {
         $id = Horde_ActiveSync::REQUEST_TYPE_FOLDERSYNC;
     }
     // synckey == 0 is an initial sync or reset.
     if (empty($syncKey)) {
         $this->_logger->notice(sprintf('[%s] %s::loadState: clearing folder state.', $this->_procid, __CLASS__));
         if ($type == Horde_ActiveSync::REQUEST_TYPE_FOLDERSYNC) {
             $this->_folder = array();
         } else {
             // Create a new folder object.
             $this->_folder = $this->_collection['class'] == Horde_ActiveSync::CLASS_EMAIL ? new Horde_ActiveSync_Folder_Imap($this->_collection['serverid'], Horde_ActiveSync::CLASS_EMAIL) : ($this->_collection['serverid'] == 'RI' ? new Horde_ActiveSync_Folder_RI('RI', 'RI') : new Horde_ActiveSync_Folder_Collection($this->_collection['serverid'], $this->_collection['class']));
         }
         $this->_syncKey = '0';
         $this->_resetDeviceState($id);
         return;
     }
     $this->_logger->info(sprintf('[%s] Loading state for synckey %s', $this->_procid, $syncKey));
     // Check if synckey is allowed
     if (!preg_match('/^\\{([0-9A-Za-z-]+)\\}([0-9]+)$/', $syncKey, $matches)) {
         throw new Horde_ActiveSync_Exception('Invalid sync key');
     }
     $this->_syncKey = $syncKey;
     // Cleanup older syncstates
     $this->_gc($syncKey);
     // Load the state
     $this->_loadState($type);
 }
Пример #11
0
 /**
  * The heart of the server. Dispatch a request to the appropriate request
  * handler.
  *
  * @param string $cmd    The command we are requesting.
  * @param string $devId  The device id making the request. @deprecated
  *
  * @return string|boolean  false if failed, true if succeeded and response
  *                         content is wbxml, otherwise the
  *                         content-type string to send in the response.
  * @throws Horde_ActiveSync_Exception
  * @throws Horde_ActiveSync_Exception_InvalidRequest
  * @throws Horde_ActiveSync_PermissionDenied
  */
 public function handleRequest($cmd, $devId)
 {
     $get = $this->getGetVars();
     if (empty($cmd)) {
         $cmd = $get['Cmd'];
     }
     if (empty($devId)) {
         $devId = !empty($get['DeviceId']) ? Horde_String::upper($get['DeviceId']) : null;
     } else {
         $devId = Horde_String::upper($devId);
     }
     $this->_setLogger($get);
     // @TODO: Remove is_callable check for H6.
     // Callback to give the backend the option to limit EAS version based
     // on user/device/etc...
     if (is_callable(array($this->_driver, 'versionCallback'))) {
         $this->_driver->versionCallback($this);
     }
     // Autodiscovery handles authentication on it's own.
     if ($cmd == 'Autodiscover') {
         $request = new Horde_ActiveSync_Request_Autodiscover($this, new Horde_ActiveSync_Device($this->_state));
         if (!empty(self::$_logger)) {
             $request->setLogger(self::$_logger);
         }
         $result = $request->handle($this->_request);
         $this->_driver->clearAuthentication();
         return $result;
     }
     if (!$this->authenticate(new Horde_ActiveSync_Credentials($this))) {
         $this->activeSyncHeader();
         $this->versionHeader();
         $this->commandsHeader();
         throw new Horde_Exception_AuthenticationFailure();
     }
     self::$_logger->info(sprintf('[%s] %s request received for user %s', $this->_procid, Horde_String::upper($cmd), $this->_driver->getUser()));
     // These are all handled in the same class.
     if ($cmd == 'FolderDelete' || $cmd == 'FolderUpdate') {
         $cmd = 'FolderCreate';
     }
     // Device id is REQUIRED
     if (empty($devId)) {
         if ($cmd == 'Options') {
             $this->_doOptionsRequest();
             $this->_driver->clearAuthentication();
             return true;
         }
         $this->_driver->clearAuthentication();
         throw new Horde_ActiveSync_Exception_InvalidRequest('Device failed to send device id.');
     }
     // EAS Version
     $version = $this->getProtocolVersion();
     // Device. Even though versions of EAS > 12.1 are supposed to send
     // EAS status codes back to indicate various errors in allowing a client
     // to connect, we just throw an exception (thus causing a HTTP error
     // code to be sent as in versions 12.1 and below). Until we refactor for
     // Horde 6, we don't know the response type to wrap the status code in
     // until we load the request handler, which requires we start to parse
     // the WBXML stream and device information etc... This saves resources
     // as well as keeps things cleaner until we refactor.
     $device_result = $this->_handleDevice($devId);
     // Don't bother with everything else if all we want are Options
     if ($cmd == 'Options') {
         $this->_doOptionsRequest();
         $this->_driver->clearAuthentication();
         return true;
     }
     // Set provisioning support now that we are authenticated.
     $this->setProvisioning($this->_driver->getProvisioning(self::$_device));
     // Read the initial Wbxml header
     $this->_decoder->readWbxmlHeader();
     // Support Multipart response for ITEMOPERATIONS requests?
     $headers = $this->_request->getHeaders();
     if (!empty($headers['ms-asacceptmultipart']) && $headers['ms-asacceptmultipart'] == 'T' || !empty($get['AcceptMultiPart'])) {
         $this->_multipart = true;
         self::$_logger->info(sprintf('[%s] Requesting multipart data.', $this->_procid));
     }
     // Load the request handler to handle the request
     // We must send the EAS header here, since some requests may start
     // output and be large enough to flush the buffer (e.g., GetAttachment)
     // See Bug: 12486
     $this->activeSyncHeader();
     if ($cmd != 'GetAttachment') {
         $this->contentTypeHeader();
     }
     // Should we announce a new version is available to the client?
     if (!empty($this->_needMsRp)) {
         self::$_logger->info(sprintf('[%s] Announcing X-MS-RP to client.', $this->_procid));
         header("X-MS-RP: " . $this->getSupportedVersions());
     }
     // @TODO: Look at getting rid of having to set the version in the driver
     //        and get it from the device object for H6.
     $this->_driver->setDevice(self::$_device);
     $class = 'Horde_ActiveSync_Request_' . basename($cmd);
     if (class_exists($class)) {
         $request = new $class($this);
         $request->setLogger(self::$_logger);
         $result = $request->handle();
         self::$_logger->info(sprintf('[%s] Maximum memory usage for ActiveSync request: %d bytes.', $this->_procid, memory_get_peak_usage(true)));
         return $result;
     }
     $this->_driver->clearAuthentication();
     throw new Horde_ActiveSync_Exception_InvalidRequest(basename($cmd) . ' not supported.');
 }
Пример #12
0
 /**
  * The heart of the server. Dispatch a request to the appropriate request
  * handler.
  *
  * @param string $cmd    The command we are requesting.
  * @param string $devId  The device id making the request. @deprecated
  *
  * @return string|boolean  false if failed, true if succeeded and response
  *                         content is wbxml, otherwise the
  *                         content-type string to send in the response.
  * @throws Horde_ActiveSync_Exception
  * @throws Horde_ActiveSync_Exception_InvalidRequest
  * @throws Horde_ActiveSync_PermissionDenied
  */
 public function handleRequest($cmd, $devId)
 {
     $get = $this->getGetVars();
     if (empty($cmd)) {
         $cmd = $get['Cmd'];
     }
     if (empty($devId)) {
         $devId = !empty($get['DeviceId']) ? Horde_String::upper($get['DeviceId']) : null;
     } else {
         $devId = Horde_String::upper($devId);
     }
     $this->_setLogger($get);
     // @TODO: Remove is_callable check for H6.
     // Callback to give the backend the option to limit EAS version based
     // on user/device/etc...
     if (is_callable(array($this->_driver, 'versionCallback'))) {
         $this->_driver->versionCallback($this);
     }
     // Autodiscovery handles authentication on it's own.
     if ($cmd == 'Autodiscover') {
         $request = new Horde_ActiveSync_Request_Autodiscover($this, new Horde_ActiveSync_Device($this->_state));
         if (!empty(self::$_logger)) {
             $request->setLogger(self::$_logger);
         }
         $result = $request->handle($this->_request);
         $this->_driver->clearAuthentication();
         return $result;
     }
     if (!$this->authenticate(new Horde_ActiveSync_Credentials($this))) {
         $this->activeSyncHeader();
         $this->versionHeader();
         $this->commandsHeader();
         throw new Horde_Exception_AuthenticationFailure();
     }
     self::$_logger->info(sprintf('[%s] %s request received for user %s', $this->_procid, Horde_String::upper($cmd), $this->_driver->getUser()));
     // These are all handled in the same class.
     if ($cmd == 'FolderDelete' || $cmd == 'FolderUpdate') {
         $cmd = 'FolderCreate';
     }
     // Device id is REQUIRED
     if (empty($devId)) {
         if ($cmd == 'Options') {
             $this->_doOptionsRequest();
             $this->_driver->clearAuthentication();
             return true;
         }
         $this->_driver->clearAuthentication();
         throw new Horde_ActiveSync_Exception_InvalidRequest('Device failed to send device id.');
     }
     // EAS Version
     $version = $this->getProtocolVersion();
     // Does device exist AND does the user have an account on the device?
     if (!$this->_state->deviceExists($devId, $this->_driver->getUser())) {
         // Device might exist, but with a new (additional) user account
         if ($this->_state->deviceExists($devId)) {
             self::$_device = $this->_state->loadDeviceInfo($devId);
         } else {
             self::$_device = new Horde_ActiveSync_Device($this->_state);
         }
         self::$_device->policykey = 0;
         self::$_device->userAgent = $this->_request->getHeader('User-Agent');
         self::$_device->deviceType = !empty($get['DeviceType']) ? $get['DeviceType'] : '';
         self::$_device->rwstatus = self::RWSTATUS_NA;
         self::$_device->user = $this->_driver->getUser();
         self::$_device->id = $devId;
         self::$_device->needsVersionUpdate($this->getSupportedVersions());
         self::$_device->version = $version;
         // @TODO: Remove is_callable check for H6.
         //        Combine this with the modifyDevice callback? Allow $device
         //        to be modified here?
         if (is_callable(array($this->_driver, 'createDeviceCallback'))) {
             $callback_ret = $this->_driver->createDeviceCallback(self::$_device);
             if ($callback_ret !== true) {
                 $msg = sprintf('The device %s was disallowed for user %s per policy settings.', self::$_device->id, self::$_device->user);
                 self::$_logger->err($msg);
                 if ($version > self::VERSION_TWELVEONE) {
                     $this->_globalError = $callback_ret;
                 } else {
                     throw new Horde_ActiveSync_Exception($msg);
                 }
             } else {
                 // Give the driver a chance to modify device properties.
                 if (is_callable(array($this->_driver, 'modifyDeviceCallback'))) {
                     self::$_device = $this->_driver->modifyDeviceCallback(self::$_device);
                 }
             }
         }
     } else {
         self::$_device = $this->_state->loadDeviceInfo($devId, $this->_driver->getUser());
         // If the device state was removed from storage, we may lose the
         // device properties, so try to repopulate what we can. userAgent
         // is ALWAYS available, so if it's missing, the state is gone.
         if (empty(self::$_device->userAgent)) {
             self::$_device->userAgent = $this->_request->getHeader('User-Agent');
             self::$_device->deviceType = !empty($get['DeviceType']) ? $get['DeviceType'] : '';
             self::$_device->user = $this->_driver->getUser();
         }
         if (empty(self::$_device->version)) {
             self::$_device->version = $version;
         }
         if (self::$_device->version < $this->_maxVersion && self::$_device->needsVersionUpdate($this->getSupportedVersions())) {
             $needMsRp = true;
         }
         // Give the driver a chance to modify device properties.
         if (is_callable(array($this->_driver, 'modifyDeviceCallback'))) {
             self::$_device = $this->_driver->modifyDeviceCallback(self::$_device);
         }
     }
     self::$_device->save();
     if (is_callable(array($this->_driver, 'deviceCallback'))) {
         $callback_ret = $this->_driver->deviceCallback(self::$_device);
         if ($callback_ret !== true) {
             $msg = sprintf('The device %s was disallowed for user %s per policy settings.', self::$_device->id, self::$_device->user);
             self::$_logger->err($msg);
             if ($version > self::VERSION_TWELVEONE) {
                 $this->_globalError = $callback_ret;
             } else {
                 throw new Horde_ActiveSync_Exception($msg);
             }
         }
     }
     // Lastly, check if the device has been set to blocked.
     if (self::$_device->blocked) {
         $msg = sprintf('The device %s was blocked.', self::$_device->id);
         self::$_logger->err($msg);
         if ($version > self::VERSION_TWELVEONE) {
             $this->_globalError = Horde_ActiveSync_Status::DEVICE_BLOCKED_FOR_USER;
         } else {
             throw new Horde_ActiveSync_Exception($msg);
         }
     }
     // Don't bother with everything else if all we want are Options
     if ($cmd == 'Options') {
         $this->_doOptionsRequest();
         $this->_driver->clearAuthentication();
         return true;
     }
     // Set provisioning support now that we are authenticated.
     $this->setProvisioning($this->_driver->getProvisioning(self::$_device));
     // Read the initial Wbxml header
     $this->_decoder->readWbxmlHeader();
     // Support Multipart response for ITEMOPERATIONS requests?
     $headers = $this->_request->getHeaders();
     if (!empty($headers['ms-asacceptmultipart']) && $headers['ms-asacceptmultipart'] == 'T' || !empty($get['AcceptMultiPart'])) {
         $this->_multipart = true;
         self::$_logger->info(sprintf('[%s] Requesting multipart data.', $this->_procid));
     }
     // Load the request handler to handle the request
     // We must send the eas header here, since some requests may start
     // output and be large enough to flush the buffer (e.g., GetAttachment)
     // See Bug: 12486
     $this->activeSyncHeader();
     if ($cmd != 'GetAttachment') {
         $this->contentTypeHeader();
     }
     // Should we announce a new version is available to the client?
     if (!empty($needMsRp)) {
         self::$_logger->info(sprintf('[%s] Announcing X-MS-RP to client.', $this->_procid));
         header("X-MS-RP: " . $this->getSupportedVersions());
     }
     // @TODO: Look at getting rid of having to set the version in the driver
     //        and get it from the device object for H6.
     $this->_driver->setDevice(self::$_device);
     $class = 'Horde_ActiveSync_Request_' . basename($cmd);
     if (class_exists($class)) {
         $request = new $class($this);
         $request->setLogger(self::$_logger);
         $result = $request->handle();
         self::$_logger->info(sprintf('[%s] Maximum memory usage for ActiveSync request: %d bytes.', $this->_procid, memory_get_peak_usage(true)));
         return $result;
     }
     $this->_driver->clearAuthentication();
     throw new Horde_ActiveSync_Exception_InvalidRequest(basename($cmd) . ' not supported.');
 }
Пример #13
0
 /**
  * @param   string  $text
  */
 public function log($text = '')
 {
     if ($this->_logger) {
         $this->_logger->info($text);
     }
 }
Пример #14
0
 /**
  * Encodes this object (and any sub-objects) as wbxml to the output stream.
  * Output is ordered according to $_mapping
  *
  * @param Horde_ActiveSync_Wbxml_Encoder $encoder  The wbxml stream encoder
  * @throws  Horde_ActiveSync_Exception
  */
 public function encodeStream(Horde_ActiveSync_Wbxml_Encoder &$encoder)
 {
     if (!$this->_preEncodeValidation()) {
         $this->_logger->err(sprintf('Pre-encoding validation failed for %s item', get_class($this)));
         throw new Horde_ActiveSync_Exception(sprintf('Pre-encoding validation failded for %s item', get_class($this)));
     }
     foreach ($this->_mapping as $tag => $map) {
         if (isset($this->{$map[self::KEY_ATTRIBUTE]})) {
             // Variable is available
             if (is_object($this->{$map[self::KEY_ATTRIBUTE]}) && !$this->{$map[self::KEY_ATTRIBUTE]} instanceof Horde_Date) {
                 // Objects can do their own encoding
                 $encoder->startTag($tag);
                 $this->{$map[self::KEY_ATTRIBUTE]}->encodeStream($encoder);
                 $encoder->endTag();
             } elseif (isset($map[self::KEY_VALUES]) && is_array($this->{$map[self::KEY_ATTRIBUTE]})) {
                 // Array of objects. Note that some array values must be
                 // send as an empty tag if they contain no elements.
                 if (count($this->{$map[self::KEY_ATTRIBUTE]})) {
                     if (!isset($map[self::KEY_PROPERTY]) || $map[self::KEY_PROPERTY] != self::PROPERTY_NO_CONTAINER) {
                         $encoder->startTag($tag);
                     }
                     foreach ($this->{$map[self::KEY_ATTRIBUTE]} as $element) {
                         if (is_object($element)) {
                             // Hanlde multi-typed array containers.
                             if (is_array($map[self::KEY_VALUES])) {
                                 $idx = array_search(get_class($element), $map[self::KEY_TYPE]);
                                 $tag = $map[self::KEY_VALUES][$idx];
                             } else {
                                 $tag = $map[self::KEY_VALUES];
                             }
                             // Outputs object container (eg Attachment)
                             $encoder->startTag($tag);
                             $element->encodeStream($encoder);
                             $encoder->endTag();
                         } else {
                             // Do not ever output empty items here
                             if (strlen($element) > 0) {
                                 $encoder->startTag($map[self::KEY_VALUES]);
                                 $encoder->content($element);
                                 $encoder->endTag();
                             }
                         }
                     }
                     if (!isset($map[self::KEY_PROPERTY]) || $map[self::KEY_PROPERTY] != self::PROPERTY_NO_CONTAINER) {
                         $encoder->endTag();
                     }
                 } elseif ($this->_checkSendEmpty($tag)) {
                     $encoder->startTag($tag, null, true);
                 }
             } else {
                 // Simple type
                 if (!is_resource($this->{$map[self::KEY_ATTRIBUTE]}) && strlen($this->{$map[self::KEY_ATTRIBUTE]}) == 0) {
                     // Do not output empty items except for the following:
                     if ($this->_checkSendEmpty($tag)) {
                         $encoder->startTag($tag, $this->{$map[self::KEY_ATTRIBUTE]}, true);
                     }
                     continue;
                 } elseif ($encoder->multipart && in_array($tag, array(Horde_ActiveSync::SYNC_DATA, Horde_ActiveSync::AIRSYNCBASE_DATA, Horde_ActiveSync_Request_ItemOperations::ITEMOPERATIONS_DATA))) {
                     $this->_logger->info('HANDLING MULTIPART OUTPUT');
                     $encoder->addPart($this->{$map[self::KEY_ATTRIBUTE]});
                     $encoder->startTag(Horde_ActiveSync_Request_ItemOperations::ITEMOPERATIONS_PART);
                     $encoder->content((string) (count($encoder->getParts()) - 1));
                     $encoder->endTag();
                     continue;
                 }
                 $encoder->startTag($tag);
                 if (isset($map[self::KEY_TYPE]) && in_array($map[self::KEY_TYPE], array(self::TYPE_DATE, self::TYPE_DATE_DASHES, self::TYPE_DATE_LOCAL))) {
                     if (!empty($this->{$map[self::KEY_ATTRIBUTE]})) {
                         // don't output 1-1-1970
                         $encoder->content($this->_formatDate($this->{$map[self::KEY_ATTRIBUTE]}, $map[self::KEY_TYPE]));
                     }
                 } elseif (isset($map[self::KEY_TYPE]) && $map[self::KEY_TYPE] == self::TYPE_HEX) {
                     $encoder->content(Horde_String::upper(bin2hex($this->{$map[self::KEY_ATTRIBUTE]})));
                 } elseif (isset($map[self::KEY_TYPE]) && $map[self::KEY_TYPE] == self::TYPE_MAPI_STREAM) {
                     $encoder->content($this->{$map[self::KEY_ATTRIBUTE]});
                 } else {
                     $encoder->content($this->_checkEncoding($this->{$map[self::KEY_ATTRIBUTE]}, $tag));
                 }
                 $encoder->endTag();
             }
         }
     }
 }
Пример #15
0
 /**
  * Clean up after initial pairing. Initial pairing can happen either as a
  * result of either a FOLDERSYNC or PROVISION command, depending on the
  * device capabilities.
  */
 protected function _cleanUpAfterPairing()
 {
     // Android sends a bogus device id of 'validate' during initial
     // handshake. This data is never used again, and the resulting
     // FOLDERSYNC response is ignored by the client. Remove the entry,
     // to avoid having 2 device entries for every android client.
     if ($this->_device->id == 'validate') {
         $this->_logger->info(sprintf('[%s] Removing state for bogus VALIDATE device.', $this->_procid));
         $this->_state->removeState(array('devId' => 'validate'));
     }
 }
Пример #16
0
 /**
  * Update a collection in the cache.
  *
  * @param array $collection  The collection data to add/update.
  * @param array $options     Options:
  *  - newsynckey: (boolean) Set the new synckey in the collection.
  *             DEFAULT: false (Do not set the new synckey).
  *  - unsetChanges: (boolean) Unset the GETCHANGES flag in the collection.
  *             DEFAULT: false (Do not unset the GETCHANGES flag).
  *  - unsetPingChangeFlag: (boolean) Unset the PINGCHANGES flag in the collection.
  *             DEFUALT: false (Do not uset the PINGCHANGES flag).
  *             @since 2.3.0
  */
 public function updateCollection(array $collection, array $options = array())
 {
     $options = array_merge(array('newsynckey' => false, 'unsetChanges' => false, 'unsetPingChangeFlag' => false), $options);
     if (!empty($collection['id'])) {
         if ($options['newsynckey']) {
             $this->_data['collections'][$collection['id']]['synckey'] = $collection['newsynckey'];
             $this->_markCollectionsDirty($collection['id']);
         } elseif (isset($collection['synckey'])) {
             $this->_data['collections'][$collection['id']]['synckey'] = $collection['synckey'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if (isset($collection['class'])) {
             $this->_data['collections'][$collection['id']]['class'] = $collection['class'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if (isset($collection['windowsize'])) {
             $this->_data['collections'][$collection['id']]['windowsize'] = $collection['windowsize'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if (isset($collection['deletesasmoves'])) {
             $this->_data['collections'][$collection['id']]['deletesasmoves'] = $collection['deletesasmoves'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if (isset($collection['filtertype'])) {
             $this->_data['collections'][$collection['id']]['filtertype'] = $collection['filtertype'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if (isset($collection['truncation'])) {
             $this->_data['collections'][$collection['id']]['truncation'] = $collection['truncation'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if (isset($collection['rtftruncation'])) {
             $this->_data['collections'][$collection['id']]['rtftruncation'] = $collection['rtftruncation'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if (isset($collection['mimesupport'])) {
             $this->_data['collections'][$collection['id']]['mimesupport'] = $collection['mimesupport'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if (isset($collection['mimetruncation'])) {
             $this->_data['collections'][$collection['id']]['mimetruncation'] = $collection['mimetruncation'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if (isset($collection['conflict'])) {
             $this->_data['collections'][$collection['id']]['conflict'] = $collection['conflict'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if (isset($collection['bodyprefs'])) {
             $this->_data['collections'][$collection['id']]['bodyprefs'] = $collection['bodyprefs'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if (isset($collection['bodypartprefs'])) {
             $this->_data['collections'][$collection['id']]['bodypartprefs'] = $collection['bodypartprefs'];
         }
         if (isset($collection['pingable'])) {
             $this->_data['collections'][$collection['id']]['pingable'] = $collection['pingable'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if (isset($collection['serverid'])) {
             $this->_data['collections'][$collection['id']]['serverid'] = $collection['serverid'];
             $this->_markCollectionsDirty($collection['id']);
         }
         if ($options['unsetChanges']) {
             unset($this->_data['collections'][$collection['id']]['getchanges']);
             $this->_markCollectionsDirty($collection['id']);
         }
         if ($options['unsetPingChangeFlag']) {
             unset($this->_data['collections'][$collection['id']]['pingchange']);
             $this->_markCollectionsDirty($collection['id']);
         }
     } else {
         $this->_logger->info(sprintf('[%s] Collection without id found: %s', $this->_procid, serialize($collection)));
     }
 }
Пример #17
0
 /**
  * Encodes this object (and any sub-objects) as wbxml to the output stream.
  * Output is ordered according to $_mapping
  *
  * @param Horde_ActiveSync_Wbxml_Encoder $encoder  The wbxml stream encoder
  */
 public function encodeStream(Horde_ActiveSync_Wbxml_Encoder &$encoder)
 {
     foreach ($this->_mapping as $tag => $map) {
         if (isset($this->{$map}[self::KEY_ATTRIBUTE])) {
             // Variable is available
             if (is_object($this->{$map}[self::KEY_ATTRIBUTE]) && !$this->{$map}[self::KEY_ATTRIBUTE] instanceof Horde_Date) {
                 // Subobjects can do their own encoding
                 $encoder->startTag($tag);
                 $this->{$map}[self::KEY_ATTRIBUTE]->encodeStream($encoder);
                 $encoder->endTag();
             } elseif (isset($map[self::KEY_VALUES]) && is_array($this->{$map}[self::KEY_ATTRIBUTE])) {
                 // Array of objects. Note that some array values must be
                 // send as an empty tag if they contain no elements.
                 if (count($this->{$map}[self::KEY_ATTRIBUTE])) {
                     $encoder->startTag($tag);
                     foreach ($this->{$map}[self::KEY_ATTRIBUTE] as $element) {
                         if (is_object($element)) {
                             // Outputs object container (eg Attachment)
                             $encoder->startTag($map[self::KEY_VALUES]);
                             $element->encodeStream($encoder);
                             $encoder->endTag();
                         } else {
                             // Do not ever output empty items here
                             if (strlen($element) > 0) {
                                 $encoder->startTag($map[self::KEY_VALUES]);
                                 $encoder->content($element);
                                 $encoder->endTag();
                             }
                         }
                     }
                     $encoder->endTag();
                 } elseif ($this->_checkSendEmpty($tag)) {
                     $encoder->startTag($tag, null, true);
                 }
             } else {
                 // Simple type
                 if (!is_resource($this->{$map}[self::KEY_ATTRIBUTE]) && strlen($this->{$map}[self::KEY_ATTRIBUTE]) == 0) {
                     // Do not output empty items except for the following:
                     if ($this->_checkSendEmpty($tag)) {
                         $encoder->startTag($tag, $this->{$map}[self::KEY_ATTRIBUTE], true);
                     }
                     continue;
                 } elseif ($encoder->multipart && in_array($tag, array(Horde_ActiveSync::SYNC_DATA, Horde_ActiveSync::AIRSYNCBASE_DATA, Horde_ActiveSync_Request_ItemOperations::ITEMOPERATIONS_DATA))) {
                     $this->_logger->info('HANDLING MULTIPART OUTPUT');
                     $encoder->addPart($this->{$map}[self::KEY_ATTRIBUTE]);
                     $encoder->startTag(Horde_ActiveSync_Request_ItemOperations::ITEMOPERATIONS_PART);
                     $encoder->content((string) (count($encoder->getParts()) - 1));
                     $encoder->endTag();
                     continue;
                 }
                 $encoder->startTag($tag);
                 if (isset($map[self::KEY_TYPE]) && ($map[self::KEY_TYPE] == self::TYPE_DATE || $map[self::KEY_TYPE] == self::TYPE_DATE_DASHES)) {
                     if (!empty($this->{$map}[self::KEY_ATTRIBUTE])) {
                         // don't output 1-1-1970
                         $encoder->content($this->_formatDate($this->{$map}[self::KEY_ATTRIBUTE], $map[self::KEY_TYPE]));
                     }
                 } elseif (isset($map[self::KEY_TYPE]) && $map[self::KEY_TYPE] == self::TYPE_HEX) {
                     $encoder->content(Horde_String::upper(bin2hex($this->{$map}[self::KEY_ATTRIBUTE])));
                 } elseif (isset($map[self::KEY_TYPE]) && $map[self::KEY_TYPE] == self::TYPE_MAPI_STREAM) {
                     $encoder->content($this->{$map}[self::KEY_ATTRIBUTE]);
                 } else {
                     $encoder->content($this->_checkEncoding($this->{$map}[self::KEY_ATTRIBUTE], $tag));
                 }
                 $encoder->endTag();
             }
         }
     }
 }