/**
  * Handles a webservice command
  *
  * @param int       $commandCode
  *
  * @access public
  * @return boolean
  * @throws SoapFault
  */
 public function Handle($commandCode)
 {
     if (Request::GetDeviceType() !== "webservice" || Request::GetDeviceID() !== "webservice") {
         throw new FatalException("Invalid device id and type for webservice execution");
     }
     if (Request::GetGETUser() != Request::GetAuthUser()) {
         ZLog::Write(LOGLEVEL_INFO, sprintf("Webservice::HandleWebservice('%s'): user '%s' executing action for user '%s'", $commandCode, Request::GetAuthUser(), Request::GetGETUser()));
     }
     // initialize non-wsdl soap server
     $this->server = new SoapServer(null, array('uri' => "http://z-push.sf.net/webservice"));
     // the webservice command is handled by its class
     if ($commandCode == ZPush::COMMAND_WEBSERVICE_DEVICE) {
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("Webservice::HandleWebservice('%s'): executing WebserviceDevice service", $commandCode));
         include_once 'webservicedevice.php';
         $this->server->setClass("WebserviceDevice");
     }
     // the webservice command is handled by its class
     if ($commandCode == ZPush::COMMAND_WEBSERVICE_USERS) {
         if (!defined("ALLOW_WEBSERVICE_USERS_ACCESS") || ALLOW_WEBSERVICE_USERS_ACCESS !== true) {
             throw new HTTPReturnCodeException(sprintf("Access to the WebserviceUsers service is disabled in configuration. Enable setting ALLOW_WEBSERVICE_USERS_ACCESS.", Request::GetAuthUser()), 403);
         }
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("Webservice::HandleWebservice('%s'): executing WebserviceUsers service", $commandCode));
         if (ZPush::GetBackend()->Setup("SYSTEM", true) == false) {
             throw new AuthenticationRequiredException(sprintf("User '%s' has no admin privileges", Request::GetAuthUser()));
         }
         include_once 'webserviceusers.php';
         $this->server->setClass("WebserviceUsers");
     }
     $this->server->handle();
     ZLog::Write(LOGLEVEL_DEBUG, sprintf("Webservice::HandleWebservice('%s'): sucessfully sent %d bytes", $commandCode, ob_get_length()));
     return true;
 }
 /**
  * Initializes internal parameters
  *
  * @access public
  * @return boolean
  */
 public function InitializeParams()
 {
     if (!isset(self::$devid)) {
         self::$devid = Request::GetDeviceID();
         self::$pid = @getmypid();
         self::$user = Request::GetAuthUser();
         self::$start = time();
     }
     return true;
 }
 /**
  * Authenticates the remote user
  * The sent HTTP authentication information is used to on Backend->Logon().
  * As second step the GET-User verified by Backend->Setup() for permission check
  * Request::GetGETUser() is usually the same as the Request::GetAuthUser().
  * If the GETUser is different from the AuthUser, the AuthUser MUST HAVE admin
  * permissions on GETUsers data store. Only then the Setup() will be sucessfull.
  * This allows the user 'john' to do operations as user 'joe' if he has sufficient privileges.
  *
  * @access public
  * @return
  * @throws AuthenticationRequiredException
  */
 public static function Authenticate()
 {
     self::$userIsAuthenticated = false;
     $backend = ZPush::GetBackend();
     if ($backend->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword()) == false) {
         throw new AuthenticationRequiredException("Access denied. Username or password incorrect");
     }
     // mark this request as "authenticated"
     self::$userIsAuthenticated = true;
     // check Auth-User's permissions on GETUser's store
     if ($backend->Setup(Request::GetGETUser(), true) == false) {
         throw new AuthenticationRequiredException(sprintf("Not enough privileges of '%s' to setup for user '%s': Permission denied", Request::GetAuthUser(), Request::GetGETUser()));
     }
 }
Example #4
0
 /**
  * Authenticates the remote user
  * The sent HTTP authentication information is used to on Backend->Logon().
  * As second step the GET-User verified by Backend->Setup() for permission check
  * Request::GetGETUser() is usually the same as the Request::GetAuthUser().
  * If the GETUser is different from the AuthUser, the AuthUser MUST HAVE admin
  * permissions on GETUsers data store. Only then the Setup() will be sucessfull.
  * This allows the user 'john' to do operations as user 'joe' if he has sufficient privileges.
  *
  * @access public
  * @return
  * @throws AuthenticationRequiredException
  */
 public static function Authenticate()
 {
     self::$userIsAuthenticated = false;
     // when a certificate is sent, allow authentication only as the certificate owner
     if (defined("CERTIFICATE_OWNER_PARAMETER") && isset($_SERVER[CERTIFICATE_OWNER_PARAMETER]) && strtolower($_SERVER[CERTIFICATE_OWNER_PARAMETER]) != strtolower(Request::GetAuthUser())) {
         throw new AuthenticationRequiredException(sprintf("Access denied. Access is allowed only for the certificate owner '%s'", $_SERVER[CERTIFICATE_OWNER_PARAMETER]));
     }
     $backend = ZPush::GetBackend();
     if ($backend->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword()) == false) {
         throw new AuthenticationRequiredException("Access denied. Username or password incorrect");
     }
     // mark this request as "authenticated"
     self::$userIsAuthenticated = true;
 }
Example #5
0
 /**
  * Handles a webservice command
  *
  * @param int       $commandCode
  *
  * @access public
  * @return boolean
  * @throws SoapFault
  */
 public function Handle($commandCode)
 {
     if (Request::GetDeviceType() !== "webservice" || Request::GetDeviceID() !== "webservice") {
         throw new FatalException("Invalid device id and type for webservice execution");
     }
     if (Request::GetGETUser() != Request::GetAuthUser()) {
         ZLog::Write(LOGLEVEL_INFO, sprintf("Webservice::HandleWebservice('%s'): user '%s' executing action for user '%s'", $commandCode, Request::GetAuthUser(), Request::GetGETUser()));
     }
     // initialize non-wsdl soap server
     $this->server = new SoapServer(null, array('uri' => "http://z-push.sf.net/webservice"));
     // the webservice command is handled by its class
     if ($commandCode == ZPush::COMMAND_WEBSERVICE_DEVICE) {
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("Webservice::HandleWebservice('%s'): executing WebserviceDevice service", $commandCode));
         include_once 'webservicedevice.php';
         $this->server->setClass("WebserviceDevice");
     }
     $this->server->handle();
     ZLog::Write(LOGLEVEL_DEBUG, sprintf("Webservice::HandleWebservice('%s'): sucessfully sent %d bytes", $commandCode, ob_get_length()));
     return true;
 }
Example #6
0
function update_calendar_attendee($uid, $mailto, $status)
{
    ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->update_calendar_attendee('%s', '%s', '%s'): Updating calendar event attendee", $uid, $mailto, $status));
    $updated = false;
    if ($uid === false) {
        ZLog::Write(LOGLEVEL_WARN, "BackendIMAP->update_calendar_attendee(): UID not found; report the full calendar object to developers");
    } else {
        if (defined('IMAP_MEETING_USE_CALDAV') && IMAP_MEETING_USE_CALDAV) {
            $caldav = new BackendCalDAV();
            if ($caldav->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword())) {
                $events = $caldav->FindCalendar($uid);
                if (count($events) == 1) {
                    $href = $events[0]["href"];
                    $etag = $events[0]["etag"];
                    ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->update_calendar_attendee(): found event with href '%s' etag '%s'; updating", $href, $etag));
                    // Get Attendee status
                    $old_status = "";
                    if (strcasecmp($old_status, $status) != 0) {
                        ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->update_calendar_attendee(): Before <%s>", $events[0]["data"]));
                        $ical = new iCalComponent();
                        $ical->ParseFrom($events[0]["data"]);
                        $ical->SetCPParameterValue("VEVENT", "ATTENDEE", "PARTSTAT", strtoupper($status), $mailto);
                        ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->update_calendar_attendee(): After <%s>", $ical->Render()));
                        $etag = $caldav->CreateUpdateCalendar($ical->Render(), $href, $etag);
                        ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->update_calendar_attendee(): Calendar updated with etag '%s'", $etag));
                        // Update new status
                        $updated = true;
                    }
                    $caldav->Logoff();
                } else {
                    ZLog::Write(LOGLEVEL_ERROR, "BackendIMAP->update_calendar_attendee(): event not found or duplicated event");
                }
            } else {
                ZLog::Write(LOGLEVEL_ERROR, "BackendIMAP->update_calendar_attendee(): Error connecting with BackendCalDAV");
            }
        }
    }
    return $updated;
}
Example #7
0
     if ($ex instanceof ZPushException) {
         header('HTTP/1.1 ' . $ex->getHTTPCodeString());
         foreach ($ex->getHTTPHeaders() as $h) {
             header($h);
         }
     } else {
         header('HTTP/1.1 500 Internal Server Error');
     }
 } else {
     ZLog::Write(LOGLEVEL_FATAL, "Exception: ({$exclass}) - headers were already sent. Message: " . $ex->getMessage());
 }
 if ($ex instanceof AuthenticationRequiredException) {
     ZPush::PrintZPushLegal($exclass, sprintf('<pre>%s</pre>', $ex->getMessage()));
     // log the failed login attemt e.g. for fail2ban
     if (defined('LOGAUTHFAIL') && LOGAUTHFAIL != false) {
         ZLog::Write(LOGLEVEL_WARN, sprintf("IP: %s failed to authenticate user '%s'", Request::GetRemoteAddr(), Request::GetAuthUser() ? Request::GetAuthUser() : Request::GetGETUser()));
     }
 } else {
     if ($ex instanceof WBXMLException) {
         ZLog::Write(LOGLEVEL_FATAL, "Request could not be processed correctly due to a WBXMLException. Please report this.");
     } else {
         if (!$ex instanceof ZPushException || $ex->showLegalNotice()) {
             $cmdinfo = Request::GetCommand() ? sprintf(" processing command <i>%s</i>", Request::GetCommand()) : "";
             $extrace = $ex->getTrace();
             $trace = !empty($extrace) ? "\n\nTrace:\n" . print_r($extrace, 1) : "";
             ZPush::PrintZPushLegal($exclass . $cmdinfo, sprintf('<pre>%s</pre>', $ex->getMessage() . $trace));
         }
     }
 }
 // Announce exception to process loop detection
 if (ZPush::GetDeviceManager(false)) {
Example #8
0
 /**
  * Returns the filename logs for a WBXML debug log user should be saved to
  *
  * @access private
  * @return string
  */
 private static function logToUserFile()
 {
     global $specialLogUsers;
     if (self::$authUser === false) {
         if (RequestProcessor::isUserAuthenticated()) {
             $authuser = Request::GetAuthUser();
             if ($authuser && in_array($authuser, $specialLogUsers)) {
                 self::$authUser = preg_replace('/[^a-z0-9]/', '_', strtolower($authuser));
             }
         }
     }
     return self::$authUser;
 }
Example #9
0
 /**
  * Marks a device of the Request::GetGETUser() to be remotely wiped
  *
  * @param string    $deviceId       the device id
  *
  * @access public
  * @return boolean
  * @throws SoapFault
  */
 public function WipeDevice($deviceId)
 {
     $deviceId = preg_replace("/[^A-Za-z0-9]/", "", $deviceId);
     ZLog::Write(LOGLEVEL_INFO, sprintf("WebserviceDevice::WipeDevice('%s'): mark device of user '%s' for remote wipe", $deviceId, Request::GetGETUser()));
     if (!ZPushAdmin::WipeDevice(Request::GetAuthUser(), Request::GetGETUser(), $deviceId)) {
         ZPush::GetTopCollector()->AnnounceInformation(ZLog::GetLastMessage(LOGLEVEL_ERROR), true);
         throw new SoapFault("ERROR", ZLog::GetLastMessage(LOGLEVEL_ERROR));
     }
     ZPush::GetTopCollector()->AnnounceInformation(sprintf("Wipe requested - device id '%s'", $deviceId), true);
     return true;
 }
Example #10
0
 /**
  * Sends an email notification to the user containing the data the user tried to save.
  *
  * @param SyncObject $message
  * @param SyncObject $oldmessage
  * @return void
  */
 private function sendNotificationEmail($message, $oldmessage)
 {
     // get email address and full name of the user
     $userinfo = ZPush::GetBackend()->GetUserDetails(Request::GetAuthUser());
     // get the name of the folder
     $foldername = "unknown";
     $folderid = bin2hex($this->folderid);
     $folders = ZPush::GetAdditionalSyncFolders();
     if (isset($folders[$folderid]) && isset($folders[$folderid]->displayname)) {
         $foldername = $folders[$folderid]->displayname;
     }
     // get the differences between the two objects
     $data = substr(get_class($oldmessage), 4) . "\r\n";
     // get the suppported fields as we need them to determine the ghosted properties
     $supportedFields = ZPush::GetDeviceManager()->GetSupportedFields(ZPush::GetDeviceManager()->GetFolderIdForBackendId($folderid));
     $dataarray = $oldmessage->EvaluateAndCompare($message, @constant('READ_ONLY_NOTIFY_YOURDATA'), $supportedFields);
     foreach ($dataarray as $key => $value) {
         $value = str_replace("\r", "", $value);
         $value = str_replace("\n", str_pad("\r\n", 25), $value);
         $data .= str_pad(ucfirst($key) . ":", 25) . $value . "\r\n";
     }
     // build a simple mime message
     $toEmail = $userinfo['emailaddress'];
     $mail = "From: Z-Push <no-reply>\r\n";
     $mail .= "To: {$toEmail}\r\n";
     $mail .= "Content-Type: text/plain; charset=utf-8\r\n";
     $mail .= "Subject: " . @constant('READ_ONLY_NOTIFY_SUBJECT') . "\r\n\r\n";
     $mail .= @constant('READ_ONLY_NOTIFY_BODY') . "\r\n";
     // replace values of template
     $mail = str_replace("**USERFULLNAME**", $userinfo['fullname'], $mail);
     $mail = str_replace("**DATE**", strftime(@constant('READ_ONLY_NOTIFY_DATE_FORMAT')), $mail);
     $mail = str_replace("**TIME**", strftime(@constant('READ_ONLY_NOTIFY_TIME_FORMAT')), $mail);
     $mail = str_replace("**FOLDERNAME**", $foldername, $mail);
     $mail = str_replace("**MOBILETYPE**", Request::GetDeviceType(), $mail);
     $mail = str_replace("**MOBILEDEVICEID**", Request::GetDeviceID(), $mail);
     $mail = str_replace("**DIFFERENCES**", $data, $mail);
     // user send email to himself
     $m = new SyncSendMail();
     $m->saveinsent = false;
     $m->replacemime = true;
     $m->mime = $mail;
     ZPush::GetBackend()->SendMail($m);
 }
Example #11
0
 /**
  * Imports a move of a message. This occurs when a user moves an item to another folder
  *
  * @param string        $id
  * @param string        $newfolder
  *
  * @access public
  * @return boolean
  */
 public function ImportMessageMove($id, $newfolder)
 {
     ZLog::Write(LOGLEVEL_DEBUG, sprintf("ImportChangesCombined->ImportMessageMove('%s', '%s')", $id, $newfolder));
     if (!$this->icc) {
         ZLog::Write(LOGLEVEL_ERROR, "ImportChangesCombined->ImportMessageMove icc not configured");
         return false;
     }
     if ($this->backend->GetBackendId($this->folderid) != $this->backend->GetBackendId($newfolder)) {
         ZLog::Write(LOGLEVEL_WARN, "ImportChangesCombined->ImportMessageMove() cannot move message between two backends");
         return false;
     }
     $res = $this->icc->ImportMessageMove($id, $this->backend->GetBackendFolder($newfolder));
     if ($res) {
         //TODO: we should add newid to new folder, instead of a full folder resync
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("ImportChangesCombined->ImportMessageMove(): Force resync of dest folder (%s)", $newfolder));
         ZPushAdmin::ResyncFolder(Request::GetAuthUser(), Request::GetDeviceID(), $newfolder);
     }
     return $res;
 }
Example #12
0
 public function decryptSmtpPassword()
 {
     if (!empty(\GO::session()->values['emailModule']['smtpPasswords'][$this->id])) {
         $decrypted = \GO\Base\Util\Crypt::decrypt(\GO::session()->values['emailModule']['smtpPasswords'][$this->id]);
     } else {
         //support for z-push without storing passwords
         if (empty($this->smtp_password) && method_exists('Request', 'GetAuthPassword') && Request::GetAuthUser() == $this->smtp_username) {
             $decrypted = Request::GetAuthPassword();
         } else {
             $decrypted = \GO\Base\Util\Crypt::decrypt($this->smtp_password);
         }
     }
     return $decrypted ? $decrypted : $this->smtp_password;
 }
Example #13
0
 /**
  * Returns the username and store of the currently active user
  *
  * @access public
  * @return Array
  */
 public function GetCurrentUsername()
 {
     return $this->GetUserDetails(Request::GetAuthUser());
 }
Example #14
0
 /**
  * Handles the FolderSync command
  *
  * @param int       $commandCode
  *
  * @access public
  * @return boolean
  */
 public function Handle($commandCode)
 {
     // Maps serverid -> clientid for items that are received from the PIM
     $map = array();
     // Parse input
     if (!self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_FOLDERSYNC)) {
         return false;
     }
     if (!self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_SYNCKEY)) {
         return false;
     }
     $synckey = self::$decoder->getElementContent();
     if (!self::$decoder->getElementEndTag()) {
         return false;
     }
     // every FolderSync with SyncKey 0 should return the supported AS version & command headers
     if ($synckey == "0") {
         self::$specialHeaders = array();
         self::$specialHeaders[] = ZPush::GetSupportedProtocolVersions();
         self::$specialHeaders[] = ZPush::GetSupportedCommands();
     }
     $status = SYNC_FSSTATUS_SUCCESS;
     $newsynckey = $synckey;
     try {
         $syncstate = self::$deviceManager->GetStateManager()->GetSyncState($synckey);
         // We will be saving the sync state under 'newsynckey'
         $newsynckey = self::$deviceManager->GetStateManager()->GetNewSyncKey($synckey);
     } catch (StateNotFoundException $snfex) {
         $status = SYNC_FSSTATUS_SYNCKEYERROR;
     } catch (StateInvalidException $sive) {
         $status = SYNC_FSSTATUS_SYNCKEYERROR;
     }
     // The ChangesWrapper caches all imports in-memory, so we can send a change count
     // before sending the actual data.
     // the HierarchyCache is notified and the changes from the PIM are transmitted to the actual backend
     $changesMem = self::$deviceManager->GetHierarchyChangesWrapper();
     // the hierarchyCache should now fully be initialized - check for changes in the additional folders
     $changesMem->Config(ZPush::GetAdditionalSyncFolders());
     // process incoming changes
     if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_CHANGES)) {
         // Ignore <Count> if present
         if (self::$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_COUNT)) {
             self::$decoder->getElementContent();
             if (!self::$decoder->getElementEndTag()) {
                 return false;
             }
         }
         // Process the changes (either <Add>, <Modify>, or <Remove>)
         $element = self::$decoder->getElement();
         if ($element[EN_TYPE] != EN_TYPE_STARTTAG) {
             return false;
         }
         $importer = false;
         while (1) {
             $folder = new SyncFolder();
             if (!$folder->Decode(self::$decoder)) {
                 break;
             }
             try {
                 if ($status == SYNC_FSSTATUS_SUCCESS && !$importer) {
                     // Configure the backends importer with last state
                     $importer = self::$backend->GetImporter();
                     $importer->Config($syncstate);
                     // the messages from the PIM will be forwarded to the backend
                     $changesMem->forwardImporter($importer);
                 }
                 if ($status == SYNC_FSSTATUS_SUCCESS) {
                     switch ($element[EN_TAG]) {
                         case SYNC_ADD:
                         case SYNC_MODIFY:
                             $serverid = $changesMem->ImportFolderChange($folder);
                             break;
                         case SYNC_REMOVE:
                             $serverid = $changesMem->ImportFolderDeletion($folder);
                             break;
                     }
                     // TODO what does $map??
                     if ($serverid) {
                         $map[$serverid] = $folder->clientid;
                     }
                 } else {
                     ZLog::Write(LOGLEVEL_WARN, sprintf("Request->HandleFolderSync(): ignoring incoming folderchange for folder '%s' as status indicates problem.", $folder->displayname));
                     self::$topCollector->AnnounceInformation("Incoming change ignored", true);
                 }
             } catch (StatusException $stex) {
                 $status = $stex->getCode();
             }
         }
         if (!self::$decoder->getElementEndTag()) {
             return false;
         }
     } else {
         // check for a potential process loop like described in Issue ZP-5
         if ($synckey != "0" && self::$deviceManager->IsHierarchyFullResyncRequired()) {
             $status = SYNC_FSSTATUS_SYNCKEYERROR;
         }
         self::$deviceManager->AnnounceProcessStatus(false, $status);
     }
     if (!self::$decoder->getElementEndTag()) {
         return false;
     }
     // We have processed incoming foldersync requests, now send the PIM
     // our changes
     // Output our WBXML reply now
     self::$encoder->StartWBXML();
     self::$encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERSYNC);
     if ($status == SYNC_FSSTATUS_SUCCESS) {
         try {
             // do nothing if this is an invalid device id (like the 'validate' Androids internal client sends)
             if (!Request::IsValidDeviceID()) {
                 throw new StatusException(sprintf("Request::IsValidDeviceID() indicated that '%s' is not a valid device id", Request::GetDeviceID()), SYNC_FSSTATUS_SERVERERROR);
             }
             // Changes from backend are sent to the MemImporter and processed for the HierarchyCache.
             // The state which is saved is from the backend, as the MemImporter is only a proxy.
             $exporter = self::$backend->GetExporter();
             $exporter->Config($syncstate);
             $exporter->InitializeExporter($changesMem);
             // Stream all changes to the ImportExportChangesMem
             $maxExporttime = Request::GetExpectedConnectionTimeout();
             $totalChanges = $exporter->GetChangeCount();
             $started = time();
             $exported = 0;
             $partial = false;
             while (is_array($exporter->Synchronize())) {
                 $exported++;
                 if (time() % 4) {
                     self::$topCollector->AnnounceInformation(sprintf("Exported %d from %d folders", $exported, $totalChanges));
                 }
                 // if partial sync is allowed, stop if this takes too long
                 if (USE_PARTIAL_FOLDERSYNC && time() - $started > $maxExporttime) {
                     ZLog::Write(LOGLEVEL_WARN, sprintf("Request->HandleFolderSync(): Exporting folders is too slow. In %d seconds only %d from %d changes were processed.", time() - $started, $exported, $totalChanges));
                     self::$topCollector->AnnounceInformation(sprintf("Partial export of %d out of %d folders", $exported, $totalChanges), true);
                     self::$deviceManager->SetFolderSyncComplete(false);
                     $partial = true;
                     break;
                 }
             }
             // update the foldersync complete flag
             if (USE_PARTIAL_FOLDERSYNC && $partial == false && self::$deviceManager->GetFolderSyncComplete() === false) {
                 // say that we are done with partial synching
                 self::$deviceManager->SetFolderSyncComplete(true);
                 // reset the loop data to prevent any loop detection to kick in now
                 self::$deviceManager->ClearLoopDetectionData(Request::GetAuthUser(), Request::GetDeviceId());
                 ZLog::Write(LOGLEVEL_INFO, "Request->HandleFolderSync(): Chunked exporting of folders completed successfully");
             }
             // get the new state from the backend
             $newsyncstate = isset($exporter) ? $exporter->GetState() : "";
         } catch (StatusException $stex) {
             if ($stex->getCode() == SYNC_FSSTATUS_CODEUNKNOWN) {
                 $status = SYNC_FSSTATUS_SYNCKEYERROR;
             } else {
                 $status = $stex->getCode();
             }
         }
     }
     self::$encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS);
     self::$encoder->content($status);
     self::$encoder->endTag();
     if ($status == SYNC_FSSTATUS_SUCCESS) {
         self::$encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY);
         $synckey = $changesMem->IsStateChanged() ? $newsynckey : $synckey;
         self::$encoder->content($synckey);
         self::$encoder->endTag();
         // Stream folders directly to the PDA
         $streamimporter = new ImportChangesStream(self::$encoder, false);
         $changesMem->InitializeExporter($streamimporter);
         $changeCount = $changesMem->GetChangeCount();
         self::$encoder->startTag(SYNC_FOLDERHIERARCHY_CHANGES);
         self::$encoder->startTag(SYNC_FOLDERHIERARCHY_COUNT);
         self::$encoder->content($changeCount);
         self::$encoder->endTag();
         while ($changesMem->Synchronize()) {
         }
         self::$encoder->endTag();
         self::$topCollector->AnnounceInformation(sprintf("Outgoing %d folders", $changeCount), true);
         // everything fine, save the sync state for the next time
         if ($synckey == $newsynckey) {
             self::$deviceManager->GetStateManager()->SetSyncState($newsynckey, $newsyncstate);
         }
     }
     self::$encoder->endTag();
     return true;
 }
 /**
  * Writes a SyncTask to MAPI
  *
  * @param mixed             $mapimessage
  * @param SyncTask          $task
  *
  * @access private
  * @return boolean
  */
 private function setTask($mapimessage, $task)
 {
     mapi_setprops($mapimessage, array(PR_MESSAGE_CLASS => "IPM.Task"));
     $taskmapping = MAPIMapping::GetTaskMapping();
     $taskprops = MAPIMapping::GetTaskProperties();
     $this->setPropsInMAPI($mapimessage, $task, $taskmapping);
     $taskprops = array_merge($this->getPropIdsFromStrings($taskmapping), $this->getPropIdsFromStrings($taskprops));
     // task specific properties to be set
     $props = array();
     if (isset($task->asbody)) {
         $this->setASbody($task->asbody, $props, $taskprops);
     }
     if (isset($task->complete)) {
         if ($task->complete) {
             // Set completion to 100%
             // Set status to 'complete'
             $props[$taskprops["completion"]] = 1.0;
             $props[$taskprops["status"]] = 2;
             $props[$taskprops["reminderset"]] = false;
         } else {
             // Set completion to 0%
             // Set status to 'not started'
             $props[$taskprops["completion"]] = 0.0;
             $props[$taskprops["status"]] = 0;
         }
     }
     if (isset($task->recurrence) && class_exists('TaskRecurrence')) {
         $deadoccur = false;
         if (isset($task->recurrence->occurrences) && $task->recurrence->occurrences == 1 || isset($task->recurrence->deadoccur) && $task->recurrence->deadoccur == 1) {
             //ios5 sends deadoccur inside the recurrence
             $deadoccur = true;
         }
         // Set PR_ICON_INDEX to 1281 to show correct icon in category view
         $props[$taskprops["icon"]] = 1281;
         // dead occur - false if new occurrences should be generated from the task
         // true - if it is the last ocurrence of the task
         $props[$taskprops["deadoccur"]] = $deadoccur;
         $props[$taskprops["isrecurringtag"]] = true;
         $recurrence = new TaskRecurrence($this->store, $mapimessage);
         $recur = array();
         $this->setRecurrence($task, $recur);
         // task specific recurrence properties which we need to set here
         // "start" and "end" are in GMT when passing to class.recurrence
         // set recurrence start here because it's calculated differently for tasks and appointments
         $recur["start"] = $task->recurrence->start;
         $recur["regen"] = $task->regenerate;
         //Also add dates to $recur
         $recur["duedate"] = $task->duedate;
         $recurrence->setRecurrence($recur);
     }
     //open addresss book for user resolve to set the owner
     $addrbook = $this->getAddressbook();
     // check if there is already an owner for the task, set current user if not
     $p = array($taskprops["owner"]);
     $owner = $this->getProps($mapimessage, $p);
     if (!isset($owner[$taskprops["owner"]])) {
         $userinfo = mapi_zarafa_getuser($this->store, Request::GetAuthUser());
         if (mapi_last_hresult() == NOERROR && isset($userinfo["fullname"])) {
             $props[$taskprops["owner"]] = $userinfo["fullname"];
         }
     }
     mapi_setprops($mapimessage, $props);
 }
 /**
  * Writes a SyncAppointment to MAPI
  *
  * @param mixed             $mapimessage
  * @param SyncAppointment   $message
  *
  * @access private
  * @return boolean
  */
 private function setAppointment($mapimessage, $appointment)
 {
     // Get timezone info
     if (isset($appointment->timezone)) {
         $tz = $this->getTZFromSyncBlob(base64_decode($appointment->timezone));
     } else {
         $tz = false;
     }
     //calculate duration because without it some webaccess views are broken. duration is in min
     $localstart = $this->getLocaltimeByTZ($appointment->starttime, $tz);
     $localend = $this->getLocaltimeByTZ($appointment->endtime, $tz);
     $duration = ($localend - $localstart) / 60;
     //nokia sends an yearly event with 0 mins duration but as all day event,
     //so make it end next day
     if ($appointment->starttime == $appointment->endtime && isset($appointment->alldayevent) && $appointment->alldayevent) {
         $duration = 1440;
         $appointment->endtime = $appointment->starttime + 24 * 60 * 60;
         $localend = $localstart + 24 * 60 * 60;
     }
     // is the transmitted UID OL compatible?
     // if not, encapsulate the transmitted uid
     $appointment->uid = Utils::GetOLUidFromICalUid($appointment->uid);
     mapi_setprops($mapimessage, array(PR_MESSAGE_CLASS => "IPM.Appointment"));
     $appointmentmapping = MAPIMapping::GetAppointmentMapping();
     $this->setPropsInMAPI($mapimessage, $appointment, $appointmentmapping);
     $appointmentprops = MAPIMapping::GetAppointmentProperties();
     $appointmentprops = array_merge($this->getPropIdsFromStrings($appointmentmapping), $this->getPropIdsFromStrings($appointmentprops));
     //appointment specific properties to be set
     $props = array();
     //we also have to set the responsestatus and not only meetingstatus, so we use another mapi tag
     $props[$appointmentprops["responsestatus"]] = isset($appointment->responsestatus) ? $appointment->responsestatus : olResponseNone;
     //sensitivity is not enough to mark an appointment as private, so we use another mapi tag
     $private = isset($appointment->sensitivity) && $appointment->sensitivity == 0 ? false : true;
     // Set commonstart/commonend to start/end and remindertime to start, duration, private and cleanGlobalObjectId
     $props[$appointmentprops["commonstart"]] = $appointment->starttime;
     $props[$appointmentprops["commonend"]] = $appointment->endtime;
     $props[$appointmentprops["reminderstart"]] = $appointment->starttime;
     // Set reminder boolean to 'true' if reminder is set
     $props[$appointmentprops["reminderset"]] = isset($appointment->reminder) ? true : false;
     $props[$appointmentprops["duration"]] = $duration;
     $props[$appointmentprops["private"]] = $private;
     $props[$appointmentprops["uid"]] = $appointment->uid;
     // Set named prop 8510, unknown property, but enables deleting a single occurrence of a recurring
     // type in OLK2003.
     $props[$appointmentprops["sideeffects"]] = 369;
     if (isset($appointment->reminder) && $appointment->reminder >= 0) {
         // Set 'flagdueby' to correct value (start - reminderminutes)
         $props[$appointmentprops["flagdueby"]] = $appointment->starttime - $appointment->reminder * 60;
         $props[$appointmentprops["remindertime"]] = $appointment->reminder;
     } else {
         $props[$appointmentprops["reminderset"]] = false;
     }
     if (isset($appointment->asbody)) {
         $this->setASbody($appointment->asbody, $props, $appointmentprops);
     }
     if (isset($appointment->recurrence)) {
         // Set PR_ICON_INDEX to 1025 to show correct icon in category view
         $props[$appointmentprops["icon"]] = 1025;
         //if there aren't any exceptions, use the 'old style' set recurrence
         $noexceptions = true;
         $recurrence = new Recurrence($this->store, $mapimessage);
         $recur = array();
         $this->setRecurrence($appointment, $recur);
         // set the recurrence type to that of the MAPI
         $props[$appointmentprops["recurrencetype"]] = $recur["recurrencetype"];
         $starttime = $this->gmtime($localstart);
         $endtime = $this->gmtime($localend);
         //set recurrence start here because it's calculated differently for tasks and appointments
         $recur["start"] = $this->getDayStartOfTimestamp($this->getGMTTimeByTZ($localstart, $tz));
         $recur["startocc"] = $starttime["tm_hour"] * 60 + $starttime["tm_min"];
         $recur["endocc"] = $recur["startocc"] + $duration;
         // Note that this may be > 24*60 if multi-day
         //only tasks can regenerate
         $recur["regen"] = false;
         // Process exceptions. The PDA will send all exceptions for this recurring item.
         if (isset($appointment->exceptions)) {
             foreach ($appointment->exceptions as $exception) {
                 // we always need the base date
                 if (!isset($exception->exceptionstarttime)) {
                     continue;
                 }
                 if (isset($exception->deleted) && $exception->deleted) {
                     // Delete exception
                     if (!isset($recur["deleted_occurences"])) {
                         $recur["deleted_occurences"] = array();
                     }
                     array_push($recur["deleted_occurences"], $this->getDayStartOfTimestamp($exception->exceptionstarttime));
                 } else {
                     // Change exception
                     $basedate = $this->getDayStartOfTimestamp($exception->exceptionstarttime);
                     $mapiexception = array("basedate" => $basedate);
                     //other exception properties which are not handled in recurrence
                     $exceptionprops = array();
                     if (isset($exception->starttime)) {
                         $mapiexception["start"] = $this->getLocaltimeByTZ($exception->starttime, $tz);
                         $exceptionprops[$appointmentprops["starttime"]] = $exception->starttime;
                     }
                     if (isset($exception->endtime)) {
                         $mapiexception["end"] = $this->getLocaltimeByTZ($exception->endtime, $tz);
                         $exceptionprops[$appointmentprops["endtime"]] = $exception->endtime;
                     }
                     if (isset($exception->subject)) {
                         $exceptionprops[$appointmentprops["subject"]] = $mapiexception["subject"] = u2w($exception->subject);
                     }
                     if (isset($exception->location)) {
                         $exceptionprops[$appointmentprops["location"]] = $mapiexception["location"] = u2w($exception->location);
                     }
                     if (isset($exception->busystatus)) {
                         $exceptionprops[$appointmentprops["busystatus"]] = $mapiexception["busystatus"] = $exception->busystatus;
                     }
                     if (isset($exception->reminder)) {
                         $exceptionprops[$appointmentprops["reminderset"]] = $mapiexception["reminder_set"] = 1;
                         $exceptionprops[$appointmentprops["remindertime"]] = $mapiexception["remind_before"] = $exception->reminder;
                     }
                     if (isset($exception->alldayevent)) {
                         $exceptionprops[$appointmentprops["alldayevent"]] = $mapiexception["alldayevent"] = $exception->alldayevent;
                     }
                     if (!isset($recur["changed_occurences"])) {
                         $recur["changed_occurences"] = array();
                     }
                     if (isset($exception->body)) {
                         $exceptionprops[$appointmentprops["body"]] = u2w($exception->body);
                     }
                     array_push($recur["changed_occurences"], $mapiexception);
                     if (!empty($exceptionprops)) {
                         $noexceptions = false;
                         if ($recurrence->isException($basedate)) {
                             $recurrence->modifyException($exceptionprops, $basedate);
                         } else {
                             $recurrence->createException($exceptionprops, $basedate);
                         }
                     }
                 }
             }
         }
         //setRecurrence deletes the attachments from an appointment
         if ($noexceptions) {
             $recurrence->setRecurrence($tz, $recur);
         }
     } else {
         $props[$appointmentprops["isrecurring"]] = false;
     }
     //always set the PR_SENT_REPRESENTING_* props so that the attendee status update also works with the webaccess
     $p = array($appointmentprops["representingentryid"], $appointmentprops["representingname"], $appointmentprops["sentrepresentingaddt"], $appointmentprops["sentrepresentingemail"], $appointmentprops["sentrepresentinsrchk"]);
     $representingprops = $this->getProps($mapimessage, $p);
     if (!isset($representingprops[$appointmentprops["representingentryid"]])) {
         $props[$appointmentprops["representingname"]] = Request::GetAuthUser();
         $props[$appointmentprops["sentrepresentingemail"]] = Request::GetAuthUser();
         $props[$appointmentprops["sentrepresentingaddt"]] = "ZARAFA";
         $props[$appointmentprops["representingentryid"]] = mapi_createoneoff(Request::GetAuthUser(), "ZARAFA", Request::GetAuthUser());
         $props[$appointmentprops["sentrepresentinsrchk"]] = $props[$appointmentprops["sentrepresentingaddt"]] . ":" . $props[$appointmentprops["sentrepresentingemail"]];
     }
     // Do attendees
     if (isset($appointment->attendees) && is_array($appointment->attendees)) {
         $recips = array();
         // Outlook XP requires organizer in the attendee list as well
         $org = array();
         $org[PR_ENTRYID] = isset($representingprops[$appointmentprops["representingentryid"]]) ? $representingprops[$appointmentprops["representingentryid"]] : $props[$appointmentprops["representingentryid"]];
         $org[PR_DISPLAY_NAME] = isset($representingprops[$appointmentprops["representingname"]]) ? $representingprops[$appointmentprops["representingname"]] : $props[$appointmentprops["representingname"]];
         $org[PR_ADDRTYPE] = isset($representingprops[$appointmentprops["sentrepresentingaddt"]]) ? $representingprops[$appointmentprops["sentrepresentingaddt"]] : $props[$appointmentprops["sentrepresentingaddt"]];
         $org[PR_EMAIL_ADDRESS] = isset($representingprops[$appointmentprops["sentrepresentingemail"]]) ? $representingprops[$appointmentprops["sentrepresentingemail"]] : $props[$appointmentprops["sentrepresentingemail"]];
         $org[PR_SEARCH_KEY] = isset($representingprops[$appointmentprops["sentrepresentinsrchk"]]) ? $representingprops[$appointmentprops["sentrepresentinsrchk"]] : $props[$appointmentprops["sentrepresentinsrchk"]];
         $org[PR_RECIPIENT_FLAGS] = recipOrganizer | recipSendable;
         $org[PR_RECIPIENT_TYPE] = MAPI_TO;
         array_push($recips, $org);
         //open addresss book for user resolve
         $addrbook = $this->getAddressbook();
         foreach ($appointment->attendees as $attendee) {
             $recip = array();
             $recip[PR_EMAIL_ADDRESS] = u2w($attendee->email);
             // lookup information in GAB if possible so we have up-to-date name for given address
             $userinfo = array(array(PR_DISPLAY_NAME => $recip[PR_EMAIL_ADDRESS]));
             $userinfo = mapi_ab_resolvename($addrbook, $userinfo, EMS_AB_ADDRESS_LOOKUP);
             if (mapi_last_hresult() == NOERROR) {
                 $recip[PR_DISPLAY_NAME] = $userinfo[0][PR_DISPLAY_NAME];
                 $recip[PR_EMAIL_ADDRESS] = $userinfo[0][PR_EMAIL_ADDRESS];
                 $recip[PR_SEARCH_KEY] = $userinfo[0][PR_SEARCH_KEY];
                 $recip[PR_ADDRTYPE] = $userinfo[0][PR_ADDRTYPE];
                 $recip[PR_ENTRYID] = $userinfo[0][PR_ENTRYID];
                 $recip[PR_RECIPIENT_TYPE] = MAPI_TO;
                 $recip[PR_RECIPIENT_FLAGS] = recipSendable;
             } else {
                 $recip[PR_DISPLAY_NAME] = u2w($attendee->name);
                 $recip[PR_SEARCH_KEY] = "SMTP:" . $recip[PR_EMAIL_ADDRESS] . "";
                 $recip[PR_ADDRTYPE] = "SMTP";
                 $recip[PR_RECIPIENT_TYPE] = MAPI_TO;
                 $recip[PR_ENTRYID] = mapi_createoneoff($recip[PR_DISPLAY_NAME], $recip[PR_ADDRTYPE], $recip[PR_EMAIL_ADDRESS]);
             }
             array_push($recips, $recip);
         }
         mapi_message_modifyrecipients($mapimessage, 0, $recips);
         $props[$appointmentprops["icon"]] = 1026;
         $props[$appointmentprops["mrwassent"]] = true;
     }
     mapi_setprops($mapimessage, $props);
 }
Example #17
0
 /**
  * Returns the logger object. If no logger has been initialized, FileLog will be initialized and returned.
  *
  * @access private
  * @return Log
  * @throws Exception thrown if the logger class cannot be instantiated.
  */
 private static function getLogger()
 {
     if (!self::$logger) {
         global $specialLogUsers;
         // This variable comes from the configuration file (config.php)
         $logger = LOGBACKEND_CLASS;
         if (!class_exists($logger)) {
             $errmsg = 'The configured logging class `' . $logger . '` does not exist. Check your configuration.';
             error_log($errmsg);
             throw new \Exception($errmsg);
         }
         list($user) = Utils::SplitDomainUser(strtolower(Request::GetGETUser()));
         $user = '******' . $user . ']';
         self::$logger = new $logger();
         self::$logger->SetUser($user);
         self::$logger->SetAuthUser(Request::GetAuthUser());
         self::$logger->SetSpecialLogUsers($specialLogUsers);
         self::$logger->SetDevid('[' . Request::GetDeviceID() . ']');
         self::$logger->SetPidstr('[' . str_pad(@getmypid(), 5, " ", STR_PAD_LEFT) . ']');
         self::$logger->AfterInitialize();
     }
     return self::$logger;
 }