Пример #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
 protected function _logError($error, $name, $runtime = null)
 {
     if ($this->_logger) {
         $name = (empty($name) ? '' : $name) . (empty($runtime) ? '' : sprintf(" (%.4fs)", $runtime));
         $this->_logger->err($this->_formatLogEntry($name, $error));
     }
 }
Пример #3
0
 /**
  * Import an event response into a user's calendar. Used for updating
  * attendee information from a meeting response.
  *
  * @param Horde_Icalendar_vEvent $vEvent  The event data.
  * @param string $attendee                The attendee.
  */
 public function calendar_import_attendee(Horde_Icalendar_vEvent $vEvent, $attendee)
 {
     if ($this->_registry->hasMethod('calendar/updateAttendee')) {
         // If the mail interface (i.e., IMP) provides a mime driver for
         // iTips, check if we are allowed to autoupdate. If we have no
         // configuration, err on the side of caution and DO NOT auto import.
         $config = $GLOBALS['injector']->getInstance('Horde_Core_Factory_MimeViewer')->getViewerConfig('text/calendar', $this->_registry->hasInterface('mail'));
         if ($config[1]['driver'] == 'Itip' && !empty($config[1]['auto_update_eventreply'])) {
             if (is_array($config[1]['auto_update_eventreply'])) {
                 $adr = new Horde_Mail_Rfc822_Address($attendee);
                 $have_match = false;
                 foreach ($config[1]['auto_update_eventreply'] as $val) {
                     if ($adr->matchDomain($val)) {
                         $have_match = true;
                         break;
                     }
                 }
                 if (!$have_match) {
                     return;
                 }
             }
             try {
                 $this->_registry->calendar->updateAttendee($vEvent, $attendee);
             } catch (Horde_Exception $e) {
                 $this->_logger->err($e->getMessage());
             }
         }
     }
 }
Пример #4
0
 /**
  *
  * @param Horde_Imap_Client_Mailbox $mbox   The mailbox
  * @param array $uids                       An array of message uids
  * @param array $options                    An options array
  *   - headers: (boolean)  Fetch header text if true.
  *              DEFAULT: false (Do not fetch header text).
  *   - structure: (boolean) Fetch message structure.
  *            DEFAULT: true (Fetch message structure).
  *   - flags: (boolean) Fetch messagge flags.
  *            DEFAULT: true (Fetch message flags).
  *   - envelope: (boolen) Fetch the envelope data.
  *               DEFAULT: false (Do not fetch envelope). @since 2.4.0
  *
  * @return Horde_Imap_Fetch_Results  The results.
  * @throws Horde_ActiveSync_Exception
  */
 protected function _getMailMessages(Horde_Imap_Client_Mailbox $mbox, array $uids, array $options = array())
 {
     $options = array_merge(array('headers' => false, 'structure' => true, 'flags' => true, 'envelope' => false), $options);
     $imap = $this->_getImapOb();
     $query = new Horde_Imap_Client_Fetch_Query();
     if ($options['structure']) {
         $query->structure();
     }
     if ($options['flags']) {
         $query->flags();
     }
     if ($options['envelope']) {
         $query->envelope();
     }
     if (!empty($options['headers'])) {
         $query->headerText(array('peek' => true));
     }
     $ids = new Horde_Imap_Client_Ids($uids);
     try {
         return $imap->fetch($mbox, $query, array('ids' => $ids, 'exists' => true));
     } catch (Horde_Imap_Client_Exception $e) {
         $this->_logger->err(sprintf('[%s] Unable to fetch message: %s', $this->_procid, $e->getMessage()));
         throw new Horde_ActiveSync_Exception($e);
     }
 }
Пример #5
0
 public function mail_logRecipient($action, $recipients, $message_id)
 {
     if ($this->_registry->hasMethod('logRecipient', $this->_registry->hasInterface('mail'))) {
         try {
             $this->_registry->mail->logRecipient($action, $recipients, $message_id);
         } catch (Horde_Exception $e) {
             $this->_logger->err($e->getMessage());
         }
     }
 }
Пример #6
0
 /**
  * React on detection of more than one default folder.
  *
  * @param string  $first  The first default folder name.
  * @param string  $second The second default folder name.
  * @param string  $type   The folder type.
  * @param string  $owner  The folder owner.
  */
 protected function doubleDefault($first, $second, $owner, $type)
 {
     $this->_logger->err(sprintf('Both folders "%s" and "%s" of owner "%s" are marked as default folder of type "%s"!', $first, $second, $owner, $type));
 }
Пример #7
0
 /**
  * Handle device checks. Takes into account permissions and restrictions
  * via various callback methods.
  *
  * @param  string $devId  The client provided device id.
  *
  * @return boolean  If EAS version is > 12.1 returns false on any type of
  *                  failure in allowing the device to connect. Sets
  *                  appropriate internal variables to indicate the type of
  *                  error to return to the client. Failure on EAS version
  *                  < 12.1 results in throwing exceptions. Otherwise, return
  *                  true.
  * @throws Horde_ActiveSync_Exception, Horde_Exception_AuthenticationFailure
  */
 protected function _handleDevice($devId)
 {
     $get = $this->getGetVars();
     $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);
                 // Always throw exception in place of status code since we
                 // won't have a version number before the device is created.
                 throw new Horde_Exception_AuthenticationFailure($msg, $callback_ret);
             } 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())) {
             $this->_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);
         }
     }
     // Save the device now that we know it is at least allowed to connect,
     // or it has connected successfully at least once in the past.
     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) {
                 // Use a status code here, since the device has already
                 // connected.
                 $this->_globalError = $callback_ret;
                 return false;
             } else {
                 throw new Horde_Exception_AuthenticationFailure($msg, $callback_ret);
             }
         }
     }
     // 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;
             return false;
         } else {
             throw new Horde_ActiveSync_Exception($msg);
         }
     }
     return true;
 }
Пример #8
0
 /**
  * Poll the backend for changes.
  *
  * @param integer $heartbeat  The heartbeat lifetime to wait for changes.
  * @param integer $interval   The wait interval between poll iterations.
  * @param array $options      An options array containing any of:
  *   - pingable: (boolean)  Only poll collections with the pingable flag set.
  *                DEFAULT: false
  *
  * @return boolean|integer True if changes were detected in any of the
  *                         collections, false if no changes detected
  *                         or a status code if failed.
  */
 public function pollForChanges($heartbeat, $interval, array $options = array())
 {
     $dataavailable = false;
     $started = time();
     $until = $started + $heartbeat;
     $this->_logger->info(sprintf('Waiting for changes for %s seconds', $heartbeat));
     // If pinging, make sure we have pingable collections. Note we can't
     // filter on them here because the collections might change during the
     // loop below.
     if (!empty($options['pingable']) && !$this->havePingableCollections()) {
         $this->_logger->err('No pingable collections.');
         return self::COLLECTION_ERR_SERVER;
     }
     // Need to update AND SAVE the timestamp for race conditions to be
     // detected.
     $this->lasthbsyncstarted = $started;
     $this->save();
     // We only check for remote wipe request once every 5 iterations to
     // save on DB load since we must reload the device's state each time.
     $rw_check_countdown = 5;
     while (($now = time()) < $until) {
         // Try not to go over the heartbeat interval.
         if ($until - $now < $interval) {
             $interval = $until - $now;
         }
         // See if another process has altered the sync_cache.
         if ($this->checkStaleRequest()) {
             return self::COLLECTION_ERR_STALE;
         }
         // Make sure the collections are still there (there might have been
         // an error in refreshing them from the cache). Ideally this should
         // NEVER happen.
         if (!count($this->_collections)) {
             $this->_logger->err('NO COLLECTIONS! This should not happen!');
             return self::COLLECTION_ERR_SERVER;
         }
         // Check for WIPE request once every 5 iterations to balance between
         // performance and speed of catching a remote wipe request.
         if ($rw_check_countdown-- == 0) {
             $rw_check_countdown = 5;
             if ($this->_as->provisioning != Horde_ActiveSync::PROVISIONING_NONE) {
                 $rwstatus = $this->_as->state->getDeviceRWStatus($this->_as->device->id, true);
                 if ($rwstatus == Horde_ActiveSync::RWSTATUS_PENDING || $rwstatus == Horde_ActiveSync::RWSTATUS_WIPED) {
                     return self::COLLECTION_ERR_FOLDERSYNC_REQUIRED;
                 }
             }
         }
         // Check each collection we are interested in.
         foreach ($this->_collections as $id => $collection) {
             // Initialize the collection's state data in the state handler.
             try {
                 $this->initCollectionState($collection, true);
             } catch (Horde_ActiveSync_Exception_StateGone $e) {
                 $this->_logger->notice(sprintf('[%s] State not found for %s. Continuing.', $this->_procid, $id));
                 if (!empty($options['pingable'])) {
                     return self::COLLECTION_ERR_PING_NEED_FULL;
                 }
                 $dataavailable = true;
                 $this->setGetChangesFlag($id);
                 continue;
             } catch (Horde_ActiveSync_Exception_InvalidRequest $e) {
                 // Thrown when state is unable to be initialized because the
                 // collection has not yet been synched, but was requested to
                 // be pinged.
                 $this->_logger->err(sprintf('[%s] Unable to initialize state for %s. Ignoring during pollForChanges: %s.', $this->_procid, $id, $e->getMessage()));
                 continue;
             } catch (Horde_ActiveSync_Exception_FolderGone $e) {
                 $this->_logger->warn('Folder gone for collection ' . $collection['id']);
                 return self::COLLECTION_ERR_FOLDERSYNC_REQUIRED;
             } catch (Horde_ActiveSync_Exception $e) {
                 $this->_logger->err('Error loading state: ' . $e->getMessage());
                 $this->_as->state->loadState(array(), null, Horde_ActiveSync::REQUEST_TYPE_SYNC, $id);
                 $this->setGetChangesFlag($id);
                 $dataavailable = true;
                 continue;
             }
             if (!empty($options['pingable']) && !$this->_cache->collectionIsPingable($id)) {
                 $this->_logger->notice(sprintf('[%s] Skipping %s because it is not PINGable.', $this->_procid, $id));
                 continue;
             }
             try {
                 if ($cnt = $this->getCollectionChangeCount(true)) {
                     $dataavailable = true;
                     $this->setGetChangesFlag($id);
                     if (!empty($options['pingable'])) {
                         $this->_cache->setPingChangeFlag($id);
                     }
                 } else {
                     try {
                         $this->_as->state->updateSyncStamp();
                     } catch (Horde_ActiveSync_Exception $e) {
                         $this->_logger->err($e->getMessage());
                     }
                 }
             } catch (Horde_ActiveSync_Exception_StaleState $e) {
                 $this->_logger->notice(sprintf('[%s] SYNC terminating and force-clearing device state: %s', $this->_procid, $e->getMessage()));
                 $this->_as->state->loadState(array(), null, Horde_ActiveSync::REQUEST_TYPE_SYNC, $id);
                 $this->setGetChangesFlag($id);
                 $dataavailable = true;
             } catch (Horde_ActiveSync_Exception_FolderGone $e) {
                 $this->_logger->notice(sprintf('[%s] SYNC terminating: %s', $this->_procid, $e->getMessage()));
                 // If we are missing a folder, we should clear the PING
                 // cache also, to be sure it picks up any hierarchy changes
                 // since most clients don't seem smart enough to figure this
                 // out on their own.
                 $this->resetPingCache();
                 return self::COLLECTION_ERR_FOLDERSYNC_REQUIRED;
             } catch (Horde_Exception_AuthenticationFailure $e) {
                 // We lost authentication for some reason.
                 $this->_logger->err(sprintf('[%s] Authentication lost during PING!!', $this->_procid));
                 return self::COLLECTION_ERR_AUTHENTICATION;
             } catch (Horde_ActiveSync_Exception $e) {
                 $this->_logger->err(sprintf('[%s] Sync object cannot be configured, throttling: %s', $this->_procid, $e->getMessage()));
                 $this->_sleep(30);
                 continue;
             }
         }
         if (!empty($dataavailable)) {
             $this->_logger->info(sprintf('[%s] Found changes!', $this->_procid));
             break;
         }
         // Wait a bit...
         $this->_sleep($interval);
         // Refresh the collections.
         $this->updateCollectionsFromCache();
     }
     // Check that no other Sync process already started
     // If so, we exit here and let the other process do the export.
     if ($this->checkStaleRequest()) {
         $this->_logger->info('Changes in cache determined during Sync Wait/Heartbeat, exiting here.');
         return self::COLLECTION_ERR_STALE;
     }
     $this->_logger->info(sprintf('[%s] Looping Sync complete: DataAvailable: %s, DataImported: %s', $this->_procid, $dataavailable, $this->importedChanges));
     return $dataavailable;
 }
Пример #9
0
 /**
  * Handle the request.
  *
  * @return boolean
  */
 public function handle()
 {
     $this->_logger->info(sprintf('[%s] Request being handled for device: %s, Supporting protocol version: %s, Using Horde_ActiveSync v%s', $this->_procid, $this->_device->id, $this->_device->version, Horde_ActiveSync::LIBRARY_VERSION));
     $this->_logger->info(sprintf('[%s] GET VARIABLES: %s', $this->_procid, print_r($this->_activeSync->getGetVars(), true)));
     try {
         return $this->_handle();
     } catch (Exception $e) {
         $this->_logger->err($e->getMessage());
         throw $e;
     }
 }
Пример #10
0
 /**
  * Recursively decodes the WBXML from input stream. This means that if this
  * message contains complex types (like Appointment.Recuurence for example)
  * the sub-objects are auto-instantiated and decoded as well. Places the
  * decoded objects in the local properties array.
  *
  * @param Horde_ActiveSync_Wbxml_Decoder  The stream decoder
  *
  * @throws Horde_ActiveSync_Exception
  */
 public function decodeStream(Horde_ActiveSync_Wbxml_Decoder &$decoder)
 {
     while (1) {
         $entity = $decoder->getElement();
         if ($entity[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_STARTTAG) {
             if (!($entity[Horde_ActiveSync_Wbxml::EN_FLAGS] & Horde_ActiveSync_Wbxml::EN_FLAGS_CONTENT)) {
                 $map = $this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]];
                 if (!isset($map[self::KEY_TYPE])) {
                     $this->{$map}[self::KEY_ATTRIBUTE] = '';
                 } elseif ($map[self::KEY_TYPE] == self::TYPE_DATE || $map[self::KEY_TYPE] == self::TYPE_DATE_DASHES) {
                     $this->{$map}[self::KEY_ATTRIBUTE] = '';
                 }
                 continue;
             }
             // Found start tag
             if (!isset($this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]])) {
                 $this->_logger->err('Tag ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG] . ' unexpected in type XML type ' . get_class($this));
                 throw new Horde_ActiveSync_Exception('Unexpected tag');
             } else {
                 $map = $this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]];
                 if (isset($map[self::KEY_VALUES])) {
                     // Handle arrays of attribute values
                     while (1) {
                         if (!$decoder->getElementStartTag($map[self::KEY_VALUES])) {
                             break;
                         }
                         if (isset($map[self::KEY_TYPE])) {
                             $class = $map[self::KEY_TYPE];
                             $decoded = new $class(array('protocolversion' => $this->_version, 'logger' => $this->_logger));
                             $decoded->decodeStream($decoder);
                         } else {
                             $decoded = $decoder->getElementContent();
                         }
                         if (!isset($this->{$map}[self::KEY_ATTRIBUTE])) {
                             $this->{$map}[self::KEY_ATTRIBUTE] = array($decoded);
                         } else {
                             $this->{$map[self::KEY_ATTRIBUTE]}[] = $decoded;
                         }
                         if (!$decoder->getElementEndTag()) {
                             throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                         }
                     }
                     if (!$decoder->getElementEndTag()) {
                         return false;
                     }
                 } else {
                     // Handle a simple attribute value
                     if (isset($map[self::KEY_TYPE])) {
                         // Complex type, decode recursively
                         if ($map[self::KEY_TYPE] == self::TYPE_DATE || $map[self::KEY_TYPE] == self::TYPE_DATE_DASHES) {
                             $decoded = $this->_parseDate($decoder->getElementContent());
                             if (!$decoder->getElementEndTag()) {
                                 throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                             }
                         } elseif ($map[self::KEY_TYPE] == self::TYPE_HEX) {
                             $decoded = self::hex2bin($decoder->getElementContent());
                             if (!$decoder->getElementEndTag()) {
                                 throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                             }
                         } else {
                             $class = $map[self::KEY_TYPE];
                             $subdecoder = new $class(array('protocolversion' => $this->_version, 'logger' => $this->_logger));
                             if ($subdecoder->decodeStream($decoder) === false) {
                                 throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                             }
                             $decoded = $subdecoder;
                             if (!$decoder->getElementEndTag()) {
                                 $this->_logger->err('No end tag for ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG]);
                                 throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                             }
                         }
                     } else {
                         // Simple type, just get content
                         $decoded = $decoder->getElementContent();
                         if ($decoded === false) {
                             $this->_logger->err('Unable to get content for ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG]);
                         }
                         if (!$decoder->getElementEndTag()) {
                             $this->_logger->err('Unable to get end tag for ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG]);
                             throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                         }
                     }
                     // $decoded now contains data object (or string)
                     $this->{$map}[self::KEY_ATTRIBUTE] = $decoded;
                 }
             }
         } elseif ($entity[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_ENDTAG) {
             $decoder->_ungetElement($entity);
             break;
         } else {
             $this->_logger->err('Unexpected content in type');
             break;
         }
     }
 }
Пример #11
0
            $baseImg->applyEffects();
            $baseImg->display();
            $time = xdebug_time_index() - $time;
            $memory = xdebug_peak_memory_usage();
            logThis($test, $time, $memory);
            break;
        case 'testPolaroidstackBlueBG':
            $imgs = array(getImageObject(array('filename' => 'img1.jpg')), getImageObject(array('filename' => 'img2.jpg')), getImageObject(array('filename' => 'img3.jpg')));
            $baseImg = getImageObject(array('width' => 1, 'height' => 1, 'background' => 'none'));
            $baseImg->addEffect('PhotoStack', array('images' => $imgs, 'resize_height' => 150, 'padding' => 0, 'background' => 'blue', 'type' => 'polaroid'));
            $baseImg->applyEffects();
            $baseImg->display();
            break;
    }
} catch (Exception $e) {
    $logger->err($e);
    header('Content-Type: image/png');
    readfile('error.png');
    exit;
}
/**
 * Obtain a Horde_Image object
 *
 * @param array $params  Any additional parameters
 *
 * @return Horde_Image_Base The image object.
 */
function getImageObject($params = array())
{
    global $convert, $driver, $identify;
    $context = array('tmpdir' => Horde::getTempdir());
Пример #12
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();
             }
         }
     }
 }
Пример #13
0
 /**
  * Recursively decodes the WBXML from input stream. This means that if this
  * message contains complex types (like Appointment.Recuurence for example)
  * the sub-objects are auto-instantiated and decoded as well. Places the
  * decoded objects in the local properties array.
  *
  * @param Horde_ActiveSync_Wbxml_Decoder  The stream decoder
  *
  * @throws Horde_ActiveSync_Exception
  */
 public function decodeStream(Horde_ActiveSync_Wbxml_Decoder &$decoder)
 {
     while (1) {
         $entity = $decoder->getElement();
         if ($entity[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_STARTTAG) {
             if (!($entity[Horde_ActiveSync_Wbxml::EN_FLAGS] & Horde_ActiveSync_Wbxml::EN_FLAGS_CONTENT)) {
                 $map = $this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]];
                 if (!isset($map[self::KEY_TYPE])) {
                     $this->{$map[self::KEY_ATTRIBUTE]} = '';
                 } elseif ($map[self::KEY_TYPE] == self::TYPE_DATE || $map[self::KEY_TYPE] == self::TYPE_DATE_DASHES) {
                     $this->{$map[self::KEY_ATTRIBUTE]} = '';
                 }
                 continue;
             }
             // Found start tag
             if (!isset($this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]])) {
                 $this->_logger->err('Tag ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG] . ' unexpected in type XML type ' . get_class($this));
                 throw new Horde_ActiveSync_Exception('Unexpected tag');
             } else {
                 $map = $this->_mapping[$entity[Horde_ActiveSync_Wbxml::EN_TAG]];
                 if (isset($map[self::KEY_VALUES])) {
                     // Handle arrays of attribute values
                     while (1) {
                         //do not get start tag for an array without a container
                         if (!(isset($map[self::KEY_PROPERTY]) && $map[self::KEY_PROPERTY] == self::PROPERTY_NO_CONTAINER)) {
                             if (!$decoder->getElementStartTag($map[self::KEY_VALUES])) {
                                 break;
                             }
                         }
                         if (isset($map[self::KEY_TYPE])) {
                             $class = $map[self::KEY_TYPE];
                             $decoded = new $class(array('protocolversion' => $this->_version, 'logger' => $this->_logger));
                             $decoded->decodeStream($decoder);
                         } else {
                             $decoded = $decoder->getElementContent();
                         }
                         if (!isset($this->{$map[self::KEY_ATTRIBUTE]})) {
                             $this->{$map[self::KEY_ATTRIBUTE]} = array($decoded);
                         } else {
                             $this->{$map[self::KEY_ATTRIBUTE]}[] = $decoded;
                         }
                         if (!$decoder->getElementEndTag()) {
                             throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                         }
                         if (isset($map[self::KEY_PROPERTY]) && $map[self::KEY_PROPERTY] == self::PROPERTY_NO_CONTAINER) {
                             $e = $decoder->peek();
                             //go back to the initial while if another block of no container elements is found
                             if ($e[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_STARTTAG) {
                                 continue 2;
                             }
                             //break on end tag because no container elements block end is reached
                             if ($e[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_ENDTAG) {
                                 break;
                             }
                             if (empty($e)) {
                                 break;
                             }
                         }
                     }
                     //do not get container end tag for an array without a container
                     if (!(isset($map[self::KEY_PROPERTY]) && $map[self::KEY_PROPERTY] == self::PROPERTY_NO_CONTAINER)) {
                         if (!$decoder->getElementEndTag()) {
                             return false;
                         }
                     }
                 } else {
                     // Handle a simple attribute value
                     if (isset($map[self::KEY_TYPE])) {
                         // Complex type, decode recursively
                         if ($map[self::KEY_TYPE] == self::TYPE_DATE || $map[self::KEY_TYPE] == self::TYPE_DATE_DASHES) {
                             $decoded = $this->_parseDate($decoder->getElementContent());
                         } elseif ($map[self::KEY_TYPE] == self::TYPE_HEX) {
                             $decoded = self::hex2bin($decoder->getElementContent());
                         } else {
                             $class = $map[self::KEY_TYPE];
                             $subdecoder = new $class(array('protocolversion' => $this->_version, 'logger' => $this->_logger));
                             $subdecoder->decodeStream($decoder);
                             $decoded = $subdecoder;
                         }
                     } else {
                         // Simple type, just get content
                         $decoded = $decoder->getElementContent();
                         if ($decoded === false) {
                             $decoded = '';
                             $this->_logger->notice('Unable to get expected content for ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG] . ': Setting to an empty string.');
                         }
                     }
                     if (!$decoder->getElementEndTag()) {
                         $this->_logger->err('Unable to get end tag for ' . $entity[Horde_ActiveSync_Wbxml::EN_TAG]);
                         throw new Horde_ActiveSync_Exception('Missing expected wbxml end tag');
                     }
                     $this->{$map[self::KEY_ATTRIBUTE]} = $decoded;
                 }
             }
         } elseif ($entity[Horde_ActiveSync_Wbxml::EN_TYPE] == Horde_ActiveSync_Wbxml::EN_TYPE_ENDTAG) {
             $decoder->_ungetElement($entity);
             break;
         } else {
             $this->_logger->err('Unexpected content in type');
             break;
         }
     }
 }
Пример #14
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.');
 }
Пример #15
0
 /**
  * Non-static wrapper for getNewSyncKey.
  *
  * @param string $syncKey  The old syncKey
  *
  * @return string  The new synckey
  * @throws Horde_ActiveSync_Exception
  *
  * @todo  Remove/replace in H6 with Horde_ActiveSync_SyncKey
  */
 public function getNewSyncKeyWrapper($syncKey)
 {
     if ($this->checkCollision($newKey = self::getNewSyncKey($syncKey))) {
         $this->_logger->err(sprintf('[%s] Found collision when generating synckey %s. Trying again.', $this->_procid, $newKey));
         return $this->getNewSyncKeyWrapper($synckey);
     }
     return $newKey;
 }