diff --git a/phpgwapi/inc/class.egw_session.inc.php b/phpgwapi/inc/class.egw_session.inc.php index ef26966e2a..dafb6fbaf1 100644 --- a/phpgwapi/inc/class.egw_session.inc.php +++ b/phpgwapi/inc/class.egw_session.inc.php @@ -500,6 +500,12 @@ class egw_session } $this->account_id = $GLOBALS['egw']->accounts->auto_add($this->account_lid, $passwd); } + // fix maybe wrong case in username, it makes problems eg. in filemanager (name of homedir) + if ($this->account_lid != ($lid = $GLOBALS['egw']->accounts->id2name($this->account_id))) + { + $this->account_lid = $lid; + $this->login = $lid.substr($this->login,strlen($lid)); + } $GLOBALS['egw_info']['user']['account_id'] = $this->account_id; $GLOBALS['egw']->accounts->accounts($this->account_id); @@ -740,7 +746,8 @@ class egw_session in_array(basename($_SERVER['SCRIPT_NAME']),array('webdav.php','groupdav.php'))) { // we generate a pseudo-sessionid from the basic auth credentials - $sessionid = md5($_SERVER['PHP_AUTH_USER'].':'.$_SERVER['PHP_AUTH_PW'].':'.$_SERVER['HTTP_HOST'].':'.EGW_SERVER_ROOT); + $sessionid = md5($_SERVER['PHP_AUTH_USER'].':'.$_SERVER['PHP_AUTH_PW'].':' + .$_SERVER['HTTP_HOST'].':'.EGW_SERVER_ROOT.':'.self::getuser_ip()); } elseif(!$only_basic_auth && isset($_REQUEST[self::EGW_SESSION_NAME])) { @@ -830,6 +837,8 @@ class egw_session // This is to ensure that we authenticate to the correct domain (might not be default) if($GLOBALS['egw_info']['user']['domain'] && $this->account_domain != $GLOBALS['egw_info']['user']['domain']) { + return false; // session not verified, domain changed + throw new Exception("Wrong domain! '$this->account_domain' != '{$GLOBALS['egw_info']['user']['domain']}'"); /* if (self::ERROR_LOG_DEBUG) error_log(__METHOD__."('$sessionid','$kp3') account_domain='$this->account_domain' != '{$GLOBALS['egw_info']['user']['domain']}'=egw_info[user][domain]"); $GLOBALS['egw']->ADOdb = null; @@ -1071,7 +1080,7 @@ class egw_session } else { - if ($othervars) $extravars .= '&'.$othervars; + if ($othervars) $extravars .= ($extravars?'&':'').$othervars; } // parse extravars string into the vars array diff --git a/phpgwapi/inc/horde/Horde/SyncML.php b/phpgwapi/inc/horde/Horde/SyncML.php index 1525855b45..e29d479619 100644 --- a/phpgwapi/inc/horde/Horde/SyncML.php +++ b/phpgwapi/inc/horde/Horde/SyncML.php @@ -19,6 +19,7 @@ * @copyright (c) The Horde Project (http://www.horde.org/) * @version $Id$ */ + include_once 'Horde/SyncML/Command.php'; include_once 'Horde/SyncML/Command/Status.php'; include_once 'Horde/SyncML/Command/Alert.php'; @@ -146,7 +147,7 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler { var $_maxMsgSize; - function getStateFromSession($sourceURI, $locName, $sessionID) + function &getStateFromSession($sourceURI, $locName, $sessionID) { // Remove any existing session since we'll be contructing a // custom session id. @@ -185,7 +186,7 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler { } - if($_SESSION['SyncML.state']->isAuthorized()) { + if ($_SESSION['SyncML.state']->isAuthorized()) { Horde::logMessage('SyncML['. session_id() .']: session is authorized', __FILE__, __LINE__, PEAR_LOG_DEBUG); } @@ -214,29 +215,22 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler { { switch ($this->_xmlStack) { case 2: - /* - $str = 'localname=' . $this->_locName; - $str .= ' version=' . $this->_version; - $str .= ' msgid=' . $this->_msgID; - $str .= ' source=' . $this->_sourceURI; - $str .= ' target=' . $this->_targetURI; - $str .= ' sessionID=' . $this->_sessionID; - */ // - // Find the state. - #Horde::logMessage('SymcML: SyncHdr done. Try to load state from session.', __FILE__, __LINE__, PEAR_LOG_DEBUG); - $state = $this->getStateFromSession($this->_sourceURI, $this->_locName, $this->_sessionID); - - Horde::logMessage('SyncML['. session_id() .']: package ' + Horde::logMessage('SyncML['. session_id() .']: package ' . $this->_msgID.' +++++++++++++++++++++ started', __FILE__, __LINE__, PEAR_LOG_DEBUG); + // Find the state. + //Horde::logMessage('SymcML: SyncHdr done. Try to load state from session.', + // __FILE__, __LINE__, PEAR_LOG_DEBUG); + $state =& $this->getStateFromSession($this->_sourceURI, $this->_locName, $this->_sessionID); + $state->setVersion($this->_version); $state->setMsgID($this->_msgID); $state->setTargetURI($this->_targetURI); $state->setWBXML(is_a($this->_output, 'XML_WBXML_Encoder')); - if(isset($this->_credData) + if (isset($this->_credData) && isset($this->_locName) && !$state->isAuthorized()) { $state->setPassword($this->_credData); @@ -247,14 +241,7 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler { $state->setMaxMsgSize($this->_maxMsgSize); } - #$str = 'authorized=' . $state->isAuthorized(); - #$str .= ' version=' . $state->getVersion(); - #$str .= ' msgid=' . $state->getMsgID(); - #$str .= ' source=' . $state->getSourceURI(); - #$str .= ' target=' . $state->getTargetURI(); - #$str .= ' locName=' . $state->getLocName(); - - $_SESSION['SyncML.state'] = $state; + // $_SESSION['SyncML.state'] = $state; #Horde::logMessage('SymcML: session id 2 =' . session_id(), __FILE__, __LINE__, PEAR_LOG_DEBUG); @@ -289,14 +276,14 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler { // $this->_isCred = false; - //multisync does not specify the cred format + // We only support b64 for now //if ($this->_credFormat == 'b64') { $this->_credData = base64_decode($this->_credData); //} $tmp = explode(':', $this->_credData, 2); // set only if not set by LocName already - if(!isset($this->_locName)) { + if (!isset($this->_locName)) { $this->_locName = $tmp[0]; } $this->_credData = $tmp[1]; @@ -355,7 +342,7 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler { { $attrs = array(); - $state = &$_SESSION['SyncML.state']; + $state =& $_SESSION['SyncML.state']; $uri = $state->getURI(); $uriMeta = $state->getURIMeta(); @@ -495,7 +482,7 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { function startElement($uri, $element, $attrs) { parent::startElement($uri, $element, $attrs); - $state = &$_SESSION['SyncML.state']; + $state =& $_SESSION['SyncML.state']; switch ($this->_xmlStack) { case 2: @@ -505,8 +492,8 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { // $this->_output->startElement($uri, $element, $attrs); - if($state->getLocName()) { - if($state->isAuthConfirmed()) { + if ($state->getLocName()) { + if ($state->isAuthConfirmed()) { // Right our status about the header $status = new Horde_SyncML_Command_Status(($state->isAuthorized()) ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS, 'SyncHdr'); @@ -550,7 +537,7 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { Horde::logMessage('SyncML['. session_id() ."]: found action commands <$element> ", __FILE__, __LINE__, PEAR_LOG_DEBUG); } - switch($element) + switch ($element) { case 'Sync': $state->setSyncStatus(CLIENT_SYNC_STARTED); @@ -568,7 +555,7 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { function endElement($uri, $element) { - $state = &$_SESSION['SyncML.state']; + $state =& $_SESSION['SyncML.state']; switch ($this->_xmlStack) { case 2: @@ -588,14 +575,14 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { // send the sync reply // we do still have some data to send OR // we should reply to the Sync command - if($state->getSyncStatus() > CLIENT_SYNC_FINNISHED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED) { + if ($state->getSyncStatus() > CLIENT_SYNC_FINNISHED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED) { $sync = new Horde_SyncML_Command_Sync(); $this->_currentCmdID = $sync->syncToClient($this->_currentCmdID, $this->_output); } // send the Final tag if possible - #if($state->getSyncStatus() != SERVER_SYNC_DATA_PENDING && $state->getSyncStatus() != CLIENT_SYNC_STARTED) { - if($state->getSyncStatus() >= SERVER_SYNC_FINNISHED || $state->_sendFinal) { + #if ($state->getSyncStatus() != SERVER_SYNC_DATA_PENDING && $state->getSyncStatus() != CLIENT_SYNC_STARTED) { + if ($state->getSyncStatus() >= SERVER_SYNC_FINNISHED || $state->_sendFinal) { $final = new Horde_SyncML_Command_Final(); $this->_currentCmdID = $final->output($this->_currentCmdID, $this->_output); } @@ -609,11 +596,12 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { // this packet did not contain any real actions, just status and map. // This means, we're through! The session can be closed and // the Anchors saved for the next Sync - Horde::logMessage('SyncML['. session_id() .']: sync' . session_id() . ' completed successfully!', __FILE__, __LINE__, PEAR_LOG_INFO); + Horde::logMessage('SyncML['. session_id() .']: sync' . session_id() . ' completed successfully!', + __FILE__, __LINE__, PEAR_LOG_INFO); $state->writeSyncSummary(); $log = $state->getLog(); $s=""; - foreach($log as $k => $v) { + foreach ($log as $k => $v) { $s .= " $k=$v"; } if (strlen(trim($s)) == 0) { @@ -630,11 +618,12 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { // this packet did not contain any real actions, just status and map. // This means, we're through! The session can be closed and // the Anchors saved for the next Sync - Horde::logMessage('SyncML['. session_id() .']: sync' . session_id() . ' completed successfully!', __FILE__, __LINE__, PEAR_LOG_INFO); + Horde::logMessage('SyncML['. session_id() .']: sync' . session_id() . ' completed successfully!', + __FILE__, __LINE__, PEAR_LOG_INFO); $state->writeSyncSummary(); $log = $state->getLog(); $s=""; - foreach($log as $k => $v) { + foreach ($log as $k => $v) { $s .= " $k=$v"; } if (strlen(trim($s)) == 0) { @@ -654,14 +643,15 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { $this->_currentCommand->endElement($uri, $element); - switch($element) { + switch ($element) { case 'Final': $this->_actionCommands = false; - $deviceInfo = $state->getClientDeviceInfo(); if ($state->getSyncStatus() == CLIENT_SYNC_STARTED) { - if (strtolower($deviceInfo['manufacturer']) == 'funambol' - && isset($deviceInfo['softwareVersion'])) { + if ($state->isAuthorized() && + ($deviceInfo = $state->getClientDeviceInfo()) && + strtolower($deviceInfo['manufacturer']) == 'funambol' + && isset($deviceInfo['softwareVersion'])) { $swversion = $deviceInfo['softwareVersion']; if ($swversion < 1.0) { // e.g. Mozilla plugin uses this range @@ -679,9 +669,8 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { } else { $state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED); } - } - if ($state->getSyncStatus() == SERVER_SYNC_FINNISHED) { + } elseif ($state->getSyncStatus() == SERVER_SYNC_FINNISHED) { $state->setSyncStatus(SERVER_SYNC_ACKNOWLEDGED); } diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/ContentSyncElement.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/ContentSyncElement.php index 4d6f7fac20..8a4ee363ce 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/ContentSyncElement.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/ContentSyncElement.php @@ -48,7 +48,7 @@ class Horde_SyncML_Command_Sync_ContentSyncElement extends Horde_SyncML_Command_ } */ if (isset($this->_content) && !$this->_moreData) { - $this->_content = trim($this->_content); + //$this->_content = trim($this->_content); $this->_contentSize = strlen($this->_content); if (strtolower($this->_contentFormat) == 'b64') { $this->_content = base64_encode($this->_content); diff --git a/phpgwapi/inc/horde/Horde/SyncML/State.php b/phpgwapi/inc/horde/Horde/SyncML/State.php index 61c744a551..f908cee06e 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/State.php +++ b/phpgwapi/inc/horde/Horde/SyncML/State.php @@ -203,6 +203,11 @@ class Horde_SyncML_State { var $_password; + /* + * integer 0 authorization pending + * -1 authorization failed + * 1 session is authorized + */ var $_isAuthorized; var $_AuthConfirmed; @@ -277,7 +282,7 @@ class Horde_SyncML_State { $this->setPassword($password); } - $this->_isAuthorized = false; + $this->_isAuthorized = 0; $this->_isAuthConfirmed = false; } @@ -560,12 +565,12 @@ class Horde_SyncML_State { if($GLOBALS['sessionid'] = $GLOBALS['egw']->session->create($this->_locName,$this->_password,'text','u')) { - $this->_isAuthorized = true; + $this->_isAuthorized = 1; #Horde::logMessage('SyncML_EGW: Authentication of ' . $this->_locName . '/' . $GLOBALS['sessionid'] . ' succeded' , __FILE__, __LINE__, PEAR_LOG_DEBUG); } else { - $this->_isAuthorized = false; + $this->_isAuthorized = -1; Horde::logMessage('SyncML: Authentication of ' . $this->_locName . ' failed' , __FILE__, __LINE__, PEAR_LOG_DEBUG); } } @@ -577,7 +582,7 @@ class Horde_SyncML_State { Horde::logMessage('SyncML_EGW: egw session('.$sessionID. ') not verified ' , __FILE__, __LINE__, PEAR_LOG_DEBUG); } - return $this->_isAuthorized; + return ($this->_isAuthorized > 0); } function isAuthConfirmed() diff --git a/phpgwapi/inc/horde/Horde/SyncML/State_egw.php b/phpgwapi/inc/horde/Horde/SyncML/State_egw.php index 92d5a60c1e..458877022e 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/State_egw.php +++ b/phpgwapi/inc/horde/Horde/SyncML/State_egw.php @@ -13,6 +13,7 @@ * @author Joerg Lehrke * @version $Id$ */ + include_once dirname(__FILE__).'/State.php'; /** @@ -59,6 +60,12 @@ class EGW_SyncML_State extends Horde_SyncML_State $ts = $GLOBALS['egw']->contenthistory->getTSforAction($_appName, $_id, $_action); + if (strstr($_id, ':')) { + // pseudo entries are related to parent entry + $parentId = array_shift(explode(':', $_id)); + $pts = $GLOBALS['egw']->contenthistory->getTSforAction($_appName, $parentId, $_action); + if ($pts > $ts) $ts = $pts; // We have changed the parent + } return $ts; } @@ -294,65 +301,99 @@ class EGW_SyncML_State extends Horde_SyncML_State } function isAuthorized() { - if (!$this->_isAuthorized) { - if(!isset($this->_locName) && !isset($this->_password)) { - Horde::logMessage('SyncML: Authentication not yet possible currently. Username and password not available' , __FILE__, __LINE__, PEAR_LOG_DEBUG); - return FALSE; - } - if (!isset($this->_password)) { - Horde::logMessage('SyncML: Authentication not yet possible currently. Password not available' , __FILE__, __LINE__, PEAR_LOG_DEBUG); - return FALSE; - } + if(!isset($this->_locName)) + { + Horde::logMessage('SyncML: Authentication not yet possible. Username not available', + __FILE__, __LINE__, PEAR_LOG_DEBUG); + return false; + } - if (strpos($this->_locName,'@') === False) { - $this->_account_domain = $GLOBALS['egw_info']['server']['default_domain']; - $this->_locName .= '@'. $this->_account_domain; - } else { - $parts = explode('@',$this->_locName); - $this->_account_domain = array_pop($parts); - } + // store sessionID in a variable, because create() and verify() reset this value + $sessionID = session_id(); + if (strpos($this->_locName,'@') === False) + { + $this->_account_domain = $GLOBALS['egw_info']['server']['default_domain']; + $this->_locName .= '@'. $this->_account_domain; + } + else + { + $parts = explode('@',$this->_locName); + $this->_account_domain = array_pop($parts); + } + + if (!is_object($GLOBALS['egw'])) + { + // Let the EGw core create the infrastructure classes + $_POST['login'] = $this->_locName; + $_REQUEST['domain'] = $this->_account_domain; + $GLOBALS['egw_info']['server']['default_domain'] = $this->_account_domain; $GLOBALS['egw_info']['user']['domain'] = $this->_account_domain; - if (is_array($GLOBALS['egw_domain'][$this->_account_domain])) + $GLOBALS['egw_info']['flags']['currentapp'] = 'login'; + $GLOBALS['egw_info']['flags']['noapi'] = false; + require_once(EGW_API_INC . '/functions.inc.php'); + } + + $GLOBALS['egw_info']['flags']['currentapp'] = 'syncml'; + + if (!$this->_isAuthorized) + { + + if (!isset($this->_password)) { + Horde::logMessage('SyncML: Authentication not yet possible. Credetials missing', + __FILE__, __LINE__, PEAR_LOG_DEBUG); + return false; + } - $GLOBALS['egw_info']['server']['db_host'] = $GLOBALS['egw_domain'][$this->_account_domain]['db_host']; - $GLOBALS['egw_info']['server']['db_port'] = $GLOBALS['egw_domain'][$this->_account_domain]['db_port']; - $GLOBALS['egw_info']['server']['db_name'] = $GLOBALS['egw_domain'][$this->_account_domain]['db_name']; - $GLOBALS['egw_info']['server']['db_user'] = $GLOBALS['egw_domain'][$this->_account_domain]['db_user']; - $GLOBALS['egw_info']['server']['db_pass'] = $GLOBALS['egw_domain'][$this->_account_domain]['db_pass']; - $GLOBALS['egw_info']['server']['db_type'] = $GLOBALS['egw_domain'][$this->_account_domain]['db_type']; - // It works -- don't ask me why. - $this->db = new egw_db($GLOBALS['egw_info']['server']); - $this->db->connect(); - - #Horde::logMessage('SyncML: authenticate with username: ' . $this->_locName . ' and password: ' . $this->_password, __FILE__, __LINE__, PEAR_LOG_DEBUG); - - if (($GLOBALS['sessionid'] = $GLOBALS['egw']->session->create($this->_locName,$this->_password,'text'))) + if ($GLOBALS['egw']->session->create($this->_locName,$this->_password,'text')) + { + if ($GLOBALS['egw_info']['user']['apps']['syncml']) { - if ($GLOBALS['egw_info']['user']['apps']['syncml']) { - $this->_isAuthorized = true; - Horde::logMessage('SyncML_EGW: Authentication of ' . $this->_locName . '/' . $GLOBALS['sessionid'] . ' succeded' , __FILE__, __LINE__, PEAR_LOG_DEBUG); - } else { - $this->_isAuthorized = false; - Horde::logMessage('SyncML is not enabled for user ' . $this->_locName , __FILE__, __LINE__, PEAR_LOG_ERROR); - } - return $this->_isAuthorized; + $this->_isAuthorized = 1; + // restore the original sessionID + session_regenerate_id(); + session_id($sessionID); + $GLOBALS['sessionid'] = $sessionID; + @session_start(); + + Horde::logMessage('SyncML_EGW[' . $GLOBALS['sessionid'] + .']: Authentication of ' . $this->_locName . ' succeded', + __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $config =& CreateObject('phpgwapi.config','syncml'); + $config->read_repository(); + $GLOBALS['config_syncml'] =& $config->config_data; + unset($config); + + } + else + { + $this->_isAuthorized = -1; // Authorization failed! + Horde::logMessage('SyncML is not enabled for user ' + . $this->_locName, __FILE__, __LINE__, PEAR_LOG_ERROR); } } - $this->_isAuthorized = false; - Horde::logMessage('SyncML: Authentication of ' . $this->_locName . ' failed' , __FILE__, __LINE__, PEAR_LOG_INFO); - } else { - if ($this->log) error_log(__FILE__.'['.__LINE__.'] '.__METHOD__."()\n".var_export($GLOBALS['egw_info'], true)."\n",3,$this->logfile); - // store sessionID in a variable, because ->verify maybe resets that value - $sessionID = session_id(); - $GLOBALS['egw_info']['user']['domain'] = $this->_account_domain; - if (!$GLOBALS['egw']->session->verify($sessionID, 'staticsyncmlkp3')) { - Horde::logMessage('SyncML_EGW: egw session(' .$sessionID. ') not verified ' , __FILE__, __LINE__, PEAR_LOG_DEBUG); + else + { + $this->_isAuthorized = -1; + Horde::logMessage('SyncML: Authentication of ' . $this->_locName + . ' failed', __FILE__, __LINE__, PEAR_LOG_INFO); + + } + + } + elseif ($this->_isAuthorized > 0) + { + if (!$GLOBALS['egw']->session->verify($sessionID, 'staticsyncmlkp3')) + { + Horde::logMessage('SyncML_EGW: egw session(' . $sessionID + . ') could not be not verified' , + __FILE__, __LINE__, PEAR_LOG_ERROR); } } - return $this->_isAuthorized; + return ($this->_isAuthorized > 0); } /** diff --git a/phpgwapi/inc/horde/Horde/SyncML/Sync/RefreshFromServerSync.php b/phpgwapi/inc/horde/Horde/SyncML/Sync/RefreshFromServerSync.php index 1eb07c795b..1575017f19 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Sync/RefreshFromServerSync.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Sync/RefreshFromServerSync.php @@ -89,6 +89,9 @@ class Horde_SyncML_Sync_RefreshFromServerSync extends Horde_SyncML_Sync_TwoWaySy $contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI); $c = $registry->call($hordeType . '/export', array('guid' => $guid, 'contentType' => $contentType)); + + if ($c === false) continue; // no content to export + if (is_a($c, 'PEAR_Error')) { Horde::logMessage("SyncML: refresh failed to export guid $guid:\n" . print_r($c, true), __FILE__, __LINE__, PEAR_LOG_WARNING); diff --git a/phpgwapi/inc/horde/Horde/SyncML/Sync/SlowSync.php b/phpgwapi/inc/horde/Horde/SyncML/Sync/SlowSync.php index 8a9d704f9c..59664cb881 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Sync/SlowSync.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Sync/SlowSync.php @@ -96,6 +96,9 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync { $contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI); $c = $registry->call($hordeType . '/export', array('guid' => $guid, 'contentType' => $contentType)); + + if ($c === false) continue; // no content to export + if (is_a($c, 'PEAR_Error')) { Horde::logMessage("SyncML: slowsync failed to export guid $guid:\n" . print_r($c, true), __FILE__, __LINE__, PEAR_LOG_WARNING); @@ -235,7 +238,7 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync { $guid = false; $guid = $registry->call($hordeType . '/search', - array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType, $state->getGlobalUID($type, $syncItem->getLocURI()) )); + array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType, $state->getGlobalUID($type, $syncItem->getLocURI()), $type)); if ($guid) { // Check if the found entry came from the client diff --git a/phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php b/phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php index d68ba1ccfc..1e8eae1d8d 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php @@ -135,6 +135,9 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync { 'guid' => $guid, 'contentType' => $contentType )); + + if ($c === false) continue; // no content to export + if (is_a($c, 'PEAR_Error')) { // Item in history but not in database. Strange, but can happen. Horde :: logMessage("SyncML: change: export of guid $guid failed:\n" . print_r($c, true), @@ -343,13 +346,14 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync { // Create an Add request for client. $contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI, $this->_targetLocURI); - $c = $registry->call($hordeType . '/export', array ( 'guid' => $guid, 'contentType' => $contentType, )); + if ($c === false) continue; // no content to export + if (is_a($c, 'PEAR_Error')) { // Item in history but not in database. Strange, but can happen. Horde :: logMessage("SyncML: add: export of guid $guid failed:\n" . print_r($c, true), @@ -406,7 +410,7 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync { function loadData() { global $registry; - $state = & $_SESSION['SyncML.state']; + $state =& $_SESSION['SyncML.state']; $syncType = $this->_targetLocURI; $hordeType = $state->getHordeType($syncType); $refts = $state->getServerAnchorLast($syncType); @@ -421,15 +425,29 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync { $state->setAddedItems($syncType, $addedItems); - $state->setDeletedItems($syncType, $registry->call($hordeType . '/listBy', array ( + $changedItems =& $state->getChangedItems($syncType); + + $deletedItems =& $registry->call($hordeType . '/listBy', array ( 'action' => 'delete', 'timestamp' => $refts, 'type' => $syncType, 'filter' => $this->_filterExpression - ))); + )); + foreach ($deletedItems as $guid) + { + if (strstr($guid, ':')) + { + $parentGUID = array_shift(explode(':', $guid)); + if (!in_array($parentGUID, $changedItems)) + { + $changedItems[] = $parentGUID; + } + } + } + $state->setDeletedItems($syncType, $deletedItems); - $this->_syncDataLoaded = TRUE; + $this->_syncDataLoaded = true; - return count($state->getChangedItems($syncType)) + count($state->getDeletedItems($syncType)) + count($state->getAddedItems($syncType)) + count($state->getConflictItems($syncType)); + return count($changedItems) + count($deletedItems) + count($addedItems) + count($state->getConflictItems($syncType)); } } \ No newline at end of file diff --git a/phpgwapi/inc/horde/Horde/iCalendar.php b/phpgwapi/inc/horde/Horde/iCalendar.php index 94efde396d..bc81cf3b8a 100644 --- a/phpgwapi/inc/horde/Horde/iCalendar.php +++ b/phpgwapi/inc/horde/Horde/iCalendar.php @@ -520,14 +520,20 @@ class Horde_iCalendar { * * @return boolean True on successful import, false otherwise. */ - function parsevCalendar($text, $base = 'VCALENDAR', $charset = null, - $clear = true) + function parsevCalendar($text, $base = 'VCALENDAR', $charset = null, $clear = true) { if ($clear) { $this->clear(); } - if (preg_match('/^BEGIN:' . $base . '(.*)^END:' . $base . '/ism', $text, $matches)) { + if ($base == 'VTODO' && + preg_match('/^BEGIN:VTODO(.*)^END:VEVENT/ism', $text, $matches)) { + // Workaround for Funambol VTODO bug in Mozilla Sync Plugins + Horde::logMessage('iCalendar: Funambol VTODO-bug detected, workaround activated...', + __FILE__, __LINE__, PEAR_LOG_WARNING); + $container = true; + $vCal = $matches[1]; + } elseif (preg_match('/^BEGIN:' . $base . '(.*)^END:' . $base . '/ism', $text, $matches)) { $container = true; $vCal = $matches[1]; } else { @@ -543,12 +549,14 @@ class Horde_iCalendar { $this->setAttribute('VERSION', $matches[1]); } - // Preserve a trailing CR + // Preserve a trailing CR $vCal = trim($vCal) . "\n"; // All subcomponents. $matches = null; - if (preg_match_all('/^BEGIN:(.*)(\r\n|\r|\n)(.*)^END:\1/Uims', $vCal, $matches)) { + // Workaround for Funambol VTODO bug in Mozilla Sync Plugins + if (preg_match_all('/^BEGIN:(VTODO)(\r\n|\r|\n)(.*)^END:VEVENT/Uims', $vCal, $matches) || + preg_match_all('/^BEGIN:(.*)(\r\n|\r|\n)(.*)^END:\1/Uims', $vCal, $matches)) { // vTimezone components are processed first. They are // needed to process vEvents that may use a TZID. foreach ($matches[0] as $key => $data) { @@ -602,6 +610,7 @@ class Horde_iCalendar { // Unfold any folded lines. if ($this->isOldFormat()) { + // old formats force folding at whitespace which must therefore be preserved $vCal = preg_replace('/[\r\n]+([ \t])/', '\1', $vCal); } else { $vCal = preg_replace('/[\r\n]+[ \t]/', '', $vCal); @@ -640,222 +649,224 @@ class Horde_iCalendar { if (isset($params['BASE64'])) { $params['ENCODING'] = 'BASE64'; } - if (isset($params['ENCODING'])) { - switch (String::upper($params['ENCODING'])) { - case 'Q': - case 'QUOTED-PRINTABLE': - $value = quoted_printable_decode($value); - if (isset($params['CHARSET'])) { - $value = $GLOBALS['egw']->translation->convert($value, $params['CHARSET']); - } else { - $value = $GLOBALS['egw']->translation->convert($value, - empty($charset) ? ($this->isOldFormat() ? 'iso-8859-1' : 'utf-8') : $charset); - } - break; - case 'B': - case 'BASE64': - $value = base64_decode($value); - break; - } - } elseif (isset($params['CHARSET'])) { - $value = $GLOBALS['egw']->translation->convert($value, $params['CHARSET']); - } else { - // As per RFC 2279, assume UTF8 if we don't have an - // explicit charset parameter. - $value = $GLOBALS['egw']->translation->convert($value, - empty($charset) ? ($this->isOldFormat() ? 'iso-8859-1' : 'utf-8') : $charset); - } + if (isset($params['ENCODING'])) { + switch (String::upper($params['ENCODING'])) { + case 'Q': + case 'QUOTED-PRINTABLE': + $value = quoted_printable_decode($value); + if (isset($params['CHARSET'])) { + $value = $GLOBALS['egw']->translation->convert($value, $params['CHARSET']); + } else { + $value = $GLOBALS['egw']->translation->convert($value, + empty($charset) ? ($this->isOldFormat() ? 'iso-8859-1' : 'utf-8') : $charset); + } + // Funambol hack :-( + $value = str_replace('\\\\n', "\n", $value); + break; + case 'B': + case 'BASE64': + $value = base64_decode($value); + break; + } + } elseif (isset($params['CHARSET'])) { + $value = $GLOBALS['egw']->translation->convert($value, $params['CHARSET']); + } else { + // As per RFC 2279, assume UTF8 if we don't have an + // explicit charset parameter. + $value = $GLOBALS['egw']->translation->convert($value, + empty($charset) ? ($this->isOldFormat() ? 'iso-8859-1' : 'utf-8') : $charset); + } - // Get timezone info for date fields from $params. - $tzid = isset($params['TZID']) ? trim($params['TZID'], '\"') : false; + // Get timezone info for date fields from $params. + $tzid = isset($params['TZID']) ? trim($params['TZID'], '\"') : false; - switch ($tag) { - case 'VERSION': // already processed + switch ($tag) { + case 'VERSION': // already processed + break; + // Date fields. + case 'COMPLETED': + case 'CREATED': + case 'LAST-MODIFIED': + $this->setAttribute($tag, $this->_parseDateTime($value, $tzid), $params); + break; + + case 'BDAY': + case 'X-SYNCJE-ANNIVERSARY': + $this->setAttribute($tag, $value, $params, true, $this->_parseDate($value)); + break; + + case 'DTEND': + case 'DTSTART': + case 'DTSTAMP': + case 'DUE': + case 'AALARM': + case 'DALARM': + case 'RECURRENCE-ID': + case 'X-RECURRENCE-ID': + // types like AALARM may contain additional data after a ; + // ignore these. + $ts = explode(';', $value); + if (isset($params['VALUE']) && $params['VALUE'] == 'DATE') { + $isDate = true; + $this->setAttribute($tag, $this->_parseDateTime($ts[0], $tzid), $params, true, $this->_parseDate($ts[0])); + } else { + $this->setAttribute($tag, $this->_parseDateTime($ts[0], $tzid), $params); + } + break; + + case 'TRIGGER': + if (isset($params['VALUE'])) { + if ($params['VALUE'] == 'DATE-TIME') { + $this->setAttribute($tag, $this->_parseDateTime($value, $tzid), $params); + } else { + $this->setAttribute($tag, $this->_parseDuration($value), $params); + } + } else { + $this->setAttribute($tag, $this->_parseDuration($value), $params); + } + break; + + // Comma or semicolon seperated dates. + case 'EXDATE': + case 'RDATE': + $dates = array(); + preg_match_all('/[;,]([^;,]*)/', ';' . $value, $values); + + foreach ($values[1] as $value) { + if ((isset($params['VALUE']) + && $params['VALUE'] == 'DATE') || (!isset($params['VALUE']) && $isDate)) { + $dates[] = $this->_parseDate(trim($value)); + } else { + $dates[] = $this->_parseDateTime(trim($value), $tzid); + } + } + $this->setAttribute($tag, isset($dates[0]) ? $dates[0] : null, $params, true, $dates); + break; + + // Duration fields. + case 'DURATION': + $this->setAttribute($tag, $this->_parseDuration($value), $params); + break; + + // Period of time fields. + case 'FREEBUSY': + $periods = array(); + preg_match_all('/,([^,]*)/', ',' . $value, $values); + foreach ($values[1] as $value) { + $periods[] = $this->_parsePeriod($value); + } + + $this->setAttribute($tag, isset($periods[0]) ? $periods[0] : null, $params, true, $periods); + break; + + // UTC offset fields. + case 'TZOFFSETFROM': + case 'TZOFFSETTO': + $this->setAttribute($tag, $this->_parseUtcOffset($value), $params); + break; + + // Integer fields. + case 'PERCENT-COMPLETE': + case 'PRIORITY': + case 'REPEAT': + case 'SEQUENCE': + $this->setAttribute($tag, intval($value), $params); + break; + + // Geo fields. + case 'GEO': + if ($this->isOldFormat()) { + $floats = explode(',', $value); + $value = array('latitude' => floatval($floats[1]), + 'longitude' => floatval($floats[0])); + } else { + $floats = explode(';', $value); + $value = array('latitude' => floatval($floats[0]), + 'longitude' => floatval($floats[1])); + } + $this->setAttribute($tag, $value, $params); + break; + + // Recursion fields. # add more flexibility + #case 'EXRULE': + #case 'RRULE': + # $this->setAttribute($tag, trim($value), $params); + # break; + + // Binary fields. + case 'PHOTO': + $this->setAttribute($tag, $value, $params); + break; + + // ADR, ORG and N are lists seperated by unescaped semicolons + // with a specific number of slots. + case 'ADR': + case 'N': + case 'ORG': + $value = trim($value); + // As of rfc 2426 2.4.2 semicolon, comma, and colon must + // be escaped (comma is unescaped after splitting below). + $value = str_replace(array('\\n', '\\N', '\\;', '\\:'), + array("\n", "\n", ';', ':'), + $value); + + // Split by unescaped semicolons: + $values = preg_split('/(?setAttribute($tag, trim($value), $params, true, $values); + break; + + // CATEGORIES is a lists seperated by unescaped commas + // with a unspecific number of slots. + case 'CATEGORIES': + $value = trim($value); + // As of rfc 2426 2.4.2 semicolon, comma, and colon must + // be escaped (semicolon is unescaped after splitting below). + $value = str_replace(array('\\n', '\\N', '\\,', '\\:'), + array("\n", "\n", ',', ':'), + $value); + + // Split by unescaped commas: + $values = preg_split('/(?setAttribute($tag, trim($value), $params, true, $values); + break; + + // String fields. + default: + if ($this->isOldFormat()) { + // vCalendar 1.0 and vCard 2.1 only escape semicolons + // and use unescaped semicolons to create lists. + $value = trim($value); + // Split by unescaped semicolons: + $values = preg_split('/(?setAttribute($tag, trim($value), $params, true, $values); + } else { + $value = trim($value); + // As of rfc 2426 2.4.2 semicolon, comma, and colon + // must be escaped (comma is unescaped after splitting + // below). + $value = str_replace(array('\\n', '\\N', '\\;', '\\:', '\\\\'), + array("\n", "\n", ';', ':', '\\'), + $value); + + // Split by unescaped commas. + $values = preg_split('/(?setAttribute($tag, trim($value), $params, true, $values); + } break; - // Date fields. - case 'COMPLETED': - case 'CREATED': - case 'LAST-MODIFIED': - $this->setAttribute($tag, $this->_parseDateTime($value, $tzid), $params); - break; - - case 'BDAY': - case 'X-SYNCJE-ANNIVERSARY': - $this->setAttribute($tag, $value, $params, true, $this->_parseDate($value)); - break; - - case 'DTEND': - case 'DTSTART': - case 'DTSTAMP': - case 'DUE': - case 'AALARM': - case 'DALARM': - case 'RECURRENCE-ID': - case 'X-RECURRENCE-ID': - // types like AALARM may contain additional data after a ; - // ignore these. - $ts = explode(';', $value); - if (isset($params['VALUE']) && $params['VALUE'] == 'DATE') { - $isDate = true; - $this->setAttribute($tag, $this->_parseDateTime($ts[0], $tzid), $params, true, $this->_parseDate($ts[0])); - } else { - $this->setAttribute($tag, $this->_parseDateTime($ts[0], $tzid), $params); - } - break; - - case 'TRIGGER': - if (isset($params['VALUE'])) { - if ($params['VALUE'] == 'DATE-TIME') { - $this->setAttribute($tag, $this->_parseDateTime($value, $tzid), $params); - } else { - $this->setAttribute($tag, $this->_parseDuration($value), $params); - } - } else { - $this->setAttribute($tag, $this->_parseDuration($value), $params); - } - break; - - // Comma or semicolon seperated dates. - case 'EXDATE': - case 'RDATE': - $dates = array(); - preg_match_all('/[;,]([^;,]*)/', ';' . $value, $values); - - foreach ($values[1] as $value) { - if ((isset($params['VALUE']) - && $params['VALUE'] == 'DATE') || (!isset($params['VALUE']) && $isDate)) { - $dates[] = $this->_parseDate($value); - } else { - $dates[] = $this->_parseDateTime($value, $tzid); - } - } - $this->setAttribute($tag, isset($dates[0]) ? $dates[0] : null, $params, true, $dates); - break; - - // Duration fields. - case 'DURATION': - $this->setAttribute($tag, $this->_parseDuration($value), $params); - break; - - // Period of time fields. - case 'FREEBUSY': - $periods = array(); - preg_match_all('/,([^,]*)/', ',' . $value, $values); - foreach ($values[1] as $value) { - $periods[] = $this->_parsePeriod($value); - } - - $this->setAttribute($tag, isset($periods[0]) ? $periods[0] : null, $params, true, $periods); - break; - - // UTC offset fields. - case 'TZOFFSETFROM': - case 'TZOFFSETTO': - $this->setAttribute($tag, $this->_parseUtcOffset($value), $params); - break; - - // Integer fields. - case 'PERCENT-COMPLETE': - case 'PRIORITY': - case 'REPEAT': - case 'SEQUENCE': - $this->setAttribute($tag, intval($value), $params); - break; - - // Geo fields. - case 'GEO': - if ($this->isOldFormat()) { - $floats = explode(',', $value); - $value = array('latitude' => floatval($floats[1]), - 'longitude' => floatval($floats[0])); - } else { - $floats = explode(';', $value); - $value = array('latitude' => floatval($floats[0]), - 'longitude' => floatval($floats[1])); - } - $this->setAttribute($tag, $value, $params); - break; - - // Recursion fields. # add more flexibility - #case 'EXRULE': - #case 'RRULE': - # $this->setAttribute($tag, trim($value), $params); - # break; - - // Binary fields. - case 'PHOTO': - $this->setAttribute($tag, $value, $params); - break; - - // ADR, ORG and N are lists seperated by unescaped semicolons - // with a specific number of slots. - case 'ADR': - case 'N': - case 'ORG': - $value = trim($value); - // As of rfc 2426 2.4.2 semicolon, comma, and colon must - // be escaped (comma is unescaped after splitting below). - $value = str_replace(array('\\n', '\\N', '\\;', '\\:'), - array("\n", "\n", ';', ':'), - $value); - - // Split by unescaped semicolons: - $values = preg_split('/(?setAttribute($tag, trim($value), $params, true, $values); - break; - - // CATEGORIES is a lists seperated by unescaped commas - // with a unspecific number of slots. - case 'CATEGORIES': - $value = trim($value); - // As of rfc 2426 2.4.2 semicolon, comma, and colon must - // be escaped (semicolon is unescaped after splitting below). - $value = str_replace(array('\\n', '\\N', '\\,', '\\:'), - array("\n", "\n", ',', ':'), - $value); - - // Split by unescaped commas: - $values = preg_split('/(?setAttribute($tag, trim($value), $params, true, $values); - break; - - // String fields. - default: - if ($this->isOldFormat()) { - // vCalendar 1.0 and vCard 2.1 only escape semicolons - // and use unescaped semicolons to create lists. - $value = trim($value); - // Split by unescaped semicolons: - $values = preg_split('/(?setAttribute($tag, trim($value), $params, true, $values); - } else { - $value = trim($value); - // As of rfc 2426 2.4.2 semicolon, comma, and colon - // must be escaped (comma is unescaped after splitting - // below). - $value = str_replace(array('\\n', '\\N', '\\;', '\\:', '\\\\'), - array("\n", "\n", ';', ':', '\\'), - $value); - - // Split by unescaped commas. - $values = preg_split('/(?setAttribute($tag, trim($value), $params, true, $values); - } - break; - } + } } } @@ -899,7 +910,7 @@ class Horde_iCalendar { && (!$this->isOldFormat() || empty($param_value))) { continue; } - if ($param_name == 'ENCODING' && empty($param_value)) { + if ($param_name == 'ENCODING') { continue; } /* Skip VALUE=DATE for vCalendar 1.0 data, not allowed. */ @@ -928,14 +939,54 @@ class Horde_iCalendar { case 'DCREATED': case 'LAST-MODIFIED': $value = $this->_exportDateTime($value); + break; + + + // Support additional fields after date. + case 'AALARM': + case 'DALARM': + if (isset($params['VALUE'])) { + if ($params['VALUE'] == 'DATE') { + // VCALENDAR 1.0 uses T000000 - T235959 for all day events: + if ($this->isOldFormat() && $name == 'DTEND') { + $d = new Horde_Date($value); + $value = new Horde_Date(array( + 'year' => $d->year, + 'month' => $d->month, + 'mday' => $d->mday - 1)); + $value->correct(); + $value = $this->_exportDate($value, '235959'); + } else { + $value = $this->_exportDate($value, '000000'); + } + } else { + $value = $this->_exportDateTime($value); + } + } else { + $value = $this->_exportDateTime($value); + } + + if (is_array($attribute['values']) && + count($attribute['values']) > 0) { + $values = $attribute['values']; + if ($this->isOldFormat()) { + $values = str_replace(';', '\\;', $values); + } else { + // As of rfc 2426 2.5 semicolon and comma must be + // escaped. + $values = str_replace(array('\\', ';', ','), + array('\\\\', '\\;', '\\,'), + $values); + } + $value .= ';' . implode(';', $values); + } + break; case 'DTEND': case 'DTSTART': case 'DTSTAMP': case 'DUE': - case 'AALARM': - case 'DALARM': case 'RECURRENCE-ID': case 'X-RECURRENCE-ID': if (isset($params['VALUE'])) { @@ -1080,20 +1131,20 @@ class Horde_iCalendar { // Text containing newlines or ASCII >= 127 must be BASE64 // or QUOTED-PRINTABLE encoded. Currently we use // QUOTED-PRINTABLE as default. - if (preg_match("/[^\x20-\x7F]/", $value) && - !isset($params['ENCODING'])) { - $params['ENCODING'] = 'QUOTED-PRINTABLE'; - $params_str .= ';ENCODING=QUOTED-PRINTABLE'; - // Add CHARSET as well. At least the synthesis client - // gets confused otherwise - if (!isset($params['CHARSET'])) { - $params['CHARSET'] = NLS::getCharset(); - $params_str .= ';CHARSET=' . $params['CHARSET']; - } + if (preg_match('/[^\x20-\x7F]/', $value) && + !isset($params['ENCODING'])) { + $params['ENCODING'] = 'QUOTED-PRINTABLE'; + } + if (preg_match('/([\177-\377])/', $value) && + !isset($params['CHARSET'])) { + // Add CHARSET as well. At least the synthesis client + // gets confused otherwise + $params['CHARSET'] = NLS::getCharset(); + $params_str .= ';CHARSET=' . $params['CHARSET']; } } else { if (is_array($attribute['values']) && - count($attribute['values'])) { + count($attribute['values']) > 1) { $values = $attribute['values']; if ($name == 'N' || $name == 'ADR' || $name == 'ORG') { $glue = ';'; @@ -1117,31 +1168,55 @@ class Horde_iCalendar { } } - if (!empty($params['ENCODING']) && strlen(trim($value))) { - switch($params['ENCODING']) { - case 'Q': - case 'QUOTED-PRINTABLE': - $value = str_replace("\r", '', $value); - $result .= $name . $params_str . ':' - . str_replace('=0A', '=0D=0A', - $this->_quotedPrintableEncode($value)) - . $this->_newline; - break; - case 'B': - case 'BASE64': - $attr_string = $name . $params_str . ":" . $this->_newline . ' ' . $this->_base64Encode($value); - $attr_string = String::wordwrap($attr_string, 75, $this->_newline . ' ', - true, 'utf-8', true); - $result .= $attr_string . $this->_newline; - if ($this->isOldFormat()) { - $result .= $this->_newline; // Append an empty line - } - break; - } - } else { + $encoding = (!empty($params['ENCODING']) && strlen(trim($value)) > 0); + + if ($encoding) { + switch($params['ENCODING']) { + case 'Q': + case 'QUOTED-PRINTABLE': + if (!$this->isOldFormat()) + { + $enconding = false; + break; + } + $params_str .= ';ENCODING=' . $params['ENCODING']; + $value = str_replace("\r", '', $value); + $result .= $name . $params_str . ':' + . str_replace('=0A', '=0D=0A', + $this->_quotedPrintableEncode($value)) + . $this->_newline; + break; + case 'FUNAMBOL-QP': + // Funambol needs some special quoting + $value = str_replace(array('<', "\r"), array('<', ''), $value); + if (!$this->isOldFormat()) + { + $encoding = false; + break; + } + $params_str .= ';ENCODING=QUOTED-PRINTABLE'; + $result .= $name . $params_str . ':' + . str_replace('=0A', '=0D=0A', + $this->_quotedPrintableEncode($value, false)) + . $this->_newline; + break; + case 'B': + case 'BASE64': + $params_str .= ';ENCODING=' . $params['ENCODING']; + $attr_string = $name . $params_str . ':' . $this->_newline . ' ' . $this->_base64Encode($value); + $attr_string = String::wordwrap($attr_string, 75, $this->_newline . ' ', + true, 'utf-8', true); + $result .= $attr_string . $this->_newline; + if ($this->isOldFormat()) { + $result .= $this->_newline; // Append an empty line + } + } + } + + if (!$encoding) { $value = str_replace(array("\r", "\n"), array('', '\\n'), $value); $attr_string = $name . $params_str; - if (!empty($value) || $value === 0 || (is_string($value) && strlen($value) > 0)) { + if (strlen($value) > 0) { $attr_string .= ':' . $value; } elseif ($name != 'RRULE') { $attr_string .= ':'; @@ -1537,7 +1612,7 @@ class Horde_iCalendar { * * @return string The quoted-printable encoded string. */ - function _quotedPrintableEncode($input = '') + function _quotedPrintableEncode($input = '', $withFolding=true) { $output = $line = ''; $len = strlen($input); @@ -1555,7 +1630,7 @@ class Horde_iCalendar { } $line .= $chunk; // Wrap long lines (rule 5) - if (strlen($line) + 1 > 76) { + if ($withFolding && strlen($line) + 1 > 76) { $line = String::wordwrap($line, 75, "=\r\n", true, 'us-ascii', true); $newline = strrchr($line, "\r\n"); if ($newline !== false) { @@ -1567,7 +1642,7 @@ class Horde_iCalendar { continue; } // Wrap at line breaks for better readability (rule 4). - if (substr($line, -3) == '=0A') { + if ($withFolding && substr($line, -3) == '=0A') { $output .= $line . "=\r\n"; $line = ''; } diff --git a/rpc.php b/rpc.php index 8701e77841..60313008df 100644 --- a/rpc.php +++ b/rpc.php @@ -10,22 +10,27 @@ error_reporting(E_ALL & ~E_NOTICE); @define('AUTH_HANDLER', true); -@define('HORDE_BASE', dirname(__FILE__).'/phpgwapi/inc/horde/'); +@define('EGW_API_INC', dirname(__FILE__) . '/phpgwapi/inc/'); +@define('HORDE_BASE', EGW_API_INC . '/horde/'); require_once HORDE_BASE . '/lib/core.php'; require_once 'Horde/RPC.php'; +//require_once EGW_API_INC . '/common_functions.inc.php'; $GLOBALS['egw_info'] = array( 'flags' => array( - 'currentapp' => 'login', - 'noheader' => True, - 'nonavbar' => True, - 'disable_Template_class' => True - ) + 'currentapp' => 'syncml', + 'noheader' => true, + 'nonavbar' => true, + 'noapi' => true, + 'disable_Template_class' => true, + ), + 'server' => array( + 'show_domain_selectbox' => true, + ), ); -include('./header.inc.php'); -// allow to use an authentication specific for SyncML -$GLOBALS['egw_info']['flags']['currentapp'] = 'syncml'; + +include('./header.inc.php'); $errors = array(); @@ -45,11 +50,6 @@ if(version_compare(PHP_VERSION, '5.0.0') < 0) { $errors[] = 'eGroupWare\'s SyncML server requires PHP5. Please update to PHP 5.0.x if you want to use SyncML.'; } -$config =& CreateObject('phpgwapi.config','syncml'); -$config->read_repository(); -$GLOBALS['config_syncml'] =& $config->config_data; -unset($config); - /* Look at the Content-type of the request, if it is available, to try * and determine what kind of request this is. */ $input = null;